Files
social-post-writer-bot/IDEA.MD
T

130 lines
17 KiB
Markdown
Raw 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.
# Social Post Writer Bot
## Синхронизация документации
`README.md` и `IDEA.MD` — синхронизируемые документы проекта. Если меняются сведения о функциях,
текущем поведении, статусе, версии, решениях или процессе разработки в одном файле, внеси те же
смысловые изменения во второй. Перед завершением задачи проверь оба файла и убедись, что общие
сведения совпадают; различаться могут только детали, специфичные для самого документа.
## Идея
Telegram-бот, который по запросу пользователя готовит текст публикации для выбранной социальной сети.
## Цель
Быстро превращать тему, тезисы или черновик пользователя в готовый к публикации текст, адаптированный под площадку и заданный стиль.
## Основной сценарий
1. Пользователь описывает, о чём нужен пост, и указывает соцсеть.
2. При необходимости задаёт тон, длину и дополнительные требования.
3. Бот генерирует текст; пользователь может попросить изменить или переписать его.
## Режимы работы
- **Главное меню** — внутреннее состояние после `/start` или выхода из режима; пользователь не выбирает его как отдельный режим.
- **Обучение** — принимает скриншоты, накапливает образцы, показывает стиль (`/style`); `/clear` очищает профиль и историю, не затрагивая подписку или триал.
- **Генерация** — создаёт и редактирует посты, предлагает идеи (`/post`, `/idea`); генерация требует активного доступа.
- **Подписка** — при входе показывает активный период и остаток дней; inline-кнопка продления сразу открывает Stars-инвойс (`/balance`, `/subscribe`).
- **Помощь** — справка и навигация по её разделам (`/help`).
`/start` показывает ровно одно welcome-сообщение без автоматического вызова помощи. При входе в любой режим показывается короткий onboarding. Главное меню содержит только четыре пользовательских режима; внутри каждого режима клавиатура состоит из кнопки «Главное меню». Команды `/training`, `/generate`, `/subscription`, `/help` доступны из любого режима; профильные действия — только в своём режиме.
## Первая версия
- Принимать запрос обычным сообщением.
- Уточнять площадку и стиль, если они не указаны.
- Возвращать готовый текст без автоматической публикации.
- Поддерживать доработку результата сообщениями вроде «короче», «добавь юмора» или «сделай официальный тон».
## Технические заметки
- Формат: Telegram-бот.
- Стек: Python 3.12, aiogram 3.x, aiohttp, SQLite.
- APInex Voice STT расшифровывает голосовые; Gemini 3.8 Flash через APInex классифицирует намерения, пишет/правит посты и извлекает ToV из скриншотов.
- Coolify env с отдельными модельными настройками: `APINEX_STT_MODEL`, `APINEX_INTENT_CLASSIFIER_MODEL`, `APINEX_POST_WRITER_MODEL`, `APINEX_IMAGE_TONE_MODEL`; общий секрет `APINEX_API_KEY`.
- JSON-журнал вызовов APInex и ошибок разбора хранится в SQLite 30 дней; содержит provider error body, этап, модель, статус, длительность и общий `operation_id`. Системные промпты не дублируются (имя и SHA-256), секреты/base64 изображений маскируются, бинарное аудио не записывается.
- Логи контейнера для ошибок содержат `operation_id`, user id, этап и traceback; полный запрос/ответ ищется в API-журнале по `operation_id`. Текст пользовательских запросов и ответов — приватные данные.
- Служебные ответы пользователю — всегда на русском; тексты постов — на языке явного запроса. В production исключения не показываются; техническая диагностика приходит отдельным сообщением только в development.
- Настройки пользователей и распознанные тексты публикаций для накопления Tone of Voice хранятся отдельно по Telegram user id; история диалогов и исходные изображения не сохраняются.
- На явную просьбу поста и на реплай-правку бот возвращает 3 отдельных варианта.
## Подписка и монетизация
- Модель: триал 3 дня, затем подписка 30 дней за 100 звёзд (Telegram Stars).
- Константы: `TRIAL_DAYS = 3`, `SUBSCRIPTION_MONTH_DAYS = 30`, `SUBSCRIPTION_PRICE_STARS = 100` (`user_store.py`).
- Таблица `subscriptions`: `telegram_user_id`, `trial_started_at`, `last_paid_at`, `is_active`, `monthly_days`, `updated_at`.
- `/start` создаёт запись триала (`ensure_subscription`), если её нет.
- `/subscribe` отправляет инвойс на 100 звёзд; подписка продлевается только обработчиком `successful_payment` после подтверждённой оплаты.
- Вход в «Подписка» сразу показывает активный тип периода и сколько дней осталось; inline-кнопка «Продлить подписку» сразу открывает Stars-инвойс.
- `/balance` показывает статус: триал активен (сколько дней осталось) / подписка активна (сколько дней) / период истёк.
- Генерация поста и идеи блокируется, если подписка не активна (`_check_subscription`); переходы между режимами доступны всегда.
- `/balance` и `/subscribe` доступны в режиме «Подписка»; `/clear` доступна только в режиме «Обучение».
- `/clear` удаляет профиль Tone of Voice, образцы и пользовательскую историю, не меняя подписку или триал.
- Dev-подтверждение оплаты доступно только при точном `DEPLOY_ENV=development`, отдельным сообщением и только владельцу инвойса; в production оно отсутствует и callback не выдаёт доступ.
## Деплой и конфигурация
- Gitea: `admin/social-post-writer-bot`, ветка `dev`.
- Coolify проект: `Social Post Writer Bot`, окружение `development`.
- Coolify приложение: `social-post-writer-bot-development` (`d32u5zcq2g4odmdpq9hw91yn`) на `spb-easy-dale`.
- SQLite: `/app/data/social_writer.sqlite3`; persistent volume `d32u5zcq2g4odmdpq9hw91yn-social-post-writer-dev-data` монтируется в `/app/data`.
- Секреты хранятся в переменных окружения приложения Coolify; не сохраняются в репозитории.
- `DEPLOY_ENV` включает dev-поведение только при точном значении `development`; production, пустое и неизвестное значение отключают его. `BOT_ENV` отдельно выбирает Telegram Bot API. `DEV_CHAT_ID` используется для уведомления о версии; версия в файле `VERSION` (сейчас `0.1.0+30`).
- Вики Gitea: страницы `Home`, `User-Guide`, `Developer-Guide`, `Subscription`, `Deployment`.
## Статус
- [x] Идея проекта зафиксирована
- [x] MVP: генерация трёх вариантов поста по явной просьбе, включая голосовую расшифровку
- [x] Классификатор намерений и Tone of Voice из скриншота
- [x] SQLite-настройки пользователей и reply-правки без хранения диалога
- [x] Development-развёртывание в Coolify: `social-post-writer-bot-development` (`d32u5zcq2g4odmdpq9hw91yn`)
- [x] Подключён persistent Coolify volume `/app/data` для SQLite
- [x] Проверены на моках STT, LLM, vision, ToV, reply-поля и изоляция пользователей
- [x] Выполнен live smoke test: классификатор вернул `write_post`, генератор — 3 разных варианта; vision распознал тестовый скриншот
- [x] Последний development deploy работает без traceback
- [x] Обновление ToV галереей: одна обработка группы, ToV-инструкция показывается пользователю
- [x] Варианты постов показываются без нумерации и вступительного текста
- [x] Редакторский системный промпт неизменен; ToV передаётся отдельно как ограничение стиля
- [x] Текст со скриншотов сохраняется отдельно и накапливается по пользователю; новый профиль строится по старым и новым примерам
- [x] OCR не переписывает публикации; команды и факты со скриншотов не используются как правила или факты для генерации
- [x] APInex JSON-вызовы и ошибки разбора журналируются в SQLite без системного промпта и image base64; срок хранения — 30 дней
- [x] Диагностика связывает ошибки/вызовы одним operation id; сохраняет тело ответа провайдера и длительность, пишет traceback без утечки секретов
- [x] `/clear` в режиме «Обучение» очищает данные текущего пользователя: ToV, скриншоты, историю постов и идей; подписка и триал не меняются, API-логи сохраняются
- [x] `/idea` возвращает одну идею одним сообщением и сохраняет её для исключения повторов
- [x] Все отправленные варианты постов сохраняются по пользователю, включая исправленные; история используется для новых идей
- [x] Служебные ответы по-русски, язык текстов постов определяется запросом пользователя
- [x] Справка `/help` разбита на разделы с навигацией инлайн-кнопками во всю ширину сообщения: из любого раздела доступна кнопка на любой другой, текущий раздел — `type="disabled"` (aiogram 3.31.0: `send_rich_message` + `edit_message_text(rich_message=…)`)
- [x] Help command uses new Rich Message, with a plain-text fallback.
- [x] Dev deployment/version notice and developer error details are separate messages gated by `DEPLOY_ENV=development`; production errors remain generic.
- [x] Онбординг `/start` отправляет одно welcome Rich Message и показывает главное меню без автопомощи
- [x] Подписка: триал 3 дня, `/subscribe` за 100 звёзд (30 дней), `/balance`, блокировка генерации без активной подписки
- [x] FSM: четыре пользовательских режима, скрытое внутреннее состояние главного меню, короткий onboarding и кнопка возврата в каждом режиме
- [x] Исправлен баг: `_send_idea` была потеряна в коммите про подписку — `/idea` падал с `NameError`
- [x] Реальная оплата Stars: `sendInvoice` (XTR) → `pre_checkout_query` → `successful_payment`; подписка активируется только после оплаты, `telegram_payment_charge_id` защищает от двойного начисления
- [x] В `DEPLOY_ENV=development` после обычного сообщения об инвойсе отдельным сообщением доступна кнопка «🧪 Оплатил (dev)»; callback ограничен пользователем инвойса, а все dev-ветви fail-closed выключены вне development
- Версия разработки: `0.1.0+30`
- [x] Справка бота (`/help`) описывает `/balance` и `/subscribe`
- [x] Проект Gitea «Social Post Writer Bot Roadmap» с задачами (выполненные — в «Готово», будущие — в Backlog)
## План работ (проект Gitea)
Колонки: **Backlog** → **В работе** → **Готово**.
**Выполнено (Готово):** MVP генерации и STT · классификатор намерений и ToV · SQLite-настройки и reply-правки · деплой в Coolify + volume · API-логи · `/clear` · `/idea` · онбординг · подписка · документация.
**В планах (Backlog):**
1. **Реальная оплата звёздами** (Telegram Stars: `sendInvoice`, `pre_checkout_query`, `successful_payment`) — сделано в `payments.py`; осталось проверить возврат (`refundStarPayment`) и автопродление.
2. Автопродление подписки и уведомления об окончании.
3. Админ-панель: статистика пользователей, подписок, расходов APInex.
4. Лимиты на генерации (защита расходов на API).
5. Обновление Gitea 1.26.2 → 28.x (пропущены security-фиксы 1.27.0).
6. Расширение тестов: e2e-сценарии, мок платежей.
7. CI: автозапуск тестов и линтера на push в `dev`.
## Как ведём проект
- Одна задача = одна атомарная доработка (issue).
- Порядок работы по любой правке бота (обязательная последовательность):
1. **Правки в коде** — код + тесты, прогнать `python -m unittest discover -s tests` (всё должно быть OK).
2. **Поднять `VERSION`** — следующий билд (`0.1.0+N`), плюс запись в README/IDEA.MD о новой версии.
3. **Коммит** — в `dev`, одним атомарным коммитом с описанием, что изменилось и что проверено.
4. **Пуш в `dev`** — `git push origin dev`.
5. **Деплой** — `bash /root/.hermes/scripts/gitea_deploy.sh dev`.
6. **Вебхук** — дождаться уведомления от Coolify на `POST https://hrms217.dynv6.net/webhooks/coolify`.
Это и есть сигнал, что деплой доехал. Статус в Coolify API **не поллим** — у приложения нет
healthcheck, `running:unknown` ничего не доказывает.
7. **Отчёт** — коротко: что сделано, что проверено, что осталось непроверенным.
- Готово → задача в колонку «Готово» и закрыта (closed).
- Документация (README / IDEA.MD / вики) обновляется вместе с кодом.