實作內容:使用 Dialogflow 和 Actions on Google 為 Google 助理建立電視導覽動作

1. 簡介

你正在看電視,但找不到遙控器,或者不想逐一瀏覽每個電視頻道,看看是否有喜歡的節目?讓我們問問 Google 助理電視上正在播放什麼節目!在本實驗室中,您將使用 Dialogflow 建構簡單的動作,並瞭解如何與 Google 助理整合。

本實驗室包含多個練習,順序與常見雲端開發作業類似,包括:

  1. 建立 Dialogflow V2 代理程式
  2. 建立自訂實體
  3. 建立意圖
  4. 使用 Firebase Functions 設定 Webhook
  5. 測試聊天機器人
  6. 啟用 Google 助理整合功能

建構目標

我們將為 Google 助理建構互動式電視節目表聊天機器人代理程式。你可以詢問電視節目表,或特定頻道目前播放的內容。例如:「MTV 正在播什麼節目?」電視節目表動作會告訴你目前正在播放的節目,以及接下來的節目。

課程內容

  • 如何使用 Dialogflow V2 建立聊天機器人
  • 如何使用 Dialogflow 建立自訂實體
  • 如何使用 Dialogflow 建立線性對話
  • 如何使用 Dialogflow 和 Firebase Functions 設定 Webhook 執行要求
  • 如何透過 Actions on Google 將應用程式整合至 Google 助理

必要條件

  • 您需要 Google 身分 / Gmail 地址,才能建立 Dialogflow 虛擬服務專員。
  • 您不需要具備 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. 按一下「Create」(建立)

設定 Dialogflow

  1. 在左選單中,點選專案名稱旁的齒輪圖示。

1d7c2b56a1ab95b8.png

  1. 輸入下列代理程式說明:My TV Guide

26f262d359c49075.png

  1. 向下捲動至「記錄設定」,然後將兩個切換鈕都設為記錄 Dialogflow 的互動,以及記錄 Google Cloud Stackdriver 中的所有互動。我們稍後會需要這個 ID,以便偵錯動作。

e80c17acc3cce993.png

  1. 按一下「儲存」

設定 Actions on Google

  1. 按一下右側面板「瞭解 Google 助理的運作方式」中的「Google 助理」連結。

5a4940338fc351e3.png

系統會開啟:http://console.actions.google.com

如果您是 Google 助理動作的新手,請先填寫這份表單:

3fd4e594fa169072.png

  1. 點選專案名稱,在模擬器中開啟動作。**
  2. 選取選單列中的「測試」

6adb83ffb7adeb78.png

  1. 確認模擬器已設為「英文」,然後按一下「對我的測試應用程式下達語音指令」

這項動作會使用基本的 Dialogflow 預設意圖向您問候。這表示與 Google 助理整合的設定已完成!

3. 自訂實體

實體是指應用程式或裝置執行的動作對象。這就像參數 / 變數。在電視節目表,我們會詢問「MTV 正在播放什麼節目?」,MTV 是實體和變數。我也可以要求其他頻道,例如「國家地理頻道」或「Comedy Central」。收集到的實體將做為參數,用於向 TV Guide API 網路服務發出的要求。

進一步瞭解 Dialogflow 實體

建立頻道實體

  1. 在 Dialogflow 主控台中,按一下選單項目「Entities」(實體)
  2. 按一下「建立實體」
  3. 實體名稱:channel (請務必全部小寫)
  4. 傳遞頻道名稱。(如果 Google 助理理解的內容有誤,部分頻道需要同義詞)。輸入文字時,可以使用 Tab 鍵和 Enter 鍵。請輸入頻道號碼做為參照值。頻道名稱則視為同義詞,例如:
  • 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 會使用意圖將使用者的目的分類。意圖包含訓練詞組,這是使用者可能會向代理程式說的內容範例。舉例來說,想知道電視節目內容的使用者可能會問「今天電視上播什麼?」,「現在播放的是什麼?」或直接說「電視節目表」。

當使用者輸入或說出某項內容時 (稱為「使用者表達內容」),Dialogflow 會為使用者表達內容進行比對,找出代理程式中最相符的意圖。比對意圖的作業也稱為「意圖分類」

進一步瞭解 Dialogflow 意圖

修改預設的歡迎意圖

建立新的 Dialogflow 代理程式時,系統會自動建立兩個預設意圖。預設歡迎意圖是您與代理程式展開對話時,首先會遇到的流程。如果代理程式無法理解您說的內容,或無法比對您剛才說的內容與意圖,就會進入「Default Fallback Intent」(預設備用意圖) 流程。

  1. 按一下「Default Welcome Intent」

以 Google 助理為例,系統會自動啟動預設歡迎意圖。這是因為 Dialogflow 正在監聽歡迎事件。不過,你也可以說出輸入的訓練詞組,來叫用意圖。

6beee64e8910b85d.png

以下是預設歡迎意圖的歡迎訊息:

使用者

Agent

「Ok Google,與你的電視節目表對話。」

「歡迎,我是電視節目表專員。我可以告訴你電視頻道目前播放的內容。例如,你可以問我「MTV 在播什麼?」

  1. 向下捲動至「Responses」
  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. 再次按一下「意圖」選單項目。
  2. 按一下「建立意圖」
  3. 輸入意圖名稱:Test Intent (請務必使用大寫 T 和大寫 I。- 如果意圖的拼字不同,後端服務就無法運作!)

925e02caa4de6b99.png

  1. 按一下「新增訓練詞組」
  • Test my agent
  • Test intent

2e44ddb2fae3c841.png

  1. 依序點選「完成」>「啟用完成」

7eb73ba04d76140e.png

這次我們不會將回應寫死在程式碼中。回覆內容來自雲端函式!

  1. 將「Enable Webhook call for this intent」(為這個意圖啟用 Webhook 呼叫) 切換鈕設為開啟。

748a82d9b4d7d253.png

  1. 按一下「儲存」

建立管道意圖

頻道意圖會包含對話的這部分:

使用者

Agent

「Comedy Central 有什麼節目?」

「目前 Comedy Central 正在播放《辛普森家庭》,隨後在晚上 7 點,『居家大改造』就會開始。」

  1. 再次按一下「意圖」選單項目。
  2. 按一下「建立意圖」
  3. 輸入意圖名稱:Channel Intent (請務必使用大寫 T 和大寫 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

請注意 Dialogflow 已知的 @channel@sys.time 實體。稍後,系統會將參數名稱和參數值傳送至 Web 服務。例如:

channel=8

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

  1. 頻道標示為必要

與電視節目表代理程式對話時,一律須填寫空位參數名稱 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. 請勿將時間參數設為必要。

時間為選填欄位。如未指定時間,Web 服務會傳回目前時間。

  1. 按一下「履行」

這次我們不會將回應寫死在程式碼中。回應會來自 Cloud Functions!因此,請將「Enable Webhook call for this intent」(為這個意圖啟用 Webhook 呼叫) 切換鈕設為開啟。

  1. 按一下「儲存」

5. Webhook 履行

如果代理程式需要的不只是靜態意圖回應,您則必須使用「執行要求」將網路服務連結至代理程式。連結網路服務可讓您依據使用者表達內容採取行動,並將動態回應傳回使用者端。舉例來說,如果使用者想接收 MTV 的電視節目表,您的網路服務可以檢查資料庫,並將 MTV 的節目表傳送給使用者。

  1. 按一下主選單中的「Fulfillment」
  2. 啟用「Inline Editor」(內嵌編輯器) 切換按鈕

cc84351f0d03ab6f.png

如要進行簡單的 Webhook 測試和導入作業,可以使用內嵌編輯器。這項服務會使用無伺服器的 Cloud Functions for Firebase

  1. 在編輯器中按一下「index.js」index.js分頁,然後複製並貼上這段 Node.js 程式碼的 JavaScript:
'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」package.json分頁,然後複製並貼上這段 JSON 程式碼,匯入所有 Node.js 套件管理員 (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. 按一下「部署」按鈕。部署無伺服器函式需要一些時間,畫面底部會顯示彈出式視窗,說明狀態。
  2. 讓我們測試 Webhook,看看程式碼是否正常運作。在右側的模擬工具中輸入:

Test my agent.

如果一切正常,您應該會看到「這是測試訊息」。

  1. 現在來測試頻道意圖,請提出以下問題:

What's on MTV?

一切正確無誤時,您應該會看到:

「On MTV from 4 30 pm, MTV Unplugged is playing. 隨後在下午 5 點 30 分,將播出魯保羅變裝皇后秀。」

選用步驟 - Firebase

使用其他管道測試時,你會發現電視結果相同。這是因為雲端函式尚未從實際的網路伺服器擷取資料。

為此,我們需要建立輸出網路連線

如要使用網路服務測試這個應用程式,請將 Firebase 方案升級為 Blaze。注意:這些步驟為選用步驟。您也可以繼續進行本實驗室的後續步驟,在 Actions on Google 中繼續測試應用程式。

  1. 前往 Firebase 控制台:https://console.firebase.google.com

  1. 按下畫面底部的「升級」按鈕

ad38bc6d07462abf.png

在彈出式視窗中選取「Blaze」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 助理的開發平台。第三方開發人員可透過這項服務開發「動作」,也就是 Google 助理的小程式,提供擴充功能。

你必須呼叫 Google 動作,要求 Google 開啟或與應用程式互動。

這會開啟動作、變更語音,並離開「原生」Google 助理範圍。也就是說,您之後要求代理執行的所有動作,都必須由您建立。如果想請 Google 助理提供 Google 天氣資訊,您不能突然提出要求,必須先離開 (關閉) 動作範圍 (您的應用程式)。

在 Google 助理模擬器中測試動作

讓我們測試以下對話:

使用者

Google 助理

「Ok Google,跟『你的名稱電視節目表』your-name-tv-guide對話。」

「沒問題,請稍待,我會為你開啟your-name-tv-guide。」

使用者

Your-Name-TV-Guide Agent

-

「歡迎,我是電視節目表....」

測試我的代理

「This is a test message, when you see this, it means your webhook fulfillment worked!」(這是測試訊息,看到這則訊息表示 Webhook 履行作業已順利完成!)

MTV 有哪些節目?

MTV 頻道下午 4 點 30 分開始播放 MTV Unplugged。隨後在下午 5 點 30 分,將開始播放《魯保羅變裝皇后秀》。

  1. 改回使用 Google 助理模擬器

開啟: https://console.actions.google.com

  1. 按一下麥克風圖示,然後提出以下問題:

c3b200803c7ba95e.png

  • Talk to my test agent
  • Test my agent

Google 助理應會回覆:

5d93c6d037c8c8eb.png

  1. 現在來問問:
  • What's on Comedy Central?

這應該會傳回:

目前 Comedy Central 正在播放《辛普森家庭》(晚上 6 點起)。隨後在晚上 7 點開始播放《居家大改造》。

7. 恭喜

您已使用 Dialogflow 建立第一個 Google 助理動作,做得好!

如您所見,動作是以測試模式執行,並連結至您的 Google 帳戶。如果使用同一個帳戶登入 Nest 裝置或 iOS/Android 手機上的 Google 助理應用程式,你也可以測試動作。

現在是研討會的示範。但如果您要實際為 Google 助理建構應用程式,可以提交動作以供核准。詳情請參閱這份指南。

涵蓋內容

  • 如何使用 Dialogflow V2 建立聊天機器人
  • 如何使用 Dialogflow 建立自訂實體
  • 如何使用 Dialogflow 建立線性對話
  • 如何使用 Dialogflow 和 Firebase Functions 設定 Webhook 執行要求
  • 如何透過 Actions on Google 將應用程式整合至 Google 助理

後續步驟

喜歡這個程式碼研究室嗎?快來看看這些精彩的實驗室!

繼續完成本程式碼研究室,將其整合至 Google Chat:

使用 G Suite 和 Dialogflow 建立電視節目表 Google Chat