Creating a Telegram bot in R (part 2): Adding command support and message filters

In previous publication We figured out how to create a bot and initialized an instance of the class. Bot We also learned about the methods for sending messages using it.

In this article, I continue this topic, so I recommend starting to read this article only after reading the first part.

This time we will figure out how to bring our bot to life, 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 last one will determine whether a day is a holiday or a working day in a given country based on the specified date and country code according to the production calendar. But, as before, the goal of the article is to familiarize you with the package interface telegram.bot for solving your own tasks.

Creating a Telegram bot in R (part 2): Adding command support and message filters

All articles from the "Writing a Telegram Bot in R" series

  1. Creating a bot and sending messages through it on Telegram
  2. Adding command support and message filters to the bot

Content

If you're interested in data analysis, you might find my telegram and youtube channels interesting. Most of their content is devoted to the R language.

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

The Updater Class

Updater — is a class that simplifies the development of a Telegram bot for you, and uses the class under the hood Dispatcher. The purpose of the class Updater is to get updates from the bot (in the previous article, we used the method for this purpose getUpdates()), and pass them on to Dispatcher.

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

Handlers — the handlers

With the help of handlers, you add Dispatcher the bot's reactions to various events. At the time of writing the article, the following types of handlers have been added to telegram.bot MessageHandler — Message handler

  • CommandHandler — Command handler
  • CallbackQueryHandler — Handler for data sent from inline keyboards
  • ErrorHandler — Error handler when requesting updates from the bot
  • If you have never used bots before and are unaware of what a command is, you need to send commands to the bot using a forward slash

Adding the first command to the bot, the command handler

as a prefix. / Let's start with simple commands, i.e. we will teach our bot to greet on command

Code 1: Teaching the bot to greet /hi.

Code 1: Teaching the bot to greet

library(telegram.bot)

# Creating an instance of the Updater class
updater <- Updater('YOUR BOT TOKEN')

# Writing a greeting method
say_hello <- function(bot, update) {

  # User's first name to greet
  user_name <- update$message$from$first_name

  # Sending a welcome message
  bot$sendMessage(update$message$chat_id, 
                  text = paste0("Greetings, ", user_name, "!"), 
                  parse_mode = "Markdown")

}

# Creating a handler 
hi_hendler <- CommandHandler('hi', say_hello)

# Adding the handler to the dispatcher
updater <- updater + hi_hendler

# Starting the bot
updater$start_polling()

Run the example code above, replacing 'YOUR BOT TOKEN' with the actual token you received when creating the bot through BotFather (I explained how to create a bot in first article)).

Element.getAnimations() start_polling() class Updater, which is used at the end of the code to start an infinite loop requesting and processing updates from the bot.

Now let's open Telegram and send our bot the first command /hi.

Creating a Telegram bot in R (part 2): Adding command support and message filters

Now our bot understands the command /hi, and knows how to greet us.

The process of building such a simple bot can be schematically illustrated as follows.

Creating a Telegram bot in R (part 2): Adding command support and message filters

  1. Creating an instance of the class Updater;
  2. Creating methods, i.e., functions that our bot will perform. In the example code, this function is say_hello(). Functions that you will use as bot methods must have two required arguments — bot and update, and one optional — args. The argument bot, which is your bot. With it, you can respond to messages, send messages, or use any other available methods. The argument update is what the bot received from the user, essentially what we received in the first article using the method getUpdates(). The argument args allows you to handle additional data sent by the user along with the command, we will revisit this topic a bit later;
  3. Creating handlers, i.e., linking some user actions to the methods created in the previous step. Essentially, a handler is a trigger, an event that calls a function of the bot. In our example, such a trigger is sending the command /hi, implemented by the command hi_hendler <- CommandHandler('hi', say_hello). The first argument of the function CommandHandler() allows you to set the command, in our case hi, that the bot will respond to. The second argument allows you to specify the bot's method, we will call the method say_hello, which will be executed when the user invokes the command specified in the first argument;
  4. Next, we add the created handler to the dispatcher of our class instance Updater. Handlers can be added in several ways; in the example above, I used the simplest method, with the sign +, i.e. updater <- updater + hi_handler. The same can be done using the method add_handler(), which belongs to the class Dispatcher, this method can be found like this: updater$dispatcher$add_handler();
  5. We start the bot with the command start_polling().

Text message handler and filters

We have figured out how to send commands to the bot, but sometimes we need the bot to respond not only to commands but also to regular text messages. For this, we need to use message handlers — MessageHandler.

Standalone MessageHandler will respond to absolutely all incoming messages. Therefore, message handlers are often used with filters. Let's teach the bot to greet not only when the command /hi, but also whenever one of the following words is included in the message sent to the bot: hello, hi, salute, hey, bonjour.

For now, we will not write any new methods, as we already have a method through which the bot greets us. We only need to create the required filter and message handler.

Code 2: Adding a text message handler and filter

library(telegram.bot)

# creating an instance of the Updater class
updater <- Updater('YOUR BOT TOKEN')

# Writing a method for greeting
## greeting command
say_hello <- function(bot, update) {

  # Username to greet
  user_name <- update$message$from$first_name

  # Sending greeting message
  bot$sendMessage(update$message$chat_id, 
                  text = paste0("Hello, ", user_name, "!"),
                  parse_mode = "Markdown",
                  reply_to_message_id = update$message$message_id)

}

# creating filters
MessageFilters$hi <- BaseFilter(function(message) {

  # checking if the message text contains the words: hello, hi, salute, hey, bonjour
  grepl(x           = message$text, 
        pattern     = 'hello|hi|salute|hey|bonjour',
        ignore.case = TRUE)
  }
)

# creating handler 
hi_handler <- CommandHandler('hi', say_hello) # handler for the hi command
hi_txt_hnd <- MessageHandler(say_hello, filters = MessageFilters$hi)

# adding handlers to the dispatcher
updater <- updater + 
             hi_handler +
             hi_txt_hnd

# starting the bot
updater$start_polling()

Run the example code above, replacing 'YOUR BOT TOKEN' with the actual token you received when creating the bot through BotFather (I explained how to create a bot in first article)).

Now let's try sending the bot a few messages that contain the previously mentioned greeting words:
Creating a Telegram bot in R (part 2): Adding command support and message filters

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

But the main thing we did was 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 need to be added to the object MessageFilters, which already has a small set of built-in filters. In our example, we added an element to the object MessageFilters , which is a new filter. hiYou need to pass the filtering function. Essentially, a filter is just a function that receives a message instance and returns

In the function BaseFilter() . In our example, we wrote the simplest function that uses the basic function TRUE or FALSEgrepl() to check the message text, and if it matches the regular expression hello|hi|greeting|hey|bonjour Next, we create a message handler brings back TRUE.

hi_txt_hnd <- MessageHandler(say_hello, filters = MessageFilters$hi) MessageHandler(). The first argument of the function is the method that will call the handler, and the second argument is the filter according to which it will be called. In our case, this is the filter we created MessageFilters$hi And finally, we add the handler we just created to the dispatcher.

hi_txt_hnd updater <- updater + hi_handler + hi_txt_hnd.

As I mentioned earlier, in the package

and in the object telegram.bot there is already a set of built-in filters that you can use: MessageFilters all — All messages

  • text — Text messages
  • command — Commands, i.e., messages that start with
  • reply — Messages that are replies to another message /
  • audio — Messages that contain an audio file
  • document — Messages with a sent document
  • photo — Messages with sent images
  • sticker — Messages with a sent sticker
  • video — Messages with video
  • voice — Voice messages
  • contact — Messages that contain a Telegram user's contact
  • location — Messages with geolocation
  • venue — Forwarded messages
  • game — Games
  • If you want to combine some filters in one handler, just use the sign

— as a logical | , and the sign ORas a logical & as a logical one I can useFor example, if you want the bot to call the same method when it receives a video, image, or document, use the following example for creating a message handler:

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 make the bot execute the desired command. However, in some cases, besides the command name, we also need to pass certain data for it to execute.

Below is an example of a bot that returns the type of day from the production calendar based on the specified date and country.

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

Code 3: A bot that reports the type of day based on the date and country.

library(telegram.bot)

# Create an instance of the Updater class
updater <- Updater('1165649194:AAFkDqIzQ6Wq5GV0YU7PmEZcv1gmWIFIB_8')

# Write a method for greeting
## greeting command
check_date <- function(bot, update, args) {

  # Incoming data
  day     <- args[1]  # date
  country <- args[2]  # country

  # Check the entered parameters
  if ( !grepl('\d{4}-\d{2}-\d{2}', day) ) {

    # Send Custom Keyboard
    bot$sendMessage(update$message$chat_id, 
                    text = paste0(day, " - incorrect date, please enter a date in the format YYYY-MM-DD"),
                    parse_mode = "Markdown")

  } else {
    day <- as.Date(day)
    # Convert to POSIXtl format
    y <- format(day, "%Y")
    m <- format(day, "%m")
    d <- format(day, "%d")

  }

  # Country for checking
  ## Check if a country is specified
  ## If not specified, set to ru
  if ( ! country %in% c('ru', 'ua', 'by', 'kz', 'us') ) {

    # Send Custom Keyboard
    bot$sendMessage(update$message$chat_id, 
                    text = paste0(country, " - incorrect country code, possible values: ru, by, kz, ua, us. Requested data for Russia."),
                    parse_mode = "Markdown")

    country <- 'ru'

  }

  # Request data from API
  # Compose HTTP request
  url <- paste0("https://isdayoff.ru/api/getdata?",
                "year=",  y, "&",
                "month=", m, "&",
                "day=",   d, "&",
                "cc=",    country, "&",
                "pre=1&",
                "covid=1")

  # Get response
  res <- readLines(url)

  # Interpret response
  out <- switch(res, 
                "0"   = "Working day",
                "1"   = "Non-working day",
                "2"   = "Shortened working day",
                "4"   = "covid-19",
                "100" = "Error in date",
                "101" = "Data not found",
                "199" = "Service error")

  # Send message
  bot$sendMessage(update$message$chat_id, 
                  text = paste0(day, " - ", out),
                  parse_mode = "Markdown")

}

# Create a handler
date_handler <- CommandHandler('check_date', check_date, pass_args = TRUE)

# Add handler to dispatcher
updater <- updater + date_handler

# Start the bot
updater$start_polling()

Run the example code above, replacing 'YOUR BOT TOKEN' with the actual token you received when creating the bot through BotFather (I explained how to create a bot in first article)).

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

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

To allow the method we are creating to accept additional parameters along with the command, use the argument pass_args = TRUE in the function CommandHandler(), and when creating the method, in addition to mandatory parameters bot, update create an optional one — argsThe method created this way will accept parameters that you pass to the bot after the command name. Parameters must be separated by spaces, and they will be received in the method as a text vector.

Let's run and test our bot.

Creating a Telegram bot in R (part 2): Adding command support and message filters

Running the bot in the background

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

To do this, follow the algorithm described below:

  1. Save the bot's code in a file with the .R extension. In RStudio, this is done through the menu File, with the command Save As….
  2. Add the path to the bin folder, which is located in the folder where you installed the R language, to the Path variable, the instructions here.
  3. Create a plain text file with one line written in it: R CMD BATCH C:UsersAlseyDocumentsmy_bot.R. Instead of C:UsersAlseyDocumentsmy_bot.R write the path to your bot script. It is important that there are no Cyrillic characters or spaces in the path, as this may cause issues when starting the bot. Save it and change its extension from txt to bat.
  4. Open the Windows Task Scheduler. There are many ways to do this, for instance, open any folder and enter %windir%system32taskschd.msc /s. Other ways to launch it can be found here.
  5. In the upper right menu of the scheduler, click "Create Task...".
  6. In the "General" tab, assign an arbitrary name to your task and switch the toggle to "Run for all users".
  7. Go to the "Actions" tab, click "Create". In the "Program or script" field, click "Browse", find the file created in the second step bat , and click OK.
  8. Click OK, and if necessary, enter your operating system account password.
  9. 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 operate until you stop the task or turn off your PC or server on which it was launched.

Conclusion

In this article, we covered how to write a fully functional bot that can not only send messages but also respond to incoming messages and commands. The knowledge gained is already sufficient for solving most of your tasks.

In the next article, we will discuss how to add a keyboard to the bot for more convenient operation.

Subscribe to my telegram and youtube channels.

Source: habr.com

Buy reliable website hosting with DDoS protection, VPS VDS servers 🔥 Buy reliable website hosting with DDoS protection, VPS VDS servers | ProHoster