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."""
|
||||
id: str
|
||||
document_id: str
|
||||
document_filename: str = ""
|
||||
benchmark_config: dict
|
||||
questions: list[dict]
|
||||
per_question: list[dict]
|
||||
|
||||
@@ -154,9 +154,15 @@ async def get_benchmark(experiment_id: str):
|
||||
if result is None:
|
||||
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(
|
||||
id=result["id"],
|
||||
document_id=result["document_id"],
|
||||
document_filename=doc_filename,
|
||||
benchmark_config=result.get("benchmark_config", {}),
|
||||
questions=result.get("questions", []),
|
||||
per_question=result.get("per_question", []),
|
||||
@@ -171,7 +177,35 @@ async def get_benchmark(experiment_id: str):
|
||||
@router.get("/experiments")
|
||||
async def list_experiments(document_id: str | None = None):
|
||||
"""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)
|
||||
|
||||
Reference in New Issue
Block a user