# 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+**: без подтверждения возраста бот не принимает запросы. - **Контекст**: следующий текстовый запрос продолжает предыдущую сцену; `/restart` начинает новую. - **Настройки Krea2**: `/settings` переключает стандартную (Q4) и улучшенную (Q6) модель. - Глобальная очередь с одной активной задачей на пользователя. - Позиция в очереди и прогресс генерации через WebSocket ComfyUI. - PostgreSQL: запросы, статусы, seed, пути к файлам. ## Требования - Python 3.10+ (проверено на 3.13). - ComfyUI с доступом по сети, например: ```text python main.py --listen 0.0.0.0 --port 8188 ``` - Установленные кастомные ноды для текущих workflow: `Krea2ModelLoader`, `TextEncodeQwenImageEdit`, `UnetLoaderGGUF`, `CLIPLoaderGGUF`. - Модели, указанные в `workflows/txt2img.json` и `workflows/img2img.json`. ## Настройка ```powershell 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: ```dotenv # Docker на Linux, рекомендуется SOCKS5 TELEGRAM_PROXY=socks5h://host.docker.internal:20170 # HTTP-вариант # TELEGRAM_PROXY=http://host.docker.internal:20171 # Запуск без Docker, на том же хосте # TELEGRAM_PROXY=socks5h://127.0.0.1:20170 ``` SOCKS5 стабильнее держит long polling; зависимость `socksio` уже включена в `requirements.txt`. ## Запуск ```powershell py -3 -m venv .venv .\.venv\Scripts\Activate.ps1 pip install -r requirements.txt python bot.py ``` Бот работает в приватных чатах. Пользователь отправляет текст или фото с подписью. Для локального запуска нужен PostgreSQL и `DATABASE_URL` с хостом `localhost`. ## Docker ```powershell docker compose up -d --build ``` Compose поднимает PostgreSQL, бота и веб. Каталог `./storage` монтируется в контейнеры, данные PostgreSQL лежат в `./data/postgres`. Для ComfyUI на другой машине используйте её LAN-IP, а не `localhost`. ## PostgreSQL ```dotenv 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-базы ```powershell 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:latest` - `git.mpakosrv.ru/mpakobecex/mpakoimageaibot:` - локально: `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`: ```dotenv 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`. ## Управление пользователями В админ-панели есть раздел **«Пользователи»** (`/admin/users`): - поиск по ID или username; - установка точного баланса генераций; - назначение/снятие админа; - блокировка/разблокировка. Заблокированный пользователь не может отправлять запросы, получать счета и оплачивать. Админ-флаг из веб-интерфейса действует сразу. `ADMIN_USER_IDS` используется только для первичной инициализации админов; после первого запуска админы хранятся в БД и управляются через веб. ## Надёжность Telegram ```dotenv 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 не ответит. - Watchdog проверяет pending updates: если они не обрабатываются 5 минут, polling перезапускается, а при неудаче контейнер перезапускается автоматически. ## Подтверждение возраста Перед использованием бота нужно подтвердить 18+: - в `/start` показываются кнопки «Мне 18+» и «Мне меньше 18»; - без подтверждения текстовые и фото-запросы отклоняются; - отказ «мне меньше 18» сохраняется в БД и блокирует доступ; - статус 18+ виден в веб-разделе «Пользователи». Существующие пользователи проходят подтверждение один раз после обновления. ## Баланс и рефералы - Новому пользователю начисляется 3 генерации. - Каждый день в 00:00 МСК — ещё 1 генерация. - Обычная генерация может быть оплачена 1 генерацией с баланса или 5 звёздами. - Премиум-очередь всегда оплачивается 15 звёздами; баланс при этом не расходуется. - `/balance` — текущий баланс. - `/invite` — реферальная ссылка. - `/restart` — сбросить контекст и начать новую сцену (алиас `/reset`). - `/settings` — выбор модели Krea2: стандартная Q4 или улучшенная Q6. - При старте бот проверяет `setMyCommands` и включает кнопку меню с командами. - За первую оплату приглашённого друга начисляется +3 генерации, реферер получает уведомление. Баланс и рефералы хранятся в таблице `users`. Пропущенные дни начисляются при следующем запуске/полуночи. ## Контекст - Первый текстовый запрос создаёт контекст: базовую сцену и текущий улучшенный промпт. - Следующий текст обрабатывается вместе с предыдущим промптом: бот сохраняет сцену и применяет только запрошенное изменение. - `/restart` очищает контекст; следующий запрос начнёт новую сцену. - Новое фото с подписью автоматически начинает новую цепочку. - Для точного редактирования конкретной картинки ответь на сообщение бота с изображением. - `/restart` не отменяет уже запущенную генерацию: она завершится со своим снимком контекста. Контекст хранится в таблице `user_contexts` и обновляется только после успешной отправки результата. ## Оплата Генерация стоит 5 Telegram Stars в обычной очереди и 15 звёзд в премиум-очереди: ```dotenv 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` доступна страница: ```text http://192.168.31.158:8099 ``` Возможности: Публичная страница `/` показывает только историю: - фильтр по Telegram `user_id` (с подсказкой известных пользователей); - в списке показывается `@username`, если он известен, иначе Telegram ID; - фильтр по статусу и режиму (`t2i`/`i2i`); - пагинация; - превью результата в списке (кэшируются в `storage/.thumbnails`); - карточка запроса с полным промптом, ошибкой, seed и изображениями. Админ-панель находится на `/admin` и защищена HTTP Basic: - `/admin` — история, включая скрытые запросы; - `/admin/users` — управление пользователями; - скрытие/показ запроса из публичной истории; - скрытые запросы не видны в публичном списке, их карточки и медиа отдают `404`. ```dotenv WEB_BIND_IP=192.168.31.158 WEB_PAGE_SIZE=50 WEB_ADMIN_USERNAME=admin WEB_ADMIN_PASSWORD=change-me ``` Если `WEB_ADMIN_PASSWORD` пустой, админ-панель отключена. Basic Auth передаёт пароль без шифрования, поэтому используй только LAN или VPN; не публикуй порт `8099` наружу. После успешной сборки обновление контейнера: ```bash 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` — исходные экспорты. - Krea2 edit: VAE подключён к `TextEncodeQwenImageEdit`, латент подгоняется под пропорции входного изображения; 12 шагов, `dpmpp_2m`/`karras`. - `/settings` переключает модель Krea2: стандартная `Q4_K_M` или улучшенная `Q6_K`. Настройки сэмплера и латента одинаковые. - Файлы моделей должны быть в `models/diffusion_models`; имена задаются `KREA2_Q4_MODEL` и `KREA2_Q6_MODEL`. Если меняются workflow, обновите `mapping.json`. При старте бот проверяет, что все узлы и поля существуют. ## Очистка ComfyUI После успешного скачивания результата бот удаляет запись истории ComfyUI по `prompt_id`: ```json POST /history {"delete": [""]} ``` Это убирает запрос и его ассеты из истории ComfyUI, но не удаляет файлы с диска. Для файлов `output/` и `temp/` есть скрипт для машины с ComfyUI: ```powershell .\scripts\cleanup_comfy_assets.ps1 -ComfyRoot "C:\ComfyUI" -RetentionHours 6 ``` Запускай его по расписанию, например раз в час. Сначала можно проверить без удаления: ```powershell .\scripts\cleanup_comfy_assets.ps1 -ComfyRoot "C:\ComfyUI" -RetentionHours 6 -WhatIf ``` ## Тесты ```powershell pip install -r requirements-dev.txt pytest ``` ## Ограничения текущей версии - Один воркер и одна активная задача на пользователя. - Нет `/cancel` и удаления задачи из очереди. - Нет автоочистки `storage/` и `data/`. - Прогресс в процентах зависит от WebSocket; при его недоступности используется polling без процентов. - При рестарте задача в статусе `running` помечается `failed`.