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>
80 lines
3.0 KiB
Python
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()
|