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

Еще одна необходимая команда после установки

php artisan key:generate

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

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=loc-team.test 80

Или

ngrok http loc-team.test --host-header=loc-team.test

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

Перед установкой вэб-хука нужно

Создать бота через BotFather

Добавить в ваш .env файл строчку с токеном из BotFather

TELEGRAM_TOKEN='Ваш_токен'

Установка Вэб-хука для бота 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. Напишите первый комментарий
*Комментарий будет опубликован после проверки модератором

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

Загрузка изображения в Laravel

Русификация Laravel

Добавить поле к существующей таблице Laravel

Как поменять язык в Faker

Транслитерация URL в Laravel. Примеры str_slug()

Разработка бота Telegram с помощью Botman на локальном компьютере

Валидация данных в Laravel form request

Laravel Excel - Базовый экспорт

Добавить в botman editMessageText для Telegram

Как сделать middleware в Laravel 6 - простой пример

Laravel: Отношения моделей многие ко многим - belongsToMany

Laravel: Отношения моделей один ко многим - hasMany, belongsTo

Как русифицировать или поменять шаблон уведомления о сбросе пароля в Laravel

Создать ссылку на storage из внешнего каталога для Laravel

Установить Laravel в отдельную папку (site.ru/laravel/)

Валидация номера кредитной карты на PHP (Laravel)

Создание form request в Laravel: руководство для начинающих

Связать папку storage с папкой public в Laravel

Экспорт маршрутов из Laravel в JSON файл

Откуда в Laravel Jetstream (inertia) prop auth.user?

Постраничная навигация на Bootstrap в Laravel 8

Обработка ошибок в Laravel form request

Blade - расширить @section с использованием директивы @parent

Добавить данные об авторизации при каждом запросе к API в Laravel

Работа с файлами в Laravel Form Request

Работа с вложенными объектами и коллекциями в Laravel form request

Laravel: Отношение через таблицу-посредника - hasOneThrough()

Стандартные свойства модели в Laravel

Laravel: Отношения моделей один к одному - hasOne, belongsTo

Laravel: Отношение через таблицу-посредника - hasManyThrough()

Авторизацией и аутентификация в Laravel form request

Создание уникального индекса в миграции Laravel

Laravel form request для создания API-запросов

Настройка команды CRON на хостинге nic.ru для активации Laravel schedule

Установка Laravel и создание нового проекта

HTTP-запросы в Laravel form request - работа с различными типами запросов

Создание класса модели в Laravel

Создание таблицы в базе данных (миграции) для модели в Laravel

Как создать модель в Laravel

Базовые методы CRUD контроллера для модели в Laravel

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