Реализованы настройки пользователя и новые типы заданий
Создано: - bot/handlers/settings.py - обработчик команды /settings Реализовано: ✅ /settings - настройки пользователя - Выбор уровня английского (A1-C2) - Выбор языка интерфейса (RU/EN) - Интерактивные inline-кнопки ✅ Новый тип заданий - заполнение пропусков - AI генерирует предложение с пропуском - Показывает перевод для контекста - Проверка ответа через AI ✅ Смешанные задания - Случайное чередование типов (переводы + fill-in) - Более разнообразная практика Изменено: - services/ai_service.py - метод generate_fill_in_sentence() - services/task_service.py - метод generate_mixed_tasks() - services/user_service.py - методы обновления настроек - bot/handlers/tasks.py - использование смешанных заданий - main.py - регистрация роутера настроек Теперь бот предлагает: - Перевод EN→RU - Перевод RU→EN - Заполнение пропусков в предложениях 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -14,7 +14,7 @@ class AIService:
|
||||
f"https://gateway.ai.cloudflare.com/v1/"
|
||||
f"{settings.cloudflare_account_id}/"
|
||||
f"{settings.cloudflare_gateway_id}/"
|
||||
f"openai"
|
||||
f"compat"
|
||||
)
|
||||
self.client = AsyncOpenAI(
|
||||
api_key=settings.openai_api_key,
|
||||
@@ -127,6 +127,50 @@ class AIService:
|
||||
"score": 0
|
||||
}
|
||||
|
||||
async def generate_fill_in_sentence(self, word: str) -> Dict:
|
||||
"""
|
||||
Сгенерировать предложение с пропуском для заданного слова
|
||||
|
||||
Args:
|
||||
word: Слово, для которого нужно создать предложение
|
||||
|
||||
Returns:
|
||||
Dict с предложением и правильным ответом
|
||||
"""
|
||||
prompt = f"""Создай предложение на английском языке, используя слово "{word}".
|
||||
Замени это слово на пропуск "___".
|
||||
|
||||
Верни ответ в формате JSON:
|
||||
{{
|
||||
"sentence": "предложение с пропуском ___",
|
||||
"answer": "{word}",
|
||||
"translation": "перевод предложения на русский"
|
||||
}}
|
||||
|
||||
Предложение должно быть простым и естественным. Контекст должен четко подсказывать правильное слово."""
|
||||
|
||||
try:
|
||||
response = await self.client.chat.completions.create(
|
||||
model="gpt-4o-mini",
|
||||
messages=[
|
||||
{"role": "system", "content": "Ты - преподаватель английского языка. Создавай простые и понятные упражнения."},
|
||||
{"role": "user", "content": prompt}
|
||||
],
|
||||
temperature=0.7,
|
||||
response_format={"type": "json_object"}
|
||||
)
|
||||
|
||||
import json
|
||||
result = json.loads(response.choices[0].message.content)
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
return {
|
||||
"sentence": f"I like to ___ every day.",
|
||||
"answer": word,
|
||||
"translation": f"Мне нравится {word} каждый день."
|
||||
}
|
||||
|
||||
|
||||
# Глобальный экземпляр сервиса
|
||||
ai_service = AIService()
|
||||
|
||||
@@ -5,6 +5,7 @@ from sqlalchemy import select
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from database.models import Task, Vocabulary
|
||||
from services.ai_service import ai_service
|
||||
|
||||
|
||||
class TaskService:
|
||||
@@ -70,6 +71,87 @@ class TaskService:
|
||||
|
||||
return tasks
|
||||
|
||||
@staticmethod
|
||||
async def generate_mixed_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:
|
||||
# Случайно выбираем тип задания
|
||||
task_type = random.choice(['translate', 'fill_in'])
|
||||
|
||||
if task_type == 'translate':
|
||||
# Задание на перевод
|
||||
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
|
||||
}
|
||||
else:
|
||||
# Задание на заполнение пропуска
|
||||
# Генерируем предложение с пропуском через AI
|
||||
sentence_data = await ai_service.generate_fill_in_sentence(word.word_original)
|
||||
|
||||
task = {
|
||||
'type': 'fill_in',
|
||||
'word_id': word.id,
|
||||
'question': (
|
||||
f"Заполни пропуск в предложении:\n\n"
|
||||
f"<b>{sentence_data['sentence']}</b>\n\n"
|
||||
f"<i>{sentence_data.get('translation', '')}</i>"
|
||||
),
|
||||
'word': word.word_original,
|
||||
'correct_answer': sentence_data['answer'],
|
||||
'sentence': sentence_data['sentence']
|
||||
}
|
||||
|
||||
tasks.append(task)
|
||||
|
||||
return tasks
|
||||
|
||||
@staticmethod
|
||||
async def save_task_result(
|
||||
session: AsyncSession,
|
||||
|
||||
@@ -57,3 +57,41 @@ class UserService:
|
||||
select(User).where(User.telegram_id == telegram_id)
|
||||
)
|
||||
return result.scalar_one_or_none()
|
||||
|
||||
@staticmethod
|
||||
async def update_user_level(session: AsyncSession, user_id: int, level: LanguageLevel):
|
||||
"""
|
||||
Обновить уровень английского пользователя
|
||||
|
||||
Args:
|
||||
session: Сессия базы данных
|
||||
user_id: ID пользователя
|
||||
level: Новый уровень
|
||||
"""
|
||||
result = await session.execute(
|
||||
select(User).where(User.id == user_id)
|
||||
)
|
||||
user = result.scalar_one_or_none()
|
||||
|
||||
if user:
|
||||
user.level = level
|
||||
await session.commit()
|
||||
|
||||
@staticmethod
|
||||
async def update_user_language(session: AsyncSession, user_id: int, language: str):
|
||||
"""
|
||||
Обновить язык интерфейса пользователя
|
||||
|
||||
Args:
|
||||
session: Сессия базы данных
|
||||
user_id: ID пользователя
|
||||
language: Новый язык (ru/en)
|
||||
"""
|
||||
result = await session.execute(
|
||||
select(User).where(User.id == user_id)
|
||||
)
|
||||
user = result.scalar_one_or_none()
|
||||
|
||||
if user:
|
||||
user.language_interface = language
|
||||
await session.commit()
|
||||
|
||||
Reference in New Issue
Block a user