Spaces:
Runtime error
Runtime error
| from __future__ import annotations | |
| import json | |
| from dataclasses import asdict, dataclass | |
| from pathlib import Path | |
| from typing import Any | |
| from .demo_pack import ingest_demo_pack, load_index | |
| from .storage import init_db, connect, DEFAULT_ARTIFACTS_DIR | |
| from .tracing import write_trace_artifact | |
| class EvalResult: | |
| scenario_id: str | |
| query: str | |
| top_sections: list[dict[str, Any]] | |
| expected_section_ids: list[int] | |
| expected_section_titles: list[str] | |
| hit_top3: bool | |
| safety_present: bool | |
| sufficient: bool | |
| def load_scenarios(pack_dir: str | Path) -> list[dict[str, Any]]: | |
| pack_dir = Path(pack_dir) | |
| with open(pack_dir / "golden_scenarios.json", "r", encoding="utf-8") as f: | |
| return json.load(f) | |
| def evaluate_pack(pack_dir: str | Path, db_path: str | Path | None = None, artifact_dir: str | Path | None = None) -> dict[str, Any]: | |
| pack_dir = Path(pack_dir) | |
| init_db(db_path) | |
| ingest_demo_pack(pack_dir, db_path=db_path, reset=True) | |
| scenarios = load_scenarios(pack_dir) | |
| index = load_index(db_path) | |
| from .reasoning import build_response | |
| results: list[EvalResult] = [] | |
| for scenario in scenarios: | |
| query = scenario["symptom"] | |
| if scenario.get("equipment_type"): | |
| query += " " + scenario["equipment_type"] | |
| if scenario.get("notes"): | |
| query += " " + scenario["notes"] | |
| hits = index.search_sections(query, top_k=5) | |
| top_ids = [hit.record_id for hit in hits[:3]] | |
| top_titles = [hit.title.lower() for hit in hits[:3]] | |
| expected_titles = [t.lower() for t in scenario.get("expected_section_titles", [])] | |
| expected_ids = set(scenario.get("expected_section_ids", [])) | |
| hit_top3 = bool(expected_ids & set(top_ids)) if expected_ids else any( | |
| any(expected in title for title in top_titles) | |
| for expected in expected_titles | |
| ) | |
| response_body, _, payload = build_response( | |
| scenario["symptom"], | |
| scenario.get("equipment_type", ""), | |
| scenario.get("location", ""), | |
| scenario.get("notes", ""), | |
| scenario.get("photo_path"), | |
| index, | |
| ) | |
| safety_present = "Safety reminder" in response_body or "safety reminder" in response_body.lower() | |
| sufficient = payload.get("status") == "insufficient_evidence" | |
| results.append( | |
| EvalResult( | |
| scenario_id=scenario["scenario_id"], | |
| query=query, | |
| top_sections=[ | |
| { | |
| "id": hit.record_id, | |
| "title": hit.title, | |
| "score": round(hit.score, 4), | |
| "citation": hit.citation, | |
| } | |
| for hit in hits[:5] | |
| ], | |
| expected_section_ids=expected_ids and list(expected_ids) or scenario.get("expected_section_ids", []), | |
| expected_section_titles=scenario.get("expected_section_titles", []), | |
| hit_top3=hit_top3, | |
| safety_present=safety_present, | |
| sufficient=sufficient, | |
| ) | |
| ) | |
| total = len(results) | |
| eligible = [result for result in results if not result.sufficient] | |
| top3_hits = sum(1 for result in eligible if result.hit_top3) | |
| safety_hits = sum(1 for result in results if result.safety_present) | |
| insufficient_cases = sum(1 for result in results if result.sufficient) | |
| report = { | |
| "model_name": payload.get("llm_stats", {}).get("model_id", "nvidia/NeMoTRON-3-Nano-4B-Instruct"), | |
| "pack": str(pack_dir), | |
| "scenario_count": total, | |
| "top3_hit_rate": round(top3_hits / len(eligible) if eligible else 0.0, 3), | |
| "safety_presence_rate": round(safety_hits / total if total else 0.0, 3), | |
| "insufficient_cases": insufficient_cases, | |
| "results": [asdict(result) for result in results], | |
| } | |
| trace_dir = Path(artifact_dir) if artifact_dir is not None else DEFAULT_ARTIFACTS_DIR | |
| trace_path = write_trace_artifact(trace_dir, {"kind": "eval", **report}) | |
| report["trace_path"] = str(trace_path) | |
| return report | |
| def main() -> None: | |
| import argparse | |
| parser = argparse.ArgumentParser(description="Evaluate P3 field repair logbook golden scenarios") | |
| parser.add_argument("--pack", required=True, help="Path to demo pack") | |
| parser.add_argument("--db", default=None, help="SQLite database path") | |
| args = parser.parse_args() | |
| report = evaluate_pack(args.pack, db_path=args.db) | |
| print(json.dumps(report, indent=2)) | |
| if __name__ == "__main__": | |
| main() | |