diff --git a/src/lib/apis/knowledge/index.ts b/src/lib/apis/knowledge/index.ts index f436cb86bb..dfbd671413 100644 --- a/src/lib/apis/knowledge/index.ts +++ b/src/lib/apis/knowledge/index.ts @@ -246,6 +246,7 @@ export const syncFileToKnowledgeById = async (token: string, id: string, fileId: return res; }; + export const updateFileFromKnowledgeById = async (token: string, id: string, fileId: string) => { let error = null; @@ -281,10 +282,17 @@ export const updateFileFromKnowledgeById = async (token: string, id: string, fil return res; }; -export const removeFileFromKnowledgeById = async (token: string, id: string, fileId: string) => { +export const removeFileFromKnowledgeById = async ( + token: string, + id: string, + fileId: string, + deleteFile: boolean = true +) => { let error = null; - const res = await fetch(`${WEBUI_API_BASE_URL}/knowledge/${id}/file/remove`, { + const res = await fetch( + `${WEBUI_API_BASE_URL}/knowledge/${id}/file/remove?delete_file=${deleteFile}`, + { method: 'POST', headers: { Accept: 'application/json', diff --git a/src/lib/components/workspace/Knowledge/KnowledgeBase.svelte b/src/lib/components/workspace/Knowledge/KnowledgeBase.svelte index 86ed49e420..508428cd7d 100644 --- a/src/lib/components/workspace/Knowledge/KnowledgeBase.svelte +++ b/src/lib/components/workspace/Knowledge/KnowledgeBase.svelte @@ -79,6 +79,7 @@ let inputFiles = null; let syncMode = false; + let syncCollectedNames: Set = new Set(); let filteredItems = []; $: if (knowledge && knowledge.files) { @@ -129,6 +130,16 @@ const uploadFileHandler = async (file) => { console.log(file); + // When syncing a directory, remember each file's relative name used on upload. + if (syncMode) { + try { + // Track only base names to match server-side storage + const baseName = file.name?.split(/[\\/]/).pop() ?? file.name; + syncCollectedNames.add(baseName); + } catch (_) { + // no-op + } + } const tempItemId = uuidv4(); const fileItem = { @@ -389,8 +400,31 @@ // Helper function to maintain file paths within zip const syncDirectoryHandler = async () => { syncMode = true; + syncCollectedNames = new Set(); try { await uploadDirectoryHandler(); + + // After uploading and per-file syncs, remove KB files that are not present in the directory + const dirNames = new Set(Array.from(syncCollectedNames)); + const currentFiles = knowledge?.files ?? []; + const toRemove = currentFiles.filter((f) => !dirNames.has(f?.meta?.name ?? f?.filename)); + + for (const f of toRemove) { + // First remove from knowledge (and KB vectors) but keep file record + const updated = await removeFileFromKnowledgeById(localStorage.token, id, f.id, false).catch((e) => { + toast.error(`${e}`); + return null; + }); + if (updated) { + knowledge = updated; + } + + // Then delete the actual file (removes per-file vectors and storage) + await deleteFileById(localStorage.token, f.id).catch((e) => { + console.error(e); + }); + } + toast.success($i18n.t('Directory sync completed.')); } finally { syncMode = false; @@ -652,7 +686,7 @@ { syncDirectoryHandler();