Files
tg_bot_language/services/user_service.py
mamonov.ep 16a7df0343 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>
2025-12-08 16:43:08 +03:00

200 lines
6.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from database.models import User, LanguageLevel
from typing import Optional
from utils.levels import set_user_level_for_language, get_default_level
class UserService:
"""Сервис для работы с пользователями"""
@staticmethod
async def get_or_create_user(session: AsyncSession, telegram_id: int, username: Optional[str] = None) -> User:
"""
Получить пользователя или создать нового
Args:
session: Сессия базы данных
telegram_id: Telegram ID пользователя
username: Username пользователя
Returns:
Объект пользователя
"""
# Попытка найти существующего пользователя
result = await session.execute(
select(User).where(User.telegram_id == telegram_id)
)
user = result.scalar_one_or_none()
if user:
return user
# Создание нового пользователя
new_user = User(
telegram_id=telegram_id,
username=username,
level=LanguageLevel.A1
)
session.add(new_user)
await session.commit()
await session.refresh(new_user)
return new_user
@staticmethod
async def get_user_by_telegram_id(session: AsyncSession, telegram_id: int) -> Optional[User]:
"""
Получить пользователя по Telegram ID
Args:
session: Сессия базы данных
telegram_id: Telegram ID пользователя
Returns:
Объект пользователя или None
"""
result = await session.execute(
select(User).where(User.telegram_id == telegram_id)
)
return result.scalar_one_or_none()
@staticmethod
async def get_user_by_id(session: AsyncSession, user_id: int) -> Optional[User]:
"""
Получить пользователя по внутреннему ID
Args:
session: Сессия базы данных
user_id: ID пользователя в БД
Returns:
Объект пользователя или None
"""
result = await session.execute(
select(User).where(User.id == user_id)
)
return result.scalar_one_or_none()
@staticmethod
async def update_user_level(session: AsyncSession, user_id: int, level: str, language: str = None):
"""
Обновить уровень пользователя для языка изучения.
Args:
session: Сессия базы данных
user_id: ID пользователя
level: Новый уровень (строка, например "B1" или "N4")
language: Язык (если None, берётся learning_language пользователя)
"""
result = await session.execute(
select(User).where(User.id == user_id)
)
user = result.scalar_one_or_none()
if user:
# Сохраняем в JSON для всех языков
set_user_level_for_language(user, level, language)
# Для обратной совместимости обновляем старое поле level (только для CEFR)
if level in ["A1", "A2", "B1", "B2", "C1", "C2"]:
user.level = LanguageLevel[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()
@staticmethod
async def update_user_learning_language(session: AsyncSession, user_id: int, language: str):
"""
Обновить язык изучения пользователя
Args:
session: Сессия базы данных
user_id: ID пользователя
language: Новый язык изучения (ISO2)
"""
result = await session.execute(
select(User).where(User.id == user_id)
)
user = result.scalar_one_or_none()
if user:
user.learning_language = language
await session.commit()
@staticmethod
async def update_user_translation_language(session: AsyncSession, user_id: int, language: str):
"""
Обновить язык перевода пользователя
Args:
session: Сессия базы данных
user_id: ID пользователя
language: Новый язык перевода (ru/en/ja)
"""
result = await session.execute(
select(User).where(User.id == user_id)
)
user = result.scalar_one_or_none()
if user:
user.translation_language = language
await session.commit()
@staticmethod
async def update_user_tasks_count(session: AsyncSession, user_id: int, count: int):
"""
Обновить количество заданий пользователя
Args:
session: Сессия базы данных
user_id: ID пользователя
count: Количество заданий (5-15)
"""
# Валидация диапазона
count = max(5, min(15, count))
result = await session.execute(
select(User).where(User.id == user_id)
)
user = result.scalar_one_or_none()
if user:
user.tasks_count = count
await session.commit()
@staticmethod
async def update_user_ai_model(session: AsyncSession, user_id: int, model_id: Optional[int]):
"""
Обновить AI модель пользователя
Args:
session: Сессия базы данных
user_id: ID пользователя
model_id: ID модели или None для глобальной
"""
result = await session.execute(
select(User).where(User.id == user_id)
)
user = result.scalar_one_or_none()
if user:
user.ai_model_id = model_id
await session.commit()