243 lines
7.8 KiB
Python
243 lines
7.8 KiB
Python
"""
|
|
知识库 API 接口
|
|
|
|
实现知识库相关的 REST API 接口。
|
|
对应 Java: com.deepdata.rag.indexer.interfaces.KnowledgeBaseController
|
|
"""
|
|
import json
|
|
|
|
from fastapi import APIRouter, Depends, BackgroundTasks
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from app.core.exception import SuccessResponse
|
|
from app.db.session import get_db
|
|
from app.module.rag.schema.request import (
|
|
KnowledgeBaseCreateReq,
|
|
KnowledgeBaseUpdateReq,
|
|
KnowledgeBaseQueryReq,
|
|
AddFilesReq,
|
|
DeleteFilesReq,
|
|
RagFileReq,
|
|
RetrieveReq,
|
|
PagingQuery,
|
|
ChunkFilterQuery,
|
|
QueryRequest,
|
|
ChunkUpdateReq,
|
|
)
|
|
from app.module.rag.service.knowledge_base_service import KnowledgeBaseService
|
|
from app.module.rag.service.unified_retrieval_service import UnifiedRetrievalService
|
|
|
|
router = APIRouter(prefix="/knowledge-base", tags=["知识库管理"])
|
|
|
|
|
|
@router.post("/create", response_model=SuccessResponse)
|
|
async def create_knowledge_base(
|
|
request: KnowledgeBaseCreateReq,
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""创建知识库"""
|
|
service = KnowledgeBaseService(db)
|
|
knowledge_base_id = await service.create(request)
|
|
return SuccessResponse(data=knowledge_base_id)
|
|
|
|
|
|
@router.put("/{knowledge_base_id}", response_model=SuccessResponse)
|
|
async def update_knowledge_base(
|
|
knowledge_base_id: str,
|
|
request: KnowledgeBaseUpdateReq,
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""更新知识库"""
|
|
service = KnowledgeBaseService(db)
|
|
await service.update(knowledge_base_id, request)
|
|
return SuccessResponse(message="知识库更新成功")
|
|
|
|
|
|
@router.delete("/{knowledge_base_id}", response_model=SuccessResponse)
|
|
async def delete_knowledge_base(
|
|
knowledge_base_id: str,
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""删除知识库"""
|
|
service = KnowledgeBaseService(db)
|
|
await service.delete(knowledge_base_id)
|
|
return SuccessResponse(message="知识库删除成功")
|
|
|
|
|
|
@router.get("/{knowledge_base_id}", response_model=SuccessResponse)
|
|
async def get_knowledge_base(
|
|
knowledge_base_id: str,
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""获取知识库详情"""
|
|
service = KnowledgeBaseService(db)
|
|
knowledge_base = await service.get_by_id(knowledge_base_id)
|
|
return SuccessResponse(data=knowledge_base)
|
|
|
|
|
|
@router.post("/list", response_model=SuccessResponse)
|
|
async def list_knowledge_bases(
|
|
request: KnowledgeBaseQueryReq,
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""分页查询知识库列表"""
|
|
service = KnowledgeBaseService(db)
|
|
result = await service.list(request)
|
|
return SuccessResponse(data=result)
|
|
|
|
|
|
@router.post("/{knowledge_base_id}/files", response_model=SuccessResponse)
|
|
async def add_files_to_knowledge_base(
|
|
knowledge_base_id: str,
|
|
request: AddFilesReq,
|
|
background_tasks: BackgroundTasks,
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""添加文件到知识库
|
|
|
|
文件记录存入数据库后立即返回,后台异步处理文件。
|
|
"""
|
|
request.knowledge_base_id = knowledge_base_id
|
|
|
|
service = KnowledgeBaseService(db)
|
|
result = await service.add_files(request, background_tasks)
|
|
|
|
message = f"文件添加成功,正在后台处理 {result['success_count']} 个文件"
|
|
if result["skipped_count"] > 0:
|
|
message = f"成功添加 {result['success_count']} 个文件,跳过 {result['skipped_count']} 个不存在的文件"
|
|
|
|
return SuccessResponse(
|
|
message=message,
|
|
data={
|
|
"successCount": result["success_count"],
|
|
"skippedCount": result["skipped_count"],
|
|
"skippedFileIds": result["skipped_file_ids"],
|
|
},
|
|
)
|
|
|
|
|
|
@router.get("/{knowledge_base_id}/files", response_model=SuccessResponse)
|
|
async def list_knowledge_base_files(
|
|
knowledge_base_id: str,
|
|
request: RagFileReq = Depends(),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""获取知识库文件列表"""
|
|
service = KnowledgeBaseService(db)
|
|
result = await service.list_files(knowledge_base_id, request)
|
|
return SuccessResponse(data=result)
|
|
|
|
|
|
@router.delete("/{knowledge_base_id}/files", response_model=SuccessResponse)
|
|
async def delete_knowledge_base_files(
|
|
knowledge_base_id: str,
|
|
request: DeleteFilesReq,
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""删除知识库文件"""
|
|
service = KnowledgeBaseService(db)
|
|
await service.delete_files(knowledge_base_id, request)
|
|
return SuccessResponse(message="文件删除成功")
|
|
|
|
|
|
@router.get("/{knowledge_base_id}/files/{rag_file_id}", response_model=SuccessResponse)
|
|
async def get_file_chunks(
|
|
knowledge_base_id: str,
|
|
rag_file_id: str,
|
|
query: ChunkFilterQuery = Depends(),
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""获取指定 RAG 文件的分块列表"""
|
|
service = UnifiedRetrievalService(db)
|
|
result = await service.get_chunks(knowledge_base_id, rag_file_id, query)
|
|
return SuccessResponse(data=result)
|
|
|
|
|
|
@router.put("/{knowledge_base_id}/chunks/{chunk_id}", response_model=SuccessResponse)
|
|
async def update_chunk(
|
|
knowledge_base_id: str,
|
|
chunk_id: str,
|
|
request: ChunkUpdateReq,
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""更新指定分块的文本和元数据"""
|
|
service = KnowledgeBaseService(db)
|
|
await service.update_chunk(
|
|
knowledge_base_id=knowledge_base_id,
|
|
chunk_id=chunk_id,
|
|
text=request.text,
|
|
metadata=request.metadata,
|
|
)
|
|
return SuccessResponse(message="分块更新成功")
|
|
|
|
|
|
@router.delete("/{knowledge_base_id}/chunks/{chunk_id}", response_model=SuccessResponse)
|
|
async def delete_chunk(
|
|
knowledge_base_id: str,
|
|
chunk_id: str,
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""删除指定分块"""
|
|
service = KnowledgeBaseService(db)
|
|
await service.delete_chunk(
|
|
knowledge_base_id=knowledge_base_id,
|
|
chunk_id=chunk_id,
|
|
)
|
|
return SuccessResponse(message="分块删除成功")
|
|
|
|
|
|
@router.post("/retrieve", response_model=SuccessResponse)
|
|
async def retrieve_knowledge_base(
|
|
request: RetrieveReq,
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""检索知识库内容(统一检索接口,兼容旧版本格式)"""
|
|
service = UnifiedRetrievalService(db)
|
|
results = await service.search(request)
|
|
|
|
legacy_results = []
|
|
for item in results:
|
|
legacy_item = {
|
|
"entity": {
|
|
"metadata": json.dumps(item.get("metadata", {}), ensure_ascii=False),
|
|
"text": item.get("text", ""),
|
|
"id": item.get("id", ""),
|
|
},
|
|
"score": item.get("score", 0.0),
|
|
"id": item.get("id", ""),
|
|
"knowledgeBaseId": item.get("knowledgeBaseId", ""),
|
|
"knowledgeBaseName": item.get("knowledgeBaseName", ""),
|
|
}
|
|
legacy_results.append(legacy_item)
|
|
|
|
return SuccessResponse(data=legacy_results)
|
|
|
|
@router.post("/v2/retrieve", response_model=SuccessResponse)
|
|
async def v2_retrieve_knowledge_base(
|
|
request: RetrieveReq,
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""检索知识库内容(统一检索接口)"""
|
|
service = UnifiedRetrievalService(db)
|
|
results = await service.search(request)
|
|
return SuccessResponse(data=results)
|
|
|
|
|
|
@router.post("/query", response_model=SuccessResponse)
|
|
async def query_knowledge_base(
|
|
payload: QueryRequest,
|
|
db: AsyncSession = Depends(get_db),
|
|
):
|
|
"""查询知识库(支持向量检索和知识图谱)
|
|
|
|
根据知识库类型自动选择查询策略:
|
|
- DOCUMENT: 向量检索
|
|
- GRAPH: 知识图谱查询
|
|
"""
|
|
service = UnifiedRetrievalService(db)
|
|
result = await service.query(
|
|
knowledge_base_id=payload.knowledge_base_id,
|
|
node_label=payload.query,
|
|
)
|
|
return SuccessResponse(data=result)
|