mirror of
https://github.com/Mintplex-Labs/anything-llm.git
synced 2024-10-02 08:50:11 +02:00
529 UI update llm embedder and vectordb selection pages (#533)
* move llm, embedder, vectordb items to components folder * add backdrop blur to search in llm, embedder, vectordb preferences * implement searchable llm preference in settings * implement searchable embedder in settings * remove unused useState from embedder preferences * implement searchable vector database in settings * fix save changes button not appearing on change for llm, embedder, and vectordb settings pages * sort selected items in all settings and put selected item at top of list * no auto-top for selection --------- Co-authored-by: timothycarambat <rambat1010@gmail.com>
This commit is contained in:
parent
e9f7b9b79e
commit
d95d1a9dfd
@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import System from "@/models/system";
|
import System from "@/models/system";
|
||||||
|
|
||||||
export default function LocalAiOptions({ settings }) {
|
export default function LocalAiOptions({ settings }) {
|
||||||
@ -12,67 +12,64 @@ export default function LocalAiOptions({ settings }) {
|
|||||||
return (
|
return (
|
||||||
<div className="w-full flex flex-col gap-y-4">
|
<div className="w-full flex flex-col gap-y-4">
|
||||||
<div className="w-full flex items-center gap-4">
|
<div className="w-full flex items-center gap-4">
|
||||||
<div className="w-full flex items-center gap-4">
|
<div className="flex flex-col w-60">
|
||||||
<div className="flex flex-col w-60">
|
<label className="text-white text-sm font-semibold block mb-4">
|
||||||
<label className="text-white text-sm font-semibold block mb-4">
|
LocalAI Base URL
|
||||||
LocalAI Base URL
|
</label>
|
||||||
</label>
|
<input
|
||||||
<input
|
type="url"
|
||||||
type="url"
|
name="EmbeddingBasePath"
|
||||||
name="EmbeddingBasePath"
|
className="bg-zinc-900 text-white placeholder-white placeholder-opacity-60 text-sm rounded-lg focus:border-white block w-full p-2.5"
|
||||||
className="bg-zinc-900 text-white placeholder-white placeholder-opacity-60 text-sm rounded-lg focus:border-white block w-full p-2.5"
|
placeholder="http://localhost:8080/v1"
|
||||||
placeholder="http://localhost:8080/v1"
|
defaultValue={settings?.EmbeddingBasePath}
|
||||||
defaultValue={settings?.EmbeddingBasePath}
|
onChange={(e) => setBasePathValue(e.target.value)}
|
||||||
onChange={(e) => setBasePathValue(e.target.value)}
|
onBlur={() => setBasePath(basePathValue)}
|
||||||
onBlur={() => setBasePath(basePathValue)}
|
required={true}
|
||||||
required={true}
|
autoComplete="off"
|
||||||
autoComplete="off"
|
spellCheck={false}
|
||||||
spellCheck={false}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<LocalAIModelSelection
|
|
||||||
settings={settings}
|
|
||||||
apiKey={apiKey}
|
|
||||||
basePath={basePath}
|
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-col w-60">
|
|
||||||
<label className="text-white text-sm font-semibold block mb-4">
|
|
||||||
Max embedding chunk length
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
name="EmbeddingModelMaxChunkLength"
|
|
||||||
className="bg-zinc-900 text-white placeholder-white placeholder-opacity-60 text-sm rounded-lg focus:border-white block w-full p-2.5"
|
|
||||||
placeholder="1000"
|
|
||||||
min={1}
|
|
||||||
onScroll={(e) => e.target.blur()}
|
|
||||||
defaultValue={settings?.EmbeddingModelMaxChunkLength}
|
|
||||||
required={false}
|
|
||||||
autoComplete="off"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full flex items-center gap-4">
|
<LocalAIModelSelection
|
||||||
<div className="flex flex-col w-60">
|
settings={settings}
|
||||||
<div className="flex flex-col gap-y-1 mb-4">
|
apiKey={apiKey}
|
||||||
<label className="text-white text-sm font-semibold flex items-center gap-x-2">
|
basePath={basePath}
|
||||||
Local AI API Key{" "}
|
/>
|
||||||
<p className="!text-xs !italic !font-thin">optional</p>
|
<div className="flex flex-col w-60">
|
||||||
</label>
|
<label className="text-white text-sm font-semibold block mb-4">
|
||||||
</div>
|
Max embedding chunk length
|
||||||
|
</label>
|
||||||
<input
|
<input
|
||||||
type="password"
|
type="number"
|
||||||
name="LocalAiApiKey"
|
name="EmbeddingModelMaxChunkLength"
|
||||||
className="bg-zinc-900 text-white placeholder-white placeholder-opacity-60 text-sm rounded-lg focus:border-white block w-full p-2.5"
|
className="bg-zinc-900 text-white placeholder-white placeholder-opacity-60 text-sm rounded-lg focus:border-white block w-full p-2.5"
|
||||||
placeholder="sk-mysecretkey"
|
placeholder="1000"
|
||||||
defaultValue={settings?.LocalAiApiKey ? "*".repeat(20) : ""}
|
min={1}
|
||||||
autoComplete="off"
|
onScroll={(e) => e.target.blur()}
|
||||||
spellCheck={false}
|
defaultValue={settings?.EmbeddingModelMaxChunkLength}
|
||||||
onChange={(e) => setApiKeyValue(e.target.value)}
|
required={false}
|
||||||
onBlur={() => setApiKey(apiKeyValue)}
|
autoComplete="off"
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="w-full flex items-center gap-4">
|
||||||
|
<div className="flex flex-col w-60">
|
||||||
|
<div className="flex flex-col gap-y-1 mb-4">
|
||||||
|
<label className="text-white text-sm font-semibold flex items-center gap-x-2">
|
||||||
|
Local AI API Key{" "}
|
||||||
|
<p className="!text-xs !italic !font-thin">optional</p>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
name="LocalAiApiKey"
|
||||||
|
className="bg-zinc-900 text-white placeholder-white placeholder-opacity-60 text-sm rounded-lg focus:border-white block w-full p-2.5"
|
||||||
|
placeholder="sk-mysecretkey"
|
||||||
|
defaultValue={settings?.LocalAiApiKey ? "*".repeat(20) : ""}
|
||||||
|
autoComplete="off"
|
||||||
|
spellCheck={false}
|
||||||
|
onChange={(e) => setApiKeyValue(e.target.value)}
|
||||||
|
onBlur={() => setApiKey(apiKeyValue)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -71,12 +71,10 @@ export default function LocalAiOptions({ settings, showAlert = false }) {
|
|||||||
<div className="w-full flex items-center gap-4">
|
<div className="w-full flex items-center gap-4">
|
||||||
<div className="flex flex-col w-60">
|
<div className="flex flex-col w-60">
|
||||||
<div className="flex flex-col gap-y-1 mb-4">
|
<div className="flex flex-col gap-y-1 mb-4">
|
||||||
<label className="text-white text-sm font-semibold block">
|
<label className="text-white text-sm font-semibold flex items-center gap-x-2">
|
||||||
Local AI API Key
|
Local AI API Key{" "}
|
||||||
|
<p className="!text-xs !italic !font-thin">optional</p>
|
||||||
</label>
|
</label>
|
||||||
<p className="text-xs italic text-white/60">
|
|
||||||
optional API key to use if running LocalAI with API keys.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
|
@ -1,39 +0,0 @@
|
|||||||
import React from "react";
|
|
||||||
|
|
||||||
export default function VectorDBOption({
|
|
||||||
name,
|
|
||||||
link,
|
|
||||||
description,
|
|
||||||
value,
|
|
||||||
image,
|
|
||||||
checked = false,
|
|
||||||
onClick,
|
|
||||||
}) {
|
|
||||||
return (
|
|
||||||
<div onClick={() => onClick(value)}>
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
value={value}
|
|
||||||
className="peer hidden"
|
|
||||||
checked={checked}
|
|
||||||
readOnly={true}
|
|
||||||
formNoValidate={true}
|
|
||||||
/>
|
|
||||||
<label className="transition-all duration-300 inline-flex flex-col h-full w-60 cursor-pointer items-start justify-between rounded-2xl bg-preference-gradient border-2 border-transparent shadow-md px-5 py-4 text-white hover:bg-selected-preference-gradient hover:text-underline hover:border-white/60 peer-checked:border-white peer-checked:border-opacity-90 peer-checked:bg-selected-preference-gradient">
|
|
||||||
<div className="flex items-center">
|
|
||||||
<img src={image} alt={name} className="h-10 w-10 rounded" />
|
|
||||||
<div className="ml-4 text-sm font-semibold">{name}</div>
|
|
||||||
</div>
|
|
||||||
<div className="mt-2 text-xs font-base text-white tracking-wide">
|
|
||||||
{description}
|
|
||||||
</div>
|
|
||||||
<a
|
|
||||||
href={`https://${link}`}
|
|
||||||
className="mt-2 text-xs text-white font-medium underline"
|
|
||||||
>
|
|
||||||
{link}
|
|
||||||
</a>
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,4 +1,4 @@
|
|||||||
export default function VectorDatabaseItem({
|
export default function VectorDBItem({
|
||||||
name,
|
name,
|
||||||
value,
|
value,
|
||||||
image,
|
image,
|
@ -8,25 +8,28 @@ import OpenAiLogo from "@/media/llmprovider/openai.png";
|
|||||||
import AzureOpenAiLogo from "@/media/llmprovider/azure.png";
|
import AzureOpenAiLogo from "@/media/llmprovider/azure.png";
|
||||||
import LocalAiLogo from "@/media/llmprovider/localai.png";
|
import LocalAiLogo from "@/media/llmprovider/localai.png";
|
||||||
import PreLoader from "@/components/Preloader";
|
import PreLoader from "@/components/Preloader";
|
||||||
import LLMProviderOption from "@/components/LLMSelection/LLMProviderOption";
|
|
||||||
import ChangeWarningModal from "@/components/ChangeWarning";
|
import ChangeWarningModal from "@/components/ChangeWarning";
|
||||||
import OpenAiOptions from "@/components/EmbeddingSelection/OpenAiOptions";
|
import OpenAiOptions from "@/components/EmbeddingSelection/OpenAiOptions";
|
||||||
import AzureAiOptions from "@/components/EmbeddingSelection/AzureAiOptions";
|
import AzureAiOptions from "@/components/EmbeddingSelection/AzureAiOptions";
|
||||||
import LocalAiOptions from "@/components/EmbeddingSelection/LocalAiOptions";
|
import LocalAiOptions from "@/components/EmbeddingSelection/LocalAiOptions";
|
||||||
import NativeEmbeddingOptions from "@/components/EmbeddingSelection/NativeEmbeddingOptions";
|
import NativeEmbeddingOptions from "@/components/EmbeddingSelection/NativeEmbeddingOptions";
|
||||||
|
import EmbedderItem from "@/components/EmbeddingSelection/EmbedderItem";
|
||||||
|
import { MagnifyingGlass } from "@phosphor-icons/react";
|
||||||
|
|
||||||
export default function GeneralEmbeddingPreference() {
|
export default function GeneralEmbeddingPreference() {
|
||||||
const [saving, setSaving] = useState(false);
|
const [saving, setSaving] = useState(false);
|
||||||
const [hasChanges, setHasChanges] = useState(false);
|
const [hasChanges, setHasChanges] = useState(false);
|
||||||
const [hasEmbeddings, setHasEmbeddings] = useState(false);
|
const [hasEmbeddings, setHasEmbeddings] = useState(false);
|
||||||
const [embeddingChoice, setEmbeddingChoice] = useState("openai");
|
|
||||||
const [settings, setSettings] = useState(null);
|
const [settings, setSettings] = useState(null);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
|
const [filteredEmbedders, setFilteredEmbedders] = useState([]);
|
||||||
|
const [selectedEmbedder, setSelectedEmbedder] = useState(null);
|
||||||
|
|
||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (
|
if (
|
||||||
embeddingChoice !== settings?.EmbeddingEngine &&
|
selectedEmbedder !== settings?.EmbeddingEngine &&
|
||||||
hasChanges &&
|
hasChanges &&
|
||||||
hasEmbeddings
|
hasEmbeddings
|
||||||
) {
|
) {
|
||||||
@ -38,11 +41,11 @@ export default function GeneralEmbeddingPreference() {
|
|||||||
|
|
||||||
const handleSaveSettings = async () => {
|
const handleSaveSettings = async () => {
|
||||||
setSaving(true);
|
setSaving(true);
|
||||||
const data = new FormData(document.getElementById("embedding-form"));
|
const form = document.getElementById("embedding-form");
|
||||||
const settingsData = {};
|
const settingsData = {};
|
||||||
for (let [key, value] of data.entries()) {
|
const formData = new FormData(form);
|
||||||
settingsData[key] = value;
|
settingsData.EmbeddingEngine = selectedEmbedder;
|
||||||
}
|
for (var [key, value] of formData.entries()) settingsData[key] = value;
|
||||||
|
|
||||||
const { error } = await System.updateSystem(settingsData);
|
const { error } = await System.updateSystem(settingsData);
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -57,7 +60,7 @@ export default function GeneralEmbeddingPreference() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const updateChoice = (selection) => {
|
const updateChoice = (selection) => {
|
||||||
setEmbeddingChoice(selection);
|
setSelectedEmbedder(selection);
|
||||||
setHasChanges(true);
|
setHasChanges(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -65,13 +68,52 @@ export default function GeneralEmbeddingPreference() {
|
|||||||
async function fetchKeys() {
|
async function fetchKeys() {
|
||||||
const _settings = await System.keys();
|
const _settings = await System.keys();
|
||||||
setSettings(_settings);
|
setSettings(_settings);
|
||||||
setEmbeddingChoice(_settings?.EmbeddingEngine || "openai");
|
setSelectedEmbedder(_settings?.EmbeddingEngine || "native");
|
||||||
setHasEmbeddings(_settings?.HasExistingEmbeddings || false);
|
setHasEmbeddings(_settings?.HasExistingEmbeddings || false);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
fetchKeys();
|
fetchKeys();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const EMBEDDERS = [
|
||||||
|
{
|
||||||
|
name: "AnythingLLM Embedder",
|
||||||
|
value: "native",
|
||||||
|
logo: AnythingLLMIcon,
|
||||||
|
options: <NativeEmbeddingOptions settings={settings} />,
|
||||||
|
description:
|
||||||
|
"Use the built-in embedding engine for AnythingLLM. Zero setup!",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "OpenAI",
|
||||||
|
value: "openai",
|
||||||
|
logo: OpenAiLogo,
|
||||||
|
options: <OpenAiOptions settings={settings} />,
|
||||||
|
description: "The standard option for most non-commercial use.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Azure OpenAI",
|
||||||
|
value: "azure",
|
||||||
|
logo: AzureOpenAiLogo,
|
||||||
|
options: <AzureAiOptions settings={settings} />,
|
||||||
|
description: "The enterprise option of OpenAI hosted on Azure services.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Local AI",
|
||||||
|
value: "localai",
|
||||||
|
logo: LocalAiLogo,
|
||||||
|
options: <LocalAiOptions settings={settings} />,
|
||||||
|
description: "Run embedding models locally on your own machine.",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const filtered = EMBEDDERS.filter((embedder) =>
|
||||||
|
embedder.name.toLowerCase().includes(searchQuery.toLowerCase())
|
||||||
|
);
|
||||||
|
setFilteredEmbedders(filtered);
|
||||||
|
}, [searchQuery, selectedEmbedder]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-screen h-screen overflow-hidden bg-sidebar flex">
|
<div className="w-screen h-screen overflow-hidden bg-sidebar flex">
|
||||||
<ChangeWarningModal
|
<ChangeWarningModal
|
||||||
@ -98,7 +140,6 @@ export default function GeneralEmbeddingPreference() {
|
|||||||
<form
|
<form
|
||||||
id="embedding-form"
|
id="embedding-form"
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
onChange={() => setHasChanges(true)}
|
|
||||||
className="flex w-full"
|
className="flex w-full"
|
||||||
>
|
>
|
||||||
<div className="flex flex-col w-full px-1 md:px-20 md:py-12 py-16">
|
<div className="flex flex-col w-full px-1 md:px-20 md:py-12 py-16">
|
||||||
@ -132,59 +173,52 @@ export default function GeneralEmbeddingPreference() {
|
|||||||
<div className="text-white text-sm font-medium py-4">
|
<div className="text-white text-sm font-medium py-4">
|
||||||
Embedding Providers
|
Embedding Providers
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full flex md:flex-wrap overflow-x-scroll gap-4">
|
<div className="w-full">
|
||||||
<input
|
<div className="w-full relative border-slate-300/20 shadow border-4 rounded-xl text-white">
|
||||||
hidden={true}
|
<div className="w-full p-4 absolute top-0 rounded-t-lg backdrop-blur-sm">
|
||||||
name="EmbeddingEngine"
|
<div className="w-full flex items-center sticky top-0 z-20">
|
||||||
value={embeddingChoice}
|
<MagnifyingGlass
|
||||||
/>
|
size={16}
|
||||||
<LLMProviderOption
|
weight="bold"
|
||||||
name="AnythingLLM Embedder"
|
className="absolute left-4 z-30 text-white"
|
||||||
value="native"
|
/>
|
||||||
description="Use the built-in embedding engine for AnythingLLM. Zero setup!"
|
<input
|
||||||
checked={embeddingChoice === "native"}
|
type="text"
|
||||||
image={AnythingLLMIcon}
|
placeholder="Search Embedding providers"
|
||||||
onClick={updateChoice}
|
className="bg-zinc-600 z-20 pl-10 rounded-full w-full px-4 py-1 text-sm border-2 border-slate-300/40 outline-none focus:border-white text-white"
|
||||||
/>
|
onChange={(e) => setSearchQuery(e.target.value)}
|
||||||
<LLMProviderOption
|
autoComplete="off"
|
||||||
name="OpenAI"
|
onKeyDown={(e) => {
|
||||||
value="openai"
|
if (e.key === "Enter") e.preventDefault();
|
||||||
link="openai.com"
|
}}
|
||||||
description="Use OpenAI's text-embedding-ada-002 embedding model."
|
/>
|
||||||
checked={embeddingChoice === "openai"}
|
</div>
|
||||||
image={OpenAiLogo}
|
</div>
|
||||||
onClick={updateChoice}
|
<div className="px-4 pt-[70px] flex flex-col gap-y-1 max-h-[390px] overflow-y-auto no-scroll pb-4">
|
||||||
/>
|
{filteredEmbedders.map((embedder) => {
|
||||||
<LLMProviderOption
|
return (
|
||||||
name="Azure OpenAI"
|
<EmbedderItem
|
||||||
value="azure"
|
key={embedder.name}
|
||||||
link="azure.microsoft.com"
|
name={embedder.name}
|
||||||
description="The enterprise option of OpenAI hosted on Azure services."
|
value={embedder.value}
|
||||||
checked={embeddingChoice === "azure"}
|
image={embedder.logo}
|
||||||
image={AzureOpenAiLogo}
|
description={embedder.description}
|
||||||
onClick={updateChoice}
|
checked={selectedEmbedder === embedder.value}
|
||||||
/>
|
onClick={() => updateChoice(embedder.value)}
|
||||||
<LLMProviderOption
|
/>
|
||||||
name="LocalAI"
|
);
|
||||||
value="localai"
|
})}
|
||||||
link="localai.io"
|
</div>
|
||||||
description="Self hosted LocalAI embedding engine."
|
</div>
|
||||||
checked={embeddingChoice === "localai"}
|
<div
|
||||||
image={LocalAiLogo}
|
onChange={() => setHasChanges(true)}
|
||||||
onClick={updateChoice}
|
className="mt-4 flex flex-col gap-y-1"
|
||||||
/>
|
>
|
||||||
</div>
|
{selectedEmbedder &&
|
||||||
<div className="mt-10 flex flex-wrap gap-4">
|
EMBEDDERS.find(
|
||||||
{embeddingChoice === "native" && <NativeEmbeddingOptions />}
|
(embedder) => embedder.value === selectedEmbedder
|
||||||
{embeddingChoice === "openai" && (
|
)?.options}
|
||||||
<OpenAiOptions settings={settings} />
|
</div>
|
||||||
)}
|
|
||||||
{embeddingChoice === "azure" && (
|
|
||||||
<AzureAiOptions settings={settings} />
|
|
||||||
)}
|
|
||||||
{embeddingChoice === "localai" && (
|
|
||||||
<LocalAiOptions settings={settings} />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
</div>
|
</div>
|
||||||
|
@ -12,7 +12,6 @@ import OllamaLogo from "@/media/llmprovider/ollama.png";
|
|||||||
import LMStudioLogo from "@/media/llmprovider/lmstudio.png";
|
import LMStudioLogo from "@/media/llmprovider/lmstudio.png";
|
||||||
import LocalAiLogo from "@/media/llmprovider/localai.png";
|
import LocalAiLogo from "@/media/llmprovider/localai.png";
|
||||||
import PreLoader from "@/components/Preloader";
|
import PreLoader from "@/components/Preloader";
|
||||||
import LLMProviderOption from "@/components/LLMSelection/LLMProviderOption";
|
|
||||||
import OpenAiOptions from "@/components/LLMSelection/OpenAiOptions";
|
import OpenAiOptions from "@/components/LLMSelection/OpenAiOptions";
|
||||||
import AzureAiOptions from "@/components/LLMSelection/AzureAiOptions";
|
import AzureAiOptions from "@/components/LLMSelection/AzureAiOptions";
|
||||||
import AnthropicAiOptions from "@/components/LLMSelection/AnthropicAiOptions";
|
import AnthropicAiOptions from "@/components/LLMSelection/AnthropicAiOptions";
|
||||||
@ -21,21 +20,31 @@ import LocalAiOptions from "@/components/LLMSelection/LocalAiOptions";
|
|||||||
import NativeLLMOptions from "@/components/LLMSelection/NativeLLMOptions";
|
import NativeLLMOptions from "@/components/LLMSelection/NativeLLMOptions";
|
||||||
import GeminiLLMOptions from "@/components/LLMSelection/GeminiLLMOptions";
|
import GeminiLLMOptions from "@/components/LLMSelection/GeminiLLMOptions";
|
||||||
import OllamaLLMOptions from "@/components/LLMSelection/OllamaLLMOptions";
|
import OllamaLLMOptions from "@/components/LLMSelection/OllamaLLMOptions";
|
||||||
|
import LLMItem from "@/components/LLMSelection/LLMItem";
|
||||||
|
import { MagnifyingGlass } from "@phosphor-icons/react";
|
||||||
|
|
||||||
export default function GeneralLLMPreference() {
|
export default function GeneralLLMPreference() {
|
||||||
const [saving, setSaving] = useState(false);
|
const [saving, setSaving] = useState(false);
|
||||||
const [hasChanges, setHasChanges] = useState(false);
|
const [hasChanges, setHasChanges] = useState(false);
|
||||||
const [llmChoice, setLLMChoice] = useState("openai");
|
|
||||||
const [settings, setSettings] = useState(null);
|
const [settings, setSettings] = useState(null);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
|
const [filteredLLMs, setFilteredLLMs] = useState([]);
|
||||||
|
const [selectedLLM, setSelectedLLM] = useState(null);
|
||||||
|
|
||||||
|
const isHosted = window.location.hostname.includes("useanything.com");
|
||||||
|
|
||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
setSaving(true);
|
const form = e.target;
|
||||||
const data = {};
|
const data = {};
|
||||||
const form = new FormData(e.target);
|
const formData = new FormData(form);
|
||||||
for (var [key, value] of form.entries()) data[key] = value;
|
data.LLMProvider = selectedLLM;
|
||||||
|
for (var [key, value] of formData.entries()) data[key] = value;
|
||||||
const { error } = await System.updateSystem(data);
|
const { error } = await System.updateSystem(data);
|
||||||
|
setSaving(true);
|
||||||
|
|
||||||
if (error) {
|
if (error) {
|
||||||
showToast(`Failed to save LLM settings: ${error}`, "error");
|
showToast(`Failed to save LLM settings: ${error}`, "error");
|
||||||
} else {
|
} else {
|
||||||
@ -46,7 +55,7 @@ export default function GeneralLLMPreference() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const updateLLMChoice = (selection) => {
|
const updateLLMChoice = (selection) => {
|
||||||
setLLMChoice(selection);
|
setSelectedLLM(selection);
|
||||||
setHasChanges(true);
|
setHasChanges(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -54,12 +63,80 @@ export default function GeneralLLMPreference() {
|
|||||||
async function fetchKeys() {
|
async function fetchKeys() {
|
||||||
const _settings = await System.keys();
|
const _settings = await System.keys();
|
||||||
setSettings(_settings);
|
setSettings(_settings);
|
||||||
setLLMChoice(_settings?.LLMProvider);
|
setSelectedLLM(_settings?.LLMProvider);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
fetchKeys();
|
fetchKeys();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const filtered = LLMS.filter((llm) =>
|
||||||
|
llm.name.toLowerCase().includes(searchQuery.toLowerCase())
|
||||||
|
);
|
||||||
|
setFilteredLLMs(filtered);
|
||||||
|
}, [searchQuery, selectedLLM]);
|
||||||
|
|
||||||
|
const LLMS = [
|
||||||
|
{
|
||||||
|
name: "OpenAI",
|
||||||
|
value: "openai",
|
||||||
|
logo: OpenAiLogo,
|
||||||
|
options: <OpenAiOptions settings={settings} />,
|
||||||
|
description: "The standard option for most non-commercial use.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Azure OpenAI",
|
||||||
|
value: "azure",
|
||||||
|
logo: AzureOpenAiLogo,
|
||||||
|
options: <AzureAiOptions settings={settings} />,
|
||||||
|
description: "The enterprise option of OpenAI hosted on Azure services.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Anthropic",
|
||||||
|
value: "anthropic",
|
||||||
|
logo: AnthropicLogo,
|
||||||
|
options: <AnthropicAiOptions settings={settings} />,
|
||||||
|
description: "A friendly AI Assistant hosted by Anthropic.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Gemini",
|
||||||
|
value: "gemini",
|
||||||
|
logo: GeminiLogo,
|
||||||
|
options: <GeminiLLMOptions settings={settings} />,
|
||||||
|
description: "Google's largest and most capable AI model",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Ollama",
|
||||||
|
value: "ollama",
|
||||||
|
logo: OllamaLogo,
|
||||||
|
options: <OllamaLLMOptions settings={settings} />,
|
||||||
|
description: "Run LLMs locally on your own machine.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "LM Studio",
|
||||||
|
value: "lmstudio",
|
||||||
|
logo: LMStudioLogo,
|
||||||
|
options: <LMStudioOptions settings={settings} />,
|
||||||
|
description:
|
||||||
|
"Discover, download, and run thousands of cutting edge LLMs in a few clicks.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Local AI",
|
||||||
|
value: "localai",
|
||||||
|
logo: LocalAiLogo,
|
||||||
|
options: <LocalAiOptions settings={settings} />,
|
||||||
|
description: "Run LLMs locally on your own machine.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Native",
|
||||||
|
value: "native",
|
||||||
|
logo: AnythingLLMIcon,
|
||||||
|
options: <NativeLLMOptions settings={settings} />,
|
||||||
|
description:
|
||||||
|
"Use a downloaded custom Llama model for chatting on this AnythingLLM instance.",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-screen h-screen overflow-hidden bg-sidebar flex">
|
<div className="w-screen h-screen overflow-hidden bg-sidebar flex">
|
||||||
{!isMobile && <Sidebar />}
|
{!isMobile && <Sidebar />}
|
||||||
@ -78,11 +155,7 @@ export default function GeneralLLMPreference() {
|
|||||||
className="relative md:ml-[2px] md:mr-[16px] md:my-[16px] md:rounded-[26px] bg-main-gradient w-full h-full overflow-y-scroll border-4 border-accent"
|
className="relative md:ml-[2px] md:mr-[16px] md:my-[16px] md:rounded-[26px] bg-main-gradient w-full h-full overflow-y-scroll border-4 border-accent"
|
||||||
>
|
>
|
||||||
{isMobile && <SidebarMobileHeader />}
|
{isMobile && <SidebarMobileHeader />}
|
||||||
<form
|
<form onSubmit={handleSubmit} className="flex w-full">
|
||||||
onSubmit={handleSubmit}
|
|
||||||
onChange={() => setHasChanges(true)}
|
|
||||||
className="flex w-full"
|
|
||||||
>
|
|
||||||
<div className="flex flex-col w-full px-1 md:px-20 md:py-12 py-16">
|
<div className="flex flex-col w-full px-1 md:px-20 md:py-12 py-16">
|
||||||
<div className="w-full flex flex-col gap-y-1 pb-6 border-white border-b-2 border-opacity-10">
|
<div className="w-full flex flex-col gap-y-1 pb-6 border-white border-b-2 border-opacity-10">
|
||||||
<div className="items-center flex gap-x-4">
|
<div className="items-center flex gap-x-4">
|
||||||
@ -109,107 +182,51 @@ export default function GeneralLLMPreference() {
|
|||||||
<div className="text-white text-sm font-medium py-4">
|
<div className="text-white text-sm font-medium py-4">
|
||||||
LLM Providers
|
LLM Providers
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full flex md:flex-wrap overflow-x-scroll gap-4">
|
<div className="w-full">
|
||||||
<input hidden={true} name="LLMProvider" value={llmChoice} />
|
<div className="w-full relative border-slate-300/20 shadow border-4 rounded-xl text-white">
|
||||||
<LLMProviderOption
|
<div className="w-full p-4 absolute top-0 rounded-t-lg backdrop-blur-sm">
|
||||||
name="OpenAI"
|
<div className="w-full flex items-center sticky top-0">
|
||||||
value="openai"
|
<MagnifyingGlass
|
||||||
link="openai.com"
|
size={16}
|
||||||
description="The standard option for most non-commercial use."
|
weight="bold"
|
||||||
checked={llmChoice === "openai"}
|
className="absolute left-4 z-30 text-white"
|
||||||
image={OpenAiLogo}
|
/>
|
||||||
onClick={updateLLMChoice}
|
<input
|
||||||
/>
|
type="text"
|
||||||
<LLMProviderOption
|
placeholder="Search LLM providers"
|
||||||
name="Azure OpenAI"
|
className="bg-zinc-600 z-20 pl-10 rounded-full w-full px-4 py-1 text-sm border-2 border-slate-300/40 outline-none focus:border-white text-white"
|
||||||
value="azure"
|
onChange={(e) => setSearchQuery(e.target.value)}
|
||||||
link="azure.microsoft.com"
|
autoComplete="off"
|
||||||
description="The enterprise option of OpenAI hosted on Azure services."
|
onKeyDown={(e) => {
|
||||||
checked={llmChoice === "azure"}
|
if (e.key === "Enter") e.preventDefault();
|
||||||
image={AzureOpenAiLogo}
|
}}
|
||||||
onClick={updateLLMChoice}
|
/>
|
||||||
/>
|
</div>
|
||||||
<LLMProviderOption
|
</div>
|
||||||
name="Anthropic Claude 2"
|
<div className="px-4 pt-[70px] flex flex-col gap-y-1 max-h-[390px] overflow-y-auto no-scroll pb-4">
|
||||||
value="anthropic"
|
{filteredLLMs.map((llm) => {
|
||||||
link="anthropic.com"
|
if (llm.value === "native" && isHosted) return null;
|
||||||
description="A friendly AI Assistant hosted by Anthropic."
|
return (
|
||||||
checked={llmChoice === "anthropic"}
|
<LLMItem
|
||||||
image={AnthropicLogo}
|
key={llm.name}
|
||||||
onClick={updateLLMChoice}
|
name={llm.name}
|
||||||
/>
|
value={llm.value}
|
||||||
<LLMProviderOption
|
image={llm.logo}
|
||||||
name="Google Gemini"
|
description={llm.description}
|
||||||
value="gemini"
|
checked={selectedLLM === llm.value}
|
||||||
link="ai.google.dev"
|
onClick={() => updateLLMChoice(llm.value)}
|
||||||
description="Google's largest and most capable AI model"
|
/>
|
||||||
checked={llmChoice === "gemini"}
|
);
|
||||||
image={GeminiLogo}
|
})}
|
||||||
onClick={updateLLMChoice}
|
</div>
|
||||||
/>
|
</div>
|
||||||
<LLMProviderOption
|
<div
|
||||||
name="LM Studio"
|
onChange={() => setHasChanges(true)}
|
||||||
value="lmstudio"
|
className="mt-4 flex flex-col gap-y-1"
|
||||||
link="lmstudio.ai"
|
>
|
||||||
description="Discover, download, and run thousands of cutting edge LLMs in a few clicks."
|
{selectedLLM &&
|
||||||
checked={llmChoice === "lmstudio"}
|
LLMS.find((llm) => llm.value === selectedLLM)?.options}
|
||||||
image={LMStudioLogo}
|
</div>
|
||||||
onClick={updateLLMChoice}
|
|
||||||
/>
|
|
||||||
<LLMProviderOption
|
|
||||||
name="Local AI"
|
|
||||||
value="localai"
|
|
||||||
link="localai.io"
|
|
||||||
description="Run LLMs locally on your own machine."
|
|
||||||
checked={llmChoice === "localai"}
|
|
||||||
image={LocalAiLogo}
|
|
||||||
onClick={updateLLMChoice}
|
|
||||||
/>
|
|
||||||
<LLMProviderOption
|
|
||||||
name="Ollama"
|
|
||||||
value="ollama"
|
|
||||||
link="ollama.ai"
|
|
||||||
description="Run LLMs locally on your own machine."
|
|
||||||
checked={llmChoice === "ollama"}
|
|
||||||
image={OllamaLogo}
|
|
||||||
onClick={updateLLMChoice}
|
|
||||||
/>
|
|
||||||
{!window.location.hostname.includes("useanything.com") && (
|
|
||||||
<LLMProviderOption
|
|
||||||
name="Custom Llama Model"
|
|
||||||
value="native"
|
|
||||||
description="Use a downloaded custom Llama model for chatting on this AnythingLLM instance."
|
|
||||||
checked={llmChoice === "native"}
|
|
||||||
image={AnythingLLMIcon}
|
|
||||||
onClick={updateLLMChoice}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="mt-10 flex flex-wrap gap-4 max-w-[800px]">
|
|
||||||
{llmChoice === "openai" && (
|
|
||||||
<OpenAiOptions settings={settings} />
|
|
||||||
)}
|
|
||||||
{llmChoice === "azure" && (
|
|
||||||
<AzureAiOptions settings={settings} />
|
|
||||||
)}
|
|
||||||
{llmChoice === "anthropic" && (
|
|
||||||
<AnthropicAiOptions settings={settings} showAlert={true} />
|
|
||||||
)}
|
|
||||||
{llmChoice === "gemini" && (
|
|
||||||
<GeminiLLMOptions settings={settings} />
|
|
||||||
)}
|
|
||||||
{llmChoice === "lmstudio" && (
|
|
||||||
<LMStudioOptions settings={settings} showAlert={true} />
|
|
||||||
)}
|
|
||||||
{llmChoice === "localai" && (
|
|
||||||
<LocalAiOptions settings={settings} showAlert={true} />
|
|
||||||
)}
|
|
||||||
{llmChoice === "ollama" && (
|
|
||||||
<OllamaLLMOptions settings={settings} />
|
|
||||||
)}
|
|
||||||
{llmChoice === "native" && (
|
|
||||||
<NativeLLMOptions settings={settings} />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -9,36 +9,86 @@ import LanceDbLogo from "@/media/vectordbs/lancedb.png";
|
|||||||
import WeaviateLogo from "@/media/vectordbs/weaviate.png";
|
import WeaviateLogo from "@/media/vectordbs/weaviate.png";
|
||||||
import QDrantLogo from "@/media/vectordbs/qdrant.png";
|
import QDrantLogo from "@/media/vectordbs/qdrant.png";
|
||||||
import PreLoader from "@/components/Preloader";
|
import PreLoader from "@/components/Preloader";
|
||||||
import VectorDBOption from "@/components/VectorDBOption";
|
|
||||||
import ChangeWarningModal from "@/components/ChangeWarning";
|
import ChangeWarningModal from "@/components/ChangeWarning";
|
||||||
|
import { MagnifyingGlass } from "@phosphor-icons/react";
|
||||||
|
import LanceDBOptions from "@/components/VectorDBSelection/LanceDBOptions";
|
||||||
|
import ChromaDBOptions from "@/components/VectorDBSelection/ChromaDBOptions";
|
||||||
|
import PineconeDBOptions from "@/components/VectorDBSelection/PineconeDBOptions";
|
||||||
|
import QDrantDBOptions from "@/components/VectorDBSelection/QDrantDBOptions";
|
||||||
|
import WeaviateDBOptions from "@/components/VectorDBSelection/WeaviateDBOptions";
|
||||||
|
import VectorDBItem from "@/components/VectorDBSelection/VectorDBItem";
|
||||||
|
|
||||||
export default function GeneralVectorDatabase() {
|
export default function GeneralVectorDatabase() {
|
||||||
const [saving, setSaving] = useState(false);
|
const [saving, setSaving] = useState(false);
|
||||||
const [hasChanges, setHasChanges] = useState(false);
|
const [hasChanges, setHasChanges] = useState(false);
|
||||||
const [hasEmbeddings, setHasEmbeddings] = useState(false);
|
const [hasEmbeddings, setHasEmbeddings] = useState(false);
|
||||||
const [vectorDB, setVectorDB] = useState("lancedb");
|
|
||||||
const [settings, setSettings] = useState({});
|
const [settings, setSettings] = useState({});
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
|
const [filteredVDBs, setFilteredVDBs] = useState([]);
|
||||||
|
const [selectedVDB, setSelectedVDB] = useState(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function fetchKeys() {
|
async function fetchKeys() {
|
||||||
const _settings = await System.keys();
|
const _settings = await System.keys();
|
||||||
|
console.log(_settings);
|
||||||
setSettings(_settings);
|
setSettings(_settings);
|
||||||
setVectorDB(_settings?.VectorDB || "lancedb");
|
setSelectedVDB(_settings?.VectorDB || "lancedb");
|
||||||
setHasEmbeddings(_settings?.HasExistingEmbeddings || false);
|
setHasEmbeddings(_settings?.HasExistingEmbeddings || false);
|
||||||
setLoading(false);
|
setLoading(false);
|
||||||
}
|
}
|
||||||
fetchKeys();
|
fetchKeys();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const VECTOR_DBS = [
|
||||||
|
{
|
||||||
|
name: "LanceDB",
|
||||||
|
value: "lancedb",
|
||||||
|
logo: LanceDbLogo,
|
||||||
|
options: <LanceDBOptions />,
|
||||||
|
description:
|
||||||
|
"100% local vector DB that runs on the same instance as AnythingLLM.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Chroma",
|
||||||
|
value: "chroma",
|
||||||
|
logo: ChromaLogo,
|
||||||
|
options: <ChromaDBOptions settings={settings} />,
|
||||||
|
description:
|
||||||
|
"Open source vector database you can host yourself or on the cloud.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Pinecone",
|
||||||
|
value: "pinecone",
|
||||||
|
logo: PineconeLogo,
|
||||||
|
options: <PineconeDBOptions settings={settings} />,
|
||||||
|
description: "100% cloud-based vector database for enterprise use cases.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "QDrant",
|
||||||
|
value: "qdrant",
|
||||||
|
logo: QDrantLogo,
|
||||||
|
options: <QDrantDBOptions settings={settings} />,
|
||||||
|
description: "Open source local and distributed cloud vector database.",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Weaviate",
|
||||||
|
value: "weaviate",
|
||||||
|
logo: WeaviateLogo,
|
||||||
|
options: <WeaviateDBOptions settings={settings} />,
|
||||||
|
description:
|
||||||
|
"Open source local and cloud hosted multi-modal vector database.",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const updateVectorChoice = (selection) => {
|
const updateVectorChoice = (selection) => {
|
||||||
setHasChanges(true);
|
setHasChanges(true);
|
||||||
setVectorDB(selection);
|
setSelectedVDB(selection);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
if (vectorDB !== settings?.VectorDB && hasChanges && hasEmbeddings) {
|
if (selectedVDB !== settings?.VectorDB && hasChanges && hasEmbeddings) {
|
||||||
document.getElementById("confirmation-modal")?.showModal();
|
document.getElementById("confirmation-modal")?.showModal();
|
||||||
} else {
|
} else {
|
||||||
await handleSaveSettings();
|
await handleSaveSettings();
|
||||||
@ -47,11 +97,11 @@ export default function GeneralVectorDatabase() {
|
|||||||
|
|
||||||
const handleSaveSettings = async () => {
|
const handleSaveSettings = async () => {
|
||||||
setSaving(true);
|
setSaving(true);
|
||||||
const data = new FormData(document.getElementById("vectordb-form"));
|
const form = document.getElementById("vectordb-form");
|
||||||
const settingsData = {};
|
const settingsData = {};
|
||||||
for (let [key, value] of data.entries()) {
|
const formData = new FormData(form);
|
||||||
settingsData[key] = value;
|
settingsData.VectorDB = selectedVDB;
|
||||||
}
|
for (var [key, value] of formData.entries()) settingsData[key] = value;
|
||||||
|
|
||||||
const { error } = await System.updateSystem(settingsData);
|
const { error } = await System.updateSystem(settingsData);
|
||||||
if (error) {
|
if (error) {
|
||||||
@ -65,6 +115,13 @@ export default function GeneralVectorDatabase() {
|
|||||||
document.getElementById("confirmation-modal")?.close();
|
document.getElementById("confirmation-modal")?.close();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const filtered = VECTOR_DBS.filter((vdb) =>
|
||||||
|
vdb.name.toLowerCase().includes(searchQuery.toLowerCase())
|
||||||
|
);
|
||||||
|
setFilteredVDBs(filtered);
|
||||||
|
}, [searchQuery, selectedVDB]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-screen h-screen overflow-hidden bg-sidebar flex">
|
<div className="w-screen h-screen overflow-hidden bg-sidebar flex">
|
||||||
<ChangeWarningModal
|
<ChangeWarningModal
|
||||||
@ -91,7 +148,6 @@ export default function GeneralVectorDatabase() {
|
|||||||
<form
|
<form
|
||||||
id="vectordb-form"
|
id="vectordb-form"
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
onChange={() => setHasChanges(true)}
|
|
||||||
className="flex w-full"
|
className="flex w-full"
|
||||||
>
|
>
|
||||||
<div className="flex flex-col w-full px-1 md:px-20 md:py-12 py-16">
|
<div className="flex flex-col w-full px-1 md:px-20 md:py-12 py-16">
|
||||||
@ -119,236 +175,52 @@ export default function GeneralVectorDatabase() {
|
|||||||
<div className="text-white text-sm font-medium py-4">
|
<div className="text-white text-sm font-medium py-4">
|
||||||
Select your preferred vector database provider
|
Select your preferred vector database provider
|
||||||
</div>
|
</div>
|
||||||
<div className="w-full flex md:flex-wrap overflow-x-scroll gap-4 max-w-[900px]">
|
<div className="w-full">
|
||||||
<input hidden={true} name="VectorDB" value={vectorDB} />
|
<div className="w-full relative border-slate-300/20 shadow border-4 rounded-xl text-white">
|
||||||
<VectorDBOption
|
<div className="w-full p-4 absolute top-0 rounded-t-lg backdrop-blur-sm">
|
||||||
name="Chroma"
|
<div className="w-full flex items-center sticky top-0 z-20">
|
||||||
value="chroma"
|
<MagnifyingGlass
|
||||||
link="trychroma.com"
|
size={16}
|
||||||
description="Open source vector database you can host yourself or on the cloud."
|
weight="bold"
|
||||||
checked={vectorDB === "chroma"}
|
className="absolute left-4 z-30 text-white"
|
||||||
image={ChromaLogo}
|
|
||||||
onClick={updateVectorChoice}
|
|
||||||
/>
|
|
||||||
<VectorDBOption
|
|
||||||
name="Pinecone"
|
|
||||||
value="pinecone"
|
|
||||||
link="pinecone.io"
|
|
||||||
description="100% cloud-based vector database for enterprise use cases."
|
|
||||||
checked={vectorDB === "pinecone"}
|
|
||||||
image={PineconeLogo}
|
|
||||||
onClick={updateVectorChoice}
|
|
||||||
/>
|
|
||||||
<VectorDBOption
|
|
||||||
name="QDrant"
|
|
||||||
value="qdrant"
|
|
||||||
link="qdrant.tech"
|
|
||||||
description="Open source local and distributed cloud vector database."
|
|
||||||
checked={vectorDB === "qdrant"}
|
|
||||||
image={QDrantLogo}
|
|
||||||
onClick={updateVectorChoice}
|
|
||||||
/>
|
|
||||||
<VectorDBOption
|
|
||||||
name="Weaviate"
|
|
||||||
value="weaviate"
|
|
||||||
link="weaviate.io"
|
|
||||||
description="Open source local and cloud hosted multi-modal vector database."
|
|
||||||
checked={vectorDB === "weaviate"}
|
|
||||||
image={WeaviateLogo}
|
|
||||||
onClick={updateVectorChoice}
|
|
||||||
/>
|
|
||||||
<VectorDBOption
|
|
||||||
name="LanceDB"
|
|
||||||
value="lancedb"
|
|
||||||
link="lancedb.com"
|
|
||||||
description="100% local vector DB that runs on the same instance as AnythingLLM."
|
|
||||||
checked={vectorDB === "lancedb"}
|
|
||||||
image={LanceDbLogo}
|
|
||||||
onClick={updateVectorChoice}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="mt-10 flex flex-wrap gap-4 max-w-[800px]">
|
|
||||||
{vectorDB === "pinecone" && (
|
|
||||||
<>
|
|
||||||
<div className="flex flex-col w-60">
|
|
||||||
<label className="text-white text-sm font-semibold block mb-4">
|
|
||||||
Pinecone DB API Key
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="password"
|
|
||||||
name="PineConeKey"
|
|
||||||
className="bg-zinc-900 text-white placeholder-white placeholder-opacity-60 text-sm rounded-lg focus:border-white block w-full p-2.5"
|
|
||||||
placeholder="Pinecone API Key"
|
|
||||||
defaultValue={
|
|
||||||
settings?.PineConeKey ? "*".repeat(20) : ""
|
|
||||||
}
|
|
||||||
required={true}
|
|
||||||
autoComplete="off"
|
|
||||||
spellCheck={false}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col w-60">
|
|
||||||
<label className="text-white text-sm font-semibold block mb-4">
|
|
||||||
Pinecone Index Environment
|
|
||||||
</label>
|
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
name="PineConeEnvironment"
|
placeholder="Search vector databases"
|
||||||
className="bg-zinc-900 text-white placeholder-white placeholder-opacity-60 text-sm rounded-lg focus:border-white block w-full p-2.5"
|
className="bg-zinc-600 z-20 pl-10 rounded-full w-full px-4 py-1 text-sm border-2 border-slate-300/40 outline-none focus:border-white text-white"
|
||||||
placeholder="us-gcp-west-1"
|
onChange={(e) => {
|
||||||
defaultValue={settings?.PineConeEnvironment}
|
e.preventDefault();
|
||||||
required={true}
|
setSearchQuery(e.target.value);
|
||||||
|
}}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
spellCheck={false}
|
onKeyDown={(e) => {
|
||||||
|
if (e.key === "Enter") e.preventDefault();
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex flex-col w-60">
|
|
||||||
<label className="text-white text-sm font-semibold block mb-4">
|
|
||||||
Pinecone Index Name
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="text"
|
|
||||||
name="PineConeIndex"
|
|
||||||
className="bg-zinc-900 text-white placeholder-white placeholder-opacity-60 text-sm rounded-lg focus:border-white block w-full p-2.5"
|
|
||||||
placeholder="my-index"
|
|
||||||
defaultValue={settings?.PineConeIndex}
|
|
||||||
required={true}
|
|
||||||
autoComplete="off"
|
|
||||||
spellCheck={false}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{vectorDB === "chroma" && (
|
|
||||||
<>
|
|
||||||
<div className="flex flex-col w-60">
|
|
||||||
<label className="text-white text-sm font-semibold block mb-4">
|
|
||||||
Chroma Endpoint
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="url"
|
|
||||||
name="ChromaEndpoint"
|
|
||||||
className="bg-zinc-900 text-white placeholder-white placeholder-opacity-60 text-sm rounded-lg focus:border-white block w-full p-2.5"
|
|
||||||
placeholder="http://localhost:8000"
|
|
||||||
defaultValue={settings?.ChromaEndpoint}
|
|
||||||
required={true}
|
|
||||||
autoComplete="off"
|
|
||||||
spellCheck={false}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col w-60">
|
|
||||||
<label className="text-white text-sm font-semibold block mb-4">
|
|
||||||
API Header
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
name="ChromaApiHeader"
|
|
||||||
autoComplete="off"
|
|
||||||
type="text"
|
|
||||||
defaultValue={settings?.ChromaApiHeader}
|
|
||||||
className="bg-zinc-900 text-white placeholder-white placeholder-opacity-60 text-sm rounded-lg focus:border-white block w-full p-2.5"
|
|
||||||
placeholder="X-Api-Key"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col w-60">
|
|
||||||
<label className="text-white text-sm font-semibold block mb-4">
|
|
||||||
API Key
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
name="ChromaApiKey"
|
|
||||||
autoComplete="off"
|
|
||||||
type="password"
|
|
||||||
defaultValue={
|
|
||||||
settings?.ChromaApiKey ? "*".repeat(20) : ""
|
|
||||||
}
|
|
||||||
className="bg-zinc-900 text-white placeholder-white placeholder-opacity-60 text-sm rounded-lg focus:border-white block w-full p-2.5"
|
|
||||||
placeholder="sk-myApiKeyToAccessMyChromaInstance"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{vectorDB === "lancedb" && (
|
|
||||||
<div className="w-full h-40 items-center justify-center flex">
|
|
||||||
<p className="text-sm font-base text-white text-opacity-60">
|
|
||||||
There is no configuration needed for LanceDB.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
<div className="px-4 pt-[70px] flex flex-col gap-y-1 max-h-[390px] overflow-y-auto no-scroll pb-4">
|
||||||
|
{filteredVDBs.map((vdb) => (
|
||||||
{vectorDB === "qdrant" && (
|
<VectorDBItem
|
||||||
<>
|
key={vdb.name}
|
||||||
<div className="flex flex-col w-60">
|
name={vdb.name}
|
||||||
<label className="text-white text-sm font-semibold block mb-4">
|
value={vdb.value}
|
||||||
QDrant API Endpoint
|
image={vdb.logo}
|
||||||
</label>
|
description={vdb.description}
|
||||||
<input
|
checked={selectedVDB === vdb.value}
|
||||||
type="url"
|
onClick={() => updateVectorChoice(vdb.value)}
|
||||||
name="QdrantEndpoint"
|
|
||||||
className="bg-zinc-900 text-white placeholder-white placeholder-opacity-60 text-sm rounded-lg focus:border-white block w-full p-2.5"
|
|
||||||
placeholder="http://localhost:6633"
|
|
||||||
defaultValue={settings?.QdrantEndpoint}
|
|
||||||
required={true}
|
|
||||||
autoComplete="off"
|
|
||||||
spellCheck={false}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
))}
|
||||||
|
</div>
|
||||||
<div className="flex flex-col w-60">
|
</div>
|
||||||
<label className="text-white text-sm font-semibold block mb-4">
|
<div
|
||||||
API Key
|
onChange={() => setHasChanges(true)}
|
||||||
</label>
|
className="mt-4 flex flex-col gap-y-1"
|
||||||
<input
|
>
|
||||||
type="password"
|
{selectedVDB &&
|
||||||
name="QdrantApiKey"
|
VECTOR_DBS.find((vdb) => vdb.value === selectedVDB)
|
||||||
className="bg-zinc-900 text-white placeholder-white placeholder-opacity-60 text-sm rounded-lg focus:border-white block w-full p-2.5"
|
?.options}
|
||||||
placeholder="wOeqxsYP4....1244sba"
|
</div>
|
||||||
defaultValue={settings?.QdrantApiKey}
|
|
||||||
autoComplete="off"
|
|
||||||
spellCheck={false}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{vectorDB === "weaviate" && (
|
|
||||||
<>
|
|
||||||
<div className="flex flex-col w-60">
|
|
||||||
<label className="text-white text-sm font-semibold block mb-4">
|
|
||||||
Weaviate Endpoint
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="url"
|
|
||||||
name="WeaviateEndpoint"
|
|
||||||
className="bg-zinc-900 text-white placeholder-white placeholder-opacity-60 text-sm rounded-lg focus:border-white block w-full p-2.5"
|
|
||||||
placeholder="http://localhost:8080"
|
|
||||||
defaultValue={settings?.WeaviateEndpoint}
|
|
||||||
required={true}
|
|
||||||
autoComplete="off"
|
|
||||||
spellCheck={false}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="flex flex-col w-60">
|
|
||||||
<label className="text-white text-sm font-semibold block mb-4">
|
|
||||||
API Key
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type="password"
|
|
||||||
name="WeaviateApiKey"
|
|
||||||
className="bg-zinc-900 text-white placeholder-white placeholder-opacity-60 text-sm rounded-lg focus:border-white block w-full p-2.5"
|
|
||||||
placeholder="sk-123Abcweaviate"
|
|
||||||
defaultValue={settings?.WeaviateApiKey}
|
|
||||||
autoComplete="off"
|
|
||||||
spellCheck={false}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -8,7 +8,7 @@ import NativeEmbeddingOptions from "@/components/EmbeddingSelection/NativeEmbedd
|
|||||||
import OpenAiOptions from "@/components/EmbeddingSelection/OpenAiOptions";
|
import OpenAiOptions from "@/components/EmbeddingSelection/OpenAiOptions";
|
||||||
import AzureAiOptions from "@/components/EmbeddingSelection/AzureAiOptions";
|
import AzureAiOptions from "@/components/EmbeddingSelection/AzureAiOptions";
|
||||||
import LocalAiOptions from "@/components/EmbeddingSelection/LocalAiOptions";
|
import LocalAiOptions from "@/components/EmbeddingSelection/LocalAiOptions";
|
||||||
import EmbedderItem from "./EmbedderItem";
|
import EmbedderItem from "@/components/EmbeddingSelection/EmbedderItem";
|
||||||
import System from "@/models/system";
|
import System from "@/models/system";
|
||||||
import paths from "@/utils/paths";
|
import paths from "@/utils/paths";
|
||||||
import showToast from "@/utils/toast";
|
import showToast from "@/utils/toast";
|
||||||
@ -108,22 +108,17 @@ export default function EmbeddingPreference({
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (searchQuery.trim() === "") {
|
const filtered = EMBEDDERS.filter((embedder) =>
|
||||||
setFilteredEmbedders(EMBEDDERS);
|
embedder.name.toLowerCase().includes(searchQuery.toLowerCase())
|
||||||
} else {
|
);
|
||||||
const lowercasedQuery = searchQuery.toLowerCase();
|
setFilteredEmbedders(filtered);
|
||||||
const filtered = EMBEDDERS.filter((embedder) =>
|
}, [searchQuery, selectedEmbedder]);
|
||||||
embedder.name.toLowerCase().includes(lowercasedQuery)
|
|
||||||
);
|
|
||||||
setFilteredEmbedders(filtered);
|
|
||||||
}
|
|
||||||
}, [searchQuery]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<form ref={formRef} onSubmit={handleSubmit} className="w-full">
|
<form ref={formRef} onSubmit={handleSubmit} className="w-full">
|
||||||
<div className="w-full relative border-slate-300/40 shadow border-2 rounded-lg text-white">
|
<div className="w-full relative border-slate-300/40 shadow border-2 rounded-lg text-white">
|
||||||
<div className="w-full p-4 absolute top-0 rounded-t-lg bg-accent/50">
|
<div className="w-full p-4 absolute top-0 rounded-t-lg backdrop-blur-sm">
|
||||||
<div className="w-full flex items-center sticky top-0 z-20">
|
<div className="w-full flex items-center sticky top-0 z-20">
|
||||||
<MagnifyingGlass
|
<MagnifyingGlass
|
||||||
size={16}
|
size={16}
|
||||||
|
@ -16,7 +16,7 @@ import LocalAiOptions from "@/components/LLMSelection/LocalAiOptions";
|
|||||||
import NativeLLMOptions from "@/components/LLMSelection/NativeLLMOptions";
|
import NativeLLMOptions from "@/components/LLMSelection/NativeLLMOptions";
|
||||||
import GeminiLLMOptions from "@/components/LLMSelection/GeminiLLMOptions";
|
import GeminiLLMOptions from "@/components/LLMSelection/GeminiLLMOptions";
|
||||||
import OllamaLLMOptions from "@/components/LLMSelection/OllamaLLMOptions";
|
import OllamaLLMOptions from "@/components/LLMSelection/OllamaLLMOptions";
|
||||||
import LLMItem from "./LLMItem";
|
import LLMItem from "@/components/LLMSelection/LLMItem";
|
||||||
import System from "@/models/system";
|
import System from "@/models/system";
|
||||||
import paths from "@/utils/paths";
|
import paths from "@/utils/paths";
|
||||||
import showToast from "@/utils/toast";
|
import showToast from "@/utils/toast";
|
||||||
@ -144,23 +144,18 @@ export default function LLMPreference({
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (searchQuery.trim() === "") {
|
const filtered = LLMS.filter((llm) =>
|
||||||
setFilteredLLMs(LLMS);
|
llm.name.toLowerCase().includes(searchQuery.toLowerCase())
|
||||||
} else {
|
);
|
||||||
const lowercasedQuery = searchQuery.toLowerCase();
|
setFilteredLLMs(filtered);
|
||||||
const filtered = LLMS.filter((llm) =>
|
}, [searchQuery, selectedLLM]);
|
||||||
llm.name.toLowerCase().includes(lowercasedQuery)
|
|
||||||
);
|
|
||||||
setFilteredLLMs(filtered);
|
|
||||||
}
|
|
||||||
}, [searchQuery]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<form ref={formRef} onSubmit={handleSubmit} className="w-full">
|
<form ref={formRef} onSubmit={handleSubmit} className="w-full">
|
||||||
<div className="w-full relative border-slate-300/40 shadow border-2 rounded-lg text-white">
|
<div className="w-full relative border-slate-300/40 shadow border-2 rounded-lg text-white">
|
||||||
<div className="w-full p-4 absolute top-0 rounded-t-lg bg-accent/50">
|
<div className="w-full p-4 absolute top-0 rounded-t-lg backdrop-blur-sm">
|
||||||
<div className="w-full flex items-center sticky top-0 z-20">
|
<div className="w-full flex items-center sticky top-0">
|
||||||
<MagnifyingGlass
|
<MagnifyingGlass
|
||||||
size={16}
|
size={16}
|
||||||
weight="bold"
|
weight="bold"
|
||||||
|
@ -6,7 +6,6 @@ import LanceDbLogo from "@/media/vectordbs/lancedb.png";
|
|||||||
import WeaviateLogo from "@/media/vectordbs/weaviate.png";
|
import WeaviateLogo from "@/media/vectordbs/weaviate.png";
|
||||||
import QDrantLogo from "@/media/vectordbs/qdrant.png";
|
import QDrantLogo from "@/media/vectordbs/qdrant.png";
|
||||||
import System from "@/models/system";
|
import System from "@/models/system";
|
||||||
import VectorDatabaseItem from "./VectorDatabaseItem";
|
|
||||||
import paths from "@/utils/paths";
|
import paths from "@/utils/paths";
|
||||||
import PineconeDBOptions from "@/components/VectorDBSelection/PineconeDBOptions";
|
import PineconeDBOptions from "@/components/VectorDBSelection/PineconeDBOptions";
|
||||||
import ChromaDBOptions from "@/components/VectorDBSelection/ChromaDBOptions";
|
import ChromaDBOptions from "@/components/VectorDBSelection/ChromaDBOptions";
|
||||||
@ -15,6 +14,7 @@ import WeaviateDBOptions from "@/components/VectorDBSelection/WeaviateDBOptions"
|
|||||||
import LanceDBOptions from "@/components/VectorDBSelection/LanceDBOptions";
|
import LanceDBOptions from "@/components/VectorDBSelection/LanceDBOptions";
|
||||||
import showToast from "@/utils/toast";
|
import showToast from "@/utils/toast";
|
||||||
import { useNavigate } from "react-router-dom";
|
import { useNavigate } from "react-router-dom";
|
||||||
|
import VectorDBItem from "@/components/VectorDBSelection/VectorDBItem";
|
||||||
|
|
||||||
const TITLE = "Vector Database Connection";
|
const TITLE = "Vector Database Connection";
|
||||||
const DESCRIPTION =
|
const DESCRIPTION =
|
||||||
@ -118,22 +118,17 @@ export default function VectorDatabaseConnection({
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (searchQuery.trim() === "") {
|
const filtered = VECTOR_DBS.filter((vdb) =>
|
||||||
setFilteredVDBs(VECTOR_DBS);
|
vdb.name.toLowerCase().includes(searchQuery.toLowerCase())
|
||||||
} else {
|
);
|
||||||
const lowercasedQuery = searchQuery.toLowerCase();
|
setFilteredVDBs(filtered);
|
||||||
const filtered = VECTOR_DBS.filter((vdb) =>
|
}, [searchQuery, selectedVDB]);
|
||||||
vdb.name.toLowerCase().includes(lowercasedQuery)
|
|
||||||
);
|
|
||||||
setFilteredVDBs(filtered);
|
|
||||||
}
|
|
||||||
}, [searchQuery]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<form ref={formRef} onSubmit={handleSubmit} className="w-full">
|
<form ref={formRef} onSubmit={handleSubmit} className="w-full">
|
||||||
<div className="w-full relative border-slate-300/40 shadow border-2 rounded-lg text-white pb-4">
|
<div className="w-full relative border-slate-300/40 shadow border-2 rounded-lg text-white pb-4">
|
||||||
<div className="w-full p-4 absolute top-0 rounded-t-lg bg-accent/50">
|
<div className="w-full p-4 absolute top-0 rounded-t-lg backdrop-blur-sm">
|
||||||
<div className="w-full flex items-center sticky top-0 z-20">
|
<div className="w-full flex items-center sticky top-0 z-20">
|
||||||
<MagnifyingGlass
|
<MagnifyingGlass
|
||||||
size={16}
|
size={16}
|
||||||
@ -154,7 +149,7 @@ export default function VectorDatabaseConnection({
|
|||||||
</div>
|
</div>
|
||||||
<div className="px-4 pt-[70px] flex flex-col gap-y-1 max-h-[390px] overflow-y-auto no-scroll">
|
<div className="px-4 pt-[70px] flex flex-col gap-y-1 max-h-[390px] overflow-y-auto no-scroll">
|
||||||
{filteredVDBs.map((vdb) => (
|
{filteredVDBs.map((vdb) => (
|
||||||
<VectorDatabaseItem
|
<VectorDBItem
|
||||||
key={vdb.name}
|
key={vdb.name}
|
||||||
name={vdb.name}
|
name={vdb.name}
|
||||||
value={vdb.value}
|
value={vdb.value}
|
||||||
|
Loading…
Reference in New Issue
Block a user