Хабрахабр

Как нужно и не нужно писать чат ботов на примере моего бота для игры в «Тайный Санта»

image

Предыстория

Год назад решил я создать телеграм бот для того, чтобы поиграть в достаточно популярную новогоднюю игру «Тайный Санта». Вдохновился я тем, что пару лет назад мы на работе компанией решили сыграть в эту игру (это показалось очень круто), и плюс я давно следил за клубом АДМ на Хабре. В октябре-ноябре прошлого года, я понял, что нужно сыграть между своей же компанией в этом году снова, но в этот раз не вытягивая имена написанные на листочке с шапки Деда Мороза, а более технологично, что ли. Поскольку все сидели в телеграме и мне было очень интересно написать туда бота, я решил это сделать именно на этой платформе
Кстати, год назад я уже писал об этом проекте статью на Хабре, но я ничего не говорил о реализации. Не говорил не зря, потому что было стыдно, что ли 🙂 Проект готовился только для компании на работе (человек 15-20 на максималках) а вышло так, что проект «стрельнул» в других кругах после пары статей на ресурсах. Далее, более популярные ресурсы сами начали меня рекламировать (я об этом даже не знал, до того как пошел из ниоткуда большой приток людей)
За месяц без единого вложения в рекламу я собрал 5000+ довольных игроков и очень сильно полюбил этот проект. Но помимо всех его бенефитов, в нем был один огромнейший минус, и это реализация.

Как это было год назад

Было забавно, что у меня была кнопка в боте «присоедениться к комнате». Да, именно присоедЕниться. Мне писали пофиксить этот грамматический баг, но я не рисковал, и вот почему 🙂 Далее, прикладываю кусок кода из прошлогодней версии бота.

elseif ($user['state'] == 7) else { $text = "Отлично! Если у Вас уже есть комната - напиши мне ее номер сюда, и ты присоеденишься к этой комнате"; $db->updateState($userId, 8); } }

Весь бот — это был один огромнейший index.php файлик, который жил за счет функции mb_stripos, по сути. При чем было очень много одинаковых «ифчиков». Т.е. mb_stripos($textMessage, 'присоедениться') !== false мог встретиться не единажды. Если ты поменяешь в кнопке слово «присоедениться» на «присоединиться», и забудешь поменять какой то ифчик (которых, опять же, много) всё может посыпаться. При чем это может быть не сразу заметно (просто бот на определенных сценариях будет не отвечать как надо). Разок я поменял текст, начали писать юзеры, что на определенном сценарии бот отвечает не как надо. Дальше я рисковать не хотел, и подумал, что ошибка не такая уж и критичная 🙂 В принципе, вы поняли. Если была кнопка, например «Найти случайного Санту», я зацеплялся на слово «случайного» через mb_stripos. Весело было, когда появлялась подобная кнопка, с подобным текстом, и когда не надо оно все попадало в не нужный if (если например и там и там есть слово «случайного») 🙂
Кстати, заметили $user['state']? На то время я ввёл «состояния», чтобы понимать, на каком состоянии сейчас находится пользователь. Захотел ли он присоединиться к комнате, например, или создать, или может он захотел в одиночную игру поиграть? И для каждого стейта свой набор ифчиков шел, который важно было также не сломать.
Крон файлик, кстати, лежал рядом с index.php, его можно было запустить на прямую из под браузера (видимо тогда меня это не особо волновало). Далее, когда вдруг хотелось добавить какой-то «стейт» (лучше бы я этого не хотел) мне приходилось окунаться в это г.., и с первой же попытки ничего конечно же не получалось. Все это еще и лежало на самом дешевом хостинге за 1$ в месяц, который мог меня послать куда подальше, когда начало писать в «час пик» достаточно большое количество человек.

Это был конечно сущий ад для программиста 🙂

К сожалению у меня не получилось на 70% даже разобраться в старом коде, даже при том, что тогда я пытался оставлять себе комментарии в коде, чтобы помочь себе через год 🙂 Что я решил делать в этом году
В этом году я понятное дело решил переписать бота (раз был немалый спрос в прошлом году), захотел зайти в старый код и разобраться, как это было в том году, чтобы перенести бизнес-логику.

Начал с вопроса: «а что же использовать для написания архитектуры так, чтобы потом не плакать?». Решил я просто вспоминать основные сценарии, а там и добавлять что-то новое по ходу дела. У нас есть небольшие статьи на Хабре о нем. После долгих исследований — выбор пал на Botman. Его можно поставить как на «чистую», так и сразу установить его сборку вместе с Laravel (да, есть сразу ботман установленный сверху Laravel). Если коротко, то Botman это очень классная вещь. Если вдруг вам не нравится Laravel, Вы можете использовать любой другой фреймворк, и сверху него установить Botman, либо же не использовать фреймворк вовсе. Я решил и остановиться на этой версии, поскольку Laravel это явно лучше, чем то, что было год назад 🙂 У него есть возможность кэширования из «коробки», удобный роутинг, artisan, миддлвары, удобность возможность работать с БД и прочие бенефиты. Кстати, Botman построен поверх ReactPHP, что как бы круто 🙂

Пример:
Далее, я буду описывать бенефиты Botman:
Есть единый файлик botman.php, в котором Вы можете описать все команды.

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

При написании команды /start, запустится StartConversation (который должен наследоваться от абстрактного класса Conversation) и реализовывать метод run().
Вопросы задаются достаточно удобно, пример:

$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') {

Заметили, что у Button мы можем задать value, и в последствии цепляться потом на него? То есть, на ваших глазах баг с «присоедЕниться» пофикшен, за счет того, что я цепляюсь на value() 🙂 Кстати, еще можно юзать isInteractiveMessageReply метод, который ответит на вопрос, написали ли вам текст, или нажали интерактивную кнопку, при ответе на вопрос заданный юзеру.
Ботман помог избавиться от стейтов, я могу в методе ask сделать еще один метод ask, например если человек нажал «присоединиться», я просто делаю еще один ask внутри этого if.

Вот еще несколько методов (из очень большого количества), которые предоставляет ботман, которые можно легко понять из названия:

$this->repeat($question);

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

$this->bot->reply($reply);

То есть, Вы можете написать свой код, изначально запустить его только для Telegram. Киллер же фичей ботмана является то, что один код может запускаться на многих платформах. Просто нужно будет установить драйвер и задать API Token вашего Facebook Messenger бота в .env. Потом, решить, что Вы хотите еще перейти в Facebook Manager, и вам совсем не надо начинать разбираться с SDK Facebook, разработчики Botman уже это сделали за вас. Весь функционал автоматически заработает в фейсбук мессенджере.
Botman поддерживает не только Facebook Messenger и Telegram, в этот список входят также Slack, Skype, WeChat (с полным списком можно ознакомиться у них на сайте).

Все бенефиты тяжело назвать, поскольку я явно не со всеми поработал, не все помню, но думаю того, что я описал, должно уже хватить, чтобы им как минимум заинтересоваться 🙂 Также «виновник торжества» славится тем, что с ним уже идет папочка tests/Botman (можете писать юнит тесты, ваш кэп), а также хорошей документацией.

Ну ок, а хостить опять на хостинге за $1 будем?

Не, в этом году всё серьезно. Хостинг за $10 в месяц и бесплатным доменом с ссл. Шучу 🙂
Решил подтянуть знания по докеру, купил VPS на DigitalOcean, и развернул проект в докере. Вышло достаточно неплохо, при том что я это всё делал чуть ли не в первый раз. На удивление докер ни разу не падал
С VPS конечно круче 🙂
При докере было сильно удобнее вести разработку (версионность на деве и на проде сохранилась)

Платежная система постоянно возвращала мне мою заявку на апрув, и говорила «сайт не работает». Самое забавное, что когда я вводил платный функционал в бота, мне нужно было получить апрув от платежной системы. Не долго думая, я увидел, что Роскомнадзор еще год назад забанил айпишник моего дроплета (очень много серверов DigitalOcean пострадало на то время от руки РКН). У меня работал, у друзей работал (мы из Украины), а вот у ребят из РФ не работал. С этим потом тоже порешали.

На чем написан же все таки твой бот?

  • PHP 7.3
  • Laravel
  • Botman

И всем советую использовать именно этот стэк при написании своих ботов на PHP (чтобы в последствии себе не стрелять в ногу, как это было у меня).

Что хоть нового в боте появилось?

Санта научился звонить

У Санты можно заказать звонок! Он даже будет Вас понимать и слушать 🙂
Санта звонит на указанный номер (с номеров USA), задает вопросы, например «как ты себя вёл в году?», «что хочешь на Новый Год?», «Стишок знаешь?» и т.д. Если пользователь говорит, что стишок не знает, то Санта пойдет по другому сценарию вопросов, если скажет, что знает, то Санта любезно попросит рассказать стишок 🙂 Еще: когда человек говорит свой список желаний на Новый Год Санте, Санта слушает, и присылает потом этот список желаний пользователю, который заказал звонок (вдруг, ребёнок закрылся от родителей в комнате, а им как-то надо узнать что же он попросил у Санты?). Также Санта присылает саму аудиозапись звонка с Сантой на память 🙂

Теперь можно узнать кто твой Санта

Зрада? Это же противоречит названию игры «Тайный Санта», разве нет? В принципе — да. НО в прошлом году от количества желающих узнать своего Санту мои ЛС разрывались. «Мне будет дарить подарок босс?», «Нам одной девочке не подарил подарок кто-то, можете сказать, кто ей должен был дарить?» ну и всё в таком роде. Сейчас есть такая возможность, но что бы было не повадно — такое удовольствие выйдет в $5.99 🙂

Это кайфово! Всем хорошего кода, написания своих чат-ботов, а также пишите свои проекты.

Да, действительно, в том году все играли с удовольствием, не представляя даже, что происходит внутри этого бота (я сам в шоке, как он пережил тот декабрь :)) В конце хочется вспомнить о том, что где-то читал, что:
Если бы вы знали, что ваши любимые проекты, которыми вы пользуетесь (фейсбуки, вк, и т.д) построены так, что на грани от того, чтобы упасть, вы бы были удивлены.

Если захотелось поиграть — велкам 🙂

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть