init
This commit is contained in:
commit
ec1112e162
22 changed files with 837 additions and 0 deletions
66
bot/services/formatter.py
Normal file
66
bot/services/formatter.py
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
import re
|
||||
|
||||
MAX_MSG_LEN = 4000
|
||||
|
||||
|
||||
def _escape_md2(text: str) -> str:
|
||||
"""Escape special chars for MarkdownV2, preserving bold/headers/bullets."""
|
||||
# We use HTML instead — MarkdownV2 escaping is too fragile
|
||||
raise NotImplementedError("Use HTML mode")
|
||||
|
||||
|
||||
def _md_to_html(text: str) -> str:
|
||||
"""Minimal Markdown-to-HTML for Telegram's supported subset."""
|
||||
# Bold: **text** or __text__
|
||||
text = re.sub(r"\*\*(.+?)\*\*", r"<b>\1</b>", text)
|
||||
text = re.sub(r"__(.+?)__", r"<b>\1</b>", text)
|
||||
# Italic: *text* (but not inside bold tags)
|
||||
text = re.sub(r"(?<!</b>)\*(.+?)\*(?!<)", r"<i>\1</i>", text)
|
||||
# Inline code
|
||||
text = re.sub(r"`(.+?)`", r"<code>\1</code>", text)
|
||||
# Headers: ## Title -> bold
|
||||
text = re.sub(r"^#{1,3}\s+(.+)$", r"<b>\1</b>", text, flags=re.MULTILINE)
|
||||
# Escape HTML entities in remaining text (but preserve our tags)
|
||||
# Already handled — Telegram is lenient with unescaped text in HTML mode
|
||||
return text
|
||||
|
||||
|
||||
def split_report(report: str) -> list[str]:
|
||||
"""Split a report into Telegram-safe HTML messages."""
|
||||
html = _md_to_html(report)
|
||||
|
||||
if len(html) <= MAX_MSG_LEN:
|
||||
return [html]
|
||||
|
||||
# Split on section boundaries (bold headers on their own line)
|
||||
sections = re.split(r"(?=\n<b>[^<]+</b>\n)", html)
|
||||
|
||||
messages: list[str] = []
|
||||
current = ""
|
||||
|
||||
for section in sections:
|
||||
if not section.strip():
|
||||
continue
|
||||
if len(current) + len(section) > MAX_MSG_LEN:
|
||||
if current.strip():
|
||||
messages.append(current.strip())
|
||||
# If a single section is too long, split on paragraphs
|
||||
if len(section) > MAX_MSG_LEN:
|
||||
paragraphs = section.split("\n\n")
|
||||
current = ""
|
||||
for para in paragraphs:
|
||||
if len(current) + len(para) + 2 > MAX_MSG_LEN:
|
||||
if current.strip():
|
||||
messages.append(current.strip())
|
||||
current = para + "\n\n"
|
||||
else:
|
||||
current += para + "\n\n"
|
||||
else:
|
||||
current = section
|
||||
else:
|
||||
current += section
|
||||
|
||||
if current.strip():
|
||||
messages.append(current.strip())
|
||||
|
||||
return messages if messages else [html[:MAX_MSG_LEN]]
|
||||
Loading…
Add table
Add a link
Reference in a new issue