feat: externalisation des listes — stop-words et villes modifiables sans code

Toutes les listes de règles sont maintenant modifiables sans toucher
au code Python :

Fichiers de données (data/) :
  - stopwords_manuels.txt : 1307 termes médicaux/techniques
  - villes_blacklist.txt : 117 communes à ne pas matcher
  - medicaments_stopwords.txt : 7312 médicaments BDPM (existant)
  - Chargés automatiquement au démarrage

Config YAML (dictionnaires.yml) :
  - additional_stopwords : mots supplémentaires par établissement
  - additional_villes_blacklist : villes supplémentaires
  - whitelist_phrases : phrases à ne jamais anonymiser
  - force_mask_terms : mots à toujours masquer

Chaîne de chargement : code dur → fichiers data/ → YAML config
Les 3 niveaux se cumulent (union).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-31 07:45:42 +02:00
parent b2ee6ad835
commit ac5c35ae2d
4 changed files with 1479 additions and 0 deletions

View File

@@ -204,6 +204,14 @@ _VILLE_BLACKLIST = {
# Parties du corps homonymes de communes (FP "prurit invalidant (COU, décolleté)")
"COU", "DOS", "SEIN", "BRAS",
}
# Enrichissement depuis fichier externe (modifiable sans toucher au code)
_villes_bl_file = Path(__file__).parent / "data" / "villes_blacklist.txt"
if _villes_bl_file.exists():
for _line in _villes_bl_file.read_text(encoding="utf-8").splitlines():
_w = _line.strip()
if _w and not _w.startswith("#"):
_VILLE_BLACKLIST.add(_w)
log.info("Villes blacklist chargées : %d entrées", len(_VILLE_BLACKLIST))
try:
import ahocorasick as _ahocorasick
@@ -772,6 +780,17 @@ _MEDICAL_STOP_WORDS_SET = {
# Enrichissement automatique avec les ~4000 noms de médicaments d'edsnlp
_MEDICAL_STOP_WORDS_SET.update(_load_edsnlp_drug_names())
# Enrichissement depuis fichier externe (modifiable sans toucher au code)
_stopwords_file = Path(__file__).parent / "data" / "stopwords_manuels.txt"
if _stopwords_file.exists():
_sw_count = 0
for _line in _stopwords_file.read_text(encoding="utf-8").splitlines():
_w = _line.strip()
if _w and not _w.startswith("#"):
_MEDICAL_STOP_WORDS_SET.add(_w)
_sw_count += 1
log.info("Stop-words manuels chargés : %d mots depuis %s", _sw_count, _stopwords_file.name)
# Enrichissement BDPM : ~7300 noms commerciaux + DCI/substances actives
_bdpm_path = Path(__file__).parent / "data" / "bdpm" / "medicaments_stopwords.txt"
if _bdpm_path.exists():
@@ -1053,6 +1072,22 @@ def load_dictionaries(config_path: Optional[Path]) -> Dict[str, Any]:
cfg[k] = v
except Exception:
pass
# Charger les stop-words et villes supplémentaires depuis le YAML
extra_sw = cfg.get("additional_stopwords", [])
if extra_sw:
for w in extra_sw:
if w and str(w).strip():
_MEDICAL_STOP_WORDS_SET.add(str(w).strip().lower())
log.info("Stop-words YAML supplémentaires : %d", len(extra_sw))
extra_villes = cfg.get("additional_villes_blacklist", [])
if extra_villes:
for v in extra_villes:
if v and str(v).strip():
_VILLE_BLACKLIST.add(str(v).strip().upper())
log.info("Villes blacklist YAML supplémentaires : %d", len(extra_villes))
return cfg
# ----------------- Extraction -----------------