Update knowldge base layout
This commit is contained in:
@@ -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<KnowledgeBase | null>(null);
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [embeddingOptions, setEmbeddingOptions] = useState<string[]>(EMBEDDING_OPTIONS);
|
||||
const [hasDbEmbeddingModels, setHasDbEmbeddingModels] = useState(false);
|
||||
const [openMenuKbId, setOpenMenuKbId] = useState<string | null>(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 = () => {
|
||||
<Card
|
||||
key={kb.id}
|
||||
className="p-6 hover:border-primary/50 transition-colors cursor-pointer group relative"
|
||||
onClick={() => openEditKb(kb)}
|
||||
onClick={() => handleSelect(kb)}
|
||||
>
|
||||
<div className="absolute top-3 right-3 z-20">
|
||||
<Button
|
||||
@@ -243,22 +248,13 @@ export const KnowledgeBasePage: React.FC = () => {
|
||||
setOpenMenuKbId((prev) => (prev === kb.id ? null : kb.id));
|
||||
}}
|
||||
>
|
||||
<MoreVertical className="h-4 w-4" />
|
||||
<MoreHorizontal className="h-4 w-4" />
|
||||
</Button>
|
||||
{openMenuKbId === kb.id && (
|
||||
<div
|
||||
className="absolute right-0 mt-1 w-36 rounded-md border border-white/10 bg-card/95 backdrop-blur-md shadow-lg overflow-hidden"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<button
|
||||
className="w-full text-left px-3 py-2 text-sm hover:bg-white/10 text-foreground"
|
||||
onClick={() => {
|
||||
setOpenMenuKbId(null);
|
||||
handleSelect(kb);
|
||||
}}
|
||||
>
|
||||
管理文档
|
||||
</button>
|
||||
<button
|
||||
className="w-full text-left px-3 py-2 text-sm hover:bg-white/10 text-destructive"
|
||||
onClick={() => {
|
||||
@@ -275,9 +271,11 @@ export const KnowledgeBasePage: React.FC = () => {
|
||||
<div className="p-2 bg-primary/10 rounded-lg text-primary">
|
||||
<FileText className="h-6 w-6" />
|
||||
</div>
|
||||
<Badge variant="outline">{kb.embeddingModel || 'embedding'}</Badge>
|
||||
</div>
|
||||
<h3 className="text-lg font-semibold group-hover:text-primary transition-colors text-white">{kb.name}</h3>
|
||||
<div className="mt-2">
|
||||
<Badge variant="outline">{kb.embeddingModel || 'embedding'}</Badge>
|
||||
</div>
|
||||
<div className="mt-4 space-y-1 text-sm text-muted-foreground">
|
||||
<p>文档数量: {kb.documents.length}</p>
|
||||
<p>分片数量: {kb.chunkSize ?? 500}/{kb.chunkOverlap ?? 50}</p>
|
||||
@@ -319,6 +317,7 @@ export const KnowledgeBasePage: React.FC = () => {
|
||||
kbChunkOverlap={kbChunkOverlap}
|
||||
setKbChunkOverlap={setKbChunkOverlap}
|
||||
embeddingOptions={embeddingOptions}
|
||||
hasDbEmbeddingModels={hasDbEmbeddingModels}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
@@ -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,
|
||||
}) => (
|
||||
<Dialog
|
||||
isOpen={isOpen}
|
||||
@@ -415,6 +416,12 @@ const KnowledgeBaseModal: React.FC<{
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!hasDbEmbeddingModels && (
|
||||
<p className="text-xs text-yellow-400/90">
|
||||
未在 LLM Library 检测到 `embedding` 类型模型,当前使用默认 embedding 选项。
|
||||
</p>
|
||||
)}
|
||||
|
||||
<p className="text-xs text-muted-foreground">
|
||||
使用 ChromaDB 作为向量存储。若知识库已有已索引分片,不能直接变更 Embedding Model,需要先删除文档后重建。
|
||||
</p>
|
||||
|
||||
Reference in New Issue
Block a user