feat: /help разбита на разделы с навигацией инлайн-кнопками (aiogram 3.31.0)
- requirements.txt: aiogram 3.26.0 -> 3.31.0 (нативный send_rich_message + edit_message_text(rich_message=...)) - help_message.py: HELP_RICH_HTML -> HELP_SECTIONS (6 разделов) + help_menu_html/help_section_html/help_view/help_plain_view - навигация на HTML-тегах <tg-button-row>/<tg-button type="callback_data"> (в меню 2 кнопки в ряд, в разделе «В меню» + «Предыдущий»/«Следующий») - bot.py: самописный raw-запрос sendRichMessage заменён на bot.send_rich_message; edit_rich_message + callback help_navigation - онбординг по-прежнему вызывает help_command — кнопки появляются и там - тест поймал реальный баг: в help_navigation пропущен await у edit_rich_message - 58 тестов, VERSION 0.1.0+23
This commit is contained in:
1 parent
0ff0e1abe7
commit
c85f0a34fe
7 files changed
+236
-69
No files matched your search
@@ -8,17 +8,16 @@ import sqlite3
|
||||
from contextlib import asynccontextmanager, nullcontext
|
||||
from pathlib import Path
|
||||
|
||||
import aiohttp
|
||||
from aiogram import Bot, Dispatcher, F, Router
|
||||
from aiogram.client.session.aiohttp import AiohttpSession
|
||||
from aiogram.client.telegram import TEST
|
||||
from aiogram.filters import CommandStart
|
||||
from aiogram.types import Message
|
||||
from aiogram.types import CallbackQuery, InputRichMessage, Message
|
||||
|
||||
import user_store
|
||||
|
||||
from apinex_client import APINEX_STT_URL, POST_HISTORY_CHAR_LIMIT, POST_HISTORY_LIMIT, classify_intent, create_tone_profile, extract_posts_from_images, extract_transcript, generate_ideas, generate_posts, transcribe_audio
|
||||
from help_message import HELP_RICH_HTML, WELCOME_RICH_HTML, rich_to_plain
|
||||
from help_message import WELCOME_RICH_HTML, help_plain_view, help_view, rich_to_plain
|
||||
from user_store import (
|
||||
add_post_samples,
|
||||
clear_user_data,
|
||||
@@ -114,41 +113,49 @@ async def notify_development_deploy(bot: Bot) -> None:
|
||||
logger.info("Development deploy notice sent: version=%s", VERSION)
|
||||
|
||||
|
||||
async def send_rich_html(message: Message, rich_html: str, stage: str = "помощи") -> bool:
|
||||
async def send_rich_message(message: Message, rich_html: str, stage: str) -> Message | None:
|
||||
bot = message.bot
|
||||
payload = {"chat_id": message.chat.id, "rich_message": {"html": rich_html}}
|
||||
if message.message_thread_id is not None:
|
||||
payload["message_thread_id"] = message.message_thread_id
|
||||
url = bot.session.api.api_url(token=bot.token, method="sendRichMessage")
|
||||
timeout = aiohttp.ClientTimeout(total=15)
|
||||
try:
|
||||
async with aiohttp.ClientSession(timeout=timeout) as session:
|
||||
async with session.post(
|
||||
url, json=payload,
|
||||
headers={"User-Agent": "Mozilla/5.0 (compatible; SocialPostWriterBot/1.0)"},
|
||||
) as response:
|
||||
data = await response.json(content_type=None)
|
||||
if response.status == 200 and data.get("ok"):
|
||||
return True
|
||||
logger.warning("Rich %s rejected with HTTP %s", stage, response.status)
|
||||
return False
|
||||
sent = await bot.send_rich_message(
|
||||
chat_id=message.chat.id,
|
||||
rich_message=InputRichMessage(html=rich_html),
|
||||
message_thread_id=message.message_thread_id,
|
||||
)
|
||||
return sent
|
||||
except Exception as exc:
|
||||
logger.warning("Rich %s delivery error (%s): %s", stage, type(exc).__name__, str(exc)[:160])
|
||||
return False
|
||||
|
||||
|
||||
async def send_rich_message(message: Message, rich_html: str, stage: str) -> None:
|
||||
try:
|
||||
sent = await send_rich_html(message, rich_html, stage)
|
||||
except Exception as exc:
|
||||
sent = False
|
||||
logger.warning("Rich %s send failed (%s): %s", stage, type(exc).__name__, str(exc)[:180])
|
||||
if DEPLOY_ENV == "development":
|
||||
await report_error(message, f"отправка Rich Message: {stage}", exc)
|
||||
if not sent:
|
||||
if DEPLOY_ENV == "development":
|
||||
await report_error(message, f"отправка Rich Message: {stage}", RuntimeError("sendRichMessage returned false"))
|
||||
await message.answer(rich_to_plain(rich_html))
|
||||
await message.answer(help_plain_view(None) if stage == "помощи" else rich_to_plain(rich_html))
|
||||
return None
|
||||
|
||||
|
||||
async def edit_rich_message(message: Message, rich_html: str) -> bool:
|
||||
bot = message.bot
|
||||
if message.message_id is None:
|
||||
return False
|
||||
try:
|
||||
await bot.edit_message_text(
|
||||
chat_id=message.chat.id,
|
||||
message_id=message.message_id,
|
||||
rich_message=InputRichMessage(html=rich_html),
|
||||
)
|
||||
return True
|
||||
except Exception as exc:
|
||||
logger.warning("Rich help edit failed (%s): %s", type(exc).__name__, str(exc)[:180])
|
||||
return False
|
||||
|
||||
|
||||
@router.callback_query(F.data.startswith("help:"))
|
||||
async def help_navigation(callback: CallbackQuery) -> None:
|
||||
message = callback.message
|
||||
if not isinstance(message, Message):
|
||||
return
|
||||
section = (callback.data or "help:menu").split(":", 1)[1]
|
||||
if not await edit_rich_message(message, help_view(section)):
|
||||
await callback.answer("Не удалось обновить справку, открой /help заново", show_alert=True)
|
||||
return
|
||||
await callback.answer()
|
||||
|
||||
|
||||
@router.message(CommandStart())
|
||||
@@ -234,7 +241,7 @@ async def clear_command(message: Message) -> None:
|
||||
|
||||
|
||||
async def help_command(message: Message) -> None:
|
||||
await send_rich_message(message, HELP_RICH_HTML, "помощи")
|
||||
await send_rich_message(message, help_view(None), "помощи")
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user