expAge
feat(phase-11): moteur d'inférence + consolidation + soumission
5c1d1c7
"""Modèles Pydantic pour le fact-checker."""
from __future__ import annotations
from enum import Enum
from typing import List, Optional
from pydantic import BaseModel, ConfigDict, Field
class Status(str, Enum):
SUPPORTED = "supported" # JDM confirme directement le triplet
CONTRADICTED = "contradicted" # JDM contient une info incompatible
UNKNOWN = "unknown" # JDM ne dit rien à ce sujet
class Claim(BaseModel):
"""Une affirmation atomique extraite d'un texte, sous forme structurée.
`polarity = False` signifie une négation ("La baleine N'EST PAS un poisson").
"""
model_config = ConfigDict(extra="ignore")
text: str = Field(..., description="Formulation originale de l'affirmation")
subject: str = Field(..., description="Terme source (en minuscule, à l'infinitif si verbe)")
relation: str = Field(..., description="Nom technique JDM (r_isa, r_carac, r_has_color, r_agent, r_patient, ...)")
object: str = Field(..., description="Terme cible de la relation")
polarity: bool = Field(True, description="True = affirmation, False = négation")
class Evidence(BaseModel):
"""Un triplet JDM qui sert de preuve pour/contre une claim."""
source: str
relation: str
target: str
w: float
# Identifiants bruts si refinements (rarement nécessaires pour le fact-checking).
source_id: Optional[str] = None
target_id: Optional[str] = None
class Verdict(BaseModel):
"""Le verdict de vérification pour une `Claim`.
`inference_schema` est `None` pour un verdict obtenu par lookup DIRECT
(contenance JDM). Il porte le nom du schéma quand le verdict provient du
moteur d'inférence (Phase 11) — la `inference_proof` détaille alors la
chaîne de déduction.
"""
claim: Claim
status: Status
confidence: float = Field(0.0, ge=0.0, le=1.0,
description="Confiance dans le verdict (0-1)")
evidence_for: List[Evidence] = Field(default_factory=list)
evidence_against: List[Evidence] = Field(default_factory=list)
explanation: str = ""
inference_schema: Optional[str] = Field(
None, description="Nom du schéma d'inférence (None = verdict direct)")
inference_proof: List[Evidence] = Field(
default_factory=list,
description="Chaîne de triplets justifiant un verdict inféré")
class Report(BaseModel):
"""Rapport global d'un fact-check (sur un texte ou une batch de claims)."""
text: str = ""
verdicts: List[Verdict] = Field(default_factory=list)
def summary(self) -> dict:
c = {s.value: 0 for s in Status}
for v in self.verdicts:
c[v.status.value] += 1
return {"total": len(self.verdicts), **c}