258 lines
13 KiB
Markdown
258 lines
13 KiB
Markdown
<div align="center">
|
||
|
||
# 🤖 UMB — Telegram Bot
|
||
|
||
**Универсальный бот-модератор с AI-ассистентом "Астра"**
|
||
|
||
[](LICENSE)
|
||
[](https://www.python.org/)
|
||
[](https://docs.aiogram.dev/)
|
||
[](https://www.sqlite.org/)
|
||
[](https://www.docker.com/)
|
||
[](tests/)
|
||
[](#настройка)
|
||
|
||
</div>
|
||
|
||
---
|
||
|
||
UMB — это Telegram-бот для модерации стикеров/GIF, восстановления раскладки, получения погоды и общения с AI-ассистентом **Астра**.
|
||
|
||
## ✨ Функции
|
||
|
||
- **🛡️ Модерация стикеров и GIF** — если пользователь отправляет 25+ стикеров/GIF за 60 секунд, бот удаляет все последующие стикеры и GIF от этого пользователя в течение 5 минут. Текстовые сообщения не затрагиваются.
|
||
- **⌨️ Восстановление раскладки (`/res`)** — ответьте командой `/res` на сообщение с текстом в неправильной раскладке, и бот переведёт его (например, `gbdj` → `пиво`).
|
||
- **🌤️ Погода (`/weather`)** — покажет подробную погоду в указанном городе через OpenWeatherMap API.
|
||
- **🤖 AI-ассистент "Астра" (`/ai`)** — задайте вопрос, ответьте командой `/ai` на сообщение или перешлите сообщение, и Astra проанализирует его с учётом контекста и ранее сохранённых выжимок диалогов.
|
||
- **💬 Диалог с Астрой** — после `/ai` без вопроса начинается диалог. Отвечайте на сообщения бота, чтобы продолжать.
|
||
- Фаза 1: до 50 сообщений.
|
||
- Фаза 2: дополнительно до 20 сообщений.
|
||
- После исчерпания лимита — перерыв 1 час.
|
||
- **🔒 Управление AI (`/aino`, `/aiyes`)** — владелец чата может заблокировать/разблокировать пользователя от AI.
|
||
- **🧦 Поддержка SOCKS5 прокси** — настраивается через `.env`.
|
||
|
||
## 🏗️ Структура проекта
|
||
|
||
```
|
||
umb/
|
||
├── .env # настройки: токен, прокси, API ключи
|
||
├── .gitignore
|
||
├── requirements.txt
|
||
├── main.py # точка входа
|
||
├── config.py # конфигурация
|
||
├── Dockerfile
|
||
├── docker-compose.yml
|
||
└── bot/
|
||
├── __init__.py
|
||
├── bot.py # инициализация бота и сессии
|
||
├── setup_commands.py # меню команд
|
||
├── routers/
|
||
│ ├── __init__.py
|
||
│ ├── moderation.py # роутер модерации стикеров/GIF
|
||
│ ├── layout.py # роутер /start, /res
|
||
│ ├── weather.py # роутер /weather
|
||
│ ├── ai.py # роутер /ai, /aino, /aiyes, /aiclear, /aiuser
|
||
│ ├── dialogue.py # диалоговый режим с Астрой
|
||
│ ├── voice.py # распознавание голосовых сообщений
|
||
│ └── yadisk.py # скачивание с Яндекс.Диска
|
||
└── utils/
|
||
├── __init__.py
|
||
├── proxy.py # общий SOCKS5-коннектор
|
||
├── layout_converter.py # конвертер раскладки en→ru
|
||
├── weather.py # функция получения погоды
|
||
├── ai_client.py # OpenRouter/RouterAI клиент
|
||
├── memory.py # саммари и эмбеддинги
|
||
├── database.py # SQLAlchemy модели и функции БД
|
||
├── voice.py # загрузка и транскрибация голоса
|
||
├── yadisk_download.py # загрузка файлов с Яндекс.Диска
|
||
├── s3_client.py # загрузка больших файлов в S3
|
||
└── logging_config.py # настройка логирования
|
||
```
|
||
|
||
## 📊 Системные требования
|
||
|
||
### Память (RAM)
|
||
|
||
| Компонент | Расход |
|
||
|-----------|--------|
|
||
| Whisper `base` (int8) в памяти | ~600–900 МБ |
|
||
| Whisper пик при транскрибации | дополнительно ~200–400 МБ |
|
||
| aiogram + SQLAlchemy + aiohttp | ~100–200 МБ |
|
||
| SQLite | ~10–50 МБ |
|
||
| ffmpeg (пиково) | ~50–100 МБ |
|
||
| **Рекомендуемый минимум** | **2 ГБ** |
|
||
| **Без распознавания голоса** | **~512 МБ** |
|
||
|
||
### Процессор
|
||
|
||
| Параметр | Значение |
|
||
|----------|----------|
|
||
| Количество ядер | минимум 2, рекомендовано **4+** |
|
||
| Нагрузка при транскрибации | ~80–100% на 4 ядрах на 2–8 сек |
|
||
| Нагрузка в простое | ~1–5% |
|
||
| Архитектура | x86_64 / ARM64 |
|
||
|
||
> Без голосовых сообщений достаточно **1 ядра**.
|
||
|
||
### Диск
|
||
|
||
| Данные | Размер |
|
||
|--------|--------|
|
||
| Whisper `base` модель | ~500 МБ на диске |
|
||
| SQLite база | ~50–200 МБ (растёт со временем) |
|
||
| Голосовые файлы (временно) | ~1–5 МБ на сообщение, удаляются сразу |
|
||
| Логи (ротация 5×10 МБ) | ~50–100 МБ |
|
||
| **Рекомендуемое свободное место** | **5–10 ГБ** |
|
||
|
||
### Сеть
|
||
|
||
- Пропускная способность: минимальная (несколько КБ/с в среднем).
|
||
- Все API-запросы могут идти через SOCKS5-прокси.
|
||
- Для скачивания Whisper-модели через прокси: ~150 МБ одним файлом, нужна стабильность.
|
||
|
||
### Итого
|
||
|
||
| Ресурс | Минимум | Рекомендовано |
|
||
|--------|---------|---------------|
|
||
| **RAM** | 2 ГБ | 4 ГБ |
|
||
| **CPU** | 2 ядра | 4+ ядра |
|
||
| **Disk** | 5 ГБ | 10 ГБ |
|
||
| **ОС** | Linux (x86_64) | то же, Python 3.11 |
|
||
|
||
## 🚀 Установка
|
||
|
||
```bash
|
||
cd umb
|
||
python3 -m venv .venv
|
||
source .venv/bin/activate
|
||
pip install -r requirements.txt
|
||
```
|
||
|
||
## ⚙️ Настройка
|
||
|
||
Откройте `.env` и укажите необходимые ключи:
|
||
|
||
```env
|
||
BOT_TOKEN=your_bot_token_here
|
||
PROXY_ENABLED=false
|
||
PROXY_URL=socks5://user:pass@host:port
|
||
API_WEATHER=your_openweather_api_key
|
||
OPENROUTER_API_KEY=your_openrouter_api_key
|
||
ROUTERAI_API_KEY=your_routerai_api_key
|
||
ROUTERAI_BASE_URL=https://routerai.ru/api/v1
|
||
|
||
# Опционально: периодическая проверка работоспособности бесплатных моделей.
|
||
# Внимание: проверка расходует токены API. По умолчанию отключена.
|
||
AI_HEALTH_CHECK_ENABLED=false
|
||
AI_HEALTH_CHECK_INTERVAL=600
|
||
|
||
# Настройки модели Whisper для распознавания голоса.
|
||
WHISPER_MODEL_SIZE=base
|
||
WHISPER_MIN_FREE_SPACE_BYTES=5368709120
|
||
```
|
||
|
||
Для включения прокси установите `PROXY_ENABLED=true` и укажите корректный `PROXY_URL`.
|
||
|
||
## ▶️ Запуск
|
||
|
||
```bash
|
||
source .venv/bin/activate
|
||
python main.py
|
||
```
|
||
|
||
## 🐳 Запуск в Docker
|
||
|
||
```bash
|
||
docker compose up -d --build
|
||
```
|
||
|
||
Модели Whisper сохраняются в `./models`, база данных и логи — в `./bot/data`.
|
||
|
||
## 🎙️ Распознавание голосовых сообщений
|
||
|
||
Бот автоматически распознаёт все голосовые сообщения с помощью локальной модели [faster-whisper](https://github.com/SYSTRAN/faster-whisper).
|
||
|
||
### Поведение загрузки модели
|
||
|
||
- При запуске бота проверяется наличие модели в `./models/faster-whisper/<WHISPER_MODEL_SIZE>/`.
|
||
- Если модель уже скачана — бот сразу готов к работе.
|
||
- Если модели нет — бот проверяет свободное место на диске и **скачивает модель автоматически** перед началом polling.
|
||
- Для скачивания используется прокси из `.env`, если `PROXY_ENABLED=true`.
|
||
|
||
### Требования к месту
|
||
|
||
| Модель | Размер модели | Рекомендуемое свободное место |
|
||
|--------|---------------|-------------------------------|
|
||
| `base` | ~150 MB архив, ~500 MB на диске | 5 GB (`WHISPER_MIN_FREE_SPACE_BYTES=5368709120`) |
|
||
| `small` | ~500 MB архив, ~1.5 GB на диске | 5 GB+ |
|
||
| `medium` | ~1.5 GB архив, ~5 GB на диске | 10 GB+ |
|
||
|
||
> 💡 По умолчанию используется модель `base`. Для смены модели измените `WHISPER_MODEL_SIZE` в `.env`.
|
||
|
||
### Логирование
|
||
|
||
В логах будет видно:
|
||
|
||
```
|
||
Free disk space: 45.23 GB, required: 5.00 GB
|
||
Whisper model 'base' found locally at /app/models/faster-whisper/base
|
||
Whisper model 'base' is ready
|
||
```
|
||
|
||
или при скачивании:
|
||
|
||
```
|
||
Whisper model 'base' not found locally. Starting download to /app/models/faster-whisper...
|
||
Whisper model 'base' downloaded and loaded in 125.4s
|
||
Whisper model 'base' is ready
|
||
```
|
||
|
||
## 🧪 Тесты
|
||
|
||
```bash
|
||
source .venv/bin/activate
|
||
pytest tests/ -v
|
||
```
|
||
|
||
## 📋 Команды
|
||
|
||
| Команда | Описание |
|
||
|---------|----------|
|
||
| `/start` | Приветствие и информация о боте |
|
||
| `/res` | Восстановить раскладку (ответить на сообщение) |
|
||
| `/weather <город>` | Погода в указанном городе |
|
||
| `/ai <вопрос>` | Задать вопрос Астре |
|
||
| `/ai` (ответом/пересылкой) | Проанализировать сообщение |
|
||
| `/ai` (без вопроса) | Начать диалоговый режим |
|
||
| `/aiclear` | Очистить диалог и сохранить выжимку |
|
||
| `/aiuser` | Список пользователей чата (только creator) |
|
||
| `/aino @username` | Заблокировать пользователя от AI (только creator, 24ч) |
|
||
| `/aiyes @username` | Разблокировать пользователя от AI (только creator) |
|
||
| `/ydf <ссылка>` | Скачать файл с Яндекс.Диска |
|
||
| `/ydf (new) <ссылка>` | Скачать файл, игнорируя кеш Telegram |
|
||
|
||
## ⚖️ Настройки модерации
|
||
|
||
Изменяются в `config.py`:
|
||
|
||
- `MODERATION_LIMIT = 25` — количество стикеров/GIF за окно
|
||
- `MODERATION_WINDOW = 60` — окно подсчёта в секундах
|
||
- `MODERATION_BAN_DURATION = 300` — длительность бана в секундах
|
||
|
||
## 🧠 AI-ассистент "Астра"
|
||
|
||
- **Бесплатные модели** (OpenRouter): пробует по очереди доступные модели с суффиксом `:free`. При rate-limit автоматически переключается на следующую.
|
||
- **Платный fallback** (RouterAI): если все бесплатные модели недоступны, используется `deepseek/deepseek-v4-flash` через `routerai.ru`. В ответе добавляется уведомление `⚡ Обработано через платный API`.
|
||
- **Контекст**: хранит последние 10 сообщений каждого пользователя в SQLite.
|
||
- **Долгосрочная память**: при переходе между фазами диалога и при `/aiclear` создаётся краткая выжимка, которая затем подбирается по смыслу к новым вопросам.
|
||
- **Стиль**: отвечает кратко и по делу, если не просят развёрнуто.
|
||
- **Потеря контекста**: говорит что-то милое ("я потеряла мысль", "смотри, какая птичка!")
|
||
|
||
---
|
||
|
||
<div align="center">
|
||
|
||
Сделано с помощью [aiogram](https://docs.aiogram.dev/) · [SQLAlchemy](https://www.sqlalchemy.org/) · [faster-whisper](https://github.com/SYSTRAN/faster-whisper)
|
||
|
||
</div>
|