Picarones / picarones /evaluation /views /alto_view.py
Claude
feat(evaluation): Sprint A14-S15 — AltoView (vue canonique 2) + 3 métriques structurelles + pattern d'omission
99ad1af unverified
Raw
History Blame
4.92 kB
"""``AltoView`` — vue canonique 2, Sprint A14-S15.
Deuxième vue d'évaluation canonique : "quel pipeline produit le
meilleur ALTO exploitable ?".
Distinct de ``TextView`` (S14)
------------------------------
``TextView`` projette tout vers texte plat et ignore la structure
documentaire. ``AltoView`` fait l'inverse : exige un ``ALTO_XML``
en entrée et mesure la **fidélité structurelle** (validité,
nombre de lignes, présence des bbox de mots, etc.).
Un même pipeline peut être évalué dans les deux vues. Le rapport
HTML (S22) présentera les deux côte-à-côte pour qu'un lecteur
comprenne *pourquoi* deux pipelines avec le même CER produisent
des ALTO de qualités différentes.
Pipelines omis explicitement
----------------------------
Un pipeline qui ne produit pas d'``ALTO_XML`` (exemple : Tesseract
texte brut sans ALTO) ne peut pas être évalué dans ``AltoView``.
Le caller (typiquement un service applicatif au S19) doit
**omettre** ce pipeline du résultat ``AltoView`` plutôt que de lui
attribuer un score factice à 0.
Le pattern est démontré dans le test
``tests/evaluation/views/test_sprint_a14_s15_alto_view.py`` :
le caller boucle sur ``[TextView, AltoView]`` et pour chaque vue
filtre les pipelines dont l'artefact n'est pas dans
``view.candidate_types``.
Métriques par défaut
--------------------
- ``alto_validity`` — l'hypothèse est-elle structurellement
cohérente ? (≥ 1 page, ≥ 1 bloc, ≥ 1 ligne).
- ``alto_line_count_ratio`` — ratio min/max du nombre de lignes.
- ``alto_word_box_coverage`` — fraction des mots qui ont une bbox.
Toutes ∈ [0, 1] avec ``higher_is_better=True``.
Reportées à un sprint suivant
-----------------------------
- ``textline_alignment`` (IoU des bbox de lignes).
- ``reading_order_consistency`` (Kendall tau sur les IDs).
- ``layout_f1`` (ICDAR 2015) via wrapper de
``evaluation/metrics/layout.py``.
"""
from __future__ import annotations
from picarones.domain.artifacts import ArtifactType
from picarones.domain.evaluation_spec import EvaluationView
#: Métriques calculées par défaut. Toutes typées
#: ``(ALTO_XML, ALTO_XML)``.
DEFAULT_ALTO_METRICS: tuple[str, ...] = (
"alto_validity",
"alto_line_count_ratio",
"alto_word_box_coverage",
)
#: Types acceptés. Volontairement strict : seul ``ALTO_XML``
#: passe. PAGE_XML pourrait être ajouté via une projection
#: ``page_to_alto`` (post-livraison) si le besoin se présente.
DEFAULT_ALTO_CANDIDATE_TYPES: frozenset[ArtifactType] = frozenset({
ArtifactType.ALTO_XML,
})
#: Dimensions explicitement non évaluées.
DEFAULT_ALTO_IGNORED_DIMENSIONS: tuple[str, ...] = (
# Qualité linguistique pure : c'est TextView (S14) qui la mesure.
"linguistic_quality",
# Recherchabilité fuzzy : c'est SearchView (S16).
"search_recall",
# Hallucinations contenu : c'est HallucinationView (post-S18).
"content_hallucination",
)
#: Avertissement par défaut affiché en tête du bloc AltoView.
DEFAULT_ALTO_WARNINGS: tuple[str, ...] = (
"Cette vue mesure la fidélité STRUCTURELLE de l'ALTO produit "
"(validité, nombre de lignes, bbox). La qualité TEXTUELLE de "
"ce qui est dans cet ALTO est mesurée par TextView ; les deux "
"doivent être lues ensemble pour juger un pipeline.",
"Les pipelines qui ne produisent pas d'ALTO sont OMIS de cette "
"vue. Aucun score factice n'est attribué à un pipeline absent.",
)
def build_alto_view(
*,
name: str = "alto_documentary",
description: str = (
"Mesure la fidélité structurelle de l'ALTO produit par un "
"pipeline (validité, lignes, bbox)."
),
metric_names: tuple[str, ...] | None = None,
extra_warnings: tuple[str, ...] = (),
extra_ignored_dimensions: tuple[str, ...] = (),
) -> EvaluationView:
"""Construit la vue canonique AltoView.
Pas de ``candidate_types`` paramétrable (la vue exige par
nature ALTO_XML uniquement) ni de ``projection``
(l'évaluation se fait sur l'ALTO tel quel, pas sur sa
projection).
Le caller qui veut une vue plus stricte (par exemple "exiger
aussi le mapping vers une GT_ALTO précise") peut composer
plusieurs ``AltoView`` paramétrées.
"""
return EvaluationView(
name=name,
description=description,
candidate_types=DEFAULT_ALTO_CANDIDATE_TYPES,
projection=None,
projections_by_source_type={},
normalization_profile=None,
metric_names=(
metric_names if metric_names is not None
else DEFAULT_ALTO_METRICS
),
warnings=DEFAULT_ALTO_WARNINGS + extra_warnings,
ignored_dimensions=DEFAULT_ALTO_IGNORED_DIMENSIONS + extra_ignored_dimensions,
)
__all__ = [
"build_alto_view",
"DEFAULT_ALTO_METRICS",
"DEFAULT_ALTO_CANDIDATE_TYPES",
"DEFAULT_ALTO_IGNORED_DIMENSIONS",
"DEFAULT_ALTO_WARNINGS",
]