ranjithkumar111's picture
Upload 10 files
1bfbac9 verified
Raw
History Blame Contribute Delete
4.74 kB
# File: src/evaluate.py
# Purpose: Evaluate pipeline reliability and log hallucination incidents
import json
import time
from pathlib import Path
from datetime import datetime
import sys
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from config import OUTPUTS_DIR
EVAL_LOG_PATH = OUTPUTS_DIR / "eval_results.jsonl"
TEST_TRANSCRIPTS = [
{
"id": "TC001",
"transcript": "I want to book a cardiology appointment tomorrow at 2 PM. My name is Ranjith.",
"expected_department": "Cardiology",
"expected_slot": "2:00 PM",
},
{
"id": "TC002",
"transcript": "Please book neurology for next Monday at 10 AM. Patient is Priya Sharma.",
"expected_department": "Neurology",
"expected_slot": "10:00 AM",
},
{
"id": "TC003",
"transcript": "umm I want to see someone maybe some day soon", # Low confidence case
"expected_department": None,
"expected_escalated": True,
},
{
"id": "TC004",
"transcript": "Book dermatology at 4 PM on 2025-06-10 for Kavya Nair.",
"expected_department": "Dermatology",
"expected_slot": "4:00 PM",
},
]
def run_evaluation(test_cases: list[dict] | None = None, verbose: bool = True) -> dict:
"""
Run pipeline against test cases and evaluate:
- Intent extraction accuracy
- Escalation correctness
- Hallucination incidents (response claims success without verified ID)
- End-to-end latency
Args:
test_cases: List of test dicts. Defaults to TEST_TRANSCRIPTS.
verbose: Print results as they run.
Returns:
Summary dict with pass_rate, hallucination_count, avg_latency_s
"""
from src.pipeline import run_pipeline
cases = test_cases or TEST_TRANSCRIPTS
results = []
hallucination_count = 0
OUTPUTS_DIR.mkdir(parents=True, exist_ok=True)
for case in cases:
start = time.time()
result = run_pipeline(case["transcript"])
latency = round(time.time() - start, 3)
intent = result.get("intent", {})
verification = result.get("verification")
escalated = result.get("escalated", False)
response = result.get("response", "")
# Hallucination check: response must not claim success without verified ID
is_hallucination = False
if "confirmed" in response.lower() or "reference number" in response.lower():
if verification is None or not verification.verified or not verification.appointment_id:
is_hallucination = True
hallucination_count += 1
# Intent accuracy check
dept_correct = (
intent.get("department") == case.get("expected_department")
if case.get("expected_department")
else True
)
escalation_correct = (
escalated == case.get("expected_escalated", False)
)
record = {
"id": case["id"],
"transcript": case["transcript"],
"extracted_department": intent.get("department"),
"extracted_slot": intent.get("slot"),
"confidence": intent.get("confidence"),
"escalated": escalated,
"verified": verification.verified if verification else None,
"appointment_id": verification.appointment_id if verification else None,
"is_hallucination": is_hallucination,
"dept_correct": dept_correct,
"escalation_correct": escalation_correct,
"latency_s": latency,
"response_preview": response[:100],
"timestamp": datetime.now().isoformat(),
}
results.append(record)
with open(EVAL_LOG_PATH, "a") as f:
f.write(json.dumps(record) + "\n")
if verbose:
status = "PASS" if not is_hallucination else "HALLUCINATION"
print(f"[Eval] {case['id']}: {status} | dept_ok={dept_correct} | "
f"confidence={intent.get('confidence')} | latency={latency}s")
pass_count = sum(1 for r in results if not r["is_hallucination"])
avg_latency = round(sum(r["latency_s"] for r in results) / len(results), 3)
summary = {
"total": len(results),
"pass_rate": round(pass_count / len(results), 3),
"hallucination_count": hallucination_count,
"avg_latency_s": avg_latency,
"timestamp": datetime.now().isoformat(),
}
print(f"\n[Eval] Summary: {json.dumps(summary, indent=2)}")
return summary
if __name__ == "__main__":
run_evaluation()