Qwen ne lit systématiquement que la colonne de gauche du tableau
Codage quand on lui donne la page recueil entière : la colonne droite
(Recodage) a 27% de couverture en V2.0 avec 100% de validité — une
régression majeure puisque c'est le cœur métier du contrôle T2A.
Solution : après le passage principal, refaire une extraction dédiée
sur un crop zonal de la seule colonne Recodage (y=0.330→0.490 pour
exclure le bloc Actes adjacent). Prompt strict anti-hallucination
("beaucoup de lignes sont vides, n'invente rien"). Le résultat écrase
partiellement `codage_reco` (DP/DR/DAS) dans le JSON principal.
Classification Python par règle métier :
- 1er code sans position → DP
- 2e code sans position → DR (ignoré si == DP : Qwen duplique parfois)
- codes avec position → DAS
Filtre CIM-10 par regex en Python pour retirer les codes CCAM (actes)
qui pourraient rester si le crop déborde.
Ajout d'une env var `QWEN_MAX_PIXELS` (défaut 800) pour ajuster la
consommation VRAM sur machines avec GPU partagé (test sur RTX 5070
avec rpa_vision_v3 en parallèle).
Ajout de `torch.cuda.empty_cache()` après chaque inférence pour
réduire la fragmentation VRAM sur exécutions longues.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
141 lines
5.8 KiB
Python
141 lines
5.8 KiB
Python
"""Prompts GLM-OCR par type de page OGC.
|
|
|
|
Pour chaque type structuré, on demande un JSON strict. Pour les pages libres
|
|
(concertation 2, éléments de preuve…) on sort du texte brut.
|
|
"""
|
|
|
|
# Prompt court pour détecter le type de page depuis l'en-tête.
|
|
PROMPT_HEADER = "Text Recognition:"
|
|
|
|
# --- Page 1 : Fiche médicale de recueil du praticien conseil ---
|
|
# Note : accord_desaccord retiré du prompt — géré par pipeline.checkboxes
|
|
# (densité de pixels) car GLM-OCR ne sait pas lire les checkboxes
|
|
# (cf. test_prompt_crop_v2.py).
|
|
#
|
|
SCHEMA_RECUEIL = """Lis la fiche médicale OGC et renvoie STRICTEMENT le JSON suivant, sans commentaire ni markdown.
|
|
Les codes CIM-10 sont au format lettre + 2 à 4 chiffres (ex: K650, T814).
|
|
Les codes CCAM sont au format 4 lettres + 3 chiffres (ex: EBFA012).
|
|
Les codes GHM sont au format 2 chiffres + lettre + 3 chiffres (ex: 11M122).
|
|
Les codes GHS sont des nombres à 3-5 chiffres (ex: 4323).
|
|
Si un champ est illisible, laisse une chaîne vide. Ne devine pas.
|
|
|
|
{
|
|
"etablissement": "",
|
|
"finess": "",
|
|
"date_debut_controle": "",
|
|
"n_ogc": "",
|
|
"n_champ": "",
|
|
"dates_sejour": "",
|
|
"sejour_etab": {
|
|
"age": "", "sexe": "", "duree_sejour": "",
|
|
"mode_entree": "", "provenance": "",
|
|
"mode_sortie": "", "destination": ""
|
|
},
|
|
"sejour_reco": {
|
|
"age": "", "sexe": "", "duree_sejour": "",
|
|
"mode_entree": "", "provenance": "",
|
|
"mode_sortie": "", "destination": ""
|
|
},
|
|
"rum_etab": {"um": "", "igs": "", "duree": "", "dates": ""},
|
|
"codage_etab": {
|
|
"dp": "", "dp_libelle": "", "dr": "",
|
|
"das": [{"code": "", "position": "", "libelle": ""}]
|
|
},
|
|
"codage_reco": {
|
|
"dp": "", "dr": "",
|
|
"das": [{"code": "", "position": ""}]
|
|
},
|
|
"actes_etab": [{"code": "", "position": "", "libelle": ""}],
|
|
"actes_reco": [{"code": "", "position": ""}],
|
|
"ghm_etab": "", "ghs_etab": "",
|
|
"ghm_reco": "", "ghs_reco": "",
|
|
"recodage_impactant": "",
|
|
"ghs_injustifie": "",
|
|
"praticien_conseil": ""
|
|
}"""
|
|
|
|
# --- Second passage dédié : colonne Recodage de la page recueil ---
|
|
# Qwen-VL sous-extrait la colonne droite du tableau Codage quand on lui donne
|
|
# la page entière (27% de couverture sur `codage_reco.dp` en V2.0). En lui
|
|
# donnant directement un crop zonal de cette seule colonne, il lit beaucoup
|
|
# mieux (la structure à une seule colonne lève l'ambiguïté).
|
|
#
|
|
# Zone cropée (coordonnées relatives dans l'image complète) :
|
|
# Zone restreinte au seul bloc codage (DP/DR/DAS de la colonne Recodage).
|
|
# On exclut la partie Actes (qui commence autour de y=0.680) pour éviter que
|
|
# Qwen confonde les codes CCAM (actes) avec des codes CIM-10 (DAS).
|
|
RECUEIL_RECODAGE_ZONE = (0.77, 0.330, 0.97, 0.490)
|
|
|
|
SCHEMA_RECUEIL_RECODAGE = """Cette image est un extrait d'une colonne d'un tableau médical.
|
|
La colonne peut contenir ZÉRO, UN ou PLUSIEURS codes médicaux CIM-10 (format : 1 lettre majuscule + 2 à 4 chiffres, ex: K650, T810, Z954, R31, I652). Un code peut avoir un suffixe `*`. À droite d'un code, une position numérique (1-9) peut être visible.
|
|
|
|
IMPORTANT — LIS UNIQUEMENT CE QUI EST PHYSIQUEMENT VISIBLE :
|
|
- La plupart des lignes de ce tableau sont VIDES. C'est NORMAL.
|
|
- Ne liste QUE les codes effectivement écrits dans l'image. N'INVENTE rien.
|
|
- Si l'image ne contient qu'un seul code, ta réponse doit lister exactement un code (pas plusieurs).
|
|
- Si l'image ne contient aucun code, renvoie `"codes": []`.
|
|
- Ne déduis pas les codes d'autres cases non montrées dans l'image.
|
|
|
|
Pour chaque code réellement visible, indique sa position à droite si elle est écrite, sinon "".
|
|
|
|
Renvoie STRICTEMENT ce JSON, sans commentaire ni markdown :
|
|
{
|
|
"codes": [
|
|
{"code": "", "position": ""}
|
|
]
|
|
}"""
|
|
|
|
|
|
# --- Page 5 : Fiche administrative de concertation 2/2 (décision finale) ---
|
|
SCHEMA_CONCERTATION_2 = """Lis la fiche de concertation et renvoie STRICTEMENT le JSON suivant, sans commentaire ni markdown.
|
|
Si un champ est illisible, laisse une chaîne vide.
|
|
|
|
{
|
|
"ghs_initial": "",
|
|
"ghs_avant_concertation": "",
|
|
"ghs_final": "",
|
|
"decision": "",
|
|
"date_concertation": "",
|
|
"praticien_controleur": "",
|
|
"medecin_dim": ""
|
|
}
|
|
|
|
Pour "decision", choisis UNIQUEMENT une de ces valeurs selon la case cochée :
|
|
- "maintien_avis_controleur" si "Maintien de l'avis initial" est coché
|
|
- "retour_groupage_dim" si "Retour groupage initial DIM" est coché
|
|
- "autre_groupage" si "Autre groupage" est coché
|
|
- "" si rien n'est coché"""
|
|
|
|
# --- Page 6 : Fiche administrative de concertation 1/2 (argumentaire) ---
|
|
SCHEMA_CONCERTATION_1 = """Lis la fiche d'argumentaire du médecin contrôleur et renvoie STRICTEMENT le JSON suivant, sans commentaire ni markdown.
|
|
|
|
{
|
|
"date_concertation": "",
|
|
"argumentaire": ""
|
|
}
|
|
|
|
Pour "argumentaire", transcris TOUT le paragraphe sous "ARGUMENTAIRE DU MEDECIN CONTROLEUR" tel quel, sans reformuler."""
|
|
|
|
# --- Page 4 : Éléments de preuve ---
|
|
SCHEMA_PREUVES = """Lis le tableau des éléments de preuve et renvoie STRICTEMENT le JSON suivant, sans commentaire ni markdown.
|
|
Pour chaque ligne, indique si la case "Présent" ou "Photocopié" est cochée (true/false).
|
|
|
|
{
|
|
"date": "",
|
|
"praticien_controleur": "",
|
|
"medecin_dim": "",
|
|
"pieces": [
|
|
{"intitule": "", "present": false, "photocopie": false, "absent_date": "", "date_obtention": ""}
|
|
]
|
|
}"""
|
|
|
|
# Types de page reconnus
|
|
PAGE_TYPES = {
|
|
"recueil": {"keywords": ["RECUEIL DU PRATICIEN"], "prompt": SCHEMA_RECUEIL},
|
|
"concertation_2": {"keywords": ["CONCERTATION 2/2"], "prompt": SCHEMA_CONCERTATION_2},
|
|
"concertation_1": {"keywords": ["CONCERTATION 1/2"], "prompt": SCHEMA_CONCERTATION_1},
|
|
"preuves": {"keywords": ["ELEMENTS DE PREUVE", "PREUVE"], "prompt": SCHEMA_PREUVES},
|
|
"concertation_med": {"keywords": ["FICHE MEDICALE DE CONCERTATION"], "prompt": PROMPT_HEADER},
|
|
"hospitalisation":{"keywords": ["SEJOUR D'HOSPITALISATION", "HOSPITALISATION COMPLETE"], "prompt": PROMPT_HEADER},
|
|
}
|