From 6bbd9cc04a6fb222c0af11b8203d1ba00a5e16bf Mon Sep 17 00:00:00 2001 From: MpakobecEx Date: Tue, 20 Oct 2026 01:25:42 +0500 Subject: [PATCH] =?UTF-8?q?=D0=9A=D0=BE=D0=BC=D0=B0=D0=BD=D0=B4=D0=B0=20/c?= =?UTF-8?q?ontext?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Показывает текущий промпт, базовую сцену, последний запрос и время обновления контекста. --- README.md | 2 ++ bot.py | 49 ++++++++++++++++++++++++++++++++++++++++++- checklist.md | 5 +++-- tests/test_context.py | 28 +++++++++++++++++++++++++ 4 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 tests/test_context.py diff --git a/README.md b/README.md index 1f044cd..e8768c2 100644 --- a/README.md +++ b/README.md @@ -204,6 +204,7 @@ TELEGRAM_HEALTH_INTERVAL=60 - `/balance` — текущий баланс. - `/invite` — реферальная ссылка. - `/restart` — сбросить контекст и начать новую сцену (алиас `/reset`). +- `/context` — показать текущий контекст: промпт, базовую сцену и последний запрос. - `/settings` — выбор модели Krea2: стандартная Q4 или улучшенная Q6. - При старте бот проверяет `setMyCommands` и включает кнопку меню с командами. - За первую оплату приглашённого друга начисляется +3 генерации, реферер получает уведомление. @@ -215,6 +216,7 @@ TELEGRAM_HEALTH_INTERVAL=60 - Первый текстовый запрос создаёт контекст: базовую сцену и текущий улучшенный промпт. - Следующий текст обрабатывается вместе с предыдущим промптом: бот сохраняет сцену и применяет только запрошенное изменение. - `/restart` очищает контекст; следующий запрос начнёт новую сцену. +- `/context` показывает текущий промпт, базовую сцену и последний запрос. - Новое фото с подписью автоматически начинает новую цепочку. - Для точного редактирования конкретной картинки ответь на сообщение бота с изображением. - `/restart` не отменяет уже запущенную генерацию: она завершится со своим снимком контекста. diff --git a/bot.py b/bot.py index e84cb46..7a9ef3e 100644 --- a/bot.py +++ b/bot.py @@ -35,7 +35,7 @@ from telegram.ext import ( from comfy_client import ComfyClient from config import Settings, setup_logging -from db import Database, Request, UserAlreadyQueued +from db import Database, Request, UserAlreadyQueued, UserContext from moderation import PromptBlocked, detect_person, is_prompt_allowed from prompt_enhancer import PromptEnhancer from queue_manager import QueueEvent, QueueFull, QueueManager @@ -62,6 +62,34 @@ def commands_need_update( return current_pairs != desired_pairs +def format_context(context: UserContext | None) -> str: + if context is None: + return "Контекст пуст. Следующий запрос начнёт новую сцену." + + parts = ["Текущий контекст:", "", f"Промпт: {context.current_prompt}"] + if ( + context.base_prompt + and context.base_prompt != context.current_prompt + ): + parts.extend(["", f"Базовая сцена: {context.base_prompt}"]) + if context.last_request_id is not None: + mode = f" ({context.last_mode})" if context.last_mode else "" + parts.append( + f"Последний запрос: #{context.last_request_id}{mode}" + ) + if context.updated_at: + try: + updated = datetime.fromisoformat( + context.updated_at + ).astimezone(MSK) + except ValueError: + pass + else: + parts.append(f"Обновлён: {updated.strftime('%d.%m.%Y %H:%M')}") + parts.extend(["", "Сбросить: /restart"]) + return "\n".join(parts) + + def result_caption(prompt: str, *, limit: int = CAPTION_LIMIT) -> str: value = (prompt or "").strip() suffix = f"\n\n{RESTART_HINT}" @@ -93,6 +121,7 @@ START_TEXT = ( "/invite — пригласить друга.\n" "/status — состояние текущей задачи.\n" "/restart — сброс контекста.\n" + "/context — текущий контекст.\n" "/settings — качество Krea2." ) BOT_COMMANDS = ( @@ -101,6 +130,7 @@ BOT_COMMANDS = ( BotCommand("balance", "Баланс генераций"), BotCommand("invite", "Пригласить друга"), BotCommand("status", "Статус текущей задачи"), + BotCommand("context", "Текущий контекст"), BotCommand("settings", "Качество Krea2"), BotCommand("restart", "Сброс контекста"), ) @@ -163,6 +193,9 @@ 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("context", self._context_command) + ) application.add_handler( CommandHandler("settings", self._settings_command) ) @@ -583,6 +616,20 @@ class MpakoBot: ) await self._retry(message.reply_text, text) + async def _context_command( + self, update: Update, context: ContextTypes.DEFAULT_TYPE + ) -> None: + if not await self._check_access(update): + return + message = update.effective_message + user = update.effective_user + if message is None or user is None: + return + user_context = await self._db.get_user_context(user.id) + await self._retry( + message.reply_text, format_context(user_context) + ) + @staticmethod def _quality_keyboard(quality: str) -> InlineKeyboardMarkup: def label(name: str, value: str) -> str: diff --git a/checklist.md b/checklist.md index 5a5bc18..ba90b28 100644 --- a/checklist.md +++ b/checklist.md @@ -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 и веб-история. -- 78 тестов: 50 проходят локально без БД, 28 тестов БД выполняются в CI на PostgreSQL через `TEST_DATABASE_URL`. Покрыты workflows, очередь, веб-история, enhancer, модерация, платежи, премиум-очередь, баланс/рефералы, управление пользователями, retry, миграция, watchdog, контекст, админ-панель, скрытие истории, настройки Krea2. +- 80 тестов: 52 проходят локально без БД, 28 тестов БД выполняются в CI на PostgreSQL через `TEST_DATABASE_URL`. Покрыты workflows, очередь, веб-история, enhancer, модерация, платежи, премиум-очередь, баланс/рефералы, управление пользователями, retry, миграция, watchdog, контекст, админ-панель, скрытие истории, настройки Krea2. - Не проверено: реальная оплата Stars и реферальная выплата в Telegram, очередь из 3+ пользователей, падение ComfyUI, рестарт с `running`-задачей, детекция лица на реальном фото. PostgreSQL-миграция и тесты БД ещё не запускались вживую — это сделает CI и первый деплой. ## 0. Допущения и решения по умолчанию @@ -388,6 +388,7 @@ ON requests(user_id) WHERE status IN ('queued', 'running'); - [x] Следующий текстовый запрос обрабатывается вместе с предыдущим промптом. - [x] Контекст обновляется только после успешной отправки результата. - [x] `/restart` очищает контекст; новое фото начинает новую цепочку. +- [x] `/context` показывает текущий промпт, базовую сцену и последний запрос. - [x] В подписи результата итоговый промпт и подсказка `/restart`. - [x] Тесты БД, enhancer, очереди и подписи. @@ -419,7 +420,7 @@ ON requests(user_id) WHERE status IN ('queued', 'running'); ## 24. Команды и меню - [x] При старте бот получает `getMyCommands` и обновляет список при расхождении. -- [x] `setMyCommands` для `/start`, `/help`, `/balance`, `/invite`, `/status`, `/settings`, `/restart`. +- [x] `setMyCommands` для `/start`, `/help`, `/balance`, `/invite`, `/status`, `/context`, `/settings`, `/restart`. - [x] `setChatMenuButton` включает `MenuButtonCommands` — кнопка меню слева снизу. - [x] Ошибки настройки команд не блокируют запуск бота. - [x] Тесты сравнения команд и идемпотентной настройки. diff --git a/tests/test_context.py b/tests/test_context.py new file mode 100644 index 0000000..ebdb0ce --- /dev/null +++ b/tests/test_context.py @@ -0,0 +1,28 @@ +from __future__ import annotations + +from bot import format_context +from db import UserContext + + +def test_format_context_empty() -> None: + text = format_context(None) + assert "Контекст пуст" in text + + +def test_format_context_shows_prompt_and_reset_hint() -> None: + context = UserContext( + user_id=1, + base_prompt="A red apple on a table", + current_prompt="A blue apple on a table", + last_request_id=42, + last_mode="t2i", + updated_at="2026-10-19T12:00:00+00:00", + ) + + text = format_context(context) + + assert "A blue apple on a table" in text + assert "A red apple on a table" in text + assert "Последний запрос: #42 (t2i)" in text + assert "Обновлён: 19.10.2026 15:00" in text + assert "/restart" in text