Initial commit: VoIdeaAI - voice-first AI idea assistant
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
"""Telegram bot command sync service.
|
||||
|
||||
Synchronises @bot_command-decorated handlers with BotCommand DB table
|
||||
and Telegram Bot API (set_my_commands) on boot or manual trigger.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import Any
|
||||
|
||||
from sqlalchemy import select, update
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.integrations.telegram.client import TelegramBotClient
|
||||
from app.integrations.telegram.decorators import get_registered_commands
|
||||
from app.models.bot_command import BotCommand
|
||||
|
||||
logger = logging.getLogger("voidea.telegram.sync")
|
||||
|
||||
|
||||
class TelegramBotSyncService:
|
||||
"""Syncs registered bot commands to DB and Telegram API."""
|
||||
|
||||
def __init__(self, db: AsyncSession, bot_client: TelegramBotClient | None = None):
|
||||
self.db = db
|
||||
self.bot_client = bot_client
|
||||
|
||||
async def sync_to_db(self) -> list[BotCommand]:
|
||||
"""Ensure all @bot_command handlers have matching BotCommand records."""
|
||||
registered = get_registered_commands()
|
||||
result = await self.db.execute(select(BotCommand))
|
||||
existing = {cmd.name: cmd for cmd in result.scalars().all()}
|
||||
|
||||
synced: list[BotCommand] = []
|
||||
|
||||
for reg in registered:
|
||||
if reg.name in existing:
|
||||
cmd = existing[reg.name]
|
||||
if cmd.description != reg.description or cmd.requires_auth != reg.requires_auth:
|
||||
cmd.description = reg.description
|
||||
cmd.requires_auth = reg.requires_auth
|
||||
synced.append(cmd)
|
||||
else:
|
||||
cmd = BotCommand(
|
||||
name=reg.name,
|
||||
description=reg.description,
|
||||
enabled=True,
|
||||
requires_auth=reg.requires_auth,
|
||||
)
|
||||
self.db.add(cmd)
|
||||
synced.append(cmd)
|
||||
|
||||
await self.db.commit()
|
||||
for cmd in synced:
|
||||
await self.db.refresh(cmd)
|
||||
|
||||
logger.info("Synced %d bot commands to DB", len(synced))
|
||||
return synced
|
||||
|
||||
async def sync_to_telegram(self) -> bool:
|
||||
"""Push enabled commands to Telegram Bot API via set_my_commands."""
|
||||
if not self.bot_client or not self.bot_client.available:
|
||||
logger.info("Telegram client not available — skipping set_my_commands")
|
||||
return False
|
||||
|
||||
result = await self.db.execute(
|
||||
select(BotCommand).where(BotCommand.enabled == True)
|
||||
)
|
||||
enabled = result.scalars().all()
|
||||
|
||||
commands = [
|
||||
{"command": cmd.name.lstrip("/"), "description": cmd.description}
|
||||
for cmd in enabled
|
||||
]
|
||||
|
||||
ok = await self.bot_client.set_commands(commands)
|
||||
if ok:
|
||||
logger.info("Pushed %d commands to Telegram", len(commands))
|
||||
else:
|
||||
logger.warning("Failed to push commands to Telegram")
|
||||
return ok
|
||||
|
||||
async def full_sync(self) -> dict[str, Any]:
|
||||
"""Run full sync: DB → Telegram."""
|
||||
synced = await self.sync_to_db()
|
||||
telegram_ok = await self.sync_to_telegram()
|
||||
return {
|
||||
"synced_count": len(synced),
|
||||
"telegram_sync": telegram_ok,
|
||||
}
|
||||
Reference in New Issue
Block a user