From ad7f1ffa8a79637b3b9e97a24d9b5444ff23ed65 Mon Sep 17 00:00:00 2001 From: Domi31tls Date: Tue, 17 Mar 2026 07:11:57 +0100 Subject: [PATCH] =?UTF-8?q?fix:=20FP=20m=C3=A9dicaments=20dans=20raster=20?= =?UTF-8?q?+=20texte=20=E2=80=94=20RE=5FEXTRACT=5FSTAFF=5FROLE=20+=20FINES?= =?UTF-8?q?S=20+=20stop-words?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bug #1 (critique) : RE_EXTRACT_STAFF_ROLE matchait à l'intérieur des mots (IDE dans METOCLOPRAMIDE, AS dans ATORVASTATINE) → ajout \b word boundaries et suppression du ? optionnel sur ASH (AS matchait partout) Bug #2 : raster multi-mots utilisait page.search_for() (substring matching) → ajout vérification frontières de mots pour les tokens multi-mots dans redact_pdf_raster et redact_pdf_vector FP FINESS Aho-Corasick : - "resistance" (Centre de la Résistance) matchait "résistance aux fluoroquinolones" - "radiotherapie" matchait "tumorectomie, radiothérapie et hormonothérapie" → ajout blacklist : resistance, radiotherapie, chimiotherapie, etc. FP villes : "COU" (commune) matchait dans "prurit (cou, décolleté, dos)" → ajout COU, DOS, SEIN, BRAS à _VILLE_BLACKLIST Stop-words : ajout "totale", "partielle", "prothese", "unicompartimentale" Score évaluation maintenu à 100.0/100 (A+) Co-Authored-By: Claude Opus 4.6 (1M context) --- anonymizer_core_refactored_onnx.py | 38 +++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/anonymizer_core_refactored_onnx.py b/anonymizer_core_refactored_onnx.py index f8cf181..154def6 100644 --- a/anonymizer_core_refactored_onnx.py +++ b/anonymizer_core_refactored_onnx.py @@ -200,6 +200,8 @@ _VILLE_BLACKLIST = { "FRANCE", "EUROPE", # Termes ambigus (aussi communes INSEE) - trackare/DPI "COURANT", # "Médecin courant" ≠ ville + # Parties du corps homonymes de communes (FP "prurit invalidant (COU, décolleté)") + "COU", "DOS", "SEIN", "BRAS", } try: @@ -753,6 +755,9 @@ _MEDICAL_STOP_WORDS_SET = { "chlorure", # Dispositifs médicaux (FP "OXYGENE LUNETTES" → [NOM]) "canule", "canules", "masque", "sonde", "sondes", + # Termes chirurgicaux FP comme [NOM] (retour relecteur 2026-03-17) + "totale", "total", "partielle", "partiel", + "prothese", "prothèse", "unicompartimentale", } # Enrichissement automatique avec les ~4000 noms de médicaments d'edsnlp _MEDICAL_STOP_WORDS_SET.update(_load_edsnlp_drug_names()) @@ -865,8 +870,8 @@ RE_EXTRACT_DR_DEST = re.compile( ) # Noms du personnel médical après un rôle : "Aide : Marie-Paule BORDABERRY" RE_EXTRACT_STAFF_ROLE = re.compile( - r"(?:Aide|Infirmière?|IDE|IADE|IBODE|ASH?|Cadre[ \t]+Infirmier" - r"|Prescripteur|Prescrit[ \t]+par|Exécut[ée][ \t]+par|Réalisé[ \t]+par)[ \t]*:?[ \t]*" + r"\b(?:Aide|Infirmière?|IDE|IADE|IBODE|ASH|Cadre[ \t]+Infirmier" + r"|Prescripteur|Prescrit[ \t]+par|Exécut[ée][ \t]+par|Réalisé[ \t]+par)\b[ \t]*:?[ \t]*" r"((?:[A-ZÉÈÀÙÂÊÎÔÛÄËÏÖÜÇ][a-zéèàùâêîôûäëïöüç]+(?:[ \t]*-[ \t]*[A-ZÉÈÀÙÂÊÎÔÛÄËÏÖÜÇ][a-zéèàùâêîôûäëïöüç]+)?[ \t]+)?" r"(?:[A-ZÉÈÀÙÂÊÎÔÛÄËÏÖÜÇ]{2,}[\-]?)(?:[ \t\-]+[A-ZÉÈÀÙÂÊÎÔÛÄËÏÖÜÇ]{2,}){0,2})", ) @@ -2559,6 +2564,12 @@ def _build_finess_ac(): "comprimee", "comprimees", "injectable", "injectables", "maintenant", "actuellement", "auparavant", "prochainement", "rapidement", "correctement", "directement", "simplement", + # Termes médicaux homonymes d'établissements FINESS (retour relecteur 2026-03-17) + "resistance", "radiotherapie", "chimiotherapie", "curietherapie", + "hormonotherapie", "immunotherapie", "kinesitherapie", + "ergotherapie", "orthophonie", "psychomotricite", + "reeducation", "readaptation", "convalescence", + "dependance", "autonomie", "gerontologie", } # Expressions multi-mots trop génériques _ac_generic_phrases = { @@ -3334,7 +3345,14 @@ def redact_pdf_vector(original_pdf: Path, audit: List[PiiHit], out_pdf: Path, oc rects = _search_ocr_words(ocr_word_map[pno], token, page.rect) all_rects.extend(rects) else: + # Vérification frontières de mots (comme raster) rects = page.search_for(token) + if rects: + page_text = page.get_text() + import re as _re + if not _re.search(r"(?