refactor: unify Telegram delivery and add quality checks
This commit is contained in:
@@ -22,7 +22,6 @@ from .telegram_utils import (
|
||||
get_tz,
|
||||
get_voice_max_duration,
|
||||
markdown_code,
|
||||
reply_long,
|
||||
reply_markdown,
|
||||
require_user_id,
|
||||
)
|
||||
@@ -118,7 +117,7 @@ async def history_command(update: Update, context: ContextTypes.DEFAULT_TYPE) ->
|
||||
f"{str(row['content']) if row['role'] == 'assistant' else escape_markdown_text(row['content'])}"
|
||||
for row in rows
|
||||
)
|
||||
await reply_long(update.message, text)
|
||||
await reply_markdown(update.message, text)
|
||||
|
||||
|
||||
async def ask_command(update: Update, context: ContextTypes.DEFAULT_TYPE) -> None:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import asyncio
|
||||
import logging
|
||||
import re
|
||||
from collections.abc import AsyncIterator
|
||||
from collections.abc import AsyncIterator, Awaitable, Callable
|
||||
from contextlib import asynccontextmanager, suppress
|
||||
from uuid import uuid4
|
||||
from zoneinfo import ZoneInfo
|
||||
@@ -174,6 +174,30 @@ def _with_markdown_notice(markdown_v2: str) -> str:
|
||||
|
||||
|
||||
async def reply_markdown(message: Message, markdown: str) -> Message:
|
||||
async def send_formatted(text: str) -> Message:
|
||||
return await message.reply_text(
|
||||
text,
|
||||
parse_mode=ParseMode.MARKDOWN_V2,
|
||||
)
|
||||
|
||||
async def send_plain(text: str) -> Message:
|
||||
return await message.reply_text(text)
|
||||
|
||||
return await _send_markdown_chunks(
|
||||
markdown,
|
||||
send_formatted,
|
||||
send_plain,
|
||||
)
|
||||
|
||||
|
||||
MarkdownSender = Callable[[str], Awaitable[Message]]
|
||||
|
||||
|
||||
async def _send_markdown_chunks(
|
||||
markdown: str,
|
||||
send_formatted: MarkdownSender,
|
||||
send_plain: MarkdownSender,
|
||||
) -> Message:
|
||||
chunks, formatting_failed = _prepare_chunks(markdown)
|
||||
first_message: Message | None = None
|
||||
|
||||
@@ -185,17 +209,14 @@ async def reply_markdown(message: Message, markdown: str) -> Message:
|
||||
else markdown_v2
|
||||
)
|
||||
try:
|
||||
sent = await message.reply_text(
|
||||
formatted_text,
|
||||
parse_mode=ParseMode.MARKDOWN_V2,
|
||||
)
|
||||
sent = await send_formatted(formatted_text)
|
||||
except BadRequest:
|
||||
logger.warning("Telegram rejected MarkdownV2; retrying as plain text")
|
||||
formatting_failed = True
|
||||
fallback_text = (
|
||||
_with_fallback_notice(plain_text) if is_last else plain_text
|
||||
)
|
||||
sent = await message.reply_text(fallback_text)
|
||||
sent = await send_plain(fallback_text)
|
||||
if first_message is None:
|
||||
first_message = sent
|
||||
|
||||
@@ -204,38 +225,25 @@ async def reply_markdown(message: Message, markdown: str) -> Message:
|
||||
|
||||
|
||||
async def edit_markdown(message: Message, markdown: str) -> None:
|
||||
await edit_or_reply(message, markdown)
|
||||
await _edit_or_reply(message, markdown)
|
||||
|
||||
|
||||
async def send_markdown(bot: Bot, chat_id: int, markdown: str) -> Message:
|
||||
chunks, formatting_failed = _prepare_chunks(markdown)
|
||||
first_message: Message | None = None
|
||||
|
||||
for index, (markdown_v2, plain_text) in enumerate(chunks):
|
||||
is_last = index == len(chunks) - 1
|
||||
formatted_text = (
|
||||
_with_markdown_notice(markdown_v2)
|
||||
if is_last and formatting_failed
|
||||
else markdown_v2
|
||||
async def send_formatted(text: str) -> Message:
|
||||
return await bot.send_message(
|
||||
chat_id=chat_id,
|
||||
text=text,
|
||||
parse_mode=ParseMode.MARKDOWN_V2,
|
||||
)
|
||||
try:
|
||||
sent = await bot.send_message(
|
||||
chat_id=chat_id,
|
||||
text=formatted_text,
|
||||
parse_mode=ParseMode.MARKDOWN_V2,
|
||||
)
|
||||
except BadRequest:
|
||||
logger.warning("Telegram rejected MarkdownV2; retrying as plain text")
|
||||
formatting_failed = True
|
||||
fallback_text = (
|
||||
_with_fallback_notice(plain_text) if is_last else plain_text
|
||||
)
|
||||
sent = await bot.send_message(chat_id=chat_id, text=fallback_text)
|
||||
if first_message is None:
|
||||
first_message = sent
|
||||
|
||||
assert first_message is not None
|
||||
return first_message
|
||||
async def send_plain(text: str) -> Message:
|
||||
return await bot.send_message(chat_id=chat_id, text=text)
|
||||
|
||||
return await _send_markdown_chunks(
|
||||
markdown,
|
||||
send_formatted,
|
||||
send_plain,
|
||||
)
|
||||
|
||||
|
||||
def make_article(
|
||||
@@ -300,11 +308,7 @@ def require_user_id(update: Update) -> int | None:
|
||||
return None
|
||||
|
||||
|
||||
async def reply_long(message: Message, text: str) -> None:
|
||||
await reply_markdown(message, text)
|
||||
|
||||
|
||||
async def edit_or_reply(message: Message, text: str) -> None:
|
||||
async def _edit_or_reply(message: Message, text: str) -> None:
|
||||
chunks, formatting_failed = _prepare_chunks(text)
|
||||
|
||||
for index, (markdown_v2, plain_text) in enumerate(chunks):
|
||||
|
||||
Reference in New Issue
Block a user