feat: 3 quick wins — source DAS, fallback code parent, filtre anatomique
1. Champ source sur Diagnostic : trackare/edsnlp/regex/llm_das - Renseigné dans les 8 constructeurs de cim10_extractor.py - Permet l'audit de provenance des DAS dans le JSON de sortie 2. Fallback code parent pour les codes LLM halluccinés : - fallback_parent_code() dans cim10_dict.py (D71.9→D71, R69.8→R69) - Intégré dans _apply_llm_result_diagnostic() de rag_search.py - Récupère les codes rejetés dont le parent 3-char est valide 3. Règle 12 filtre DAS : en-têtes anatomiques + catégories vagues - Rejette "Musculaire", "Digestif", "Hépatique" (mots isolés) - Rejette "Musculaire - masse musculaire" (catégorie + description) - 13 nouveaux tests unitaires au total Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -504,7 +504,7 @@ class TestRAGSearchMocked:
|
||||
{"document": "cim10", "page": 496, "code": "K85", "extrait": "K85", "score": 0.9},
|
||||
]
|
||||
mock_llm = {
|
||||
"code": "X99.99", # code invalide
|
||||
"code": "QQ9.99", # code invalide (pas de parent valide)
|
||||
"confidence": "high",
|
||||
"justification": "Hallucination",
|
||||
}
|
||||
@@ -516,6 +516,26 @@ class TestRAGSearchMocked:
|
||||
# Le code original est conservé (pas remplacé par le code invalide)
|
||||
assert diag.cim10_suggestion == "K85.9"
|
||||
|
||||
def test_enrich_diagnostic_fallback_parent_code(self):
|
||||
"""Un code invalide D71.9 est corrigé en D71 (code parent standalone)."""
|
||||
from src.medical.rag_search import enrich_diagnostic
|
||||
|
||||
diag = Diagnostic(texte="Anomalie des leucocytes")
|
||||
mock_sources = [
|
||||
{"document": "cim10", "page": 100, "code": "D71", "extrait": "D71", "score": 0.9},
|
||||
]
|
||||
mock_llm = {
|
||||
"code": "D71.9", # invalide : D71 est standalone
|
||||
"confidence": "high",
|
||||
"justification": "Anomalie leucocytaire",
|
||||
}
|
||||
|
||||
with patch("src.medical.rag_search.search_similar", return_value=mock_sources), \
|
||||
patch("src.medical.rag_search._call_ollama", return_value=mock_llm):
|
||||
enrich_diagnostic(diag, {"sexe": "M", "age": 60})
|
||||
|
||||
assert diag.cim10_suggestion == "D71"
|
||||
|
||||
def test_enrich_diagnostic_normalizes_code(self):
|
||||
"""Un code Ollama sans point est normalisé (K851 → K85.1)."""
|
||||
from src.medical.rag_search import enrich_diagnostic
|
||||
@@ -668,6 +688,36 @@ class TestValidateCodeCIM10:
|
||||
assert is_valid is True
|
||||
|
||||
|
||||
class TestFallbackParentCode:
|
||||
def test_d71_9_to_d71(self):
|
||||
"""D71.9 (invalide) → D71 (standalone valide)."""
|
||||
from src.medical.cim10_dict import fallback_parent_code
|
||||
assert fallback_parent_code("D71.9") == "D71"
|
||||
|
||||
def test_r69_8_to_r69(self):
|
||||
"""R69.8 (invalide) → R69 (standalone valide)."""
|
||||
from src.medical.cim10_dict import fallback_parent_code
|
||||
assert fallback_parent_code("R69.8") == "R69"
|
||||
|
||||
def test_valid_code_no_fallback(self):
|
||||
"""Un code déjà valide ne devrait pas matcher (parent aussi valide)."""
|
||||
from src.medical.cim10_dict import fallback_parent_code
|
||||
# K85.1 est valide, donc on ne devrait pas appeler fallback
|
||||
# Mais si on l'appelle, K85 est aussi valide → retourne K85
|
||||
result = fallback_parent_code("K85.1")
|
||||
assert result == "K85" # le parent est valide
|
||||
|
||||
def test_truly_invalid_no_fallback(self):
|
||||
"""Un code sans parent valide retourne None."""
|
||||
from src.medical.cim10_dict import fallback_parent_code
|
||||
assert fallback_parent_code("QQ9.99") is None
|
||||
|
||||
def test_three_char_code_no_fallback(self):
|
||||
"""Un code 3 caractères sans point ne peut pas remonter."""
|
||||
from src.medical.cim10_dict import fallback_parent_code
|
||||
assert fallback_parent_code("QQ9") is None
|
||||
|
||||
|
||||
class TestValidateCIM10PostProcessing:
|
||||
def test_hallucination_rejected(self):
|
||||
"""Les codes hallucination (Aucun, N/A...) sont rejetés."""
|
||||
|
||||
Reference in New Issue
Block a user