extract.py contenait 4 responsabilités mélangées (320 lignes) :
parsing JSON tolérant, résolution de zones, crop Recodage avec classification
métier, orchestration. Séparation en modules cohérents :
- pipeline/json_utils.py : parsing tolérant réutilisable (strip fences,
virgules manquantes, troncature des boucles d'objets vides, fermeture
des structures JSON ouvertes). N'a aucune connaissance métier OGC.
- pipeline/recueil.py : toute la logique spécifique à la page recueil —
résolution de zones configurables, filter_cim10_codes, classification
DP/DR/DAS par règle métier, run_recodage_crop_pass, merge_codage_reco,
enrich_recueil (orchestration des trois : checkboxes + ghs_injustifie
+ crop Recodage). Chaque fonction est testable indépendamment du VLM.
- pipeline/extract.py : réduit à l'orchestration pure — ingest, routing,
boucle page par page, délégation à recueil.enrich_recueil, validation
ATIH finale. Plus aucune logique métier enfouie.
La fonction extract_dossier garde exactement la même signature et produit
le même JSON en sortie : aucun breaking change externe.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Nouveau module pipeline/zones_config.py : charge les zones d'extraction
depuis un fichier zones_config.json (coordonnées relatives 0-1), avec
fallback sur les constantes Python. Config partagée entre :
- pipeline/extract.py (crop colonne Recodage)
- pipeline/checkboxes.py (cases Accord/Désaccord)
Zones configurables aujourd'hui (page recueil) :
- codage_reco (crop zonal pour le second passage VLM)
- accord_checkbox / desaccord_checkbox (densité de pixels)
Mode "🔧 Calibration zones" ajouté dans pipeline/ui_overlay.py :
- Sélection d'un PDF de référence (idéalement bien cadré)
- Canvas interactif (streamlit-drawable-canvas) avec les zones
existantes pré-dessinées en rouge
- Dessin/déplacement/redimensionnement à la souris
- Saisie d'un nom et description par zone
- Sauvegarde en JSON (ou OGC_ZONES_CONFIG si défini)
Permet au métier (Khalid) de recalibrer les zones sans toucher au code,
par exemple si le formulaire ATIH évolue ou si les scans sont d'un autre
établissement.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Qwen renvoie typiquement le libellé complet `0 SE 1 2 3 4 ATU FFM FSD`
dans le champ ghs_injustifie alors qu'une seule valeur 0/1 est attendue.
Ajout de `pipeline.checkboxes.parse_ghs_injustifie` qui extrait le
premier chiffre 0/1 via regex, ou "" si illisible.
Post-traitement appliqué à chaque extraction recueil et aux 18 JSONs
V2 existants (10 fichiers corrigés en place — les 8 autres avaient
déjà ghs_injustifie absent ou vide).
Note sur les 7 cases SE1-4/ATU/FFM/FSD : zones trop petites pour être
calibrées à l'œil et aucun cas positif (`ghs_injustifie=1`) dans
l'échantillon 2018 pour valider visuellement. La détection est en
placeholder, à recalibrer sur un cas positif réel.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>