نستطيع استخدام البوتات الآلية (يُطلق عليها اسم بوتات bots عندما تكون في الويب) لتقديم بيانات مخصصة للمستخدمين بناءً على طلباتهم، إذ يتيح إطارا عمل لارافيل Laravel وبوتمان Potman الأدوات اللازمة لإنشاء بوتات قادرة على تنفيذ هذه المهمة بسهولة. نعمل في هذا المقال على إنشاء بوت تلغرام لمحبي الكلاب باستخدام DOG API، ويمكن اختيار أي نوعٍ مختلفٍ من البيانات عند الرغبة. يظهر البوت عند الانتهاء من العمل كما في الشكل التالي:
تثبيت لارافيل وبوتمان
يُعد إطار عمل بوتمان مكتبةً خاصةً بلغة البرمجة PHP، وصُمِّمَت لتبسيط عملية تطوير بوتات مبتكرة لمنصات المراسلة المتعددة، مثل منصة سلاك Slack، وتلغرام، وإطار عمل مايكروسوفت بوت وNixmo وفيسبوك وغيرها.
$botman->hears('Bot, What’s the best Web Development training website?', function (BotMan $bot) { $bot->reply('DigitalOcean for sure. Give me a harder question!!'); });
تثبيت بوتمان استوديو
وفّر المطور مارسيل بوكيوت Marcel Pociot كثيرًا من الوقت على المطورين من خلال تطويره برنامج بوتمان استوديو Botman Studio بالاعتماد على لارافيل مع بوتمان لنحصل على برنامج سهل الاستخدام محدّث باستمرار. ننشئ مشروعًا جديدًا ضمن بوتمان استوديو بتنفيذ التعليمة التالية في موجه الأوامر:
composer create-project --prefer-dist botman/studio ilovedogs
نتحقق من نجاح عملية التثبيت بتنفيذ التعليمة التالية في موجه الأوامر:
php artisan botman:tinker
يمكن إدخال الكلمة "Hi" في موجه الأوامر ليظهر الرد بعبارة "Hello" في حالة العمل الصحيح كما هو موضح بالشكل التالي:
إنشاء الأوامر
يتميز البوت الذي ننشئه بالقدرة على الرد على أنواع مختلفة من الرسائل والأوامر التي تصله، أي أنه يستطيع التعامل مع هذه الحالات:
- إرسال صورة عشوائية للكلاب من جميع السلالات.
- إرسال صورة عشوائية للكلب حسب سلالته.
- إرسال صورة عشوائية للكلب حسب سلالته وسلالته الفرعية.
- إجراء محادثة وتقديم المساعدة.
- الاستجابة للأوامر غير المعروفة.
لتحقيق هذه الوظائف، نفرغ محتوى الملف "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 { /** * الباني الخاص بالمتحكم * * @return void */ public function __construct() { $this->photos = new DogService; } /** * إعادة صورة عشوائية لكلب من إحدى السلالات * * @return void */ public function random($bot) { // $this->photos->random() يمثل رابط الصورة URL التي تعيدها هذه الخدمة // $bot->reply تمثل ما نستخدمه لإرسال الصورة إلى المستخدم $bot->reply($this->photos->random()); } }
ننشئ عينةً من الصنف DogService
الموجود ضمن الملف "app//services/DogService.php" ليكون مسؤولاً عن الاستجابة لاستدعاءات الواجهة البرمجية API الخاصة بجلب الصور ونضع به الشيفرة البرمجية التالية:
<?php namespace App\Services; use Exception; use GuzzleHttp\Client; class DogService { // عنوان الوجهة التي سنحصل منها على صورة الكلاب 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; } /** * إحضار وإعادة صورة كلب عشوائية من إحدى السلالات * * @return string */ public function random() { try { // التي استلمناها JSON فك ترميز استجابة $response = json_decode( // التي تعيد الجسم الخاص بالاستجابة API استدعاء $this->client->get(self::RANDOM_ENDPOINT)->getBody() ); // إعادة رابط الصورة return $response->message; } catch (Exception $e) { // نستخدم هذا السطر لإعادة رسالة الخطأ للمستخدم في حال وقوع مشكلة ما. 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 void */ public function byBreed($bot, $name) { // نترك أمر معالجة استدعاء الواجهة البرمجية إلى صنف الخدمة ونرد على الطلب القادم بالنتيجة فور وصولها إلينا $bot->reply($this->photos->byBreed($name)); }
نضيف التابع byBreed
إلى الصنف DogService
الذي أنشأناه على النحو التالي:
/** * جلب وإعادة صورة عشوائية من سلالة محددة * * @param string $breed * @return string */ public function byBreed($breed) { try { // لدى الطرف الآخر باسم الصنف المحدد %s نستبدل $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
المُستخدمة أعلاه إلى نفس الملف على النحو التالي:
// نقطة النهاية التي سنصل إليها للحصول على صورة عشوائية باسم سلالة معطى 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 { /** * التابع الباني للمتحكم * * @return void */ public function __construct() { $this->photos = new DogService; } /** * إعادة صورة عشوائية لكلب من إحدى السلالات * * @return void */ public function random($bot, $breed, $subBreed) { $bot->reply($this->photos->bySubBreed($breed, $subBreed)); } }
يجب إضافة نقطة الاتصال النهائية والتابع الذي حدثنا محتواه إلى الصنف DogService
:
// تعيد نقطة الاتصال النهائية صورة عشوائية لكلب من سلالة محددة وسلالة فرعية محددة const SUB_BREED_ENDPOINT = 'https://dog.ceo/api/breed/%s/%s/images/random';
/** * جلب وإعادة صورة عشوائية لصورة عشوائية من سلالة معينة وسلالة فرعية * * @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 { /** * إنشاء محادثة جديدة * * @return void */ public function index($bot) { // التي يوفرها إطار العمل بوتمان لبدء محادثة جديدة startConversation نستخدم التابع $bot->startConversation(new DefaultConversation); } }
إذا كنا نستخدم بوتمان ستوديو، نجد مجلد باسم "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 { /** * بدء المحادثة بالسؤال الاول * * @return void */ public function defaultQuestion() { // نبدأ المحادثة بإضافة السؤال الأول ونضبط الخيارات المتاحة للإجابة على هذا السؤال $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'), ]); // نسأل المستخدم السؤال الذي أعددناه return $this->ask($question, function (Answer $answer) { // نفحص إذا كان المستخدم قد كتب عبارة ما أم ضغط على أحد الخيارات if ($answer->isInteractiveMessageReply()) { // نقارن جواب المستخدم مع الإجابات المعدة مسبقًا switch ($answer->getValue()) { case 'random': $this->say((new App\Services\DogService)->random()); break; case 'breed': $this->askForBreedName(); break; case 'sub-breed': $this->askForSubBreed(); break; } } }); } /** * السؤال عن سلالة الكلب وسلالته الفرعية * * @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)); }); } /** *طلب اسم السلالة وإرسال الصورة * * @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])); }); } /** * بدء المحادثة * * @return void */ public function run() { // يُعد هذه التابع إقلاعي فهو ما سيجري تنفيذه أولًا $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 { /** * الإجابة برسالة عامة * * @param Botman $bot * @return void */ public function index($bot) { $bot->reply('Sorry, I did not understand these commands. Try: \'Start Conversation\''); } }
اختبار البوت
- إرسال صورة عشوائية للكلاب من جميع السلالات.
- إرسال صورة عشوائية للكلب حسب سلالته.
- إرسال صورة عشوائية للكلب حسب سلالته وسلالته الفرعية.
- إجراء محادثة وتقديم المساعدة.
- الاستجابة للأوامر غير المعروفة.
تثبيت برنامج تشغيل تلغرام
بعد الانتهاء من تطوير التطبيق يجب دمجه مع برنامج تلغرام، ولتحقيق ذلك نحتاج برنامج تشغيل التلغرام Telegram driver الذي يقدمه بوتمان والذي نحصل عليه بتنفيذ الأمر:
composer require botman/driver-telegram
إنشاء بوت تلغرام
نفتح تطبيق تلغرام ونبحث عن BotFather ونكتب "/newbot" وندخل اسم مستخدم البوت كما في الشكل:
نضيف الرمز إلى ملف "env." ونستبدل YOUR_TOKEN
بالرمز المميز Token الذي يقدمه تلغرام:
TELEGRAM_TOKEN=YOUR_TOKEN
تثبيت وتشغيل الأداة ngrok
يتطلّب التلغرام استخدام رابط URL صالح وآمن لإعداد الخطافات webhooks وتلقي الرسائل من المستخدمين، ولتحقيق ذلك نستخدم ngrok أو نضع التطبيق على خادم ونُعِد له شهادة SSL، ولكن لسهولة التنفيذ سنستخدم ngrok. نستطيع الحصول عليه من الموقع الرسمي باختيار النسخة المناسبة لنظام التشغيل الذي سنعمل عليه.
ننتقل إلى مجلد التطبيق وننفّذ التعليمة:
php artisan serve
ننتقل إلى المجلد الذي ثبتنا البرنامج ضمنه ونشغل الأداة ngrok بتنفيذ الأمر التالي:
/ngrok http 8000
ربط البوت بالتلغرام
نربط تطبيقنا ببوت التلغرام الذي أنشأناه مسبقاً بإرسال طلب من نوع POST إلى عنوان الرابط هذا وتمرير عنوان الرابط الذي ولّده ngrok:
https://api.telegram.org/bot{TOKEN}/setWebhook
نستخدم برنامج بوستمان أو أداة "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" }
الاختبار باستخدام تلغرام
- إرسال صورة عشوائية للكلاب من جميع السلالات.
- إرسال صورة عشوائية للكلب حسب سلالته.
- إرسال صورة عشوائية للكلب حسب سلالته وسلالته الفرعية.
- إجراء محادثة وتقديم المساعدة.
- الاستجابة للأوامر غير المعروفة.
الخاتمة
قدم هذا المقال طريقةً لتطوير بوت وربطه بإحدى وسائل التواصل الاجتماعي الشهيرة وهي التلغرام، إذ يمكن الاعتماد على إطار العمل بوتمان للربط مع العديد من وسائل التواصل الاجتماعي لتطوير بوت قادر على الاتصال بشريحة واسعة من المستخدمين، كما تضمن المقال خطوات تحديد الأوامر المتاحة للبوت ليتخاطب بها مع المستخدمين وطريقة التعامل مع الحالات الخاصة.
ترجمة -وبتصرف- للمقال How To Build a Telegram Bot with Laravel and BotMan لصاحبه Rachid Laasri.
أفضل التعليقات
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.