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:
@@ -69,33 +69,47 @@ async def process_word_addition(message: Message, state: FSMContext, word: str):
|
||||
lang = (user.language_interface if user else 'ru') or 'ru'
|
||||
processing_msg = await message.answer(t(lang, 'add.searching'))
|
||||
|
||||
# Получаем перевод через AI
|
||||
# Получаем перевод через AI (с несколькими значениями)
|
||||
async with async_session_maker() as session:
|
||||
user = await UserService.get_user_by_telegram_id(session, message.from_user.id)
|
||||
source_lang = user.learning_language if user else 'en'
|
||||
ui_lang = user.language_interface if user else 'ru'
|
||||
word_data = await ai_service.translate_word(word, source_lang=source_lang, translation_lang=ui_lang)
|
||||
word_data = await ai_service.translate_word_with_contexts(
|
||||
word, source_lang=source_lang, translation_lang=ui_lang, max_translations=3
|
||||
)
|
||||
|
||||
# Удаляем сообщение о загрузке
|
||||
await processing_msg.delete()
|
||||
|
||||
# Формируем примеры
|
||||
examples_text = ""
|
||||
if word_data.get("examples"):
|
||||
examples_text = "\n\n" + t(lang, 'add.examples_header') + "\n"
|
||||
for idx, example in enumerate(word_data["examples"][:2], 1):
|
||||
src = example.get(source_lang) or example.get('en') or example.get('ru') or ''
|
||||
tr = example.get(ui_lang) or example.get('ru') or example.get('en') or ''
|
||||
examples_text += f"{idx}. {src}\n <i>{tr}</i>\n"
|
||||
# Формируем текст с переводами
|
||||
translations = word_data.get("translations", [])
|
||||
translations_text = ""
|
||||
|
||||
if translations:
|
||||
# Основной перевод для backward compatibility
|
||||
primary = next((tr for tr in translations if tr.get('is_primary')), translations[0])
|
||||
word_data['translation'] = primary.get('translation', '')
|
||||
|
||||
translations_text = "\n\n" + t(lang, 'add.translations_header') + "\n"
|
||||
for idx, tr in enumerate(translations, 1):
|
||||
marker = "★ " if tr.get('is_primary') else ""
|
||||
translations_text += f"{idx}. {marker}<b>{tr.get('translation', '')}</b>\n"
|
||||
if tr.get('context'):
|
||||
translations_text += f" <i>«{tr.get('context', '')}»</i>\n"
|
||||
if tr.get('context_translation'):
|
||||
translations_text += f" <i>({tr.get('context_translation', '')})</i>\n"
|
||||
translations_text += "\n"
|
||||
else:
|
||||
# Fallback если нет переводов
|
||||
word_data['translation'] = 'Ошибка перевода'
|
||||
|
||||
# Отправляем карточку слова
|
||||
card_text = (
|
||||
f"📝 <b>{word_data['word']}</b>\n"
|
||||
f"🔊 [{word_data.get('transcription', '')}]\n\n"
|
||||
f"{t(lang, 'add.translation_label')}: {word_data['translation']}\n"
|
||||
f"{t(lang, 'add.category_label')}: {word_data.get('category', '')}\n"
|
||||
f"{t(lang, 'add.level_label')}: {word_data.get('difficulty', 'A1')}"
|
||||
f"{examples_text}\n\n"
|
||||
f"{translations_text}"
|
||||
f"{t(lang, 'add.confirm_question')}"
|
||||
)
|
||||
|
||||
@@ -130,7 +144,7 @@ async def confirm_add_word(callback: CallbackQuery, state: FSMContext):
|
||||
ui_lang = user.language_interface if user else 'ru'
|
||||
|
||||
# Добавляем слово в базу
|
||||
await VocabularyService.add_word(
|
||||
new_word = await VocabularyService.add_word(
|
||||
session,
|
||||
user_id=user_id,
|
||||
word_original=word_data["word"],
|
||||
@@ -138,12 +152,20 @@ async def confirm_add_word(callback: CallbackQuery, state: FSMContext):
|
||||
source_lang=source_lang,
|
||||
translation_lang=ui_lang,
|
||||
transcription=word_data.get("transcription"),
|
||||
examples={"examples": word_data.get("examples", [])},
|
||||
category=word_data.get("category"),
|
||||
difficulty_level=word_data.get("difficulty"),
|
||||
source=WordSource.MANUAL
|
||||
)
|
||||
|
||||
# Сохраняем переводы с контекстами в отдельную таблицу
|
||||
translations = word_data.get("translations", [])
|
||||
if translations:
|
||||
await VocabularyService.add_translations_bulk(
|
||||
session,
|
||||
vocabulary_id=new_word.id,
|
||||
translations=translations
|
||||
)
|
||||
|
||||
# Получаем общее количество слов
|
||||
words_count = await VocabularyService.get_words_count(session, user_id, learning_lang=user.learning_language)
|
||||
lang = ui_lang or 'ru'
|
||||
|
||||
Reference in New Issue
Block a user