8.3 KiB
Corrections Interface Web - Highlights et Infos Patient
Date
12 février 2026
Problèmes Identifiés
1. Highlights mal positionnés
Symptôme: Les mots/phrases surlignés ne correspondaient pas aux textes exacts dans le document (ex: "AROSCOPIE" au lieu de "LAPAROSCOPIE", "Diagnostic : cholécystite" coupé).
Cause racine: Le HighlightManager.applyHighlights() utilisait container.textContent pour extraire le contenu, ce qui normalise les espaces et les retours à la ligne, décalant ainsi toutes les positions de span.
Solution: Modifier DocumentsPanel.highlightCodeEvidence() pour passer le contenu original du document (depuis activeDocument.content) au lieu de laisser HighlightManager utiliser textContent.
2. Informations patient manquantes
Symptôme: L'en-tête patient affichait "Non renseigné" pour l'âge et le sexe.
Cause racine:
- L'API
tim_api.pyextrayait déjà correctement les infos depuis les documents (âge: 76, sexe: M, date de naissance: 1949-09-22) - Le
PatientHeader.render()utilisait une logique incorrecte pour récupérer l'âge:stay.age || this.calculateAge(...)qui retournaitfalsesiage === 0
Solution: Utiliser une vérification stricte stay.age !== null && stay.age !== undefined pour permettre l'âge 0.
Fichiers Modifiés
1. src/pipeline_mco_pmsi/api/static/js/components/documents-panel.js
Ligne modifiée: Méthode highlightCodeEvidence()
// AVANT
this.highlightManager.applyHighlights(contentContainer, documentEvidence, code.type);
// APRÈS
this.highlightManager.applyHighlights(
contentContainer,
documentEvidence,
code.type,
activeDocument.content // Contenu original du document
);
Explication: Le 4ème paramètre originalContent est maintenant passé à applyHighlights() pour utiliser le contenu original du document au lieu du textContent normalisé du DOM.
2. src/pipeline_mco_pmsi/api/static/js/components/patient-header.js
Ligne modifiée: Méthode render(), calcul de l'âge
// AVANT
const age = stay.age || this.calculateAge(patient.birthDate, stay.age);
// APRÈS
const age = stay.age !== null && stay.age !== undefined ? stay.age : this.calculateAge(patient.birthDate);
Ajout de logs de debug:
console.log('PatientHeader.render() called with stay:', stay);
console.log('PatientHeader values:', {
age: age,
sex: patient.sex,
bmi: bmi,
duration: duration,
anonymizedId: anonymizedId
});
Vérification
Test API
# Vérifier que l'API retourne les bonnes données
curl http://localhost:8001/stays/15_23096332/coding-proposal | jq '.age, .sex, .birth_date'
# Résultat attendu:
# 76
# "M"
# "1949-09-22"
Test Document
# Vérifier que le document a le bon contenu
curl http://localhost:8001/documents/15_23096332_DOC001 | jq '.content | length'
# Résultat attendu: 3425 caractères
Test Highlight Positioning
# Vérifier qu'une position de preuve correspond au texte
curl http://localhost:8001/documents/15_23096332_DOC001 | \
python3 -c "import sys, json; data = json.load(sys.stdin); print(data['content'][523:599])"
# Résultat attendu: " Diagnostic : cholécystite \n Compte rendu opératoire du 18/05/2023 : \n"
Test Interface Web
- Ouvrir http://localhost:8001
- Entrer l'ID de séjour:
15_23096332 - Cliquer sur "Charger le séjour"
- Vérifier:
- ✅ Infos patient: Âge: 76 ans, Sexe: M
- ✅ Highlights: Les mots surlignés correspondent exactement aux textes dans le document
- ✅ Colorisation: Couleurs douces et transparentes (bleu pour DP, vert pour DR, orange pour DAS, violet pour CCAM)
Test Automatisé
Ouvrir test_interface_corrections.html dans un navigateur pour exécuter les tests automatisés:
- Test 1: Données patient depuis l'API
- Test 2: Contenu du document
- Test 3: Positionnement des highlights
Architecture de la Solution
Flux de données pour les highlights
1. API /stays/{stay_id}/coding-proposal
└─> Retourne codes avec evidence (document_id, span.start, span.end)
2. API /documents/{document_id}
└─> Retourne le contenu original du document (3425 chars)
3. index.html loadStay()
└─> Charge les documents et crée l'objet stay avec documents[]
4. StateManager.setCurrentStay(stay)
└─> Émet l'événement 'stayChanged'
5. DocumentsPanel.loadDocuments(stay)
└─> Stocke stay.documents dans this.documents
6. DocumentsPanel.renderDocument(document)
└─> Affiche le contenu dans #document-text-content
7. CodesPanel sélectionne un code
└─> StateManager émet 'codeSelected'
8. DocumentsPanel.highlightCodeEvidence(code)
└─> Appelle highlightManager.applyHighlights() avec:
- container: #document-text-content
- evidence: code.evidence filtrées par document_id
- codeType: 'dp', 'dr', 'das', 'ccam'
- originalContent: activeDocument.content ← CLEF!
9. HighlightManager.applyHighlights()
└─> Utilise originalContent au lieu de container.textContent
└─> Les positions span correspondent maintenant exactement
Flux de données pour les infos patient
1. API /stays/{stay_id}/coding-proposal
└─> Extrait age, sex, birth_date depuis les documents
└─> Retourne: { age: 76, sex: "M", birth_date: "1949-09-22", ... }
2. index.html loadStay()
└─> Crée l'objet stay avec:
- stay.age = data.age (76)
- stay.patient.sex = data.sex ("M")
- stay.patient.birthDate = data.birth_date ("1949-09-22")
3. StateManager.setCurrentStay(stay)
└─> Émet l'événement 'stayChanged'
4. PatientHeader.render(stay)
└─> Utilise stay.age !== null && stay.age !== undefined
└─> Affiche correctement l'âge même si age === 0
Extraction des Infos Patient (Backend)
L'API tim_api.py extrait automatiquement les informations patient depuis les documents si elles ne sont pas disponibles dans la base:
# Extraire la date de naissance
birth_match = re.search(r'(?:Né|Date de naissance).*?(\d{2})/(\d{2})/(\d{4})', content, re.IGNORECASE)
if birth_match:
day, month, year = birth_match.groups()
birth_date = f"{year}-{month}-{day}"
# Calculer l'âge
if stay.admission_date:
birth_dt = datetime.strptime(birth_date, "%Y-%m-%d")
admission_dt = stay.admission_date
age = admission_dt.year - birth_dt.year
if (admission_dt.month, admission_dt.day) < (birth_dt.month, birth_dt.day):
age -= 1
# Extraire le sexe
if re.search(r'\bMonsieur\b', content, re.IGNORECASE):
sex = "M"
elif re.search(r'\bMadame\b', content, re.IGNORECASE):
sex = "F"
Résultat Final
✅ Highlights correctement positionnés: Les spans correspondent exactement aux positions dans le contenu original du document
✅ Infos patient affichées: Âge: 76 ans, Sexe: M, Date de naissance: 22/09/1949
✅ Colorisation douce: Couleurs transparentes avec bordures colorées pour une meilleure lisibilité
✅ Performance: Pas de dégradation, le contenu original est déjà chargé en mémoire
Notes Techniques
Pourquoi textContent normalise les espaces?
Le DOM textContent normalise automatiquement:
- Les espaces multiples → un seul espace
- Les retours à la ligne → espaces
- Les tabulations → espaces
Exemple:
// HTML
<div>Texte avec\n\nespaces</div>
// textContent
"Texte avec espaces" // Positions décalées!
// innerHTML (préservé)
"Texte avec\n\nespaces" // Positions correctes
Pourquoi age || calculateAge() ne fonctionnait pas?
En JavaScript, 0 || fallback retourne fallback car 0 est falsy:
const age = 0;
console.log(age || 100); // 100 (incorrect!)
console.log(age !== null && age !== undefined ? age : 100); // 0 (correct!)
Prochaines Étapes
- ✅ Highlights correctement positionnés
- ✅ Infos patient affichées
- 🔄 Tester avec d'autres séjours pour valider la robustesse
- 🔄 Ajouter des tests unitaires pour
HighlightManager.applyHighlights() - 🔄 Documenter l'API d'extraction des infos patient
Références
- Fichier de test:
test_interface_corrections.html - Documentation précédente:
CORRECTIONS_INTERFACE_FINALE.md - Spec interface:
.kiro/specs/amelioration-interface-tim/