Skip to content
Snippets Groups Projects
Unverified Commit 73f342eb authored by Sean Hatfield's avatar Sean Hatfield Committed by GitHub
Browse files

Warning about switching embedder or vectordb (#385)


* added warning modal to LLM preference

* added warning modal for changing embedder

* remove warning from LLM preference & add warning to vector database selection

* linting

* remove comments and move warning modal to component

---------

Co-authored-by: default avatartimothycarambat <rambat1010@gmail.com>
parent 1e3d82e1
No related branches found
No related tags found
No related merge requests found
import { Warning } from "@phosphor-icons/react";
export default function ChangeWarningModal({
warningText = "",
onClose,
onConfirm,
}) {
return (
<dialog id="confirmation-modal" className="bg-transparent outline-none">
<div className="relative w-full max-w-2xl max-h-full">
<div className="relative bg-main-gradient rounded-lg shadow">
<div className="flex items-start justify-between p-4 border-b rounded-t border-gray-500/50">
<div className="flex items-center gap-2">
<Warning
className="text-yellow-300 text-lg w-6 h-6"
weight="fill"
/>
<h3 className="text-xl font-semibold text-yellow-300">Warning</h3>
</div>
</div>
<div className="w-[550px] p-6 text-white">
<p>
{warningText}
<br />
<br />
Are you sure you want to proceed?
</p>
</div>
<div className="flex w-full justify-between items-center p-6 space-x-2 border-t rounded-b border-gray-500/50">
<button
onClick={onClose}
type="button"
className="px-4 py-2 rounded-lg text-white hover:bg-red-500 transition-all duration-300"
>
Cancel
</button>
<button
onClick={onConfirm}
className="transition-all duration-300 border border-slate-200 px-4 py-2 rounded-lg text-white text-sm items-center flex gap-x-2 hover:bg-slate-200 hover:text-slate-800 focus:ring-gray-800"
>
Confirm
</button>
</div>
</div>
</div>
</dialog>
);
}
...@@ -10,10 +10,12 @@ import AzureOpenAiLogo from "../../../media/llmprovider/azure.png"; ...@@ -10,10 +10,12 @@ 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 LLMProviderOption from "../../../components/LLMSelection/LLMProviderOption";
import ChangeWarningModal from "../../../components/ChangeWarning";
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 [embeddingChoice, setEmbeddingChoice] = useState("openai"); 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);
...@@ -22,18 +24,35 @@ export default function GeneralEmbeddingPreference() { ...@@ -22,18 +24,35 @@ export default function GeneralEmbeddingPreference() {
const handleSubmit = async (e) => { const handleSubmit = async (e) => {
e.preventDefault(); e.preventDefault();
if (
embeddingChoice !== settings?.EmbeddingEngine &&
hasChanges &&
hasEmbeddings
) {
document.getElementById("confirmation-modal")?.showModal();
} else {
await handleSaveSettings();
}
};
const handleSaveSettings = async () => {
setSaving(true); setSaving(true);
const data = {}; const data = new FormData(document.getElementById("embedding-form"));
const form = new FormData(e.target); const settingsData = {};
for (var [key, value] of form.entries()) data[key] = value; for (let [key, value] of data.entries()) {
const { error } = await System.updateSystem(data); settingsData[key] = value;
}
const { error } = await System.updateSystem(settingsData);
if (error) { if (error) {
showToast(`Failed to save embedding preferences: ${error}`, "error"); showToast(`Failed to save LLM settings: ${error}`, "error");
setHasChanges(true);
} else { } else {
showToast("Embedding preferences saved successfully.", "success"); showToast("LLM preferences saved successfully.", "success");
setHasChanges(false);
} }
setSaving(false); setSaving(false);
setHasChanges(!!error); document.getElementById("confirmation-modal")?.close();
}; };
const updateChoice = (selection) => { const updateChoice = (selection) => {
...@@ -52,6 +71,7 @@ export default function GeneralEmbeddingPreference() { ...@@ -52,6 +71,7 @@ export default function GeneralEmbeddingPreference() {
setEmbeddingChoice(_settings?.EmbeddingEngine || "openai"); setEmbeddingChoice(_settings?.EmbeddingEngine || "openai");
setBasePath(_settings?.EmbeddingBasePath || ""); setBasePath(_settings?.EmbeddingBasePath || "");
setBasePathValue(_settings?.EmbeddingBasePath || ""); setBasePathValue(_settings?.EmbeddingBasePath || "");
setHasEmbeddings(_settings?.HasExistingEmbeddings || false);
setLoading(false); setLoading(false);
} }
fetchKeys(); fetchKeys();
...@@ -59,6 +79,11 @@ export default function GeneralEmbeddingPreference() { ...@@ -59,6 +79,11 @@ export default function GeneralEmbeddingPreference() {
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
warningText=" Switching the embedder may affect previously embedded documents and future similarity search results."
onClose={() => document.getElementById("confirmation-modal")?.close()}
onConfirm={handleSaveSettings}
/>
{!isMobile && <Sidebar />} {!isMobile && <Sidebar />}
{loading ? ( {loading ? (
<div <div
...@@ -76,6 +101,7 @@ export default function GeneralEmbeddingPreference() { ...@@ -76,6 +101,7 @@ export default function GeneralEmbeddingPreference() {
> >
{isMobile && <SidebarMobileHeader />} {isMobile && <SidebarMobileHeader />}
<form <form
id="embedding-form"
onSubmit={handleSubmit} onSubmit={handleSubmit}
onChange={() => setHasChanges(true)} onChange={() => setHasChanges(true)}
className="flex w-full" className="flex w-full"
......
...@@ -12,10 +12,12 @@ import WeaviateLogo from "../../../media/vectordbs/weaviate.png"; ...@@ -12,10 +12,12 @@ 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 VectorDBOption from "../../../components/VectorDBOption";
import ChangeWarningModal from "../../../components/ChangeWarning";
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 [vectorDB, setVectorDB] = useState("lancedb"); const [vectorDB, setVectorDB] = useState("lancedb");
const [settings, setSettings] = useState({}); const [settings, setSettings] = useState({});
const [loading, setLoading] = useState(true); const [loading, setLoading] = useState(true);
...@@ -25,6 +27,7 @@ export default function GeneralVectorDatabase() { ...@@ -25,6 +27,7 @@ export default function GeneralVectorDatabase() {
const _settings = await System.keys(); const _settings = await System.keys();
setSettings(_settings); setSettings(_settings);
setVectorDB(_settings?.VectorDB || "lancedb"); setVectorDB(_settings?.VectorDB || "lancedb");
setHasEmbeddings(_settings?.HasExistingEmbeddings || false);
setLoading(false); setLoading(false);
} }
fetchKeys(); fetchKeys();
...@@ -37,22 +40,40 @@ export default function GeneralVectorDatabase() { ...@@ -37,22 +40,40 @@ export default function GeneralVectorDatabase() {
const handleSubmit = async (e) => { const handleSubmit = async (e) => {
e.preventDefault(); e.preventDefault();
if (vectorDB !== settings?.VectorDB && hasChanges && hasEmbeddings) {
document.getElementById("confirmation-modal")?.showModal();
} else {
await handleSaveSettings();
}
};
const handleSaveSettings = async () => {
setSaving(true); setSaving(true);
const data = {}; const data = new FormData(document.getElementById("vectordb-form"));
const form = new FormData(e.target); const settingsData = {};
for (var [key, value] of form.entries()) data[key] = value; for (let [key, value] of data.entries()) {
const { error } = await System.updateSystem(data); settingsData[key] = value;
}
const { error } = await System.updateSystem(settingsData);
if (error) { if (error) {
showToast(`Failed to save settings: ${error}`, "error"); showToast(`Failed to save LLM settings: ${error}`, "error");
setHasChanges(true);
} else { } else {
showToast("Settings saved successfully.", "success"); showToast("LLM preferences saved successfully.", "success");
setHasChanges(false);
} }
setSaving(false); setSaving(false);
setHasChanges(!!error); document.getElementById("confirmation-modal")?.close();
}; };
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
warningText="Switching the vector database will ignore previously embedded documents and future similarity search results. They will need to be re-added to each workspace."
onClose={() => document.getElementById("confirmation-modal")?.close()}
onConfirm={handleSaveSettings}
/>
{!isMobile && <Sidebar />} {!isMobile && <Sidebar />}
{loading ? ( {loading ? (
<div <div
...@@ -70,6 +91,7 @@ export default function GeneralVectorDatabase() { ...@@ -70,6 +91,7 @@ export default function GeneralVectorDatabase() {
> >
{isMobile && <SidebarMobileHeader />} {isMobile && <SidebarMobileHeader />}
<form <form
id="vectordb-form"
onSubmit={handleSubmit} onSubmit={handleSubmit}
onChange={() => setHasChanges(true)} onChange={() => setHasChanges(true)}
className="flex w-full" className="flex w-full"
......
...@@ -66,13 +66,11 @@ function adminEndpoints(app) { ...@@ -66,13 +66,11 @@ function adminEndpoints(app) {
) { ) {
const adminCount = await User.count({ role: "admin" }); const adminCount = await User.count({ role: "admin" });
if (adminCount - 1 <= 0) { if (adminCount - 1 <= 0) {
response response.status(200).json({
.status(200) success: false,
.json({ error:
success: false, "No system admins will remain if you do this. Update failed.",
error: });
"No system admins will remain if you do this. Update failed.",
});
return; return;
} }
} }
......
...@@ -208,13 +208,11 @@ function apiAdminEndpoints(app) { ...@@ -208,13 +208,11 @@ function apiAdminEndpoints(app) {
) { ) {
const adminCount = await User.count({ role: "admin" }); const adminCount = await User.count({ role: "admin" });
if (adminCount - 1 <= 0) { if (adminCount - 1 <= 0) {
response response.status(200).json({
.status(200) success: false,
.json({ error:
success: false, "No system admins will remain if you do this. Update failed.",
error: });
"No system admins will remain if you do this. Update failed.",
});
return; return;
} }
} }
......
...@@ -109,6 +109,19 @@ const Document = { ...@@ -109,6 +109,19 @@ const Document = {
}); });
return true; return true;
}, },
count: async function (clause = {}, limit = null) {
try {
const count = await prisma.workspace_documents.count({
where: clause,
...(limit !== null ? { take: limit } : {}),
});
return count;
} catch (error) {
console.error("FAILED TO COUNT DOCUMENTS.", error.message);
return 0;
}
},
}; };
module.exports = { Document }; module.exports = { Document };
...@@ -24,6 +24,7 @@ const SystemSettings = { ...@@ -24,6 +24,7 @@ const SystemSettings = {
StorageDir: process.env.STORAGE_DIR, StorageDir: process.env.STORAGE_DIR,
MultiUserMode: await this.isMultiUserMode(), MultiUserMode: await this.isMultiUserMode(),
VectorDB: vectorDB, VectorDB: vectorDB,
HasExistingEmbeddings: await this.hasEmbeddings(),
EmbeddingEngine: process.env.EMBEDDING_ENGINE, EmbeddingEngine: process.env.EMBEDDING_ENGINE,
EmbeddingBasePath: process.env.EMBEDDING_BASE_PATH, EmbeddingBasePath: process.env.EMBEDDING_BASE_PATH,
EmbeddingModelPref: process.env.EMBEDDING_MODEL_PREF, EmbeddingModelPref: process.env.EMBEDDING_MODEL_PREF,
...@@ -190,6 +191,17 @@ const SystemSettings = { ...@@ -190,6 +191,17 @@ const SystemSettings = {
return false; return false;
} }
}, },
hasEmbeddings: async function () {
try {
const { Document } = require("./documents");
const count = await Document.count({}, 1);
return count > 0;
} catch (error) {
console.error(error.message);
return false;
}
},
}; };
module.exports.SystemSettings = SystemSettings; module.exports.SystemSettings = SystemSettings;
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment