AgentEvalTool/backend/agenteval/web/routers/reports.py
sinohqb f285738f6d refactor(report): split report generation from pure rendering
report.py mixed DB-reading generation with string formatting: the four
render_*_report(run_id, session) functions each re-fetched via
generate_report, so the HTML/Markdown/JSON formatting was welded to storage
and could not be unit-tested from a plain dict. Extract the formatting into a
new pure report_render module whose renderers take the already-built report
dict (no session, no storage import). Migrate every caller to generate-then-
render, delete the old coupled renderers with no back-compat shim, and drop
the _aggregate_runs middle-man alias in favour of metrics.aggregate_runs.
2026-07-31 10:19:04 +08:00

75 lines
2.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""API routes for evaluation reports."""
from fastapi import APIRouter, Depends, HTTPException, Query, Response
from sqlmodel import Session
from agenteval.evaluation.report import generate_compare_report, generate_report
from agenteval.evaluation.report_render import render_html, render_json, render_markdown
from agenteval.storage.repository import RunRepository
from agenteval.web.deps import get_db
router = APIRouter()
@router.get("/compare")
def get_compare_report(
run1: str = Query(..., description="First run ID"),
run2: str = Query(..., description="Second run ID"),
session: Session = Depends(get_db),
) -> dict:
repo = RunRepository(session)
run_a = repo.get(run1)
run_b = repo.get(run2)
if not run_a:
raise HTTPException(status_code=404, detail=f"run not found: {run1}")
if not run_b:
raise HTTPException(status_code=404, detail=f"run not found: {run2}")
if run_a.scenario_id != run_b.scenario_id:
raise HTTPException(status_code=400, detail="对比报告要求两个运行使用相同场景")
if run_a.scenario_version != run_b.scenario_version:
raise HTTPException(
status_code=400,
detail=f"对比报告要求相同的场景考纲版本A: v{run_a.scenario_version}, B: v{run_b.scenario_version}"
"考纲变更前后的运行不可比",
)
return generate_compare_report(run1, run2, session)
@router.get("/{run_id}")
def get_report(run_id: str, session: Session = Depends(get_db)) -> dict:
run = RunRepository(session).get(run_id)
if not run:
raise HTTPException(status_code=404, detail="run not found")
return generate_report(run_id, session)
@router.get("/{run_id}/html")
def get_html_report(run_id: str, session: Session = Depends(get_db)) -> Response:
run = RunRepository(session).get(run_id)
if not run:
raise HTTPException(status_code=404, detail="run not found")
html = render_html(generate_report(run_id, session))
return Response(content=html, media_type="text/html")
@router.get("/{run_id}/json")
def get_json_report(run_id: str, session: Session = Depends(get_db)) -> Response:
run = RunRepository(session).get(run_id)
if not run:
raise HTTPException(status_code=404, detail="run not found")
json_text = render_json(generate_report(run_id, session))
return Response(content=json_text, media_type="application/json")
@router.get("/{run_id}/markdown")
def get_markdown_report(run_id: str, session: Session = Depends(get_db)) -> Response:
run = RunRepository(session).get(run_id)
if not run:
raise HTTPException(status_code=404, detail="run not found")
md = render_markdown(generate_report(run_id, session))
return Response(
content=md,
media_type="text/markdown; charset=utf-8",
headers={"Content-Disposition": f'attachment; filename="report-{run_id}.md"'},
)