ForcePilot/server/routers/data_router.py

207 lines
8.8 KiB
Python
Raw Normal View History

2024-10-02 20:11:28 +08:00
import os
2025-03-06 23:55:20 +08:00
import asyncio
2025-03-17 19:58:00 +08:00
import traceback
2025-03-20 20:31:14 +08:00
from fastapi import APIRouter, File, UploadFile, HTTPException, Depends, Body, Form, Query
2024-10-02 20:11:28 +08:00
2025-02-27 19:35:25 +08:00
from src.utils import logger, hashstr
from src import executor, config, knowledge_base, graph_base
2025-05-02 23:56:59 +08:00
from server.utils.auth_middleware import get_admin_user
from server.models.user_model import User
2024-10-02 20:11:28 +08:00
data = APIRouter(prefix="/data")
@data.get("/")
2025-05-02 23:56:59 +08:00
async def get_databases(current_user: User = Depends(get_admin_user)):
2024-10-02 20:11:28 +08:00
try:
database = knowledge_base.get_databases()
2024-10-02 20:11:28 +08:00
except Exception as e:
logger.error(f"获取数据库列表失败 {e}, {traceback.format_exc()}")
2024-10-02 20:11:28 +08:00
return {"message": f"获取数据库列表失败 {e}", "databases": []}
return database
@data.post("/")
async def create_database(
database_name: str = Body(...),
description: str = Body(...),
embed_model_name: str = Body(...),
2025-05-02 23:56:59 +08:00
current_user: User = Depends(get_admin_user)
2024-10-02 20:11:28 +08:00
):
logger.debug(f"Create database {database_name}")
try:
embed_info = config.embed_model_names[embed_model_name]
database_info = knowledge_base.create_database(
database_name,
description,
embed_info=embed_info
)
except Exception as e:
logger.error(f"创建数据库失败 {e}, {traceback.format_exc()}")
return {"message": f"创建数据库失败 {e}", "status": "failed"}
2024-10-02 20:11:28 +08:00
return database_info
@data.delete("/")
2025-05-02 23:56:59 +08:00
async def delete_database(db_id, current_user: User = Depends(get_admin_user)):
2024-10-02 20:11:28 +08:00
logger.debug(f"Delete database {db_id}")
knowledge_base.delete_database(db_id)
2024-10-02 20:11:28 +08:00
return {"message": "删除成功"}
@data.post("/query-test")
2025-05-02 23:56:59 +08:00
async def query_test(query: str = Body(...), meta: dict = Body(...), current_user: User = Depends(get_admin_user)):
2024-10-02 20:11:28 +08:00
logger.debug(f"Query test in {meta}: {query}")
result = await knowledge_base.aquery(query, **meta)
2024-10-02 20:11:28 +08:00
return result
@data.post("/add-files")
async def add_files(db_id: str = Body(...), items: list[str] = Body(...), params: dict = Body(...), current_user: User = Depends(get_admin_user)):
logger.debug(f"Add files/urls for db_id {db_id}: {items} {params=}")
# 从 params 中获取 content_type默认为 'file'
content_type = params.get('content_type', 'file')
try:
# 使用统一的 add_content 方法
processed_items = await knowledge_base.add_content(db_id, items, params=params)
item_type = "URLs" if content_type == 'url' else "files"
processed_failed_count = len([_p for _p in processed_items if _p['status'] == 'failed'])
processed_info = f"Processed {len(processed_items)} {item_type}, {processed_failed_count} {item_type} failed"
return {"message": processed_info, "items": processed_items, "status": "success"}
except Exception as e:
logger.error(f"Failed to process {content_type}s: {e}, {traceback.format_exc()}")
return {"message": f"Failed to process {content_type}s: {e}", "status": "failed"}
@data.post("/file-to-chunk")
async def file_to_chunk(db_id: str = Body(...), files: list[str] = Body(...), params: dict = Body(...), current_user: User = Depends(get_admin_user)):
logger.debug(f"File to chunk for db_id {db_id}: {files} {params=} (deprecated, use /add-files)")
# 兼容性路由,转发到新的统一接口
params['content_type'] = 'file'
return await add_files(db_id, files, params, current_user)
2025-03-23 23:10:32 +08:00
2025-05-07 00:38:33 +08:00
@data.post("/url-to-chunk")
async def url_to_chunk(db_id: str = Body(...), urls: list[str] = Body(...), params: dict = Body(...), current_user: User = Depends(get_admin_user)):
logger.debug(f"Url to chunk for db_id {db_id}: {urls} {params=} (deprecated, use /add-files)")
# 兼容性路由,转发到新的统一接口
params['content_type'] = 'url'
return await add_files(db_id, urls, params, current_user)
2025-05-07 00:38:33 +08:00
2024-10-02 20:11:28 +08:00
@data.post("/add-by-file")
2025-05-24 11:29:45 +08:00
async def create_document_by_file(db_id: str = Body(...), files: list[str] = Body(...), current_user: User = Depends(get_admin_user)):
raise ValueError("This method is deprecated. Use /add-files instead.")
2024-10-02 20:11:28 +08:00
2025-03-23 23:10:32 +08:00
@data.post("/add-by-chunks")
2025-05-02 23:56:59 +08:00
async def add_by_chunks(db_id: str = Body(...), file_chunks: dict = Body(...), current_user: User = Depends(get_admin_user)):
raise ValueError("This method is deprecated. Use /add-files instead.")
2025-03-23 23:10:32 +08:00
2024-10-08 22:16:17 +08:00
@data.get("/info")
2025-05-02 23:56:59 +08:00
async def get_database_info(db_id: str, current_user: User = Depends(get_admin_user)):
2025-03-23 19:22:00 +08:00
# logger.debug(f"Get database {db_id} info")
database = knowledge_base.get_database_info(db_id)
2024-10-02 20:11:28 +08:00
if database is None:
raise HTTPException(status_code=404, detail="Database not found")
return database
@data.delete("/document")
2025-05-02 23:56:59 +08:00
async def delete_document(db_id: str = Body(...), file_id: str = Body(...), current_user: User = Depends(get_admin_user)):
2024-10-02 20:11:28 +08:00
logger.debug(f"DELETE document {file_id} info in {db_id}")
await knowledge_base.delete_file(db_id, file_id)
2024-10-02 20:11:28 +08:00
return {"message": "删除成功"}
@data.get("/document")
2025-05-02 23:56:59 +08:00
async def get_document_info(db_id: str, file_id: str, current_user: User = Depends(get_admin_user)):
2024-10-02 20:11:28 +08:00
logger.debug(f"GET document {file_id} info in {db_id}")
2024-10-08 22:16:17 +08:00
try:
info = await knowledge_base.get_file_info(db_id, file_id)
2024-10-08 22:16:17 +08:00
except Exception as e:
2025-03-17 19:58:00 +08:00
logger.error(f"Failed to get file info, {e}, {db_id=}, {file_id=}, {traceback.format_exc()}")
info = {"message": "Failed to get file info", "status": "failed"}
2024-10-08 22:16:17 +08:00
2024-10-02 20:11:28 +08:00
return info
@data.post("/upload")
2025-03-20 20:31:14 +08:00
async def upload_file(
file: UploadFile = File(...),
2025-05-24 11:29:45 +08:00
db_id: str | None = Query(None),
2025-05-02 23:56:59 +08:00
current_user: User = Depends(get_admin_user)
2025-03-20 20:31:14 +08:00
):
2024-10-02 20:11:28 +08:00
if not file.filename:
raise HTTPException(status_code=400, detail="No selected file")
2025-03-20 20:31:14 +08:00
# 根据db_id获取上传路径如果db_id为None则使用默认路径
if db_id:
upload_dir = knowledge_base.get_db_upload_path(db_id)
else:
upload_dir = os.path.join(config.save_dir, "database", "uploads")
2025-03-20 20:31:14 +08:00
2024-10-23 16:24:29 +08:00
basename, ext = os.path.splitext(file.filename)
2025-03-06 23:55:20 +08:00
filename = f"{basename}_{hashstr(basename, 4, with_salt=True)}{ext}".lower()
2024-10-02 20:11:28 +08:00
file_path = os.path.join(upload_dir, filename)
2025-04-01 18:37:30 +08:00
os.makedirs(upload_dir, exist_ok=True)
2024-10-02 20:11:28 +08:00
with open(file_path, "wb") as buffer:
buffer.write(await file.read())
2025-03-20 20:31:14 +08:00
return {"message": "File successfully uploaded", "file_path": file_path, "db_id": db_id}
2024-10-02 20:11:28 +08:00
@data.get("/graph")
2025-05-02 23:56:59 +08:00
async def get_graph_info(current_user: User = Depends(get_admin_user)):
graph_info = graph_base.get_graph_info()
if graph_info is None:
raise HTTPException(status_code=400, detail="图数据库获取出错")
2024-10-02 20:11:28 +08:00
return graph_info
2025-03-08 22:49:13 +08:00
@data.post("/graph/index-nodes")
2025-05-02 23:56:59 +08:00
async def index_nodes(data: dict = Body(default={}), current_user: User = Depends(get_admin_user)):
if not graph_base.is_running():
2025-03-08 22:49:13 +08:00
raise HTTPException(status_code=400, detail="图数据库未启动")
# 获取参数或使用默认值
kgdb_name = data.get('kgdb_name', 'neo4j')
# 调用GraphDatabase的add_embedding_to_nodes方法
count = graph_base.add_embedding_to_nodes(kgdb_name=kgdb_name)
2025-03-08 22:49:13 +08:00
return {"status": "success", "message": f"已成功为{count}个节点添加嵌入向量", "indexed_count": count}
2024-10-02 20:11:28 +08:00
@data.get("/graph/node")
2025-05-02 23:56:59 +08:00
async def get_graph_node(entity_name: str, current_user: User = Depends(get_admin_user)):
result = graph_base.query_node(entity_name=entity_name)
return {"result": graph_base.format_query_result_to_graph(result), "message": "success"}
2024-10-02 20:11:28 +08:00
@data.get("/graph/nodes")
2025-05-02 23:56:59 +08:00
async def get_graph_nodes(kgdb_name: str, num: int, current_user: User = Depends(get_admin_user)):
2024-10-02 20:11:28 +08:00
logger.debug(f"Get graph nodes in {kgdb_name} with {num} nodes")
result = graph_base.get_sample_nodes(kgdb_name, num)
return {"result": graph_base.format_general_results(result), "message": "success"}
2024-10-02 20:11:28 +08:00
2025-02-28 00:27:58 +08:00
@data.post("/graph/add-by-jsonl")
2025-05-24 11:29:45 +08:00
async def add_graph_entity(file_path: str = Body(...), kgdb_name: str | None = Body(None), current_user: User = Depends(get_admin_user)):
2024-10-02 20:11:28 +08:00
if not file_path.endswith('.jsonl'):
return {"message": "文件格式错误请上传jsonl文件", "status": "failed"}
2024-10-02 20:11:28 +08:00
try:
await graph_base.jsonl_file_add_entity(file_path, kgdb_name)
return {"message": "实体添加成功", "status": "success"}
except Exception as e:
logger.error(f"添加实体失败: {e}, {traceback.format_exc()}")
return {"message": f"添加实体失败: {e}", "status": "failed"}
2024-10-02 20:11:28 +08:00
@data.post("/update")
async def update_database_info(
db_id: str = Body(...),
name: str = Body(...),
description: str = Body(...),
current_user: User = Depends(get_admin_user)
):
logger.debug(f"Update database {db_id} info: {name}, {description}")
try:
database = knowledge_base.update_database(db_id, name, description)
return {"message": "更新成功", "database": database}
except Exception as e:
logger.error(f"更新数据库失败 {e}, {traceback.format_exc()}")
raise HTTPException(status_code=400, detail=f"更新数据库失败: {e}")