How you need and don’t need to write a chat for bots using the example of my bot for playing Secret Santa

image



Background



A year ago, I decided to create a telegram bot in order to play the quite popular New Year's game “Secret Santa”. I was inspired by the fact that a couple of years ago we at work as a company decided to play this game (it seemed very cool), and plus, I watched the ADM club on Habr for a long time. In October-November last year, I realized that I needed to play between my own company this year again, but this time without pulling out the names written on a piece of paper from Santa Claus's hat, but more technologically, or something. Since everyone was in a telegram and it was very interesting for me to write a bot there, I decided to do it on this platform



By the way, a year ago I already wrote an article about this project on HabrĂ©, but I did not say anything about implementation. I didn’t speak for nothing, because it was a shame, perhaps :) The project was prepared only for the company at work (15-20 people at maximum speed), but it turned out that the project “shot” in other circles after a couple of articles on resources. Further, more popular resources themselves began to advertise me (I didn’t even know about it before a large influx of people went out of nowhere).



For a month, without a single investment in advertising, I gathered 5000+ satisfied players and really fell in love with this project. But besides all his benefits, there was one huge minus in him, and this is implementation.



How was it a year ago



It was funny that I had a button to join the room in the bot. Yes, it’s precisely the one that joins. They wrote to me to fix this grammar bug, but I didn’t risk it, and that’s why :) Next, I put a piece of code from last year’s version of the bot.



elseif ($user['state'] == 7) { if (mb_stripos($textMessage, '') !== false) { if (!empty($user['santa_for_user_id'])) { $text = '   ,      '; } else { $text = "!       -     ,      "; $db->updateState($userId, 8); } }
      
      





The whole bot - it was one huge index.php file that lived off the mb_stripos function, in fact. Moreover, there were a lot of identical “ifics”. Those. mb_stripos ($ textMessage, 'join')! == false could occur more than once. If you change the word "join" to "join" in the button, and forget to change some sort of ifchik (which, again, is a lot), everything can sprinkle. At what it may not be immediately noticeable (just a bot in certain scenarios will not respond as it should). Once I changed the text, users began to write that in a certain scenario the bot does not respond as it should. I didn’t want to take any further risks, and I thought that the mistake wasn’t so critical :) In principle, you understand. If there was a button, for example, “Find random Santa,” I got hooked on the word “random” through mb_stripos. It was fun when a similar button appeared, with similar text, and when it wasn’t necessary, it all got into an unnecessary if (if for example there is the word “random” both there and there) :)



By the way, did you notice $ user ['state']? At that time, I introduced “states” to understand what state the user is currently on. Did he want to join the room, for example, or create, or maybe he wanted to play a single game? And for each state, its own set of ifchi went, which was also important not to break.



Cron file, by the way, lay next to index.php, it could be launched directly from under the browser (apparently then it didn’t really bother me). Further, when I suddenly wanted to add some kind of “state” (I wish I didn’t want this) I had to plunge into this city, and from the first attempt, of course, nothing came of it. All this also lay on the cheapest hosting for $ 1 per month, which could send me to hell when a lot of people started writing at rush hour.



It was certainly a hell for a programmer :)



What I decided to do this year



This year, of course, I decided to rewrite the bot (since there was considerable demand last year), I wanted to go into the old code and figure out how it was that year in order to transfer the business logic. Unfortunately, I was not able to 70% even understand the old code, even though then I tried to leave comments for myself in the code to help myself in a year :)



I decided to just recall the main scenarios, and there and add something new along the way. He began with the question: “what to use for writing architecture so that you don’t cry later?” After much research, the choice fell on Botman . We have small articles on HabrĂ© about it. In short, Botman is a very cool thing. It can be installed both on a “clean” one, and you can immediately install its assembly with Laravel (yes, there is a botman installed immediately on top of Laravel). I decided to stay on this version, since Laravel is clearly better than what it was a year ago :) It has the ability to cache from the "box", convenient routing, artisan, middleware, the convenience of the ability to work with the database and other benefits. If suddenly you do not like Laravel, you can use any other framework, and install Botman on top of it, or you can’t use the framework at all . By the way, Botman is built on top of ReactPHP, which is cool :)



Next, I will describe the benefits of Botman:



There is a single file botman.php in which you can describe all the commands. Example:



 $botman->hears('/start', function (BotMan $bot) { $bot->startConversation(new StartConversation()); })->stopsConversation();
      
      





When writing the / start command, StartConversation will start (which should inherit from the abstract Conversation class) and implement the run () method.



Questions are asked quite conveniently, for example:



 $question = Question::create("   ,    ?")->addButtons([Button::create('')->value('create'), Button::create('')->value('join')]); $this->ask($question, function (Answer $answer) { if ($answer->isInteractiveMessageReply()) { if ($answer->getValue() == 'join') {
      
      





Notice that at Button we can set a value, and later cling to it later? That is, before your eyes the bug with the "join" is fixed, due to the fact that I cling to value () :)

By the way, you can still use the isInteractiveMessageReply method, which will answer the question whether you wrote the text or clicked the interactive button when answering the question asked to the user.



Botman helped get rid of the states, I can make another ask method in the ask method, for example, if a person clicked “join”, I just do another ask inside this if.



Here are a few more methods (from a very large number) that the botman provides, which can be easily understood from the name:

$ this-> repeat ($ question);


$ this-> bot-> typesAndWaits ($ secondsToWait);


$ this-> bot-> reply ($ reply);
The killer of the botman's features is that one code can run on many platforms. That is, you can write your code, initially run it only for Telegram. Then, decide that you still want to go to Facebook Manager, and you don’t have to start to deal with the Facebook SDK at all, Botman developers have already done this for you. You just need to install the driver and set the Token API of your Facebook Messenger bot in .env. All the functionality will automatically work on the Facebook messenger.

Botman not only supports Facebook Messenger and Telegram, this list also includes Slack, Skype, WeChat (a full list can be found on their website).



Also, the "hero of the occasion" is famous for the fact that he already has the daddy tests / Botman (you can write unit tests, your cap), as well as good documentation. It’s hard to name all the benefits, because I obviously didn’t work with everyone, I don’t remember everything, but I think that what I described should already be enough to be interested in them at least :)



Well, ok, but will we host again on the hosting for $ 1?



No, this year everything is serious. Hosting for $ 10 per month and a free domain with ref. Just kidding :)



I decided to improve my knowledge of the docker, bought a VPS on DigitalOcean, and launched the project in docker. It turned out pretty well, despite the fact that I did it almost the first time. Surprisingly, the docker never fell .



With VPS, of course, cooler :)



When docker, it was much more convenient to conduct development (versioning on the maiden and on the prod was preserved).



The funny thing is that when I introduced paid functionality in the bot, I needed to get an upgrade from the payment system. The payment system constantly returned to me my application for an upgrade, and said "the site is down." He worked for me, worked for friends (we are from Ukraine), but he didn’t work for guys from the Russian Federation. Without hesitation, I saw that Roskomnadzor still a year ago banned the IP address of my droplet (a lot of DigitalOcean servers were damaged by the ILV at that time). Then they also decided on this.



What is your bot written on?





And I advise everyone to use this particular stack when writing their bots in PHP (so as not to shoot yourself in the leg later, as I had).



What's new in the bot?



Santa learned to call



You can order a call from Santa! He will even understand and listen to you :)



Santa calls the indicated number (from USA numbers), asks questions, for example, “How did you behave in the year?”, “What do you want for the New Year?”, “Do you know the poem?”, Etc. If the user says that he doesn’t know the poem, then Santa will follow a different scenario of questions, if he says that he knows, then Santa will kindly ask you to tell the poem :) Also: when a person says his wish list for New Year to Santa, Santa listens, and then sends this wish list to the user who ordered the call (all of a sudden, the child was closed from his parents in the room, but they somehow need to find out what he asked Santa?). Santa also sends the audio recording of the call with Santa as a souvenir :)



Now you can find out who your Santa is.



Zrada? This is contrary to the name of the game "Secret Santa", is not it? I guess, yes. BUT last year, from the number of people who wanted to know their Santa, my drugs were torn. “Will the boss give me a present?”, “Someone didn’t give us one girl a present, can you tell who should have given her?” And so on. Now there is such an opportunity, but whatever it was - such a pleasure will come out at $ 5.99 :)



conclusions



You should not hope that your project will always be small. You do not need to create one index.php with a bunch of ifs, even if the project starts with just a couple of three ifs (I know enough of these projects)). Better to do right away. Even if you spend more time on it, it will give you benefits in that when you urgently need to change / add logic to the project, you did not have to think about how to change ifas so that the bot does not fall, as it turned out for me :). Also, this approach (with ifas) teaches you to make all other decisions crutched (not the best skill, agree). Well, of course, think about yourself, but you will have to go into this code later, and you will have to deal with it, and then it will not be very sweet :(



All the good code, writing your chat bots, and also write your projects. This is awesome!



In the end, I want to recall that I read somewhere that:

If you knew that your favorite projects that you use (Facebook, VK, etc.) are built so that on the verge of falling, you would be surprised. Yes, indeed, that year everyone played with pleasure, not even imagining what was going on inside this bot (I myself was shocked how he survived that December :)).



If you want to play - Wellcome :)



All Articles