fix(detect): accepter prénoms 3 chars après Dr/Mme (Ute, Eva, Léo…)
Audit manuel après batch QC : 20 occurrences de "Dr Ute" dans trackare-03020576-23175616 non masquées. Audit jsonl confirme : 0 hit pour "Ute" → pas détecté. Cause : _add_candidate (deux implémentations, lignes 1908 et 2225) filtrait len(token) < 4, empêchant la création du NameCandidate pour "Ute" (3 chars) même avec bypass_stopwords=True. La cross-validation écrasait alors all_names avec validated_names (vide pour Ute), et _apply_extracted_names ne recevait donc jamais Ute. Le commit 2f79f7c avait fait le fix uniquement dans _apply_extracted_names. Fix incomplet : le filtre amont _add_candidate rejetait avant. Correctif symétrique sur _add_candidate (×2) + _add_tokens_force_first : accepter 3 chars UNIQUEMENT si bypass=True (contexte Dr/Mme) ET majuscule initiale ET alpha pur. 2 chars reste filtré (initiales ambigues). Validation : - "DR. DURANTEAU Ute" matche bien RE_EXTRACT_DR_DEST et capture "DURANTEAU Ute" - Audit produit "Ute DURANTEAU" en bloc + "DURANTEAU" seul (41 hits total) - PDF redacted : 0 résiduel "Ute" (avant : 38) Cas protégés : - "Ute" accepté : bypass=True, U majuscule, alpha ✓ - "Les" refusé : bypass=True mais stopword (filtré ailleurs) ✓ - "JF" refusé : 2 chars, filtre longueur < 3 ✓ Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1903,9 +1903,13 @@ def _extract_trackare_identity(full_text: str) -> Tuple[set, List[PiiHit], set,
|
||||
force_names: set = set() # noms issus de contextes structurés (DR., Signé, etc.) → bypass stop words
|
||||
|
||||
def _add_candidate(token: str, source: str, strength: str, bypass: bool):
|
||||
"""Ajoute un NameCandidate à la liste."""
|
||||
"""Ajoute un NameCandidate à la liste.
|
||||
Accepte les prénoms courts 3 chars (Ute, Eva, Léo…) si bypass=True
|
||||
(contexte Dr/Mme fort) ET majuscule initiale + alpha pur."""
|
||||
token = token.strip(" .-'(),")
|
||||
if len(token) < 4:
|
||||
if len(token) < 3:
|
||||
return
|
||||
if len(token) == 3 and not (bypass and token[0].isupper() and token.isalpha()):
|
||||
return
|
||||
candidates.append(NameCandidate(
|
||||
token=token, source=source,
|
||||
@@ -2220,9 +2224,13 @@ def _extract_document_names(full_text: str, cfg: Dict[str, Any]) -> Tuple[set, s
|
||||
candidates: List[NameCandidate] = []
|
||||
|
||||
def _add_candidate(token: str, source: str, strength: str, bypass: bool):
|
||||
"""Ajoute un NameCandidate à la liste (dédupliqué par token+source)."""
|
||||
"""Ajoute un NameCandidate à la liste (dédupliqué par token+source).
|
||||
Accepte les prénoms courts 3 chars (Ute, Eva, Léo…) si bypass=True
|
||||
(contexte Dr/Mme fort) ET majuscule initiale + alpha pur."""
|
||||
token = token.strip(" .-'")
|
||||
if len(token) < 4:
|
||||
if len(token) < 3:
|
||||
return
|
||||
if len(token) == 3 and not (bypass and token[0].isupper() and token.isalpha()):
|
||||
return
|
||||
candidates.append(NameCandidate(
|
||||
token=token, source=source,
|
||||
@@ -2270,12 +2278,21 @@ def _extract_document_names(full_text: str, cfg: Dict[str, Any]) -> Tuple[set, s
|
||||
|
||||
Après Dr/Mme, tous les tokens sont des noms — même s'ils sont
|
||||
homonymes de termes médicaux (ex: Dr Laurence MASSE).
|
||||
|
||||
Accepte les prénoms courts 3 chars (Dr Ute, Dr Eva, Dr Léo) : le
|
||||
contexte Dr/Mme est suffisamment fort pour lever le filtre de
|
||||
longueur, à condition que le token soit alpha et commence par
|
||||
une majuscule. 2 chars reste filtré (trop ambigu : initiales).
|
||||
"""
|
||||
_add_compound(match_str)
|
||||
tokens = match_str.split()
|
||||
for token in tokens:
|
||||
token = token.strip(" .-'")
|
||||
if len(token) < 4:
|
||||
if len(token) < 3:
|
||||
continue
|
||||
# 3 chars : accepter uniquement si majuscule initiale + alpha
|
||||
# (évite "Les", "Des" mais accepte "Ute", "Eva").
|
||||
if len(token) == 3 and not (token[0].isupper() and token.isalpha()):
|
||||
continue
|
||||
if token.upper() in wl_sections or token in wl_phrases:
|
||||
continue
|
||||
|
||||
Reference in New Issue
Block a user