Dom 1255468676 feat(ui): calibration visuelle des zones via dessin à la souris
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>
2026-04-24 23:07:59 +02:00

Aivanov_scan_ogc

Pipeline d'extraction structurée des fiches OGC (contrôles T2A/PMSI de l'Assurance Maladie) à partir de PDFs scannés. Produit un JSON par dossier + validation automatique des codes médicaux contre les référentiels ATIH 2018.


Architecture en une page

PDF scanné (6 pages)
      │
      ▼
┌───────────────┐   pipeline/ingest.py
│   ingest      │   → PNG 300 dpi, cache par hash SHA256
└───────┬───────┘
        ▼
┌───────────────┐   pipeline/classify.py
│   routing     │   → type de page (recueil, concertation_1/2, preuves…)
└───────┬───────┘   → vérif 1 seule page (ordre standard OGC respecté)
        ▼
┌───────────────┐   pipeline/ocr_qwen.py — Qwen2.5-VL-3B (VLM local ~7 Go VRAM)
│   extraction  │   + pipeline/prompts.py — JSON schemas par type de page
│   OCR + JSON  │   + pipeline/checkboxes.py — densité pixels pour Accord/Désaccord
└───────┬───────┘     (les VLM testés n'arrivent pas à lire les cases à cocher)
        ▼
┌───────────────┐   pipeline/validation.py + pipeline/referentials.py
│  validation   │   → lookup ATIH (CIM-10, CCAM, GHM, GHS 2018 en SQLite local)
│   ATIH        │   → suggestion Levenshtein ≤ 1 en cas de code invalide
└───────┬───────┘   → cross-check GHM ↔ GHS
        ▼
┌───────────────┐   pipeline/persist.py — JSON annoté + metadata
│  output JSON  │   pipeline/ui_overlay.py — Streamlit review/annotation
└───────────────┘

Prérequis

  • Python 3.10 3.12
  • Linux ou macOS (testé sur Linux + RTX 5070, et macOS Apple Silicon)
  • GPU : une carte CUDA avec ≥ 8 Go VRAM (Qwen2.5-VL-3B en bfloat16 tient en 7 Go). Sur Apple Silicon, MPS fonctionne mais n'a pas été validé ici.
  • poppler pour pdf2image
  • git, curl

Installation des deps système

Linux (Debian/Ubuntu) :

sudo apt update
sudo apt install -y python3.12 python3.12-venv python3-pip poppler-utils git curl

macOS :

brew install python@3.12 poppler git

Installation du projet

git clone http://localhost:3100/Dom/Aivanov_scan_ogc.git
cd Aivanov_scan_ogc

python3.12 -m venv .venv
source .venv/bin/activate
pip install --upgrade pip

# Deps principales (GPU)
pip install "torch>=2.6" torchvision --index-url https://download.pytorch.org/whl/cu128
pip install transformers "accelerate>=1.0" qwen-vl-utils
pip install pdf2image Pillow openpyxl numpy

# UI + tests
pip install streamlit pytest

Note VRAM : si la carte fait < 8 Go, réduire max_pixels dans pipeline/ocr_qwen.py (max_pixels=1280 * 28 * 28640 * 28 * 28). Si pas de GPU du tout, le modèle tournera sur CPU mais très lentement (≈ 5-10 min par page au lieu de 3 s).

Données d'entrée

Déposer les PDFs à extraire dans un répertoire, par exemple 2018 CARC/ à la racine. Le nom est libre, mais les fichiers doivent suivre le modèle OGC <N>.pdf (ex. OGC 7.pdf). Le répertoire de données n'est pas dans le dépôt (voir .gitignore) — c'est à chacun de récupérer ses scans.

Utilisation

1. Extraire un ou plusieurs dossiers

# Un PDF
python -m pipeline.cli "2018 CARC/OGC 7.pdf"

# Tout un répertoire
python -m pipeline.cli "2018 CARC" --out output/v2

Sortie : output/v2/<nom>.json avec la structure :

{
  "fichier": "OGC 7",
  "pdf_hash": "…",
  "pages": [ { "page": 1, "type": "recueil", "elapsed_s": 6.3,  },  ],
  "extraction": {
    "recueil":        { "etablissement": "…", "ghm_etab": "21M162", …,
                        "_validation": { "summary": {}, "cross_checks": {} } },
    "concertation_2": { "ghs_initial": "…", "decision": "…", "_validation":  },
    "concertation_1": { "argumentaire": "…", "date_concertation": "…" },
    "preuves":        { "date": "…", "pieces": [] }
  },
  "_meta": { "pipeline_version": "v1", "ocr_model": "…", "generated_at": "…" }
}

Temps attendu : ~35 s / dossier (6 pages).

2. Interface de review & annotation

streamlit run pipeline/ui_overlay.py

Ouvre http://localhost:8501. Sélectionner un dossier dans la sidebar ; pour chaque page, l'image est affichée à gauche et les champs extraits (éditables) à droite. Les codes médicaux sont annotés d'un badge ATIH (🟢 valide / 🟡 invalide mais suggestion / 🔴 invalide). Les corrections sont sauvegardées dans gold/<nom>.json.

3. Validation ATIH sur les JSONs existants

python annotate_validation.py     # annote output/v2/*.json et produit validation_report.md

Rapport produit : validation_report.md avec taux de validité par champ, suggestions de correction OCR, incohérences GHM↔GHS.

4. Tests

pytest tests/                     # 11 tests unitaires sur les référentiels ATIH

5. Reconstruction de la base ATIH (si besoin)

La base SQLite referentials/atih_2018.sqlite est déjà incluse dans le dépôt, donc aucune action n'est normalement requise. Si les sources changent :

python -m pipeline.referentials --build   # relit referentials/sources/ → SQLite
python -m pipeline.referentials --stats   # affiche le nombre de codes par table
python -m pipeline.referentials --test    # self-test rapide

Structure des répertoires

Chemin Contenu Dans git ?
pipeline/ Code de production (modules OCR, validation, UI)
pipeline/ui_overlay.py Interface Streamlit
referentials/sources/ Données ATIH brutes (XLSX, XML ClaML, ~8 Mo)
referentials/atih_2018.sqlite Base SQLite générée (3 Mo)
tests/ Tests unitaires
output/ Sorties legacy (pipeline V0 extract_ogc.py)
output/v2/ Sorties pipeline V2 (JSONs annotés ATIH, 18 dossiers)
scratch/ Scripts exploratoires (choix d'OCR) + README
bench_v2_report.md Comparaison V2 vs legacy
validation_report.md Rapport validation ATIH
2018 CARC/ PDFs scannés — à fournir, ignoré par git
.cache/images/ Cache PDF → PNG (reconstructible, gitignoré)
gold/ Annotations manuelles (créé au besoin via l'UI)
.venv/ Environnement Python virtuel
extract_ogc.py Pipeline legacy docTR+VLM (conservé pour comparaison)
generate_pdf.py Reconstruction de PDFs propres depuis JSON (legacy)

État du pipeline (au 2026-04-24)

Qualité mesurée sur 18 dossiers (validation ATIH, fix */+N appliqué) :

Champ Validité
ghm_etab / ghs_etab / ghm_reco / ghs_reco 94 %
codage_etab.dp 94 %
codage_etab.das / codage_reco.das 100 %
codage_etab.dr 79 % (suffixes PMSI)
accord_desaccord (checkboxes) 17/17 sur échantillon vérifié

Limites connues (cf. bench_v2_report.md) :

  • codage_reco.* sous-extrait (27 % de couverture, mais 100 % de validité quand extrait) — la colonne « Recodage » du tableau n'est pas lue systématiquement.
  • praticien_conseil halluciné (biais fréquentiel « DR VIGNAU »).
  • Pages manuscrites (p3 et parfois p6) : hors scope actuel.

Pistes pour la suite :

  1. Prompt explicite colonne Recodage, ou crop demi-page droite en second passage.
  2. Anti-hallucination praticien_conseil (consigne stricte + crop bas de page).
  3. Passage de ghs_injustifie dans checkboxes.py (comme Accord/Désaccord).
  4. Annotation manuelle d'un gold set de 5-10 dossiers via l'UI pour mesurer chaque itération contre une vérité auditée (et pas seulement contre le legacy qui contient lui-même des erreurs).

Références

Description
Pipeline extraction fiches OGC (T2A 2018) — Qwen2.5-VL-3B + validation ATIH
Readme 10 MiB
Languages
Python 100%