initial commit (backend)
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
"""
|
||||
Единый профиль ученика — источник правды для аналитики и повторения.
|
||||
Никакой LLM здесь нет — только детерминированная бизнес-логика.
|
||||
"""
|
||||
import hashlib
|
||||
import json
|
||||
from decimal import Decimal
|
||||
|
||||
|
||||
async def get_weak_skills(conn, user_id: int, limit: int = 5):
|
||||
"""Получить слабые навыки (mastery < 75 или needs_review/overdue или repeated_error).
|
||||
Одинаково используется в /analytics и /review."""
|
||||
rows = await conn.fetch("""
|
||||
SELECT skill_tag, mastery_score, repeated_error_count,
|
||||
retention_status, trend, recent_accuracy,
|
||||
recognition_score, production_score, application_score,
|
||||
median_correct_time_ms, days_since_last_attempt
|
||||
FROM user_skill_mastery
|
||||
WHERE user_id = $1 AND attempts_count >= 2
|
||||
AND (mastery_score < 75
|
||||
OR retention_status IN ('needs_review', 'overdue')
|
||||
OR repeated_error_count > 0)
|
||||
ORDER BY mastery_score ASC
|
||||
LIMIT $2
|
||||
""", user_id, limit)
|
||||
|
||||
return [dict(r) for r in rows]
|
||||
|
||||
|
||||
async def get_strong_skills(conn, user_id: int, limit: int = 8):
|
||||
"""Получить сильные навыки (mastery >= 75)."""
|
||||
rows = await conn.fetch("""
|
||||
SELECT skill_tag, mastery_score FROM user_skill_mastery
|
||||
WHERE user_id = $1 AND attempts_count >= 2 AND mastery_score >= 75
|
||||
ORDER BY mastery_score DESC
|
||||
LIMIT $2
|
||||
""", user_id, limit)
|
||||
|
||||
return [dict(r) for r in rows]
|
||||
|
||||
|
||||
def get_profile_hash(weak_skills: list) -> str:
|
||||
"""Хэш списка слабых навыков — для инвалидации кэша."""
|
||||
# Конвертируем Decimal в float для JSON
|
||||
serializable = []
|
||||
for s in weak_skills:
|
||||
item = {}
|
||||
for k, v in s.items():
|
||||
if isinstance(v, Decimal):
|
||||
item[k] = float(v)
|
||||
else:
|
||||
item[k] = v
|
||||
serializable.append(item)
|
||||
|
||||
canonical = json.dumps(serializable, sort_keys=True, ensure_ascii=False)
|
||||
return hashlib.sha256(canonical.encode()).hexdigest()[:16]
|
||||
Reference in New Issue
Block a user