fix: filtre bruit Trackare — antécédents parasites + répétitions DAS
- das_filter: regex anti-répétition gère les espaces entre mots concaténés
("VentilationVentilation Ventilation..." désormais rejeté)
- cim10_extractor: regex antécédents s'arrête à "Signes Vitaux" (ne capture
plus le tableau de surveillance)
- Nouveau _is_valid_antecedent() filtre noms de service, mots de surveillance
isolés, infos admin (RPPS), répétitions, Mode de vie
- 28 nouveaux tests (TestIsValidAntecedent + das_filter repetition)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -528,10 +528,57 @@ def _extract_actes(text: str, dossier: DossierMedical) -> None:
|
||||
acte.code_ccam_suggestion = code
|
||||
|
||||
|
||||
_ANTECEDENT_NOISE = (
|
||||
"item de", "surveillance", "température", "signes vitaux",
|
||||
"pouls", "type de note", "aucune donnée", "renseignée",
|
||||
"habitudes de vie", "systolique", "diastolique", "saturation",
|
||||
"texte libre", "mode de vie", "n° rpps",
|
||||
)
|
||||
|
||||
_SURVEILLANCE_SINGLE_WORDS = frozenset({
|
||||
"moyenne", "ventilation", "echelle", "gauche", "droite",
|
||||
"capillaire", "repos", "diurèse", "glycémie", "ambiant",
|
||||
})
|
||||
|
||||
|
||||
def _is_valid_antecedent(line: str) -> bool:
|
||||
"""Filtre les lignes parasites du bloc antécédents (bruit Trackare)."""
|
||||
if not line or len(line) <= 5 or line == "0":
|
||||
return False
|
||||
if re.match(r"^\d", line):
|
||||
return False
|
||||
low = line.lower()
|
||||
# Mots-clés de bruit (sous-chaînes)
|
||||
if any(kw in low for kw in _ANTECEDENT_NOISE):
|
||||
return False
|
||||
words = low.split()
|
||||
# Mots isolés de tableau de surveillance
|
||||
if len(words) == 1 and low in _SURVEILLANCE_SINGLE_WORDS:
|
||||
return False
|
||||
# Noms de service (tout majuscules, court)
|
||||
if line.isupper() and len(line) < 40:
|
||||
return False
|
||||
# Mots concaténés ou répétés avec espaces : "VentilationVentilation Ventilation..."
|
||||
if re.match(r'^([a-zà-ÿ]{3,})(\s*\1)+\s*$', line, re.IGNORECASE):
|
||||
return False
|
||||
# Mots répétés mélangés (≥ 3 occurrences du même mot)
|
||||
if len(words) >= 3:
|
||||
from collections import Counter
|
||||
if Counter(words).most_common(1)[0][1] >= 3:
|
||||
return False
|
||||
# Deux mots identiques
|
||||
if len(words) == 2 and len(set(words)) == 1:
|
||||
return False
|
||||
# Identifiants administratifs isolés
|
||||
if re.match(r'^\[MEDECIN\]\s', line) and len(line) < 30:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def _extract_antecedents(text: str, dossier: DossierMedical) -> None:
|
||||
"""Extrait les antécédents."""
|
||||
m = re.search(
|
||||
r"Antécédents?\s*[::]?\s*\n?(.*?)(?=\n\s*(?:Traitements?\s*[::]|Allergie|Histoire de la maladie|Examen clinique|\n\n))",
|
||||
r"Antécédents?\s*[::]?\s*\n?(.*?)(?=\n\s*(?:Traitements?\s*[::]|Allergie|Histoire de la maladie|Examen clinique|Signes\s+[Vv]itaux|Observations?\s+m[eé]dicale|Passage aux|\n\n))",
|
||||
text,
|
||||
re.DOTALL | re.IGNORECASE,
|
||||
)
|
||||
@@ -539,21 +586,7 @@ def _extract_antecedents(text: str, dossier: DossierMedical) -> None:
|
||||
block = m.group(1).strip()
|
||||
for line in block.split("\n"):
|
||||
line = line.strip().lstrip("- •")
|
||||
# Filtrer les lignes non pertinentes
|
||||
if (line and len(line) > 5 and line != "0"
|
||||
and not re.match(r"^\d", line)
|
||||
and "Item de" not in line
|
||||
and "surveillance" not in line.lower()
|
||||
and "Température" not in line
|
||||
and "Signes Vitaux" not in line
|
||||
and "Pouls" not in line
|
||||
and "Type de note" not in line
|
||||
and "Aucune donnée" not in line
|
||||
and "renseignée" not in line
|
||||
and "habitudes de vie" not in line
|
||||
and "Systolique" not in line
|
||||
and "Diastolique" not in line
|
||||
and "Saturation" not in line):
|
||||
if _is_valid_antecedent(line):
|
||||
dossier.antecedents.append(line)
|
||||
|
||||
|
||||
|
||||
@@ -39,8 +39,8 @@ def is_valid_diagnostic_text(text: str) -> bool:
|
||||
if re.match(r"^[A-ZÀ-Ú]\s*\d{1,3}([.,]\d+)?$", t):
|
||||
return False
|
||||
|
||||
# 4. Mots concaténés : "Ventilationventilation"
|
||||
if re.match(r"^([a-zà-ÿ]{3,})\1+[a-zà-ÿ]*$", t, re.IGNORECASE):
|
||||
# 4. Mots concaténés et/ou répétés avec espaces : "VentilationVentilation Ventilation..."
|
||||
if re.match(r"^([a-zà-ÿ]{3,})(\s*\1)+\s*$", t, re.IGNORECASE):
|
||||
return False
|
||||
|
||||
# 5. Mots répétés : tous identiques ("Absence absence", "Anticoagulant anticoagulant")
|
||||
|
||||
Reference in New Issue
Block a user