تطوير Chatbot لـ Facebook Messenger على node.js

المواد التي نعرضها على انتباهكم اليوم مكرسة لتطوير روبوت للدردشة على Facebook Messenger. سيرسل روبوت يسمى Aww Bot ، الذي يتواصل مع المستخدمين ، صورًا للقطط والكلاب اللطيفة.



الشروع في العمل


لنبدأ بإنشاء صفحة على Facebook عن طريق ملء الحقول المطلوبة. هذه الصفحة للبوت. بالإضافة إلى ذلك ، سنقوم بإنشاء تطبيق Facebook ، وبعد ذلك ، في صفحة إضافة منتج ، سنقوم بتوصيل منتج Messenger بالتطبيق. بعد ذلك ، سنجد أنفسنا في صفحة إعدادات المراسلة. هنا تحتاج إلى العثور على قسم إنشاء الرمز المميز فيه - حدد صفحة الروبوت في قائمة الصفحة. بعد ذلك ، سيتم سؤالك عن الأذونات وسيتم إنشاء رمز وصول. سيستخدم البوت هذا الرمز المميز لإجراء مكالمات إلى Facebook Messenger API ، مما سيسمح لها بالتواصل مع المستخدمين.

إعداد خادم الويب


سنستخدم node.js و express.js لإنشاء خادم HTTP. قم بتشغيل الأمر التالي:

npm install express body-parser request config --save 

أضف الكود التالي إلى index.js الذي يسمح لك بإنشاء خادم HTTP بسيط:

 'use strict'; let express = require('express'),   bodyParser = require('body-parser'),   app = express(); app.use(bodyParser.urlencoded({ extended: false })); app.use(bodyParser.json()); app.listen(8989, () => console.log('Example app listening on port 8989!')); app.get('/', (req, res) => res.send('Hello World!')); 

الآن ، إذا قمت بتشغيل الخادم وذهبت ، باستخدام متصفحك ، في http://127.0.0.1:8989 ، سترى صفحة تحتوي على استجابة الخادم - Hello World! .

HTTPS وبيئة التنمية المحلية


قبل الانتقال إلى تقنية Webhook ، نحتاج إلى تكوين HTTPS لبيئة التطوير. لن يقبل برنامج المراسلة عنوان Webhook المستخدم لإرسال إعلامات إلى خادمنا إذا كنت تستخدم شهادة SSL موقعة ذاتيًا. تتوفر شهادة مجانية من Let's Encrypt . هنا ، ومع ذلك ، يمكنك الحصول على شهادة لمجال فقط ، وليس لعنوان IP. سنستخدم خدمة ngrok ، والتي ستسمح لك بتنظيم الوصول إلى الخادم المحلي من خلال عنوان URL عام يستخدم HTTPS.

إعداد Ngrok


ngrok سهل. تحتاج فقط إلى تنزيل الأرشيف المضغوط من موقع المشروع وفك ضغطه وتشغيل الأمر التالي:

 ./ngrok http 80 

تذكر إعادة توجيه المنفذ 80 إلى 8989 في إعدادات WAN الخاصة بالموجه. نتيجة لذلك ، سيقوم ngrok بإنشاء عناوين HTTP و HTTPS عامة للخادم المحلي.

العمل مع إشعارات Webhook


يستخدم برنامج المراسلة تقنية Webhook للمصادقة وإرسال إعلامات حول الأحداث إلى تطبيقك. من وجهة نظر البرمجة ، كل هذا يتلخص في وظائف رد الاتصال المعتادة لمعالجة طلبات HTTP التي ستتلقى بيانات حول الأحداث ، مثل الرسائل التي يتلقاها برنامج الدردشة. لتحليل طلبات GET و POST ، سنستخدم وحدة body-parser .

أضف المسار التالي إلى التطبيق. هناك حاجة لمعالجة طلبات التحقق من Webhook.

 //   GET-  webhook app.get('/webhook', (req, res) => {   //  .    ,       let VERIFY_TOKEN = "SOMETHING_RANDOM";   //      let mode = req.query['hub.mode'];   let token = req.query['hub.verify_token'];   let challenge = req.query['hub.challenge'];   // ,     mode  token   if (mode && token) {       //   mode  token       if (mode === 'subscribe' && token === VERIFY_TOKEN) {           //   challenge             console.log('WEBHOOK_VERIFIED');           res.status(200).send(challenge);       } else {           //   '403 Forbidden'                res.sendStatus(403);       }   } }); 

تحتاج الآن إلى فتح إعدادات المراسلة ، والعثور على قسم Webhooks هناك وتكوين تكامل التطبيق مع إشعارات Webhook. في صفحة الإعدادات ، في حقل عنوان URL لرد الاتصال ، أدخل عنوان URL HTTPS الذي تم تلقيه من ngrok. يجب وضع رمز التحقق (الرمز الموجود في الرمز ويمثل سلسلة عشوائية أنشأناها) في حقل التحقق من الرمز المميز. بعد ذلك ، يجب أن تكون قادرًا على التحقق من الإعدادات وحفظها عن طريق النقر على الزر "تحقق والحفظ" إذا كان عنوان URL الخاص بك لمعالجة إشعارات Webhook متاحًا ويتطابق رمز التحقق مع الرمز الموجود في الرمز.


هيئ الرمز المميز وعنوان URL للتطبيق لتلقي إشعارات Webhook

بعد الحفظ ، حدد صفحتك من القائمة المنسدلة واشترك في أحداث الصفحة.

الآن قم بإنشاء مسار POST للتعامل مع أحداث POST من برنامج المراسلة. أضف التعليمات البرمجية التالية إلى التطبيق.

 //     webhook app.post('/webhook', (req, res) => {   let body = req.body;   if (body.object === 'page') {       // ,               body.entry.forEach(function(entry) {           //  entry.messaging  ,            //     ,    0           let webhook_event = entry.messaging[0];           console.log(webhook_event);           //  PSID            let sender_psid = webhook_event.sender.id;           console.log('Sender PSID: ' + sender_psid);           //  ,  , message   postback,           //     -           if (webhook_event.message) {               console.log(webhook_event.message)           } else if (webhook_event.postback) {               console.log(webhook_event.postback)           }       });       //  '200 OK'            res.status(200).send('EVENT_RECEIVED');   } else {       //  '404 Not Found',      ,           res.sendStatus(404);   } }); 

قمنا بإعداد التطبيق بحيث يتعامل مع نوعين من الأحداث - message وإعادة postback . للتحقق من تشغيل آلية إشعار Webhook ، افتح برنامج المراسلة وأرسل رسالة إلى صفحة الروبوت. إذا كان كل شيء يعمل كما ينبغي ، فسيتم تسجيل PSID للمرسل ومعلومات الحدث ومحتوى الرسالة. الآن سنكتب وظائف معالج للأحداث التي تهمنا.

 //   message const handleMessage = (sender_psid, received_message) => {   let response;   if (received_message.text) {   } } //   postback const handlePostback = (sender_psid, received_postback) => {   let response;   //    postback   let payload = received_postback.payload;   if(payload === 'GET_STARTED'){   } } 

تعد الطريقة handleMessage() مسؤولة عن معالجة الرسائل الواردة ، handlePostback() عن معالجة أحداث postback الواردة. قم بتحديث رمزك الحالي بإضافة مكالمات إلى هذه الطرق:

 //   //     - if (webhook_event.message) {   handleMessage(sender_psid, webhook_event.message); } else if (webhook_event.postback) {   handlePostback(sender_psid, webhook_event.postback); } 

الآن ، عندما نتلقى postback message أو postback ، سيتم إرسال البيانات إلى المعالجات المقابلة مع PSID الخاص بالمرسل.

تكوين شاشة الترحيب وأحداث إعادة النشر لبدء حوار مع الروبوت


عندما يبدأ مستخدم جديد محادثة مع الروبوت ، يتم عرض زر البدء في نافذة الدردشة. يمكنك تكوين حدث إعادة النشر الخاص بك لهذا الموقف. على سبيل المثال ، قم بتعيين رسالة لمستخدم يصف البوت وكيفية التواصل معه. لتهيئة التحية الخاصة بك ، قم بتشغيل أمر curl هذا في النهاية الطرفية:

 curl -X POST -H "Content-Type: application/json" -d '{ "greeting": [   {     "locale":"default",     "text":"Hello {{user_first_name}}! Are you ready to see the cutests cats and dogs"   } ] }' "https://graph.facebook.com/v2.6/me/messenger_profile?access_token=YOUR_PAGE_ACCESS_TOKEN" 

أنشأنا Aww Bot بحيث يعرض رسالة تسأل المستخدم عما إذا كان مستعدًا لرؤية ألطف القطط والكلاب. لتهيئة حدث إعادة النشر ، قم بتنفيذ هذا الأمر في النهاية الطرفية:

 curl -X POST -H "Content-Type: application/json" -d '{ "get_started": {"payload": "GET_STARTED"} }' "https://graph.facebook.com/v2.6/me/messenger_profile?access_token=YOUR_PAGE_ACCESS_TOKEN" 

إليك ما تبدو عليه جلسة الدردشة مع الروبوت.


شاشة البدء

إعداد التطبيق


سنستخدم وحدة التكوين npm لتخزين الرمز المميز للوصول إلى الصفحة في ملف تكوين منفصل. قم config دليل config في مشروعنا default.json فيه. في هذا الملف ، تحتاج إلى إضافة رمز الوصول إلى الصفحة وتسجيل هذا الملف في .gitignore .

 { "facebook": {   "page": {     "access_token": "PAGE_ACCESS_TOKEN"   } } } 

سنحصل على الرمز المميز للوصول إلى الصفحة في طريقة callSendAPI() باستخدام الأمر config.get('facebook.page.access_token') .

معالجة حدث البداية


إليك رمز معالجة حدث البدء.

 const handlePostback = (sender_psid, received_postback) => {   let response;   //   postback-   let payload = received_postback.payload;   if(payload === 'GET_STARTED'){       response = askTemplate('Are you a Cat or Dog Person?');       callSendAPI(sender_psid, response);   } } 

لنقم بإنشاء طريقة askTemplate() ، والتي ستعيد كائن استجابة معدة بشكل صحيح لواجهة برمجة تطبيقات messenger. callSendAPI() أسلوب callSendAPI() رسالة إلى المستخدم. أضف الطرق التالية إلى التطبيق:

 const askTemplate = (text) => {   return {       "attachment":{           "type":"template",           "payload":{               "template_type":"button",               "text": text,               "buttons":[                   {                       "type":"postback",                       "title":"Cats",                       "payload":"CAT_PICS"                   },                   {                       "type":"postback",                       "title":"Dogs",                       "payload":"DOG_PICS"                   }               ]           }       }   } } //     API Send const callSendAPI = (sender_psid, response, cb = null) => {   //      let request_body = {       "recipient": {           "id": sender_psid       },       "message": response   };   //  HTTP-  Messenger Platform   request({       "uri": "https://graph.facebook.com/v2.6/me/messages",       "qs": { "access_token": config.get('facebook.page.access_token') },       "method": "POST",       "json": request_body   }, (err, res, body) => {       if (!err) {           if(cb){               cb();           }       } else {           console.error("Unable to send message:" + err);       }   }); } 

نرسل للمستخدم رسالة تحتوي على زرين ونص. عندما يختار المستخدم ما يحتاجه من خلال النقر على الزر المناسب ، سيتم إرسال طلب إلى عنوان Webhook مع بيانات حدث postback وسنقوم بمعالجته.


يُطلب من المستخدم تحديد نوع الصورة التي تهمه.

معالجة أحداث إعادة النشر المخصصة


تحديث رمز وظيفة معالج حدث إعادة النشر:

 const handlePostback = (sender_psid, received_postback) => {   let response;   //   postback-   let payload = received_postback.payload;   //  ,       if (payload === 'CAT_PICS') {       response = imageTemplate('cats', sender_psid);       callSendAPI(sender_psid, response, function(){           callSendAPI(sender_psid, askTemplate('Show me more'));       });   } else if (payload === 'DOG_PICS') {       response = imageTemplate('dogs', sender_psid);       callSendAPI(sender_psid, response, function(){           callSendAPI(sender_psid, askTemplate('Show me more'));       });   } else if(payload === 'GET_STARTED'){       response = askTemplate('Are you a Cat or Dog Person?');       callSendAPI(sender_psid, response);   }   //   } 

عندما ينقر المستخدم على الزر Cats ، سيتم إرسال طلب يتضمن حدث postback يحتوي على بيانات CAT_PICS إلى عنواننا المستخدم لمعالجة إشعارات Webhook. سيؤدي اختيار خيار Dogs إلى إرسال حدث postback مع بيانات DOG_PICS . أضفنا طريقة أخرى إلى النظام ، imageTemplate() ، والتي تُرجع رسالة تحتوي على رابط لصورة قطة أو كلب.

أنشئ واجهة برمجة تطبيقات بسيطة تُرجع روابط الصور


سنكتب واجهة برمجة تطبيقات بسيطة لإرجاع الروابط إلى صور القطط أو الكلاب التي سيتم استخدامها في الرسائل التي يرسلها البوت إلى المستخدمين. قم pics.js ملف pics.js وأضف الكود التالي إليه:

 module.exports = {   cats : [       'https://i.imgur.com/Qbg7CeM.jpg',       'https://i.imgur.com/nUzkpJY.jpg',       'https://i.imgur.com/NpDcKph.jpg',       'https://i.imgur.com/oJtSDaO.jpg',       'https://i.redd.it/82ajpsrd17111.jpg',       'https://i.redd.it/00km1d2rt0111.jpg',       'https://i.redd.it/rdbavhp0y7111.jpg',       'https://i.redd.it/5hn3mg0n98111.jpg',       'https://i.redd.it/d23pb8mta6111.jpg',       'https://i.redd.it/d2gyrwgy7oz01.jpg',       'https://i.redd.it/z4sgl84q72z01.jpg',       'https://i.redd.it/wvykzo8n1cy01.jpg'   ],   dogs : [       'https://i.redd.it/6tjihi2qe7111.jpg',       'https://i.imgur.com/etRCs56.jpg',       'https://i.redd.it/nibw50f8y4111.jpg',       'https://i.redd.it/izcvnvj1o7111.jpg',       'https://i.redd.it/eqs1g9dldz011.jpg',       'https://i.redd.it/civ9dnu9u1111.jpg',       'https://i.redd.it/kk03qwclkp011.jpg',       'https://i.redd.it/2694pupjne011.jpg',       'https://i.redd.it/qk49ls5y6oy01.jpg',       'https://i.imgur.com/oM3mKgB.jpg',       'https://i.redd.it/8kx2riaulux01.jpg'   ] }; 

الآن قم بتوصيله في التطبيق.

 images = require('./pics'); 

أضف الطريقة التالية إلى الكود المستخدم لتكوين رسالة تحتوي على رابط للصورة.

 const = imageTemplate(type, sender_id) => {   return {       "attachment":{           "type":"image",           "payload":{               "url": getImage(type, sender_id),               "is_reusable":true           }       }   } } 

في عملية تفاعل المستخدم مع البوت ، يتم استخراج الصور بالتسلسل من المصفوفة وإرسالها كردود بوت للمستخدم. بعد إرسال الصورة الأخيرة ، نعود إلى أعلى القائمة.

نضيف الكود التالي إلى المشروع ، المصمم لتخزين ومعالجة البيانات حول المستخدمين الذين يتواصلون مع البوت.

 let users = {}; const = getImage(type, sender_id) => {   //       -     if(users[sender_id] === undefined){       users = Object.assign({           [sender_id] : {               'cats_count' : 0,               'dogs_count' : 0           }       }, users);   }   let count = images[type].length, //            user = users[sender_id], // ,         user_type_count = user[type+'_count'];   //          let updated_user = {       [sender_id] : Object.assign(user, {           [type+'_count'] : count === user_type_count + 1 ? 0 : user_type_count + 1       })   };   //      users = Object.assign(users, updated_user);   console.log(users);   return images[type][user_type_count]; } 

نقوم بتخزين PSID لكل من المستخدمين الذين يتواصلون مع البوت كمفتاح في كائن users . إذا لم يكن هناك سجل مستخدم حتى الآن ، فقم بإنشاء سجل جديد. سنقوم بتحديث معلومات رقم الصورة في كل مرة يطلب فيها المستخدم صورة قطة أو كلب. ثم نعيد المسار المطلق إلى الصورة التي سيتم استخدامها في قالب الرسالة. بعد ذلك ، نرسل رسالة تحتوي على الصورة في شكل رد على حدث postback الذي تم إنشاؤه عندما يختار المستخدم نوع الصورة التي تهمه.

 //  ,    postback- if (payload === 'CAT_PICS') {   response = imageTemplate('cats', sender_psid);   callSendAPI(sender_psid, response, function(){       callSendAPI(sender_psid, askTemplate('Show me more'));   }); } else if (payload === 'DOG_PICS') {   response = imageTemplate('dogs', sender_psid);   callSendAPI(sender_psid, response, function(){       callSendAPI(sender_psid, askTemplate('Show me more'));   }); } else if(payload === 'GET_STARTED'){   response = askTemplate('Are you a Cat or Dog Person?');   callSendAPI(sender_psid, response); } 

بالإضافة إلى ذلك ، بعد إرسال الصورة ، نقوم بتمرير وظيفة رد الاتصال إلى طريقة callSendAPI() لإرسال سؤال جديد للمستخدم حول الصور التي يهتم بها. إذا نجحت ، فإننا نسمي هذه الوظيفة. يسمح نظام العمل هذا ، مع مراعاة الطبيعة غير المتزامنة لوظائف رد الاتصال ، للمستخدم بتلقي رسالة تحتوي على سؤال حول الصورة التالية بعد إرسال رسالة إليه مع الصورة المطلوبة سابقًا.


التواصل مع البوت

الملخص


هنا هو مستودع لهذا المشروع. هناك ، في ملف readme.md ، يمكنك العثور على تعليمات تثبيت برنامج readme.md وتكوينه. لكي يتمكن الأشخاص الآخرون من الدردشة مع برنامج الروبوت الخاص بك ، يجب الموافقة على تطبيق Facebook الخاص بك. حتى هذه اللحظة ، لن يتمكن سوى المسؤولون والمختبرون في تطبيقك من التحدث مع الروبوت. هنا فيديو يوضح عملية التواصل مع الروبوت.

أعزائي القراء! هل تخطط لإنشاء برامج الروبوت لـ Facebook Messenger؟

Source: https://habr.com/ru/post/ar414081/


All Articles