184 lines
5.9 KiB
Python
184 lines
5.9 KiB
Python
|
|
import random
|
|||
|
|
from datetime import datetime
|
|||
|
|
from typing import List, Dict, Optional
|
|||
|
|
from sqlalchemy import select
|
|||
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|||
|
|
|
|||
|
|
from database.models import Task, Vocabulary
|
|||
|
|
|
|||
|
|
|
|||
|
|
class TaskService:
|
|||
|
|
"""Сервис для работы с заданиями"""
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
async def generate_translation_tasks(
|
|||
|
|
session: AsyncSession,
|
|||
|
|
user_id: int,
|
|||
|
|
count: int = 5
|
|||
|
|
) -> List[Dict]:
|
|||
|
|
"""
|
|||
|
|
Генерация заданий на перевод слов
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
session: Сессия базы данных
|
|||
|
|
user_id: ID пользователя
|
|||
|
|
count: Количество заданий
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
Список заданий
|
|||
|
|
"""
|
|||
|
|
# Получаем слова пользователя
|
|||
|
|
result = await session.execute(
|
|||
|
|
select(Vocabulary)
|
|||
|
|
.where(Vocabulary.user_id == user_id)
|
|||
|
|
.order_by(Vocabulary.last_reviewed.asc().nullsfirst())
|
|||
|
|
.limit(count * 2) # Берем больше, чтобы было из чего выбрать
|
|||
|
|
)
|
|||
|
|
words = list(result.scalars().all())
|
|||
|
|
|
|||
|
|
if not words:
|
|||
|
|
return []
|
|||
|
|
|
|||
|
|
# Выбираем случайные слова
|
|||
|
|
selected_words = random.sample(words, min(count, len(words)))
|
|||
|
|
|
|||
|
|
tasks = []
|
|||
|
|
for word in selected_words:
|
|||
|
|
# Случайно выбираем направление перевода
|
|||
|
|
direction = random.choice(['en_to_ru', 'ru_to_en'])
|
|||
|
|
|
|||
|
|
if direction == 'en_to_ru':
|
|||
|
|
task = {
|
|||
|
|
'type': 'translate_to_ru',
|
|||
|
|
'word_id': word.id,
|
|||
|
|
'question': f"Переведи слово: <b>{word.word_original}</b>",
|
|||
|
|
'word': word.word_original,
|
|||
|
|
'correct_answer': word.word_translation,
|
|||
|
|
'transcription': word.transcription
|
|||
|
|
}
|
|||
|
|
else:
|
|||
|
|
task = {
|
|||
|
|
'type': 'translate_to_en',
|
|||
|
|
'word_id': word.id,
|
|||
|
|
'question': f"Переведи слово: <b>{word.word_translation}</b>",
|
|||
|
|
'word': word.word_translation,
|
|||
|
|
'correct_answer': word.word_original,
|
|||
|
|
'transcription': word.transcription
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
tasks.append(task)
|
|||
|
|
|
|||
|
|
return tasks
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
async def save_task_result(
|
|||
|
|
session: AsyncSession,
|
|||
|
|
user_id: int,
|
|||
|
|
task_type: str,
|
|||
|
|
content: Dict,
|
|||
|
|
user_answer: str,
|
|||
|
|
correct_answer: str,
|
|||
|
|
is_correct: bool,
|
|||
|
|
ai_feedback: Optional[str] = None
|
|||
|
|
) -> Task:
|
|||
|
|
"""
|
|||
|
|
Сохранение результата выполнения задания
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
session: Сессия базы данных
|
|||
|
|
user_id: ID пользователя
|
|||
|
|
task_type: Тип задания
|
|||
|
|
content: Содержимое задания
|
|||
|
|
user_answer: Ответ пользователя
|
|||
|
|
correct_answer: Правильный ответ
|
|||
|
|
is_correct: Правильность ответа
|
|||
|
|
ai_feedback: Обратная связь от AI
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
Сохраненное задание
|
|||
|
|
"""
|
|||
|
|
task = Task(
|
|||
|
|
user_id=user_id,
|
|||
|
|
task_type=task_type,
|
|||
|
|
content=content,
|
|||
|
|
user_answer=user_answer,
|
|||
|
|
correct_answer=correct_answer,
|
|||
|
|
is_correct=is_correct,
|
|||
|
|
ai_feedback=ai_feedback,
|
|||
|
|
completed_at=datetime.utcnow()
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
session.add(task)
|
|||
|
|
await session.commit()
|
|||
|
|
await session.refresh(task)
|
|||
|
|
|
|||
|
|
return task
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
async def update_word_statistics(
|
|||
|
|
session: AsyncSession,
|
|||
|
|
word_id: int,
|
|||
|
|
is_correct: bool
|
|||
|
|
):
|
|||
|
|
"""
|
|||
|
|
Обновление статистики слова
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
session: Сессия базы данных
|
|||
|
|
word_id: ID слова
|
|||
|
|
is_correct: Правильность ответа
|
|||
|
|
"""
|
|||
|
|
result = await session.execute(
|
|||
|
|
select(Vocabulary).where(Vocabulary.id == word_id)
|
|||
|
|
)
|
|||
|
|
word = result.scalar_one_or_none()
|
|||
|
|
|
|||
|
|
if word:
|
|||
|
|
word.times_reviewed += 1
|
|||
|
|
if is_correct:
|
|||
|
|
word.correct_answers += 1
|
|||
|
|
word.last_reviewed = datetime.utcnow()
|
|||
|
|
|
|||
|
|
await session.commit()
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
async def get_user_stats(session: AsyncSession, user_id: int) -> Dict:
|
|||
|
|
"""
|
|||
|
|
Получение статистики пользователя
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
session: Сессия базы данных
|
|||
|
|
user_id: ID пользователя
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
Статистика пользователя
|
|||
|
|
"""
|
|||
|
|
# Количество слов
|
|||
|
|
words_result = await session.execute(
|
|||
|
|
select(Vocabulary).where(Vocabulary.user_id == user_id)
|
|||
|
|
)
|
|||
|
|
words = list(words_result.scalars().all())
|
|||
|
|
total_words = len(words)
|
|||
|
|
|
|||
|
|
# Количество выполненных заданий
|
|||
|
|
tasks_result = await session.execute(
|
|||
|
|
select(Task).where(Task.user_id == user_id)
|
|||
|
|
)
|
|||
|
|
tasks = list(tasks_result.scalars().all())
|
|||
|
|
total_tasks = len(tasks)
|
|||
|
|
|
|||
|
|
# Правильные ответы
|
|||
|
|
correct_tasks = len([t for t in tasks if t.is_correct])
|
|||
|
|
accuracy = int((correct_tasks / total_tasks * 100)) if total_tasks > 0 else 0
|
|||
|
|
|
|||
|
|
# Слова с повторениями
|
|||
|
|
reviewed_words = len([w for w in words if w.times_reviewed > 0])
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
'total_words': total_words,
|
|||
|
|
'reviewed_words': reviewed_words,
|
|||
|
|
'total_tasks': total_tasks,
|
|||
|
|
'correct_tasks': correct_tasks,
|
|||
|
|
'accuracy': accuracy
|
|||
|
|
}
|