- 新增 MilvusGraphVectorStore 和 KnowledgeGraphRepository - 新增文件大小从 MinIO 补全的逻辑(上传时 + 启动时) - 重构 FileTable、GraphDetailPanel、KnowledgeGraphSection 等前端组件 - 新增文件大小回退测试和 kb_utils 测试 - 优化 file_utils 工具函数 - 更新 roadmap 文档
110 lines
4.2 KiB
Python
110 lines
4.2 KiB
Python
import traceback
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Query
|
|
|
|
from server.utils.auth_middleware import get_admin_user
|
|
from yuxi import knowledge_base
|
|
from yuxi.knowledge.graphs.milvus_graph_service import MilvusGraphService
|
|
from yuxi.storage.postgres.models_business import User
|
|
from yuxi.utils.logging_config import logger
|
|
|
|
graph = APIRouter(prefix="/graph", tags=["graph"])
|
|
|
|
|
|
async def _get_graph_service(db_id: str) -> MilvusGraphService:
|
|
db_info = await knowledge_base.get_database_info(db_id)
|
|
if not db_info:
|
|
raise HTTPException(status_code=404, detail="Knowledge base not found")
|
|
|
|
kb_type = (db_info.get("kb_type") or "").lower()
|
|
if kb_type != "milvus":
|
|
raise HTTPException(status_code=404, detail="Graph API only supports Milvus knowledge bases")
|
|
|
|
return MilvusGraphService(db_id=db_id)
|
|
|
|
|
|
@graph.get("/list")
|
|
async def get_graphs(current_user: User = Depends(get_admin_user)):
|
|
"""获取支持图谱能力的 Milvus 知识库列表"""
|
|
try:
|
|
databases = (await knowledge_base.get_databases_by_user_id(current_user.user_id)).get("databases", [])
|
|
graphs = []
|
|
for db in databases:
|
|
if (db.get("kb_type") or "").lower() != "milvus":
|
|
continue
|
|
graphs.append(
|
|
{
|
|
"id": db.get("db_id"),
|
|
"name": db.get("name"),
|
|
"type": "milvus",
|
|
"description": db.get("description"),
|
|
"status": db.get("status", "active"),
|
|
"created_at": db.get("created_at"),
|
|
"metadata": db,
|
|
}
|
|
)
|
|
return {"success": True, "data": graphs}
|
|
except Exception as e:
|
|
logger.error(f"Failed to list graphs: {e}")
|
|
logger.error(f"Traceback: {traceback.format_exc()}")
|
|
raise HTTPException(status_code=500, detail=f"Failed to list graphs: {str(e)}")
|
|
|
|
|
|
@graph.get("/subgraph")
|
|
async def get_subgraph(
|
|
db_id: str = Query(..., description="Milvus 知识库ID"),
|
|
node_label: str = Query("*", description="节点标签或查询关键词"),
|
|
max_depth: int = Query(2, description="最大深度", ge=1, le=5),
|
|
max_nodes: int = Query(100, description="最大节点数", ge=1, le=1000),
|
|
exclude_chunk: bool = Query(False, description="是否排除 Chunk 节点"),
|
|
current_user: User = Depends(get_admin_user),
|
|
):
|
|
"""查询 Milvus 知识库图谱子图"""
|
|
try:
|
|
logger.info(f"Querying subgraph - db_id: {db_id}, label: {node_label}")
|
|
service = await _get_graph_service(db_id)
|
|
result_data = await service.query_nodes(
|
|
keyword=node_label, max_depth=max_depth, max_nodes=max_nodes, exclude_chunk=exclude_chunk,
|
|
)
|
|
return {"success": True, "data": result_data}
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
logger.error(f"Failed to get subgraph: {e}")
|
|
logger.error(f"Traceback: {traceback.format_exc()}")
|
|
raise HTTPException(status_code=500, detail=f"Failed to get subgraph: {str(e)}")
|
|
|
|
|
|
@graph.get("/labels")
|
|
async def get_graph_labels(
|
|
db_id: str = Query(..., description="Milvus 知识库ID"),
|
|
current_user: User = Depends(get_admin_user),
|
|
):
|
|
"""获取 Milvus 知识库图谱的所有标签"""
|
|
try:
|
|
service = await _get_graph_service(db_id)
|
|
labels = await service.get_labels()
|
|
return {"success": True, "data": {"labels": labels}}
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
logger.error(f"Failed to get labels: {e}")
|
|
raise HTTPException(status_code=500, detail=f"Failed to get labels: {str(e)}")
|
|
|
|
|
|
@graph.get("/stats")
|
|
async def get_graph_stats(
|
|
db_id: str = Query(..., description="Milvus 知识库ID"),
|
|
current_user: User = Depends(get_admin_user),
|
|
):
|
|
"""获取 Milvus 知识库图谱统计信息"""
|
|
try:
|
|
service = await _get_graph_service(db_id)
|
|
stats_data = await service.get_stats()
|
|
return {"success": True, "data": stats_data}
|
|
except HTTPException:
|
|
raise
|
|
except Exception as e:
|
|
logger.error(f"Failed to get stats: {e}")
|
|
raise HTTPException(status_code=500, detail=f"Failed to get stats: {str(e)}")
|