feat: персональные AI модели, оптимизация задач, фильтрация словаря
- Добавлена поддержка персональных AI моделей для каждого пользователя - Оптимизация создания заданий: батч-запрос к AI вместо N запросов - Фильтрация слов по языку изучения (source_lang) в словаре - Удалены неиспользуемые колонки examples и category из vocabulary - Миграции для ai_model_id и удаления колонок 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -243,7 +243,7 @@ class TaskService:
|
||||
translation_lang: str = 'ru'
|
||||
) -> List[Dict]:
|
||||
"""
|
||||
Генерация заданий определённого типа
|
||||
Генерация заданий определённого типа (оптимизировано - 1 запрос к AI)
|
||||
|
||||
Args:
|
||||
session: Сессия базы данных
|
||||
@@ -272,9 +272,10 @@ class TaskService:
|
||||
# Выбираем случайные слова
|
||||
selected_words = random.sample(words, min(count, len(words)))
|
||||
|
||||
tasks = []
|
||||
# 1. Подготовка: определяем типы и собираем данные для всех слов
|
||||
word_data_list = []
|
||||
for word in selected_words:
|
||||
# Получаем переводы из таблицы WordTranslation
|
||||
# Получаем переводы
|
||||
translations_result = await session.execute(
|
||||
select(WordTranslation)
|
||||
.where(WordTranslation.vocabulary_id == word.id)
|
||||
@@ -288,18 +289,57 @@ class TaskService:
|
||||
else:
|
||||
chosen_type = task_type
|
||||
|
||||
# Определяем правильный перевод
|
||||
# Определяем перевод
|
||||
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
|
||||
|
||||
word_data_list.append({
|
||||
'word': word,
|
||||
'translations': translations,
|
||||
'correct_translation': correct_translation,
|
||||
'chosen_type': chosen_type
|
||||
})
|
||||
|
||||
# 2. Собираем задания, требующие AI
|
||||
ai_tasks = []
|
||||
ai_task_indices = []
|
||||
|
||||
for i, wd in enumerate(word_data_list):
|
||||
if wd['chosen_type'] in ('fill_blank', 'sentence_translate'):
|
||||
ai_tasks.append({
|
||||
'word': wd['word'].word_original,
|
||||
'task_type': wd['chosen_type']
|
||||
})
|
||||
ai_task_indices.append(i)
|
||||
|
||||
# 3. Один запрос к AI
|
||||
ai_results = []
|
||||
if ai_tasks:
|
||||
ai_results = await ai_service.generate_task_sentences_batch(
|
||||
ai_tasks,
|
||||
learning_lang=learning_lang,
|
||||
translation_lang=translation_lang
|
||||
)
|
||||
|
||||
# Маппинг результатов
|
||||
ai_results_map = {}
|
||||
for idx, result in zip(ai_task_indices, ai_results):
|
||||
ai_results_map[idx] = result
|
||||
|
||||
# 4. Собираем финальные задания
|
||||
tasks = []
|
||||
for i, wd in enumerate(word_data_list):
|
||||
word = wd['word']
|
||||
translations = wd['translations']
|
||||
correct_translation = wd['correct_translation']
|
||||
chosen_type = wd['chosen_type']
|
||||
|
||||
if chosen_type == 'word_translate':
|
||||
# Задание на перевод слова
|
||||
direction = random.choice(['learn_to_tr', 'tr_to_learn'])
|
||||
|
||||
# Локализация
|
||||
if translation_lang == 'en':
|
||||
prompt = "Translate the word:"
|
||||
elif translation_lang == 'ja':
|
||||
@@ -328,12 +368,7 @@ class TaskService:
|
||||
}
|
||||
|
||||
elif chosen_type == 'fill_blank':
|
||||
# Задание на заполнение пропуска
|
||||
sentence_data = await ai_service.generate_fill_in_sentence(
|
||||
word.word_original,
|
||||
learning_lang=learning_lang,
|
||||
translation_lang=translation_lang
|
||||
)
|
||||
sentence_data = ai_results_map.get(i, {})
|
||||
|
||||
if translation_lang == 'en':
|
||||
fill_title = "Fill in the blank:"
|
||||
@@ -347,21 +382,16 @@ class TaskService:
|
||||
'word_id': word.id,
|
||||
'question': (
|
||||
f"{fill_title}\n\n"
|
||||
f"<b>{sentence_data['sentence']}</b>\n\n"
|
||||
f"<b>{sentence_data.get('sentence', '___')}</b>\n\n"
|
||||
f"<i>{sentence_data.get('translation', '')}</i>"
|
||||
),
|
||||
'word': word.word_original,
|
||||
'correct_answer': sentence_data['answer'],
|
||||
'sentence': sentence_data['sentence']
|
||||
'correct_answer': sentence_data.get('answer', word.word_original),
|
||||
'sentence': sentence_data.get('sentence', '___')
|
||||
}
|
||||
|
||||
elif chosen_type == 'sentence_translate':
|
||||
# Задание на перевод предложения
|
||||
sentence_data = await ai_service.generate_sentence_for_translation(
|
||||
word.word_original,
|
||||
learning_lang=learning_lang,
|
||||
translation_lang=translation_lang
|
||||
)
|
||||
sentence_data = ai_results_map.get(i, {})
|
||||
|
||||
if translation_lang == 'en':
|
||||
sentence_title = "Translate the sentence:"
|
||||
@@ -376,10 +406,10 @@ class TaskService:
|
||||
task = {
|
||||
'type': 'sentence_translate',
|
||||
'word_id': word.id,
|
||||
'question': f"{sentence_title}\n\n<b>{sentence_data['sentence']}</b>\n\n📝 {word_hint}: <code>{word.word_original}</code> — {correct_translation}",
|
||||
'question': f"{sentence_title}\n\n<b>{sentence_data.get('sentence', word.word_original)}</b>\n\n📝 {word_hint}: <code>{word.word_original}</code> — {correct_translation}",
|
||||
'word': word.word_original,
|
||||
'correct_answer': sentence_data['translation'],
|
||||
'sentence': sentence_data['sentence']
|
||||
'correct_answer': sentence_data.get('translation', correct_translation),
|
||||
'sentence': sentence_data.get('sentence', word.word_original)
|
||||
}
|
||||
|
||||
tasks.append(task)
|
||||
|
||||
Reference in New Issue
Block a user