"""Telegram-бот: текстовые и голосовые сообщения → LLM → ответ.""" import asyncio import logging import tempfile from pathlib import Path from aiogram import Bot, Dispatcher, F, Router from aiogram.types import Message import config from config import get_gitea_username from llm_handler import process_message from transcribe import transcribe_audio logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) config.validate() bot = Bot(token=config.TELEGRAM_BOT_TOKEN) dp = Dispatcher() router = Router() dp.include_router(router) @router.message(F.text) async def on_text(message: Message) -> None: text = (message.text or "").strip() if not text: return gitea_username = get_gitea_username( message.from_user.username if message.from_user else None, message.from_user.id if message.from_user else None, ) try: reply = await asyncio.wait_for(process_message(text, gitea_username), timeout=60.0) await message.answer(reply or "Готово.") except asyncio.TimeoutError: await message.answer("Таймаут. Попробуй короче или позже.") except Exception as e: logger.exception("Handler error") await message.answer(f"Ошибка: {e!s}") @router.message(F.voice) async def on_voice(message: Message) -> None: if not message.voice: return gitea_username = get_gitea_username( message.from_user.username if message.from_user else None, message.from_user.id if message.from_user else None, ) tmp = None try: file = await message.bot.get_file(message.voice.file_id) tmp = tempfile.NamedTemporaryFile(suffix=".ogg", delete=False) tmp.close() await message.bot.download_file(file.file_path, tmp.name) text = await asyncio.to_thread(transcribe_audio, tmp.name) Path(tmp.name).unlink(missing_ok=True) tmp = None if not (text or "").strip(): await message.answer("Не удалось распознать речь.") return reply = await asyncio.wait_for(process_message(text.strip(), gitea_username), timeout=60.0) await message.answer(reply or "Готово.") except asyncio.TimeoutError: await message.answer("Таймаут. Попробуй короче или позже.") except Exception as e: logger.exception("Voice handler error") await message.answer(f"Ошибка: {e!s}") finally: if tmp is not None and getattr(tmp, "name", None): Path(tmp.name).unlink(missing_ok=True) async def main() -> None: await dp.start_polling(bot) if __name__ == "__main__": asyncio.run(main())