Writing a telegram bot in R (part 2): Adding command support and message filters to the bot

В previous publication we figured out how to create a bot, initialized an instance of the class Bot and got acquainted with the methods of sending messages using it.

In this article, I continue this topic, so I recommend that you start reading this article only after reading the first part.

This time we will figure out how to revive our bot and add command support to it, and also get acquainted with the class Updater.

In the course of the article, we will write several simple bots, the latter will determine, by a given date and country code, whether a day in a given country is a day off or a workday according to the production calendar. But, as before, the purpose of the article is to acquaint you with the interface of the package telegram.bot to solve your own problems.

Writing a telegram bot in R (part 2): Adding command support and message filters to the bot

All articles from the series "Writing a telegram bot in R"

  1. Create a bot and use it to send messages to telegram
  2. Add command support and message filters to the bot

Content

If you are interested in data analysis, you might be interested in my telegram и youtube channels. Most of the content of which is devoted to the R language.

  1. Updater class
  2. Handlers - handlers
  3. Adding the first command to the bot, the command handler
  4. Text message handler and filters
  5. Adding commands with parameters
  6. Run the bot in the background
  7. Conclusion

Updater class

Updater is a class that makes it easier for you to develop a telegram bot, and uses the class under the hood Dispetcher. Class Assignment Updater is to receive updates from the bot (in the previous article we used the method getUpdates()) and pass them on to Dispetcher.

In turn, Dispetcher contains the handlers you created, i.e. class objects Handler.

Handlers - handlers

With handlers, you add to Dispetcher bot reactions to various events. At the time of writing in telegram.bot The following types of handlers have been added:

  • MessageHandler — Message handler
  • CommandHandler — Command handler
  • CallbackQueryHandler - Data handler sent from Inline keyboards
  • ErrorHandler - Error handler when requesting updates from the bot

Adding the first command to the bot, the command handler

If you have never used bots before and do not know what a command is, then you need to send commands to the bot using a forward slash / as a prefix.

We will start with simple commands, i.e. let's teach our bot to say hello on command /hi.

Code 1: Teaching the bot to say hello

library(telegram.bot)

# создаём экземпляр класса Updater
updater <- Updater('ТОКЕН ВАШЕГО БОТА')

# Пишем метод для приветсвия
say_hello <- function(bot, update) {

  # Имя пользователя с которым надо поздароваться
  user_name <- update$message$from$first_name

  # Отправка приветственного сообщения
  bot$sendMessage(update$message$chat_id, 
                  text = paste0("Моё почтение, ", user_name, "!"), 
                  parse_mode = "Markdown")

}

# создаём обработчик 
hi_hendler <- CommandHandler('hi', say_hello)

# добаляем обработчик в диспетчер
updater <- updater + hi_hendler

# запускаем бота
updater$start_polling()

Run the code example above, after replacing 'YOUR BOT TOKEN' with the real token you received when you created the bot via Bot Father (I talked about creating a bot in first article).

Method start_polling() Class Updater, which is used at the end of the code, starts an endless loop of requesting and processing updates from the bot.

Now let's open telegram and write the first command to our bot /hi.

Writing a telegram bot in R (part 2): Adding command support and message filters to the bot

Now our bot understands the command /hiand knows how to greet us.

Schematically, the process of building such a simple bot can be depicted as follows.

Writing a telegram bot in R (part 2): Adding command support and message filters to the bot

  1. Create an instance of the class Updater;
  2. We create methods, i.e. functions that our bot will perform. In the code example, this is the function say_hello(). The functions that you will use as bot methods must have two required arguments - muzzle и Update, and one optional - args. Argument muzzle, this is your bot, with it you can reply to messages, send messages, or use any other methods available to the bot. Argument Update this is what the bot received from the user, in fact, what we received in the first article using the method getUpdates(). Argument args allows you to process additional data sent by the user along with the command, we will return to this topic a little later;
  3. We create handlers, i.e. we associate some user actions with the methods created at the last step. In fact, a handler is a trigger, an event that calls some kind of bot function. In our example, such a trigger is sending a command /hi, and implemented by the team hi_hendler <- CommandHandler('hi', say_hello). First function argument CommandHandler() allows you to specify a command, in our case hi, which the bot will respond to. The second argument allows you to specify the bot method, we will call the method say_hello, which will be executed if the user called the command specified in the first argument;
  4. Next, add the created handler to the dispatcher of our class instance Updater. You can add handlers in several ways, in the example above I used the simplest one, using the sign +Ie updater <- updater + hi_hendler. The same can be done with the method add_handler(), which belongs to the class Dispatcher, you can find this method like this: updater$dispatcher$add_handler();
  5. Launch the bot with the command start_polling().

Text message handler and filters

We figured out how to send commands to the bot, but sometimes we need the bot to respond not only to commands, but also to some ordinary text messages. To do this, you need to use message handlers − MessageHandler.

Normal MessageHandler will respond to absolutely all incoming messages. Therefore, message handlers are often used in conjunction with filters. Let's teach the bot to say hello not only on command /hi, but also whenever one of the following words occurs in the message sent to the bot: hello, hello, salute, hai, bonjour.

While we will not write any new methods, because we already have a method by which the bot greets us. We only need to create the necessary filter and message handler.

Code 2: Adding a text message handler and filter

library(telegram.bot)

# создаём экземпляр класса Updater
updater <- Updater('ТОКЕН ВАШЕГО БОТА')

# Пишем метод для приветсвия
## команда приветвия
say_hello <- function(bot, update) {

  # Имя пользователя с которым надо поздароваться
  user_name <- update$message$from$first_name

  # Отправляем приветсвенное сообщение
  bot$sendMessage(update$message$chat_id, 
                  text = paste0("Моё почтение, ", user_name, "!"),
                  parse_mode = "Markdown",
                  reply_to_message_id = update$message$message_id)

}

# создаём фильтры
MessageFilters$hi <- BaseFilter(function(message) {

  # проверяем, встречается ли в тексте сообщения слова: привет, здравствуй, салют, хай, бонжур
  grepl(x           = message$text, 
        pattern     = 'привет|здравствуй|салют|хай|бонжур',
        ignore.case = TRUE)
  }
)

# создаём обработчик 
hi_hendler <- CommandHandler('hi', say_hello) # обработчик команды hi
hi_txt_hnd <- MessageHandler(say_hello, filters = MessageFilters$hi)

# добаляем обработчики в диспетчер
updater <- updater + 
             hi_hendler +
             hi_txt_hnd

# запускаем бота
updater$start_polling()

Run the code example above, after replacing 'YOUR BOT TOKEN' with the real token you received when you created the bot via Bot Father (I talked about creating a bot in first article).

Now let's try to send a few messages to the bot, which will contain the previously listed greeting words:
Writing a telegram bot in R (part 2): Adding command support and message filters to the bot

So, first of all, we taught the bot not just to say hello, but to respond to a greeting. We did this with the argument reply_to_message_id, which is available in the method sendMessage(), to which you need to pass the id of the message to which you want to respond. You can get the message id like this: update$message$message_id.

But the main thing we did was to add a filter to the bot using the function BaseFilter():

# создаём фильтры
MessageFilters$hi <- BaseFilter( 

  # анонимная фильтрующая функция
  function(message) {

    # проверяем, встречается ли в тексте сообщения слова приветствия
    grepl(x           = message$text, 
          pattern     = 'привет|здравствуй|салют|хай|бонжур',
          ignore.case = TRUE)
  }

)

As you may have noticed, filters must be added to the object MessageFilters, which initially already has a small set of ready-made filters. In our example, the object MessageFilters we have added an element hi, this is a new filter.

In function BaseFilter() you need to pass a filter function. Essentially, a filter is just a function that takes a message instance and returns TRUE CODE or FALSE. In our example, we have written a simple function that, using the base function grepl() checks the text of the message, and if it matches a regular expression привет|здравствуй|салют|хай|бонжур returns TRUE CODE.

Next, we create a message handler hi_txt_hnd <- MessageHandler(say_hello, filters = MessageFilters$hi). First function argument MessageHandler() is the method that the handler will call, and the second argument is the filter by which it will be called. In our case, this is the filter we created. MessageFilters$hi.

Well, in the end, we add to the dispatcher the just created handler hi_txt_hnd.

updater <- updater + 
             hi_hendler +
             hi_txt_hnd

As I wrote above, in the package telegram.bot and object MessageFilters there is already a set of built-in filters that you can use:

  • all — All messages
  • text — Text messages
  • command - Commands, i.e. messages that start with /
  • reply — Messages that are a reply to another message
  • audio — Messages containing an audio file
  • document — Posted document messages
  • photo - Messages with sent images
  • sticker — Messages with sent sticker
  • video — Messages with video
  • voice — Voice messages
  • contact — Messages containing the user's telegram content
  • location — Posts with geolocation
  • venue — Forwarded messages
  • game - Games

If you want to combine some filters in one handler just use the sign | - as a logical OR, and sign & as a logical И. For example, if you want the bot to call the same method when it receives a video, image, or document, use the following message handler example:

handler <- MessageHandler(callback, 
  MessageFilters$video | MessageFilters$photo | MessageFilters$document
)

Adding commands with parameters

We already know what commands are, how to create them, and how to get the bot to execute the desired command. But in some cases, in addition to the name of the command, we need to pass some data for its execution.

Below is an example of a bot that, for a given date and country, returns you the type of day from the production calendar.

The bot below uses the production calendar API isdayoff.ru.

Code 3: Bot that reports by date and country

library(telegram.bot)

# создаём экземпляр класса Updater
updater <- Updater('1165649194:AAFkDqIzQ6Wq5GV0YU7PmEZcv1gmWIFIB_8')

# Пишем метод для приветсвия
## команда приветвия
check_date <- function(bot, update, args) {

  # входящие данные
  day     <- args[1]  # дата
  country <- args[2]  # страна

  # проверка введённых параметров
  if ( !grepl('\d{4}-\d{2}-\d{2}', day) ) {

    # Send Custom Keyboard
    bot$sendMessage(update$message$chat_id, 
                    text = paste0(day, " - некорреткная дата, введите дату в формате ГГГГ-ММ-ДД"),
                    parse_mode = "Markdown")

  } else {
    day <- as.Date(day)
    # переводим в формат POSIXtl
    y <- format(day, "%Y")
    m <- format(day, "%m")
    d <- format(day, "%d")

  }

  # страна для проверки
  ## проверяем задана ли страна
  ## если не задана устанавливаем ru
  if ( ! country %in% c('ru', 'ua', 'by', 'kz', 'us') ) {

    # Send Custom Keyboard
    bot$sendMessage(update$message$chat_id, 
                    text = paste0(country, " - некорретктный код страны, возможнные значения: ru, by, kz, ua, us. Запрошены данные по России."),
                    parse_mode = "Markdown")

    country <- 'ru'

  }

  # запрос данных из API
  # компоновка HTTP запроса
  url <- paste0("https://isdayoff.ru/api/getdata?",
                "year=",  y, "&",
                "month=", m, "&",
                "day=",   d, "&",
                "cc=",    country, "&",
                "pre=1&",
                "covid=1")

  # получаем ответ
  res <- readLines(url)

  # интрепретация ответа
  out <- switch(res, 
                "0"   = "Рабочий день",
                "1"   = "Нерабочий день",
                "2"   = "Сокращённый рабочий день",
                "4"   = "covid-19",
                "100" = "Ошибка в дате",
                "101" = "Данные не найдены",
                "199" = "Ошибка сервиса")

  # отправляем сообщение
  bot$sendMessage(update$message$chat_id, 
                  text = paste0(day, " - ", out),
                  parse_mode = "Markdown")

}

# создаём обработчик 
date_hendler <- CommandHandler('check_date', check_date, pass_args = TRUE)

# добаляем обработчик в диспетчер
updater <- updater + date_hendler

# запускаем бота
updater$start_polling()

Run the code example above, after replacing 'YOUR BOT TOKEN' with the real token you received when you created the bot via Bot Father (I talked about creating a bot in first article).

We have created a bot that has only one method in its arsenal check_date, this method is called by the command of the same name.

But, in addition to the command name, this method expects you to enter two parameters, the country code and the date. Next, the bot checks whether the given day in the specified country is a weekend, shortened or working day according to the official production calendar.

To make the method we create accept additional parameters along with the command, use the argument pass_args = TRUE in function CommandHandler(), and when creating a method, in addition to the required arguments muzzle, Update create optional - args. The method created in this way will take the parameters that you pass to the bot after the command name. Parameters must be separated by a space; they will be sent to the method as a text vector.

Let's run and test our bot.

Writing a telegram bot in R (part 2): Adding command support and message filters to the bot

Run the bot in the background

The last step that we need to complete is to run the bot in the background.

To do this, follow the algorithm described below:

  1. Save the bot code to a file with the R extension. When working in RStudio, this is done through the menu Fillet, team Save As.
  2. Add the path to the bin folder, which in turn is located in the folder where you installed the R language, to the Path variable, instruction here.
  3. Create a plain text file with 1 line: R CMD BATCH C:UsersAlseyDocumentsmy_bot.R. Instead C:UsersAlseyDocumentsmy_bot.R write the path to your bot script. At the same time, it is important that there are no Cyrillic characters and spaces along the way, because this can cause problems when starting the bot. Save it and replace its extension with txt on Beat.
  4. Open the Windows Task Scheduler, there are many ways to do this, for example, open any folder and enter in the address %windir%system32taskschd.msc /s. Other ways to start can be found here.
  5. In the top right menu of the scheduler, click "Create a task ...".
  6. On the "General" tab, set an arbitrary name for your task, and change the switch to the "Run for all users" state.
  7. Go to the "Actions" tab, click "Create". In the "Program or script" field, click "Browse", find the one created in the second step Beat file and click OK.
  8. Click OK, if necessary, enter the password for your operating system account.
  9. We find the created task in the scheduler, select it and click the "Run" button in the lower right corner.

Our bot is running in the background and will work until you stop the task or turn off your PC or the server on which it was launched.

Conclusion

In this article, we figured out how to write a full-fledged bot that can not only send messages, but also respond to incoming messages and commands. The acquired knowledge is already enough to solve most of your problems.

In the next article, we will talk about how to add a keyboard to the bot for more convenient work.

Subscribe to my telegram и youtube channels.

Source: habr.com

Add a comment