diff --git a/web/static/i18n/en-US.json b/web/static/i18n/en-US.json index b7d34ac9..a2ba619b 100644 --- a/web/static/i18n/en-US.json +++ b/web/static/i18n/en-US.json @@ -1405,8 +1405,10 @@ "totalItems": "Total items", "categories": "Categories", "addKnowledge": "Add knowledge", - "rebuildIndex": "Rebuild index", - "rebuildIndexConfirm": "Rebuild index?", + "buildIndex": "Build index", + "buildIndexConfirm": "Build vectors for knowledge items that are not indexed yet?", + "rebuildIndexFull": "Full rebuild", + "rebuildIndexFullConfirm": "Re-index all knowledge items? This may take a while.", "deleteItemConfirm": "Delete this knowledge item?", "notEnabledTitle": "Knowledge base function not enabled", "notEnabledHint": "Please go to system settings to enable knowledge retrieval.", @@ -1653,7 +1655,7 @@ "updateKnowledgeItem": "Update knowledge item", "deleteKnowledgeItem": "Delete knowledge item", "getIndexStatus": "Get index status", - "rebuildIndex": "Rebuild index", + "startKnowledgeIndex": "Build index", "scanKnowledgeBase": "Scan knowledge base", "searchKnowledgeBase": "Search knowledge base", "basicSearch": "Basic search", @@ -2469,7 +2471,8 @@ "connection_create": "Create connection", "connection_delete": "Delete connection", "item_delete": "Delete knowledge item", - "index_rebuild": "Rebuild index", + "index_build": "Build knowledge index", + "index_rebuild_full": "Full knowledge index rebuild", "delete": "Delete", "delete_turn": "Delete turn", "create": "Create", @@ -2542,7 +2545,8 @@ }, "knowledge": { "item_delete": "Knowledge item deleted", - "index_rebuild": "Knowledge index rebuilt" + "index_build": "Knowledge index built", + "index_rebuild_full": "Knowledge index fully rebuilt" }, "vulnerability": { "create": "Vulnerability record created", diff --git a/web/static/i18n/zh-CN.json b/web/static/i18n/zh-CN.json index 346a32c8..36a3b9f6 100644 --- a/web/static/i18n/zh-CN.json +++ b/web/static/i18n/zh-CN.json @@ -1393,8 +1393,10 @@ "totalItems": "总知识项", "categories": "分类数", "addKnowledge": "添加知识", - "rebuildIndex": "重建索引", - "rebuildIndexConfirm": "确定要重建索引吗?", + "buildIndex": "构建索引", + "buildIndexConfirm": "将为尚未生成向量的知识项构建索引,是否继续?", + "rebuildIndexFull": "全量重建", + "rebuildIndexFullConfirm": "将重新索引全部知识项,这可能需要较长时间,是否继续?", "deleteItemConfirm": "确定要删除这个知识项吗?", "notEnabledTitle": "知识库功能未启用", "notEnabledHint": "请前往系统设置启用知识检索功能", @@ -1641,7 +1643,7 @@ "updateKnowledgeItem": "更新知识项", "deleteKnowledgeItem": "删除知识项", "getIndexStatus": "获取索引状态", - "rebuildIndex": "重建索引", + "startKnowledgeIndex": "构建索引", "scanKnowledgeBase": "扫描知识库", "searchKnowledgeBase": "搜索知识库", "basicSearch": "基础搜索", @@ -2457,7 +2459,8 @@ "connection_create": "创建连接", "connection_delete": "删除连接", "item_delete": "删除知识项", - "index_rebuild": "重建索引", + "index_build": "构建知识库索引", + "index_rebuild_full": "全量重建知识库索引", "delete": "删除", "delete_turn": "删除轮次", "create": "创建", @@ -2530,7 +2533,8 @@ }, "knowledge": { "item_delete": "删除知识项", - "index_rebuild": "重建知识库索引" + "index_build": "构建知识库索引", + "index_rebuild_full": "全量重建知识库索引" }, "vulnerability": { "create": "创建漏洞记录", diff --git a/web/static/js/audit.js b/web/static/js/audit.js index a252df1e..c2d41327 100644 --- a/web/static/js/audit.js +++ b/web/static/js/audit.js @@ -15,7 +15,7 @@ const AUDIT_ACTIONS_BY_CATEGORY = { c2: ['listener_create', 'listener_delete', 'listener_start', 'listener_stop', 'session_delete', 'task_create', 'task_cancel', 'task_delete'], webshell: ['connection_create', 'connection_delete'], - knowledge: ['item_delete', 'index_rebuild'], + knowledge: ['item_delete', 'index_build', 'index_rebuild_full'], conversation: ['create', 'delete', 'delete_turn'], vulnerability: ['create', 'update', 'delete'], external_mcp: ['upsert', 'delete'], diff --git a/web/static/js/knowledge.js b/web/static/js/knowledge.js index 37db2add..33a51450 100644 --- a/web/static/js/knowledge.js +++ b/web/static/js/knowledge.js @@ -495,8 +495,8 @@ async function updateIndexProgress() {
可能的原因:嵌入模型配置错误、API密钥无效、余额不足等。请检查配置后重试。
-
- + ' : ''} +
`; @@ -842,59 +855,87 @@ async function refreshKnowledgeBase() { } } -// 重建索引 -async function rebuildKnowledgeIndex() { - try { - if (!confirm('确定要重建索引吗?这可能需要一些时间。')) { - return; - } - showNotification('正在重建索引...', 'info'); - - // 先停止现有的轮询 - if (indexProgressInterval) { - clearInterval(indexProgressInterval); - indexProgressInterval = null; - } - - // 立即显示"正在重建"状态,因为重建开始时会清空旧索引 - const progressContainer = document.getElementById('knowledge-index-progress'); - if (progressContainer) { - progressContainer.style.display = 'block'; - progressContainer.innerHTML = ` -
-
- 🔨 - 正在重建索引: 准备中... -
-
-
-
-
索引构建完成后,语义搜索功能将可用
+// 启动知识库索引任务(mode: missing | full) +async function startKnowledgeIndexJob(mode = 'missing') { + const fullRebuild = mode === 'full'; + const confirmMessage = fullRebuild + ? '将重新索引全部知识项,这可能需要较长时间,是否继续?' + : '将为尚未生成向量的知识项构建索引,是否继续?'; + if (!confirm(confirmMessage)) { + return; + } + + const actionLabel = fullRebuild ? '全量重建索引' : '构建索引'; + showNotification(`正在启动${actionLabel}...`, 'info'); + + if (indexProgressInterval) { + clearInterval(indexProgressInterval); + indexProgressInterval = null; + } + + const progressContainer = document.getElementById('knowledge-index-progress'); + if (progressContainer) { + progressContainer.style.display = 'block'; + progressContainer.innerHTML = ` +
+
+ 🔨 + 正在${actionLabel}: 准备中...
- `; - } - - const response = await apiFetch('/api/knowledge/index', { - method: 'POST' - }); - if (!response.ok) { - throw new Error('重建索引失败'); - } - showNotification('索引重建已开始,将在后台进行', 'success'); - - // 等待一小段时间,确保后端已经开始处理并清空了旧索引 - await new Promise(resolve => setTimeout(resolve, 500)); - - // 立即更新一次进度 +
+
+
+
索引构建完成后,语义搜索功能将可用
+
+ `; + } + + const query = fullRebuild ? '?mode=full' : ''; + const response = await apiFetch(`/api/knowledge/index${query}`, { + method: 'POST' + }); + + let payload = {}; + try { + payload = await response.json(); + } catch (_) { + payload = {}; + } + + if (response.status === 409) { + showNotification(payload.error || '已有索引任务正在进行,请等待完成', 'warning'); updateIndexProgress(); - - // 开始轮询进度(每2秒刷新一次,比默认的3秒更频繁) - if (!indexProgressInterval) { - indexProgressInterval = setInterval(updateIndexProgress, 2000); - } + return; + } + if (!response.ok) { + throw new Error(payload.error || `${actionLabel}失败`); + } + + showNotification(payload.message || `${actionLabel}已开始,将在后台进行`, 'success'); + await new Promise(resolve => setTimeout(resolve, 500)); + updateIndexProgress(); + if (!indexProgressInterval) { + indexProgressInterval = setInterval(updateIndexProgress, 2000); + } +} + +// 构建索引(默认:仅处理尚无向量的知识项) +async function buildKnowledgeIndex() { + try { + await startKnowledgeIndexJob('missing'); } catch (error) { - console.error('重建索引失败:', error); - showNotification('重建索引失败: ' + error.message, 'error'); + console.error('构建索引失败:', error); + showNotification('构建索引失败: ' + error.message, 'error'); + } +} + +// 全量重建索引(显式 opt-in) +async function rebuildKnowledgeIndexFull() { + try { + await startKnowledgeIndexJob('full'); + } catch (error) { + console.error('全量重建索引失败:', error); + showNotification('全量重建索引失败: ' + error.message, 'error'); } } diff --git a/web/templates/index.html b/web/templates/index.html index 27e74d28..089bb097 100644 --- a/web/templates/index.html +++ b/web/templates/index.html @@ -1509,7 +1509,8 @@

知识管理

- + +