feat: réduction FP + gazetteers adresses FINESS + batch parallèle + corrections multi-axes
- Token min length relevé de 2-3 → 4 chars (élimine FP EPO, IRC, SIB...) - Stop-words enrichis : acronymes médicaux 3 lettres, termes pharma, soins infirmiers - BDPM stop-words : ~7300 noms commerciaux + DCI/substances actives - Gazetteers adresses FINESS : 63K patterns Aho-Corasick (position-preserving normalization) - Filtre contextuel anatomique pour FINESS établissements - Nouvelles regex : RE_CIVILITE_COMMA_LIST, RE_EXTRACT_NOM_UTILISE, RE_EXTRACT_PRENOM, RE_NUM_EXAMEN_PATIENT, RE_ADRESSE_LIEU_DIT, RE_CIVILITE_INITIALE, Dr X.NOM - URLs complètes (RE_URL) + détection multiline - N° venue inversé (layout-aware) + EPISODE/NDA dans _CRITICAL_PII_TYPES - HospitalFilter désactivé pour ADRESSE/TEL/VILLE/EPISODE (identifient le patient) - Batch silver export parallélisé (multiprocessing spawn, N workers) - Seuil sur-masquage relevé à 8%, server.py enrichi (source regex/ner) - Blacklist villes : COURANT, PARIS ; contexte villes étendu (UHCD, spécialités) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -166,24 +166,13 @@ class HospitalFilter:
|
||||
Returns:
|
||||
True si la détection doit être filtrée (faux positif)
|
||||
"""
|
||||
# Filtrer par type
|
||||
if pii_type == "ADRESSE":
|
||||
return self.is_hospital_address(text)
|
||||
|
||||
elif pii_type == "CODE_POSTAL":
|
||||
return self.is_hospital_postal_code(text)
|
||||
|
||||
elif pii_type == "VILLE":
|
||||
return self.is_hospital_city(text)
|
||||
|
||||
elif pii_type == "TEL":
|
||||
return self.is_hospital_phone(text)
|
||||
|
||||
elif pii_type == "EPISODE":
|
||||
# Filtrer les épisodes qui proviennent du nom de fichier
|
||||
# (répétés dans les en-têtes/pieds de page des documents trackare)
|
||||
return self.is_episode_in_filename(text, filename)
|
||||
|
||||
# ADRESSE, CODE_POSTAL, VILLE, TEL : NE PAS filtrer.
|
||||
# Les coordonnées hospitalières identifient indirectement le patient
|
||||
# et doivent être masquées (validé par contrôle humain 2026-03-12).
|
||||
|
||||
# EPISODE : NE PAS filtrer.
|
||||
# Les numéros d'épisode identifient le patient (validé 2026-03-14).
|
||||
|
||||
return False
|
||||
|
||||
def filter_detections(self, detections: List[Dict], filename: str = "", is_trackare: bool = False) -> List[Dict]:
|
||||
@@ -222,15 +211,17 @@ if __name__ == "__main__":
|
||||
|
||||
# Tests
|
||||
test_cases = [
|
||||
("ADRESSE", "13, Avenue de l'Interne J", "", -1, True),
|
||||
# ADRESSE, CODE_POSTAL, VILLE, TEL : ne sont plus filtrés (identifient le patient)
|
||||
("ADRESSE", "13, Avenue de l'Interne J", "", -1, False),
|
||||
("ADRESSE", "22 LOT MENDI ALDE", "", -1, False),
|
||||
("CODE_POSTAL", "64109 BAYONNE CEDEX", "", -1, True),
|
||||
("CODE_POSTAL", "64109 BAYONNE CEDEX", "", -1, False),
|
||||
("CODE_POSTAL", "64130", "", -1, False),
|
||||
("VILLE", "BAYONNE CEDEX", "", -1, True),
|
||||
("VILLE", "BAYONNE CEDEX", "", -1, False),
|
||||
("VILLE", "CHERAUTE", "", -1, False),
|
||||
("VILLE", "DROIT", "", -1, True), # Terme anatomique
|
||||
("TEL", "05 59 44 35 35", "", -1, True),
|
||||
("VILLE", "DROIT", "", -1, False),
|
||||
("TEL", "05 59 44 35 35", "", -1, False),
|
||||
("TEL", "0676085336", "", -1, False),
|
||||
# EPISODE : filtré uniquement si provient du nom de fichier trackare
|
||||
("EPISODE", "23202435", "trackare-14004105-23202435", -1, True),
|
||||
("EPISODE", "23102610", "CRH_23102610", 0, False),
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user