מעשית: יצירת פעולה במדריך הטלוויזיה ל-Google Assistant באמצעות Dialogflow ו-Actions on Google

1. מבוא

אתם צופים בטלוויזיה, אבל לא מוצאים את השלט הרחוק, או שאולי לא רוצים לבקר בכל ערוץ טלוויזיה כדי להבין אם יש משהו נחמד בטלוויזיה? שנשאל את Google Assistant מה רואים בטלוויזיה! בשיעור ה-Lab הזה תפתחו פעולה פשוטה באמצעות Dialogflow ותלמדו איך לשלב אותה עם Google Assistant.

התרגילים מאורגנים כדי לשקף חוויה נפוצה של מפתחי ענן:

  1. יצירת נציג של Dialogflow גרסה 2
  2. יצירת ישות בהתאמה אישית
  3. יצירת כוונות
  4. הגדרת תגובה לפעולה מאתר אחר (webhook) באמצעות פונקציות של Firebase
  5. בדיקת הצ'אט בוט
  6. הפעלת השילוב של Google Assistant

מה תפַתחו

אנחנו ניצור סוכן צ'אט בוט אינטראקטיבי למדריך טלוויזיה בשביל Google Assistant. אפשר לשאול את מדריך הטלוויזיה מה משודר עכשיו בערוץ מסוים. לדוגמה: "What's on MTV? " בעזרת הפעולה של מדריך הטלוויזיה אפשר לדעת מה מושמע עכשיו ומה יהיה בהמשך.

מה תלמדו

  • איך יוצרים צ'אט בוט באמצעות Dialogflow v2
  • איך יוצרים ישויות בהתאמה אישית באמצעות Dialogflow
  • איך יוצרים שיחה לינארית באמצעות Dialogflow
  • איך מגדירים מילוי הזמנות ב-webhook בפונקציות של Dialogflow ו-Firebase
  • איך מעבירים את האפליקציה אל Google Assistant באמצעות Actions on Google

דרישות מוקדמות

  • כדי ליצור נציג ב-Dialogflow צריך כתובת ב-Google Identity או ב-Gmail.
  • לא נדרש ידע בסיסי ב-JavaScript, אבל הוא יכול לעזור לכם אם רוצים לשנות את קוד האספקה של התגובה לפעולה מאתר אחר (webhook).

2. בתהליך ההגדרה

הפעלת פעילות באינטרנט בדפדפן

  1. לוחצים על: http://myaccount.google.com/activitycontrols

  1. הקפדה על חיפוש באינטרנט ההגדרה 'פעילות באפליקציות' מופעלת:

bf8d16b828d6f79a.png

יצירת נציג ב-Dialogflow

  1. פותחים את: https://console.dialogflow.com

  1. בסרגל הימני, מתחת ללוגו, בוחרים באפשרות יצירת נציג חדש. אם יש לכם נציגים קיימים, צריך ללחוץ קודם על התפריט הנפתח.

1d7c2b56a1ab95b8.png

  1. בחירת שם הנציג: your-name-tvguide (באמצעות שם משלך)

35237b5c5c539ecc.png

  1. כברירת מחדל, בוחרים את שפת ברירת המחדל: אנגלית – en
  2. כאזור הזמן שמוגדר כברירת מחדל, בוחרים את אזור הזמן הקרוב ביותר אליכם.
  3. לחץ על צור.

הגדרה של Dialogflow

  1. בתפריט הימני, לוחצים על סמל גלגל השיניים ליד שם הפרויקט.

1d7c2b56a1ab95b8.png

  1. מזינים את תיאור הנציג הבא: המדריך שלי לטלוויזיה

26f262d359c49075.png

  1. גוללים למטה אל Log Settings (הגדרות היומן) והופכים את שני המתגים כדי לרשום את האינטראקציות של Dialogflow וכדי לתעד את כל האינטראקציות ב-Google Cloud Stackdriver. נזדקק למידע הזה בהמשך, אם נרצה לנפות באגים בפעולה שלנו.

e80c17acc3cce993.png

  1. לוחצים על שמירה.

הגדרת Actions on Google

  1. לוחצים על הקישור ל-Google Assistant בחלונית השמאלית, בקטע איך זה עובד ב-Google Assistant.

5a4940338fc351e3.png

הפעולה הזו תפתח את הכתובת: http://console.actions.google.com

משתמשים חדשים ב-Actions on Google צריכים למלא קודם את הטופס הזה:

3fd4e594fa169072.png

  1. מנסים לפתוח את הפעולה בסימולטור** על ידי לחיצה על שם הפרויקט.**
  2. בוחרים באפשרות בדיקה בסרגל התפריטים.

6adb83ffb7adeb78.png

  1. מוודאים שההגדרה של הסימולטור היא אנגלית ולוחצים על דיבור לאפליקציית הבדיקה שלי.

הפעולה הזו תכיל את פניכם, עם הגדרת ברירת המחדל הבסיסית של Dialogflow. המשמעות היא שהגדרת השילוב עם Action on Google עבדה!

3. ישויות מותאמות אישית

ישויות הן אובייקטים שהאפליקציה או המכשיר שלכם מבצעים בהם פעולות. אפשר לחשוב על זה בתור פרמטרים או משתנים. במדריך הטלוויזיה שלנו נשאל: "What's on MTV". MTV הוא הישות והמשתנה. אני יכול לבקש גם ערוצים אחרים, כמו: "National geo" או "Comedy Central". הישות שנאספה תשמש כפרמטר בבקשה שלי לשירות האינטרנט של TV Guide API.

מידע נוסף על ישויות של Dialogflow

יצירת ישות הערוץ

  1. לוחצים במסוף Dialogflow על האפשרות שבתפריט: ישויות.
  2. לוחצים על יצירת ישות
  3. שם הישות: channel (יש להקפיד להשתמש באותיות קטנות בלבד)
  4. להעביר את שם הערוץ. (בחלק מהערוצים נדרשת מילה נרדפת למקרה ש-Google Assistant תבין משהו אחר). אפשר להשתמש בכרטיסייה ולהזין מקשים תוך כדי הקלדה. מזינים את מספר הערוץ כערך של קובץ עזר. את שמות הערוצים כמילים נרדפות, כמו:
  • 1 - 1, Net 1, Net Station 1

ee4e4955aa77232d.png

5**.** עוברים למצב **עריכה גולמית** בלחיצה על לחצן התפריט שליד לחצן השמירה הכחול.

e294b49b123e034f.png

  1. העתקה & מדביקים את הישויות האחרות בפורמט CSV:
"2","2","Net 2, Net Station 2"
"3","3","Net 3, Net Station 3"
"4","4","RTL 4"
"5","5","Movie Channel"
"6","6","Sports Channel"
"7","7","Comedy Central"
"8","8","Cartoon Network"
"9","9","National Geographic"
"10","10","MTV"

ed78514afd5badef.png

  1. לוחצים על שמירה.

4. כוונות

ב-Dialogflow נעשה שימוש בכוונות כדי לסווג את כוונות המשתמש. לאובייקטים מסוג Intent יש ביטויים לאימון, שהם דוגמאות למה שמשתמש עשוי לומר לנציג. לדוגמה, משתמש שרוצה לדעת מה משודר בטלוויזיה עשוי לשאול, "What is on TV today? ", "מה פועל עכשיו?", או פשוט אומרים "tvguide".

כשמשתמש כותב או אומר משהו, שנקרא ביטוי משתמש, מערכת Dialogflow מתאימה את ביטוי המשתמש לכוונה הטובה ביותר של הנציג שלכם. התאמה של כוונת רכישה נקראת גם סיווג כוונת רכישה.

מידע נוסף על מנגנוני Intent של Dialogflow

שינוי של Intent הודעת הפתיחה שמוגדר כברירת מחדל

כשיוצרים נציג חדש ב-Dialogflow, המערכת יוצרת באופן אוטומטי שני אובייקטים מסוג Intent שמוגדרים כברירת מחדל. ברירת המחדל של כוונת הרכישה היא התהליך הראשון שאליו מגיעים כשמתחילים שיחה עם הנציג. ברירת המחדל של Intent חלופי היא הזרימה שאתם מקבלים ברגע שהנציג לא יכול להבין אתכם או לא יכול להתאים לכוונה למה שאמרתם.

  1. לוחצים על ברירת המחדל של כוונת הרכישה

במקרה של Google Assistant, היא תתחיל באופן אוטומטי עם ברירת המחדל של Intent המשתמש. הסיבה לכך היא ש-Dialogflow מאזין לאירוע הפתיחה. עם זאת, אתם יכולים לעורר את הכוונה גם על ידי אמירת אחד מביטויי האימון שהוזנו.

6beee64e8910b85d.png

זו הודעת הפתיחה לגבי ברירת המחדל של Intent קבלת הפנים:

משתמש

נציג

"Ok Google, talk to your-name-tvguide".

"Welcome, אני נציגה של מדריך הטלוויזיה. אוכל להראות לך מה מופעל עכשיו בערוץ טלוויזיה. לדוגמה, אפשר לשאול אותי: What's on MTV.

  1. גוללים למטה אל תגובות.
  2. ניקוי כל תגובות הטקסט.
  3. יוצרים תשובת טקסט חדשה אחת, שכוללת את הודעת הפתיחה הבאה:

Welcome, I am the TV Guide agent. I can tell you what's currently playing on a TV channel. For example, you can ask me: What's on MTV?

84a1110a7f7edba2.png

  1. לוחצים על שמירה.

יצירת כוונת בדיקה זמנית

למטרות בדיקה, ניצור כוונת בדיקה זמנית כדי שנוכל לבדוק את ה-webhook מאוחר יותר.

  1. לוחצים שוב על האפשרות Intents בתפריט.
  2. לוחצים על Create Intent.
  3. מזינים את שם ה-Intent: Test Intent (חשוב להקפיד להשתמש באות רישית ובאות גדולה I. - אם תאיתו את הכוונה בצורה שונה, השירות לקצה העורפי לא יפעל!)

925e02caa4de6b99.png

  1. לוחצים על הוספת ביטויים לאימון.
  • Test my agent
  • Test intent

2e44ddb2fae3c841.png

  1. לוחצים על מילוי הזמנה > הפעלת האפשרות למילוי הזמנות

7eb73ba04d76140e.png

הפעם אנחנו לא כותבים את התשובה בתוך הקוד. התשובה תגיע מפונקציה של Cloud Functions!

  1. מחליפים את המצב של המתג הפעלת קריאה לפעולה מאתר אחר (webhook) עבור ה-Intent הזה.

748a82d9b4d7d253.png

  1. לוחצים על שמירה.

יצירת כוונת הרכישה של הערוץ

כוונת הערוץ תכלול את החלק הבא בשיחה:

משתמש

נציג

"What's on Comedy Central? "

"עכשיו ב-Comedy Central מ-18:00, של 'סימפסונס' משודר. אחרי 19:00 יתחיל איש המשפחה".

  1. לוחצים שוב על האפשרות Intents בתפריט.
  2. לוחצים על Create Intent.
  3. מזינים את שם ה-Intent: Channel Intent (חשוב להשתמש באות רישית ובאות גדולה I. - אם תאיתו את הכוונה בצורה שונה, השירות לקצה העורפי לא יפעל!)
  4. לוחצים על הוספת ביטויי אימון ומוסיפים את הפרטים הבאים:
  • What's on MTV?
  • What's playing on Comedy Central?
  • What show will start at 8 PM on National Geographic?
  • What is currently on TV?
  • What is airing now.
  • Anything airing on Net Station 1 right now?
  • What can I watch at 7 PM?
  • What's on channel MTV?
  • What's on TV?
  • Please give me the tv guide.
  • Tell me what is on television.
  • What's on Comedy Central from 10 AM?
  • What will be on tv at noon?
  • Anything on National Geographic?
  • TV Guide

6eee02db02831397.png

  1. גוללים למטה אל פעולות ופרמטרים.

b7e917026760218a.png

שימו לב ל-@channel ול- ישויות @sys.time המוכרות ל-Dialogflow. בהמשך ה-webhook, שם הפרמטר וערך הפרמטר יישלחו לשירות האינטרנט שלך. לדוגמה:

channel=8

time=2020-01-29T19:00:00+01:00

  1. מסמנים את channel כנדרש

במהלך שיחה עם נציג ממדריך הטלוויזיה, תמיד צריך למלא את השם של פרמטר המיקום (channel). אם שם הערוץ לא צוין בתחילת השיחה, תוצג ב-Dialogflow בקשה נוספת עד שתמלא את כל משבצות הפרמטרים. 6f36973fd789c182.png

בהנחיה, צריך להזין:

  • For which TV channel do you want to hear the tv guide information?
  • In which TV channel are you interested?

cdb5601ead9423f8.png

  1. לא להגדיר את פרמטר הזמן כנדרש.

השעה תהיה אופציונלית. אם לא תציינו שעה, שירות האינטרנט יחזיר את השעה הנוכחית.

  1. לוחצים על מילוי הזמנה

הפעם אנחנו לא כותבים את התשובה בתוך הקוד. התשובה תגיע מהפונקציה של Cloud Functions! כך הופכים את המתג הפעלת קריאה לפעולה לפעולה מאתר אחר (webhook) עבור ה-Intent הזה.

  1. לוחצים על שמירה.

5. מילוי הזמנות של ה-webhook

אם הנציג צריך יותר מתשובות סטטיות ל-Intent, אתם צריכים להשתמש במילוי הזמנות כדי לחבר את שירות האינטרנט לנציג. חיבור שירות האינטרנט מאפשר לבצע פעולות על סמך ביטויי משתמשים ולשלוח תגובות דינמיות חזרה למשתמש. לדוגמה, אם משתמש רוצה לקבל את לוח הזמנים של טלוויזיית MTV, שירות האינטרנט יכול לבדוק במסד הנתונים שלכם ולהגיב למשתמש, את לוח הזמנים ל-MTV.

  1. לוחצים על מילוי הזמנה בתפריט הראשי.
  2. הפעלת המתג עורך מוטבע

cc84351f0d03ab6f.png

כדי לבצע בדיקה והטמעה פשוטים של webhook, אפשר להשתמש בכלי העריכה המוטבע. הוא משתמש ב-Cloud Functions for Firebase ללא שרת (serverless).

  1. לוחצים על הכרטיסייה index.js בעורך ומדביקים את קטע ה-JavaScript הזה עבור קוד Node.js:
'use strict';

process.env.DEBUG = 'dialogflow:debug';

const {
  dialogflow,
  BasicCard,
  Button,
  Image,
  List
 } = require('actions-on-google');

const functions = require('firebase-functions');
const moment = require('moment');
const TVGUIDE_WEBSERVICE = 'https://tvguide-e4s5ds5dsa-ew.a.run.app/channel';
const { WebhookClient } = require('dialogflow-fulfillment');
var spokenText = '';
var results = null;


/* When the Test Intent gets invoked. */
function testHandler(agent) {
    let spokenText = 'This is a test message, when you see this, it means your webhook fulfillment worked!';

    if (agent.requestSource === agent.ACTIONS_ON_GOOGLE) {
        let conv = agent.conv();
        conv.ask(spokenText);
        conv.ask(new BasicCard({
            title: `Test Message`,
            subTitle: `Dialogflow Test`,
            image: new Image({
                url: 'https://dummyimage.com/600x400/000/fff',
                alt: 'Image alternate text',
            }),
            text: spokenText,
            buttons: new Button({
                title: 'This is a button',
                url: 'https://assistant.google.com/',
            }),
        }));
        // Add Actions on Google library responses to your agent's response
        agent.add(conv);
    } else {
        agent.add(spokenText);
    }
}

/* When the Channel Intent gets invoked. */
function channelHandler(agent) {
    var jsonResponse = `{"ID":10,"Listings":[{"Title":"Catfish Marathon","Date":"2018-07-13","Time":"11:00:00"},{"Title":"Videoclips","Date":"2018-07-13","Time":"12:00:00"},{"Title":"Pimp my ride","Date":"2018-07-13","Time":"12:30:00"},{"Title":"Jersey Shore","Date":"2018-07-13","Time":"13:00:00"},{"Title":"Jersey Shore","Date":"2018-07-13","Time":"13:30:00"},{"Title":"Daria","Date":"2018-07-13","Time":"13:45:00"},{"Title":"The Real World","Date":"2018-07-13","Time":"14:00:00"},{"Title":"The Osbournes","Date":"2018-07-13","Time":"15:00:00"},{"Title":"Teenwolf","Date":"2018-07-13","Time":"16:00:00"},{"Title":"MTV Unplugged","Date":"2018-07-13","Time":"16:30:00"},{"Title":"Rupauls Drag Race","Date":"2018-07-13","Time":"17:30:00"},{"Title":"Ridiculousness","Date":"2018-07-13","Time":"18:00:00"},{"Title":"Punk'd","Date":"2018-07-13","Time":"19:00:00"},{"Title":"Jersey Shore","Date":"2018-07-13","Time":"20:00:00"},{"Title":"MTV Awards","Date":"2018-07-13","Time":"20:30:00"},{"Title":"Beavis & Butthead","Date":"2018-07-13","Time":"22:00:00"}],"Name":"MTV"}`;
    var results = JSON.parse(jsonResponse);
    var listItems = {};
    spokenText = getSpeech(results);

    for (var i = 0; i < results['Listings'].length; i++) {
        listItems[`SELECT_${i}`] = {
            title: `${getSpokenTime(results['Listings'][i]['Time'])} - ${results['Listings'][i]['Title']}`,
            description: `Channel: ${results['Name']}`
        }
    }
    if (agent.requestSource === agent.ACTIONS_ON_GOOGLE) {
        let conv = agent.conv();
        conv.ask(spokenText);
        conv.ask(new List({
            title: 'TV Guide',
            items: listItems
        }));
        // Add Actions on Google library responses to your agent's response
        agent.add(conv);
    } else {
        agent.add(spokenText);
    }
}

/**
 * Return a text string to be spoken out by the Google Assistant
 * @param {object} JSON tv results
 */
var getSpeech = function(tvresults) {
    let s = "";
    if(tvresults['Listings'][0]) {
        let channelName = tvresults['Name'];
        let currentlyPlayingTime = getSpokenTime(tvresults['Listings'][0]['Time']);
        let laterPlayingTime = getSpokenTime(tvresults['Listings'][1]['Time']);
        s = `On ${channelName} from ${currentlyPlayingTime}, ${tvresults['Listings'][0]['Title']} is playing.
        Afterwards at ${laterPlayingTime}, ${tvresults['Listings'][1]['Title']} will start.`
    }

    return s;
}

/**
 * Return a natural spoken time
 * @param {string} time in 'HH:mm:ss' format
 * @returns {string} spoken time (like 8 30 pm i.s.o. 20:00:00)
 */
var getSpokenTime = function(time){
    let datetime = moment(time, 'HH:mm:ss');
    let min = moment(datetime).format('m');
    let hour = moment(datetime).format('h');
    let partOfTheDay = moment(datetime).format('a');

    if (min == '0') {
        min = '';
    }

    return `${hour} ${min} ${partOfTheDay}`;
};

exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
    var agent = new WebhookClient({ request, response });

    console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
    console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
   
    let channelInput = request.body.queryResult.parameters.channel;
    let requestedTime = request.body.queryResult.parameters.time;
    let url = `${TVGUIDE_WEBSERVICE}/${channelInput}`;

    var intentMap = new Map();
    intentMap.set('Test Intent', testHandler);
    intentMap.set('Channel Intent', channelHandler);
    agent.handleRequest(intentMap);
});

cc84351f0d03ab6f.png

  1. לוחצים על הכרטיסייה package.json בעורך, מעתיקים ומדביקים את קטע הקוד הזה של קוד JSON, שמייבא את כל ספריות Node.js Package Manager (NPM):
{
  "name": "tvGuideFulfillment",
  "description": "Requesting TV Guide information from a web service.",
  "version": "1.0.0",
  "private": true,
  "license": "Apache Version 2.0",
  "author": "Google Inc.",
  "engines": {
    "node": "8"
  },
  "scripts": {
    "start": "firebase serve --only functions:dialogflowFirebaseFulfillment",
    "deploy": "firebase deploy --only functions:dialogflowFirebaseFulfillment"
  },
  "dependencies": {
    "actions-on-google": "^2.2.0",
    "firebase-admin": "^5.13.1",
    "firebase-functions": "^2.0.2",
    "request": "^2.85.0",
    "request-promise": "^4.2.5",
    "moment" : "^2.24.0",
    "dialogflow-fulfillment": "^0.6.1"
  }
}

af01460c2a023e68.png

  1. לוחצים על הלחצן פריסה. זה ייקח כמה רגעים, כי מתבצעת פריסה של הפונקציה ללא שרת (serverless). בתחתית המסך, יופיע חלון קופץ שמציין את הסטטוס.
  2. נבדוק את התגובה לפעולה מאתר אחר (webhook) כדי לראות אם הקוד עובד. בסימולטור שבצד שמאל, מקלידים:

Test my agent.

אם כל הפרטים נכונים, תופיע ההודעה "זוהי הודעת בדיקה".

  1. נבחן את 'כוונת הערוץ'. עכשיו נשאל את השאלה:

What's on MTV?

אם כל הפרטים נכונים, אתם אמורים לראות:

"ב-MTV מ-4 30:00, MTV UnPlugged פועל. לאחר מכן בשעה 17:00, יתחיל מרוץ הדראג של Rupauls."

שלבים אופציונליים – Firebase

כשתבצעו בדיקה בערוץ אחר, תראו שהתוצאות בטלוויזיה זהות. הסיבה לכך היא שהפונקציה של Cloud Functions עדיין לא שולפת משרת אינטרנט אמיתי.

כדי לעשות זאת, נצטרך ליצור חיבור לרשת יוצאי.

כדי לבדוק את האפליקציה הזו באמצעות שירות אינטרנט, צריך לשדרג את תוכנית Firebase ל-Blaze. הערה: השלבים הבאים הם אופציונליים. אפשר גם לעבור לשלבים הבאים בשיעור ה-Lab הזה כדי להמשיך לבדוק את האפליקציה ב-Actions on Google.

  1. עוברים אל מסוף Firebase: https://console.firebase.google.com

  1. בתחתית המסך, לוחצים על הלחצן שדרוג

ad38bc6d07462abf.png

בוחרים בתוכנית Blaze בחלון הקופץ.

  1. אנחנו יודעים שהתגובה לפעולה מאתר אחר (webhook) פועלת, ואנחנו יכולים להמשיך ולהחליף את הקוד של index.js בקוד שבהמשך. כך תוכלו לוודא שתוכלו לבקש מידע על מדריך הטלוויזיה משירות האינטרנט:
'use strict';

process.env.DEBUG = 'dialogflow:debug';

const {
  dialogflow,
  BasicCard,
  Button,
  Image,
  List
 } = require('actions-on-google');

const functions = require('firebase-functions');
const moment = require('moment');
const { WebhookClient } = require('dialogflow-fulfillment');
const rp = require('request-promise');

const TVGUIDE_WEBSERVICE = 'https://tvguide-e4s5ds5dsa-ew.a.run.app/channel';
var spokenText = '';
var results = null;


/* When the Test Intent gets invoked. */
function testHandler(agent) {
    let spokenText = 'This is a test message, when you see this, it means your webhook fulfillment worked!';

    if (agent.requestSource === agent.ACTIONS_ON_GOOGLE) {
        let conv = agent.conv();
        conv.ask(spokenText);
        conv.ask(new BasicCard({
            title: `Test Message`,
            subTitle: `Dialogflow Test`,
            image: new Image({
                url: 'https://dummyimage.com/600x400/000/fff',
                alt: 'Image alternate text',
            }),
            text: spokenText,
            buttons: new Button({
                title: 'This is a button',
                url: 'https://assistant.google.com/',
            }),
        }));
        // Add Actions on Google library responses to your agent's response
        agent.add(conv);
    } else {
        agent.add(spokenText);
    }
}

/* When the Channel Intent gets invoked. */
function channelHandler(agent) {
    var listItems = {};
    spokenText = getSpeech(results);

    for (var i = 0; i < results['Listings'].length; i++) {
        listItems[`SELECT_${i}`] = {
            title: `${getSpokenTime(results['Listings'][i]['Time'])} - ${results['Listings'][i]['Title']}`,
            description: `Channel: ${results['Name']}`

        }
    }
    if (agent.requestSource === agent.ACTIONS_ON_GOOGLE) {
        let conv = agent.conv();
        conv.ask(spokenText);
        conv.ask(new List({
            title: 'TV Guide',
            items: listItems
        }));
        // Add Actions on Google library responses to your agent's response
        agent.add(conv);
    } else {
        agent.add(spokenText);
    }
}

/**
 * Return a text string to be spoken out by the Google Assistant
 * @param {object} JSON tv results
 */
var getSpeech = function(tvresults) {
    let s = "";
    if(tvresults && tvresults['Listings'][0]) {
        let channelName = tvresults['Name'];
        let currentlyPlayingTime = getSpokenTime(tvresults['Listings'][0]['Time']);
        let laterPlayingTime = getSpokenTime(tvresults['Listings'][1]['Time']);
        s = `On ${channelName} from ${currentlyPlayingTime}, ${tvresults['Listings'][0]['Title']} is playing.
        Afterwards at ${laterPlayingTime}, ${tvresults['Listings'][1]['Title']} will start.`
    }

    return s;
}

/**
 * Return a natural spoken time
 * @param {string} time in 'HH:mm:ss' format
 * @returns {string} spoken time (like 8 30 pm i.s.o. 20:00:00)
 */
var getSpokenTime = function(time){
    let datetime = moment(time, 'HH:mm:ss');
    let min = moment(datetime).format('m');
    let hour = moment(datetime).format('h');
    let partOfTheDay = moment(datetime).format('a');

    if (min == '0') {
        min = '';
    }

    return `${hour} ${min} ${partOfTheDay}`;
};

exports.dialogflowFirebaseFulfillment = functions.https.onRequest((request, response) => {
    var agent = new WebhookClient({ request, response });

    console.log('Dialogflow Request headers: ' + JSON.stringify(request.headers));
    console.log('Dialogflow Request body: ' + JSON.stringify(request.body));
   
    let channelInput = request.body.queryResult.parameters.channel;
    let requestedTime = request.body.queryResult.parameters.time;
    let url = `${TVGUIDE_WEBSERVICE}/${channelInput}`;

    if (requestedTime) {
        console.log(requestedTime);
        let offsetMin = moment().utcOffset(requestedTime)._offset;
        console.log(offsetMin);
        let time = moment(requestedTime).utc().add(offsetMin,'m').format('HH:mm:ss');
        url = `${TVGUIDE_WEBSERVICE}/${channelInput}/${time}`;
      }
    
      console.log(url);
  
      var options = {
          uri: encodeURI(url),
          json: true
      };
       
      // request promise calls an URL and returns the JSON response.
      rp(options)
        .then(function(tvresults) {
            console.log(tvresults);
            // the JSON response, will need to be formatted in 'spoken' text strings.
            spokenText = getSpeech(tvresults);
            results = tvresults;
        })
        .catch(function (err) {
            console.error(err);
        })
        .finally(function(){
            // kick start the Dialogflow app
            // based on an intent match, execute
            var intentMap = new Map();
            intentMap.set('Test Intent', testHandler);
            intentMap.set('Channel Intent', channelHandler);
            agent.handleRequest(intentMap);
        });
});

6. Actions on Google

Actions on Google היא פלטפורמת פיתוח ל-Google Assistant. הוא מאפשר פיתוח של 'פעולות' על ידי צד שלישי – יישומונים ל-Google Assistant שמספקים פונקציונליות מורחבת.

כדי להפעיל פעולה ב-Google, צריך לבקש מ-Google לפתוח אפליקציה או לדבר איתה.

הפעולה הזו תפתח את הפעולה, תשנה את הקול ותתבצע יציאה מהשפה 'נייטיב' היקף ההרשאות של Google Assistant. כלומר, כל מה שמבקשים מהנציג בשלב הזה צריך ליצור על ידכם. אי אפשר יהיה לבקש מ-Google Assistant מידע על מזג האוויר ב-Google, אם זה מה שמעניין אותך. עליך להשאיר (לסגור) את היקף הפעולה (האפליקציה שלך).

בדיקת הפעולה בסימולטור של Google Assistant

נבדוק את השיחה הבאה:

משתמש

Google Assistant

"Ok Google, talk to your-name-tv-guide"

"בטח. אני רוצה לקבל your-name-tv-guide".

משתמש

נציגי הדרכה לטלוויזיה

-

"ברוכים הבאים, אני מדריך הטלוויזיה...."

בדיקת הנציג

"זו הודעת בדיקה. אם רואים אותה, המשמעות היא שמילוי הבקשות לפעולה מאתר אחר (webhook) עבד!"

מה מוצג ב-MTV?

ב-MTV החל מ-16:00, MTV UnPlugged פועל. לאחר מכן בשעה 17:00, יתחיל מרוץ הדראג של Rupauls.

  1. חוזרים לסימולטור של Google Assistant

פותחים את: https://console.actions.google.com

  1. לוחצים על סמל המיקרופון ושואלים את השאלות הבאות:

c3b200803c7ba95e.png

  • Talk to my test agent
  • Test my agent

Google Assistant אמורה לשלוח את הפרטים הבאים:

5d93c6d037c8c8eb.png

  1. עכשיו נשאל:
  • What's on Comedy Central?

הפלט אמור להחזיר:

כרגע משודרת משפחת סימפסון מ-18:00 ב-Comedy Central. ואז ב-19:00 יתחיל איש המשפחה.

7. מזל טוב

יצרת את הפעולה הראשונה שלך ב-Google Assistant ב-Dialogflow. כל הכבוד!

כפי שאולי הבחנת, הפעולה שלך פעלה במצב בדיקה, המקושר לחשבון Google שלך. אם תתחברו למכשיר Nest או לאפליקציית Google Assistant בטלפון iOS או Android, באמצעות אותו החשבון. גם לך יש אפשרות לבדוק את הפעולה שביצעת.

כעת זוהי הדגמה של סדנה. אבל כשיוצרים בקשות ל-Google Assistant באופן אמיתי, אפשר לשלוח את הפעולה לאישור. מידע נוסף זמין במדריך הזה.

אילו נושאים דיברנו?

  • איך יוצרים צ'אט בוט באמצעות Dialogflow v2
  • איך יוצרים ישויות בהתאמה אישית באמצעות Dialogflow
  • איך יוצרים שיחה לינארית באמצעות Dialogflow
  • איך מגדירים מילוי הזמנות ב-webhook בפונקציות של Dialogflow ו-Firebase
  • איך מעבירים את האפליקציה אל Google Assistant באמצעות Actions on Google

מה השלב הבא?

נהנית משיעור ה-Lab הזה של כתיבת קוד? בואו לראות את שיעורי ה-Lab המעולים האלה!

אתם יכולים לשלב את שיעור ה-Lab הזה ב-Google Chat כדי להמשיך:

איך יוצרים מדריך לטלוויזיה ב-Google Chat באמצעות G Suite ו-Dialogflow