Picarones / picarones /evaluation /metrics /builtin_metrics.py
Claude
feat(sprint-E.4): 3 modules hooks/registres migrΓ©s vers evaluation/metrics/
ad8d926 unverified
Raw
History Blame
6.01 kB
"""MΓ©triques natives enregistrΓ©es dans le registre typΓ© (Sprint 34).
Ce module est un dΓ©monstrateur d'enregistrement : il expose les
mΓ©triques scalaires existantes (CER, WER, MER, WIL) sous une forme
unitaire dans le registre, plus un stub typé hétérogène pour les
jonctions ``(TEXT, ALTO)``.
L'import du module suffit Γ  peupler le registre β€” le dΓ©corateur
``@register_metric`` s'exΓ©cute Γ  l'import. Les sprints suivants (axe A
du plan d'Γ©volution) ajouteront ici les mΓ©triques structurelles
(``reading_order_f1``, ``layout_f1``), philologiques (``unicode_block_*``,
``mufi_coverage``), et de fiabilitΓ© (``ece``, ``mce``).
Important β€” pas de double calcul
-------------------------------
Ces wrappers ne **remplacent pas** ``compute_metrics`` du module
``metrics.py``. Ils existent pour les nouveaux chemins (pipelines
composΓ©es qui calculent par jonction). Le rapport HTML existant
continue Γ  passer par ``compute_metrics`` et reste donc strictement
identique octet par octet (critère de la Phase 0.3).
"""
from __future__ import annotations
import logging
from picarones.evaluation.metric_registry import register_metric
from picarones.domain.artifacts import ArtifactType
logger = logging.getLogger(__name__)
try:
import jiwer
_JIWER_AVAILABLE = True
except ImportError:
_JIWER_AVAILABLE = False
# ──────────────────────────────────────────────────────────────────────────
# MΓ©triques scalaires (TEXT, TEXT) β€” wrappers fins autour de jiwer
# ──────────────────────────────────────────────────────────────────────────
def _safe_jiwer_call(fn, reference: str, hypothesis: str) -> float:
"""Wrapper qui gère les cas dégénérés (références ou hypothèses vides)."""
if not _JIWER_AVAILABLE:
raise RuntimeError(
"jiwer n'est pas installΓ© β€” installer avec `pip install jiwer`"
)
if not reference:
return 0.0 if not hypothesis else 1.0
if not hypothesis:
return 1.0
return fn(reference, hypothesis)
@register_metric(
name="cer",
input_types=(ArtifactType.TEXT, ArtifactType.TEXT),
description="Character Error Rate (distance d'Γ©dition normalisΓ©e par la longueur de la GT).",
higher_is_better=False,
tags={"text", "edit_distance", "error_rate"},
)
def cer(reference: str, hypothesis: str) -> float:
"""CER brut sur les caractères, via jiwer."""
return _safe_jiwer_call(jiwer.cer, reference, hypothesis)
@register_metric(
name="wer",
input_types=(ArtifactType.TEXT, ArtifactType.TEXT),
description="Word Error Rate.",
higher_is_better=False,
tags={"text", "edit_distance", "error_rate"},
)
def wer(reference: str, hypothesis: str) -> float:
"""WER brut, via jiwer."""
return _safe_jiwer_call(jiwer.wer, reference, hypothesis)
@register_metric(
name="mer",
input_types=(ArtifactType.TEXT, ArtifactType.TEXT),
description="Match Error Rate (jiwer).",
higher_is_better=False,
tags={"text", "error_rate"},
)
def mer(reference: str, hypothesis: str) -> float:
return _safe_jiwer_call(jiwer.mer, reference, hypothesis)
@register_metric(
name="wil",
input_types=(ArtifactType.TEXT, ArtifactType.TEXT),
description="Word Information Lost (jiwer).",
higher_is_better=False,
tags={"text", "error_rate"},
)
def wil(reference: str, hypothesis: str) -> float:
return _safe_jiwer_call(jiwer.wil, reference, hypothesis)
# ──────────────────────────────────────────────────────────────────────────
# Métrique typée hétérogène (TEXT, ALTO) — stub démonstrateur
# ──────────────────────────────────────────────────────────────────────────
@register_metric(
name="text_preservation_after_reconstruction",
input_types=(ArtifactType.TEXT, ArtifactType.ALTO),
description=(
"Taux de tokens de la GT texte prΓ©sents dans le texte extrait de "
"l'ALTO produit (preuve de concept ; remplaΓ§able par une mesure "
"alignΓ©e par les sprints futurs)."
),
higher_is_better=True,
tags={"structure", "preservation", "stub"},
)
def text_preservation_after_reconstruction(
reference_text: str,
hypothesis_alto: str,
) -> float:
"""Stub dΓ©monstrateur d'une jonction texte β†’ ALTO.
Sprints Γ  venir (axe A du plan d'Γ©volution) remplaceront cette
implΓ©mentation par une vraie mesure de prΓ©servation : extraction
structurΓ©e du texte ALTO via le parser dΓ©diΓ©, alignement, calcul
dΓ©terministe. Pour l'instant la mesure est volontairement simple
pour dΓ©montrer le mΓ©canisme.
Parameters
----------
reference_text:
Texte GT (niveau ``ArtifactType.RAW_TEXT``).
hypothesis_alto:
ALTO XML brut produit par un module de reconstruction (niveau
``ArtifactType.ALTO``).
Returns
-------
float
Taux de tokens uniques de ``reference_text`` apparaissant dans
``hypothesis_alto`` (case-insensitive). ``1.0`` = tous les
tokens prΓ©servΓ©s.
"""
if not reference_text:
return 1.0
ref_tokens = {tok.lower() for tok in reference_text.split() if tok}
if not ref_tokens:
return 1.0
alto_text = hypothesis_alto.lower()
preserved = sum(1 for tok in ref_tokens if tok in alto_text)
return preserved / len(ref_tokens)
__all__ = [
"cer",
"wer",
"mer",
"wil",
"text_preservation_after_reconstruction",
]