Telegram и Discord бот с поддержкой генерации текста через OpenRouter или OpenClaw OAuth (Codex) и изображений через PiAPI.ai.
- Генерация изображений
- Обработка кастомных промптов
- Память контекста для последних сообщений
- Получение списка моделей
- Загрузка списка моделей в бота, чтобы к ним можно было обращаться
- Работа в групповых чатах
- LLM-роутинг с подтверждением действий через
/yes - Пагинация
/models_freeи выбор текстовой модели через/set_text_model
Список задач вынесен в todo.md.
- Переключение для конкретного пользователя в чате: отправьте текстом «роутинг алгоритмами» или «роутинг ллм».
- Аналогичные слеш-команды:
/rout_algo,/rout_llm,/routдля просмотра текущего режима. - По умолчанию используется режим из конфигурации, но пользовательский выбор сохраняется в настройках.
- В режиме LLM бот сообщает о запросе к роутеру и предлагает подтвердить действие командой
/yes.
/models_free— список бесплатных моделей с пагинацией (кнопки)./set_text_model <номер>— закрепить модель генерации текста для пользователя в чате./models_picи/set_pic_model <номер>— список и выбор модели генерации изображений.
- Перед отправкой запроса на OpenRouter бот оценивает примерный объем контекста (символы/токены) с учетом системных сообщений, истории и текущего запроса. Лимит берется из витрины моделей
MODEL_CATALOGили изCONTEXT_GUARD.DEFAULT_CONTEXT_LENGTH. - При заполнении более
CONTEXT_GUARD.WARNING_RATIOотправляется предупреждение пользователю, а при достиженииHARD_RATIOбот скрывает самые старые сообщения из запроса и, при необходимости, делает краткую саммари переполненных частей (стратегияOVERFLOW_STRATEGY). Исходная история в БД не меняется, саммари складываются вsummaries. - Настройки порога и стратегии находятся в
config.py(CONTEXT_GUARD): можно выбратьtruncateилиsummarize, указать модель для саммаризации и лимиты токенов. Логи фиксируют срабатывание механизма и добавление саммари.
- Раздел
INSTRUCTION_SETTINGSвconfig.pyрезервирует настройки для двух типов инструкций: пользовательские подсказки (от самого пользователя для конкретного чата) и заметки администратора о пользователях. Пока функциональность не реализована, но можно управлять включением и максимальной длиной заранее.
NeiroTolikBot/
├── handlers/ # Обработчики команд и сообщений
│ ├── commands.py # Обработчики команд (например, /start)
│ ├── messages.py # Обработчики сообщений Telegram
│ └── message_service.py # Общая бизнес-логика для всех платформ
├── services/ # Сервисы генерации и другие сервисы
│ ├── generation.py # Функции для генерации текста и изображений
│ ├── memory.py # Управление памятью и контекстом диалогов
│ └── consilium.py # Функционал консилиума (параллельные запросы к моделям)
├── utils/ # Вспомогательные функции
│ └── helpers.py # Утилиты (экранирование, инициализация)
├── config.py # Конфигурация бота
├── tbot.py # Основной файл Telegram-бота
├── discord_bot.py # Основной файл Discord-бота
├── .env # Переменные окружения
└── README.md # Документация
⚠️ Рекомендуется работать в виртуальном окружении, чтобы не трогать системный Python.
- Клонируйте репозиторий
- Создайте и активируйте виртуальное окружение:
cd NeiroTolikBot python3 -m venv venv source venv/bin/activate
- Установите зависимости:
pip install -r requirements.txt
- Создайте файл
.envсо следующими переменными:TELEGRAM_BOT_TOKEN=ваш_токен_бота DISCORD_BOT_TOKEN=ваш_discord_бот_token OPENROUTER_API_KEY=ваш_ключ_openrouter # Альтернатива OpenRouter для текста: OpenClaw OAuth OPENCLAW_OAUTH_ENABLED=1 OPENCLAW_BASE_URL=https://de.hohohosting.ru:18789 OPENCLAW_GATEWAY_TOKEN=ваш_gateway_token OPENCLAW_MODEL=openclaw:main PIAPI_KEY=ваш_ключ_piapi (опционально) CUSTOM_SYSTEM_PROMPT=ваш_промпт (опционально) # или можно указать файл: CUSTOM_SYSTEM_PROMPT_FILE=neiro-tolik-promt.txt - Запустите бота:
python tbot.py
- Создайте Discord-приложение и бота в Developer Portal.
- На вкладке Bot включите привилегированные интенты:
MESSAGE CONTENT INTENT(для чтения текста),SERVER MEMBERS INTENTне требуется, но оставьте включеннымиMESSAGE CONTENTи базовыеGUILD/MESSAGE. - Скопируйте токен бота и пропишите его в
.envкакDISCORD_BOT_TOKEN=<ваш_токен>вместе сOPENROUTER_API_KEY. - Добавьте бота на сервер: вкладка OAuth2 → URL Generator, отметьте
botиapplications.commands, дайте праваSend Messages/Read Message History, перейдите по сгенерированной ссылке. - Запустите Discord-бота отдельной точкой входа:
python discord_bot.py
- Поведение в Discord:
- бот игнорирует собственные сообщения;
- в серверах отвечает только на упоминание
@ИмяБотаили сообщения с префиксами!//; - в личных сообщениях отвечает на любой текст;
- доступны команды
!start//startи!help//help.
Команды Discord:
/start— подсказка по использованию/help— справка по командам/join— подключиться к голосовому каналу, где вы сейчас/leave— выйти из голосового канала/autojoin_on— включить автоподключение к голосу/autojoin_off— отключить автоподключение к голосу
Голосовые сообщения:
- Telegram голосовые распознаются через OpenAI Whisper (нужен
OPENAI_API_KEY). - В Discord можно присылать аудио-вложения (.ogg/.mp3/.wav/.m4a) — бот распознает и отвечает.
- Для локального Whisper можно указать
VOICE_LOCAL_WHISPER_URL(по умолчаниюhttp://127.0.0.1:8000/transcribe). - Режимы отправки в STT:
raw(целый файл) иsegmented(кусочки по паузам речи). Переключаются командами/voice_send_rawи/voice_send_segmented. - Жёсткий лимит файла для STT: 25 MB.
- TTS в Discord: команда
/say <текст>озвучивает текст в голосовом канале автора (нуженOPENAI_API_KEYиffmpeg).
Приглашение Discord-бота:
- OAuth2 ссылка для добавления бота на сервер доступна через администратора.
Команды Telegram (админ):
/flow— показать текущие связи Discord → Telegram/setflow— выбрать связь Discord → Telegram (без аргументов покажет списки; пример:/setflow 2 C)/unsetflow— удалить связь (без аргументов покажет список с римскими цифрами; пример:/unsetflow ii)/user_profile [chat_id] <user_id>— показать профиль пользователя (админ)/models_voice— список моделей распознавания речи/set_voice_model <номер>— выбрать модель распознавания речи/voice_send_raw— слать аудио целиком, без нарезки (дороже, лимит 25MB)/voice_send_segmented— слать аудио кусками по паузам речи (лимит 25MB)/say <текст>— озвучить текст и отправить голосовуху (TTS)/tts_voices— список голосов TTS/set_tts_voice <номер>— выбрать голос TTS
В репозитории уже есть файл neirotolikbot.service (на сервере de используется Docker).
sudo cp neirotolikbot.service /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable neirotolikbot.service
sudo systemctl start neirotolikbot.serviceЛоги: sudo journalctl -u neirotolikbot.service -f
Бот запускается в одном контейнере через start-bot.sh (внутри поднимаются tbot.py и discord_bot.py).
-
Постройте образ и запустите через Docker Compose (в
docker-compose.ymlлимит памяти 1 GB):docker-compose up --build -d
-
Перезапуск контейнера:
docker-compose restart
-
Или запустите вручную, задав ограничение по памяти:
docker build -t neirotolikbot . docker run --rm -d --env-file .env --memory=150m --name neirotolikbot neirotolikbot
Через переменные окружения можно управлять дополнительными настройками для экономии ресурсов:
UPDATE_QUEUE_MAXSIZE— максимальный размер очереди обновлений (по умолчанию 50)MAX_CONCURRENT_UPDATES— максимальное число одновременно обрабатываемых обновлений (по умолчанию 2)
Для автопроверки STT добавлен отдельный тестовый Discord-бот voice_test_sender.
Он заходит в заданный voice-канал, проигрывает .wav-файл и выходит. После этого раннер проверяет свежие записи в data/memory.db (voice_logs) и печатает PASS/FAIL.
По умолчанию sender запускается локально (через .venv/bin/python, если есть), без Docker-сети.
- Добавьте в
.env:DISCORD_TEST_BOT_TOKEN=... DISCORD_TEST_GUILD_ID=123456789012345678 DISCORD_TEST_CHANNEL_ID=123456789012345678
- Убедитесь, что локальный
piperдоступен наhttp://127.0.0.1:8001/tts(или передайте--piper-url). - Запуск:
./scripts/run_voice_regression.sh
- Ручной запуск:
python3 tests/voice/run_voice_regression.py --generate-fixtures
Файлы:
tests/voice/cases.json— сценарии, эталонные фразы, таймаутыtests/voice/generate_fixtures.py— генерация.wavфикстур через локальный pipertests/voice/run_voice_regression.py— проигрывание + SQL-проверка результатаtools/voice_test_sender/send_voice.py— одноразовый плеер в Discord voice
Talker может непрерывно озвучивать анекдоты в voice-канале:
- каждый следующий анекдот новый;
- при исчерпании базы автоматически генерируются новые;
- стиль голоса чередуется:
male -> female.
Запуск:
./scripts/run_talker_jokes.shОграничить количество анекдотов (для прогона):
./scripts/run_talker_jokes.sh --max-jokes 8Файлы:
tools/voice_test_sender/talker_joker.py— runtime Talkertools/voice_test_sender/data/talker_jokes_seed.json— стартовая база анекдотовdata/talker_jokes_db.json— рабочая база (автодополняется)data/talker_jokes_state.json— позиция в базе
В проекте есть простой механизм CI/CD, который подтягивает изменения из GitHub и перезапускает бота после каждого push в main/master.
webhook_server.py— небольшой Flask-сервер, принимающий webhook от GitHubdeploy.sh— скрипт, который:- делает
git pull - определяет, запущен бот через systemd или Docker
- перезапускает нужный сервис/контейнер
- делает
webhook.service— пример systemd-сервиса для webhook-сервера
-
Переменные окружения (добавьте в
.env):GITHUB_WEBHOOK_SECRET=случайная_строка_из_32_символов WEBHOOK_PORT=5000 WEBHOOK_HOST=0.0.0.0Сгенерировать секрет:
python3 -c "import secrets; print(secrets.token_urlsafe(32))" -
Убедитесь, что зависимости установлены (см. раздел «Установка и запуск»).
-
Запустите webhook-сервер как сервис:
sudo cp webhook.service /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable webhook.service sudo systemctl start webhook.service sudo journalctl -u webhook.service -f # проверки
-
Настройте GitHub Webhook:
- GitHub → Settings → Webhooks → Add webhook
- Payload URL:
http(s)://ВАШ_СЕРВЕР:5000/webhook - Content type:
application/json - Secret: то же значение, что
GITHUB_WEBHOOK_SECRET - Events: Just the push event
-
Пробросьте порт:
- откройте 5000/TCP в файрволе (
sudo ufw allow 5000/tcp) - либо повесьте nginx/Cloudflare/ngrok поверх сервиса
- откройте 5000/TCP в файрволе (
-
Тест: в настройках webhook нажмите «Redeliver» или сделайте тестовый push.
- GitHub присылает запрос на
/webhook webhook_server.pyпроверяет подпись и запускаетdeploy.sh- Скрипт определяет окружение:
- если поднят Docker (
docker-compose.yml), пересобирает и перезапускает контейнер - иначе перезапускает
neirotolikbot.service - если ничего из перечисленного не найдено — только делает
git pull
- если поднят Docker (
- Бот обновляется до последнего коммита
- Генерация текста через различные модели (ChatGPT, Claude, DeepSeek)
- Генерация изображений через PiAPI.ai
- Работа в группах (требуется упоминание бота или ответ на сообщение бота)
- Гибкая маршрутизация запросов
- Управление памятью и контекстом диалогов
- Консилиум моделей — получение ответов от нескольких моделей одновременно
- Просто напишите свой вопрос
- Укажите модель в начале или конце запроса
- Для генерации изображений используйте ключевые слова "нарисуй" или "сгенерируй картинку"
- Используйте консилиум для получения ответов от нескольких моделей одновременно
Консилиум позволяет получить ответы от нескольких моделей одновременно для сравнения их мнений.
Использование:
-
Автоматический выбор моделей (3 модели по умолчанию):
/consilium какая погода в Москве? консилиум: объясни квантовую физику -
Указание конкретных моделей:
/consilium через chatgpt, claude, deepseek: напиши стихотворение консилиум через chatgpt, claude: какой сегодня день?
Примеры:
/consilium какая погода в Москве?— автоматический выбор 3 моделей/consilium через chatgpt, claude, deepseek: объясни квантовую физику— указанные моделиконсилиум: напиши стихотворение— через текстовое сообщение
Бот параллельно запросит ответы у всех указанных моделей и покажет результаты с указанием времени выполнения.
-
Отключите Privacy Mode через @BotFather:
- Откройте @BotFather в Telegram
- Отправьте команду
/mybots - Выберите вашего бота (NeiroTolikBot)
- Нажмите "Bot Settings"
- Выберите "Group Privacy"
- Нажмите "Turn off" (выключить)
Это необходимо, чтобы бот мог получать все сообщения из групп, а не только команды и ответы на свои сообщения.
-
Добавьте бота в группу:
- Добавьте бота в группу как обычного участника
- Бот должен иметь возможность читать сообщения
-
Использование в группе:
- Упомяните бота в сообщении:
@NeiroTolikBot привет - Или ответьте на сообщение бота (бот автоматически обработает ответ без упоминания)
- Используйте те же команды, что и в личных сообщениях
- Бот будет реагировать на сообщения с упоминанием или на ответы к его сообщениям
- Упомяните бота в сообщении:
/new- Начать новый диалог (сохраняет историю для будущего использования)/clear- Полностью очистить память бота/help- Показать справку по командам/consilium- Получить ответы от нескольких моделей одновременно (см. раздел "Консилиум моделей")
Для быстрого прогона смоук-тестов и проверки ключа OpenRouter можно использовать скрипт utils/console_tester.py. Он также умеет офлайн проверять команды /help и /models.
python utils/console_tester.py --run-tests --api-key "<OPENROUTER_API_KEY>"Тесты проверяют:
- доступность основной модели;
- базовую генерацию ответа;
- переключение на альтернативную модель;
- работу памяти и наличие истории в SQLite.
Если основная модель недоступна, отчёт помечает остальные шаги как пропущенные, но тестирование не прерывается.
Можно прогнать ответы на /help и /models без доступа к OpenRouter:
python utils/console_tester.py --run-command-testspython utils/console_tester.py --interactive --api-key "<OPENROUTER_API_KEY>"Дополнительные параметры:
--model— основная модель (по умолчаниюanthropic/claude-3-haiku);--alternate-model— модель для проверки переключения;--prompt— отправить один промпт и вывести ответ;--run-command-tests— запустить офлайн-тесты команд /help и /models.