|
Build and push Docker image / tests (push) Successful in 12s
Details
Build and push Docker image / docker (push) Successful in 31s
Details
pytest не видел пакеты проекта без pythonpath. Добавил корень репозитория в pytest.ini. |
||
|---|---|---|
| .gitea/workflows | ||
| scripts | ||
| tests | ||
| web | ||
| workflows | ||
| .dockerignore | ||
| .env.example | ||
| .gitattributes | ||
| .gitignore | ||
| Dockerfile | ||
| README.md | ||
| bot.py | ||
| checklist.md | ||
| comfy_client.py | ||
| config.py | ||
| db.py | ||
| docker-compose.yml | ||
| moderation.py | ||
| plan.md | ||
| prompt_enhancer.py | ||
| pytest.ini | ||
| queue_manager.py | ||
| requirements-dev.txt | ||
| requirements.txt | ||
| web.py | ||
| workflows.py | ||
README.md
MpakoImageAIbot
Telegram-бот для генерации и редактирования изображений через удалённый ComfyUI API.
Что умеет
- Text-to-image: текст → изображение (Z-Image Turbo, 1024×1024).
- Image-to-image: фото + подпись → редактирование (Krea2 edit).
- Reply-to-image: ответ текстом на готовую картинку бота → редактирование этой картинки.
- Веб-история: просмотр запросов с фильтрами по
user_id, статусу и режиму, просмотр изображений. - Улучшение промптов: перевод и переписывание запроса на английский через
TextGenerate+qwen3vl_4bв ComfyUI. - Фильтрация промптов: блокировка CSAM, зоофилии, NSFW с публичными людьми и обходных вариантов для не-админов.
- Оплата: 5 Telegram Stars за обычную очередь, 15 за премиум; админам бесплатно, возврат при ошибке.
- Премиум-очередь: чередуется с обычной (одна премиум, одна обычная); если одна пуста — работает другая.
- Баланс и рефералы: 3 стартовые генерации, +1 ежедневно в 00:00 МСК, +3 за первую оплату друга.
- Управление пользователями: в веб-интерфейсе можно выдавать админку, менять баланс и блокировать.
- Подтверждение 18+: без подтверждения возраста бот не принимает запросы.
- Глобальная очередь с одной активной задачей на пользователя.
- Позиция в очереди и прогресс генерации через WebSocket ComfyUI.
- PostgreSQL: запросы, статусы, seed, пути к файлам.
Требования
- Python 3.10+ (проверено на 3.13).
- ComfyUI с доступом по сети, например:
python main.py --listen 0.0.0.0 --port 8188 - Установленные кастомные ноды для текущих workflow:
Krea2ModelLoader,TextEncodeQwenImageEdit,UnetLoaderGGUF,CLIPLoaderGGUF. - Модели, указанные в
workflows/txt2img.jsonиworkflows/img2img.json.
Настройка
Copy-Item .env.example .env
Заполнить .env:
BOT_TOKEN— токен от@BotFather.TELEGRAM_PROXY— прокси для Telegram API (пусто — напрямую).COMFY_BASE_URL— напримерhttp://192.168.31.113:8188.DATABASE_URL— строка подключения PostgreSQL. В Docker хостdb, при локальном запуске —localhost.- Остальные параметры можно оставить по умолчанию.
Прокси для Telegram
Если сервер не имеет прямого доступа к Telegram, укажи прокси V2RayA/HTTP/SOCKS5:
# Docker на Linux (V2RayA слушает на хосте)
TELEGRAM_PROXY=http://host.docker.internal:20171
# Запуск без Docker, на том же хосте
# TELEGRAM_PROXY=http://127.0.0.1:20171
Для SOCKS5 используй socks5h://host.docker.internal:20170; зависимость socksio уже включена в requirements.txt.
Запуск
py -3 -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
python bot.py
Бот работает в приватных чатах. Пользователь отправляет текст или фото с подписью.
Для локального запуска нужен PostgreSQL и DATABASE_URL с хостом localhost.
Docker
docker compose up -d --build
Compose поднимает PostgreSQL, бота и веб. Каталог ./storage монтируется в контейнеры, данные PostgreSQL лежат в ./data/postgres. Для ComfyUI на другой машине используйте её LAN-IP, а не localhost.
PostgreSQL
POSTGRES_DB=mpakoimageaibot
POSTGRES_USER=mpako
POSTGRES_PASSWORD=change-me
DATABASE_URL=postgresql://mpako:change-me@db:5432/mpakoimageaibot
DB_POOL_MIN_SIZE=1
DB_POOL_MAX_SIZE=10
Пароль в DATABASE_URL должен совпадать с POSTGRES_PASSWORD; спецсимволы в пароле нужно URL-кодировать.
Перенос старой SQLite-базы
python scripts/migrate_sqlite_to_postgres.py `
--sqlite data/bot.db `
--database-url "postgresql://mpako:change-me@localhost:5432/mpakoimageaibot"
Перед миграцией останови старый бот, чтобы SQLite закрылась и данные были консистентны. Скрипт создаёт схему, переносит данные и пропускает уже существующие записи.
CI
При push в main или master Gitea Actions сначала запускает тесты на PostgreSQL, затем собирает образ на сервере, где запущен runner, и пушит его в Gitea Registry:
git.mpakosrv.ru/mpakobecex/mpakoimageaibot:latestgit.mpakosrv.ru/mpakobecex/mpakoimageaibot:<sha>- локально:
mpakoimageaibot:latest
Workflow: .gitea/workflows/docker-build.yml. Runner использует label ubuntu-latest и смонтированный Docker socket. Для входа в registry нужны секреты REGISTRY_USER и REGISTRY_TOKEN.
WORKFLOW_PROMPT— workflow улучшения промптов (по умолчаниюworkflows/prompt_enhance.json).PROMPT_ENHANCE_ENABLED— включить улучшение промптов.PROMPT_ENHANCE_TIMEOUT— таймаут генерации промпта в секундах.
Улучшение промптов
Перед генерацией исходный текст проходит через ComfyUI TextGenerate с уже установленной моделью qwen3vl_4b_fp8_scaled.safetensors:
- T2I: перевод и переписывание в английский промпт для генерации.
- I2I: перевод и переписывание инструкции для редактирования.
- Исходный и улучшенный промпты сохраняются в БД и видны в веб-истории.
- При ошибке или таймауте используется исходный промпт.
Отдельную модель скачивать не нужно, используется существующий CLIP-файл ComfyUI.
Фильтрация промптов
Фильтр работает для всех, кроме пользователей из ADMIN_USER_IDS:
MODERATION_ENABLED=true
ADMIN_USER_IDS=7467236616
BLOCKED_PUBLIC_FIGURES=
BLOCKED_PUBLIC_FIGURES добавляет имена к встроенному списку (через запятую).
Что блокируется:
- CSAM: child/kid/minor/teen/young/loli/shota/school/underage + NSFW;
- зоофилия: sex/nude + animal/dog/cat/horse/beast;
- публичные люди + nude/naked/sex/undress/deepfake;
- undress/nude/naked + photo/real/person/woman/man;
- насилие + NSFW;
- экстремизм + инструкции/символика;
- обходные написания (
n_u_d_e,l0li,ch1ldи т.п.).
Для i2i: если установлен OpenCV, проверяется наличие лица/человека. В базовом образе OpenCV нет, поэтому NSFW-промпты в i2i блокируются консервативно — как если бы на фото был человек.
При блокировке пользователь получает «Запрос нарушает правила. Звёзды не списаны.», а запись с user_id, временем, промптом и причиной сохраняется в таблицу blocked_requests.
Управление пользователями
В веб-интерфейсе есть раздел «Пользователи» (/users):
- поиск по ID или username;
- установка точного баланса генераций;
- назначение/снятие админа;
- блокировка/разблокировка.
Заблокированный пользователь не может отправлять запросы, получать счета и оплачивать. Админ-флаг из веб-интерфейса действует сразу.
ADMIN_USER_IDS используется только для первичной инициализации админов; после первого запуска админы хранятся в БД и управляются через веб.
Надёжность Telegram
TELEGRAM_RETRY_ATTEMPTS=0
TELEGRAM_RETRY_MAX_DELAY=30
TELEGRAM_HEALTH_INTERVAL=60
TELEGRAM_RETRY_ATTEMPTS=0— повторять операции до успеха.- Backoff растёт до
TELEGRAM_RETRY_MAX_DELAY. - Критичные отправки (результат, счёт, подтверждение) повторяются бесконечно; обновления статуса — ограниченно, чтобы не плодить зависшие задачи.
- Раз в
TELEGRAM_HEALTH_INTERVALвыполняетсяgetMe; при сбое проверка повторяется с backoff, пока Telegram не ответит.
Подтверждение возраста
Перед использованием бота нужно подтвердить 18+:
- в
/startпоказываются кнопки «Мне 18+» и «Мне меньше 18»; - без подтверждения текстовые и фото-запросы отклоняются;
- отказ «мне меньше 18» сохраняется в БД и блокирует доступ;
- статус 18+ виден в веб-разделе «Пользователи».
Существующие пользователи проходят подтверждение один раз после обновления.
Баланс и рефералы
- Новому пользователю начисляется 3 генерации.
- Каждый день в 00:00 МСК — ещё 1 генерация.
- Обычная генерация может быть оплачена 1 генерацией с баланса или 5 звёздами.
- Премиум-очередь всегда оплачивается 15 звёздами; баланс при этом не расходуется.
/balance— текущий баланс./invite— реферальная ссылка.- За первую оплату приглашённого друга начисляется +3 генерации, реферер получает уведомление.
Баланс и рефералы хранятся в таблице users. Пропущенные дни начисляются при следующем запуске/полуночи.
Оплата
Генерация стоит 5 Telegram Stars в обычной очереди и 15 звёзд в премиум-очереди:
PAYMENTS_ENABLED=true
STARS_PRICE=5
PREMIUM_STARS_PRICE=15
- Перед оплатой бот показывает количество людей в обычной и премиум-очередях.
- Пользователь выбирает очередь кнопкой, после чего получает счёт.
- Премиум- и обычные задачи чередуются: одна премиум, одна обычная; если одна очередь пуста, берётся из другой.
- Админы из
ADMIN_USER_IDSгенерируют бесплатно в обычной очереди. - Не-админу выставляется счёт через Telegram Stars (
XTR). - Фильтрация промпта выполняется до выставления счёта.
- Если поставить задачу в очередь не удалось, звёзды возвращаются.
- При ошибке генерации звёзды также возвращаются.
- Оплата и
telegram_payment_charge_idсохраняются вpending_paymentsиrequests.
Веб-история
После docker compose up -d доступна страница:
http://192.168.31.158:8099
Возможности:
- фильтр по Telegram
user_id(с подсказкой известных пользователей); - в списке показывается
@username, если он известен, иначе Telegram ID; - фильтр по статусу и режиму (
t2i/i2i); - пагинация;
- превью результата в списке (кэшируются в
storage/.thumbnails); - карточка запроса с полным промптом, ошибкой, seed и изображениями.
Доступ только с локальной сети: Compose публикует порт на WEB_BIND_IP. Для доступа из LAN:
WEB_BIND_IP=192.168.31.158
WEB_PAGE_SIZE=50
Авторизации нет. Не публикуй порт 8099 наружу и не делай проброс на роутере.
После успешной сборки обновление контейнера:
docker compose up -d
Без --build: Compose возьмёт готовый образ mpakoimageaibot:latest.
Workflow
workflows/txt2img.json— Z-Image Turbo:EmptySD3LatentImage → KSampler → VAEDecode → SaveImage.workflows/img2img.json— Krea2 edit:LoadImage → TextEncodeQwenImageEdit → KSamplerAdvanced → VAEDecode → SaveImage.workflows/mapping.json— ID узлов, в которые подставляются prompt, negative, seed и входное изображение.workflows/Krea2.jsonиworkflows/ZImage.json— исходные экспорты.
Если меняются workflow, обновите mapping.json. При старте бот проверяет, что все узлы и поля существуют.
Тесты
pip install -r requirements-dev.txt
pytest
Ограничения текущей версии
- Один воркер и одна активная задача на пользователя.
- Нет
/cancelи удаления задачи из очереди. - Нет автоочистки
storage/иdata/. - Прогресс в процентах зависит от WebSocket; при его недоступности используется polling без процентов.
- При рестарте задача в статусе
runningпомечаетсяfailed.