Files

102 lines
8.2 KiB
Python
Raw Permalink 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.
from __future__ import annotations
import html
WELCOME_RICH_HTML = """<h1>Привет!</h1>
<p>Я помогаю писать посты для соцсетей.</p>
<p>Сначала познакомь меня с твоим аккаунтом. Пришли примеры публикаций и расскажи, о чём ты пишешь и для кого. Это поможет мне лучше понимать темы, аудиторию и подачу.</p>
<p>Потом можешь в любое время дополнять «Обучение» новыми постами и информацией об аккаунте. Я буду учитывать всё это в дальнейшей работе.</p>
<p>Когда понадобится новый пост, открой «Генерацию» и отправь запрос. Я предложу несколько вариантов черновика, которые можно самостоятельно опубликовать в нужной социальной сети.</p>
<p>Для начала выбери «Обучение» в меню ниже.</p>
"""
HELP_MENU_TITLE = "Помощь по боту"
HELP_MENU_INTRO = "Выбери раздел — откроется только он. Из любого раздела можно перейти в любой."
HELP_SECTIONS: dict[str, tuple[str, str]] = {
"posts": (
"✍️ Написать пост",
"""<ol>
<li>В разделе «Генерация» напиши сообщение или отправь голосовое с прямой просьбой, например: «Придумай пост для Telegram про запуск нового продукта».</li>
<li>Можешь указать площадку, аудиторию, факты, длину, цель и другие требования. Можно надиктовать подробное ТЗ или просто тему.</li>
<li>Я распознаю речь, проверю, просишь ли ты именно написать пост, и верну три варианта отдельными сообщениями.</li>
</ol>
<p>В сообщениях с вариантами будет только текст поста: без нумерации и вступлений, с абзацами, переносами строк и уместными эмодзи.</p>""",
),
"tone": (
"🎨 Tone of Voice",
"""<p>Пришли скриншоты постов, текстовые примеры или просто расскажи об аккаунте. Можно отправить голосовое или аудиофайл. Я буду постепенно накапливать и обновлять профиль аккаунта и Tone of Voice; новые сведения дополняют прежние.</p>
<p>Чтобы начать обучение заново и удалить накопленное, нажми «Сбросить данные» и подтверди действие.</p>""",
),
"edit": (
"✏️ Правка поста",
"""<p>Ответь реплаем на сообщение с вариантом и укажи, что изменить. Например: «Сделай короче и добавь призыв». Я учту оригинальный текст и верну три новых варианта отдельными сообщениями.</p>""",
),
"idea": (
"💡 Идея для поста",
"""<p>Напиши «предложи идею для поста», «о чём написать?» или «накидай тему» — верну одну идею. Команда <code>/idea</code> работает так же.</p>
<p>Идеи сохраняются, чтобы не повторяться: каждая новая идея отличается от предыдущих.</p>""",
),
"subscription": (
"💳 Подписка",
"""<p>У тебя есть пробный период — 3 дня бесплатно. Дальше — подписка на 30 дней за 100 звёзд.</p>
<ul>
<li><code>/balance</code> — узнать статус: сколько осталось дней триала или подписки.</li>
<li><code>/subscribe</code> — оплатить подписку на 30 дней.</li>
</ul>
<p>При открытии раздела «Подписка» бот сразу показывает активный период и сколько дней осталось. Нажми «Продлить подписку», чтобы открыть счёт в звёздах. Когда период закончится, генерация постов и идей станет недоступна.</p>""",
),
"commands": (
"⌨️ Команды",
"""<p>Основные команды доступны в любом разделе: <code>/start</code> — главное меню; <code>/training</code> — настройка стиля; <code>/generate</code> — создание постов; <code>/subscription</code> — подписка; <code>/help</code> — помощь.</p>
<p>Действия открываются в соответствующем разделе: <code>/style</code> и <code>/clear</code> — настройка стиля; <code>/post</code> и <code>/idea</code> — создание постов; <code>/balance</code> и <code>/subscribe</code> — подписка. <code>/clear</code> и кнопка «Сбросить данные» сначала запрашивают подтверждение; подписка и пробный период не меняются.</p>
<p>Для создания поста можно попросить идею обычными словами: «предложи идею для поста», «о чём написать?», «накидай тему».</p>""",
),
"support": (
"🆘 Поддержка",
"""<p>В разделе «Помощь» нажми «🆘 Поддержка» или отправь <code>/support</code>. В ответ придёт приветствие оператора — напиши текстом, чем помочь; можно приложить фото, документ или голосовое.</p>
<p>Оператор видит твоё сообщение и отвечает прямо в этом чате. Можно вернуться к обращению позже и дописать.</p>
<p>Кнопка «Главное меню» завершает обращение. Оно не удаляется: при следующем нажатии «Поддержка» оператор увидит всю историю.</p>""",
),
}
HELP_SECTION_ORDER: tuple[str, ...] = tuple(HELP_SECTIONS)
def help_menu_html(current: str | None = None) -> str:
return (
f"<h1>{HELP_MENU_TITLE}</h1>"
f"<p>{HELP_MENU_INTRO}</p>"
f"<p>Я помогаю писать и редактировать посты для соцсетей. "
f"Генерирую посты только по явной просьбе.</p>"
)
def help_section_html(section: str) -> str:
title, body = HELP_SECTIONS[section]
return f"<h1>{title}</h1>{body}"
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"<li(?:\s[^>]*)?>", "• ", rich_html, flags=re.IGNORECASE)
text = re.sub(r"</?(?:h[1-6]|p|ul|ol|li|hr|table|tr|td|th|input)(?:\s[^>]*)?/?>", "\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())