ساخت یک ربات تلگرام با استفاده از Laravel و Botman

گردآوری و تالیف : عرفان کاکایی
تاریخ انتشار : 31 اردیبهشت 1397
دسته بندی ها : لاراول

معرفی

امروز، چیز متفاوتی برای شما داریم، امروز رباتی برای دوست داران حیوانات خانگی برای شما خواهیم ساخت. بله، درست خواندید. یک ربات تلگرام برای دوستداران سگ ها با استفاده از Dog API.

لاراول

جدول محتویات:

  1. معرفی
  2. نصب لاراول و باتمن
  3. ایجاد دستورات
  4. نصب درایور تلگرام
  5. ساخت ربات تلگرام
  6. نصب و اجرای ngrok
  7. اتصال ربات به تلگرام
  8. کلام آخر

هیجان زده شده اید؟ بیایید به بخش بعدی برویم.

نصب لاراول و باتمن

اولین قدمی که برای ساخت این ربات شگفت انگیر بر خواهیم داشت، نصب لاراول و باتمن خواهد بود. اما قبل از آن، بیایید نگاهی به این که باتمن چیست و چگونه کار می کند بیندازیم:

باتمن چیست؟

باتمن یک کتابخانه 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('roocket.ir for sure. Give me a harder question!!');
});

نصب Botman Studio

مارسل پوکیوت، سازنده باتمن با ساخت Botman Studio که آماده استفاده و شامل نرم افزار لاراول و دیگر ابزار (در ادامه پست با آن ها آشنا می شویم) می شود کار ما را آسان تر کرده است.

یک پروژه جدید بسازید:

composer create-project --prefer-dist botman/studio ilovedogs

حال که لاراول و باتمن را نصب کرده ایم، بیایید ببینیم که همه چیز به درستی کار می کند یا نه. ترمینال خود را باز کنید و این دستور را اجرا کنید:

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

یک متود ورودی داخل کلاس مورد نظر تعریف می کنیم:

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

اگر در حال استفاده از  باتمن استودیو هستید، باید یک فولدر به نام Conversations داخل فولدر App داشته باشید. حال به داخل آن فولدر می رویم و کلاس جدیدی ایجاد می کنیم و آن را 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\'');
    }
}

نصب درایور تلگرام:

پس از ایجاد دستورات، حال وقت ادغام کردن آنها با تلگرام است. برای انجام این کار، باید درایور تلگرام که توسط باتمن فراهم شده است را بالا بیاوریم:

composer require botman/driver-telegram

حال با موفقیت ربات خود را ساختیم، دستورات را نوشتیم و حال وقت ایجاد ربات تلگرام است. برنامه را باز کنید و BotFather را جست و جو کنید، بنویسید /newbot، نام کاربری ربات خود را وارد کنید و کار تمام است.

این بخش را به فایل .env خود اضافه کنید و YOUR_TOKEN را با نشانی که تلگرام به شما داده است جایگزین کنید:

TELEGRAM_TOKEN=YOUR_TOKEN

نصب و اجرای ngrok

از آنجایی که تلگرام به یک URL معتبر و امن برای دریافت پیام از کاربران شما نیاز دارد، ما از ngrok استفاده می کنیم. گرچه می توانید برنامه خود را بر روی یک سرور پیاده سازی کنید، اما ما با ngrok پیش خواهیم رفت. به لینک دانلود آن بروید و نسخه ای که با سیستم عامل شما سازگار است را دانلود کنید:

https://ngrok.com/download

حال به فولدر برنامه خود بروید و php artisan serve را اجرا کنید. سپس به فولدر ngrok بروید و ./ngrok http 8000 را اجرا کنید.

اتصال ربات به تلگرام:

آخرین قدم اتصال برنامه مان به رباتی است که ایجاد کردیم. برای این کار، یک درخواست از نوع POST را ارسال می کنیم و URL ای که ngrok به ما می دهد را میگیریم.

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"
}

کلام آخر:

امیدوارم که این آموزش برای شما پر استفاده بوده باشد. اگر شما هم ربات خود را ساخته اید، لطفا آن را در توییتر ما (RashidLaasri) به اشتراک بگذارید.

منبع

مقالات پیشنهادی

هک css - ساخت یک Dropdowns تنها با checkbox

در این آموزش سریع ، ما یک نگاه به تنها روش ساخت Dropdowns کردیم بعد تصمصیم گرفتیم به دنبال یک راه دیگه برای ساخت Dropdowns بگردیم که به یک روش هوشمندا...

آیکون های فروشگاهی و بازاریابی

در این پست لذت بخش من میخوام به شما یک مجموعه از آیکون های زیبا و ضررویه بازاریابی و فروشگاهی رو معرفی کنم که شامل +100 آیکون Swificons با 3 نوع مختلف...

آموزش ساخت برنامه موبایل توسط React Native – قسمت اول

در این سری آموزش‌ها میخوایم درباره ساخت اپلیکیشن های native برای ios و اندروید یاد بگیریم. اما این کار رو توسط فریمورک محبوب React Native Javascript ا...

نکاتی برای ساخت یک رابط کاربری زیبا و جذاب

رابط کاربری یا UI یک ملاحظه در طراحی هر چیزی است که باید استفاده شود. با اینکه طراحان صنعتی و طراحان گرافیک از اصول اولیه طراحی رابط کاربری در کار های...