t2sTelegramBot/ARCHITECTURE.md

7.5 KiB
Raw Permalink Blame History

Архитектура сервиса T2S Telegram Bot

Описание

Сервис реализует двухбота — один для пользователей (озвучка текста в голос), второй для администратора (логи и копии озвучек). Оба бота запускаются в одном Docker-контейнере в рамках одного asyncio-процесса.

Компоненты

┌─────────────────────────────────────────────────────┐
│                   Docker Container                  │
│  ┌──────────────────────────────────────────────┐  │
│  │            Python 3.12 процесс               │  │
│  │                                               │  │
│  │  ┌─────────────────┐  ┌─────────────────┐    │  │
│  │  │  User Bot App   │  │  Admin Bot App  │    │  │
│  │  │  (Application)  │  │  (Application)  │    │  │
│  │  │                 │  │                 │    │  │
│  │  │  Token:         │  │  Token:         │    │  │
│  │  │  USER_BOT_TOKEN │  │  ADMIN_BOT_TOKEN│    │  │
│  │  └───────┬─────────┘  └────────┬────────┘    │  │
│  │          │                      │              │  │
│  │          │    Admin Bot         │              │  │
│  │          │    Instance          │              │  │
│  │          └──────┬───────────────┘              │  │
│  │                 │  (Bot token=ADMIN_BOT_TOKEN)  │  │
│  │                 ▼                               │  │
│  │  ┌────────────────────────────┐                │  │
│  │  │     edge-tts (TTS)         │                │  │
│  │  │  Microsoft TTS Service     │                │  │
│  │  │  via websocket/HTTP        │                │  │
│  │  │  Voice: ru-RU-DmitryNeural │                │  │
│  │  └────────────────────────────┘                │  │
│  └──────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────┘

Потоки данных

Пользовательский поток

Пользователь ──текст──▶ User Bot App ──TTS──▶ edge-tts
                                                   │
              User Bot App ◀──audio.ogg────────────┘
                   │
              голосовое сообщение
                   │
                   ▼
              Пользователь

Администраторский поток

User Bot App ──текст + user info──▶ Admin Bot (прямой Bot-клиент)
                                        │
                                   голосовое + подпись
                                        │
                                        ▼
                                   Администратор

Детали реализации

bot.py — точка входа

async def main():
    admin_app = Application.builder().token(ADMIN_TOKEN).build()
    user_app = Application.builder().token(USER_TOKEN).build()
    # Оба запускаются внутри вложенных async with

Ключевые решения:

  1. Один процесс — два Application внутри вложенных async with. Это позволяет разделять память (переменная admin_chat_id) и не усложнять инфраструктуру.

  2. Отдельный Bot-клиент для админаadmin_bot = Bot(token=ADMIN_TOKEN) создаётся как экземпляр telegram.Bot, а не Application. Это лёгкий HTTP-клиент для отправки сообщений без полного цикла поллинга.

  3. Временные файлы — TTS генерируется в NamedTemporaryFile(suffix='.ogg'), файл открывается для чтения, отправляется, затем удаляется в finally. Никакого накопления мусора.

Озвучка (edge-tts)

  • Библиотека edge-tts эмулирует запрос к Microsoft Edge TTS API
  • Не требует API-ключа, бесплатно
  • Голос кешируется при первом вызове (скачивается в ~/.cache/edge-tts/)
  • Формат вывода — Ogg Opus (нативно поддерживается Telegram как голосовое сообщение)
  • Асинхронный вызов: await edge_tts.Communicate(text, voice).save(path)

Telegram Bot API

  • Используется python-telegram-bot v21+ (синтаксис Application, async with)
  • Long-polling (без webhook — не требует публичного HTTPS-адреса)
  • send_action(action='record_voice') показывает индикатор "запись голоса"

Обработка ошибок

Сценарий Реакция
edge-tts недоступен Исключение в communicate.save() → ошибка в лог
Админ не запустил /start admin_chat_id is None → лог warning + без уведомления
Ошибка отправки админу try/except → лог error, пользователь всё равно получает ответ
Временный файл не удалился try/unlink в finally — silent ignore

Сетевая модель

Container ──443/tcp──▶ api.telegram.org  (боты)
Container ──443/tcp──▶ speech.microsoft.com  (edge-tts)

Исходящие HTTPS-соединения. Входящих нет — только long-polling к Telegram API.

Зависимости

  • python:3.12-slim — base image (~130 MB)
  • python-telegram-bot >=21, <22 — Telegram API
  • edge-tts >=6, <7 — Microsoft TTS
  • httpx — HTTP-клиент PTB
  • aiohttp — HTTP-клиент edge-tts

Конфигурация

Вся конфигурация через переменные окружения (файл .env):

USER_BOT_TOKEN=***       # Токен пользовательского бота (Telegram BotFather)
ADMIN_BOT_TOKEN=***      # Токен админского бота
TTS_VOICE=ru-RU-DmitryNeural  # Голос edge-tts (опционально)

Docker

# docker-compose.yml
services:
  t2s:
    build: ./app
    container_name: t2s-telegram-bot
    restart: always
    env_file: .env

Сборка при заблокированном Docker Hub:

DOCKER_BUILDKIT=0 docker build --network=host -t t2s-telegram-bot ./app