Add kb index status
This commit is contained in:
@@ -309,7 +309,10 @@ def delete_document(kb_id: str, doc_id: str, db: Session = Depends(get_db)):
|
|||||||
# ============ Search ============
|
# ============ Search ============
|
||||||
@router.post("/search")
|
@router.post("/search")
|
||||||
def search_knowledge_base(query: KnowledgeSearchQuery):
|
def search_knowledge_base(query: KnowledgeSearchQuery):
|
||||||
|
try:
|
||||||
return search_knowledge(kb_id=query.kb_id, query=query.query, n_results=query.nResults)
|
return search_knowledge(kb_id=query.kb_id, query=query.query, n_results=query.nResults)
|
||||||
|
except ValueError as exc:
|
||||||
|
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
||||||
|
|
||||||
|
|
||||||
# ============ Stats ============
|
# ============ Stats ============
|
||||||
|
|||||||
@@ -64,6 +64,8 @@ class VectorStore:
|
|||||||
):
|
):
|
||||||
"""添加文档片段到向量库"""
|
"""添加文档片段到向量库"""
|
||||||
collection = self.get_collection(kb_id)
|
collection = self.get_collection(kb_id)
|
||||||
|
if collection is None:
|
||||||
|
raise ValueError(f"Knowledge collection not found for kb_id={kb_id}")
|
||||||
|
|
||||||
if ids is None:
|
if ids is None:
|
||||||
ids = [f"chunk-{i}" for i in range(len(documents))]
|
ids = [f"chunk-{i}" for i in range(len(documents))]
|
||||||
@@ -93,6 +95,11 @@ class VectorStore:
|
|||||||
) -> Dict:
|
) -> Dict:
|
||||||
"""检索相似文档"""
|
"""检索相似文档"""
|
||||||
collection = self.get_collection(kb_id)
|
collection = self.get_collection(kb_id)
|
||||||
|
if collection is None:
|
||||||
|
raise ValueError(
|
||||||
|
f"Knowledge collection not found for kb_id={kb_id}. "
|
||||||
|
"Please ensure the knowledge base exists and documents are indexed."
|
||||||
|
)
|
||||||
|
|
||||||
# 生成查询向量
|
# 生成查询向量
|
||||||
query_embedding = embedding_service.embed_query(query)
|
query_embedding = embedding_service.embed_query(query)
|
||||||
@@ -108,6 +115,8 @@ class VectorStore:
|
|||||||
def get_stats(self, kb_id: str) -> Dict:
|
def get_stats(self, kb_id: str) -> Dict:
|
||||||
"""获取向量库统计"""
|
"""获取向量库统计"""
|
||||||
collection = self.get_collection(kb_id)
|
collection = self.get_collection(kb_id)
|
||||||
|
if collection is None:
|
||||||
|
raise ValueError(f"Knowledge collection not found for kb_id={kb_id}")
|
||||||
return {
|
return {
|
||||||
"count": collection.count(),
|
"count": collection.count(),
|
||||||
"kb_id": kb_id
|
"kb_id": kb_id
|
||||||
@@ -116,11 +125,15 @@ class VectorStore:
|
|||||||
def delete_documents(self, kb_id: str, ids: List[str]):
|
def delete_documents(self, kb_id: str, ids: List[str]):
|
||||||
"""删除指定文档片段"""
|
"""删除指定文档片段"""
|
||||||
collection = self.get_collection(kb_id)
|
collection = self.get_collection(kb_id)
|
||||||
|
if collection is None:
|
||||||
|
return
|
||||||
collection.delete(ids=ids)
|
collection.delete(ids=ids)
|
||||||
|
|
||||||
def delete_by_metadata(self, kb_id: str, document_id: str):
|
def delete_by_metadata(self, kb_id: str, document_id: str):
|
||||||
"""根据文档 ID 删除所有片段"""
|
"""根据文档 ID 删除所有片段"""
|
||||||
collection = self.get_collection(kb_id)
|
collection = self.get_collection(kb_id)
|
||||||
|
if collection is None:
|
||||||
|
return
|
||||||
results = collection.get(where={"document_id": document_id})
|
results = collection.get(where={"document_id": document_id})
|
||||||
if results["ids"]:
|
if results["ids"]:
|
||||||
collection.delete(ids=results["ids"])
|
collection.delete(ids=results["ids"])
|
||||||
@@ -244,9 +257,6 @@ embedding_service = EmbeddingService()
|
|||||||
|
|
||||||
def search_knowledge(kb_id: str, query: str, n_results: int = 5) -> Dict:
|
def search_knowledge(kb_id: str, query: str, n_results: int = 5) -> Dict:
|
||||||
"""知识库检索"""
|
"""知识库检索"""
|
||||||
# 生成查询向量
|
|
||||||
query_vector = embedding_service.embed_query(query)
|
|
||||||
|
|
||||||
# 检索
|
# 检索
|
||||||
results = vector_store.search(
|
results = vector_store.search(
|
||||||
kb_id=kb_id,
|
kb_id=kb_id,
|
||||||
|
|||||||
@@ -525,6 +525,8 @@ const KnowledgeBaseDetail: React.FC<{
|
|||||||
<TableRow>
|
<TableRow>
|
||||||
<TableHead>文档名称</TableHead>
|
<TableHead>文档名称</TableHead>
|
||||||
<TableHead>大小</TableHead>
|
<TableHead>大小</TableHead>
|
||||||
|
<TableHead>索引状态</TableHead>
|
||||||
|
<TableHead>分片数</TableHead>
|
||||||
<TableHead>上传时间</TableHead>
|
<TableHead>上传时间</TableHead>
|
||||||
<TableHead className="text-right">操作</TableHead>
|
<TableHead className="text-right">操作</TableHead>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
@@ -536,6 +538,12 @@ const KnowledgeBaseDetail: React.FC<{
|
|||||||
<FileText className="h-4 w-4 mr-2 text-primary" /> {doc.name}
|
<FileText className="h-4 w-4 mr-2 text-primary" /> {doc.name}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell className="text-muted-foreground">{doc.size}</TableCell>
|
<TableCell className="text-muted-foreground">{doc.size}</TableCell>
|
||||||
|
<TableCell>
|
||||||
|
<Badge variant="outline">
|
||||||
|
{doc.status === 'completed' ? '已索引' : doc.status === 'failed' ? '失败' : doc.status === 'processing' ? '处理中' : '待处理'}
|
||||||
|
</Badge>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="text-muted-foreground">{doc.chunkCount ?? 0}</TableCell>
|
||||||
<TableCell className="text-muted-foreground">{doc.uploadDate}</TableCell>
|
<TableCell className="text-muted-foreground">{doc.uploadDate}</TableCell>
|
||||||
<TableCell className="text-right">
|
<TableCell className="text-right">
|
||||||
<Button
|
<Button
|
||||||
@@ -550,7 +558,7 @@ const KnowledgeBaseDetail: React.FC<{
|
|||||||
</TableRow>
|
</TableRow>
|
||||||
)) : (
|
)) : (
|
||||||
<TableRow>
|
<TableRow>
|
||||||
<TableCell colSpan={4} className="text-center py-8 text-muted-foreground">暂无文档</TableCell>
|
<TableCell colSpan={6} className="text-center py-8 text-muted-foreground">暂无文档</TableCell>
|
||||||
</TableRow>
|
</TableRow>
|
||||||
)}
|
)}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|||||||
@@ -154,6 +154,8 @@ const mapKnowledgeDocument = (raw: AnyRecord): KnowledgeDocument => ({
|
|||||||
name: readField(raw, ['name'], ''),
|
name: readField(raw, ['name'], ''),
|
||||||
size: readField(raw, ['size'], ''),
|
size: readField(raw, ['size'], ''),
|
||||||
uploadDate: normalizeDateLabel(readField(raw, ['uploadDate', 'upload_date', 'created_at'], '')),
|
uploadDate: normalizeDateLabel(readField(raw, ['uploadDate', 'upload_date', 'created_at'], '')),
|
||||||
|
status: readField(raw, ['status'], 'pending'),
|
||||||
|
chunkCount: Number(readField(raw, ['chunkCount', 'chunk_count'], 0)),
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapKnowledgeBase = (raw: AnyRecord): KnowledgeBase => ({
|
const mapKnowledgeBase = (raw: AnyRecord): KnowledgeBase => ({
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ export interface KnowledgeDocument {
|
|||||||
name: string;
|
name: string;
|
||||||
size: string;
|
size: string;
|
||||||
uploadDate: string;
|
uploadDate: string;
|
||||||
|
status?: string;
|
||||||
|
chunkCount?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type InteractionType = 'text' | 'audio' | 'video';
|
export type InteractionType = 'text' | 'audio' | 'video';
|
||||||
|
|||||||
Reference in New Issue
Block a user