141 lines
5.0 KiB
Python
141 lines
5.0 KiB
Python
"""
|
|
Typing Router — раздел "Печать".
|
|
Пользователь печатает польские предложения, система проверяет.
|
|
Без AI — просто сравнение с правильным ответом из БД.
|
|
"""
|
|
import random
|
|
from fastapi import APIRouter, Request, HTTPException
|
|
from auth import require_auth
|
|
from database import get_pool
|
|
|
|
router = APIRouter(prefix="/typing", tags=["typing"])
|
|
|
|
|
|
def normalize_text(text: str) -> str:
|
|
"""Нормализует текст для сравнения: нижний регистр, убирает лишние пробелы."""
|
|
return ' '.join(text.strip().lower().split())
|
|
|
|
|
|
@router.get("/next")
|
|
async def get_next_typing_sentence(request: Request):
|
|
"""Выдаёт случайное непройденное предложение для выбранного уровня."""
|
|
telegram_id, _ = await require_auth(request)
|
|
|
|
pool = await get_pool()
|
|
async with pool.acquire() as conn:
|
|
user = await conn.fetchrow("""
|
|
SELECT app_language, current_level FROM users WHERE telegram_id = $1
|
|
""", telegram_id)
|
|
if not user:
|
|
raise HTTPException(401, "User not registered")
|
|
|
|
lang = user["app_language"] or "pl"
|
|
current_level = user["current_level"] or "A1"
|
|
|
|
# Находим случайное непройденное предложение
|
|
row = await conn.fetchrow("""
|
|
SELECT s.id, s.sentence_pl, s.translation_ru, s.translation_uk, s.translation_en, s.level
|
|
FROM sentences s
|
|
WHERE s.level = $1
|
|
AND s.id NOT IN (
|
|
SELECT sentence_id FROM typing_progress WHERE user_id = $2
|
|
)
|
|
ORDER BY RANDOM()
|
|
LIMIT 1
|
|
""", current_level, telegram_id)
|
|
|
|
if not row:
|
|
return {"completed": True, "message": "Все предложения пройдены!"}
|
|
|
|
translation_field = f"translation_{lang}"
|
|
translation = row.get(translation_field) or row.get("translation_en") or row["sentence_pl"]
|
|
|
|
return {
|
|
"completed": False,
|
|
"sentence_id": row["id"],
|
|
"translation": translation,
|
|
"level": row["level"],
|
|
}
|
|
|
|
|
|
@router.post("/check")
|
|
async def check_typing_sentence(request: Request):
|
|
"""Проверяет напечатанное предложение."""
|
|
telegram_id, _ = await require_auth(request)
|
|
body = await request.json()
|
|
sentence_id = body.get("sentence_id")
|
|
user_text = body.get("text", "")
|
|
|
|
if not sentence_id or not user_text:
|
|
raise HTTPException(400, "sentence_id and text required")
|
|
|
|
pool = await get_pool()
|
|
async with pool.acquire() as conn:
|
|
row = await conn.fetchrow("""
|
|
SELECT sentence_pl FROM sentences WHERE id = $1
|
|
""", sentence_id)
|
|
if not row:
|
|
raise HTTPException(404, "Sentence not found")
|
|
|
|
correct_text = normalize_text(row["sentence_pl"])
|
|
user_normalized = normalize_text(user_text)
|
|
|
|
is_correct = correct_text == user_normalized
|
|
|
|
if is_correct:
|
|
# Сохраняем прогресс
|
|
await conn.execute("""
|
|
INSERT INTO typing_progress (user_id, sentence_id, completed_at)
|
|
VALUES ($1, $2, NOW())
|
|
ON CONFLICT (user_id, sentence_id) DO NOTHING
|
|
""", telegram_id, sentence_id)
|
|
|
|
return {
|
|
"correct": is_correct,
|
|
"correct_answer": row["sentence_pl"],
|
|
}
|
|
|
|
|
|
@router.get("/hint/{sentence_id}")
|
|
async def get_typing_hint(request: Request, sentence_id: int):
|
|
"""Возвращает правильный ответ для подсказки."""
|
|
await require_auth(request)
|
|
|
|
pool = await get_pool()
|
|
async with pool.acquire() as conn:
|
|
row = await conn.fetchrow("""
|
|
SELECT sentence_pl FROM sentences WHERE id = $1
|
|
""", sentence_id)
|
|
if not row:
|
|
raise HTTPException(404, "Sentence not found")
|
|
|
|
return {"correct_answer": row["sentence_pl"]}
|
|
|
|
|
|
@router.get("/progress")
|
|
async def get_typing_progress(request: Request):
|
|
"""Статистика по печати."""
|
|
telegram_id, _ = await require_auth(request)
|
|
|
|
pool = await get_pool()
|
|
async with pool.acquire() as conn:
|
|
user = await conn.fetchrow("""
|
|
SELECT current_level FROM users WHERE telegram_id = $1
|
|
""", telegram_id)
|
|
current_level = user["current_level"] if user else "A1"
|
|
|
|
total = await conn.fetchval("""
|
|
SELECT COUNT(*) FROM sentences WHERE level = $1
|
|
""", current_level) or 0
|
|
|
|
completed = await conn.fetchval("""
|
|
SELECT COUNT(*) FROM typing_progress tp
|
|
JOIN sentences s ON tp.sentence_id = s.id
|
|
WHERE tp.user_id = $1 AND s.level = $2
|
|
""", telegram_id, current_level) or 0
|
|
|
|
return {
|
|
"total": total,
|
|
"completed": completed,
|
|
"remaining": total - completed,
|
|
} |