LaravelとBotManでテレグラムボットを構築する方法
序章
自動ボットは、ユーザーのリクエストに基づいてカスタマイズされたデータをユーザーに提供する方法です。 LaravelとBotmanフレームワークは、便利なボットを作成するためのツールを提供します。 このチュートリアルでは、 Dog API を使用して、犬愛好家向けのTelegramボットを作成します。これは次のようになります。
Laravel&Botmanのインストール
このボットを作成するための最初のステップは、LaravelとBotmanをインストールすることです。 しかし、それを行う前に、まずボットマンとは何か、そしてそれがどのように機能するかを簡単に見てみましょう。
BotManは、フレームワークに依存しないPHPライブラリであり、Slack、Telegram、Microsoft Bot Framework、Nexmo、HipChat、Facebook Messenger、WeChatなどの複数のメッセージングプラットフォーム向けの革新的なボットを開発するタスクを簡素化するように設計されています。
$botman->hears('Bot, What’s the best Web Development training website?', function (BotMan $bot) { $bot->reply('DigitalOcean for sure. Give me a harder question!!'); });
BotmanStudioのインストール
Botmanの作成者であるMarcelPociot は、Botmanなどを使用してすぐに使用できる最新のLaravelアプリケーションである Botman Studio を作成することで、すでに時間を節約しています。テストツール(後で説明)が含まれています。
先に進み、新しいプロジェクトを作成します。
composer create-project --prefer-dist botman/studio ilovedogs
LaravelとBotmanを新たにインストールしたので、すべてが正常に機能しているかどうかを確認しましょう。 ターミナルを開き、次のコマンドを実行します。
php artisan botman:tinker
「こんにちは」と入力し、ボットが「こんにちは」と応答した場合は、準備ができています。
コマンドの作成
ボットはさまざまなメッセージタイプに応答できる必要があります。これは実装する機能のリストですが、もちろん、ボットに聞いてもらいたい追加のコマンドをいつでも追加できます。
- すべての品種からランダムな犬の写真を送信します。
- その品種ごとにランダムな犬の写真を送信します。
- その品種と亜品種ごとにランダムな犬の写真を送信します。
- 会話をして助けを提供してください。
- 認識されないコマンドに応答します。
routes/botman.php
ファイルをクリアして、最初から始めましょう。
すべての品種からランダムな犬の写真を送信します
ボットからランダムな犬の写真を受信するには、/random
を送信する必要があります。これにより、正確なコマンドに応答するように指示されます。
routes/botman.php
ファイル:
<?php use App\Conversations\StartConversation; $botman = resolve('botman'); $botman->hears('/random', 'App\Http\Controllers\AllBreedsController@random');
先に進み、コントローラーを作成します。
php artisan make:controller AllBreedsController
これはどのように見えるべきかです:
<?php namespace App\Http\Controllers; use App\Services\DogService; use App\Http\Controllers\Controller; class AllBreedsController extends Controller { /** * Controller constructor * * @return void */ public function __construct() { $this->photos = new DogService; } /** * Return a random dog image from all breeds. * * @return void */ public function random($bot) { // $this->photos->random() is basically the photo URL returned from the service. // $bot->reply is what we will use to send a message back to the user. $bot->reply($this->photos->random()); } }
最初にDogService
(app//services/DogService.php
)のインスタンスを作成しました。これは、エンドポイントへのAPI呼び出しの作成と画像の取得を担当し、次のようになります。
<?php namespace App\Services; use Exception; use GuzzleHttp\Client; class DogService { // The endpoint we will be getting a random image from. const RANDOM_ENDPOINT = 'https://dog.ceo/api/breeds/image/random'; /** * Guzzle client. * * @var GuzzleHttp\Client */ protected $client; /** * DogService constructor * * @return void */ public function __construct() { $this->client = new Client; } /** * Fetch and return a random image from all breeds. * * @return string */ public function random() { try { // Decode the json response. $response = json_decode( // Make an API call an return the response body. $this->client->get(self::RANDOM_ENDPOINT)->getBody() ); // Return the image URL. return $response->message; } catch (Exception $e) { // If anything goes wrong, we will be sending the user this error message. return 'An unexpected error occurred. Please try again later.'; } } }
その品種によってランダムな犬の写真を送信します
これには、コマンド/b {breed}
を使用し、上記と同じように、routes/botman.php
ファイルを開き、次の行を追加して、ボットにそのコマンドをリッスンするように指示します。
$botman->hears('/b {breed}', 'App\Http\Controllers\AllBreedsController@byBreed');
以前使用したものと同じコントローラーを使用します。 AllBreedsController
を開き、次のメソッドを追加します。
/** * Return a random dog image from a given breed. * * @return void */ public function byBreed($bot, $name) { // Because we used a wildcard in the command definition, Botman will pass it to our method. // Again, we let the service class handle the API call and we reply with the result we get back. $bot->reply($this->photos->byBreed($name)); }
DogServiceクラスを開き、このメソッドを追加して、サービスクラスのbyBreed
メソッドを定義しましょう。
/** * Fetch and return a random image from a given breed. * * @param string $breed * @return string */ public function byBreed($breed) { try { // We replace %s in our endpoint with the given breed name. $endpoint = sprintf(self::BREED_ENDPOINT, $breed); $response = json_decode( $this->client->get($endpoint)->getBody() ); return $response->message; } catch (Exception $e) { return "Sorry I couldn\"t get you any photos from $breed. Please try with a different breed."; } }
また、上記で使用したエンドポイントconst
を同じファイルに追加することを忘れないでください。
// The endpoint we will hit to get a random image by a given breed name. const BREED_ENDPOINT = 'https://dog.ceo/api/breed/%s/images/random';
その品種とサブ品種でランダムな犬の写真を送信します
サブブリードの写真の場合は、コマンド/s {breed}:{subBreed}
を使用してみましょう。
$botman->hears('/s {breed}:{subBreed}', 'App\Http\Controllers\SubBreedController@random');
コントローラの作成:
php artisan make:controller SubBreedController
次に、random
メソッドを次のように定義します。
<?php namespace App\Conversations; use App\Services\DogService; use App\Http\Controllers\Controller; class SubBreedController extends Controller { /** * Controller constructor * * @return void */ public function __construct() { $this->photos = new DogService; } /** * Return a random dog image from all breeds. * * @return void */ public function random($bot, $breed, $subBreed) { $bot->reply($this->photos->bySubBreed($breed, $subBreed)); } }
そして、必要なエンドポイントとメソッドをDogService
クラスに追加します。
// The endpoint we will hit to get a random image by a given breed name and its sub-breed. const SUB_BREED_ENDPOINT = 'https://dog.ceo/api/breed/%s/%s/images/random';
/** * Fetch and return a random image from a given breed and its sub-breed. * * @param string $breed * @param string $subBreed * @return string */ public function bySubBreed($breed, $subBreed) { try { $endpoint = sprintf(self::SUB_BREED_ENDPOINT, $breed, $subBreed); $response = json_decode( $this->client->get($endpoint)->getBody() ); return $response->message; } catch (Exception $e) { return "Sorry I couldn\"t get you any photos from $breed. Please try with a different breed."; } }
会話をして助けを提供する
会話は、ボットを構築するときに通常使用するものであり、ドキュメントでは次のように説明されています。
チャットボットに関しては、単一のキーワードに単純に反応したくない場合がありますが、代わりに、会話を使用してユーザーから情報を収集する必要がある場合があります。 たとえば、チャットボットがアプリケーションユーザーにエレガントなユーザーオンボーディングエクスペリエンスを提供するようにしたいとします。
routes/botman.php
ファイルに次の行を追加して、会話を作成しましょう。
$botman->hears('Start conversation', 'App\Http\Controllers\ConversationController@index');
コントローラを生成します。
php artisan make:controller ConversationController
そして、そのクラス内でindex
メソッドを定義します。
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller; use App\Conversations\DefaultConversation; class ConversationController extends Controller { /** * Create a new conversation. * * @return void */ public function index($bot) { // We use the startConversation method provided by botman to start a new conversation and pass // our conversation class as a param to it. $bot->startConversation(new DefaultConversation); } }
Botman Studioを使用している場合は、Appフォルダー内にConversationsフォルダーが既に存在するはずなので、先に進んでそのフォルダー内に新しいクラスを作成し、DefaultConversation.phpという名前を付けます。
<?php namespace App\Conversations; use BotMan\BotMan\Messages\Incoming\Answer; use BotMan\BotMan\Messages\Outgoing\Question; use BotMan\BotMan\Messages\Outgoing\Actions\Button; use BotMan\BotMan\Messages\Conversations\Conversation; class DefaultConversation extends Conversation { /** * First question to start the conversation. * * @return void */ public function defaultQuestion() { // We first create our question and set the options and their values. $question = Question::create('Huh - you woke me up. What do you need?') ->addButtons([ Button::create('Random dog photo')->value('random'), Button::create('A photo by breed')->value('breed'), Button::create('A photo by sub-breed')->value('sub-breed'), ]); // We ask our user the question. return $this->ask($question, function (Answer $answer) { // Did the user click on an option or entered a text? if ($answer->isInteractiveMessageReply()) { // We compare the answer to our pre-defined ones and respond accordingly. switch ($answer->getValue()) { case 'random': $this->say((new App\Services\DogService)->random()); break; case 'breed': $this->askForBreedName(); break; case 'sub-breed': $this->askForSubBreed(); break; } } }); } /** * Ask for the breed name and send the image. * * @return void */ public function askForBreedName() { $this->ask('What\'s the breed name?', function (Answer $answer) { $name = $answer->getText(); $this->say((new App\Services\DogService)->byBreed($name)); }); } /** * Ask for the breed name and send the image. * * @return void */ public function askForSubBreed() { $this->ask('What\'s the breed and sub-breed names? ex:hound:afghan', function (Answer $answer) { $answer = explode(':', $answer->getText()); $this->say((new App\Services\DogService)->bySubBreed($answer[0], $answer[1])); }); } /** * Start the conversation * * @return void */ public function run() { // This is the boot method, it's what will be excuted first. $this->defaultQuestion(); } }
認識されないコマンドに応答します。
最後に、ボットが認識しないメッセージを送信したときにユーザーに通知する必要があります。これは、フォールバック方式を使用して行うことができます。 routes/botman.php
と次の行を開きます。
$botman->fallback('App\Http\Controllers\FallbackController@index');
コントローラを作成します。
php artisan make:controller FallbackController
そして、ユーザーに見せたいメッセージを返すだけです。
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller; class FallbackController extends Controller { /** * Respond with a generic message. * * @param Botman $bot * @return void */ public function index($bot) { $bot->reply('Sorry, I did not understand these commands. Try: \'Start Conversation\''); } }
ボットのテスト
- すべての品種からランダムな犬の写真を送信します。
- 犬種ごとにランダムな犬の写真を送信します。
- その品種とサブ品種ごとにランダムな犬の写真を送信します。
- 会話をして助けを提供する:
- 認識されないコマンドに応答します。
TelegramDriverのインストール
コマンドの作成とテストに成功したら、Telegramと統合します。 そのためには、Botmanが提供するTelegramドライバーをプルする必要があります。
composer require botman/driver-telegram
テレグラムボットの作成
ボットの作成に成功し、コマンドを定義してテストしました。今度はテレグラムボットを作成します。 アプリを開いてBotFatherを検索し、 / newbot と入力して、ボットのユーザー名を入力すると、準備が整います。
これを.env
ファイルに追加し、YOUR_TOKENをTelegramから提供されたトークンに置き換えます。
TELEGRAM_TOKEN=YOUR_TOKEN
ngrokのインストールと実行
TelegramはWebhookを設定してユーザーからのメッセージを受信するために有効で安全なURLを必要とするため、ngrokを使用するか、サーバーにアプリをデプロイしてSSL証明書を設定できますが、デモではngrokを使用します。 ダウンロードページにアクセスし、オペレーティングシステムに一致するダウンロードボタンをクリックします。
次に、cd
をアプリフォルダーに挿入し、php artisan serve
を実行します。
ngrokを実行する時間です。ngrokがあるフォルダーにcdして、./ngrok http 8000
を実行します。
ボットをテレグラムにリンクする
最後のステップは、アプリを以前に作成したTelegram Botにリンクすることです。これを行うには、このURLにPOSTリクエストを送信し、生成されたURLngrokを渡します。
https://api.telegram.org/bot{TOKEN}/setWebhook
次のコマンドを実行して、PostmanまたはCURLでこれを行うことができます。
curl -X POST -F 'url=https://{YOU_URL}/botman' https://api.telegram.org/bot{TOKEN}/setWebhook
これを正しく行うと、次の正確なJSON応答を受け取るはずです。
{ "ok": true, "result": true, "description": "Webhook was set" }
Telegramでテストしてください
- すべての品種からランダムな犬の写真を送信します。
- 犬種ごとにランダムな犬の写真を送信します。
- その品種とサブ品種ごとにランダムな犬の写真を送信します。
- 会話をして助けを提供する:
- 認識されないコマンドに応答します。
結論
従い、独自のボットを作成した場合は、このチュートリアルがお役に立てば幸いです。