2025-12-09 16:21:18 +08:00
|
|
|
|
import traceback
|
|
|
|
|
|
|
|
|
|
|
|
from fastapi import APIRouter, HTTPException, Depends, File, Form, Body, UploadFile
|
2026-02-20 13:23:20 +08:00
|
|
|
|
from fastapi.responses import FileResponse
|
2026-03-17 10:16:44 +08:00
|
|
|
|
from yuxi.storage.postgres.models_business import User
|
2025-12-09 16:21:18 +08:00
|
|
|
|
from server.utils.auth_middleware import get_admin_user
|
2026-03-17 10:16:44 +08:00
|
|
|
|
from yuxi.utils import logger
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
|
|
|
|
|
# 创建路由器
|
|
|
|
|
|
evaluation = APIRouter(prefix="/evaluation", tags=["evaluation"])
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-12-10 22:48:53 +08:00
|
|
|
|
# 移除旧详情接口,统一使用带 db_id 的接口
|
2026-01-16 14:06:42 +08:00
|
|
|
|
# ============================================================================
|
|
|
|
|
|
# 评估基准
|
|
|
|
|
|
# ============================================================================
|
2025-12-10 22:48:53 +08:00
|
|
|
|
|
2026-01-18 22:55:37 +08:00
|
|
|
|
|
2025-12-10 22:48:53 +08:00
|
|
|
|
@evaluation.get("/databases/{db_id}/benchmarks/{benchmark_id}")
|
|
|
|
|
|
async def get_evaluation_benchmark_by_db(
|
2025-12-14 22:44:18 +08:00
|
|
|
|
db_id: str, benchmark_id: str, page: int = 1, page_size: int = 10, current_user: User = Depends(get_admin_user)
|
2025-12-10 22:48:53 +08:00
|
|
|
|
):
|
2025-12-14 18:13:46 +08:00
|
|
|
|
"""根据 db_id 获取评估基准详情(支持分页)"""
|
2026-03-17 10:16:44 +08:00
|
|
|
|
from yuxi.services.evaluation_service import EvaluationService
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
|
|
|
|
|
try:
|
2025-12-14 18:13:46 +08:00
|
|
|
|
# 验证分页参数
|
|
|
|
|
|
if page < 1:
|
|
|
|
|
|
raise HTTPException(status_code=400, detail="页码必须大于0")
|
|
|
|
|
|
if page_size < 1 or page_size > 100:
|
|
|
|
|
|
raise HTTPException(status_code=400, detail="每页大小必须在1-100之间")
|
|
|
|
|
|
|
2025-12-09 16:21:18 +08:00
|
|
|
|
service = EvaluationService()
|
2025-12-14 18:13:46 +08:00
|
|
|
|
benchmark = await service.get_benchmark_detail_by_db(db_id, benchmark_id, page, page_size)
|
2025-12-09 16:21:18 +08:00
|
|
|
|
return {"message": "success", "data": benchmark}
|
2025-12-14 18:13:46 +08:00
|
|
|
|
except HTTPException:
|
|
|
|
|
|
raise
|
2025-12-09 16:21:18 +08:00
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"获取评估基准详情失败: {e}, {traceback.format_exc()}")
|
|
|
|
|
|
raise HTTPException(status_code=500, detail=f"获取评估基准详情失败: {str(e)}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@evaluation.delete("/benchmarks/{benchmark_id}")
|
|
|
|
|
|
async def delete_evaluation_benchmark(benchmark_id: str, current_user: User = Depends(get_admin_user)):
|
|
|
|
|
|
"""删除评估基准"""
|
2026-03-17 10:16:44 +08:00
|
|
|
|
from yuxi.services.evaluation_service import EvaluationService
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
service = EvaluationService()
|
|
|
|
|
|
await service.delete_benchmark(benchmark_id)
|
|
|
|
|
|
return {"message": "success", "data": None}
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"删除评估基准失败: {e}, {traceback.format_exc()}")
|
|
|
|
|
|
raise HTTPException(status_code=500, detail=f"删除评估基准失败: {str(e)}")
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-02-20 13:23:20 +08:00
|
|
|
|
@evaluation.get("/benchmarks/{benchmark_id}/download")
|
|
|
|
|
|
async def download_evaluation_benchmark(benchmark_id: str, current_user: User = Depends(get_admin_user)):
|
|
|
|
|
|
"""下载评估基准文件"""
|
2026-03-17 10:16:44 +08:00
|
|
|
|
from yuxi.services.evaluation_service import EvaluationService
|
2026-02-20 13:23:20 +08:00
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
service = EvaluationService()
|
|
|
|
|
|
download_info = await service.get_benchmark_download_info(benchmark_id)
|
|
|
|
|
|
return FileResponse(
|
|
|
|
|
|
path=download_info["file_path"],
|
|
|
|
|
|
filename=download_info["filename"],
|
|
|
|
|
|
media_type="application/x-ndjson",
|
|
|
|
|
|
)
|
|
|
|
|
|
except ValueError as e:
|
|
|
|
|
|
if "not found" in str(e).lower():
|
|
|
|
|
|
raise HTTPException(status_code=404, detail=str(e))
|
|
|
|
|
|
logger.error(f"下载评估基准失败: {e}, {traceback.format_exc()}")
|
|
|
|
|
|
raise HTTPException(status_code=500, detail=f"下载评估基准失败: {str(e)}")
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"下载评估基准失败: {e}, {traceback.format_exc()}")
|
|
|
|
|
|
raise HTTPException(status_code=500, detail=f"下载评估基准失败: {str(e)}")
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-12-10 22:48:53 +08:00
|
|
|
|
@evaluation.get("/databases/{db_id}/results/{task_id}")
|
2025-12-14 18:13:46 +08:00
|
|
|
|
async def get_evaluation_results_by_db(
|
|
|
|
|
|
db_id: str,
|
|
|
|
|
|
task_id: str,
|
|
|
|
|
|
page: int = 1,
|
|
|
|
|
|
page_size: int = 20,
|
|
|
|
|
|
error_only: bool = False,
|
2025-12-14 22:44:18 +08:00
|
|
|
|
current_user: User = Depends(get_admin_user),
|
2025-12-14 18:13:46 +08:00
|
|
|
|
):
|
|
|
|
|
|
"""获取评估结果(带 db_id,支持分页)"""
|
2026-03-17 10:16:44 +08:00
|
|
|
|
from yuxi.services.evaluation_service import EvaluationService
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
|
|
|
|
|
try:
|
2025-12-14 18:13:46 +08:00
|
|
|
|
# 验证分页参数
|
|
|
|
|
|
if page < 1:
|
|
|
|
|
|
raise HTTPException(status_code=400, detail="页码必须大于0")
|
|
|
|
|
|
if page_size < 1 or page_size > 100:
|
|
|
|
|
|
raise HTTPException(status_code=400, detail="每页大小必须在1-100之间")
|
|
|
|
|
|
|
2025-12-09 16:21:18 +08:00
|
|
|
|
service = EvaluationService()
|
2025-12-14 18:13:46 +08:00
|
|
|
|
results = await service.get_evaluation_results_by_db(
|
|
|
|
|
|
db_id, task_id, page=page, page_size=page_size, error_only=error_only
|
|
|
|
|
|
)
|
2025-12-09 16:21:18 +08:00
|
|
|
|
return {"message": "success", "data": results}
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"获取评估结果失败: {e}, {traceback.format_exc()}")
|
|
|
|
|
|
raise HTTPException(status_code=500, detail=f"获取评估结果失败: {str(e)}")
|
|
|
|
|
|
|
|
|
|
|
|
|
2025-12-10 22:48:53 +08:00
|
|
|
|
@evaluation.delete("/databases/{db_id}/results/{task_id}")
|
|
|
|
|
|
async def delete_evaluation_result_by_db(db_id: str, task_id: str, current_user: User = Depends(get_admin_user)):
|
|
|
|
|
|
"""删除评估结果(带 db_id)"""
|
2026-03-17 10:16:44 +08:00
|
|
|
|
from yuxi.services.evaluation_service import EvaluationService
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
service = EvaluationService()
|
2025-12-10 22:48:53 +08:00
|
|
|
|
await service.delete_evaluation_result_by_db(db_id, task_id)
|
2025-12-09 16:21:18 +08:00
|
|
|
|
return {"message": "success", "data": None}
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"删除评估结果失败: {e}, {traceback.format_exc()}")
|
|
|
|
|
|
raise HTTPException(status_code=500, detail=f"删除评估结果失败: {str(e)}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# ============================================================================
|
2026-01-16 14:06:42 +08:00
|
|
|
|
# RAG评估
|
2025-12-09 16:21:18 +08:00
|
|
|
|
# ============================================================================
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@evaluation.post("/databases/{db_id}/benchmarks/upload")
|
|
|
|
|
|
async def upload_evaluation_benchmark(
|
|
|
|
|
|
db_id: str,
|
|
|
|
|
|
file: UploadFile = File(...),
|
|
|
|
|
|
name: str = Form(...),
|
|
|
|
|
|
description: str = Form(""),
|
|
|
|
|
|
current_user: User = Depends(get_admin_user),
|
|
|
|
|
|
):
|
|
|
|
|
|
"""上传评估基准文件"""
|
2026-03-17 10:16:44 +08:00
|
|
|
|
from yuxi.services.evaluation_service import EvaluationService
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
# 验证文件格式
|
|
|
|
|
|
if not file.filename.endswith(".jsonl"):
|
|
|
|
|
|
raise HTTPException(status_code=400, detail="仅支持JSONL格式文件")
|
|
|
|
|
|
|
|
|
|
|
|
# 读取文件内容
|
|
|
|
|
|
content = await file.read()
|
|
|
|
|
|
|
|
|
|
|
|
# 调用评估服务处理上传
|
|
|
|
|
|
service = EvaluationService()
|
|
|
|
|
|
result = await service.upload_benchmark(
|
|
|
|
|
|
db_id=db_id,
|
|
|
|
|
|
file_content=content,
|
|
|
|
|
|
filename=file.filename,
|
|
|
|
|
|
name=name,
|
|
|
|
|
|
description=description,
|
|
|
|
|
|
created_by=current_user.user_id,
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
return {"message": "success", "data": result}
|
|
|
|
|
|
except HTTPException:
|
|
|
|
|
|
raise
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"上传评估基准失败: {e}, {traceback.format_exc()}")
|
|
|
|
|
|
raise HTTPException(status_code=500, detail=f"上传评估基准失败: {str(e)}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@evaluation.get("/databases/{db_id}/benchmarks")
|
|
|
|
|
|
async def get_evaluation_benchmarks(db_id: str, current_user: User = Depends(get_admin_user)):
|
|
|
|
|
|
"""获取知识库的评估基准列表"""
|
2026-03-17 10:16:44 +08:00
|
|
|
|
from yuxi.services.evaluation_service import EvaluationService
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
service = EvaluationService()
|
|
|
|
|
|
benchmarks = await service.get_benchmarks(db_id)
|
|
|
|
|
|
return {"message": "success", "data": benchmarks}
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"获取评估基准列表失败: {e}, {traceback.format_exc()}")
|
|
|
|
|
|
raise HTTPException(status_code=500, detail=f"获取评估基准列表失败: {str(e)}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@evaluation.post("/databases/{db_id}/benchmarks/generate")
|
|
|
|
|
|
async def generate_evaluation_benchmark(
|
|
|
|
|
|
db_id: str, params: dict = Body(...), current_user: User = Depends(get_admin_user)
|
|
|
|
|
|
):
|
|
|
|
|
|
"""自动生成评估基准"""
|
2026-03-17 10:16:44 +08:00
|
|
|
|
from yuxi.services.evaluation_service import EvaluationService
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
service = EvaluationService()
|
|
|
|
|
|
result = await service.generate_benchmark(db_id=db_id, params=params, created_by=current_user.user_id)
|
|
|
|
|
|
return {"message": "success", "data": result}
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"生成评估基准失败: {e}, {traceback.format_exc()}")
|
|
|
|
|
|
raise HTTPException(status_code=500, detail=f"生成评估基准失败: {str(e)}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@evaluation.post("/databases/{db_id}/run")
|
|
|
|
|
|
async def run_evaluation(db_id: str, params: dict = Body(...), current_user: User = Depends(get_admin_user)):
|
|
|
|
|
|
"""运行RAG评估"""
|
2026-03-17 10:16:44 +08:00
|
|
|
|
from yuxi.services.evaluation_service import EvaluationService
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
service = EvaluationService()
|
|
|
|
|
|
task_id = await service.run_evaluation(
|
|
|
|
|
|
db_id=db_id,
|
|
|
|
|
|
benchmark_id=params.get("benchmark_id"),
|
2025-12-09 21:11:51 +08:00
|
|
|
|
model_config=params.get("model_config", {}),
|
2025-12-09 16:21:18 +08:00
|
|
|
|
created_by=current_user.user_id,
|
|
|
|
|
|
)
|
|
|
|
|
|
return {"message": "success", "data": {"task_id": task_id}}
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"启动评估失败: {e}, {traceback.format_exc()}")
|
|
|
|
|
|
raise HTTPException(status_code=500, detail=f"启动评估失败: {str(e)}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@evaluation.get("/databases/{db_id}/history")
|
|
|
|
|
|
async def get_evaluation_history(db_id: str, current_user: User = Depends(get_admin_user)):
|
|
|
|
|
|
"""获取知识库的评估历史记录"""
|
2026-03-17 10:16:44 +08:00
|
|
|
|
from yuxi.services.evaluation_service import EvaluationService
|
2025-12-09 16:21:18 +08:00
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
service = EvaluationService()
|
|
|
|
|
|
history = await service.get_evaluation_history(db_id)
|
|
|
|
|
|
return {"message": "success", "data": history}
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
logger.error(f"获取评估历史失败: {e}, {traceback.format_exc()}")
|
|
|
|
|
|
raise HTTPException(status_code=500, detail=f"获取评估历史失败: {str(e)}")
|