Coverage for narrative_harm_classifier/api/routes/validate.py: 58%
24 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-07-20 13:25 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-07-20 13:25 +0000
1"""
2api/routes/validate.py — Validation endpoints.
3Runs held-out sample validation and returns performance reports.
4"""
6from fastapi import APIRouter, Depends, HTTPException
7from narrative_harm_classifier.core.models import ValidationSample, ValidationReport
8from narrative_harm_classifier.core.config import get_settings, Settings
9from narrative_harm_classifier.classifier.factory import build_validator
10from narrative_harm_classifier.classifier.validators.performance import (
11 PerformanceValidator,
12 DEHUMANIZATION_VALIDATION_SAMPLES,
13)
15router = APIRouter()
18def get_validator(settings: Settings = Depends(get_settings)) -> PerformanceValidator:
19 return build_validator(settings)
22@router.post(
23 "/dehumanization",
24 response_model=ValidationReport,
25 summary="Run Phase 1 end-to-end validation for priority category: dehumanization",
26 description=(
27 "Validates the dehumanization category against the built-in held-out sample set. "
28 "Checks Precision ≥ 0.70, Recall ≥ 0.65, FPR ≤ 0.20. "
29 "This is the Phase 1 milestone validation gate."
30 ),
31)
32def validate_dehumanization(
33 validator: PerformanceValidator = Depends(get_validator),
34) -> ValidationReport:
35 try:
36 return validator.validate_category(
37 category_name="dehumanization",
38 samples=DEHUMANIZATION_VALIDATION_SAMPLES,
39 )
40 except Exception as e:
41 raise HTTPException(status_code=500, detail=str(e))
44@router.post(
45 "/custom",
46 response_model=ValidationReport,
47 summary="Run validation against a custom sample set",
48)
49def validate_custom(
50 category: str,
51 samples: list[ValidationSample],
52 validator: PerformanceValidator = Depends(get_validator),
53) -> ValidationReport:
54 if not samples:
55 raise HTTPException(status_code=400, detail="At least one sample required")
56 try:
57 return validator.validate_category(category_name=category, samples=samples)
58 except ValueError as e:
59 raise HTTPException(status_code=404, detail=str(e))
60 except Exception as e:
61 raise HTTPException(status_code=500, detail=str(e))