Files
Aivanov_scan_ogc/scratch/test_prompt_ab.py
Dom 71f91d9c31 chore(scratch): archives des scripts exploratoires de choix d'OCR
Conservés comme trace de recherche — non documentés, non factorisés,
ne pas dépendre de ce dossier depuis le code de production.

- test_glm_ocr.py          : benchmark GLM-OCR 0.9B (écarté pour
                             faiblesse sur dp_libelle, praticien et
                             colonne Recodage).
- test_got_ocr.py          : tests GOT-OCR2.0 (échec sur tableaux
                             denses à en-têtes verticaux).
- test_paddle.py           : tentative PaddleOCR (incompatible avec
                             paddlepaddle installé).
- test_surya.py            : tentative Surya (incompatible
                             transformers 5.6).
- test_qwen_vl.py          : Qwen2.5-VL-7B (excellent mais 220s/page,
                             écarté faute de VRAM et vitesse).
- test_qwen_vl_3b.py       : Qwen2.5-VL-3B (retenu, 3s/page, qualité
                             > GLM-OCR sur les champs critiques).
- test_prompt_ab.py        : A/B test prompts Accord/Désaccord.
- test_prompt_crop*.py     : prompts + crop ciblé checkboxes (échec
                             → module pipeline/checkboxes.py).
- test_prompt_recueil_*.py : prompts page recueil (consignes verbeuses
                             dégradent la sortie, cf. discussion).
- README.md                : index du dossier.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-24 15:06:44 +02:00

80 lines
3.0 KiB
Python

"""A/B test : effet du prompt engineering sur la détection Accord/Désaccord.
Ground truth (vérifié visuellement sur les images) :
- OGC 7 p1 → "accord"
- OGC 55 p1 → "désaccord"
- OGC 27 p1 → "désaccord"
"""
import time
from pathlib import Path
from pipeline.ocr_glm import GLMOCR
from pipeline.ingest import pdf_to_images
# --- Variantes de prompt ---
PROMPTS = {
# V0 : ce que fait actuellement la V1 — schéma JSON complet
"V0_json_schema_complet": """Lis la fiche médicale OGC et renvoie STRICTEMENT le JSON suivant :
{
"etablissement": "", "finess": "", "n_ogc": "",
"ghm_etab": "", "ghs_etab": "",
"accord_desaccord": "",
"praticien_conseil": ""
}""",
# V1 : JSON minimal, seulement la checkbox
"V1_json_cible": """Regarde la fiche médicale OGC et renvoie UNIQUEMENT ce JSON :
{"accord_desaccord": ""}
Pour accord_desaccord, écris "accord" ou "désaccord" selon la case cochée en bas à droite (zone "Accord □ Désaccord □").""",
# V2 : question directe en langage naturel
"V2_question_naturelle": """Sur la fiche médicale OGC, en bas à droite, il y a deux cases à cocher : "Accord" et "Désaccord". Quelle case est cochée ? Réponds UNIQUEMENT par un seul mot : "accord" ou "désaccord".""",
# V3 : chain of thought court
"V3_CoT_court": """Sur cette fiche médicale OGC :
1. Repère en bas à droite la zone avec "Accord" et "Désaccord", chacun suivi d'une case à cocher.
2. Identifie laquelle des deux cases est cochée (X, V ou remplie).
3. Réponds par un JSON strict : {"case_cochee": "accord"} ou {"case_cochee": "désaccord"}.""",
}
CASES = [
("2018 CARC/OGC 7.pdf", 1, "accord"),
("2018 CARC/OGC 55.pdf", 1, "désaccord"),
("2018 CARC/OGC 27.pdf", 1, "désaccord"),
]
def main():
ocr = GLMOCR()
print(f"Modèle chargé, VRAM={ocr.vram_gb:.2f} Go\n")
results = {}
for pdf, page, expected in CASES:
images = pdf_to_images(pdf)
img = images[page - 1]
print(f"=== {Path(pdf).stem} page {page} (attendu: {expected}) ===")
for name, prompt in PROMPTS.items():
t0 = time.time()
res = ocr.run(img, prompt, max_new_tokens=256)
out = res["text"].strip().replace("\n", " ")[:180]
print(f" [{name}] ({time.time()-t0:.1f}s)")
print(f"{out}")
results.setdefault(name, []).append((expected, out))
print()
print("=== RÉCAPITULATIF ===")
for name, outs in results.items():
hits = 0
for expected, out in outs:
low = out.lower()
# On compte un hit si la bonne valeur apparaît et pas l'autre
is_acc = "accord" in low and "désaccord" not in low and "desaccord" not in low
is_des = "désaccord" in low or "desaccord" in low
got = "accord" if is_acc else ("désaccord" if is_des else "?")
hits += 1 if got == expected else 0
print(f" {name:28s} : {hits}/{len(outs)}")
if __name__ == "__main__":
main()