feat(phase2): Gazetteers INSEE (36K prénoms + 34K communes) + silver annotations
- Prénoms INSEE renforcent la confiance NER (prénom connu → ne pas filtrer) - Communes INSEE disponibles pour distinction ville/nom de famille - Export 29 fichiers silver annotations (252K tokens, 12.8K entités) pour fine-tuning Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -114,6 +114,42 @@ def _load_bdpm_medication_names() -> set:
|
||||
return set()
|
||||
|
||||
|
||||
# ----------------- Gazetteers INSEE (prénoms + communes) -----------------
|
||||
_INSEE_PRENOMS: set = set()
|
||||
_INSEE_COMMUNES: set = set()
|
||||
|
||||
def _load_insee_gazetteers():
|
||||
"""Charge les gazetteers INSEE (prénoms français + communes)."""
|
||||
global _INSEE_PRENOMS, _INSEE_COMMUNES
|
||||
data_dir = Path(__file__).parent / "data" / "insee"
|
||||
|
||||
# Prénoms (lowercase, >= 3 chars)
|
||||
prenoms_path = data_dir / "prenoms_france.txt"
|
||||
if prenoms_path.exists():
|
||||
try:
|
||||
_INSEE_PRENOMS = {
|
||||
line.strip().lower() for line in prenoms_path.read_text(encoding="utf-8").splitlines()
|
||||
if line.strip() and len(line.strip()) >= 3
|
||||
}
|
||||
log.info(f"Gazetteers INSEE prénoms: {len(_INSEE_PRENOMS)} entrées")
|
||||
except Exception as e:
|
||||
log.warning(f"Erreur chargement prénoms INSEE: {e}")
|
||||
|
||||
# Communes (uppercase, >= 3 chars)
|
||||
communes_path = data_dir / "communes_france.txt"
|
||||
if communes_path.exists():
|
||||
try:
|
||||
_INSEE_COMMUNES = {
|
||||
line.strip().upper() for line in communes_path.read_text(encoding="utf-8").splitlines()
|
||||
if line.strip() and len(line.strip()) >= 3
|
||||
}
|
||||
log.info(f"Gazetteers INSEE communes: {len(_INSEE_COMMUNES)} entrées")
|
||||
except Exception as e:
|
||||
log.warning(f"Erreur chargement communes INSEE: {e}")
|
||||
|
||||
_load_insee_gazetteers()
|
||||
|
||||
|
||||
# ----------------- Whitelists Médicales -----------------
|
||||
_MEDICAL_STRUCTURAL_TERMS = set()
|
||||
_MEDICATION_WHITELIST = set()
|
||||
@@ -1846,14 +1882,16 @@ def _mask_with_eds_pseudo(text: str, ents: List[Dict[str, Any]], cfg: Dict[str,
|
||||
# Vérifier si c'est un médicament connu
|
||||
if w.lower() in _MEDICATION_WHITELIST:
|
||||
continue
|
||||
# Chantier 3+4 : Confiance NER + vote croisé GLiNER (combinés)
|
||||
# Chantier 3+4 : Confiance NER + vote croisé GLiNER + gazetteers INSEE
|
||||
# Sécurité d'abord : haute confiance NER → toujours masquer
|
||||
# GLiNER peut rejeter SEULEMENT si confiance NER basse
|
||||
gliner_vote = e.get("gliner_confirmed") # True=PII, False=médical, None=neutre
|
||||
if label in ("NOM", "PRENOM"):
|
||||
score = e.get("score", 1.0)
|
||||
if isinstance(score, float) and score < 0.70:
|
||||
# Basse confiance NER : GLiNER peut trancher
|
||||
# Gazetteer INSEE : prénom connu = renforcement confiance (ne pas filtrer)
|
||||
is_known_prenom = w.lower() in _INSEE_PRENOMS
|
||||
if isinstance(score, float) and score < 0.70 and not is_known_prenom:
|
||||
# Basse confiance NER + pas un prénom connu : GLiNER peut trancher
|
||||
if gliner_vote is False:
|
||||
continue # NER pas sûr + GLiNER dit "médical" → skip
|
||||
if score < 0.30:
|
||||
|
||||
Reference in New Issue
Block a user