feat(benchmarking): add document filename and delete experiment endpoint
Why:
- Experiment list and detail responses showed raw IDs instead of filenames
- No way to delete experiments from the UI
Changes:
- Add document_filename field to ExperimentDetailResponse
- Enrich list endpoint with filenames and calculated best_strategy from aggregate_metrics
- Add DELETE /experiments/{id} endpoint
Impact:
- API responses now include document_filename for all experiment endpoints
- Frontend can display filenames instead of IDs
This commit is contained in:
@@ -119,6 +119,7 @@ class ExperimentDetailResponse(BaseModel):
|
|||||||
"""Returned when retrieving an experiment."""
|
"""Returned when retrieving an experiment."""
|
||||||
id: str
|
id: str
|
||||||
document_id: str
|
document_id: str
|
||||||
|
document_filename: str = ""
|
||||||
benchmark_config: dict
|
benchmark_config: dict
|
||||||
questions: list[dict]
|
questions: list[dict]
|
||||||
per_question: list[dict]
|
per_question: list[dict]
|
||||||
|
|||||||
@@ -154,9 +154,15 @@ async def get_benchmark(experiment_id: str):
|
|||||||
if result is None:
|
if result is None:
|
||||||
raise BenchmarkError(f"Experiment not found: {experiment_id}")
|
raise BenchmarkError(f"Experiment not found: {experiment_id}")
|
||||||
|
|
||||||
|
# Resolve document filename
|
||||||
|
from src.storage import sqlite as db
|
||||||
|
doc = db.get_document(result.get("document_id", ""))
|
||||||
|
doc_filename = doc.get("filename", "Unknown") if doc else "Deleted"
|
||||||
|
|
||||||
return ExperimentDetailResponse(
|
return ExperimentDetailResponse(
|
||||||
id=result["id"],
|
id=result["id"],
|
||||||
document_id=result["document_id"],
|
document_id=result["document_id"],
|
||||||
|
document_filename=doc_filename,
|
||||||
benchmark_config=result.get("benchmark_config", {}),
|
benchmark_config=result.get("benchmark_config", {}),
|
||||||
questions=result.get("questions", []),
|
questions=result.get("questions", []),
|
||||||
per_question=result.get("per_question", []),
|
per_question=result.get("per_question", []),
|
||||||
@@ -171,7 +177,35 @@ async def get_benchmark(experiment_id: str):
|
|||||||
@router.get("/experiments")
|
@router.get("/experiments")
|
||||||
async def list_experiments(document_id: str | None = None):
|
async def list_experiments(document_id: str | None = None):
|
||||||
"""List all experiments, optionally filtered by document."""
|
"""List all experiments, optionally filtered by document."""
|
||||||
return benchmark_service.list_experiments(document_id=document_id)
|
result = benchmark_service.list_experiments(document_id=document_id)
|
||||||
|
# Enrich with document filenames and best_strategy
|
||||||
|
from src.storage import sqlite as db
|
||||||
|
for item in result.get("items", []):
|
||||||
|
doc = db.get_document(item.get("document_id", ""))
|
||||||
|
item["document_filename"] = doc.get("filename", "Unknown") if doc else "Deleted"
|
||||||
|
# Calculate best_strategy from aggregate_metrics
|
||||||
|
aggs = item.get("aggregate_metrics", {})
|
||||||
|
best_strat, best_score = "N/A", -1
|
||||||
|
for strat, m in aggs.items():
|
||||||
|
score = (m.get("avg_context_relevance", 0) * 0.3 +
|
||||||
|
m.get("avg_answer_similarity", 0) * 0.4 +
|
||||||
|
m.get("avg_faithfulness", 0) * 0.3)
|
||||||
|
adjusted = score * (1 - m.get("hallucination_rate", 0))
|
||||||
|
if adjusted > best_score:
|
||||||
|
best_score = adjusted
|
||||||
|
best_strat = strat
|
||||||
|
item["best_strategy"] = best_strat
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
@router.delete("/experiments/{experiment_id}")
|
||||||
|
async def delete_experiment(experiment_id: str):
|
||||||
|
"""Delete an experiment by ID."""
|
||||||
|
from src.storage import sqlite as db
|
||||||
|
deleted = db.delete_experiment(experiment_id)
|
||||||
|
if not deleted:
|
||||||
|
raise BenchmarkError(f"Experiment not found: {experiment_id}")
|
||||||
|
return {"deleted": True, "experiment_id": experiment_id}
|
||||||
|
|
||||||
|
|
||||||
@router.get("/benchmarks/{experiment_id}/report", response_class=HTMLResponse)
|
@router.get("/benchmarks/{experiment_id}/report", response_class=HTMLResponse)
|
||||||
|
|||||||
Reference in New Issue
Block a user