Почему Telegram, а не свой фронтенд
Telegram — лучший UI для персональной автоматизации и большинства внутренних инструментов. Причины простые: приложение уже стоит на телефоне, не нужно делать авторизацию, push-уведомления работают из коробки, поддерживаются кнопки и структурированные ответы.
Альтернатива — веб-интерфейс или мобильное приложение — требует в разы больше работы и поддержки. Для инструментов, которыми пользуется один-два человека, это оверинжиниринг.
Polling vs Webhook
Polling — бот сам периодически спрашивает Telegram API: «есть новые сообщения?» Просто в реализации, работает за NAT, не нужен публичный IP. Недостаток: задержка (обычно 1–3 секунды) и лишние запросы.
Webhook — Telegram сам отправляет сообщения на ваш сервер при поступлении. Нужен HTTPS-эндпоинт с валидным SSL (Let's Encrypt подходит). Задержка минимальная, нагрузка меньше. Это предпочтительный вариант для production.
# Регистрация webhook (curl)
curl -F "url=https://example.com/bot/webhook" \
https://api.telegram.org/bot{TOKEN}/setWebhook
# Проверка
curl https://api.telegram.org/bot{TOKEN}/getWebhookInfo
# Удаление webhook (вернуться к polling)
curl https://api.telegram.org/bot{TOKEN}/deleteWebhook
Выбор библиотеки
Две основные библиотеки для Python:
python-telegram-bot — классика, богатая документация, синхронный и асинхронный режимы. Хороший выбор для начала. Версия 20+ полностью асинхронная.
aiogram — чисто асинхронная, более идиоматична для asyncio, лучше подходит для высоконагруженных ботов. Синтаксис с декораторами и роутерами удобен для сложной логики.
# Установка aiogram 3.x
pip install aiogram
# Установка python-telegram-bot 20+
pip install python-telegram-bot
Структура бота-инструмента на aiogram
Минимальная структура, которая не превращается в спагетти при росте:
project/
bot.py # точка входа, запуск
config.py # токен, допустимые user_id, настройки
handlers/
__init__.py
commands.py # /start, /help и т.д.
messages.py # обработка текста
callbacks.py # нажатия на инлайн-кнопки
services/
__init__.py
my_service.py # бизнес-логика отдельно от хендлеров
keyboards/
__init__.py
inline.py # построение клавиатур
# bot.py
import asyncio
from aiogram import Bot, Dispatcher
from aiogram.fsm.storage.memory import MemoryStorage
from config import TOKEN
from handlers import commands, messages
async def main():
bot = Bot(token=TOKEN)
dp = Dispatcher(storage=MemoryStorage())
dp.include_router(commands.router)
dp.include_router(messages.router)
# Удалить старые апдейты при старте
await bot.delete_webhook(drop_pending_updates=True)
await dp.start_polling(bot)
if __name__ == "__main__":
asyncio.run(main())
# handlers/commands.py
from aiogram import Router
from aiogram.filters import Command
from aiogram.types import Message
from config import ALLOWED_USERS
router = Router()
# Фильтр по user_id — обязательно для личных инструментов
def is_allowed(message: Message) -> bool:
return message.from_user.id in ALLOWED_USERS
@router.message(Command("start"))
async def cmd_start(message: Message):
if not is_allowed(message):
return
await message.answer(
"Готов к работе.\n\n"
"/status — статус сервисов\n"
"/logs — последние логи\n"
"/deploy — деплой"
)
Инлайн-кнопки и callback
# keyboards/inline.py
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton
from aiogram.utils.keyboard import InlineKeyboardBuilder
def confirm_keyboard(action: str, item_id: str) -> InlineKeyboardMarkup:
builder = InlineKeyboardBuilder()
builder.button(text="✓ Подтвердить", callback_data=f"confirm:{action}:{item_id}")
builder.button(text="✗ Отмена", callback_data="cancel")
builder.adjust(2)
return builder.as_markup()
# handlers/callbacks.py
from aiogram import Router, F
from aiogram.types import CallbackQuery
router = Router()
@router.callback_query(F.data.startswith("confirm:"))
async def handle_confirm(callback: CallbackQuery):
_, action, item_id = callback.data.split(":", 2)
# выполнить действие...
await callback.answer("Выполнено")
await callback.message.edit_text(f"Действие {action} выполнено для {item_id}")
Отправка уведомлений без ответа на сообщение
Боты часто используются для push-уведомлений из других систем: мониторинг упал, деплой завершился, задача выполнена. Для этого нужен только токен и chat_id:
import httpx
async def send_alert(token: str, chat_id: int, text: str):
url = f"https://api.telegram.org/bot{token}/sendMessage"
async with httpx.AsyncClient() as client:
await client.post(url, json={
"chat_id": chat_id,
"text": text,
"parse_mode": "HTML"
})
# Использование из любого места:
await send_alert(TOKEN, MY_CHAT_ID, "⚠️ Сервис упал: api.example.com")
Типичные применения
- Мониторинг серверов. Бот получает алерты от Grafana или собственного скрипта и присылает в чат с кнопками «перезапустить» или «посмотреть логи».
- Управление задачами. Отправить задачу боту, бот добавляет в список и напоминает в нужное время.
- Голосовой ввод. Бот принимает голосовые сообщения, транскрибирует через Whisper, обрабатывает текст и выполняет команды.
- Деплой по команде.
/deploy production— бот запускает CI/CD пайплайн и сообщает о результате. - Ежедневные отчёты. По cron задаче бот собирает метрики и присылает сводку.
Запуск через systemd
# /etc/systemd/system/mybot.service
[Unit]
Description=My Telegram Bot
After=network.target
[Service]
Type=simple
User=botuser
WorkingDirectory=/opt/mybot
ExecStart=/opt/mybot/venv/bin/python bot.py
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
systemctl enable mybot
systemctl start mybot
journalctl -u mybot -f # логи в реальном времени