From 0d13d6acdbc4fa25108fdf48e9981c182b6eb75f Mon Sep 17 00:00:00 2001 From: Xin Wang Date: Mon, 9 Feb 2026 08:01:15 +0800 Subject: [PATCH] Update knowldge base layout --- web/pages/KnowledgeBase.tsx | 45 +++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/web/pages/KnowledgeBase.tsx b/web/pages/KnowledgeBase.tsx index 9bad711..c02fbf5 100644 --- a/web/pages/KnowledgeBase.tsx +++ b/web/pages/KnowledgeBase.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState, useRef } from 'react'; -import { Search, Plus, FileText, Upload, ArrowLeft, CloudUpload, File as FileIcon, X, Pencil, Trash2, Settings2, MoreVertical } from 'lucide-react'; +import { Search, Plus, FileText, Upload, ArrowLeft, CloudUpload, File as FileIcon, X, Pencil, Trash2, Settings2, MoreHorizontal } from 'lucide-react'; import { Button, Input, TableHeader, TableRow, TableHead, TableCell, Card, Dialog, Badge } from '../components/UI'; import { KnowledgeBase } from '../types'; import { createKnowledgeBase, deleteKnowledgeBase, deleteKnowledgeDocument, fetchKnowledgeBases, fetchLLMModels, updateKnowledgeBase, uploadKnowledgeDocument } from '../services/backendApi'; @@ -20,6 +20,7 @@ export const KnowledgeBasePage: React.FC = () => { const [editingKb, setEditingKb] = useState(null); const [isLoading, setIsLoading] = useState(true); const [embeddingOptions, setEmbeddingOptions] = useState(EMBEDDING_OPTIONS); + const [hasDbEmbeddingModels, setHasDbEmbeddingModels] = useState(false); const [openMenuKbId, setOpenMenuKbId] = useState(null); const [kbName, setKbName] = useState(''); @@ -53,16 +54,20 @@ export const KnowledgeBasePage: React.FC = () => { const loadEmbeddingModels = async () => { try { const models = await fetchLLMModels(); - const fromDb = models + const fromDb = Array.from(new Set(models .filter((m) => m.type === 'embedding') .map((m) => (m.modelName || m.name || '').trim()) - .filter(Boolean); - const merged = Array.from(new Set([...fromDb, ...EMBEDDING_OPTIONS])); - if (merged.length > 0) { - setEmbeddingOptions(merged); - } + .filter(Boolean))); + + setHasDbEmbeddingModels(fromDb.length > 0); + + // Prefer DB embedding models first; keep defaults as fallback at the end. + const defaultsTail = EMBEDDING_OPTIONS.filter((item) => !fromDb.includes(item)); + const ordered = [...fromDb, ...defaultsTail]; + setEmbeddingOptions(ordered.length > 0 ? ordered : EMBEDDING_OPTIONS); } catch { setEmbeddingOptions(EMBEDDING_OPTIONS); + setHasDbEmbeddingModels(false); } }; loadEmbeddingModels(); @@ -231,7 +236,7 @@ export const KnowledgeBasePage: React.FC = () => { openEditKb(kb)} + onClick={() => handleSelect(kb)} >
{openMenuKbId === kb.id && (
e.stopPropagation()} > -

{kb.name}

+
+ {kb.embeddingModel || 'embedding'} +

文档数量: {kb.documents.length}

分片数量: {kb.chunkSize ?? 500}/{kb.chunkOverlap ?? 50}

@@ -319,6 +317,7 @@ export const KnowledgeBasePage: React.FC = () => { kbChunkOverlap={kbChunkOverlap} setKbChunkOverlap={setKbChunkOverlap} embeddingOptions={embeddingOptions} + hasDbEmbeddingModels={hasDbEmbeddingModels} />
); @@ -341,6 +340,7 @@ const KnowledgeBaseModal: React.FC<{ kbChunkOverlap: number; setKbChunkOverlap: (v: number) => void; embeddingOptions: string[]; + hasDbEmbeddingModels: boolean; }> = ({ isOpen, onClose, @@ -358,6 +358,7 @@ const KnowledgeBaseModal: React.FC<{ kbChunkOverlap, setKbChunkOverlap, embeddingOptions, + hasDbEmbeddingModels, }) => (
+ {!hasDbEmbeddingModels && ( +

+ 未在 LLM Library 检测到 `embedding` 类型模型,当前使用默认 embedding 选项。 +

+ )} +

使用 ChromaDB 作为向量存储。若知识库已有已索引分片,不能直接变更 Embedding Model,需要先删除文档后重建。