Как построить простой Telegram-бот на Node.js

Telegram


С тех пор, как Telegram в 2015 году представил ботов, другие мессенджеры тоже добавили ботов на свои собственные платформы. Но Telegram по-прежнему опережает своих конкурентов благодаря обширному боту API и свободе, которую он предлагает разработчику. API-бот это интерфейс на основе HTTP, созданный для разработчиков, желающих создавать боты для Telegram.

В последнее время предприятия начали использовать бот-платформу Telegram для создания полностью обособленных приложений, способных выполнять совершенно любые действия в границах бота.

Как работают боты

Чтобы получать обновления от Telegram, вам понадобится токен (token). Все обновления и взаимодействия с вашим ботом в Telegram сохраняются, так что вы можете обратиться к ним, послав запрос по этому URL с указанием токена:

 https://api.telegram.org/bot<token>/METHOD_NAME

С чего начать

Прежде всего, создайте ваш бот с помощью BotFather, который сам по себе также является ботом. Теперь у вас есть токен и вы можете получать обновления из Telegram. Давайте попробуем получить какую-нибудь информацию от Telegram, чтобы убедиться, что наш бот работает.

Замените вышеуказанный URL на ваш токен и укажите один из методов API-бота Telegram. Давайте используем метод getMe.

https://api.telegram.org/bot<token>/getMe

// --> {"ok":true,"result":{"id":437852999,"is_bot":true,"first_name":"Reddit Bot","username":"SimpleReddit_Bot"}}

Отлично. Но как это сделать в NodeJS? В общем-то так же. Каждый раз, когда нам нужно обновление, мы отсылаем запрос по адресу с указанием нужного метода.

Но делать все это вручную не хочется, поэтому у нас есть удобные фреймворки. Чтобы управлять всем этим процессом и дать нам возможность сфокусироваться на важных вещах. Для NodeJS есть целый ряд хороших фреймворков, а в этом руководстве мы остановимся на Telegraf.

Начинаем писать код

Инициализируйте процесс и установите Telegraf:

npm init
npm install telegraf --save

Теперь давайте добавим его к нашему скрипту и создадим простой бот:

const Telegraf = require('telegraf');
const app = new Telegraf(YOUR_TOKEN_HERE);

app.hears('hi', ctx => {
 return ctx.reply('Hey!');
});

app.startPolling();

Что происходит? У Telegraf есть свои собственный методы чтобы сделать за нас большую часть работы. Мы может использовать этот метод чтобы ответить на сообщение пользователя:

reddit bot

Reddit bot

Давайте рассмотрим пример. Мы будем отсылать верхний пост из сабредита по запросу пользователя. Установим библиотеку axios чтобы упростить отсылку запросов GET и получение данных от Reddit.

npm install axios --save
const axios = require('axios'); // add axios

// handle the reaction everytime user sends a text message
app.on('text', ctx => {

// ctx object holds the Update object from Telegram API
 // So you can use everything you see there

// get the text message sent by user
 const subreddit = ctx.message.text;

// GET the data from Reddit API
 axios.get(`https://reddit.com/r/${subreddit}/top.json?limit=10`)
 .then(res => {

// data recieved from Reddit
 const data = res.data.data;

// if subbreddit does not exist
 if (data.children.length < 1) 
 return ctx.reply('The subreddit couldn\'t be found.');

// send the first top post link to the user
 const link = `https://reddit.com/${data.children[0].data.permalink}`;
 return ctx.reply(link);
 })

// if there's any error in request
 .catch(err => console.log(err));
});

nodejs

Когда пользователь отсылает название сабредита, мы будем брать верхний пост из сабредита и отсылать ссылку на него. Просто, а?

Сохранение состояния (state)

Представьте, что пользователь хочет иметь возможность выбрать не только верхний пост, но и самый популярный или самый новый. Нам нужно сохранить последние команды, которые он использовал, чтобы суметь ответить правильно. Заметьте, что мы используем для этого метод command вместо on.

Вы можете создать команды на боте Telegram. Команды начинаются с «/» и являются кликабельными. Чтобы добавить команды к вашему боту, отправьте сообщение BotFather.

let state = {};

app.command('top', ctx => {
  const userId = ctx.message.from.id;

  // if user id does not exist create one  
  if (!state[userId])
    state[userId] = { id: userId };

  // save/update user last command    
  state[userId].command = 'top';
  return ctx.replyWithMarkdown(`Enter a subreddit name to get *top* posts.`);
});

app.command('hot', ctx => {
  const userId = ctx.message.from.id;
  if (!state[userId])
    state[userId] = { id: userId };
  state[userId].command = 'hot';
  return ctx.replyWithMarkdown('Enter a subreddit name to get *hot* posts.');
});

Теперь мы можем отсылать правильные посты на основе фильтра. В нашем text-ответе:

const userId = ctx.message.from.id;
// check if state and command exists and set defaults
const type = !state[userId] ? 
    'top' : 
    state[userId].command ? 
      state[userId].command : 
      'top';
axios.get(`https://reddit.com/r/${subreddit}/${type}.json?limit=10`)
  .then(res => [
    // do stuff
  ])

nodejs-reddit-bot

Встроенные кнопки

У ботов в Telegramесть интерактивные кнопки под названием InlineKeyboardMarkup. Мы добавим кнопку next, так что пользователь сможет получить следующий пост из данной категории.

Нам нужно извлечь из Telegraf особые методы для кнопок чтобы получить возможность работать с ними:

const { Markup } = require('telegraf');

Во-первых, давайте добавим номер текущего поста к state. Каждый раз, когда пользователь запрашивает сабредит, нам нужно установить индекс в 0. В нашем методе text:

 if (!state[userId])
    state[userId] = {};
  state[userId].index = 0;

Вместо отсылки простого текста, мы отсылаем его со встроенной кнопкой в ответе axios:

// old response, only text
return ctx.reply(link);

// new response, with inline buttons
return ctx.reply(link, 
	Markup.inlineKeyboard([
		// first argument is button's text
		// second argument is callback text
		Markup.callbackButton('➡️ Next', subreddit),
	]).extra()
);

Мы можем управлять откликом с помощью метода on, но в этот раз используем метод обновления callback_query:

app.on('callback_query', ctx => {
	// get info from callback_query object
  const subreddit = ctx.update.callback_query.data;
  const userId = ctx.update.callback_query.from.id;

	// check if user state and its properties exist
  let type;
  let index;
  try {
    type = state[userId].command ? state[userId].command : 'top';
    index = state[userId].index;
  } catch (err) {
    return ctx.reply('Send a subreddit name.');
  }

	// reply with a popup to callback
  ctx.answerCallbackQuery('Wait...');

  axios.get(`https://reddit.com/r/${subreddit}/${type}.json?limit=10`)
    .then(res => {
      const data = res.data.data;

			// check if next one exists
      if (!data.children[index + 1])
        return ctx.reply('No more posts!');
      
			// send next link and update the user state with new index
      const link = `https://reddit.com/${data.children[index + 1].data.permalink}`;
      state[userId].index = state[userId].index + 1;
      return ctx.reply(link, 
        Markup.inlineKeyboard([
          Markup.callbackButton('➡️ Next', subreddit),
        ]).extra()
      );
    })
    .catch(err => console.log(err));
});

Telegram-бот

Заключение

Как вы видите, мы создали простой Telegram-бот за считанные минуты. Создавать такие боты легко, но это не главное. Есть много вещей, которые вы можете делать с их помощью, например, отсылать фотографии, видео, документы и т. д.

Только представьте, все, что вы можете делать с огромным API, который постоянно улучшается с каждым обновлением.

Исходный код этого бота вы можете найти на GitHub. Также вот пример более сложного Reddit-бота, который имеет больше функций (например, возможность отсылки фото) и встроенные кнопки.

[customscript]techrocks_custom_after_post_html[/customscript]
[customscript]techrocks_custom_script[/customscript]

1 комментарий к “Как построить простой Telegram-бот на Node.js”

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Прокрутить вверх