NodeJS: Делаем кнопки в Telegram API (inline-keyboards)

  • воскресенье, 13 ноября 2016 г. в 18:44:52

Последнее время, я заметил, что на мой блог все чаще переходят по запросам связанными с Telegram API. Да и сам я в последнее время увлекся разработкой Telegram-ботов и NodeJS. В данной статье, я хочу рассказать о том, как добавлять inline-keybord к сообщениям. Разница между ReplyKeyboardMarkup, незначительная. Однако, в этой статьи я опишу пример использования первого варианта с inline-keyboards.

Пример данной клавиатуры, вы можете увидеть на скриншоте ниже. Данный бот публикует записи в мою группу Вконтакте с разных IT-сообществ.

Ничего сверхъестественного использовать мы не будем. Хочу отметить, что я работаю с пакетом [node-telegram-bot-api](https://github.com/yagop/node-telegram-bot-api). И в следующих статьях, как и в предыдущей про то, как создать своего телеграм бота на node.js, мы будем использовать только этот пакет. Советую прочесть данную статью, чтобы вы могли работать с командой npm.

Первым делом, мы создаем файл server.js и устанавливаем пакет node-telegram-bot-api.

После чего, подключаем данный пакет и создаем первую команду. Если у вас еще нету своего бота, заранее создайте его.

Использовать inline-keyboards можно следующим способом:


_13
var options = {
_13
reply_markup: JSON.stringify({
_13
inline_keyboard: [
_13
[{ text: 'Кнопка 1', callback_data: '1' }],
_13
[{ text: 'Кнопка 2', callback_data: 'data 2' }],
_13
[{ text: 'Кнопка 3', callback_data: 'text 3' }]
_13
]
_13
})
_13
};
_13
_13
bot.onText(/\/start_test/, function (msg, match) {
_13
bot.sendMessage(msg.chat.id, 'Выберите любую кнопку:', options);
_13
});

Я не стал париться над тем, какого бота мы будем делать. В качестве примера решил написать бота для теста знаний JavaScript.

Вопросы я поместил в отдельный массив, который вы можете отредактировать сами. Отмечу, что это простой пример реализации подобного бота. Если вам понравилась идея, вы с уверенностью можете его доделать.


_32
var questions = [
_32
{
_32
title:'Сколько параметров можно передать функции ?',
_32
buttons: [
_32
[{ text: 'Ровно столько, сколько указано в определении функции.', callback_data: '0_1' }],
_32
[{ text: 'Сколько указано в определении функции или меньше.', callback_data: '0_2' }],
_32
[{ text: 'Сколько указано в определении функции или больше.', callback_data: '0_3' }],
_32
[{ text: 'Любое количество.', callback_data: '0_4' }]
_32
],
_32
right_answer: 4
_32
},
_32
{
_32
title:'Чему равна переменная name?\nvar name = "пупкин".replace("п", "д")',
_32
buttons: [
_32
[{ text: 'дудкин', callback_data: '1_1' }],
_32
[{ text: 'дупкин', callback_data: '1_2' }],
_32
[{ text: 'пупкин', callback_data: '1_3' }],
_32
[{ text: 'ляпкин-тяпкин', callback_data: '1_4' }]
_32
],
_32
right_answer: 2
_32
},
_32
{
_32
title:'Чему равно 0 || "" || 2 || true ?',
_32
buttons: [
_32
[{ text: '0', callback_data: '2_1' }],
_32
[{ text: '""', callback_data: '2_2' }],
_32
[{ text: '2', callback_data: '2_3' }],
_32
[{ text: 'true', callback_data: '2_4' }]
_32
],
_32
right_answer: 3
_32
},
_32
];

  • title - текст вопроса
  • buttons - варианты ответов (кнопки). В каждом ответе хранится свое значение, которое будет отправляться на сервер.
  • right_answer - номер верного ответа.

Разъясню еще один код.


_10
[{ text: 'ТЕКСТ_КНОПКИ', callback_data: 'НОМЕР-ВОПРОСА_ВАРИАНТ-ОТВЕТА' }]

К примеру, если в вопрос по счету является 2-ым и у него 3 ответа, то варианты нужно прописывать так: 2_1, 2_2, 2_3. Можете сделать свой вариант ответа, но я решил разделять через нижнее подчеркивание.

Так же, я разработал две функции:

  • getRandomQuestion() - случайный вопрос. Возвращает массив.
  • newQuestion - отправляет вопрос пользователю.

_15
function getRandomQuestion(){
_15
return questions[Math.floor(Math.random()*questions.length)];
_15
}
_15
_15
function newQuestion(msg){
_15
var arr = getRandomQuestion(); // Получаем случайный вопрос
_15
var text = arr.title; // Вытаскиваем оттуда текст вопроса (Пример: title:'Чему равно 0 || "" || 2 || true ?')
_15
var options = {
_15
reply_markup: JSON.stringify({
_15
inline_keyboard: arr.buttons, // Добавляем кнопки, которые есть в вопросе.
_15
})
_15
};
_15
chat = msg.hasOwnProperty('chat') ? msg.chat.id : msg.from.id; // Если сообщение отправлял пользователь, то свойство msg.chat.id, если же он кликал на кнопку, то msg.from.id
_15
bot.sendMessage(chat, text, options); // Отправляем пользователю сообщение: id пользователя, текст вопроса, кнопки.
_15
}

Главные функции у меня уже готовы, теперь осталось добавить событие на сообщение /start_test. И еще одно событие, на получение ответа от кнопок.


_21
// Отправив сообщение боту "/start_test", выполнится функция newQuestion(msg);
_21
bot.onText(/\/start_test/, function (msg, match) {
_21
newQuestion(msg);
_21
});
_21
_21
// Ответ от кнопок
_21
bot.on('callback_query', function (msg) {
_21
var answer = msg.data.split('_'); // Делим ответ на две части, превратив в массив. Первый элемент номер вопроса, второй будет вариант ответа.
_21
var index = answer[0]; // Получаем номер вопроса
_21
var button = answer[1]; // И вариант ответа
_21
_21
// Если присланный вариант совпадает с вариантом из массива
_21
if (questions[index].right_answer==button) {
_21
bot.sendMessage(msg.from.id, 'Ответ верный ✅');
_21
} else {
_21
bot.sendMessage(msg.from.id, 'Ответ неверный ❌');
_21
}
_21
_21
// Отправляем еще один вопрос пользователю
_21
newQuestion(msg);
_21
});

И вроде все. Теперь бот будет присылать вопросы пользователю, отправив команду /start_test. При клике на кнопку, проверяется правильность варианта и отправляется новый вопрос.

Кстати, вы можете спокойно задавать свои команды. Неважно на русском или английском и не имеет разницы, имеется ли в команде слэш. Можно прописать хоть /дайка быстро мне тест/ и если такое сочетание найдено в сообщении, то выполнится функция генерации вопроса. Эти два слэша, нкжно ставить обязательно, так как это регулярное выражение

Пример нашего бота, вы можете увидеть ниже:

Полный код


_76
var TelegramBot = require('node-telegram-bot-api');
_76
_76
// Устанавливаем токен, который выдавал нам бот.
_76
var token = 'TELEGRAM_TOKEN';
_76
_76
// Включить опрос сервера
_76
var bot = new TelegramBot(token, {polling: true});
_76
_76
var questions = [
_76
{
_76
title:'Сколько параметров можно передать функции ?',
_76
buttons: [
_76
[{ text: 'Ровно столько, сколько указано в определении функции.', callback_data: '0_1' }],
_76
[{ text: 'Сколько указано в определении функции или меньше.', callback_data: '0_2' }],
_76
[{ text: 'Сколько указано в определении функции или больше.', callback_data: '0_3' }],
_76
[{ text: 'Любое количество.', callback_data: '0_4' }]
_76
],
_76
right_answer: 4
_76
},
_76
{
_76
title:'Чему равна переменная name?\nvar name = "пупкин".replace("п", "д")',
_76
buttons: [
_76
[{ text: 'дудкин', callback_data: '1_1' }],
_76
[{ text: 'дупкин', callback_data: '1_2' }],
_76
[{ text: 'пупкин', callback_data: '1_3' }],
_76
[{ text: 'ляпкин-тяпкин', callback_data: '1_4' }]
_76
],
_76
right_answer: 2
_76
},
_76
{
_76
title:'Чему равно 0 || "" || 2 || true ?',
_76
buttons: [
_76
[{ text: '0', callback_data: '2_1' }],
_76
[{ text: '""', callback_data: '2_2' }],
_76
[{ text: '2', callback_data: '2_3' }],
_76
[{ text: 'true', callback_data: '2_4' }]
_76
],
_76
right_answer: 3
_76
},
_76
];
_76
_76
function getRandomQuestion(){
_76
return questions[Math.floor(Math.random()*questions.length)];
_76
}
_76
_76
function newQuestion(msg){
_76
var arr = getRandomQuestion();
_76
var text = arr.title;
_76
var options = {
_76
reply_markup: JSON.stringify({
_76
inline_keyboard: arr.buttons,
_76
parse_mode: 'Markdown'
_76
})
_76
};
_76
chat = msg.hasOwnProperty('chat') ? msg.chat.id : msg.from.id;
_76
bot.sendMessage(chat, text, options);
_76
}
_76
_76
bot.onText(/\/start_test/, function (msg, match) {
_76
newQuestion(msg);
_76
});
_76
_76
bot.on('callback_query', function (msg) {
_76
var answer = msg.data.split('_');
_76
var index = answer[0];
_76
var button = answer[1];
_76
_76
if (questions[index].right_answer==button) {
_76
bot.sendMessage(msg.from.id, 'Ответ верный ✅');
_76
} else {
_76
bot.sendMessage(msg.from.id, 'Ответ неверный ❌');
_76
}
_76
_76
bot.answerCallbackQuery(msg.id, 'Вы выбрали: '+ msg.data, true);
_76
newQuestion(msg);
_76
});

#telegram#api#telegram api#buttons