Клавиатуры и форматирование
В этом разделе описывается работа с клавиатурами (inline-кнопками), форматированием текста и встроенной системой пагинации в Yandex Bot API.
Клавиатуры (Suggest Buttons)
API Яндекса поддерживает клавиатуры, которые отображаются под сообщением пользователя. Вы можете создавать их как одномерный список (в один ряд) или в виде двумерной сетки (в несколько рядов).
Для этого используются функции:
yabotapi.NewSuggestButtons(persist bool, buttons ...InlineSuggestButton)— для создания простого ряда кнопок.yabotapi.NewSuggestButtonsGrid(persist bool, rows ...[]InlineSuggestButton)— для создания многоуровневой сетки кнопок.
Флаг Persist (Поведение клавиатуры)
Первым аргументом в функции создания клавиатуры передается флаг persist, который отвечает за ее долговечность:
false(Одноразовая): Клавиатура исчезает после того, как пользователь нажимает на любую кнопку или отправляет текстовое сообщение в чат. Это стандартное поведение для опросов или быстрых ответов.true(Постоянная): Клавиатура остается прикрепленной к полю ввода и не исчезает после взаимодействия. Пользователь может нажимать на кнопки многократно.
Директивы и удобные хелперы кнопок
Для максимального упрощения создания кнопок в библиотеке предусмотрены готовые функции-конструкторы:
yabotapi.NewSimpleActionButton(title, actionName string)— создает простую кнопку действия без нагрузкиpayload.yabotapi.NewActionButton(title, actionName string, payload any)— создает кнопку действия с контекстной полезной нагрузкойpayload.yabotapi.NewURLButton(title, uri string)— создает кнопку-ссылку, открывающую внешнюю URL (NewOpenURIDirective).yabotapi.NewTextButton(title, text string)— создает кнопку быстрой отправки текста (NewSendMessageDirective).
Вы также можете конструировать кастомные директивы напрямую:
yabotapi.NewOpenURIDirective(uri string)yabotapi.NewSendMessageDirective(text string, payload any)yabotapi.NewServerActionDirective(name string, payload any)yabotapi.NewSetElementsStateDirective(ids []string, state string, timeout int)
Динамическое построение клавиатур (KeyboardBuilder)
Для удобной сборки кнопочных сеток в циклах или динамических меню используется KeyboardBuilder:
.Columns(cols int)— задает максимальное число кнопок в одном ряду..AddSimpleButton(title, actionName)— добавляет кнопку клика..AddButton(title, actionName, payload)— добавляет кнопку с payload..AddURLButton(title, uri)— добавляет кнопку-ссылку..AddTextButton(title, text)— добавляет текстовую кнопку..AddRawButton(btn)— добавляет произвольно сконструированнуюInlineSuggestButton..AddRow(buttons...)— добавляет готовый ряд кнопок..Build() *SuggestButtons— результирует готовую к отправке клавиатуру.
kb := yabotapi.NewKeyboardBuilder(true).Columns(2) // 2 кнопки в каждом ряду
for _, product := range products {
kb.AddButton(product.Name, "buy_product", product.ID)
}
keyboard := kb.Build()
Пример создания клавиатуры
package main
import (
yabotapi "github.com/go-yandex-bot-api/yandex-bot-api"
"github.com/go-yandex-bot-api/yandex-bot-api/types"
"github.com/go-yandex-bot-api/yandex-bot-api/pkg/router"
)
func sendKeyboard(c *router.Context) error {
keyboard := yabotapi.NewSuggestButtonsGrid(
true, // persist = true (клавиатура не исчезнет после нажатия)
[]types.InlineSuggestButton{
yabotapi.NewSimpleActionButton("Поздороваться", "btn_hi"),
yabotapi.NewSimpleActionButton("Попрощаться", "btn_bye"),
},
[]types.InlineSuggestButton{
yabotapi.NewURLButton("Открыть Яндекс", "https://ya.ru"),
yabotapi.NewTextButton("Отправить контакты", "Покажи контакты"),
},
)
return c.ReplyWithKeyboard("Выберите действие:", keyboard)
}
}
Форматирование текста
Яндекс Мессенджер использует свой диалект Markdown для разметки сообщений. Чтобы не запоминать синтаксис и случайно не забыть экранировать спецсимволы, библиотека предоставляет готовый пакет pkg/format.
import "github.com/go-yandex-bot-api/yandex-bot-api/pkg/format"
1. Атомарные функции форматирования
format.Escape(text string)— Экранирование специальных символов Markdown (*,_,~,+,`,[,],\).format.Bold(text string)— Жирный текст (**text**).format.Italic(text string)— Курсив (__text__).format.Strikethrough(text string)—Зачеркнутыйтекст (~~text~~).format.Underline(text string)— ++Подчеркнутый++ текст (++text++).format.Code(text string)— Строчный фрагмент кода.format.CodeBlock(text, language string)— Многострочный блок кода с поддержкой подсветки синтаксиса.format.Link(text, url string)— Кликабельная ссылка.format.Quote(text string)— Цитата (> text). Поддерживает многострочный текст.format.BulletList(items []string)— Маркированный список (• item).format.NumberedList(items []string)— Нумерованный список (1. item).format.Header(text string)— Заголовок первого уровня (# text).format.HeaderLevel(level int, text string)— Заголовок уровня 1–6 (## text).format.KeyVal(key, value string)— Пара ключ-значение (**Key:** Value).format.Divider()— Горизонтальная линия-разделитель (━━━━━━).
2. Fluent Builder API (format.NewBuilder())
Для удобной и производительной сборки сложных сообщений без ручной конкатенации строк используется Builder с цепочкой методов:
func sendDashboard(c *router.Context) error {
msg := format.NewBuilder().
Header("Отчет по серверу").
NewLine().
Divider().
NewLine().
KeyVal("Статус", "Active").
NewLine().
KeyVal("Аптайм", "99.9%").
NewLine().
Quote("Все службы работают без сбоев.").
NewLine().
Bold("Компоненты:").
NewLine().
BulletList([]string{
"PostgreSQL: OK",
"Redis: OK",
}).
String()
return c.Reply(msg)
}
3. Автоматическая разбивка длинных сообщений (format.Split)
Максимальная длина текстового сообщения в Яндекс Мессенджере составляет 6000 символов. Если сообщение превышает этот лимит, отправка завершится ошибкой. Функция format.Split аккуратно разбивает длинный текст по абзацам (\n\n), строкам (\n) или пробелам без разрыва UTF-8 символов.
// SplitDefault разбивает текст по дефолтному лимиту Яндекса (6000 символов)
chunks := format.SplitDefault(veryLongText)
for _, chunk := range chunks {
_, _ = bot.Messages.SendText(ctx, messages.NewSendTextRequest().SetChatID(chatID).SetText(chunk))
}
Пример использования
func sendFormattedText(c *router.Context) error {
text := format.Bold("Внимание!") + "\n" +
"Пожалуйста, ознакомьтесь с нашей документацией на " + format.Link("GitHub", "https://github.com") + "\n\n" +
"Пример использования:\n" +
format.CodeBlock("fmt.Println(\"Hello World\")", "go") + "\n" +
"Пользователь с ником " + format.Escape("_user*name_") + " подключился."
return c.Reply(text)
}
Пагинация
Для упрощения создания страниц с результатами и удобной навигации по ним, в библиотеке предусмотрен пакет pkg/pagination.
import "github.com/go-yandex-bot-api/yandex-bot-api/pkg/pagination"
Пакет содержит две основные функции:
pagination.PaginateSlice(totalItems, page, limit int) (start, end, totalPages)— Помогает безопасно вычислять границы среза (slice[start:end]) в зависимости от текущей страницы и лимита элементов на страницу. Защищает от выхода за границы массива.pagination.NewPaginationRow(currentPage, totalPages int, actionName string) []InlineSuggestButton— Генерирует готовый ряд кнопок:⬅️ Назад,Текущая / Всего,Вперед ➡️. При нажатии на кнопки отправляется серверное действие (ServerAction) с названиемactionNameи payload-омpagination.Payload{Page: ...}.
Полный пример пагинации
package main
import (
"fmt"
"log"
yabotapi "github.com/go-yandex-bot-api/yandex-bot-api"
"github.com/go-yandex-bot-api/yandex-bot-api/pkg/router"
"github.com/go-yandex-bot-api/yandex-bot-api/pkg/pagination"
)
var dataItems = []string{"Яблоко", "Банан", "Апельсин", "Груша", "Киви", "Манго", "Персик", "Слива"}
const ItemsPerPage = 3
func sendItemsPage(c *router.Context, page int) error {
// 1. Вычисляем безопасные границы для слайса
start, end, totalPages := pagination.PaginateSlice(len(dataItems), page, ItemsPerPage)
// 2. Формируем текст сообщения
text := fmt.Sprintf("📄 Страница %d из %d:\n\n", page, totalPages)
for i := start; i < end; i++ {
text += fmt.Sprintf("- %s\n", dataItems[i])
}
// 3. Создаем ряд кнопок навигации.
// При нажатии будет вызван хендлер кнопки с именем "items_page"
navRow := pagination.NewPaginationRow(page, totalPages, "items_page")
// 4. Генерируем клавиатуру. Устанавливаем persist=true, чтобы она не исчезала.
keyboard := yabotapi.NewSuggestButtonsGrid(true, navRow)
return c.ReplyWithKeyboard(text, keyboard)
}
func main() {
bot, _ := yabotapi.NewBot("TOKEN")
r := router.NewRouter(bot)
// Пользователь вызывает команду /start
r.HandleCommand("start", func(c *router.Context) error {
return sendItemsPage(c, 1)
})
// Хендлер для кнопок пагинации (имя совпадает с actionName из NewPaginationRow)
r.HandleButton("items_page", func(c *router.Context) error {
var payload pagination.Payload
// Автоматически парсим JSON, прикрепленный к кнопке
if err := c.BindPayload(&payload); err != nil {
return err
}
// Отправляем запрошенную страницу
return sendItemsPage(c, payload.Page)
})
// ... Запуск роутера
}