Application for a framework for a multi-platform bot


    Chatbots tightly entered our information life, all self-respecting social networks and instant messengers have support for bots, they provide a convenient API for their development and use, all for the convenience of users and programmers. Now, to create a bot in Telegram it is not even necessary to know any programming language. There are services that allow you to design a bot using the web interface. And this is really good, but just recently I ran into a problem and was surprised that on this wave of popularity of chatbots, which are now not only a cool feature, but also an income-generating tool - there is practically no answer.

    And the question is: what if I want to create more than one bot for one service? For example, I know that CA is sitting in Vkontakte and Telegram, how can I write bots with minimal effort to work with people there and there? If suddenly (for example, as the owner of an online store) I also want to work with the audience on Facebook using bots, do I really need to develop a new bot from scratch and rewrite all the logic for it or try to delve into a new API or library. And I tried to find the answer under the cut, I ask to the table.

    In fact, there are solutions, and there are many, but they all boil down to the fact that you must host your bot with a service that also provides a platform. That is, as such, you can’t get a boxed solution. Perhaps I’m wrong and did not fully study what actually exists, but the fact that the first link in Google does not lead to a solution is already alarming. There is also Botman . This is a really powerful full-fledged developing open source library with a bunch of chips and comprehensive documentation. And it is written in PHP. I have nothing against PHP, in any case, I do not acknowledge this publicly, so as not to breed an unnecessary holivar, but I do not want to conduct development on it at all. I decided to look for something similar to Python, in addition to Python, there are a lot of libraries that allow you to work with the Telegram Bot API. And I did not find anything, so I soon came to the conclusion that it was worth writing myself. (Maybe someone knows the appropriate solutions for multi-platform bots with an open system, I will be glad of any information)

    Here, by the way, another problem is brewing. I have absolutely no idea where else you can share work with the audience in the form of an article other than on Habré. I will be very glad to help in this matter.

    The name Botovod came by itself.

    In general, I will give a small code using Botovod and explain it briefly.
    Spoiler heading
    from botovod import Botovod, Message, utils
    def handler_message(agent, chat, text):
        message = Message()
        message.text = "Я получил сообщение"
        agent.send_message(chat, message)
    def handler_images(agent, chat, images):
        message = Message()
        message.text = "Я вижу фото"
        agent.send_message(chat, message)
    def handler_echo(agent, chat, message):
        agent.send_message(chat, message)
    settings = [
            "name": "telegram",
            "agent": "botovod.agents.telegram", 
            "settings": {"token": "462755273:AzBZBQ7AAnqFEXqZ_P8Z-qvCddmjqTVAYPI", "method": "polling"}
    botovod = Botovod(settings)

    Here we define 3 handlers for incoming messages, each sending something in response. The first: “I received a message,” the second: “I see a photo,” the third will simply send back what I received. Then we create a bot manager (Botovod) and pass it the settings for the bots, in this one for the bot in Telegram. Next, we sequentially add message handlers. If a message arrives at the bot, it will go to the first handler who agrees to accept it. For example, if an audio was sent to us, then the first handler will try to accept it first, but refuse, since this is not text. Then he will accept the second one, but also refuse, since this is not a picture, then he will accept the third one, which has no restrictions - in this way it will forward audio orthogonally. Constraints are imposed as decorators from the utils module.

    Now I will try to tell in detail what is what:

    There is a bot manager - an object of the Botovod class - the bot name (each has its own unique one), the agent class that will process it and the settings for the bot are passed to it in the constructor. Also, handlers are added to the bot manager in turn. If a message arrives at the bot, the manager will check them in turn until he finds the handler that throws the NotPassed exception. The first handler added is checked first, the last, respectively, the last. If you intend to use webhooks, then the bot manager can be connected to the web server. To do this, the bot manager has a listen method that accepts the bot name, headers and request body. Then it passes this data to the agent parser, which returns the generated message, after this message is pushed through the handlers. In response, the listen method returns the dictionary {"status": any_code, "headers": dict (), "body": "any_text"}, where in headers are the response headers, and in body is the response body. Sometimes the messenger / social network requires the server to return an object, so I think this behavior is convenient.

    I will give an example for the Vkontakte bot under the name "vk-bot", and Botovod will connect to the Django server

    def view(request):
        response = manager.listen("vk-bot", request.headers, request.text)
        return HttpResponse(status = response["status"], headers = response["headers"], response["body"])

    A formed message is an object of the Message class. It includes the following fields: text - message text; images - a list with images; audios - a list with sound files; videos - a list of videos; documents - a list with documents; locations - a list with places on the map; raw - the raw message body or additional information to it (dictionary).

    Also, each list of the Message object (images, audios, videos, documents) contains special objects whose classes are inherited from Attachment. The Attachment class by default has the url and file_path methods in which agent parsers usually put information about the received file. The locations list contains Location objects, to the constructor of which you need to pass longitude and latitude (longitude and latitude).

    Below is an example of constructing messages in handlers

    def handler(agent, chat, message):
        out = botovod.Message()
        image = botovod.Image()
        image.file_path = "/tmp/1.png"
        location = botovod.Location()    
        out.text = "Вот фото, что ты просил"
        agent.send_message(chat, out)

    This is all that is in it for now, but I hope that someone will be interested in such a solution and someone will want to help with advice, comment, idea, and maybe their own participation in the development. Thank you all for reading!

    Github link

    Also popular now: