fix: sync texte↔raster + GUI listes whitelist/blacklist améliorées
Bug critique corrigé : les noms forcés (contexte Dr/Mme) comme "MASSE" étaient masqués dans le texte mais pas dans le PDF raster car filtrés par les stop-words médicaux. Nouveau kind "NOM_FORCE" qui bypass le filtre stop-words dans les fonctions de redaction vector et raster. GUI : remplacement des zones texte brut par des listes interactives avec champ de saisie + bouton Ajouter + bouton Supprimer, fond coloré (vert pour whitelist, rose pour blacklist). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2154,8 +2154,11 @@ def _apply_extracted_names(text: str, names: set, audit: List[PiiHit], force_nam
|
||||
safe_names = {n for n in names if len(n) >= 4 and (n in _force or n.lower() not in _MEDICAL_STOP_WORDS_SET)}
|
||||
# Ajouter un hit global (page=-1) par nom pour la redaction PDF raster
|
||||
# (un seul hit suffit — redact_pdf_raster cherche le token sur chaque page)
|
||||
# Les noms forcés (contexte Dr/Mme) utilisent NOM_FORCE pour bypasser
|
||||
# le filtre stop-words dans le raster
|
||||
for token in sorted(safe_names, key=len, reverse=True):
|
||||
audit.append(PiiHit(-1, "NOM_GLOBAL", token, placeholder))
|
||||
kind = "NOM_FORCE" if token in _force else "NOM_GLOBAL"
|
||||
audit.append(PiiHit(-1, kind, token, placeholder))
|
||||
for token in sorted(safe_names, key=len, reverse=True):
|
||||
pattern = re.compile(rf"\b{re.escape(token)}\b", re.IGNORECASE)
|
||||
new_text = []
|
||||
@@ -3390,8 +3393,8 @@ def redact_pdf_vector(original_pdf: Path, audit: List[PiiHit], out_pdf: Path, oc
|
||||
seen_tokens.add(dedup_key)
|
||||
# --- Kinds de type nom/entité : whole-word search pour éviter le
|
||||
# substring matching (ex: "TATIN" dans "ATORVASTATINE") ---
|
||||
if h.kind in _VECTOR_WHOLEWORD_KINDS:
|
||||
if token.lower() in _MEDICAL_STOP_WORDS_SET:
|
||||
if h.kind in _VECTOR_WHOLEWORD_KINDS or h.kind == "NOM_FORCE":
|
||||
if h.kind != "NOM_FORCE" and token.lower() in _MEDICAL_STOP_WORDS_SET:
|
||||
continue
|
||||
if " " not in token:
|
||||
rects = _search_whole_word(page, token)
|
||||
@@ -3535,8 +3538,9 @@ def redact_pdf_raster(original_pdf: Path, audit: List[PiiHit], out_pdf: Path, dp
|
||||
seen_tokens.add(token)
|
||||
# --- Kinds de type nom/entité : whole-word search pour éviter le
|
||||
# substring matching (ex: "TATIN" dans "ATORVASTATINE") ---
|
||||
if h.kind in _RASTER_WHOLEWORD_KINDS:
|
||||
if token.lower() in _MEDICAL_STOP_WORDS_SET:
|
||||
if h.kind in _RASTER_WHOLEWORD_KINDS or h.kind == "NOM_FORCE":
|
||||
# NOM_FORCE bypass le filtre stop-words (nom confirmé par contexte Dr/Mme)
|
||||
if h.kind != "NOM_FORCE" and token.lower() in _MEDICAL_STOP_WORDS_SET:
|
||||
continue
|
||||
if " " not in token:
|
||||
# Token mono-mot : chercher comme mot entier
|
||||
|
||||
Reference in New Issue
Block a user