refactor: réorganisation référentiels, nouveaux modules extraction, nettoyage code obsolète
- Réorganisation data/referentiels/ : pdfs/, dicts/, user/ (structure unifiée) - Fix badges "Source absente" sur page admin référentiels - Ré-indexation COCOA 2025 (555 → 1451 chunks, couverture 94%) - Fix VRAM OOM : embeddings forcés CPU via T2A_EMBED_CPU - Nouveaux modules : document_router, docx_extractor, image_extractor, ocr_engine - Module complétude (quality/completude.py + config YAML) - Template DIM (synthèse dimensionnelle) - Gunicorn config + systemd service t2a-viewer - Suppression t2a_install_rag_cleanup/ (copie obsolète) - Suppression scripts/ et scripts_t2a_v2/ (anciens benchmarks) - Suppression 81 fichiers _doc.txt de test - Cache Ollama : TTL configurable, corrections loader YAML - Dashboard : améliorations templates (base, index, detail, cpam, validation) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -104,7 +104,9 @@ _DAS_PATTERNS: list[tuple[str, str, str]] = [
|
||||
(r"diabete\s+(?:sucre\s+)?(?:de\s+)?type\s+2|diabete\s+type\s*2", "Diabète de type 2", "E11.9"),
|
||||
(r"diabete\s+(?:sucre\s+)?(?:de\s+)?type\s+1|diabete\s+type\s*1", "Diabète de type 1", "E10.9"),
|
||||
(r"dyslipidemie|hypercholesterolemie", "Dyslipidémie", "E78.5"),
|
||||
(r"denutrition|malnutrition", "Dénutrition", "E46"),
|
||||
(r"denutrition\s+severe|malnutrition\s+severe|denutrition\s+grade\s+(?:3|iii|III)", "Dénutrition sévère", "E43"),
|
||||
(r"denutrition\s+moderee?|malnutrition\s+moderee?|denutrition\s+grade\s+(?:2|ii|II)", "Dénutrition modérée", "E44.0"),
|
||||
(r"denutrition|malnutrition|hypoalbuminemie\s+severe", "Dénutrition", "E46"),
|
||||
# Infectieux
|
||||
(r"pneumopathie|pneumonie", "Pneumopathie", "J18.9"),
|
||||
(r"infection\s+urinaire|pyelonephrite", "Infection urinaire", "N39.0"),
|
||||
@@ -271,6 +273,91 @@ def _find_diagnostics_associes(
|
||||
return das
|
||||
|
||||
|
||||
def _detect_nutrition_has2021(dossier: DossierMedical) -> None:
|
||||
"""Détecte la dénutrition selon les critères HAS/FFN novembre 2021.
|
||||
|
||||
Logique déterministe basée sur données structurées (IMC + âge + albumine).
|
||||
- Critère phénotypique : IMC < seuil (âge-dépendant)
|
||||
- Critère de sévérité : albumine < 30 g/L → sévère, 30-35 → modéré
|
||||
- Code final : max(sévérité IMC, sévérité albumine) → E43 ou E44.0
|
||||
|
||||
Ref: HAS/FFN nov 2021 « Diagnostic de la dénutrition chez l'enfant,
|
||||
l'adulte, et la personne de 70 ans et plus »
|
||||
"""
|
||||
# 1. Vérifier qu'aucun code E40-E46 n'est déjà codé
|
||||
existing_codes: set[str] = set()
|
||||
if dossier.diagnostic_principal and dossier.diagnostic_principal.cim10_suggestion:
|
||||
existing_codes.add(dossier.diagnostic_principal.cim10_suggestion)
|
||||
for d in dossier.diagnostics_associes:
|
||||
if d.cim10_suggestion:
|
||||
existing_codes.add(d.cim10_suggestion)
|
||||
|
||||
for code in existing_codes:
|
||||
if code.startswith(("E4",)) and code[:3] in ("E40", "E41", "E42", "E43", "E44", "E45", "E46"):
|
||||
return # Déjà codé
|
||||
|
||||
# 2. Vérifier qu'on a un IMC (critère phénotypique obligatoire)
|
||||
imc = dossier.sejour.imc if dossier.sejour else None
|
||||
if imc is None:
|
||||
return
|
||||
|
||||
age = dossier.sejour.age if dossier.sejour else None
|
||||
|
||||
# 3. Seuils IMC HAS 2021 (âge-dépendants)
|
||||
if age is not None and age >= 70:
|
||||
# Personne âgée ≥ 70 ans
|
||||
if imc >= 22:
|
||||
return # Au-dessus du seuil
|
||||
imc_severe = imc < 20
|
||||
imc_moderate = not imc_severe # 20 ≤ IMC < 22
|
||||
else:
|
||||
# Adulte 18-69 ans (ou âge inconnu → seuils adulte par défaut)
|
||||
if imc >= 18.5:
|
||||
return # Au-dessus du seuil
|
||||
imc_severe = imc <= 17
|
||||
imc_moderate = not imc_severe # 17 < IMC < 18.5
|
||||
|
||||
# 4. Critère de sévérité : albumine
|
||||
albumine_val = None
|
||||
for bio in dossier.biologie_cle:
|
||||
if bio.test == "Albumine" and bio.valeur_num is not None:
|
||||
if bio.quality != "discarded":
|
||||
albumine_val = bio.valeur_num
|
||||
break
|
||||
|
||||
albumine_severe = albumine_val is not None and albumine_val < 30
|
||||
albumine_moderate = albumine_val is not None and 30 <= albumine_val < 35
|
||||
|
||||
# 5. Code final : max(sévérité IMC, sévérité albumine)
|
||||
is_severe = imc_severe or albumine_severe
|
||||
is_moderate = imc_moderate or albumine_moderate
|
||||
|
||||
if is_severe:
|
||||
code = "E43"
|
||||
label = "Dénutrition sévère"
|
||||
elif is_moderate:
|
||||
code = "E44.0"
|
||||
label = "Dénutrition modérée"
|
||||
else:
|
||||
return # Ne devrait pas arriver vu les checks précédents
|
||||
|
||||
# 6. Construire l'alerte explicative
|
||||
parts = []
|
||||
if age is not None and age >= 70:
|
||||
parts.append(f"IMC {imc} (seuil ≥70 ans : <22 modéré, <20 sévère)")
|
||||
else:
|
||||
parts.append(f"IMC {imc} (seuil adulte : <18.5 modéré, ≤17 sévère)")
|
||||
if albumine_val is not None:
|
||||
parts.append(f"Albumine {albumine_val} g/L (<30 sévère, 30-35 modéré)")
|
||||
alerte = f"HAS 2021 — {label} ({code}) : {' ; '.join(parts)}"
|
||||
|
||||
dossier.diagnostics_associes.append(
|
||||
Diagnostic(texte=label, cim10_suggestion=code, source="has2021")
|
||||
)
|
||||
dossier.alertes_codage.append(alerte)
|
||||
logger.info("HAS 2021 dénutrition : %s ajouté (%s)", code, alerte)
|
||||
|
||||
|
||||
def _extract_actes(text: str, dossier: DossierMedical) -> None:
|
||||
"""Extrait les actes CCAM."""
|
||||
text_lower = text.lower()
|
||||
|
||||
Reference in New Issue
Block a user