feat(gui): exposer additional_stopwords dans le panneau Paramètres avancés

Troisième liste paramétrable dans la GUI v5.4, après whitelist_phrases et
blacklist.force_mask_terms : "Mots à ne jamais identifier comme noms".
Cible les sigles, acronymes métier locaux, ou termes ALL-CAPS récurrents
qui ressemblent à des noms propres mais n'en sont pas.

Différence avec la whitelist :
- whitelist_phrases : terme spécifique à protéger même s'il a été masqué
  par regex/NER (filtre final sur l'audit + sous-mots de hits multi-mots)
- additional_stopwords : empêche le terme d'être candidat-nom dès l'amont
  (intégré à _MEDICAL_STOP_WORDS_SET, filtre toutes les étapes)

Wired dans _load_params, _save_params, _export_params, _import_params.
La nouvelle clé additional_stopwords est incluse dans le JSON d'échange
inter-établissements.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-14 10:28:11 +02:00
parent 59acf390f4
commit 4b5925306e

View File

@@ -576,6 +576,16 @@ class App:
color_tag="#fce4ec",
)
# --- Stop-words additionnels (mots à ne jamais identifier comme noms) ---
# Différent de la whitelist : agit en amont, pour les sigles, acronymes,
# termes métier locaux qui ressemblent à des noms mais n'en sont pas.
self._sw_listbox, self._sw_entry = self._build_phrase_list(
self._params_frame,
title="\u26a0 Mots à ne jamais identifier comme noms (sigles, acronymes...) :",
placeholder="Ajouter un mot (ex: sigle local, acronyme métier)...",
color_tag="#fff8e1",
)
# Boutons sauvegarder + exporter
btn_row = tk.Frame(self._params_frame, bg=CLR_BG)
btn_row.pack(fill=tk.X, pady=(4, 4))
@@ -1244,6 +1254,12 @@ class App:
for term in bl:
if term and str(term).strip():
self._bl_listbox.insert(tk.END, str(term).strip())
# Stop-words additionnels
sw = data.get("additional_stopwords", [])
self._sw_listbox.delete(0, tk.END)
for term in sw:
if term and str(term).strip():
self._sw_listbox.insert(tk.END, str(term).strip())
except Exception:
pass
@@ -1255,6 +1271,7 @@ class App:
wl = list(self._wl_listbox.get(0, tk.END))
bl = list(self._bl_listbox.get(0, tk.END))
sw = list(self._sw_listbox.get(0, tk.END))
export_data = {
"version": APP_VERSION,
@@ -1262,6 +1279,7 @@ class App:
"etablissement": "", # à remplir par l'utilisateur
"whitelist_phrases": wl,
"blacklist_force_mask_terms": bl,
"additional_stopwords": sw,
"instructions": (
"Ce fichier contient les paramètres d'anonymisation personnalisés. "
"Envoyez-le par email à l'équipe technique pour mise à jour du programme."
@@ -1328,13 +1346,23 @@ class App:
self._bl_listbox.insert(tk.END, str(term).strip())
added_bl += 1
# Fusionner stop-words additionnels
new_sw = data.get("additional_stopwords", [])
existing_sw = set(self._sw_listbox.get(0, tk.END))
added_sw = 0
for term in new_sw:
if term and str(term).strip() and str(term).strip() not in existing_sw:
self._sw_listbox.insert(tk.END, str(term).strip())
added_sw += 1
version = data.get("version", "?")
date_exp = data.get("date_export", "?")[:10]
messagebox.showinfo(
"Import réussi",
f"Paramètres importés (v{version}, {date_exp}) :\n\n"
f" + {added_wl} phrase(s) ajoutée(s) à la whitelist\n"
f" + {added_bl} terme(s) ajouté(s) à la blacklist\n\n"
f" + {added_bl} terme(s) ajouté(s) à la blacklist\n"
f" + {added_sw} mot(s) ajouté(s) aux stop-words\n\n"
f"Cliquez sur « Sauvegarder » pour appliquer.",
)
except Exception as e:
@@ -1358,6 +1386,9 @@ class App:
data["blacklist"] = {}
data["blacklist"]["force_mask_terms"] = list(self._bl_listbox.get(0, tk.END))
# Stop-words additionnels (mots à ne jamais identifier comme noms)
data["additional_stopwords"] = list(self._sw_listbox.get(0, tk.END))
cfg_path.write_text(
yaml.dump(data, allow_unicode=True, default_flow_style=False, sort_keys=False),
encoding="utf-8",