from __future__ import annotations import html WELCOME_RICH_HTML = """

Привет! Я — бот для написания постов

Помогаю писать и редактировать посты для соцсетей. Расскажи, о чём нужен пост, а я верну три варианта: короткий, развёрнутый и с призывом к действию.

Примеры запросов

Выбери режим в нижнем меню: «Обучение», «Генерация», «Подписка» или «Помощь». Внутри режима кнопка «Главное меню» возвращает сюда. Команда /start тоже открывает главное меню.

В режиме «Обучение» пришли скриншоты своих постов; в режиме «Генерация» попроси идею или пост.

""" HELP_MENU_TITLE = "Помощь по боту" HELP_MENU_INTRO = "Выбери раздел — откроется только он. Из любого раздела можно перейти в любой." HELP_SECTIONS: dict[str, tuple[str, str]] = { "posts": ( "✍️ Написать пост", """
  1. В режиме «Генерация» напиши сообщение или отправь голосовое с прямой просьбой, например: «Придумай пост для Telegram про запуск нового продукта».
  2. Можешь указать площадку, аудиторию, факты, длину, цель и другие требования. Можно надиктовать подробное ТЗ или просто тему.
  3. Я распознаю речь, проверю, просишь ли ты именно написать пост, и верну три варианта отдельными сообщениями.

В сообщениях с вариантами будет только текст поста: без нумерации и вступлений, с абзацами, переносами строк и уместными эмодзи.

""", ), "tone": ( "🎨 Tone of Voice", """

Пришли скриншоты постов, текстовые примеры или просто расскажи об аккаунте. Можно отправить голосовое или аудиофайл. Я буду постепенно накапливать и обновлять профиль аккаунта и Tone of Voice; новые сведения дополняют прежние.

Чтобы начать обучение заново и удалить накопленное, нажми «Сбросить данные» и подтверди действие.

""", ), "edit": ( "✏️ Правка поста", """

Ответь реплаем на сообщение с вариантом и укажи, что изменить. Например: «Сделай короче и добавь призыв». Я учту оригинальный текст и верну три новых варианта отдельными сообщениями.

""", ), "idea": ( "💡 Идея для поста", """

Напиши «предложи идею для поста», «о чём написать?» или «накидай тему» — верну одну идею. Команда /idea работает так же.

Идеи сохраняются, чтобы не повторяться: каждая новая идея отличается от предыдущих.

""", ), "subscription": ( "💳 Подписка", """

У тебя есть пробный период — 3 дня бесплатно. Дальше — подписка на 30 дней за 100 звёзд.

При входе в режим «Подписка» бот сразу показывает активный период и сколько дней осталось. Нажми «Продлить подписку», чтобы сразу открыть счёт в звёздах. Когда период закончится, генерация постов и идей станет недоступна.

""", ), "commands": ( "⌨️ Команды", """

Команды-переключатели доступны в любом режиме: /start — главное меню; /training — обучение; /generate — генерация; /subscription — подписка; /help — помощь.

Действия доступны только в своём режиме: /style и /clear — обучение; /post и /idea — генерация; /balance и /subscribe — подписка. /clear и кнопка «Сбросить данные» сначала запрашивают подтверждение; подписка и триал не меняются.

В режиме «Генерация» можно попросить идею обычными словами: «предложи идею для поста», «о чём написать?», «накидай тему».

""", ), "support": ( "🆘 Поддержка", """

В режиме «Помощь» нажми «🆘 Поддержка» или отправь /support. В ответ придёт приветствие оператора — напиши текстом, чем помочь; можно приложить фото, документ или голосовое.

Оператор видит твоё сообщение и отвечает прямо в этом чате. Переписка продолжается в том же обращении: можно отвлечься на другие режимы, вернуться и дописать.

Кнопка «Главное меню» завершает обращение. Оно не удаляется: при следующем нажатии «Поддержка» оператор увидит всю историю.

""", ), } HELP_SECTION_ORDER: tuple[str, ...] = tuple(HELP_SECTIONS) HELP_BUTTON_ROW_WIDTH = 24 def _menu_buttons(current: str | None = None) -> str: buttons: list[tuple[str, str]] = [] for section in HELP_SECTION_ORDER: title = HELP_SECTIONS[section][0] if section == current: button = f'{title}' else: button = ( f'' f"{title}" ) buttons.append((title, button)) rows = [] row: list[str] = [] row_width = 0 for title, button in buttons: button_width = len(title) separator_width = 1 if row else 0 if row and row_width + separator_width + button_width > HELP_BUTTON_ROW_WIDTH: rows.append(f'{"".join(row)}') row = [] row_width = 0 separator_width = 0 row.append(button) row_width += separator_width + button_width if row: rows.append(f'{"".join(row)}') return "".join(rows) def help_menu_html(current: str | None = None) -> str: return ( f"

{HELP_MENU_TITLE}

" f"

{HELP_MENU_INTRO}

" f"

Я помогаю писать и редактировать посты для соцсетей. " f"Генерирую посты только по явной просьбе.

" f"{_menu_buttons(current)}" ) def help_section_html(section: str) -> str: title, body = HELP_SECTIONS[section] return f"

{title}

{body}{_menu_buttons(section)}" def help_view(section: str | None = None) -> str: if section and section in HELP_SECTIONS: return help_section_html(section) return help_menu_html(section) def help_plain_view(section: str | None = None) -> str: if section and section in HELP_SECTIONS: title, body = HELP_SECTIONS[section] return f"{HELP_MENU_TITLE} — {title}\n\n{rich_to_plain(body)}" lines = [HELP_MENU_TITLE, HELP_MENU_INTRO] lines += [f"• {HELP_SECTIONS[name][0]}" for name in HELP_SECTION_ORDER] return "\n".join(lines) def rich_to_plain(rich_html: str) -> str: import re text = re.sub(r"]*)?>", "• ", rich_html, flags=re.IGNORECASE) text = re.sub(r"]*)?/?>", "\n", text, flags=re.IGNORECASE) text = re.sub(r"<[^>]+>", "", text) text = html.unescape(text) return "\n".join(line.strip() for line in text.splitlines() if line.strip())