Inline запросы (встроенно)
С помощью inline запросов пользователи могут искать, просматривать и отправлять контент, предложенный вашим ботом, в любой чат, даже если он не является его участником. Для этого они начинают сообщение с @имя
и выбирают один из результатов.
Пересмотрите раздел о режиме Inline в статье Telegram Bot Features, написанной командой Telegram. Дополнительные ресурсы — это подробное описание инлайн-ботов, а также пост в блоге, анонсирующий эту функцию, и раздел Inline mode в Telegram Bot API Reference. Их стоит прочитать, прежде чем внедрять инлайн-запросы для своего бота, так как инлайн-запросы немного продвинуты. Если вам не хочется читать все это, то будьте уверены, что эта страница проведет вас через все шаги.
Включение Inline режима
По умолчанию поддержка режима inline для вашего бота отключена. Вы должны связаться с @Bot
Получилось? Теперь ваш клиент Telegram должен отображать “…”, когда вы вводите имя бота в любое текстовое поле, и показывать иконку загрузки. Вы уже можете начинать что-то набирать. Теперь давайте посмотрим, как ваш бот может обрабатывать эти запросы.
Обработка inline запросов
Как только пользователь затриггерит инлайн-запрос, то есть начнет сообщение, набрав “@имя_вашего_бота…” в поле ввода текста, ваш бот будет получать обновления об этом. В grammY есть специальная поддержка обработки инлайн-запросов с помощью метода bot
, как описано для класса Composer
в документации grammY API. Он позволяет прослушивать конкретные инлайн запросы, соответствующие строкам или регулярным выражениям. Если вы хотите обрабатывать все инлайн запросы в общем виде, используйте bot
.
// Прослушивание определенных строк или регулярных выражений.
bot.inlineQuery(/best bot (framework|library)/, async (ctx) => {
const match = ctx.match; // объект, который подходит регулярному выражению
const query = ctx.inlineQuery.query; // строка запроса
});
// Прослушивайте любые инлайн запросы.
bot.on("inline_query", async (ctx) => {
const query = ctx.inlineQuery.query; // строка запроса
});
2
3
4
5
6
7
8
9
10
Теперь, когда мы знаем, как прослушивать обновления инлайн запросов, мы можем ответить на них списком результатов.
Построение результатов инлайн запросов
Построение списка результатов для инлайн-запросов — утомительная задача, поскольку необходимо создавать сложные вложенные объекты с множеством свойств. К счастью, вы используете grammY, и, конечно, есть помощники, которые делают эту задачу очень простой.
Для каждого результата необходимы три вещи.
- Уникальный строковый идентификатор.
- Объект result, который описывает, как отобразить результат inline запроса. Он может содержать такие элементы, как заголовок, ссылка или изображение.
- Объект message content, описывающий содержание сообщения, которое будет отправлено пользователю, если он выберет этот результат. В некоторых случаях содержимое сообщения может быть неявно выведено из объекта результата. Например, если вы хотите, чтобы результат отображался в виде GIF, Telegram поймет, что содержимым сообщения будет тот же GIF, если вы не укажете объект message content.
grammY экспортирует построитель результатов инлайн-запросов, названный Inline
. Вот несколько примеров его использования.
import { InlineKeyboard, InlineQueryResultBuilder } from "grammy";
// Создайте результат с фото
InlineQueryResultBuilder.photo("id-0", "https://grammy.dev/images/grammY.png");
// Постройте результат с фото, но который отправляет текстовое сообщение
InlineQueryResultBuilder.photo("id-1", "https://grammy.dev/images/grammY.png")
.text("Этот текст будет отправлен вместо фото");
// Постройте текстовый результат
InlineQueryResultBuilder.article("id-2", "Инлайн запросы")
.text(
"Отличная документация по инлайн запросам: grammy.dev/plugins/inline-query",
);
// Передайте дополнительные параметры результату.
const keyboard = new InlineKeyboard()
.text("О, да", "перезвони мне, крошка");
InlineQueryResultBuilder.article("id-3", "Нажми на меня", {
reply_markup: keyboard,
})
.text("Нажимай на мои кнопки");
// Передайте дополнительные параметры в содержимое сообщения.
InlineQueryResultBuilder.article("id-4", "Инлайн запросы")
.text("**Выдающаяся** документация: grammy.dev", {
parse_mode: "MarkdownV2",
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const { InlineKeyboard, InlineQueryResultBuilder } = require("grammy");
// Создайте результат с фото
InlineQueryResultBuilder.photo("id-0", "https://grammy.dev/images/grammY.png");
// Постройте результат с фото, но который отправляет текстовое сообщение
InlineQueryResultBuilder.photo("id-1", "https://grammy.dev/images/grammY.png")
.text("Этот текст будет отправлен вместо фото");
// Постройте текстовый результат
InlineQueryResultBuilder.article("id-2", "Инлайн запросы")
.text(
"Отличная документация по инлайн запросам: grammy.dev/plugins/inline-query",
);
// Передайте дополнительные параметры результату.
const keyboard = new InlineKeyboard()
.text("О, да", "перезвони мне, крошка");
InlineQueryResultBuilder.article("id-3", "Нажми на меня", {
reply_markup: keyboard,
})
.text("Нажимай на мои кнопки");
// Передайте дополнительные параметры в содержимое сообщения.
InlineQueryResultBuilder.article("id-4", "Inline Queries")
.text("**Выдающаяся** документация: grammy.dev", {
parse_mode: "MarkdownV2",
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import {
InlineKeyboard,
InlineQueryResultBuilder,
} from "https://deno.land/x/grammy@v1.30.0/mod.ts";
// Создайте результат с фото
InlineQueryResultBuilder.photo("id-0", "https://grammy.dev/images/grammY.png");
// Постройте результат с фото, но который отправляет текстовое сообщение
InlineQueryResultBuilder.photo("id-1", "https://grammy.dev/images/grammY.png")
.text("Этот текст будет отправлен вместо фото");
// Постройте текстовый результат
InlineQueryResultBuilder.article("id-2", "Inline Queries")
.text(
"Отличная документация по инлайн запросам: grammy.dev/plugins/inline-query",
);
// Передайте дополнительные параметры результату.
const keyboard = new InlineKeyboard()
.text("О, да", "перезвони мне, крошка");
InlineQueryResultBuilder.article("id-3", "Нажми на меня", {
reply_markup: keyboard,
})
.text("Нажимай на мои кнопки");
// Передайте дополнительные параметры в содержимое сообщения.
InlineQueryResultBuilder.article("id-4", "Inline Queries")
.text("**Выдающаяся** документация: grammy.dev", {
parse_mode: "MarkdownV2",
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Обратите внимание, что если вы хотите отправлять файлы через существующие идентификаторы файлов, вам следует использовать методы *Cached
.
// Результат для аудиофайла, отправленного через идентификатор файла.
const audioFileId = "AgADBAADZRAxGyhM3FKSE4qKa-RODckQHxsoABDHe0BDC1GzpGACAAEC";
InlineQueryResultBuilder.audioCached("id-0", audioFileId);
2
3
Подробнее об идентификаторах файлов можно прочитать здесь.
Вам следует ознакомиться с API документациейInline
, а также, возможно, с спецификациейInline
, чтобы увидеть все доступные опции.
Ответ на инлайн запросы
Сформировав массив результатов инлайн-запроса с помощью конструктора выше, вы можете вызвать answer
, чтобы отправить эти результаты пользователю.
// Бесстыдная самореклама в документации одного проекта
// Это лучший вид рекламы.
bot.inlineQuery(/best bot (framework|library)/, async (ctx) => {
// Создайте один результат инлайн запроса.
const result = InlineQueryResultBuilder
.article("id:grammy-website", "grammY", {
reply_markup: new InlineKeyboard()
.url("grammY вебсайт", "https://grammy.dev/"),
})
.text(
`<b>grammY</b> это лучший способ создания собственных ботов Telegram.
У них даже есть симпатичный сайт! 👇`,
{ parse_mode: "HTML" },
);
// Ответьте на инлайн запросы
await ctx.answerInlineQuery(
[result], // ответ со списком результатов
{ cache_time: 30 * 24 * 3600 }, // 30 дней в секундах
);
});
// Возвращайте пустой список результатов для других запросов.
bot.on("inline_query", (ctx) => ctx.answerInlineQuery([]));
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Помните, что вы всегда можете указать дополнительные опции при вызове методов API, используя объект options типа Other
. Например, answer
позволяет выполнять построение страниц для инлайн-запросов через смещение, как вы можете увидеть здесь.
Смешивание текста и медиа Хотя разрешается отправлять списки
результатов, содержащие как медиа, так и текстовые элементы, большинство клиентов Telegram не очень хорошо их отображают. С точки зрения пользовательского опыта, их следует избегать.
Кнопка над результатами инлайн запроса
Клиенты Telegram могут показать кнопку над списком результатов. Эта кнопка может перевести пользователя в приватный чат с ботом.
const button = {
text: "Открыть приватный чат",
start_parameter: "login",
};
await ctx.answerInlineQuery(results, { button });
2
3
4
5
Когда пользователь нажмет на кнопку, вашему боту будет отправлено командное сообщение /start
. Параметр start будет доступен через deep linking. Другими словами, используя приведенный выше фрагмент кода, ctx
будет иметь значение "login"
в вашем обработчике команд.
Если затем отправить встроенную клавиатуру с кнопкой switch
, пользователь будет возвращен в чат, где он первоначально нажал кнопку результатов inline-запроса.
bot
.command("start")
.filter((ctx) => ctx.match === "login", async (ctx) => {
// Пользователь приходит из результатов встроенного запроса.
await ctx.reply("Личные сообщения открыты, теперь вы можете вернуться!", {
reply_markup: new InlineKeyboard()
.switchInline("Вернуться назад"),
});
});
2
3
4
5
6
7
8
9
Таким образом, вы можете выполнять, например, процедуры входа в систему в приватном чате с пользователем перед выдачей результатов запроса. Диалог может идти туда-сюда, прежде чем вы отправите их обратно. Например, вы можете ввести короткий диалог с помощью плагина conversations.
Получение отзывов о выбранных результатах
Результаты инлайн-запросов доставляются по принципу “авось нормально будет”. Другими словами, после того как ваш бот отправил список результатов инлайн-запросов в Telegram, он не будет знать, какой результат выбрал пользователь (и выбрал ли он его вообще).
Если вы заинтересованы в этом, вы можете включить обратную связь с помощью @Bot
Обратная связь доставляется через обновления chosen
. Вы можете прослушивать определенные идентификаторы результатов через строку или регулярное выражение. Естественно, вы также можете прослушивать обновления обычным способом с помощью запросов-фильтров.
// Прослушивание определенных идентификаторов результатов.
bot.chosenInlineResult(/id-[0-9]+/, async (ctx) => {
const match = ctx.match; // объект, который подходит регулярному выражению
const query = ctx.chosenInlineResult.query; // используемый инлайн запрос
});
// Прослушайте все выбранные inline результаты
bot.on("chosen_inline_result", async (ctx) => {
const query = ctx.chosenInlineResult.query; // используемый инлайн запрос
});
2
3
4
5
6
7
8
9
10
Некоторые боты устанавливают обратную связь на 100 % и используют ее в качестве преимущества. Они передают фиктивные сообщения без реального содержимого в answer
. Сразу после получения обновления chosen
они редактируют соответствующее сообщение и вставляют в него реальное содержимое.
Эти боты не будут работать для анонимных администраторов или при отправке сообщений по расписанию, так как в этом случае нельзя получить обратную связь. Однако если для вас это не проблема, то данный хак позволит вам не генерировать большое количество содержимого сообщений, которые в итоге так и не будут отправлены. Это позволит сэкономить ресурсы бота.
Краткая информация о плагине
Этот плагин встроен в ядро grammY. Вам не нужно ничего устанавливать, чтобы использовать его. Просто импортируйте все из самого grammY.
Кроме того, документация и ссылка на API этого плагина объединены с основным пакетом.