Wiki
猫Rich-сообщения
Rich-сообщения поддерживают заголовки, абзацы, списки, таблицы, медиа, цитаты, раскрывающиеся секции и формулы. Laniakea поддерживает исходящие деревья InputRichBlock из Bot API 10.2, входящие деревья RichBlock, преобразование в HTML, multipart-загрузки и потоковые черновики.
Пакеты и поток данных
tgapiсодержит wire-типы Telegram и методы API.tgrichсодержит конструкторыtgapi.RichTextиtgapi.InputRichBlock, валидацию и преобразование в HTML.- Исходящие сообщения используют
tgapi.InputRichMessage. Должно быть задано ровно одно из полейBlocks,HTMLилиMarkdown. - Входящие сообщения используют
Message.RichMessageс узламиtgapi.RichBlockиtgapi.RichText.
Исходящие и входящие типы блоков намеренно разделены. InputRichBlock* описывает данные, принимаемые Telegram, а RichBlock* — нормализованное дерево, возвращаемое Telegram.
Отправка из обработчика
MessageContext.RichAnswer принимает input-блоки и собирает валидированное HTML rich-сообщение:
import (
"git.scuroneko.dev/scuroneko/laniakea/tgrich"
)
func report(ctx *laniakea.MessageContext, _ struct{}) error {
ctx.RichAnswer(
tgrich.H1(tgrich.Text("Дневной отчёт")),
tgrich.P(tgrich.Concat(
tgrich.Text("Статус: "),
tgrich.Bold(tgrich.Text("всё работает")),
)),
tgrich.Ul(
tgrich.NewListItem(tgrich.P(tgrich.Text("бэкапы"))).
SetCheckbox().SetChecked().Build(),
tgrich.NewListItem(tgrich.P(tgrich.Text("миграция"))).
SetCheckbox().Build(),
),
)
return nil
}
RichAnswerKeyboard(keyboard, blocks...) отправляет те же блоки с inline-клавиатурой.
Сборка текста и блоков
Inline-конструкторы: Text, Concat, Bold, Italic, Underline, Strikethrough, Spoiler, Code, Marked, Subscript, Superscript, URL, Email, Phone, TextMention, Mention, Hashtag, Cashtag, BotCommand, Emoji, DateTime, MathExpression, anchors и references.
Блочные конструкторы: P, H1-H6, Pre, CodeBlock, Footer, Hr, Math, Anchor, Ul, Ol, цитаты, коллажи, слайд-шоу, таблицы, details, карты, анимации, аудио, фото, видео, голосовые сообщения и доступный только в черновиках блок Thinking.
Для элементов списков и таблиц используются небольшие builders:
ordered := tgrich.Ol(
tgrich.OlOpts{Start: 3, Type: tgapi.InputRichBlockListItemTypeLower},
tgrich.NewListItem(tgrich.P(tgrich.Text("третий"))).Build(),
)
table := tgrich.NewTable(
tgrich.Row(
tgrich.CellWithText(tgrich.Text("Имя")).SetHeader().Build(),
tgrich.CellWithText(tgrich.Text("Значение")).SetHeader().Build(),
),
tgrich.Row(
tgrich.CellWithText(tgrich.Text("Статус")).Build(),
tgrich.CellWithText(tgrich.Bold(tgrich.Text("ОК"))).Build(),
),
).SetBordered(true).Build()
Block payload и преобразование в HTML
Если преобразование не требуется, отправляйте input-дерево напрямую:
rich := tgapi.InputRichMessage{
Blocks: []tgapi.InputRichBlock{
tgrich.H1(tgrich.Text("Отчёт")),
tgrich.P(tgrich.Text("Готово")),
},
}
tgrich.BuildHTML(blocks...) валидирует целое дерево и преобразует его в HTML-вариант InputRichMessage. tgrich.ToHTML(block) — сокращённая форма для одного блока. Преобразование полезно для логов, превью и API вроде MessageContext.RichAnswer, которые отправляют отрендеренный HTML.
BuildHTML включает SkipEntityDetection, экранирует текст и атрибуты и проверяет официальные лимиты Telegram:
- 32768 UTF-8 символов;
- 500 блоков, включая вложенные блоки, элементы списков и строки таблиц;
- 16 общих уровней вложенных блоков и форматирования;
- 50 media attachments;
- 20 колонок таблицы с учётом
colspan.
Также проверяются discriminators блоков, размеры заголовков, типы маркеров и checkbox-состояние списков, выравнивание и spans таблиц, координаты/zoom/размеры карт и типы медиа.
Медиа и multipart-загрузки
Медиа-конструкторы принимают tgapi.InputMedia, поэтому поле Media может содержать HTTP URL, Telegram file_id или ссылку attach://name:
block := tgrich.PhotoWithCaption(
tgapi.InputMedia{Media: "telegram-file-id"},
tgrich.CaptionWithCredit(
tgrich.Text("Запуск"),
tgrich.Text("Эксплуатация"),
),
)
При преобразовании в HTML медиа-блоки превращаются в ссылки tg://photo?id=..., tg://video?id=... или tg://audio?id=.... Исходные значения InputMedia собираются в InputRichMessage.Media со стабильными идентификаторами media_1, media_2, ...
Для multipart-загрузки имя после attach:// должно совпадать с именем multipart-поля:
rich, err := tgrich.BuildHTML(
tgrich.Photo(tgapi.InputMedia{Media: "attach://report"}),
)
if err != nil {
return err
}
_, err = uploader.SendRichMessage(
tgapi.SendRichMessage{ChatID: chatID, RichMessage: rich},
tgapi.NewUploaderFile("report.jpg", data).SetAttachName("report"),
)
Та же схема загрузки доступна через Uploader.SendRichMessageDraft.
Прямой доступ через API
API.SendRichMessageотправляет завершённое rich-сообщение.API.SendRichMessageDraftобновляет эфемерное превью во время генерации.Thinkingдопустим только в черновиках.Uploader.SendRichMessageиUploader.SendRichMessageDraftзагружают файлы, указанные черезattach://.EditMessageText.RichMessageредактирует существующее rich-сообщение; оставьтеTextпустым.InputRichMessageContentзадаёт rich-контент для inline-результатов.
Приём
Message.RichMessage разбирается автоматически. Обходите принятое дерево через type switch:
for _, block := range msg.RichMessage.Blocks {
switch b := block.(type) {
case tgapi.RichBlockWrap: // paragraph, footer, thinking
handleText(b.Text)
case tgapi.RichBlockList:
for _, item := range b.Items {
// Label — готовый серверный маркер: "1.", "c.", "vii." или "•".
}
}
}
Неизвестные будущие узлы с полем text сохраняются как RichTextWrap или RichBlockWrap, поэтому parser переносит совместимые расширения Bot API.
Подводные камни
InputRichBlock*и входящиеRichBlock*— разные семейства типов.Thinkingможно отправлять только черезsendRichMessageDraft.- У отмеченного элемента списка обязательно должен быть checkbox.
- Ordered items требуют поддерживаемого типа маркера; unordered items не должны задавать
Value. - Ширина таблицы учитывает column spans.
BuildHTMLвозвращает ошибки валидации до API-запроса; для их классификации используйтеerrors.Isс экспортируемыми значениямиtgrich.ErrRich*.
Что читать дальше
- MessageContext — вспомогательные методы ответа.
- tgapi-Overview — низкоуровневый API-клиент.
- Drafts — поэтапная генерация сообщений.
Navigation
Start here
Runtime and Architecture
- Bot-Lifecycle
- Webhook-Runtime
- Middleware
- Runners
- Error-Handling
- Logging
- Update-Routing-Model
- Policies
- Scenes
Interaction and Telegram API
- Inline-Keyboards-and-Payloads
- Auto-Generated-Commands
- Drafts
- Rich-Messages
- Localization
- Rate-Limiting
- tgapi-Overview