feat(pkb): Replace Dify with self-developed pgvector RAG engine
Major milestone: Successfully replaced Dify external service with PostgreSQL + pgvector RAG engine Backend changes: - Refactor ragService.ts: Remove dual-track mode, keep only pgvector - Refactor knowledgeBaseService.ts: Remove Dify creation logic - Refactor documentService.ts: Remove Dify upload/polling logic - DifyClient.ts: Convert to deprecated stub file (for legacy compatibility) - common/rag/index.ts: Update exports - common/rag/types.ts: Remove Dify types, keep generic RAG types - config/env.ts: Remove Dify configuration Frontend changes: - DashboardPage.tsx: Add delete knowledge base dropdown menu - KnowledgeBaseList.tsx: Enhance quota warning display - CreateKBDialog.tsx: Add quota exceeded modal with guidance - knowledgeBaseApi.ts: Add auth interceptor Documentation: - Update PKB module status guide (v2.3) - Update system status guide (v4.0) Performance metrics: - Single query latency: 2.5s - Single query cost: 0.0025 CNY - Cross-language accuracy improvement: +20.5% Remaining tasks: - OSS storage integration - pg_bigm extension installation Tested: End-to-end test passed (create KB -> upload doc -> vector search)
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
* 严格遵循:知识库仪表盘V5.html
|
||||
*/
|
||||
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import React, { useState, useEffect, useRef } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { useKnowledgeBaseStore } from '../stores/useKnowledgeBaseStore';
|
||||
import DocumentUpload from '../components/DocumentUpload';
|
||||
@@ -11,9 +11,9 @@ import {
|
||||
Plus, BookOpen, Microscope, Stethoscope, Pill,
|
||||
GraduationCap, Wrench, MessageSquare, FileText,
|
||||
Loader2, MoreHorizontal, X, CheckCircle2,
|
||||
ChevronRight, Upload, Sparkles, Trash2, ArrowRight
|
||||
ChevronRight, Upload, Sparkles, Trash2, ArrowRight, Edit3
|
||||
} from 'lucide-react';
|
||||
import { message } from 'antd';
|
||||
import { message, Modal } from 'antd';
|
||||
import type { KBType } from '../types/workspace';
|
||||
|
||||
// 6种知识库类型配置(严格遵循V5设计)
|
||||
@@ -76,7 +76,7 @@ const KB_TYPES = [
|
||||
|
||||
const DashboardPage: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const { knowledgeBases, fetchKnowledgeBases, createKnowledgeBase } = useKnowledgeBaseStore();
|
||||
const { knowledgeBases, fetchKnowledgeBases, createKnowledgeBase, deleteKnowledgeBase } = useKnowledgeBaseStore();
|
||||
|
||||
// Modal状态
|
||||
const [isModalOpen, setIsModalOpen] = useState(false);
|
||||
@@ -89,10 +89,52 @@ const DashboardPage: React.FC = () => {
|
||||
// 新增:创建知识库后保存ID,用于Step3上传文档
|
||||
const [createdKbId, setCreatedKbId] = useState<string | null>(null);
|
||||
const [uploadedCount, setUploadedCount] = useState(0);
|
||||
|
||||
// 下拉菜单状态
|
||||
const [openMenuId, setOpenMenuId] = useState<string | null>(null);
|
||||
const menuRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
fetchKnowledgeBases();
|
||||
}, []);
|
||||
|
||||
// 点击外部关闭菜单
|
||||
useEffect(() => {
|
||||
const handleClickOutside = (event: MouseEvent) => {
|
||||
if (menuRef.current && !menuRef.current.contains(event.target as Node)) {
|
||||
setOpenMenuId(null);
|
||||
}
|
||||
};
|
||||
document.addEventListener('mousedown', handleClickOutside);
|
||||
return () => document.removeEventListener('mousedown', handleClickOutside);
|
||||
}, []);
|
||||
|
||||
// 删除知识库
|
||||
const handleDeleteKb = async (kbId: string, kbName: string) => {
|
||||
Modal.confirm({
|
||||
title: '确认删除知识库?',
|
||||
content: (
|
||||
<div>
|
||||
<p>您即将删除知识库 <strong>"{kbName}"</strong></p>
|
||||
<p className="text-red-500 text-sm mt-2">
|
||||
⚠️ 此操作将同时删除该知识库中的所有文档,且不可恢复!
|
||||
</p>
|
||||
</div>
|
||||
),
|
||||
okText: '确认删除',
|
||||
okButtonProps: { danger: true },
|
||||
cancelText: '取消',
|
||||
onOk: async () => {
|
||||
try {
|
||||
await deleteKnowledgeBase(kbId);
|
||||
message.success('知识库删除成功');
|
||||
setOpenMenuId(null);
|
||||
} catch (error: any) {
|
||||
message.error(error.message || '删除失败');
|
||||
}
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const getKbTypeConfig = (id: KBType) => KB_TYPES.find(t => t.id === id) || KB_TYPES[0];
|
||||
|
||||
@@ -198,9 +240,45 @@ const DashboardPage: React.FC = () => {
|
||||
<div className={`p-2.5 rounded-lg ${style.bg} ${style.color}`}>
|
||||
<TypeIcon className="w-6 h-6" />
|
||||
</div>
|
||||
<button className="text-gray-300 hover:text-gray-600 p-1 rounded hover:bg-gray-100">
|
||||
<MoreHorizontal className="w-5 h-5" />
|
||||
</button>
|
||||
<div className="relative" ref={openMenuId === kb.id ? menuRef : null}>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setOpenMenuId(openMenuId === kb.id ? null : kb.id);
|
||||
}}
|
||||
className="text-gray-300 hover:text-gray-600 p-1 rounded hover:bg-gray-100"
|
||||
>
|
||||
<MoreHorizontal className="w-5 h-5" />
|
||||
</button>
|
||||
|
||||
{/* 下拉菜单 */}
|
||||
{openMenuId === kb.id && (
|
||||
<div className="absolute right-0 top-8 bg-white rounded-lg shadow-xl border border-gray-200 py-1 z-50 min-w-[140px] animate-in fade-in duration-150">
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setOpenMenuId(null);
|
||||
navigate(`/knowledge-base/workspace/${kb.id}`);
|
||||
}}
|
||||
className="w-full px-4 py-2 text-left text-sm text-gray-700 hover:bg-gray-50 flex items-center gap-2"
|
||||
>
|
||||
<Edit3 className="w-4 h-4" />
|
||||
编辑知识库
|
||||
</button>
|
||||
<div className="border-t border-gray-100 my-1"></div>
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleDeleteKb(kb.id, kb.name);
|
||||
}}
|
||||
className="w-full px-4 py-2 text-left text-sm text-red-600 hover:bg-red-50 flex items-center gap-2"
|
||||
>
|
||||
<Trash2 className="w-4 h-4" />
|
||||
删除知识库
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 className="font-bold text-lg text-slate-800 mb-2 line-clamp-1 group-hover:text-blue-700 transition-colors">{kb.name}</h3>
|
||||
|
||||
Reference in New Issue
Block a user