mirror of
https://github.com/Mintplex-Labs/anything-llm.git
synced 2025-04-17 18:18:11 +00:00
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: timothycarambat <rambat1010@gmail.com>
This commit is contained in:
parent
1e3d82e184
commit
73f342eb19
7 changed files with 150 additions and 32 deletions
frontend/src
components/ChangeWarning
pages/GeneralSettings
server
49
frontend/src/components/ChangeWarning/index.jsx
Normal file
49
frontend/src/components/ChangeWarning/index.jsx
Normal file
|
@ -0,0 +1,49 @@
|
|||
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";
|
|||
import LocalAiLogo from "../../../media/llmprovider/localai.png";
|
||||
import PreLoader from "../../../components/Preloader";
|
||||
import LLMProviderOption from "../../../components/LLMSelection/LLMProviderOption";
|
||||
import ChangeWarningModal from "../../../components/ChangeWarning";
|
||||
|
||||
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);
|
||||
|
@ -22,18 +24,35 @@ export default function GeneralEmbeddingPreference() {
|
|||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
setSaving(true);
|
||||
const data = {};
|
||||
const form = new FormData(e.target);
|
||||
for (var [key, value] of form.entries()) data[key] = value;
|
||||
const { error } = await System.updateSystem(data);
|
||||
if (error) {
|
||||
showToast(`Failed to save embedding preferences: ${error}`, "error");
|
||||
if (
|
||||
embeddingChoice !== settings?.EmbeddingEngine &&
|
||||
hasChanges &&
|
||||
hasEmbeddings
|
||||
) {
|
||||
document.getElementById("confirmation-modal")?.showModal();
|
||||
} else {
|
||||
showToast("Embedding preferences saved successfully.", "success");
|
||||
await handleSaveSettings();
|
||||
}
|
||||
};
|
||||
|
||||
const handleSaveSettings = async () => {
|
||||
setSaving(true);
|
||||
const data = new FormData(document.getElementById("embedding-form"));
|
||||
const settingsData = {};
|
||||
for (let [key, value] of data.entries()) {
|
||||
settingsData[key] = value;
|
||||
}
|
||||
|
||||
const { error } = await System.updateSystem(settingsData);
|
||||
if (error) {
|
||||
showToast(`Failed to save LLM settings: ${error}`, "error");
|
||||
setHasChanges(true);
|
||||
} else {
|
||||
showToast("LLM preferences saved successfully.", "success");
|
||||
setHasChanges(false);
|
||||
}
|
||||
setSaving(false);
|
||||
setHasChanges(!!error);
|
||||
document.getElementById("confirmation-modal")?.close();
|
||||
};
|
||||
|
||||
const updateChoice = (selection) => {
|
||||
|
@ -52,6 +71,7 @@ export default function GeneralEmbeddingPreference() {
|
|||
setEmbeddingChoice(_settings?.EmbeddingEngine || "openai");
|
||||
setBasePath(_settings?.EmbeddingBasePath || "");
|
||||
setBasePathValue(_settings?.EmbeddingBasePath || "");
|
||||
setHasEmbeddings(_settings?.HasExistingEmbeddings || false);
|
||||
setLoading(false);
|
||||
}
|
||||
fetchKeys();
|
||||
|
@ -59,6 +79,11 @@ export default function GeneralEmbeddingPreference() {
|
|||
|
||||
return (
|
||||
<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 />}
|
||||
{loading ? (
|
||||
<div
|
||||
|
@ -76,6 +101,7 @@ export default function GeneralEmbeddingPreference() {
|
|||
>
|
||||
{isMobile && <SidebarMobileHeader />}
|
||||
<form
|
||||
id="embedding-form"
|
||||
onSubmit={handleSubmit}
|
||||
onChange={() => setHasChanges(true)}
|
||||
className="flex w-full"
|
||||
|
|
|
@ -12,10 +12,12 @@ 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";
|
||||
|
||||
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);
|
||||
|
@ -25,6 +27,7 @@ export default function GeneralVectorDatabase() {
|
|||
const _settings = await System.keys();
|
||||
setSettings(_settings);
|
||||
setVectorDB(_settings?.VectorDB || "lancedb");
|
||||
setHasEmbeddings(_settings?.HasExistingEmbeddings || false);
|
||||
setLoading(false);
|
||||
}
|
||||
fetchKeys();
|
||||
|
@ -37,22 +40,40 @@ export default function GeneralVectorDatabase() {
|
|||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
setSaving(true);
|
||||
const data = {};
|
||||
const form = new FormData(e.target);
|
||||
for (var [key, value] of form.entries()) data[key] = value;
|
||||
const { error } = await System.updateSystem(data);
|
||||
if (error) {
|
||||
showToast(`Failed to save settings: ${error}`, "error");
|
||||
if (vectorDB !== settings?.VectorDB && hasChanges && hasEmbeddings) {
|
||||
document.getElementById("confirmation-modal")?.showModal();
|
||||
} else {
|
||||
showToast("Settings saved successfully.", "success");
|
||||
await handleSaveSettings();
|
||||
}
|
||||
};
|
||||
|
||||
const handleSaveSettings = async () => {
|
||||
setSaving(true);
|
||||
const data = new FormData(document.getElementById("vectordb-form"));
|
||||
const settingsData = {};
|
||||
for (let [key, value] of data.entries()) {
|
||||
settingsData[key] = value;
|
||||
}
|
||||
|
||||
const { error } = await System.updateSystem(settingsData);
|
||||
if (error) {
|
||||
showToast(`Failed to save LLM settings: ${error}`, "error");
|
||||
setHasChanges(true);
|
||||
} else {
|
||||
showToast("LLM preferences saved successfully.", "success");
|
||||
setHasChanges(false);
|
||||
}
|
||||
setSaving(false);
|
||||
setHasChanges(!!error);
|
||||
document.getElementById("confirmation-modal")?.close();
|
||||
};
|
||||
|
||||
return (
|
||||
<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 />}
|
||||
{loading ? (
|
||||
<div
|
||||
|
@ -70,6 +91,7 @@ export default function GeneralVectorDatabase() {
|
|||
>
|
||||
{isMobile && <SidebarMobileHeader />}
|
||||
<form
|
||||
id="vectordb-form"
|
||||
onSubmit={handleSubmit}
|
||||
onChange={() => setHasChanges(true)}
|
||||
className="flex w-full"
|
||||
|
|
|
@ -66,13 +66,11 @@ function adminEndpoints(app) {
|
|||
) {
|
||||
const adminCount = await User.count({ role: "admin" });
|
||||
if (adminCount - 1 <= 0) {
|
||||
response
|
||||
.status(200)
|
||||
.json({
|
||||
success: false,
|
||||
error:
|
||||
"No system admins will remain if you do this. Update failed.",
|
||||
});
|
||||
response.status(200).json({
|
||||
success: false,
|
||||
error:
|
||||
"No system admins will remain if you do this. Update failed.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -208,13 +208,11 @@ function apiAdminEndpoints(app) {
|
|||
) {
|
||||
const adminCount = await User.count({ role: "admin" });
|
||||
if (adminCount - 1 <= 0) {
|
||||
response
|
||||
.status(200)
|
||||
.json({
|
||||
success: false,
|
||||
error:
|
||||
"No system admins will remain if you do this. Update failed.",
|
||||
});
|
||||
response.status(200).json({
|
||||
success: false,
|
||||
error:
|
||||
"No system admins will remain if you do this. Update failed.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -109,6 +109,19 @@ const Document = {
|
|||
});
|
||||
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 };
|
||||
|
|
|
@ -24,6 +24,7 @@ const SystemSettings = {
|
|||
StorageDir: process.env.STORAGE_DIR,
|
||||
MultiUserMode: await this.isMultiUserMode(),
|
||||
VectorDB: vectorDB,
|
||||
HasExistingEmbeddings: await this.hasEmbeddings(),
|
||||
EmbeddingEngine: process.env.EMBEDDING_ENGINE,
|
||||
EmbeddingBasePath: process.env.EMBEDDING_BASE_PATH,
|
||||
EmbeddingModelPref: process.env.EMBEDDING_MODEL_PREF,
|
||||
|
@ -190,6 +191,17 @@ const SystemSettings = {
|
|||
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;
|
||||
|
|
Loading…
Add table
Reference in a new issue