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:
dom
2026-03-07 16:48:10 +01:00
parent 2578afb6ff
commit 4e2b4bd946
210 changed files with 6939 additions and 22104 deletions

View File

@@ -13,7 +13,7 @@ from __future__ import annotations
import bisect
from typing import Optional
from ..config import DossierMedical, GHMEstimation
from ..config import DossierMedical, FinancialImpact, GHMEstimation
# ---------------------------------------------------------------------------
@@ -229,3 +229,99 @@ def estimate_ghm(dossier: DossierMedical) -> GHMEstimation:
estimation.ghm_approx = f"{estimation.cmd}{estimation.type_ghm}??{estimation.severite}"
return estimation
# ---------------------------------------------------------------------------
# Tarifs moyens par CMD (source ATIH open data 2024, valeurs arrondies)
# Utilisé pour le tri relatif, pas pour la facturation.
# Format : cmd -> (tarif_base_euros, supplement_par_niveau_severite)
# ---------------------------------------------------------------------------
_CMD_TARIFS: dict[str, tuple[int, int]] = {
"01": (5500, 1200), # Neurologie
"02": (2800, 600), # Ophtalmologie
"03": (2500, 550), # ORL
"04": (3800, 900), # Pneumologie
"05": (4800, 1100), # Cardiologie
"06": (3500, 800), # Digestif (tube)
"07": (3200, 900), # Hépatobiliaire
"08": (4200, 950), # Ostéo-articulaire
"09": (2400, 500), # Peau
"10": (3000, 700), # Endocrinologie
"11": (3300, 800), # Rein/urinaire
"12": (2800, 650), # Génital masculin
"13": (2600, 600), # Génital féminin
"14": (3100, 700), # Obstétrique
"15": (4500, 1000), # Néonat/périnat
"16": (3400, 800), # Hémato/tumeurs bénignes
"17": (5200, 1100), # Tumeurs malignes
"18": (3600, 850), # Infectieux
"19": (2800, 600), # Psychiatrie
"20": (2200, 500), # Alcool/toxiques
"21": (3500, 800), # Traumatismes
"22": (5800, 1300), # Brûlures
"23": (2000, 400), # Symptômes/Z
"24": (2500, 500), # Causes externes
"25": (4200, 950), # VIH
"26": (3000, 700), # Catégories spéciales
}
_DEFAULT_TARIF = (3000, 800)
def estimate_financial_impact(
ghm_etab: GHMEstimation | None,
ghm_ucr: GHMEstimation | None = None,
) -> FinancialImpact:
"""Estime l'impact financier entre le GHM établissement et le GHM UCR.
Si ghm_ucr est None, on estime l'impact de perdre le codage actuel
vers une sévérité 1 (scénario conservateur).
"""
if not ghm_etab:
return FinancialImpact(raison="GHM établissement non estimé")
cmd = ghm_etab.cmd or ""
base, supplement = _CMD_TARIFS.get(cmd, _DEFAULT_TARIF)
sev_etab = ghm_etab.severite or 1
type_etab = ghm_etab.type_ghm or "M"
if ghm_ucr:
sev_ucr = ghm_ucr.severite or 1
type_ucr = ghm_ucr.type_ghm or "M"
else:
sev_ucr = 1
type_ucr = type_etab
delta_sev = sev_ucr - sev_etab # négatif = perte de sévérité
impact = abs(delta_sev) * supplement
# Changement de type (C→M = perte importante)
changement_type = type_etab != type_ucr
if changement_type and type_etab == "C" and type_ucr == "M":
impact += base # perte du GHS chirurgical
raison = f"Changement C→M + delta sévérité {delta_sev}"
elif changement_type:
impact += supplement
raison = f"Changement type {type_etab}{type_ucr} + delta sévérité {delta_sev}"
elif delta_sev == 0:
raison = "Pas de différence de sévérité estimée"
else:
raison = f"Delta sévérité {delta_sev} (CMD {cmd})"
# Classification priorité
if impact >= 2000 or (changement_type and type_etab == "C"):
priorite = "critique"
elif impact >= 1000 or abs(delta_sev) >= 2:
priorite = "haute"
elif impact > 0:
priorite = "normale"
else:
priorite = "faible"
return FinancialImpact(
delta_severite=delta_sev,
impact_estime_euros=impact,
priorite=priorite,
raison=raison,
)