Files
tg_bot_language/services/ai_model_service.py
mamonov.ep eb666ec9bc feat: мульти-провайдер AI, выбор типов заданий, настройка количества
- Добавлена поддержка нескольких AI провайдеров (OpenAI, Google Gemini)
- Добавлена админ-панель (/admin) для переключения AI моделей
- Добавлен AIModelService для управления моделями в БД
- Добавлен выбор типа заданий (микс, перевод слов, подстановка, перевод предложений)
- Добавлена настройка количества заданий (5-15)
- ai_service динамически выбирает провайдера на основе активной модели
- Обработка ограничений моделей (temperature, response_format)
- Очистка markdown обёртки из ответов Gemini

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-08 15:16:24 +03:00

191 lines
5.9 KiB
Python
Raw 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, update
from sqlalchemy.ext.asyncio import AsyncSession
from database.models import AIModel, AIProvider
from typing import Optional, List
# Дефолтная модель если в БД ничего нет
DEFAULT_MODEL = "gpt-4o-mini"
DEFAULT_PROVIDER = AIProvider.openai
class AIModelService:
"""Сервис для работы с AI моделями"""
@staticmethod
async def get_active_model(session: AsyncSession) -> Optional[AIModel]:
"""
Получить активную AI модель
Returns:
AIModel или None если нет активной модели
"""
result = await session.execute(
select(AIModel).where(AIModel.is_active == True)
)
return result.scalar_one_or_none()
@staticmethod
async def get_active_model_name(session: AsyncSession) -> str:
"""
Получить название активной модели
Returns:
Название модели (например "gpt-4o-mini") или дефолтное
"""
model = await AIModelService.get_active_model(session)
if model:
return model.model_name
return DEFAULT_MODEL
@staticmethod
async def get_active_provider(session: AsyncSession) -> AIProvider:
"""
Получить провайдера активной модели
Returns:
AIProvider (OPENAI или GOOGLE)
"""
model = await AIModelService.get_active_model(session)
if model:
return model.provider
return DEFAULT_PROVIDER
@staticmethod
async def get_all_models(session: AsyncSession) -> List[AIModel]:
"""
Получить все доступные модели
Returns:
Список всех моделей
"""
result = await session.execute(
select(AIModel).order_by(AIModel.provider, AIModel.model_name)
)
return list(result.scalars().all())
@staticmethod
async def set_active_model(session: AsyncSession, model_id: int) -> bool:
"""
Установить активную модель по ID
Args:
model_id: ID модели для активации
Returns:
True если успешно, False если модель не найдена
"""
# Проверяем существование модели
result = await session.execute(
select(AIModel).where(AIModel.id == model_id)
)
model = result.scalar_one_or_none()
if not model:
return False
# Деактивируем все модели
await session.execute(
update(AIModel).values(is_active=False)
)
# Активируем выбранную
model.is_active = True
await session.commit()
return True
@staticmethod
async def set_active_model_by_name(session: AsyncSession, model_name: str) -> bool:
"""
Установить активную модель по названию
Args:
model_name: Название модели (например "gpt-4o-mini")
Returns:
True если успешно, False если модель не найдена
"""
result = await session.execute(
select(AIModel).where(AIModel.model_name == model_name)
)
model = result.scalar_one_or_none()
if not model:
return False
# Деактивируем все модели
await session.execute(
update(AIModel).values(is_active=False)
)
# Активируем выбранную
model.is_active = True
await session.commit()
return True
@staticmethod
async def create_model(
session: AsyncSession,
provider: AIProvider,
model_name: str,
display_name: str,
is_active: bool = False
) -> AIModel:
"""
Создать новую модель
Args:
provider: Провайдер (OPENAI, GOOGLE)
model_name: Техническое название модели
display_name: Отображаемое название
is_active: Активна ли модель
Returns:
Созданная модель
"""
# Если активируем новую модель, деактивируем остальные
if is_active:
await session.execute(
update(AIModel).values(is_active=False)
)
model = AIModel(
provider=provider,
model_name=model_name,
display_name=display_name,
is_active=is_active
)
session.add(model)
await session.commit()
await session.refresh(model)
return model
@staticmethod
async def ensure_default_models(session: AsyncSession):
"""
Создать дефолтные модели если их нет в БД
"""
result = await session.execute(select(AIModel))
existing = list(result.scalars().all())
if existing:
return # Модели уже есть
# Создаём дефолтные модели
default_models = [
(AIProvider.openai, "gpt-4o-mini", "GPT-4o Mini", True),
(AIProvider.openai, "gpt-5-nano", "GPT-5 Nano", False),
(AIProvider.google, "gemini-2.5-flash-lite", "Gemini 2.5 Flash Lite", False),
]
for provider, name, display, active in default_models:
model = AIModel(
provider=provider,
model_name=name,
display_name=display,
is_active=active
)
session.add(model)
await session.commit()