Compare commits
No commits in common. "404731ed84481a7dde3d2b4e437a8b346b535532" and "7fc148a661bbb83b2977b283db126d4d7b7b8333" have entirely different histories.
404731ed84
...
7fc148a661
170
AGENT.md
170
AGENT.md
|
|
@ -1,170 +0,0 @@
|
||||||
# AGENT.md — правила и контекст проекта
|
|
||||||
|
|
||||||
## Ответы
|
|
||||||
|
|
||||||
- **Коротко и по делу.** Без вступлений, извинений и повторов.
|
|
||||||
- Сначала результат, потом минимальные пояснения.
|
|
||||||
- Язык — русский, если не попросили иначе.
|
|
||||||
- Не пересказывать очевидное; ссылаться на конкретные файлы.
|
|
||||||
- Нужны уточнения — задать 1–3 конкретных вопроса.
|
|
||||||
- Не выдумывать факты: проверить или спросить.
|
|
||||||
|
|
||||||
## Проект
|
|
||||||
|
|
||||||
- Корень: `D:\!Projects\MpakoImageAIbot`.
|
|
||||||
- Стек: Python 3.10+, python-telegram-bot 21+, httpx, aiosqlite, SQLite, Docker, FastAPI/Jinja2.
|
|
||||||
- Требования: `plan.md`. План и статус: `checklist.md`.
|
|
||||||
- Следовать структуре, именованию и стилю существующего кода.
|
|
||||||
- Секреты — только в `.env`. Не логировать токены, не коммитить `.env`, `storage/`, `data/`.
|
|
||||||
|
|
||||||
## Текущее состояние (актуально на 18.10.2026)
|
|
||||||
|
|
||||||
- Кодовый коммит: `c633ab8` — «Ретраи Telegram»; последующие docs-коммиты не меняют код.
|
|
||||||
- Бот: `@EroDrawAI_bot`.
|
|
||||||
- Сервер: `/home/mpakobecex/MpakoImageAIbot`, Docker Compose, контейнеры `mpakoimageaibot-bot-1` и `mpakoimageaibot-web-1` — `Up`.
|
|
||||||
- Веб: `http://192.168.31.158:8099`, доступ только из LAN, без авторизации.
|
|
||||||
- ComfyUI: `http://192.168.31.113:8188`, v0.40.0, RTX 4060 Ti 8 GB.
|
|
||||||
- Тесты: `54 passed`; `ruff` чистый.
|
|
||||||
|
|
||||||
## Функционал
|
|
||||||
|
|
||||||
- T2I: Z-Image Turbo (`workflows/txt2img.json`).
|
|
||||||
- I2I: Krea2 edit (`workflows/img2img.json`), вход через фото+подпись или reply на картинку.
|
|
||||||
- Улучшение промптов: ComfyUI `TextGenerate` + `qwen3vl_4b` (`workflows/prompt_enhance.json`), ChatML, `sampling_mode=off`.
|
|
||||||
- Очередь:
|
|
||||||
- обычная и премиум;
|
|
||||||
- строгое чередование: одна премиум, одна обычная;
|
|
||||||
- если одна пуста — берётся из другой;
|
|
||||||
- одна активная задача на пользователя.
|
|
||||||
- Оплата Telegram Stars (`XTR`):
|
|
||||||
- обычная очередь — 5 звёзд;
|
|
||||||
- премиум — 15 звёзд;
|
|
||||||
- админы бесплатно и в премиум-очередь;
|
|
||||||
- перед оплатой показываются счётчики обеих очередей и кнопки выбора;
|
|
||||||
- возврат звёзд при ошибке постановки/генерации.
|
|
||||||
- Баланс:
|
|
||||||
- новый пользователь — 3 генерации;
|
|
||||||
- +1 каждый день в 00:00 МСК, пропущенные дни добираются;
|
|
||||||
- обычная генерация списывает 1 генерацию или 5 звёзд;
|
|
||||||
- премиум не списывает баланс.
|
|
||||||
- Рефералы:
|
|
||||||
- `/invite` — ссылка `?start=ref_<user_id>` и кнопка копирования;
|
|
||||||
- друг должен перейти по ссылке, запустить бота и впервые оплатить;
|
|
||||||
- реферер получает +3 генерации и уведомление.
|
|
||||||
- Возраст: обязательное подтверждение 18+ через кнопки в `/start`; без него запросы/оплата недоступны. Отказ сохраняется в БД.
|
|
||||||
- Модерация: CSAM, зоофилия, публичные люди, non-consensual, насилие+NSFW, экстремизм, обходные написания. Блокировки логируются в `blocked_requests`.
|
|
||||||
- OpenCV удалён из-за зависания CI; при i2i без детектора NSFW-промпты блокируются консервативно.
|
|
||||||
- Веб-история: фильтры по user_id/статусу/режиму, превью, карточка запроса; видны оригинальный и улучшенный промпты.
|
|
||||||
- Веб-пользователи `/users`: поиск, баланс, админ-флаг, блокировка, статус 18+.
|
|
||||||
|
|
||||||
## Архитектура
|
|
||||||
|
|
||||||
- `bot.py` — Telegram-хендлеры, оплата, возраст, баланс, рефералы, health-check.
|
|
||||||
- `queue_manager.py` — очередь, чередование premium/normal, воркер, прогресс, события.
|
|
||||||
- `db.py` — SQLite, миграции, users/requests/pending_payments/blocked_requests.
|
|
||||||
- `comfy_client.py` — HTTP + WebSocket ComfyUI, upload/history/view, текст.
|
|
||||||
- `prompt_enhancer.py` — улучшение/перевод промпта через ComfyUI.
|
|
||||||
- `moderation.py` — `is_prompt_allowed`, причины блокировок, `detect_person`.
|
|
||||||
- `workflows.py` — валидация подстановок в workflow.
|
|
||||||
- `web.py` + `web/templates` — FastAPI-история и управление пользователями.
|
|
||||||
- `config.py` — env и настройки.
|
|
||||||
|
|
||||||
## База данных
|
|
||||||
|
|
||||||
- `requests`: статусы `queued/running/done/failed`, mode, seed, username, enhanced_prompt, payment_charge_id, payment_refunded, is_premium.
|
|
||||||
- `users`: credits, last_daily_credit, referrer_id, first_paid_at, is_admin, is_blocked, age_confirmed, age_declined.
|
|
||||||
- `pending_payments`: payload, amount, status, charge_id, request_id, is_premium.
|
|
||||||
- `blocked_requests`: user_id, timestamp, prompt, reason, mode, has_person.
|
|
||||||
- `app_settings`: `admins_seeded`.
|
|
||||||
- SQLite WAL; файлы в `storage/`, БД в `data/`, оба volume в Docker.
|
|
||||||
|
|
||||||
## Env (сервер)
|
|
||||||
|
|
||||||
Не выводить `.env` в чат. Ключевые значения:
|
|
||||||
|
|
||||||
```dotenv
|
|
||||||
COMFY_BASE_URL=http://192.168.31.113:8188
|
|
||||||
TELEGRAM_PROXY=http://host.docker.internal:20171
|
|
||||||
WEB_BIND_IP=192.168.31.158
|
|
||||||
PROMPT_ENHANCE_ENABLED=true
|
|
||||||
MODERATION_ENABLED=true
|
|
||||||
PAYMENTS_ENABLED=true
|
|
||||||
STARS_PRICE=5
|
|
||||||
PREMIUM_STARS_PRICE=15
|
|
||||||
ADMIN_USER_IDS=7467236616,6532518406
|
|
||||||
TELEGRAM_RETRY_ATTEMPTS=0
|
|
||||||
TELEGRAM_RETRY_MAX_DELAY=30
|
|
||||||
TELEGRAM_HEALTH_INTERVAL=60
|
|
||||||
```
|
|
||||||
|
|
||||||
- `ADMIN_USER_IDS` — только первичный сид; далее админы в БД (`users.is_admin`), управляются через `/users`.
|
|
||||||
- `.env` на сервере имеет права `600`, не коммитится.
|
|
||||||
|
|
||||||
## Git / Gitea
|
|
||||||
|
|
||||||
- Remote: `ssh://git@home:2222/mpakobecex/MpakoImageAIbot.git`
|
|
||||||
(алиас `home` → `192.168.31.158`).
|
|
||||||
- Ветка `main`.
|
|
||||||
- Gitea Registry: `git.mpakosrv.ru/mpakobecex/mpakoimageaibot`.
|
|
||||||
- CI: `.gitea/workflows/docker-build.yml`, runner `ubuntu-latest`, Docker socket.
|
|
||||||
Собирает и пушит `latest` и `:<sha>`, а также локальный `mpakoimageaibot:latest`.
|
|
||||||
- Секреты CI: `REGISTRY_USER`, `REGISTRY_TOKEN`.
|
|
||||||
- Перед коммитом: `ruff check . --exclude .venv`, `pytest -q`, `git diff --check`.
|
|
||||||
- Коммиты атомарные: `feat:`, `fix:`, `docs:`, `chore:`.
|
|
||||||
- Push после проверки. Force push — только по прямой команде пользователя.
|
|
||||||
|
|
||||||
## Деплой
|
|
||||||
|
|
||||||
```bash
|
|
||||||
ssh home
|
|
||||||
cd ~/MpakoImageAIbot
|
|
||||||
git fetch origin
|
|
||||||
git reset --hard origin/main
|
|
||||||
docker compose up -d --no-build
|
|
||||||
```
|
|
||||||
|
|
||||||
- После изменения `.env`:
|
|
||||||
```bash
|
|
||||||
docker compose up -d --force-recreate --no-build bot
|
|
||||||
```
|
|
||||||
`docker compose restart` не перечитывает env.
|
|
||||||
- Перед деплоем проверить активную генерацию:
|
|
||||||
```bash
|
|
||||||
curl -s http://192.168.31.113:8188/queue
|
|
||||||
```
|
|
||||||
Рестарт прерывает текущую задачу и помечает её `failed`.
|
|
||||||
- Логи: `docker compose logs --tail=50 bot`.
|
|
||||||
|
|
||||||
## Telegram
|
|
||||||
|
|
||||||
- Прокси V2RayA: `http://host.docker.internal:20171`.
|
|
||||||
- PTB использует proxy и get_updates_proxy.
|
|
||||||
- `TELEGRAM_RETRY_ATTEMPTS=0` — повторять операции до успеха; backoff до 30 с.
|
|
||||||
- Health-check `getMe` каждые 60 с; при сбое ретраи с backoff.
|
|
||||||
- Критичные отправки/счета/результаты ретраятся; статус-сообщения — до 3 попыток.
|
|
||||||
- Не логировать токен: httpx-логи приглушены.
|
|
||||||
|
|
||||||
## Команды бота
|
|
||||||
|
|
||||||
- `/start` — приветствие, баланс, цены, возрастной gate.
|
|
||||||
- `/help` — инструкция.
|
|
||||||
- `/balance` — баланс.
|
|
||||||
- `/invite` — реферальная ссылка + копирование.
|
|
||||||
- `/status` — статус задачи.
|
|
||||||
|
|
||||||
## Веб
|
|
||||||
|
|
||||||
- `/` — история запросов, превью, фильтры.
|
|
||||||
- `/users` — управление пользователями.
|
|
||||||
- `/request/{id}` — карточка запроса.
|
|
||||||
- `/media/{id}/input|output`, `/thumb/{id}`.
|
|
||||||
- Авторизации нет; порт слушает только `WEB_BIND_IP`.
|
|
||||||
|
|
||||||
## Известные ограничения / не проверено
|
|
||||||
|
|
||||||
- Реальная оплата Stars и реферальное начисление в Telegram не проверены.
|
|
||||||
- Нет сброса 18+ через веб; отказ сохраняется в БД.
|
|
||||||
- OpenCV отсутствует: i2i NSFW блокируется консервативно.
|
|
||||||
- Очередь 3+ пользователей, падение ComfyUI, рестарт с `running`-задачей не тестировались.
|
|
||||||
- При рестарте активная генерация прерывается.
|
|
||||||
- Веб без авторизации — не публиковать наружу.
|
|
||||||
78
plan.md
78
plan.md
|
|
@ -1,44 +1,52 @@
|
||||||
Ты — senior Python-разработчик. Нужно написать Telegram-бота для генерации изображений через удалённый ComfyUI API.
|
# План проекта
|
||||||
|
|
||||||
|
Telegram-бот для генерации изображений через удалённый ComfyUI API.
|
||||||
|
|
||||||
## Стек
|
## Стек
|
||||||
|
|
||||||
- Python 3.10+
|
- Python 3.10+
|
||||||
- python-telegram-bot (v21+, async) [citation:3]
|
- python-telegram-bot 21+ (async)
|
||||||
- SQLite (через aiosqlite или стандартный sqlite3 с осторожностью)
|
- SQLite (aiosqlite)
|
||||||
- requests / httpx для вызова ComfyUI API
|
- httpx для вызова ComfyUI API
|
||||||
- Docker для финальной упаковки
|
- Docker для упаковки
|
||||||
|
|
||||||
## Функционал (два режима)
|
## Режимы
|
||||||
1. **Text-to-Image**: пользователь отправляет текст → бот шлёт POST на ComfyUI `/prompt` с подставленным промптом [citation:14].
|
|
||||||
2. **Image-to-Image**: пользователь отправляет фото + текст → бот скачивает фото, загружает его в ComfyUI (через `/upload/image` или временную папку), подставляет в воркфлоу как input image, шлёт POST.
|
|
||||||
|
|
||||||
## Очередь (критично)
|
1. **Text-to-Image**: пользователь отправляет текст, бот подставляет промпт в workflow и отправляет его в ComfyUI через `/prompt`.
|
||||||
- Один пользователь = одна активная задача. Если он пишет ещё раз, пока висит его задача — бот отвечает «ты уже в очереди».
|
2. **Image-to-Image**: пользователь отправляет фото и подпись, бот загружает изображение в ComfyUI через `/upload/image`, подставляет его в workflow и отправляет запрос.
|
||||||
- Нужна глобальная очередь. Показывай:
|
|
||||||
- Если в очереди: «Перед тобой X человек».
|
|
||||||
- Если генерация идёт: «Генерация… Y%» (прогресс брать из WebSocket ComfyUI, события `progress` [citation:25][citation:35]).
|
|
||||||
|
|
||||||
## Хранение (SQLite)
|
## Очередь
|
||||||
Таблица `requests`:
|
|
||||||
- id (PK)
|
|
||||||
- user_id (telegram id)
|
|
||||||
- timestamp (ISO)
|
|
||||||
- prompt_text
|
|
||||||
- input_file_path (nullable)
|
|
||||||
- output_file_path (nullable)
|
|
||||||
- status (queued/running/done/failed)
|
|
||||||
- comfy_prompt_id (для отслеживания)
|
|
||||||
|
|
||||||
Файлы (входные фото и результаты) сохраняй локально в папку `./storage/{user_id}/`. В БД только пути.
|
- Один пользователь — одна активная задача. Повторный запрос во время ожидания получает ответ «ты уже в очереди».
|
||||||
|
- Глобальная очередь с отображением позиции: «Перед тобой X человек».
|
||||||
|
- Во время генерации показывается прогресс из WebSocket ComfyUI (событие `progress`).
|
||||||
|
|
||||||
## Вызов ComfyUI
|
## Хранение
|
||||||
- База: `http://IP_WINDOWS:PORT`
|
|
||||||
- POST `/prompt` → получаешь `prompt_id` [citation:2][citation:14].
|
|
||||||
- Опрос статуса: либо через GET `/history/{prompt_id}` (проще, но медленнее), либо через WebSocket на `/ws` (для прогресса в реальном времени) [citation:30][citation:35].
|
|
||||||
- После завершения скачай изображение через `/view?filename=...`.
|
|
||||||
|
|
||||||
## Что сделать сейчас
|
SQLite, таблица `requests`:
|
||||||
1. Создай структуру проекта: `bot.py`, `comfy_client.py`, `db.py`, `queue_manager.py`.
|
|
||||||
2. Напиши `comfy_client.py` с функциями submit_workflow (POST /prompt) и get_result (скачивание).
|
- `id` — первичный ключ;
|
||||||
3. Напиши `db.py` с init_db() и CRUD для requests.
|
- `user_id` — Telegram ID;
|
||||||
4. Напиши `bot.py` с хендлерами для текста и фото, но очередь пока сделай простейшей (asyncio.Queue).
|
- `timestamp` — время создания в ISO;
|
||||||
5. Добавь `requirements.txt` и `Dockerfile`.
|
- `prompt_text` — текст запроса;
|
||||||
|
- `input_file_path` — входное изображение, может быть пустым;
|
||||||
|
- `output_file_path` — результат, может быть пустым;
|
||||||
|
- `status` — `queued`, `running`, `done` или `failed`;
|
||||||
|
- `comfy_prompt_id` — идентификатор задачи в ComfyUI.
|
||||||
|
|
||||||
|
Входные файлы и результаты хранятся в `./storage/{user_id}/`, в БД записываются только пути.
|
||||||
|
|
||||||
|
## ComfyUI
|
||||||
|
|
||||||
|
- Базовый адрес: `http://IP_WINDOWS:PORT`.
|
||||||
|
- `POST /prompt` возвращает `prompt_id`.
|
||||||
|
- Статус отслеживается через `GET /history/{prompt_id}` или WebSocket `/ws` для прогресса в реальном времени.
|
||||||
|
- Готовое изображение скачивается через `/view?filename=...`.
|
||||||
|
|
||||||
|
## Структура проекта
|
||||||
|
|
||||||
|
- `bot.py` — хендлеры текста и фото.
|
||||||
|
- `comfy_client.py` — `submit_workflow` и `get_result`.
|
||||||
|
- `db.py` — `init_db()` и CRUD для `requests`.
|
||||||
|
- `queue_manager.py` — очередь на `asyncio.Queue`.
|
||||||
|
- `requirements.txt`, `Dockerfile` — зависимости и сборка.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue