feat: whitelist phrases + panneau paramètres avancés dans la GUI

- Nouvelle section whitelist_phrases dans dictionnaires.yml : phrases
  qui ne doivent jamais être anonymisées (FP récurrents)
- Fonction _apply_whitelist : restaure les phrases whitelistées après
  anonymisation, même si des mots ont été remplacés par des placeholders
- GUI : section "Paramètres avancés" repliable avec :
  - Zone texte whitelist (phrases à exclure)
  - Zone texte blacklist (mots à toujours masquer)
  - Bouton sauvegarder → persiste dans le YAML
- Phrases initiales : "classification internationale", "prise en charge",
  "bas de contention", "date de naissance", "code postal", etc.

Score évaluation maintenu à 100.0/100 (A+)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-30 15:03:08 +02:00
parent dcccd60c39
commit f9fbae1f27
3 changed files with 177 additions and 1 deletions

View File

@@ -504,9 +504,72 @@ class App:
main, text="Comment ça marche ?", font=self._f_small,
bg=CLR_BG, fg=CLR_PRIMARY, cursor="hand2",
)
help_lbl.pack(pady=(0, 18))
help_lbl.pack(pady=(0, 8))
help_lbl.bind("<Button-1>", lambda e: self._show_help())
# =============================================================
# SECTION PARAMÈTRES (repliable)
# =============================================================
self._params_visible = False
params_toggle = tk.Label(
main, text="\u2699 Paramètres avancés \u25B6", font=self._f_small,
bg=CLR_BG, fg=CLR_PRIMARY, cursor="hand2",
)
params_toggle.pack(pady=(0, 4), padx=pad_x, anchor="w")
self._params_frame = tk.Frame(main, bg=CLR_BG)
# NE PAS pack — déplié à la demande
def _toggle_params(event=None):
if self._params_visible:
self._params_frame.pack_forget()
params_toggle.configure(text="\u2699 Paramètres avancés \u25B6")
else:
self._params_frame.pack(fill=tk.X, padx=pad_x, pady=(0, 12))
params_toggle.configure(text="\u2699 Paramètres avancés \u25BC")
self._params_visible = not self._params_visible
params_toggle.bind("<Button-1>", _toggle_params)
# --- Whitelist (phrases à ne pas anonymiser) ---
tk.Label(
self._params_frame,
text="Phrases à ne PAS anonymiser (une par ligne) :",
font=self._f_small, bg=CLR_BG, fg=CLR_TEXT, anchor="w",
).pack(fill=tk.X, pady=(4, 2))
self._whitelist_text = tk.Text(
self._params_frame, height=5, font=("Consolas", 9),
wrap=tk.WORD, relief=tk.GROOVE, bd=1,
)
self._whitelist_text.pack(fill=tk.X, pady=(0, 8))
# --- Blacklist (phrases à toujours masquer) ---
tk.Label(
self._params_frame,
text="Mots/phrases à TOUJOURS masquer (une par ligne) :",
font=self._f_small, bg=CLR_BG, fg=CLR_TEXT, anchor="w",
).pack(fill=tk.X, pady=(0, 2))
self._blacklist_text = tk.Text(
self._params_frame, height=5, font=("Consolas", 9),
wrap=tk.WORD, relief=tk.GROOVE, bd=1,
)
self._blacklist_text.pack(fill=tk.X, pady=(0, 8))
# Bouton sauvegarder
save_btn = tk.Button(
self._params_frame, text="Sauvegarder les paramètres",
font=self._f_small, bg=CLR_CARD_BG, fg=CLR_TEXT,
relief=tk.GROOVE, cursor="hand2",
command=self._save_params,
)
save_btn.pack(anchor="e", pady=(0, 4))
# Charger les valeurs initiales depuis la config
self._load_params()
ttk.Separator(main).pack(fill=tk.X, padx=pad_x, pady=(0, 8))
# =============================================================
# BARRE DE PROGRESSION (masquée)
# =============================================================
@@ -1042,6 +1105,58 @@ class App:
"« anonymise/ » à la racine du dossier sélectionné.",
)
# ---------------------------------------------------------------
# Paramètres avancés (whitelist/blacklist)
# ---------------------------------------------------------------
def _load_params(self):
"""Charge les whitelist/blacklist depuis la config YAML."""
try:
cfg_path = Path(self.cfg_path.get())
if cfg_path.exists() and yaml is not None:
data = yaml.safe_load(cfg_path.read_text(encoding="utf-8")) or {}
# Whitelist
wl = data.get("whitelist_phrases", [])
if wl:
self._whitelist_text.delete("1.0", tk.END)
self._whitelist_text.insert("1.0", "\n".join(wl))
# Blacklist
bl = data.get("blacklist", {}).get("force_mask_terms", [])
if bl:
self._blacklist_text.delete("1.0", tk.END)
self._blacklist_text.insert("1.0", "\n".join(str(t) for t in bl))
except Exception:
pass
def _save_params(self):
"""Sauvegarde les whitelist/blacklist dans la config YAML."""
try:
cfg_path = Path(self.cfg_path.get())
if not cfg_path.exists() or yaml is None:
messagebox.showwarning("Erreur", "Fichier de configuration introuvable.")
return
data = yaml.safe_load(cfg_path.read_text(encoding="utf-8")) or {}
# Whitelist phrases
wl_text = self._whitelist_text.get("1.0", tk.END).strip()
wl_lines = [l.strip() for l in wl_text.split("\n") if l.strip()]
data["whitelist_phrases"] = wl_lines
# Blacklist terms
bl_text = self._blacklist_text.get("1.0", tk.END).strip()
bl_lines = [l.strip() for l in bl_text.split("\n") if l.strip()]
if "blacklist" not in data:
data["blacklist"] = {}
data["blacklist"]["force_mask_terms"] = bl_lines
cfg_path.write_text(
yaml.dump(data, allow_unicode=True, default_flow_style=False, sort_keys=False),
encoding="utf-8",
)
messagebox.showinfo("Paramètres", "Paramètres sauvegardés avec succès.")
except Exception as e:
messagebox.showerror("Erreur", f"Impossible de sauvegarder :\n{e}")
# ---------------------------------------------------------------
# YAML (interne)
# ---------------------------------------------------------------