📜 ⬆️ ⬇️

Telegram bot for complex quests

“What is the advantage?” - you ask, well, the whole thing is that you can build logic in it from about the following expressions:

- The user in step N?
- Does the message contain an image and a smiley?
- The text fits the regular expression “I am [a-zA-Z] +”?
- Time to receive earlier / later specified?
- Was it a press on the keyboard / a regular message / inline button?

Most of these rules may be dependent on each other, but more on that later.
')
First, what I want to tell you:

  1. About the idea of ​​the project - why I did it, what are the analogues, but why I do not like them.
  2. Architectural solutions , what difficulties arose, how they were solved.
  3. What happened in the end and whether it was worth further development .

Objective of the project


It was at the end of November, I understood that the new year was coming and I needed to give presents.
The idea with Telegram Bot, as a search card, seemed extremely simple and, in due course, interesting. The only thing that needed to be done was to take and google. What I actually did. The main message of the request is a platform for creating quests, or just a chat bot with additional logic written in python (preferably Django Framework)
Most of the reviewed applications either had hardened data, or were a kind of quiz. Neither the one nor the other.

Interesting options seemed: Django Telegram Bot , PermaBot .

There is no point in lingering on the first repository for a long time, since the description clearly states “Try Permabots: more stable django app for bots.”. Therefore we choose the second.
It is worth noting that this platform is made quite qualitatively, although without compliance with pep8 (not a stone in the garden, but this is the de facto standard :)), however, with comments, tests, and most importantly REST API documentation.

In the presence of all these advantages, significant shortcomings were found:


As a result, the project was launched with the following stack:

Web framework - Django, for asynchronous tasks - Celery, message broker -
Redis, database - SQLite. In the future, it is possible to move to Postgres / MySQL, but for the time being it is pointless to drag this whole machine with you.

What is worth noting, for the development and launch of the project, you need an external https address to which the web hooks will fly. To do this, you can use tunneling to a public domain via Ngrok or LocalTunnel .

I used localtunnel locally and on the server in conjunction with nginx and let's encrypt certificates.

Architecture


Entities:

Bot - contains general information and token (analog telegram.Bot in the office. Documentation )
Quest - quest model, everything is simple: name, description, bot. rendered to a separate entity for a logical distinction
Step - possible transition states. if the flag is is_init = True, then it will be selected as the initial one when the quest is initialized
Handler - acts as a dispatcher, has a logical expression that can be executed or not, depending on this, takes the user to a certain step and sends the corresponding answers (represented by the Response model)
Condition - contains possible rules for a specific field.
Update - an object that arrives with a web hook and contains all the information.
CallbackQuery is used for inline messages, there is no such opportunity to send (the main focus was on the basic keyboard), but the expansion options were taken into account.
Reponse - stores information about the message text, keyboard, its behavior (hide, delete, set by default, show default)
Message - received message object (telegram.Message)
Chat - stores chat information (telegram.Chat)
Photo - a model that stores information about the image (telegram.PhotoSize)
Event - is responsible for sending messages to a specific chat, and has the ability to simultaneously set the status (step) of the user. all additional data (text, keyboard, settings for it) is taken from the specified Reponse model
User - the user model inherited from contrib.auth.models.AbstractUser with indication of device_uid, step and some additional fields

The full UML diagram can be viewed in draw.io, db-diagram.xml file

It seems to me that one of the curious aspects is how the decision is made on the choice of a particular handler.

image

In the “Mathematics expression” field, a logical expression can be defined in two ways. The first is the one specified in the example, in this case the conditions for this handler will be substituted in the order of their addition, in the second variant you can specify the id of the conditions.

Then parsing is performed. It goes through two stages, first a conversion is made to a Boolean mapping, where 1 and 0 are the truth of a particular condition, and then the grammar is parsed using the pyparsing library.

Another difficulty that had to face - the choice and indication of the keyboard. It was decided to make one by default and the other to provide in response. Thus, it is possible to set a default for the entire chat, which may look something like this [[“Ask a Question”], [“Ask a Tip”]]]

image

You can also see that the telegram api allows you to hide the current keyboard when you press a button or delete it completely (in this case, the default is sent).

One more thing related to the keyboard is an attempt to find out what it was, either a regular message written by the user or a click on a button. What is it for?
Suppose at some step we decided to request a text response from the user and at the same time the standard keyboard with the “Change task” button is displayed there. Although Handlers contain optional Step on success and Step on error fields, it is much easier to organize the logic by limiting the type of action to which they react. For this, the Chat model also contains information about the current keyboard, which determines whether it is pressed or another type of event. This is useful when you need to know what's going on in a particular chat.

In addition, from the features that seemed necessary - this is the function redirect message. In each handler, you can specify who should redirect the message when rendering a verdict of truth. It comes in handy when you need to trace specific moments (the same question to the administrator) or the passage of some stages by the user.

Is it worth it?


Definitely. Testing took a couple of evenings, after which I set up and run it on the server. The quest consisted of 10+ states and included a choice of answer options, a story telling (the essence was in the search for keywords), a task on a map of the area, a photo of the year, and some more.

Perhaps the reaction of the person for whom I did it, paid for the evenings before the test week, which I spent.

Perspectives


At the moment, a working version is ready, which takes place in a docker-container in a couple of minutes, but for full development, tests, a thoughtful environment and some other settings are needed. If the project seems interesting to someone, then with a desire to continue support / development, the implementation of the frontend is questionable, but possible (on emberJS or vueJS).

Thank you for attention!

I will be glad to hear questions, suggestions, criticism

Source: https://habr.com/ru/post/347592/


All Articles