feat(lessons): implement comprehensive lesson configurator, session runner and AI debrief (Beta)

This commit is contained in:
2026-10-07 13:03:16 +03:00
parent 31e105b2c2
commit 718e9797eb
12 changed files with 4093 additions and 1 deletions
+139
View File
@@ -2359,6 +2359,145 @@ def test_listening_exercise_and_check():
assert "/api/audio/" in card_ex["story_audio_url"]
def test_lessons_presets_crud():
# 1. Login user
login_resp = client.post(
"/api/login",
json={"username": config.ADMIN_USERNAME, "password": config.ADMIN_PASSWORD},
)
assert login_resp.status_code == 200
token = login_resp.json()["token"]
headers = {"Authorization": f"Bearer {token}"}
# 2. Get presets
resp = client.get("/api/lessons/presets", headers=headers)
assert resp.status_code == 200
presets = resp.json()["presets"]
assert len(presets) >= 4
preset_ids = [p["id"] for p in presets]
assert "express" in preset_ids
assert "balanced" in preset_ids
# 3. Create custom preset
new_preset_payload = {
"name": "Тестовый спринт",
"icon": "⚡",
"description": "Быстрый тест",
"estimated_min": 12,
"steps": [
{"id": "step_vocab", "type": "vocab", "enabled": True, "count": 5},
{"id": "step_ai_debrief", "type": "ai_debrief", "enabled": True},
],
}
save_resp = client.post("/api/lessons/presets", json=new_preset_payload, headers=headers)
assert save_resp.status_code == 200
created = save_resp.json()["preset"]
assert created["name"] == "Тестовый спринт"
assert created["is_custom"] is True
custom_id = created["custom_id"]
# Verify custom preset appears in list
resp2 = client.get("/api/lessons/presets", headers=headers)
assert resp2.status_code == 200
presets2 = resp2.json()["presets"]
assert any(p.get("custom_id") == custom_id for p in presets2)
# 4. Delete custom preset
del_resp = client.delete(f"/api/lessons/presets/{custom_id}", headers=headers)
assert del_resp.status_code == 200
assert del_resp.json()["deleted"] is True
def test_lessons_grammar_recommendations_and_articles():
login_resp = client.post(
"/api/login",
json={"username": config.ADMIN_USERNAME, "password": config.ADMIN_PASSWORD},
)
token = login_resp.json()["token"]
headers = {"Authorization": f"Bearer {token}"}
# 1. Grammar recommendations
rec_resp = client.get("/api/lessons/grammar-recommendations", headers=headers)
assert rec_resp.status_code == 200
recs = rec_resp.json()
assert "all_units" in recs
assert len(recs["all_units"]) >= 15
assert "weakest_unit" in recs
assert "previous_unit" in recs
assert "next_unit" in recs
# 2. Articles
art_resp = client.get("/api/lessons/articles", headers=headers)
assert art_resp.status_code == 200
articles = art_resp.json()["articles"]
assert len(articles) >= 8
first_art = articles[0]
assert "title" in first_art
assert "paragraphs" in first_art
assert "paragraphs_ru" in first_art
assert "vocabulary_highlights" in first_art
def test_lessons_debrief_and_history():
login_resp = client.post(
"/api/login",
json={"username": config.ADMIN_USERNAME, "password": config.ADMIN_PASSWORD},
)
token = login_resp.json()["token"]
headers = {"Authorization": f"Bearer {token}"}
# Post session debrief
debrief_payload = {
"preset_name": "⚡ Утренний экспресс (10 мин)",
"duration_seconds": 620,
"total_score": 85,
"steps": [
{"type": "vocab", "title": "Вспоминаем слова", "score": 90, "correct": 9, "total": 10},
{"type": "grammar_review", "title": "Закрепление грамматики", "score": 80, "correct": 4, "total": 5},
{"type": "listening", "title": "Аудирование", "score": 100, "correct": 1, "total": 1},
],
"errors": [
{
"type": "grammar",
"unit_num": 1,
"unit_title": "Present Continuous",
"formula": "S + am/is/are + V-ing",
"user_answer": "sing",
"correct_answer": "are singing",
"explanation": "Слово-маркер Listen указывает на момент речи",
},
{
"type": "vocab",
"term": "reluctant",
"translation": "неохотный",
},
],
}
debrief_resp = client.post("/api/lessons/debrief", json=debrief_payload, headers=headers)
assert debrief_resp.status_code == 200
data = debrief_resp.json()
assert "session_id" in data
assert "ai_report" in data
report = data["ai_report"]
assert report["grade"] in ["A+", "A", "B", "C"]
assert "headline" in report
assert "strengths" in report
assert "error_patterns" in report
assert "tomorrow_focus" in report
# Check history
hist_resp = client.get("/api/lessons/history", headers=headers)
assert hist_resp.status_code == 200
hist = hist_resp.json()
assert hist["total_lessons"] >= 1
assert len(hist["history"]) >= 1
last_session = hist["history"][0]
assert last_session["preset_name"] == "⚡ Утренний экспресс (10 мин)"
assert last_session["errors_count"] == 2