Dom 3a87751444 test: couvrir les modules purs du pipeline (96 nouveaux tests)
Suite de tests unitaires pour tous les modules pipeline qui ne dépendent
pas du VLM — utiles pour garantir la non-régression après refactor et
servir de spec vivante de chaque fonction.

Fichiers :
- tests/test_json_utils.py   (20 tests) : parse_json_output + toutes les
  stratégies de récupération (fences, virgules manquantes, boucles vides,
  fermeture JSON, fallback _raw/_parse_error)
- tests/test_deskew.py       (11 tests) : détection Hough + correction,
  image synthétique + fixtures cache réel
- tests/test_checkboxes.py   (17 tests) : parse_ghs_injustifie,
  dark_ratio, inner_frac, et ground truth visuel sur 17 dossiers
  (mapping hash→OGC résolu au runtime pour éviter les constantes fragiles)
- tests/test_validation.py   (18 tests) : _check_cim10/ccam/ghm/ghs,
  cross-checks GHM↔GHS, annotate sur JSON vide et complet,
  preservation de l'input (copie défensive)
- tests/test_schema.py       (8 tests)  : clean_dossier retire les champs
  debug, préserve les champs métier, compacte la validation, ne modifie
  pas l'input
- tests/test_zones_config.py (8 tests)  : load/save round-trip, merge
  avec defaults, résilience JSON corrompu, get_zone

Total : 107 tests, 5.1 s d'exécution, tous passent. Aucune dépendance
GPU, s'exécutent en CI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 23:29:23 +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%