feat: architecture multi-modèles LLM + externalisation des prompts
- Ajout OLLAMA_MODELS (coding/cpam/validation/qc) dans config.py avec get_model() - Paramètre role= dans call_ollama() pour dispatch par rôle - Cache Ollama : modèle stocké par entrée (migration auto de l'ancien format) - 7 prompts externalisés dans src/prompts/templates.py (format str.format) - Viewer : admin multi-modèles, endpoint PDF avec redaction, source texte - Documentation prompts dans docs/prompts.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -49,7 +49,30 @@ class TestOllamaCache:
|
||||
cache.save()
|
||||
assert not path.exists()
|
||||
|
||||
def test_model_change_invalidates(self, tmp_path):
|
||||
def test_model_per_entry_different_model_miss(self, tmp_path):
|
||||
"""Un get avec un modèle différent de celui du put retourne None."""
|
||||
cache = OllamaCache(tmp_path / "cache.json", "gemma3:12b")
|
||||
cache.put("HTA", "das", {"code": "I10"})
|
||||
# Même cache, mais demande avec un modèle différent
|
||||
assert cache.get("HTA", "das", model="llama3:8b") is None
|
||||
|
||||
def test_model_per_entry_same_model_hit(self, tmp_path):
|
||||
"""Un get avec le même modèle retourne le résultat."""
|
||||
cache = OllamaCache(tmp_path / "cache.json", "gemma3:12b")
|
||||
cache.put("HTA", "das", {"code": "I10"})
|
||||
assert cache.get("HTA", "das", model="gemma3:12b") == {"code": "I10"}
|
||||
|
||||
def test_model_per_entry_explicit_put_model(self, tmp_path):
|
||||
"""put() avec model= explicite stocke ce modèle."""
|
||||
cache = OllamaCache(tmp_path / "cache.json", "gemma3:12b")
|
||||
cache.put("HTA", "das", {"code": "I10"}, model="llama3:8b")
|
||||
# Le default model ne matche pas
|
||||
assert cache.get("HTA", "das") is None
|
||||
# Le modèle explicite matche
|
||||
assert cache.get("HTA", "das", model="llama3:8b") == {"code": "I10"}
|
||||
|
||||
def test_save_reload_different_model_miss(self, tmp_path):
|
||||
"""Après save/reload, les entrées gardent leur modèle."""
|
||||
path = tmp_path / "cache.json"
|
||||
cache = OllamaCache(path, "gemma3:12b")
|
||||
cache.put("HTA", "das", {"code": "I10"})
|
||||
@@ -57,7 +80,16 @@ class TestOllamaCache:
|
||||
|
||||
cache2 = OllamaCache(path, "llama3:8b")
|
||||
assert cache2.get("HTA", "das") is None
|
||||
assert len(cache2) == 0
|
||||
|
||||
def test_save_reload_same_model_hit(self, tmp_path):
|
||||
"""Après save/reload avec le même modèle, le hit fonctionne."""
|
||||
path = tmp_path / "cache.json"
|
||||
cache = OllamaCache(path, "gemma3:12b")
|
||||
cache.put("HTA", "das", {"code": "I10"})
|
||||
cache.save()
|
||||
|
||||
cache2 = OllamaCache(path, "gemma3:12b")
|
||||
assert cache2.get("HTA", "das") == {"code": "I10"}
|
||||
|
||||
def test_corrupted_file(self, tmp_path):
|
||||
path = tmp_path / "cache.json"
|
||||
@@ -95,14 +127,60 @@ class TestOllamaCache:
|
||||
assert not errors
|
||||
assert len(cache) == 20
|
||||
|
||||
def test_json_format(self, tmp_path):
|
||||
"""Le fichier JSON contient le modèle et les entrées."""
|
||||
def test_json_format_new(self, tmp_path):
|
||||
"""Le nouveau format JSON contient entries avec model par entrée."""
|
||||
path = tmp_path / "cache.json"
|
||||
cache = OllamaCache(path, "gemma3:12b")
|
||||
cache.put("HTA", "das", {"code": "I10"})
|
||||
cache.save()
|
||||
|
||||
raw = json.loads(path.read_text(encoding="utf-8"))
|
||||
assert raw["model"] == "gemma3:12b"
|
||||
assert "model" not in raw # plus de modèle global
|
||||
assert "entries" in raw
|
||||
assert len(raw["entries"]) == 1
|
||||
entry = next(iter(raw["entries"].values()))
|
||||
assert entry["model"] == "gemma3:12b"
|
||||
assert entry["result"] == {"code": "I10"}
|
||||
|
||||
def test_backward_compat_old_format_migration(self, tmp_path):
|
||||
"""L'ancien format (model global, entrées sans model) est migré correctement."""
|
||||
path = tmp_path / "cache.json"
|
||||
# Écrire un fichier avec l'ancien format
|
||||
old_data = {
|
||||
"model": "gemma3:12b",
|
||||
"entries": {
|
||||
"das::hta": {"code": "I10"},
|
||||
"dp::diabète type 2": {"code": "E11.9"},
|
||||
},
|
||||
}
|
||||
path.write_text(json.dumps(old_data), encoding="utf-8")
|
||||
|
||||
# Charger avec le même modèle → doit migrer
|
||||
cache = OllamaCache(path, "gemma3:12b")
|
||||
assert len(cache) == 2
|
||||
assert cache.get("HTA", "das") == {"code": "I10"}
|
||||
assert cache.get("diabète type 2", "dp") == {"code": "E11.9"}
|
||||
|
||||
# Sauvegarder et vérifier le nouveau format
|
||||
cache.save()
|
||||
raw = json.loads(path.read_text(encoding="utf-8"))
|
||||
assert "model" not in raw # plus de modèle global
|
||||
entry = raw["entries"]["das::hta"]
|
||||
assert entry["model"] == "gemma3:12b"
|
||||
assert entry["result"] == {"code": "I10"}
|
||||
|
||||
def test_backward_compat_old_format_wrong_model(self, tmp_path):
|
||||
"""L'ancien format migré garde le modèle d'origine, pas celui du constructeur."""
|
||||
path = tmp_path / "cache.json"
|
||||
old_data = {
|
||||
"model": "gemma3:12b",
|
||||
"entries": {
|
||||
"das::hta": {"code": "I10"},
|
||||
},
|
||||
}
|
||||
path.write_text(json.dumps(old_data), encoding="utf-8")
|
||||
|
||||
# Charger avec un modèle différent → entrée a le modèle d'origine
|
||||
cache = OllamaCache(path, "llama3:8b")
|
||||
assert cache.get("HTA", "das") is None # llama3:8b != gemma3:12b
|
||||
assert cache.get("HTA", "das", model="gemma3:12b") == {"code": "I10"}
|
||||
|
||||
Reference in New Issue
Block a user