models + refactor

This commit is contained in:
xds
2026-03-17 16:46:32 +03:00
parent e011805186
commit 14f9e7b7e9
15 changed files with 979 additions and 83 deletions

81
aiws.py
View File

@@ -23,6 +23,8 @@ from api.service.album_service import AlbumService
from middlewares.album import AlbumMiddleware
from middlewares.auth import AuthMiddleware
from middlewares.dao import DaoMiddleware
from scheduler.daily_scheduler import DailyScheduler
from scheduler.telegram_admin_handler import create_daily_scheduler_router
# Репозитории и DAO
from repos.char_repo import CharacterRepo
@@ -108,7 +110,7 @@ dp["gemini"] = gemini
# 1. Роутеры без мидлварей (например, auth)
dp.include_router(auth_router)
# 2. Основные роутеры
# 2. Основные роутеры (daily_scheduler router добавляется в lifespan)
main_router = Router()
dp.include_router(main_router)
dp.include_router(assets_router)
@@ -141,6 +143,34 @@ async def start_scheduler(service: GenerationService):
logger.error(f"Scheduler error: {e}")
await asyncio.sleep(60) # Check every 60 seconds
def _build_daily_scheduler() -> DailyScheduler:
"""Construct DailyScheduler; MetaAdapter is optional (needs env vars)."""
meta_adapter = None
if settings.META_ACCESS_TOKEN and settings.META_INSTAGRAM_ACCOUNT_ID:
from adapters.meta_adapter import MetaAdapter
meta_adapter = MetaAdapter(
access_token=settings.META_ACCESS_TOKEN,
instagram_account_id=settings.META_INSTAGRAM_ACCOUNT_ID,
)
logger.info("MetaAdapter initialized")
else:
logger.warning("META_ACCESS_TOKEN / META_INSTAGRAM_ACCOUNT_ID not set — Instagram publishing disabled")
if not settings.SCHEDULER_CHARACTER_ID:
logger.warning("SCHEDULER_CHARACTER_ID not set — daily scheduler will error at runtime")
return DailyScheduler(
dao=dao,
gemini=gemini,
s3_adapter=s3_adapter,
generation_service=generation_service,
bot=bot,
admin_id=ADMIN_ID,
character_id=settings.SCHEDULER_CHARACTER_ID or "",
meta_adapter=meta_adapter,
)
# --- LIFESPAN (Запуск FastAPI + Bot) ---
@asynccontextmanager
async def lifespan(app: FastAPI):
@@ -164,36 +194,39 @@ async def lifespan(app: FastAPI):
print("✅ DB & DAO initialized")
# 2. ЗАПУСК БОТА (в фоне)
# Важно: handle_signals=False, чтобы бот не перехватывал сигналы остановки у uvicorn
# Мы НЕ передаем сюда dao=..., так как он уже подключен через Middleware выше
# polling_task = asyncio.create_task(
# dp.start_polling(bot, handle_signals=False)
# )
# print("🤖 Bot polling started")
# 2. Инициализация и регистрация daily_scheduler роутера
daily_scheduler = _build_daily_scheduler()
dp.include_router(create_daily_scheduler_router(daily_scheduler))
print("📅 Daily scheduler router registered")
# 3. ЗАПУСК ШЕДУЛЕРА
# 3. ЗАПУСК БОТА (в фоне)
# handle_signals=False — бот не перехватывает сигналы остановки у uvicorn
polling_task = asyncio.create_task(
dp.start_polling(bot, handle_signals=False)
)
print("🤖 Bot polling started")
# 4. ЗАПУСК ШЕДУЛЕРОВ
scheduler_task = asyncio.create_task(start_scheduler(generation_service))
print("⏰ Scheduler started")
daily_scheduler_task = asyncio.create_task(daily_scheduler.run_loop())
print("⏰ Schedulers started")
yield
# --- SHUTDOWN ---
print("🛑 Shutting down...")
# 4. Остановка шедулера
scheduler_task.cancel()
try:
await scheduler_task
except asyncio.CancelledError:
print("⏰ Scheduler stopped")
# 3. Остановка бота
# polling_task.cancel()
# try:
# await polling_task
# except asyncio.CancelledError:
# print("🤖 Bot polling stopped")
# Останавливаем все фоновые задачи
for task, name in [
(polling_task, "Bot polling"),
(scheduler_task, "Stale-gen scheduler"),
(daily_scheduler_task, "Daily scheduler"),
]:
task.cancel()
try:
await task
except asyncio.CancelledError:
print(f"{name} stopped")
# 4. Отключение БД
# Обычно Motor закрывать не обязательно при выходе, но хорошим тоном считается