Skip to content
99 changes: 99 additions & 0 deletions frontend/src/components/LLMSelection/N1nOptions/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { useState, useEffect } from "react";
import System from "@/models/system";

export default function N1nOptions({ settings }) {
const [inputValue, setInputValue] = useState(settings?.N1nApiKey);
const [n1nApiKey, setN1nApiKey] = useState(settings?.N1nApiKey);

return (
<div className="flex gap-[36px] mt-1.5">
<div className="flex flex-col w-60">
<label className="text-white text-sm font-semibold block mb-3">
API Key
</label>
<input
type="password"
name="N1nApiKey"
className="border-none bg-theme-settings-input-bg text-white placeholder:text-theme-settings-input-placeholder text-sm rounded-lg focus:outline-primary-button active:outline-primary-button outline-none block w-full p-2.5"
placeholder="n1n API Key"
defaultValue={settings?.N1nApiKey ? "*".repeat(20) : ""}
required={true}
autoComplete="off"
spellCheck={false}
onChange={(e) => setInputValue(e.target.value)}
onBlur={() => setN1nApiKey(inputValue)}
/>
</div>
{!settings?.credentialsOnly && (
<N1nModelSelection settings={settings} apiKey={n1nApiKey} />
)}
</div>
);
}

function N1nModelSelection({ apiKey, settings }) {
const [models, setModels] = useState([]);
const [loading, setLoading] = useState(true);

useEffect(() => {
async function findCustomModels() {
if (!apiKey) {
setModels([]);
setLoading(true);
return;
}

setLoading(true);
const { models } = await System.customModels(
"n1n",
typeof apiKey === "boolean" ? null : apiKey
);
setModels(models || []);
setLoading(false);
}
findCustomModels();
}, [apiKey]);

if (loading) {
return (
<div className="flex flex-col w-60">
<label className="text-white text-sm font-semibold block mb-3">
Chat Model Selection
</label>
<select
name="N1nModelPref"
disabled={true}
className="border-none bg-theme-settings-input-bg border-gray-500 text-white text-sm rounded-lg block w-full p-2.5"
>
<option disabled={true} selected={true}>
-- loading available models --
</option>
</select>
</div>
);
}

return (
<div className="flex flex-col w-60">
<label className="text-white text-sm font-semibold block mb-3">
Chat Model Selection
</label>
<select
name="N1nModelPref"
required={true}
className="border-none bg-theme-settings-input-bg border-gray-500 text-white text-sm rounded-lg block w-full p-2.5"
>
{models.map((model) => (
<option
key={model.id}
value={model.id}
selected={settings?.N1nModelPref === model.id}
>
{model.name}
</option>
))}
</select>
</div>
);
}

Binary file added frontend/src/media/llmprovider/n1n.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions frontend/src/pages/GeneralSettings/LLMPreference/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import DellProAiStudioLogo from "@/media/llmprovider/dpais.png";
import MoonshotAiLogo from "@/media/llmprovider/moonshotai.png";
import CometApiLogo from "@/media/llmprovider/cometapi.png";
import FoundryLogo from "@/media/llmprovider/foundry-local.png";
import N1nLogo from "@/media/llmprovider/n1n.png";

import PreLoader from "@/components/Preloader";
import OpenAiOptions from "@/components/LLMSelection/OpenAiOptions";
Expand Down Expand Up @@ -67,6 +68,7 @@ import PPIOLLMOptions from "@/components/LLMSelection/PPIOLLMOptions";
import DellProAiStudioOptions from "@/components/LLMSelection/DPAISOptions";
import MoonshotAiOptions from "@/components/LLMSelection/MoonshotAiOptions";
import FoundryOptions from "@/components/LLMSelection/FoundryOptions";
import N1nOptions from "@/components/LLMSelection/N1nOptions";

import LLMItem from "@/components/LLMSelection/LLMItem";
import { CaretUpDown, MagnifyingGlass, X } from "@phosphor-icons/react";
Expand Down Expand Up @@ -349,6 +351,14 @@ export const AVAILABLE_LLM_PROVIDERS = [
"GenericOpenAiKey",
],
},
{
name: "n1n",
value: "n1n",
logo: N1nLogo,
options: (settings) => <N1nOptions settings={settings} />,
description: "Access 400+ LLMs and multimodal models through n1n API.",
requiredConfig: ["N1nApiKey"],
},
];

export default function GeneralLLMPreference() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import PPIOLogo from "@/media/llmprovider/ppio.png";
import DellProAiStudioLogo from "@/media/llmprovider/dpais.png";
import MoonshotAiLogo from "@/media/llmprovider/moonshotai.png";
import CometApiLogo from "@/media/llmprovider/cometapi.png";
import N1nLogo from "@/media/llmprovider/n1n.png";

import OpenAiOptions from "@/components/LLMSelection/OpenAiOptions";
import GenericOpenAiOptions from "@/components/LLMSelection/GenericOpenAiOptions";
Expand Down Expand Up @@ -59,6 +60,7 @@ import PPIOLLMOptions from "@/components/LLMSelection/PPIOLLMOptions";
import DellProAiStudioOptions from "@/components/LLMSelection/DPAISOptions";
import MoonshotAiOptions from "@/components/LLMSelection/MoonshotAiOptions";
import CometApiLLMOptions from "@/components/LLMSelection/CometApiLLMOptions";
import N1nOptions from "@/components/LLMSelection/N1nOptions";

import LLMItem from "@/components/LLMSelection/LLMItem";
import System from "@/models/system";
Expand Down Expand Up @@ -281,6 +283,13 @@ const LLMS = [
options: (settings) => <CometApiLLMOptions settings={settings} />,
description: "500+ AI Models all in one API.",
},
{
name: "n1n",
value: "n1n",
logo: N1nLogo,
options: (settings) => <N1nOptions settings={settings} />,
description: "Access 400+ LLMs and multimodal models through n1n API.",
},
];

export default function LLMPreference({
Expand Down
Loading