
في الجزء الأول ، اكتشفنا المبادئ الأساسية لتصميم التطبيقات وتطويرها لمساعد Google. حان الوقت الآن لكتابة مساعدك الخاص حتى يتمكن المستخدمون أخيرًا من اختيار فيلم للمساء. تواصل Shipa_o و raenardev و ComradeGuest مصمم الحديث.
اكتب الرمز الخاص بك
دعونا نحاول كتابة شيء أكثر تعقيدًا.
لنفترض أن وكيلنا يوصي بالأفلام حسب النوع.
نطلب منه "إظهار الرعب" ، وسيقوم الوكيل بتحليل النوع ، والبحث عن فيلم في المجموعة حسب النوع وعرضه على الشاشة.
بادئ ذي بدء ، سنقوم بتخزين مجموعة الأفلام في متغير:var json = { "filmsList": [ { "id": "1", "title": " : ", "description": " ", "genres": ["", "", ""], "imageUrl": "http://t3.gstatic.com/images?q=tbn:ANd9GcQEA5a7K9k9ajHIu4Z5AqZr7Y8P7Fgvd4txmQpDrlQY2047coRk", "trailer": "https://www.youtube.com/watch?v=RNksw9VU2BQ" }, { "id": "2", "title": " : 2 – ", "description": " ", "genres": ["", "", "", ""], "imageUrl": "http://t3.gstatic.com/images?q=tbn:ANd9GcTPPAiysdP0Sra8XcIhska4MOq86IaDS_MnEmm6H7vQCaSRwahQ", "trailer": "https://www.youtube.com/watch?v=vX_2QRHEl34" }, { "id": "3", "title": "", "description": " ", "genres": ["", "", ""], "imageUrl": "https://www.kinopoisk.ru/images/film_big/386.jpg", "trailer": "https://www.youtube.com/watch?v=xIe98nyo3xI" } ] };
exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => { const agent = new WebhookClient({ request, response }); let result = request.body.queryResult; let parameters = result.parameters; let outputContexts = result.outputContexts; let intentMap = new Map(); // agent parameters, intentMap.set('search-by-genre', searchByGenre.bind(this, agent, parameters)); agent.handleRequest(intentMap); }); function searchByGenre(agent, parameters) { let filmsList = json.filmsList; // let filteredFilms = filmsList.filter((film) => { // , return film.genres.some((genre) => genre == parameters.genre); }); // let firstFlim = filteredFilms[0]; // agent.add(firstFlim.title); // agent.add(new Card({ title: firstFlim.title, imageUrl: firstFlim.imageUrl, text: firstFlim.description, buttonText: ' ', buttonUrl: firstFlim.trailer })); // agent.add([ " ?", new Suggestion(" ?"), new Suggestion(""), new Suggestion("") ]); }
الآن أصبحت الإجابة أكثر إفادة.
نعرض نصًا ، بطاقة تحتوي على معلومات ونصائح:

ميزة جيدة في Dialogflow هي أنه خارج الصندوق المخصص للأجهزة المختلفة.
إذا كان الجهاز يحتوي على مكبرات صوت ، فسيتم التعبير عن جميع العبارات التي نرسلها إلى طريقة الإضافة ، وإذا لم تكن هناك شاشة ، فلن يتم عرض كائنات Card
Suggestion
.
نقوم بتوصيل قاعدة البيانات
دعونا نعقد المهمة ونضيف الحصول على البيانات من قاعدة البيانات (DB).
أسهل طريقة هي استخدام قاعدة بيانات Firebase في الوقت الفعلي.
على سبيل المثال ، سوف نستخدم API Admin Database API.
تحتاج أولاً إلى إنشاء قاعدة بيانات وملؤها.
يمكنك القيام بذلك في نفس المشروع الذي تم إنشاؤه للوظائف السحابية :

بعد امتلاء قاعدة البيانات ، قم بتوصيلها بالوفاء: // firebase-admin const firebaseAdmin = require('firebase-admin'); // firebaseAdmin firebaseAdmin.initializeApp({ credential: firebaseAdmin.credential.applicationDefault(), databaseURL: 'https://<ID->.firebaseio.com' }); // , function getFilmsList() { return firebaseAdmin .database() .ref() .child('filmsList') .once('value') .then(snapshot => { const filmsList = snapshot.val(); console.log('filmsList: ' + JSON.stringify(filmsList)); return filmsList; }) .catch(error => { console.log('getFilmsList error: ' + error); return error; }); }
يتطلب الوصول إلى قاعدة البيانات multithreading. تم تصميم واجهة برمجة تطبيقات قاعدة بيانات Firebase لاستخدام Promise . طريقة .once('value')
تعيدنا وعدًا. ثم نحصل على بياناتنا في الكتلة then()
ثم نعيد الوعد معهم نتيجة تنفيذ الوظيفة.
من المهم إعادة هذا الوعد إلى طريقة handleRequest()
، وإلا فسوف يخرج الوكيل من خلال رد الاتصال دون انتظار الرد ومعالجة النتيجة.
فيلم البحث عن الإصدار حسب النوع باستخدام قاعدة البيانات: 'use strict'; const functions = require('firebase-functions'); const firebaseAdmin = require('firebase-admin'); const { WebhookClient } = require('dialogflow-fulfillment'); const { Card, Suggestion } = require('dialogflow-fulfillment'); firebaseAdmin.initializeApp({ credential: firebaseAdmin.credential.applicationDefault(), databaseURL: 'https://<ID->.firebaseio.com' }); exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => { const agent = new WebhookClient({ request, response }); let result = request.body.queryResult; let parameters = result.parameters; let outputContexts = result.outputContexts; let intentMap = new Map(); intentMap.set('search-by-genre', searchByGenre.bind(this, agent, parameters)); agent.handleRequest(intentMap); }); function getFilmsList() { return firebaseAdmin .database() .ref() .child('filmsList') .once('value') .then(snapshot => { const filmsList = snapshot.val(); console.log('filmsList: ' + JSON.stringify(filmsList)); return filmsList; }) .catch(error => { console.log('getFilmsList error: ' + error); return error; }); } function searchByGenre(agent, parameters) { return getFilmsList() .then(filmsList => { let filteredFilms = filmsList.filter((film) => { return film.genres.some((genre) => genre == parameters.genre); }); let firstFlim = filteredFilms[0]; agent.add(firstFlim.title); agent.add(new Card({ title: firstFlim.title, imageUrl: firstFlim.imageUrl, text: firstFlim.description, buttonText: ' ', buttonUrl: firstFlim.trailer })); agent.add([ " ?", new Suggestion(" ?"), new Suggestion(""), new Suggestion("") ]); }) .catch(error => { console.log('getFilmsList error' + error); }); }
أضف عدم القدرة على التنبؤ
مهارتنا ستنتج أفلام بتسلسل واحد في كل مرة. نفس الإجابات سوف تزعج المستخدم في البداية ، ثم سيتوقف عن التحدث إلى الروبوت لدينا.
قم بإصلاح هذا مع مكتبة خلط الصفيف العشوائي.
أضف التبعية إلى ملف package.json
:
"dependencies": { // ... "shuffle-array": "^1.0.1" // ... }
أضف خلط الصفيف: // const shuffle = require('shuffle-array'); function searchByGenre(agent, parameters) { return getFilmsList() .then(filmsList => { let filteredFilms = filmsList.filter((film) => { return film.genres.some((genre) => genre == parameters.genre); }); // shuffle(filteredFilms); let firstFlim = filteredFilms[0]; agent.add(firstFlim.title); agent.add(new Card({ title: firstFlim.title, imageUrl: firstFlim.imageUrl, text: firstFlim.description, buttonText: ' ', buttonUrl: firstFlim.trailer })); agent.add([ " ?", new Suggestion(" ?"), new Suggestion(""), new Suggestion("") ]); }) .catch(error => { console.log('getFilmsList error' + error); }); }
الآن في كل مرة سيتم إصدار فيلم جديد.
بنفس الطريقة ، يمكنك إضافة مخرجات عبارات مختلفة: إنشاء مصفوفة مع عبارات ، ومزجها واتخاذ أول من الصفيف.
العمل مع السياق
نسأل الوكيل:
أظهر الخيال
الوكيل يعرض لنا فيلم "سيد الخواتم".
ثم نسأل:
ما الذي يتحدث عنه؟
الناس لا يقولون: "ما هو فيلم" سيد الخواتم "" غير طبيعي. لذلك ، نحتاج إلى حفظ معلومات حول الفيلم المعروض. يمكن القيام بذلك في سياق:
// , agent.setContext({ name: 'current-film', lifespan: 5, parameters: { id: firstFlim.id } });
ثم يمكننا قراءة المعلومات حول الفيلم مثل هذا: function genreSearchDescription(agent) { // current-film const context = agent.getContext('current-film'); console.log('context current-film: ' + JSON.stringify(context)); // id const currentFilmId = context.parameters.id; // return getFilmsList() .then(filmsList => { // id const currentFilm = filmsList.filter(film => film.id === currentFilmId); agent.add(currentFilm[0].description); agent.add([ ' ?', new Suggestion(''), new Suggestion(' ') ]); }) .catch(error => { console.log('getFilmsList error:' + error); }); }
بنفس الطريقة ، يمكننا تصفية قائمة الأفلام المعروضة بالفعل.
تكامل برقية
التوثيق والروابط المفيدة:
للتكامل مع Telegram ، لا يلزم تقريبًا أي شيء ، ولكن هناك العديد من الميزات التي يجب مراعاتها.
1) إذا كان ممتلئًا لعرض البطاقة أو الاقتراح ، فسيعملون أيضًا في Telegram.
ولكن هناك خطأ واحد: للردود السريعة ، يجب عليك تحديد عنوان ، وإلا سيتم عرض "اختيار عنصر" في Telegram.
حتى الآن لم ننجح في حل مشكلة الإشارة إلى العنوان في الرواية الكاملة.
2) إذا كان القصد يستخدم رقائق الاقتراح لمساعد جوجل

ثم يمكن تنفيذ نفس الوظيفة لـ Telegram بطريقتين:
ردود سريعة

حمولة مخصصة
هنا يمكنك تنفيذ إجابات سريعة باستخدام لوحة المفاتيح الرئيسية:

{ "telegram": { "text": " :", "reply_markup": { "keyboard": [ [ "", "", "", "", "" ] ], "one_time_keyboard": true, "resize_keyboard": true } } }
ولوحة المفاتيح المدمجة:

{ "telegram": { "text": " :", "reply_markup": { "inline_keyboard": [ [{ "text": "", "callback_data": "" }], [{ "text": "", "callback_data": "" }], [{ "text": "", "callback_data": "" }], [{ "text": "", "callback_data": "" }], [{ "text": "", "callback_data": "" }] ] } } }
سترسل لوحة المفاتيح الرئيسية رسالة سيتم تخزينها في السجل ، بينما لا ترسل لوحة المفاتيح المدمجة.
من المهم أن تتذكر أن لوحة المفاتيح الرئيسية لا تختفي بمرور الوقت. هناك طلب خاص لذلك في Telegram API. لذلك ، تحتاج إلى التأكد من أن المستخدم لديه دائمًا نصائح ذات صلة.
3) إذا كنت بحاجة إلى منطق مختلف لـ Telegram و Google Assistant ، فيمكنك القيام بذلك على النحو التالي:
let intentRequest = request.body.originalDetectIntentRequest; if(intentRequest.source == 'google'){ let conv = agent.conv(); conv.ask(' ?'); agent.add(conv); } else { agent.add(' ?'); }
4) يمكن تنفيذ إرسال ملف صوتي على النحو التالي:
{ "telegram": { "text": "https://s0.vocaroo.com/media/download_temp/Vocaroo_s0bXjLT1pSXK.mp3" } }
5) سيتم تخزين السياق في Dialogflow لمدة 20 دقيقة. عليك مراعاة ذلك عند تصميم روبوت Telegram. إذا كان المستخدم مشتتًا لمدة 20 دقيقة ، فلن يتمكن من المتابعة من نفس المكان.
أمثلة
سننشر كود مصدر المهارة قريبا. مباشرة بعد صدوره.
ملاحظة. ما حدث في الهاكاثون.

كان يومان مزدحمان.
في البداية كانت هناك محاضرات تعليمية ، وبعد الظهر بدأنا في تنفيذ مشاريعنا.
في اليوم التالي كان بنشاط مراجعة المشاريع وإعداد العروض التقديمية.
ساعدنا الأشخاص من Google طوال هذا الوقت وأجابوا على مجموعة من الأسئلة التي لا محالة في العمل. لقد كانت فرصة رائعة لتعلم الكثير وترك ملاحظات بينما المكواة لا تزال ساخنة.
شكرًا لجميع المشاركين ومنظمي Google والخبراء الذين ألقوا محاضرات وساعدونا طوال أحداث الهاكاثون!
بالمناسبة ، احتلنا المركز الثاني.
إذا كانت لديك أسئلة ، يمكنك الكتابة:
shipa_o
رينارديف
الرفيق
وكذلك هناك دردشة Telegram مخصصة لمناقشة الواجهات الصوتية ، اذهب:
https://t.me/conversational_interfaces_ru