MpakoImageAIbot/README.md

336 lines
20 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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) модель и 8/10/12 шагов.
- Глобальная очередь с одной активной задачей на пользователя.
- Позиция в очереди и прогресс генерации через 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:<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`:
```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`).
- `/context` — показать текущий контекст: промпт, базовую сцену и последний запрос.
- `/settings` — выбор модели Krea2 (Q4/Q6) и количества шагов (8/10/12).
- При старте бот проверяет `setMyCommands` и включает кнопку меню с командами.
- За первую оплату приглашённого друга начисляется +3 генерации, реферер получает уведомление.
Баланс и рефералы хранятся в таблице `users`. Пропущенные дни начисляются при следующем запуске/полуночи.
## Контекст
- Первый текстовый запрос создаёт контекст: базовую сцену и текущий улучшенный промпт.
- Следующий текст обрабатывается вместе с предыдущим промптом: бот сохраняет сцену и применяет только запрошенное изменение.
- `/restart` очищает контекст; следующий запрос начнёт новую сцену.
- `/context` показывает текущий промпт, базовую сцену и последний запрос.
- Новое фото с подписью автоматически начинает новую цепочку.
- Для точного редактирования конкретной картинки ответь на сообщение бота с изображением.
- `/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`, латент подгоняется под пропорции входного изображения; 8/10/12 шагов, `euler`/`simple`.
- `/settings` переключает модель Krea2 (`Q4_K_M` / `Q6_K`) и шаги (`8` / `10` / `12`). Остальные настройки сэмплера и латента одинаковые.
- Файлы моделей должны быть в `models/diffusion_models`; имена задаются `KREA2_Q4_MODEL` и `KREA2_Q6_MODEL`.
Если меняются workflow, обновите `mapping.json`. При старте бот проверяет, что все узлы и поля существуют.
## Очистка ComfyUI
После успешного скачивания результата бот удаляет запись истории ComfyUI по `prompt_id`:
```json
POST /history
{"delete": ["<prompt_id>"]}
```
Это убирает запрос и его ассеты из истории 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`.