feat(ai): integrate local Ollama AI for in-context sentence translation and caching (Task 13)

This commit is contained in:
2026-10-06 15:05:24 +03:00
parent 0c5951df8d
commit 37a1f1ab35
12 changed files with 605 additions and 15 deletions
+66
View File
@@ -1206,3 +1206,69 @@ def test_offline_dictionary_lookup_and_coverage():
asyncio.run(run_lookups())
def test_sentence_translation_ai_and_caching():
"""Validates local AI sentence translation endpoint, SQLite caching, and in-context word meaning."""
import time
from app.database import compute_sentence_hash, get_cached_sentence_translation, save_sentence_translation
# 1. Unauthenticated request must be blocked
client.cookies.clear()
unauth_res = client.post("/api/translate-sentence", json={"sentence": "He had a prodigious memory."})
assert unauth_res.status_code == 401
# 2. Login as admin
login_res = client.post("/api/login", json={"username": "testadmin", "password": "testpass12345"})
assert login_res.status_code == 200
# 3. Empty sentence validation
empty_res = client.post("/api/translate-sentence", json={"sentence": " "})
assert empty_res.status_code == 400
# 4. Direct SQLite cache unit test
sentence = "He took the matter into his own hands and succeeded."
target_word = "matter"
h = compute_sentence_hash(sentence, target_word)
assert len(h) == 64
# Initially not cached
assert get_cached_sentence_translation(sentence, target_word) is None
# Save to cache
save_sentence_translation(
sentence=sentence,
translated_text="Он взял дело в свои руки и преуспел.",
target_word=target_word,
word_meaning="дело, вопрос",
source="unit_test",
)
cached_entry = get_cached_sentence_translation(sentence, target_word)
assert cached_entry is not None
assert cached_entry["translated_text"] == "Он взял дело в свои руки и преуспел."
assert cached_entry["word_meaning"] == "дело, вопрос"
assert cached_entry["source"] == "unit_test"
# 5. Fast cached retrieval via HTTP endpoint (< 10ms)
t0 = time.perf_counter()
api_res = client.post(
"/api/translate-sentence",
json={"sentence": sentence, "target_word": target_word},
)
dt_ms = (time.perf_counter() - t0) * 1000
assert api_res.status_code == 200
data = api_res.json()
assert data["cached"] is True
assert data["sentence_ru"] == "Он взял дело в свои руки и преуспел."
assert data["word_meaning"] == "дело, вопрос"
assert dt_ms < 50.0
# 6. Test AI status endpoint
status_res = client.get("/api/ai/status")
assert status_res.status_code == 200
status_data = status_res.json()
assert "online" in status_data
assert "models" in status_data
assert "active_model" in status_data