diff --git a/pkg/api/http/controller/groups/knowledge/base.py b/pkg/api/http/controller/groups/knowledge/base.py index 5fd80cbd..a5bed5df 100644 --- a/pkg/api/http/controller/groups/knowledge/base.py +++ b/pkg/api/http/controller/groups/knowledge/base.py @@ -20,7 +20,7 @@ class KnowledgeBaseRouterGroup(group.RouterGroup): @self.route( '/', - methods=['GET', 'DELETE'], + methods=['GET', 'DELETE', 'PUT'], ) async def handle_specific_knowledge_base(knowledge_base_uuid: str) -> quart.Response: if quart.request.method == 'GET': @@ -34,6 +34,12 @@ class KnowledgeBaseRouterGroup(group.RouterGroup): 'base': knowledge_base, } ) + + elif quart.request.method == 'PUT': + json_data = await quart.request.json + await self.ap.knowledge_service.update_knowledge_base(knowledge_base_uuid, json_data) + return self.success({}) + elif quart.request.method == 'DELETE': await self.ap.knowledge_service.delete_knowledge_base(knowledge_base_uuid) return self.success({}) diff --git a/pkg/api/http/service/knowledge.py b/pkg/api/http/service/knowledge.py index b604e0ed..27506ec9 100644 --- a/pkg/api/http/service/knowledge.py +++ b/pkg/api/http/service/knowledge.py @@ -47,12 +47,18 @@ class KnowledgeService: async def update_knowledge_base(self, kb_uuid: str, kb_data: dict) -> None: """更新知识库""" + if 'uuid' in kb_data: + del kb_data['uuid'] + + if 'embedding_model_uuid' in kb_data: + del kb_data['embedding_model_uuid'] + await self.ap.persistence_mgr.execute_async( sqlalchemy.update(persistence_rag.KnowledgeBase) .values(kb_data) .where(persistence_rag.KnowledgeBase.uuid == kb_uuid) ) - await self.ap.rag_mgr.remove_knowledge_base(kb_uuid) + await self.ap.rag_mgr.remove_knowledge_base_from_runtime(kb_uuid) kb = await self.get_knowledge_base(kb_uuid) @@ -91,7 +97,7 @@ class KnowledgeService: async def delete_knowledge_base(self, kb_uuid: str) -> None: """删除知识库""" - await self.ap.rag_mgr.remove_knowledge_base(kb_uuid) + await self.ap.rag_mgr.delete_knowledge_base(kb_uuid) await self.ap.persistence_mgr.execute_async( sqlalchemy.delete(persistence_rag.KnowledgeBase).where(persistence_rag.KnowledgeBase.uuid == kb_uuid) diff --git a/pkg/provider/runners/localagent.py b/pkg/provider/runners/localagent.py index ad1ac486..1d3e88ac 100644 --- a/pkg/provider/runners/localagent.py +++ b/pkg/provider/runners/localagent.py @@ -33,6 +33,9 @@ class LocalAgentRunner(runner.RequestRunner): kb_uuid = query.pipeline_config['ai']['local-agent']['knowledge-base'] + if kb_uuid == '__none__': + kb_uuid = None + user_message = copy.deepcopy(query.user_message) user_message_text = '' diff --git a/pkg/rag/knowledge/kbmgr.py b/pkg/rag/knowledge/kbmgr.py index 24f98ea2..a9e7e57a 100644 --- a/pkg/rag/knowledge/kbmgr.py +++ b/pkg/rag/knowledge/kbmgr.py @@ -198,7 +198,13 @@ class RAGManager: return kb return None - async def remove_knowledge_base(self, kb_uuid: str): + async def remove_knowledge_base_from_runtime(self, kb_uuid: str): + for kb in self.knowledge_bases: + if kb.knowledge_base_entity.uuid == kb_uuid: + self.knowledge_bases.remove(kb) + return + + async def delete_knowledge_base(self, kb_uuid: str): for kb in self.knowledge_bases: if kb.knowledge_base_entity.uuid == kb_uuid: await kb.dispose() diff --git a/pkg/vector/vdbs/chroma.py b/pkg/vector/vdbs/chroma.py index d7e705e5..41ab7d36 100644 --- a/pkg/vector/vdbs/chroma.py +++ b/pkg/vector/vdbs/chroma.py @@ -5,6 +5,7 @@ from chromadb import PersistentClient from pkg.vector.vdb import VectorDatabase from pkg.core import app import chromadb +import chromadb.errors class ChromaVectorDatabase(VectorDatabase): @@ -51,5 +52,10 @@ class ChromaVectorDatabase(VectorDatabase): async def delete_collection(self, collection: str): if collection in self._collections: del self._collections[collection] - await asyncio.to_thread(self.client.delete_collection, name=collection) + + try: + await asyncio.to_thread(self.client.delete_collection, name=collection) + except chromadb.errors.NotFoundError: + self.ap.logger.warning(f"Chroma collection '{collection}' not found.") + return self.ap.logger.info(f"Chroma collection '{collection}' deleted.") diff --git a/templates/metadata/pipeline/ai.yaml b/templates/metadata/pipeline/ai.yaml index 5f5dea5b..ffbefe63 100644 --- a/templates/metadata/pipeline/ai.yaml +++ b/templates/metadata/pipeline/ai.yaml @@ -72,6 +72,9 @@ stages: label: en_US: Knowledge Base zh_Hans: 知识库 + description: + en_US: Configure the knowledge base to use for the agent, if not selected, the agent will directly use the LLM to reply + zh_Hans: 配置用于提升回复质量的知识库,若不选择,则直接使用大模型回复 type: knowledge-base-selector required: false default: '' diff --git a/web/src/app/home/components/dynamic-form/DynamicFormItemComponent.tsx b/web/src/app/home/components/dynamic-form/DynamicFormItemComponent.tsx index b613e05f..31eb137a 100644 --- a/web/src/app/home/components/dynamic-form/DynamicFormItemComponent.tsx +++ b/web/src/app/home/components/dynamic-form/DynamicFormItemComponent.tsx @@ -51,7 +51,7 @@ export default function DynamicFormItemComponent({ }); } }, [config.type]); - + useEffect(() => { if (config.type === DynamicFormItemType.KNOWLEDGE_BASE_SELECTOR) { httpClient @@ -272,28 +272,11 @@ export default function DynamicFormItemComponent({ - {/* {t('knowledge.empty')} */} + {t('knowledge.empty')} {knowledgeBases.map((base) => ( - - - {base.name} - - -
-
-

{base.name}

-
-

- {base.description} -

-
-
-
+ + {base.name} + ))}
diff --git a/web/src/app/home/knowledge/KBDetailDialog.tsx b/web/src/app/home/knowledge/KBDetailDialog.tsx index 3854e933..30f903dc 100644 --- a/web/src/app/home/knowledge/KBDetailDialog.tsx +++ b/web/src/app/home/knowledge/KBDetailDialog.tsx @@ -36,6 +36,7 @@ interface KBDetailDialogProps { onFormCancel: () => void; onKbDeleted: () => void; onNewKbCreated: (kbId: string) => void; + onKbUpdated: (kbId: string) => void; } export default function KBDetailDialog({ @@ -46,6 +47,7 @@ export default function KBDetailDialog({ onFormCancel, onKbDeleted, onNewKbCreated, + onKbUpdated, }: KBDetailDialogProps) { const { t } = useTranslation(); const [kbId, setKbId] = useState(propKbId); @@ -111,6 +113,7 @@ export default function KBDetailDialog({ onFormCancel={onFormCancel} onKbDeleted={onKbDeleted} onNewKbCreated={onNewKbCreated} + onKbUpdated={onKbUpdated} /> )} {activeMenu === 'documents' &&
documents
} @@ -185,6 +188,7 @@ export default function KBDetailDialog({ onFormCancel={onFormCancel} onKbDeleted={onKbDeleted} onNewKbCreated={onNewKbCreated} + onKbUpdated={onKbUpdated} /> )} {activeMenu === 'documents' && } diff --git a/web/src/app/home/knowledge/components/kb-docs/KBDoc.tsx b/web/src/app/home/knowledge/components/kb-docs/KBDoc.tsx index 0a779112..6ed6998d 100644 --- a/web/src/app/home/knowledge/components/kb-docs/KBDoc.tsx +++ b/web/src/app/home/knowledge/components/kb-docs/KBDoc.tsx @@ -28,7 +28,7 @@ export default function KBDoc({ kbId }: { kbId: string }) { setDocumentsList( resp.files.map((file: KnowledgeBaseFile) => { return { - id: file.id, + uuid: file.uuid, name: file.file_name, status: file.status, }; diff --git a/web/src/app/home/knowledge/components/kb-docs/documents/columns.tsx b/web/src/app/home/knowledge/components/kb-docs/documents/columns.tsx index 0a43cf8f..648519d9 100644 --- a/web/src/app/home/knowledge/components/kb-docs/documents/columns.tsx +++ b/web/src/app/home/knowledge/components/kb-docs/documents/columns.tsx @@ -14,7 +14,7 @@ import { import { useTranslation } from 'react-i18next'; export type DocumentFile = { - id: string; + uuid: string; name: string; status: string; }; @@ -52,7 +52,7 @@ export const columns = ( {t('knowledge.documentsTab.actions')} - onDelete(document.id)}> + onDelete(document.uuid)}> {t('knowledge.documentsTab.delete')} diff --git a/web/src/app/home/knowledge/components/kb-form/KBForm.tsx b/web/src/app/home/knowledge/components/kb-form/KBForm.tsx index b56c327b..b2db4aca 100644 --- a/web/src/app/home/knowledge/components/kb-form/KBForm.tsx +++ b/web/src/app/home/knowledge/components/kb-form/KBForm.tsx @@ -24,6 +24,7 @@ import { SelectValue, } from '@/components/ui/select'; import { KnowledgeBase } from '@/app/infra/entities/api'; +import { toast } from 'sonner'; const getFormSchema = (t: (key: string) => string) => z.object({ @@ -42,6 +43,7 @@ export default function KBForm({ onFormCancel, onKbDeleted, onNewKbCreated, + onKbUpdated, }: { initKbId?: string; // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -49,6 +51,7 @@ export default function KBForm({ onFormCancel: () => void; onKbDeleted: () => void; onNewKbCreated: (kbId: string) => void; + onKbUpdated: (kbId: string) => void; }) { const { t } = useTranslation(); const formSchema = getFormSchema(t); @@ -114,6 +117,17 @@ export default function KBForm({ description: data.description, embedding_model_uuid: data.embeddingModelUUID, }; + httpClient + .updateKnowledgeBase(initKbId, updateKb) + .then((res) => { + console.log('update knowledge base success', res); + onKbUpdated(res.uuid); + toast.success(t('knowledge.updateKnowledgeBaseSuccess')); + }) + .catch((err) => { + console.error('update knowledge base failed', err); + toast.error(t('knowledge.updateKnowledgeBaseFailed')); + }); } else { // create knowledge base const newKb: KnowledgeBase = { @@ -186,6 +200,7 @@ export default function KBForm({