File size: 2,759 Bytes
7e3f910
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5c1d1c7
 
 
 
 
 
 
7e3f910
 
 
 
 
 
 
5c1d1c7
 
 
 
 
7e3f910
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
"""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}