67 lines
2.6 KiB
Python
67 lines
2.6 KiB
Python
"""ИИ-инсайт получает только агрегаты и обязан вернуть строгий JSON."""
|
|
|
|
import json
|
|
|
|
import pytest
|
|
|
|
from app.config import get_settings
|
|
from app.scoring import group_insight
|
|
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def local_settings(monkeypatch):
|
|
monkeypatch.setenv("LLM_PROVIDER", "local")
|
|
monkeypatch.setenv("LLM_BASE_URL", "http://127.0.0.1:18080/v1")
|
|
get_settings.cache_clear()
|
|
yield
|
|
get_settings.cache_clear()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_insight_uses_only_aggregates_and_strict_schema(monkeypatch):
|
|
seen = []
|
|
|
|
class FakeClient:
|
|
def __init__(self, **_kwargs): pass
|
|
async def complete(self, request, **_kwargs):
|
|
seen.append(request)
|
|
return json.dumps({
|
|
"summary": "Группа чаще всего теряет обязательные сведения при опросе.",
|
|
"priorities": ["Отработать уточнение адреса и этажа."],
|
|
}, ensure_ascii=False)
|
|
async def aclose(self): pass
|
|
|
|
monkeypatch.setattr(group_insight, "LlmClient", FakeClient)
|
|
result = await group_insight.generate_group_insight({
|
|
"active_trainees": 4,
|
|
"scored_attempts": 7,
|
|
"average_score": 76.2,
|
|
"errors": [{
|
|
"code": "E2", "title": "Пропущен обязательный факт",
|
|
"rate_percent": 50.0, "recommendation": "Повторить алгоритм опроса",
|
|
}],
|
|
})
|
|
assert result["priorities"] == ["Отработать уточнение адреса и этажа."]
|
|
request = seen[0]
|
|
assert request.temperature == 0
|
|
assert request.response_format["schema"]["additionalProperties"] is False
|
|
payload = json.loads(request.messages[1]["content"])
|
|
assert set(payload) == {"active_trainees", "scored_attempts", "average_score", "typical_errors"}
|
|
assert "trainee_id" not in json.dumps(payload)
|
|
assert "group" not in json.dumps(payload)
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_insight_rejects_wrong_shape(monkeypatch):
|
|
class FakeClient:
|
|
def __init__(self, **_kwargs): pass
|
|
async def complete(self, *_args, **_kwargs):
|
|
return '{"summary":"слишком кратко","priorities":[],"secret":"x"}'
|
|
async def aclose(self): pass
|
|
|
|
monkeypatch.setattr(group_insight, "LlmClient", FakeClient)
|
|
with pytest.raises(group_insight.InsightInvalid):
|
|
await group_insight.generate_group_insight({
|
|
"active_trainees": 1, "scored_attempts": 1, "average_score": 50,
|
|
"errors": [],
|
|
})
|