Итоговый промпт в подписи и /restart
В подписи результата показываю итоговый промпт и подсказку /restart. /reset оставил алиасом для совместимости.
This commit is contained in:
parent
67d3180ef6
commit
d4263c8420
|
|
@ -15,7 +15,7 @@ Telegram-бот для генерации и редактирования изо
|
|||
- **Баланс и рефералы**: 3 стартовые генерации, +1 ежедневно в 00:00 МСК, +3 за первую оплату друга.
|
||||
- **Управление пользователями**: в веб-интерфейсе можно выдавать админку, менять баланс и блокировать.
|
||||
- **Подтверждение 18+**: без подтверждения возраста бот не принимает запросы.
|
||||
- **Контекст**: следующий текстовый запрос продолжает предыдущую сцену; `/reset` начинает новую.
|
||||
- **Контекст**: следующий текстовый запрос продолжает предыдущую сцену; `/restart` начинает новую.
|
||||
- Глобальная очередь с одной активной задачей на пользователя.
|
||||
- Позиция в очереди и прогресс генерации через WebSocket ComfyUI.
|
||||
- PostgreSQL: запросы, статусы, seed, пути к файлам.
|
||||
|
|
@ -202,7 +202,7 @@ TELEGRAM_HEALTH_INTERVAL=60
|
|||
- Премиум-очередь всегда оплачивается 15 звёздами; баланс при этом не расходуется.
|
||||
- `/balance` — текущий баланс.
|
||||
- `/invite` — реферальная ссылка.
|
||||
- `/reset` — сбросить контекст и начать новую сцену.
|
||||
- `/restart` — сбросить контекст и начать новую сцену (алиас `/reset`).
|
||||
- За первую оплату приглашённого друга начисляется +3 генерации, реферер получает уведомление.
|
||||
|
||||
Баланс и рефералы хранятся в таблице `users`. Пропущенные дни начисляются при следующем запуске/полуночи.
|
||||
|
|
@ -211,10 +211,10 @@ TELEGRAM_HEALTH_INTERVAL=60
|
|||
|
||||
- Первый текстовый запрос создаёт контекст: базовую сцену и текущий улучшенный промпт.
|
||||
- Следующий текст обрабатывается вместе с предыдущим промптом: бот сохраняет сцену и применяет только запрошенное изменение.
|
||||
- `/reset` очищает контекст; следующий запрос начнёт новую сцену.
|
||||
- `/restart` очищает контекст; следующий запрос начнёт новую сцену.
|
||||
- Новое фото с подписью автоматически начинает новую цепочку.
|
||||
- Для точного редактирования конкретной картинки ответь на сообщение бота с изображением.
|
||||
- `/reset` не отменяет уже запущенную генерацию: она завершится со своим снимком контекста.
|
||||
- `/restart` не отменяет уже запущенную генерацию: она завершится со своим снимком контекста.
|
||||
|
||||
Контекст хранится в таблице `user_contexts` и обновляется только после успешной отправки результата.
|
||||
|
||||
|
|
|
|||
19
bot.py
19
bot.py
|
|
@ -43,6 +43,19 @@ logger = logging.getLogger(__name__)
|
|||
MSK = timezone(timedelta(hours=3))
|
||||
POLLING_WATCHDOG_INTERVAL = 60.0
|
||||
POLLING_WATCHDOG_STUCK_AFTER = 300.0
|
||||
RESTART_HINT = "/restart — сброс контекста"
|
||||
CAPTION_LIMIT = 1024
|
||||
|
||||
|
||||
def result_caption(prompt: str, *, limit: int = CAPTION_LIMIT) -> str:
|
||||
value = (prompt or "").strip()
|
||||
suffix = f"\n\n{RESTART_HINT}"
|
||||
available = max(0, limit - len(suffix))
|
||||
if len(value) > available:
|
||||
value = value[: max(0, available - 1)].rstrip()
|
||||
if value:
|
||||
value += "…"
|
||||
return f"{value}{suffix}" if value else RESTART_HINT
|
||||
|
||||
|
||||
def polling_is_stuck(
|
||||
|
|
@ -64,7 +77,7 @@ START_TEXT = (
|
|||
"/balance — баланс генераций.\n"
|
||||
"/invite — пригласить друга.\n"
|
||||
"/status — состояние текущей задачи.\n"
|
||||
"/reset — начать новую сцену."
|
||||
"/restart — сброс контекста."
|
||||
)
|
||||
BLOCKED_TEXT = "Запрос нарушает правила. Звёзды не списаны."
|
||||
AGE_TEXT = (
|
||||
|
|
@ -125,6 +138,7 @@ class MpakoBot:
|
|||
application.add_handler(CommandHandler("status", self._status))
|
||||
application.add_handler(CommandHandler("balance", self._balance))
|
||||
application.add_handler(CommandHandler("invite", self._invite))
|
||||
application.add_handler(CommandHandler("restart", self._reset))
|
||||
application.add_handler(CommandHandler("reset", self._reset))
|
||||
application.add_handler(
|
||||
PreCheckoutQueryHandler(self._pre_checkout)
|
||||
|
|
@ -1284,7 +1298,8 @@ class MpakoBot:
|
|||
if self._bot is None:
|
||||
return
|
||||
|
||||
caption = f"Готово. Seed: {request.seed}" if request.seed is not None else "Готово."
|
||||
prompt = request.enhanced_prompt or request.prompt_text
|
||||
caption = result_caption(prompt)
|
||||
filename = Path(output_path).name
|
||||
try:
|
||||
content = await asyncio.to_thread(Path(output_path).read_bytes)
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
- Реализованы блоки 2–7, базовое хранилище (9), файлы Docker (10), тесты (11), README (12), веб-история (13), улучшение промптов (14), модерация (15), оплата Stars (16), баланс/рефералы (17), управление пользователями (18), возрастной gate (19) и надёжность Telegram (20).
|
||||
- Вживую проверены: T2I (Z-Image), I2I (Krea2), WebSocket-прогресс, улучшение промптов, Docker, CI и веб-история.
|
||||
- 66 тестов: 39 проходят локально без БД, 27 тестов БД выполняются в CI на PostgreSQL через `TEST_DATABASE_URL`. Покрыты workflows, очередь, веб-история, enhancer, модерация, платежи, премиум-очередь, баланс/рефералы, управление пользователями, retry, миграция, watchdog, контекст, админ-панель, скрытие истории.
|
||||
- 69 тестов: 42 проходят локально без БД, 27 тестов БД выполняются в CI на PostgreSQL через `TEST_DATABASE_URL`. Покрыты workflows, очередь, веб-история, enhancer, модерация, платежи, премиум-очередь, баланс/рефералы, управление пользователями, retry, миграция, watchdog, контекст, админ-панель, скрытие истории.
|
||||
- Не проверено: реальная оплата Stars и реферальная выплата в Telegram, очередь из 3+ пользователей, падение ComfyUI, рестарт с `running`-задачей, детекция лица на реальном фото. PostgreSQL-миграция и тесты БД ещё не запускались вживую — это сделает CI и первый деплой.
|
||||
|
||||
## 0. Допущения и решения по умолчанию
|
||||
|
|
@ -387,10 +387,11 @@ ON requests(user_id) WHERE status IN ('queued', 'running');
|
|||
- [x] Снимок контекста сохраняется в `requests` и `pending_payments`.
|
||||
- [x] Следующий текстовый запрос обрабатывается вместе с предыдущим промптом.
|
||||
- [x] Контекст обновляется только после успешной отправки результата.
|
||||
- [x] `/reset` очищает контекст; новое фото начинает новую цепочку.
|
||||
- [x] Тесты БД, enhancer и очереди.
|
||||
- [x] `/restart` очищает контекст; новое фото начинает новую цепочку.
|
||||
- [x] В подписи результата итоговый промпт и подсказка `/restart`.
|
||||
- [x] Тесты БД, enhancer, очереди и подписи.
|
||||
|
||||
**DoD:** продолжение сцены работает по тексту, `/reset` возвращает к новой сцене.
|
||||
**DoD:** продолжение сцены работает по тексту, `/restart` возвращает к новой сцене.
|
||||
|
||||
## 22. Админ-панель и очистка ComfyUI
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from bot import RESTART_HINT, result_caption
|
||||
|
||||
|
||||
def test_result_caption_contains_prompt_and_restart_hint() -> None:
|
||||
caption = result_caption("A red apple on a table")
|
||||
assert caption == f"A red apple on a table\n\n{RESTART_HINT}"
|
||||
|
||||
|
||||
def test_result_caption_truncates_long_prompt() -> None:
|
||||
caption = result_caption("x" * 2000, limit=100)
|
||||
assert len(caption) <= 100
|
||||
assert caption.endswith(RESTART_HINT)
|
||||
assert "…" in caption
|
||||
|
||||
|
||||
def test_result_caption_empty_prompt() -> None:
|
||||
assert result_caption("") == RESTART_HINT
|
||||
Loading…
Reference in New Issue