序章

自動ボットは、ユーザーのリクエストに基づいてカスタマイズされたデータをユーザーに提供する方法です。 LaravelとBotmanフレームワークは、便利なボットを作成するためのツールを提供します。 このチュートリアルでは、 Dog API を使用して、犬愛好家向けのTelegramボットを作成します。これは次のようになります。

Laravel&Botmanのインストール

このボットを作成するための最初のステップは、LaravelBotmanをインストールすることです。 しかし、それを行う前に、まずボットマンとは何か、そしてそれがどのように機能するかを簡単に見てみましょう。

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));
}

を定義しましょう byBreed DogServiceクラスを開き、このメソッドを追加して、サービスクラスのメソッドを作成します。

/**
 * 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でテストしてください

  • すべての品種からランダムな犬の写真を送信します。

  • 犬種ごとにランダムな犬の写真を送信します。

  • その品種とサブ品種ごとにランダムな犬の写真を送信します。

  • 会話をして助けを提供する:

  • 認識されないコマンドに応答します。

結論

従い、独自のボットを作成した場合は、このチュートリアルがお役に立てば幸いです。