Guide de démarrage pour un nouveau collaborateur : - Prérequis système (Python 3.10+, poppler, GPU ≥ 8 Go VRAM) - Installation (Debian/Ubuntu et macOS) et venv Python - Commandes principales : pipeline.cli, ui_overlay Streamlit, annotate_validation, tests, reconstruction ATIH - Structure des répertoires (ce qui est dans git vs ignoré) - Schéma d'architecture et format du JSON produit - État actuel chiffré + limites connues + pistes suite Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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_pixelsdanspipeline/ocr_qwen.py(max_pixels=1280 * 28 * 28→640 * 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_conseilhalluciné (biais fréquentiel « DR VIGNAU »).- Pages manuscrites (p3 et parfois p6) : hors scope actuel.
Pistes pour la suite :
- Prompt explicite colonne Recodage, ou crop demi-page droite en second passage.
- Anti-hallucination praticien_conseil (consigne stricte + crop bas de page).
- Passage de
ghs_injustifiedanscheckboxes.py(comme Accord/Désaccord). - 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
- Modèle OCR : Qwen/Qwen2.5-VL-3B-Instruct
- Référentiels ATIH : CIM-10 FR à usage PMSI, CCAM descriptive, Manuel des GHM, Tarifs MCO (atih.sante.fr)
- Licence : interne, projet non redistribué