Refactor backend project and tighten CV test coverage

This commit is contained in:
2026-04-01 10:42:55 +02:00
parent 44000f96f2
commit 18d1de45cb
9 changed files with 246 additions and 19 deletions
+7 -1
View File
@@ -26,6 +26,7 @@ OCR_LANGUAGES = "eng"
IMAGE_EXTENSIONS = {".png", ".jpg", ".jpeg", ".webp"}
OLLAMA_BASE_URL = os.getenv("OLLAMA_BASE_URL", "http://127.0.0.1:11434").rstrip("/")
OLLAMA_MODEL = os.getenv("OLLAMA_MODEL", "")
SKIP_MODEL_LOAD = os.getenv("AI_SERVICE_SKIP_MODEL_LOAD", "") == "1"
def _load_runtime():
@@ -39,7 +40,10 @@ def _load_runtime():
return tokenizer, model, device, has_cuda, gpu_name
tokenizer, model, device, GPU_AVAILABLE, GPU_NAME = _load_runtime()
if SKIP_MODEL_LOAD:
tokenizer, model, device, GPU_AVAILABLE, GPU_NAME = None, None, torch.device("cpu"), False, None
else:
tokenizer, model, device, GPU_AVAILABLE, GPU_NAME = _load_runtime()
cache = TTLCache(maxsize=1024, ttl=60 * 60)
@@ -298,6 +302,8 @@ def _role_focused_excerpt(text: str) -> dict:
def _model_summarize(text: str, max_length: int, min_length: int) -> str:
if tokenizer is None or model is None:
raise HTTPException(status_code=503, detail="Summarizer model is not loaded.")
inputs = tokenizer(text, return_tensors="pt", truncation=True, max_length=1024)
input_ids = inputs.input_ids.to(device)
attention_mask = inputs.attention_mask.to(device) if hasattr(inputs, "attention_mask") else None
+3
View File
@@ -0,0 +1,3 @@
-r requirements.txt
pytest==8.3.5
httpx==0.28.1
+77
View File
@@ -0,0 +1,77 @@
import importlib
import os
import sys
from pathlib import Path
from fastapi.testclient import TestClient
ROOT = Path(__file__).resolve().parents[1]
if str(ROOT) not in sys.path:
sys.path.insert(0, str(ROOT))
def load_app_module(monkeypatch):
monkeypatch.setenv("AI_SERVICE_SKIP_MODEL_LOAD", "1")
monkeypatch.delenv("OLLAMA_MODEL", raising=False)
if "app" in sys.modules:
del sys.modules["app"]
module = importlib.import_module("app")
return importlib.reload(module)
def test_health_reports_runtime_without_ollama(monkeypatch):
module = load_app_module(monkeypatch)
client = TestClient(module.app)
response = client.get("/health")
assert response.status_code == 200
payload = response.json()
assert payload["ok"] is True
assert payload["device"] == "cpu"
assert payload["ollama_configured"] is False
assert payload["ollama_model"] is None
def test_classify_block_returns_structured_json(monkeypatch):
module = load_app_module(monkeypatch)
def fake_generate_json(prompt: str):
assert "Senior Platform Engineer" in prompt
return {
"section": "Work Experience",
"confidence": 0.91,
"reason": "job block",
"title": "Senior Platform Engineer",
"company": "Atlas Systems",
"location": "Oslo",
"start": "2019",
"end": "Present",
"bullets": ["Built event-driven APIs and migration tooling."],
}
monkeypatch.setattr(module, "_ollama_generate_json", fake_generate_json)
client = TestClient(module.app)
response = client.post("/cv/classify-block", json={"block": "Senior Platform Engineer at Atlas Systems, Oslo, 2019 - Present. Built event-driven APIs and migration tooling."})
assert response.status_code == 200
payload = response.json()
assert payload["section"] == "Work Experience"
assert payload["title"] == "Senior Platform Engineer"
assert payload["company"] == "Atlas Systems"
assert payload["bullets"] == ["Built event-driven APIs and migration tooling."]
def test_classify_block_defaults_missing_section_to_other(monkeypatch):
module = load_app_module(monkeypatch)
monkeypatch.setattr(module, "_ollama_generate_json", lambda prompt: {"bullets": []})
client = TestClient(module.app)
response = client.post("/cv/classify-block", json={"block": "Miscellaneous profile text"})
assert response.status_code == 200
payload = response.json()
assert payload["section"] == "Other"
assert payload["bullets"] == []