Botman + Telegram + Ngrok

Установка Botman

Предполагаю, что вы уже зарегистрировали бот через BotFather..

Botman — это по инстрмент для удобной и быстрой разработки ботов под любые платформы. Представляет из себя компонент для фреймворка Laravel. Однако если вы не знакомы с Laravel, то это не будет большой проблемой, так как экосистема Botman достаточно изолирована и самодостаточна. Вам хватит знаний PHP.

Установить Botman starter kit командой

composer create-project --prefer-dist botman/studio <directory>

После этого возможно появится ошибка, если установлен Composer 2. Тогда нужно выполнить команду

composer update

Затем нужно подгрузить модуль для работы с Телеграм

composer require botman/driver-telegram

Запустить сервер

php artisan serve

Как вести разработку чат-бота Telegram на локальном домене? Использовать Ngrok!

Если вы ведете разработку на локальной машине без внешнего IP, то возникнет трудность с регистрацией вэб Хука для обработки сообщений телеграм. Но проблема эта легко решается сервисом ngrok.com, от даст возможность связать локальный домен с доменом вида https://99328bcc9109.ngrok.io/, доступным в интернете. Еще очень удобно, что этот сервис сам генерирует https, даже если исходный домен без SSL.

Настройки Ngrok (бесплатный аккаунт)

Для начала нужно скачать эту программу себе на компьютер, разархивировать, запустить и ввести команду

authtoken [Ваш токен]

php artisan serve + Ngrok

Если вы используете команду php artisan serve для реализации веб-сервера, то скорее всего вам будет достаточно будет ввести команду (запустите ngrok.exe и там введите эту команду)

ngrok http 127.0.0.1:8000

Увидите примерно это:

Настройка Ngrok для OpenServer, Botman

Теперь ваш локальный http://127.0.0.1:8000 доступен по адресу https://df4c2ff466f6.ngrok.io. Класс!

OpenServer + Ngrok

OpenServer — это комплект утилит для реализации локального сервера, в том числе локальных доменов.

Если просто ввести команду ngrok http cb.test (cb.test — локальный домен), почему-то при заходе на поддомен Ngrok возникает синий экран с надписью "Как вы здесь оказались? Для перенаправления IP на нужный домен создайте алиас в настройках."

Поэтому следует указывать немного другую команду чтобы Ngrok работал корректно в связке с OpenServer:

ngrok http --host-header=cb.test 80

Важный нюанс про бесплатный аккаунт Ngrok

При каждом вызове команды ngrok http ... будет генерироваться новый поддомен. Это не очень здорово, но совсем не критично, просто нужно заново установить Вэб-хук для вашего бота.

Установка Вэб-хука для бота Telegram в Botman

Вводим команду

php artisan botman:telegram:register --output

В ответ на вопрос What is the target url for the telegram bot? Вводим https адрес, полученный из Ngrok, с прибавленным путем /botman, например вот такой:

https://df4c2ff466f6.ngrok.io/botman

Настройка завершена! Ваш локальный домен теперь используется в качестве веб-кука для бота!

Построение бота в Botman

Обработка входящих сообщений

В файле routes\botman.php прописываются команды, на которые будет реагировать ваш бот

Обработать входящее сообщение можно прямо тут же, хотя лучше использовать контроллер

$botman->hears('Hi', function ($bot) {
  $bot->reply("Hello! @" . $bot->getUser()->getUsername());
});

Данные пользователя

$botman->hears('Кто я', function ($bot) {
  $bot->reply("@" . $bot->getUser()->getUsername() . " - твой Username");
  $bot->reply($bot->getUser()->getId() . " - твой Id");
});

Разные варианты вопроса

$botman->hears(['yo', 'oy'], function ($bot) {
  $bot->reply("@" . $bot->getUser()->getUsername()." - твой Username");
});

Пример с использованием контроллера

$botman->hears('/start', BotManController::class . '@start');

Означает, что команда /start будет обработана методом start в контроллере BotManController. В этот метод будет передан объект класса BotMan

namespace App\Http\Controllers;
use BotMan\BotMan\BotMan;

class BotManController extends Controller {
  public function start(BotMan $bot){
    $bot->reply("Bot started");
  }
}

Составить диалог

По-настоящему раскрывает свой потенциал Botman именно в обслуживании диалогов. Вы можете создавать достаточно сложные диалоги, при этом их структура будет упорядоченной и лаконичной. Документация на английском

Для создания файла с диалогом введите команду. Появится новый файл в app\Conversations.

php artisan botman:make:conversation SimpleConversation

В этом методе сначала есть только метод run(). Но давайте постепенно добавим туда пару вопросов.

Пример диалога (Conversation) в Botman

В файле routes\botman.php добавляем строчку с активацией диалога:

$botman->hears('/simple',  function($bot){
  $bot->startConversation(new \App\Conversations\SimpleConversation());
});

И заполним диалог. Пока все очень просто. Сначала бот спросит имя, затем email. Ответы на вопросы будут сохраняться.

namespace App\Conversations;

use BotMan\BotMan\Messages\Conversations\Conversation;
use BotMan\BotMan\Messages\Incoming\Answer;

class SimpleConversation extends Conversation {

  public $user = [];

  public function askEmail() {
    $this->ask('Напиши свой E-mail, плз', function (Answer $answer) {
      $this->user['email'] = $answer->getText();

      $this->say('Спасибо '.$this->user['name'].', теперь оправлю тебе тонну спама на ' . $this->user['email']);
      //return $this->askGender();
    });
  }

  public function askName() {
    $this->ask('Привет, как тебя зовут?', function (Answer $answer) {
      // Сохраняем результат, и он будет доступен и в других вопросах/ответах
      $this->user['name'] = $answer->getText();

      $this->say('Приятно познакомиться, ' . $this->user['name']);
      
      // переход к следующему вопросу
      $this->askEmail();
    });
  }
  
  // Этот метод запускается при создании диалога
  public function run() {
    return $this->askName();
  }
}

Добавим кнопки в диалог

добавьте метод askGender(), и раскомментируйте return $this->askGender(); в методе askEmail().

  public function askGender() {
    $question = Question::create('Ваш гендер')
      ->addButtons([
        Button::create('Женский')->value('woman'),
        Button::create('Мужской')->value('man'),
        Button::create('Другое')->value('other'),
      ]);

    $this->ask($question, function (Answer $answer) {
      // Если кликнули по кнопке
      if ($answer->isInteractiveMessageReply()) {
        switch($answer->getValue()){
          case "woman":
            $this->bot->reply($this->user['name'].", ты прекрасна!");
            break;
          case "man":
            $this->bot->reply($this->user['name'].", твой дух силен!");
            break;
          case "other":
            $this->bot->reply($this->user['name'].", ты загадка!");
            break;
        }
      }else{
        // Если ввели тект, то задаем вопрос заново
        $this->bot->reply("Вы ввели текстом ". $answer->getText(). ", но надо нажать на кнопку..");
        return $this->askGender();
      }
    });
  }

Дебаг в Botman

Первое, что нужно знать - это сброс кэша во время диалогов. Чтобы заново начать общение выполните команду

php artisan cache:clear

Логирование и дебаг вашего приложение по-умолчанию достаточно скудный. Если ошибка на сервере, то вы просто получаете 500 ошибку в своем Ngrok.exe. Неприятным дополнением является то, что ошибка зацикливается, так как Telegram повторяет запросы к серверу. Чтобы их остановить нужно чтобы ваше приложение дало хоть какой-то ответ. А потом уже ищите в чем проблема по коду. В Laravel (Botman — это пакет/расширение для Laravel) ошибки записываются в файл storage\logs\laravel.log.

Функция для логирования в Laravel:

info('some string', $some_array);

Чтобы избежать зацикливания ошибки можно настроить приложение чтобы оно возвращало JSON при 500 ошибке. Telegram не будет опрашивать ваш сервер в надежде получить какой-то ответ. Он увидит, что какая-то "шляпа", и успокоится.

Для этого в файле app\Exceptions\Handler.php метод render()

Теперь вы можете отслеживать ошибки тут http://127.0.0.1:4040, если пользуетесь Ngrok.

public function render($request, Exception $exception) {
  return response()->json([
    'type' => get_class($exception),
    'message' => $exception->getMessage(),
    'file' => $exception->getFile(),
    'line' => $exception->getLine(),
    'trace' => $exception->getTrace(),
    'previous' => $exception->getPrevious(),
  ]);
}

Хорошо бы еще отслеживать исходящие данные. Для этого я использовал костыль. Наверняка есть способы лучше, но...

В файле vendor\botman\driver-telegram\src\TelegramDriver.php

В методе sendPayload перед return добавляем:

info('TG p', $payload);

В методе sendRequest перед return добавляем:

info('TG r', $parameters);

Теперь в файл логирования storage\logs\laravel.log будут попадать дынные ответа

Как отправить свой запрос, используя API Телеграма в обход оберток Botman

Пример из routes\botman.php

Документация Telegram - https://core.telegram.org/bots/api#sendmessage

$botman->hears('yo', function (BotMan $bot) {
  $bot->sendRequest('sendMessage', ['text' => 'text..', 'reply_markup' => json_encode([
    'inline_keyboard' => [
      [ ['text' => '11', 'callback_data' => "1-1"], ['text' => 'yo', 'callback_data' => "YO"] ],
      [ ['text' => 'yo', 'callback_data' => "YO"] ],
      [ ['text' => 'yo', 'callback_data' => "YO"] ],
    ]
    ], 256)]);
});

Обновление текста и кнопок во время диалога

Подробное описание в отдельной статье — Добавить в botman editMessageText для Telegram

Комментарии (0)

  1. Напишите первый комментарий
*Комментарий будет опубликован после проверки модератором

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

Наш сайт использует куки, нажмите «ОК» если вы не против
OK