From d95d1a9dfd45457e7d665b32968e3c24b3b863bb Mon Sep 17 00:00:00 2001 From: Sean Hatfield Date: Thu, 4 Jan 2024 18:20:58 -0800 Subject: [PATCH] 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 --- .../EmbedderItem/index.jsx} | 0 .../LocalAiOptions/index.jsx | 115 +++--- .../LLMSelection/LLMItem/index.jsx} | 0 .../LLMSelection/LocalAiOptions/index.jsx | 8 +- .../src/components/VectorDBOption/index.jsx | 39 -- .../VectorDBSelection/VectorDBItem/index.jsx} | 2 +- .../EmbeddingPreference/index.jsx | 160 +++++---- .../GeneralSettings/LLMPreference/index.jsx | 243 +++++++------ .../GeneralSettings/VectorDatabase/index.jsx | 336 ++++++------------ .../Steps/EmbeddingPreference/index.jsx | 19 +- .../Steps/LLMPreference/index.jsx | 21 +- .../Steps/VectorDatabaseConnection/index.jsx | 21 +- 12 files changed, 414 insertions(+), 550 deletions(-) rename frontend/src/{pages/OnboardingFlow/Steps/EmbeddingPreference/EmbedderItem.jsx => components/EmbeddingSelection/EmbedderItem/index.jsx} (100%) rename frontend/src/{pages/OnboardingFlow/Steps/LLMPreference/LLMItem.jsx => components/LLMSelection/LLMItem/index.jsx} (100%) delete mode 100644 frontend/src/components/VectorDBOption/index.jsx rename frontend/src/{pages/OnboardingFlow/Steps/VectorDatabaseConnection/VectorDatabaseItem.jsx => components/VectorDBSelection/VectorDBItem/index.jsx} (94%) diff --git a/frontend/src/pages/OnboardingFlow/Steps/EmbeddingPreference/EmbedderItem.jsx b/frontend/src/components/EmbeddingSelection/EmbedderItem/index.jsx similarity index 100% rename from frontend/src/pages/OnboardingFlow/Steps/EmbeddingPreference/EmbedderItem.jsx rename to frontend/src/components/EmbeddingSelection/EmbedderItem/index.jsx diff --git a/frontend/src/components/EmbeddingSelection/LocalAiOptions/index.jsx b/frontend/src/components/EmbeddingSelection/LocalAiOptions/index.jsx index 6f81712c..651d3e95 100644 --- a/frontend/src/components/EmbeddingSelection/LocalAiOptions/index.jsx +++ b/frontend/src/components/EmbeddingSelection/LocalAiOptions/index.jsx @@ -1,4 +1,4 @@ -import { useEffect, useState } from "react"; +import React, { useEffect, useState } from "react"; import System from "@/models/system"; export default function LocalAiOptions({ settings }) { @@ -12,67 +12,64 @@ export default function LocalAiOptions({ settings }) { return (
-
-
- - setBasePathValue(e.target.value)} - onBlur={() => setBasePath(basePathValue)} - required={true} - autoComplete="off" - spellCheck={false} - /> -
- + + setBasePathValue(e.target.value)} + onBlur={() => setBasePath(basePathValue)} + required={true} + autoComplete="off" + spellCheck={false} /> -
- - e.target.blur()} - defaultValue={settings?.EmbeddingModelMaxChunkLength} - required={false} - autoComplete="off" - /> -
-
-
-
- -
- - setApiKeyValue(e.target.value)} - onBlur={() => setApiKey(apiKeyValue)} - /> + +
+ + e.target.blur()} + defaultValue={settings?.EmbeddingModelMaxChunkLength} + required={false} + autoComplete="off" + /> +
+
+
+
+
+
+ setApiKeyValue(e.target.value)} + onBlur={() => setApiKey(apiKeyValue)} + />
diff --git a/frontend/src/pages/OnboardingFlow/Steps/LLMPreference/LLMItem.jsx b/frontend/src/components/LLMSelection/LLMItem/index.jsx similarity index 100% rename from frontend/src/pages/OnboardingFlow/Steps/LLMPreference/LLMItem.jsx rename to frontend/src/components/LLMSelection/LLMItem/index.jsx diff --git a/frontend/src/components/LLMSelection/LocalAiOptions/index.jsx b/frontend/src/components/LLMSelection/LocalAiOptions/index.jsx index 7a385278..c7abd09a 100644 --- a/frontend/src/components/LLMSelection/LocalAiOptions/index.jsx +++ b/frontend/src/components/LLMSelection/LocalAiOptions/index.jsx @@ -71,12 +71,10 @@ export default function LocalAiOptions({ settings, showAlert = false }) {
-
onClick(value)}> - - -
- ); -} diff --git a/frontend/src/pages/OnboardingFlow/Steps/VectorDatabaseConnection/VectorDatabaseItem.jsx b/frontend/src/components/VectorDBSelection/VectorDBItem/index.jsx similarity index 94% rename from frontend/src/pages/OnboardingFlow/Steps/VectorDatabaseConnection/VectorDatabaseItem.jsx rename to frontend/src/components/VectorDBSelection/VectorDBItem/index.jsx index 4ecd304f..47f067f5 100644 --- a/frontend/src/pages/OnboardingFlow/Steps/VectorDatabaseConnection/VectorDatabaseItem.jsx +++ b/frontend/src/components/VectorDBSelection/VectorDBItem/index.jsx @@ -1,4 +1,4 @@ -export default function VectorDatabaseItem({ +export default function VectorDBItem({ name, value, image, diff --git a/frontend/src/pages/GeneralSettings/EmbeddingPreference/index.jsx b/frontend/src/pages/GeneralSettings/EmbeddingPreference/index.jsx index d6224906..ddcb8131 100644 --- a/frontend/src/pages/GeneralSettings/EmbeddingPreference/index.jsx +++ b/frontend/src/pages/GeneralSettings/EmbeddingPreference/index.jsx @@ -8,25 +8,28 @@ import OpenAiLogo from "@/media/llmprovider/openai.png"; import AzureOpenAiLogo from "@/media/llmprovider/azure.png"; import LocalAiLogo from "@/media/llmprovider/localai.png"; import PreLoader from "@/components/Preloader"; -import LLMProviderOption from "@/components/LLMSelection/LLMProviderOption"; import ChangeWarningModal from "@/components/ChangeWarning"; import OpenAiOptions from "@/components/EmbeddingSelection/OpenAiOptions"; import AzureAiOptions from "@/components/EmbeddingSelection/AzureAiOptions"; import LocalAiOptions from "@/components/EmbeddingSelection/LocalAiOptions"; import NativeEmbeddingOptions from "@/components/EmbeddingSelection/NativeEmbeddingOptions"; +import EmbedderItem from "@/components/EmbeddingSelection/EmbedderItem"; +import { MagnifyingGlass } from "@phosphor-icons/react"; export default function GeneralEmbeddingPreference() { const [saving, setSaving] = useState(false); const [hasChanges, setHasChanges] = useState(false); const [hasEmbeddings, setHasEmbeddings] = useState(false); - const [embeddingChoice, setEmbeddingChoice] = useState("openai"); const [settings, setSettings] = useState(null); const [loading, setLoading] = useState(true); + const [searchQuery, setSearchQuery] = useState(""); + const [filteredEmbedders, setFilteredEmbedders] = useState([]); + const [selectedEmbedder, setSelectedEmbedder] = useState(null); const handleSubmit = async (e) => { e.preventDefault(); if ( - embeddingChoice !== settings?.EmbeddingEngine && + selectedEmbedder !== settings?.EmbeddingEngine && hasChanges && hasEmbeddings ) { @@ -38,11 +41,11 @@ export default function GeneralEmbeddingPreference() { const handleSaveSettings = async () => { setSaving(true); - const data = new FormData(document.getElementById("embedding-form")); + const form = document.getElementById("embedding-form"); const settingsData = {}; - for (let [key, value] of data.entries()) { - settingsData[key] = value; - } + const formData = new FormData(form); + settingsData.EmbeddingEngine = selectedEmbedder; + for (var [key, value] of formData.entries()) settingsData[key] = value; const { error } = await System.updateSystem(settingsData); if (error) { @@ -57,7 +60,7 @@ export default function GeneralEmbeddingPreference() { }; const updateChoice = (selection) => { - setEmbeddingChoice(selection); + setSelectedEmbedder(selection); setHasChanges(true); }; @@ -65,13 +68,52 @@ export default function GeneralEmbeddingPreference() { async function fetchKeys() { const _settings = await System.keys(); setSettings(_settings); - setEmbeddingChoice(_settings?.EmbeddingEngine || "openai"); + setSelectedEmbedder(_settings?.EmbeddingEngine || "native"); setHasEmbeddings(_settings?.HasExistingEmbeddings || false); setLoading(false); } fetchKeys(); }, []); + const EMBEDDERS = [ + { + name: "AnythingLLM Embedder", + value: "native", + logo: AnythingLLMIcon, + options: , + description: + "Use the built-in embedding engine for AnythingLLM. Zero setup!", + }, + { + name: "OpenAI", + value: "openai", + logo: OpenAiLogo, + options: , + description: "The standard option for most non-commercial use.", + }, + { + name: "Azure OpenAI", + value: "azure", + logo: AzureOpenAiLogo, + options: , + description: "The enterprise option of OpenAI hosted on Azure services.", + }, + { + name: "Local AI", + value: "localai", + logo: LocalAiLogo, + options: , + 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 (
setHasChanges(true)} className="flex w-full" >
@@ -132,59 +173,52 @@ export default function GeneralEmbeddingPreference() {
Embedding Providers
-
- - - - - -
-
- {embeddingChoice === "native" && } - {embeddingChoice === "openai" && ( - - )} - {embeddingChoice === "azure" && ( - - )} - {embeddingChoice === "localai" && ( - - )} +
+
+
+
+ + setSearchQuery(e.target.value)} + autoComplete="off" + onKeyDown={(e) => { + if (e.key === "Enter") e.preventDefault(); + }} + /> +
+
+
+ {filteredEmbedders.map((embedder) => { + return ( + updateChoice(embedder.value)} + /> + ); + })} +
+
+
setHasChanges(true)} + className="mt-4 flex flex-col gap-y-1" + > + {selectedEmbedder && + EMBEDDERS.find( + (embedder) => embedder.value === selectedEmbedder + )?.options} +
diff --git a/frontend/src/pages/GeneralSettings/LLMPreference/index.jsx b/frontend/src/pages/GeneralSettings/LLMPreference/index.jsx index 0cecaa4d..d72cf3c2 100644 --- a/frontend/src/pages/GeneralSettings/LLMPreference/index.jsx +++ b/frontend/src/pages/GeneralSettings/LLMPreference/index.jsx @@ -12,7 +12,6 @@ import OllamaLogo from "@/media/llmprovider/ollama.png"; import LMStudioLogo from "@/media/llmprovider/lmstudio.png"; import LocalAiLogo from "@/media/llmprovider/localai.png"; import PreLoader from "@/components/Preloader"; -import LLMProviderOption from "@/components/LLMSelection/LLMProviderOption"; import OpenAiOptions from "@/components/LLMSelection/OpenAiOptions"; import AzureAiOptions from "@/components/LLMSelection/AzureAiOptions"; import AnthropicAiOptions from "@/components/LLMSelection/AnthropicAiOptions"; @@ -21,21 +20,31 @@ import LocalAiOptions from "@/components/LLMSelection/LocalAiOptions"; import NativeLLMOptions from "@/components/LLMSelection/NativeLLMOptions"; import GeminiLLMOptions from "@/components/LLMSelection/GeminiLLMOptions"; import OllamaLLMOptions from "@/components/LLMSelection/OllamaLLMOptions"; +import LLMItem from "@/components/LLMSelection/LLMItem"; +import { MagnifyingGlass } from "@phosphor-icons/react"; export default function GeneralLLMPreference() { const [saving, setSaving] = useState(false); const [hasChanges, setHasChanges] = useState(false); - const [llmChoice, setLLMChoice] = useState("openai"); const [settings, setSettings] = useState(null); 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) => { e.preventDefault(); - setSaving(true); + const form = e.target; const data = {}; - const form = new FormData(e.target); - for (var [key, value] of form.entries()) data[key] = value; + const formData = new FormData(form); + data.LLMProvider = selectedLLM; + for (var [key, value] of formData.entries()) data[key] = value; const { error } = await System.updateSystem(data); + setSaving(true); + if (error) { showToast(`Failed to save LLM settings: ${error}`, "error"); } else { @@ -46,7 +55,7 @@ export default function GeneralLLMPreference() { }; const updateLLMChoice = (selection) => { - setLLMChoice(selection); + setSelectedLLM(selection); setHasChanges(true); }; @@ -54,12 +63,80 @@ export default function GeneralLLMPreference() { async function fetchKeys() { const _settings = await System.keys(); setSettings(_settings); - setLLMChoice(_settings?.LLMProvider); + setSelectedLLM(_settings?.LLMProvider); setLoading(false); } 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: , + description: "The standard option for most non-commercial use.", + }, + { + name: "Azure OpenAI", + value: "azure", + logo: AzureOpenAiLogo, + options: , + description: "The enterprise option of OpenAI hosted on Azure services.", + }, + { + name: "Anthropic", + value: "anthropic", + logo: AnthropicLogo, + options: , + description: "A friendly AI Assistant hosted by Anthropic.", + }, + { + name: "Gemini", + value: "gemini", + logo: GeminiLogo, + options: , + description: "Google's largest and most capable AI model", + }, + { + name: "Ollama", + value: "ollama", + logo: OllamaLogo, + options: , + description: "Run LLMs locally on your own machine.", + }, + { + name: "LM Studio", + value: "lmstudio", + logo: LMStudioLogo, + options: , + description: + "Discover, download, and run thousands of cutting edge LLMs in a few clicks.", + }, + { + name: "Local AI", + value: "localai", + logo: LocalAiLogo, + options: , + description: "Run LLMs locally on your own machine.", + }, + { + name: "Native", + value: "native", + logo: AnythingLLMIcon, + options: , + description: + "Use a downloaded custom Llama model for chatting on this AnythingLLM instance.", + }, + ]; + return (
{!isMobile && } @@ -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" > {isMobile && } -
setHasChanges(true)} - className="flex w-full" - > +
@@ -109,107 +182,51 @@ export default function GeneralLLMPreference() {
LLM Providers
-
- - - - - - - - - {!window.location.hostname.includes("useanything.com") && ( - - )} -
-
- {llmChoice === "openai" && ( - - )} - {llmChoice === "azure" && ( - - )} - {llmChoice === "anthropic" && ( - - )} - {llmChoice === "gemini" && ( - - )} - {llmChoice === "lmstudio" && ( - - )} - {llmChoice === "localai" && ( - - )} - {llmChoice === "ollama" && ( - - )} - {llmChoice === "native" && ( - - )} +
+
+
+
+ + setSearchQuery(e.target.value)} + autoComplete="off" + onKeyDown={(e) => { + if (e.key === "Enter") e.preventDefault(); + }} + /> +
+
+
+ {filteredLLMs.map((llm) => { + if (llm.value === "native" && isHosted) return null; + return ( + updateLLMChoice(llm.value)} + /> + ); + })} +
+
+
setHasChanges(true)} + className="mt-4 flex flex-col gap-y-1" + > + {selectedLLM && + LLMS.find((llm) => llm.value === selectedLLM)?.options} +
diff --git a/frontend/src/pages/GeneralSettings/VectorDatabase/index.jsx b/frontend/src/pages/GeneralSettings/VectorDatabase/index.jsx index 2ddf1d5a..9ef9cff2 100644 --- a/frontend/src/pages/GeneralSettings/VectorDatabase/index.jsx +++ b/frontend/src/pages/GeneralSettings/VectorDatabase/index.jsx @@ -9,36 +9,86 @@ import LanceDbLogo from "@/media/vectordbs/lancedb.png"; import WeaviateLogo from "@/media/vectordbs/weaviate.png"; import QDrantLogo from "@/media/vectordbs/qdrant.png"; import PreLoader from "@/components/Preloader"; -import VectorDBOption from "@/components/VectorDBOption"; 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() { const [saving, setSaving] = useState(false); const [hasChanges, setHasChanges] = useState(false); const [hasEmbeddings, setHasEmbeddings] = useState(false); - const [vectorDB, setVectorDB] = useState("lancedb"); const [settings, setSettings] = useState({}); const [loading, setLoading] = useState(true); + const [searchQuery, setSearchQuery] = useState(""); + const [filteredVDBs, setFilteredVDBs] = useState([]); + const [selectedVDB, setSelectedVDB] = useState(null); useEffect(() => { async function fetchKeys() { const _settings = await System.keys(); + console.log(_settings); setSettings(_settings); - setVectorDB(_settings?.VectorDB || "lancedb"); + setSelectedVDB(_settings?.VectorDB || "lancedb"); setHasEmbeddings(_settings?.HasExistingEmbeddings || false); setLoading(false); } fetchKeys(); }, []); + const VECTOR_DBS = [ + { + name: "LanceDB", + value: "lancedb", + logo: LanceDbLogo, + options: , + description: + "100% local vector DB that runs on the same instance as AnythingLLM.", + }, + { + name: "Chroma", + value: "chroma", + logo: ChromaLogo, + options: , + description: + "Open source vector database you can host yourself or on the cloud.", + }, + { + name: "Pinecone", + value: "pinecone", + logo: PineconeLogo, + options: , + description: "100% cloud-based vector database for enterprise use cases.", + }, + { + name: "QDrant", + value: "qdrant", + logo: QDrantLogo, + options: , + description: "Open source local and distributed cloud vector database.", + }, + { + name: "Weaviate", + value: "weaviate", + logo: WeaviateLogo, + options: , + description: + "Open source local and cloud hosted multi-modal vector database.", + }, + ]; + const updateVectorChoice = (selection) => { setHasChanges(true); - setVectorDB(selection); + setSelectedVDB(selection); }; const handleSubmit = async (e) => { e.preventDefault(); - if (vectorDB !== settings?.VectorDB && hasChanges && hasEmbeddings) { + if (selectedVDB !== settings?.VectorDB && hasChanges && hasEmbeddings) { document.getElementById("confirmation-modal")?.showModal(); } else { await handleSaveSettings(); @@ -47,11 +97,11 @@ export default function GeneralVectorDatabase() { const handleSaveSettings = async () => { setSaving(true); - const data = new FormData(document.getElementById("vectordb-form")); + const form = document.getElementById("vectordb-form"); const settingsData = {}; - for (let [key, value] of data.entries()) { - settingsData[key] = value; - } + const formData = new FormData(form); + settingsData.VectorDB = selectedVDB; + for (var [key, value] of formData.entries()) settingsData[key] = value; const { error } = await System.updateSystem(settingsData); if (error) { @@ -65,6 +115,13 @@ export default function GeneralVectorDatabase() { document.getElementById("confirmation-modal")?.close(); }; + useEffect(() => { + const filtered = VECTOR_DBS.filter((vdb) => + vdb.name.toLowerCase().includes(searchQuery.toLowerCase()) + ); + setFilteredVDBs(filtered); + }, [searchQuery, selectedVDB]); + return (
setHasChanges(true)} className="flex w-full" >
@@ -119,236 +175,52 @@ export default function GeneralVectorDatabase() {
Select your preferred vector database provider
-
- - - - - - -
-
- {vectorDB === "pinecone" && ( - <> -
- - +
+
+
+ -
- -
- { + e.preventDefault(); + setSearchQuery(e.target.value); + }} autoComplete="off" - spellCheck={false} + onKeyDown={(e) => { + if (e.key === "Enter") e.preventDefault(); + }} />
- -
- - -
- - )} - - {vectorDB === "chroma" && ( - <> -
- - -
- -
- - -
- -
- - -
- - )} - - {vectorDB === "lancedb" && ( -
-

- There is no configuration needed for LanceDB. -

- )} - - {vectorDB === "qdrant" && ( - <> -
- - + {filteredVDBs.map((vdb) => ( + updateVectorChoice(vdb.value)} /> -
- -
- - -
- - )} - - {vectorDB === "weaviate" && ( - <> -
- - -
- -
- - -
- - )} + ))} +
+
+
setHasChanges(true)} + className="mt-4 flex flex-col gap-y-1" + > + {selectedVDB && + VECTOR_DBS.find((vdb) => vdb.value === selectedVDB) + ?.options} +
diff --git a/frontend/src/pages/OnboardingFlow/Steps/EmbeddingPreference/index.jsx b/frontend/src/pages/OnboardingFlow/Steps/EmbeddingPreference/index.jsx index 058967de..024fc230 100644 --- a/frontend/src/pages/OnboardingFlow/Steps/EmbeddingPreference/index.jsx +++ b/frontend/src/pages/OnboardingFlow/Steps/EmbeddingPreference/index.jsx @@ -8,7 +8,7 @@ import NativeEmbeddingOptions from "@/components/EmbeddingSelection/NativeEmbedd import OpenAiOptions from "@/components/EmbeddingSelection/OpenAiOptions"; import AzureAiOptions from "@/components/EmbeddingSelection/AzureAiOptions"; import LocalAiOptions from "@/components/EmbeddingSelection/LocalAiOptions"; -import EmbedderItem from "./EmbedderItem"; +import EmbedderItem from "@/components/EmbeddingSelection/EmbedderItem"; import System from "@/models/system"; import paths from "@/utils/paths"; import showToast from "@/utils/toast"; @@ -108,22 +108,17 @@ export default function EmbeddingPreference({ }, []); useEffect(() => { - if (searchQuery.trim() === "") { - setFilteredEmbedders(EMBEDDERS); - } else { - const lowercasedQuery = searchQuery.toLowerCase(); - const filtered = EMBEDDERS.filter((embedder) => - embedder.name.toLowerCase().includes(lowercasedQuery) - ); - setFilteredEmbedders(filtered); - } - }, [searchQuery]); + const filtered = EMBEDDERS.filter((embedder) => + embedder.name.toLowerCase().includes(searchQuery.toLowerCase()) + ); + setFilteredEmbedders(filtered); + }, [searchQuery, selectedEmbedder]); return (
-
+
{ - if (searchQuery.trim() === "") { - setFilteredLLMs(LLMS); - } else { - const lowercasedQuery = searchQuery.toLowerCase(); - const filtered = LLMS.filter((llm) => - llm.name.toLowerCase().includes(lowercasedQuery) - ); - setFilteredLLMs(filtered); - } - }, [searchQuery]); + const filtered = LLMS.filter((llm) => + llm.name.toLowerCase().includes(searchQuery.toLowerCase()) + ); + setFilteredLLMs(filtered); + }, [searchQuery, selectedLLM]); return (
-
-
+
+
{ - if (searchQuery.trim() === "") { - setFilteredVDBs(VECTOR_DBS); - } else { - const lowercasedQuery = searchQuery.toLowerCase(); - const filtered = VECTOR_DBS.filter((vdb) => - vdb.name.toLowerCase().includes(lowercasedQuery) - ); - setFilteredVDBs(filtered); - } - }, [searchQuery]); + const filtered = VECTOR_DBS.filter((vdb) => + vdb.name.toLowerCase().includes(searchQuery.toLowerCase()) + ); + setFilteredVDBs(filtered); + }, [searchQuery, selectedVDB]); return ( <>
-
+
{filteredVDBs.map((vdb) => ( -