feat: multiple translations with context, improved task examples
- Add WordTranslation model for storing multiple translations per word - AI generates translations with example sentences and their translations - Show example usage after answering tasks (learning + interface language) - Save translations to word_translations table when adding words from tasks - Improve word exclusion in new_words mode (stronger prompt + client filtering) - Add migration for word_translations table 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,7 @@ from typing import List, Dict, Optional
|
||||
from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from database.models import Task, Vocabulary
|
||||
from database.models import Task, Vocabulary, WordTranslation
|
||||
from services.ai_service import ai_service
|
||||
|
||||
|
||||
@@ -107,8 +107,54 @@ class TaskService:
|
||||
|
||||
tasks = []
|
||||
for word in selected_words:
|
||||
# Получаем переводы из таблицы WordTranslation
|
||||
translations_result = await session.execute(
|
||||
select(WordTranslation)
|
||||
.where(WordTranslation.vocabulary_id == word.id)
|
||||
.order_by(WordTranslation.is_primary.desc())
|
||||
)
|
||||
translations = list(translations_result.scalars().all())
|
||||
|
||||
# Случайно выбираем тип задания
|
||||
task_type = random.choice(['translate', 'fill_in'])
|
||||
# Если есть переводы с контекстом, добавляем тип 'context_translate'
|
||||
task_types = ['translate', 'fill_in']
|
||||
if translations and any(tr.context for tr in translations):
|
||||
task_types.append('context_translate')
|
||||
|
||||
task_type = random.choice(task_types)
|
||||
|
||||
if task_type == 'context_translate' and translations:
|
||||
# Задание на перевод по контексту
|
||||
# Выбираем случайный перевод с контекстом
|
||||
translations_with_context = [tr for tr in translations if tr.context]
|
||||
if translations_with_context:
|
||||
selected_tr = random.choice(translations_with_context)
|
||||
|
||||
# Локализация фразы
|
||||
if translation_lang == 'en':
|
||||
prompt = "Translate the highlighted word in context:"
|
||||
elif translation_lang == 'ja':
|
||||
prompt = "文脈に合った翻訳を入力してください:"
|
||||
else:
|
||||
prompt = "Переведи выделенное слово в контексте:"
|
||||
|
||||
task = {
|
||||
'type': 'context_translate',
|
||||
'word_id': word.id,
|
||||
'translation_id': selected_tr.id,
|
||||
'question': (
|
||||
f"{prompt}\n\n"
|
||||
f"<i>«{selected_tr.context}»</i>\n\n"
|
||||
f"<b>{word.word_original}</b> = ?"
|
||||
),
|
||||
'word': word.word_original,
|
||||
'correct_answer': selected_tr.translation,
|
||||
'transcription': word.transcription,
|
||||
'context': selected_tr.context,
|
||||
'context_translation': selected_tr.context_translation
|
||||
}
|
||||
tasks.append(task)
|
||||
continue
|
||||
|
||||
if task_type == 'translate':
|
||||
# Задание на перевод между языком обучения и языком перевода
|
||||
@@ -122,21 +168,31 @@ class TaskService:
|
||||
else:
|
||||
prompt = "Переведи слово:"
|
||||
|
||||
# Определяем правильный ответ - берём из таблицы переводов если есть
|
||||
correct_translation = word.word_translation
|
||||
if translations:
|
||||
# Берём основной перевод или первый
|
||||
primary = next((tr for tr in translations if tr.is_primary), translations[0] if translations else None)
|
||||
if primary:
|
||||
correct_translation = primary.translation
|
||||
|
||||
if direction == 'learn_to_tr':
|
||||
task = {
|
||||
'type': f'translate_to_{translation_lang}',
|
||||
'word_id': word.id,
|
||||
'question': f"{prompt} <b>{word.word_original}</b>",
|
||||
'word': word.word_original,
|
||||
'correct_answer': word.word_translation,
|
||||
'transcription': word.transcription
|
||||
'correct_answer': correct_translation,
|
||||
'transcription': word.transcription,
|
||||
# Все допустимые ответы для проверки
|
||||
'all_translations': [tr.translation for tr in translations] if translations else [correct_translation]
|
||||
}
|
||||
else:
|
||||
task = {
|
||||
'type': f'translate_to_{learning_lang}',
|
||||
'word_id': word.id,
|
||||
'question': f"{prompt} <b>{word.word_translation}</b>",
|
||||
'word': word.word_translation,
|
||||
'question': f"{prompt} <b>{correct_translation}</b>",
|
||||
'word': correct_translation,
|
||||
'correct_answer': word.word_original,
|
||||
'transcription': word.transcription
|
||||
}
|
||||
@@ -285,3 +341,34 @@ class TaskService:
|
||||
'correct_tasks': correct_tasks,
|
||||
'accuracy': accuracy
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
async def get_correctly_answered_words(
|
||||
session: AsyncSession,
|
||||
user_id: int
|
||||
) -> List[str]:
|
||||
"""
|
||||
Получить список слов, на которые пользователь правильно ответил в заданиях
|
||||
|
||||
Args:
|
||||
session: Сессия базы данных
|
||||
user_id: ID пользователя
|
||||
|
||||
Returns:
|
||||
Список слов (строки) с правильными ответами
|
||||
"""
|
||||
result = await session.execute(
|
||||
select(Task)
|
||||
.where(Task.user_id == user_id)
|
||||
.where(Task.is_correct == True)
|
||||
)
|
||||
tasks = list(result.scalars().all())
|
||||
|
||||
words = []
|
||||
for task in tasks:
|
||||
if task.content and isinstance(task.content, dict):
|
||||
word = task.content.get('word')
|
||||
if word:
|
||||
words.append(word.lower())
|
||||
|
||||
return list(set(words))
|
||||
|
||||
Reference in New Issue
Block a user