在 Dialogflow 中探索
按一下「Continue」,即可在 Dialogflow 中匯入我們的建議範例。接著,請按照下列步驟部署及測試範例:
- 輸入虛擬服務專員名稱,並為範例建立新的 Dialogflow 代理程式。
- 代理程式匯入完成後,按一下「Go to agent」。
- 從主要導覽選單中,前往「Fulfillment」。
- 啟用「Inline Editor」(內嵌編輯器),然後按一下「Deploy」(部署)。編輯器包含程式碼範例。
- 在主要導覽選單中,前往「Integrations」(整合),然後按一下「Google Assistant」(Google 助理)。
- 在出現的互動視窗中,啟用「Auto-preview changes」,按一下「Test」,開啟動作模擬工具。
- 在模擬工具中輸入
Talk to my test app
即可測試範例!
如果使用者未在您的動作 (無輸入錯誤) 中提供輸入內容,您可以使用下列功能處理:
- System-default reprompts - 這些指令會使用預先掃描的自動提示 (所有案例都通用的通用提示) 自動提示使用者。
- 動態重新提示:宣告您要自行處理重新提示,並在每次沒有輸入時收到意圖 (Actions SDK) 或事件 (Dialogflow),這樣您就能將其視為個案處理。
系統預設建議
根據預設,當您向 Google 助理傳回回應時,系統會使用預設的重新提示,要求使用者重複或重新輸入輸入內容。
Dialogflow
Dialogflow 最多會強制執行三個無相符項目和無輸入輸入內容。一旦對話收集到三次收集嘗試,Dialogflow 代理程式就會以預設回應結束對話。Dialogflow 中若出現不相符的輸入,則表示觸發了其中一個備用意圖。
動態建議
每當動作未收到任何輸入內容時,您就會收到意圖或 Dialogflow 事件。這可讓您視需要根據特定邏輯傳回不同的回應,並適當重新提示使用者。
Dialogflow
您可以建立兩種類型的無輸入意圖:
一般意圖 - 這個方法不會套用任何結構定義,因此當沒有其他更相關的情境意圖可觸發時,就會觸發這個事件。在大多數情況下,這很適合用於一般建議套用的提示。
後續追蹤意圖 - 後續追蹤意圖會透過 Dialogflow 情境強制執行,確保只有在對話過特定時間後才會觸發提示。如果你想在特定情況下套用專屬的自動提示,這項功能就能派上用場。
如何處理無輸入事件:
- 在左側導覽窗格中,按一下「Intents」(意圖)。
- 建立正常意圖或後續追蹤意圖。
- 一般意圖:按一下「Intent」(意圖) 選單項目旁邊的「+」圖示,並為意圖命名,例如「Reprompt」。
- 針對後續追蹤意圖:將滑鼠遊標懸停在您要自訂無輸入要求的意圖上,然後依序點選「Add Follow-up intent」(新增後續追蹤意圖) >「custom」(自訂)。系統會在原始意圖下方建立新意圖。
- 按一下新建立的意圖,開啟意圖編輯器。
- 按一下「Events」(事件) 部分,然後在「Add event」(新增事件) 欄位中輸入「actions_intent_NO_INPUT」。
- 在「Actions」(動作) 區段中,輸入動作名稱或使用預設提供的名稱。在這個範例中,我們將使用「no.input」。
- 點按「儲存」。
- 在左側導覽面板中按一下「整合」
- 選擇「Google Assistant」,然後按一下「Test」,確認變更已反映在 Actions 專案中。
只要這項意圖沒有輸入任何項目,您就能使用執行要求傳回適當的回應,或在 Dialogflow 中建立回應。舉例來說,下方的某些執行要求程式碼使用用戶端程式庫來處理稱為「Reprompt」的一般無輸入意圖。
Node.js
const {dialogflow} = require('actions-on-google'); const functions = require('firebase-functions'); const app = dialogflow({debug: true}); app.intent('Reprompt', (conv) => { const repromptCount = parseInt(conv.arguments.get('REPROMPT_COUNT')); if (repromptCount === 0) { conv.ask(`What was that?`); } else if (repromptCount === 1) { conv.ask(`Sorry I didn't catch that. Could you repeat yourself?`); } else if (conv.arguments.get('IS_FINAL_REPROMPT')) { conv.close(`Okay let's try this again later.`); } }); exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);
Java
package com.example; import com.google.actions.api.ActionRequest; import com.google.actions.api.ActionResponse; import com.google.actions.api.DialogflowApp; import com.google.actions.api.ForIntent; import com.google.actions.api.response.ResponseBuilder; public class MyActionsApp extends DialogflowApp { @ForIntent("Reprompt") public ActionResponse reprompt(ActionRequest request) { ResponseBuilder responseBuilder = getResponseBuilder(request); int repromptCount = request.getRepromptCount(); String response; if (repromptCount == 0) { response = "What was that?"; } else if (repromptCount == 1) { response = "Sorry, I didn't catch that. Could you repeat yourself?"; } else { responseBuilder.endConversation(); response = "Okay let's try this again later."; } return responseBuilder.add(response).build(); } }
要求 JSON
請注意,以下 JSON 說明 Webhook 要求。
{ "responseId": "f26a9188-4998-42eb-ac16-d0e6e273b137-712767ed", "queryResult": { "queryText": "actions_intent_NO_INPUT", "parameters": {}, "allRequiredParamsPresent": true, "fulfillmentText": "Webhook failed for intent: Reprompt", "fulfillmentMessages": [ { "text": { "text": [ "Webhook failed for intent: Reprompt" ] } } ], "outputContexts": [ { "name": "projects/df-reprompts-kohler/agent/sessions/ABwppHFi9Dpwy6KiEtS0UIPDNVfa7mlkrPIEZRlikFkjuN_4SGPixgX8OCatpXu38ln7VG43-nk-7veZWhds3nLljA/contexts/actions_capability_media_response_audio" }, { "name": "projects/df-reprompts-kohler/agent/sessions/ABwppHFi9Dpwy6KiEtS0UIPDNVfa7mlkrPIEZRlikFkjuN_4SGPixgX8OCatpXu38ln7VG43-nk-7veZWhds3nLljA/contexts/actions_capability_account_linking" }, { "name": "projects/df-reprompts-kohler/agent/sessions/ABwppHFi9Dpwy6KiEtS0UIPDNVfa7mlkrPIEZRlikFkjuN_4SGPixgX8OCatpXu38ln7VG43-nk-7veZWhds3nLljA/contexts/actions_capability_audio_output" }, { "name": "projects/df-reprompts-kohler/agent/sessions/ABwppHFi9Dpwy6KiEtS0UIPDNVfa7mlkrPIEZRlikFkjuN_4SGPixgX8OCatpXu38ln7VG43-nk-7veZWhds3nLljA/contexts/google_assistant_input_type_voice" }, { "name": "projects/df-reprompts-kohler/agent/sessions/ABwppHFi9Dpwy6KiEtS0UIPDNVfa7mlkrPIEZRlikFkjuN_4SGPixgX8OCatpXu38ln7VG43-nk-7veZWhds3nLljA/contexts/actions_intent_no_input", "parameters": { "REPROMPT_COUNT": 2, "IS_FINAL_REPROMPT": true } } ], "intent": { "name": "projects/df-reprompts-kohler/agent/intents/75dfd97d-6368-4436-9533-70f05ae76c96", "displayName": "Reprompt" }, "intentDetectionConfidence": 1, "languageCode": "en" }, "originalDetectIntentRequest": { "source": "google", "version": "2", "payload": { "user": { "locale": "en-US", "userVerificationStatus": "VERIFIED" }, "conversation": { "conversationId": "ABwppHFi9Dpwy6KiEtS0UIPDNVfa7mlkrPIEZRlikFkjuN_4SGPixgX8OCatpXu38ln7VG43-nk-7veZWhds3nLljA", "type": "ACTIVE", "conversationToken": "[]" }, "inputs": [ { "intent": "actions.intent.NO_INPUT", "rawInputs": [ { "inputType": "VOICE" } ], "arguments": [ { "name": "REPROMPT_COUNT", "intValue": "2" }, { "name": "IS_FINAL_REPROMPT", "boolValue": true } ] } ], "surface": { "capabilities": [ { "name": "actions.capability.MEDIA_RESPONSE_AUDIO" }, { "name": "actions.capability.ACCOUNT_LINKING" }, { "name": "actions.capability.AUDIO_OUTPUT" } ] }, "availableSurfaces": [ { "capabilities": [ { "name": "actions.capability.AUDIO_OUTPUT" }, { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.WEB_BROWSER" } ] } ] } }, "session": "projects/df-reprompts-kohler/agent/sessions/ABwppHFi9Dpwy6KiEtS0UIPDNVfa7mlkrPIEZRlikFkjuN_4SGPixgX8OCatpXu38ln7VG43-nk-7veZWhds3nLljA" }
回應 JSON
請注意,以下 JSON 說明 Webhook 回應。
{ "payload": { "google": { "expectUserResponse": false, "richResponse": { "items": [ { "simpleResponse": { "textToSpeech": "Okay let's try this again later." } } ] } } } }
Actions SDK
處理無輸入意圖:
- 在動作套件的
conversations
物件中,宣告您希望在使用者未提供輸入內容時接收actions.intent.NO_INPUT
意圖。{ "actions": [ { "description": "Default Welcome Intent", "name": "MAIN", "fulfillment": { "conversationName": "conversation_1" }, "intent": { "name": "actions.intent.MAIN" } } ], "conversations": { "conversation_1": { "name": "conversation_1", "url": "YOUR_FULFILLMENT_URL", "inDialogIntents": [ { "name": "actions.intent.NO_INPUT" } ] } } }
- 如果 Google 助理未收到使用者的任何輸入內容,您就會在下一個要求中收到無輸入意圖。接著,您就可以處理意圖,並傳回適當的重新提示回應。範例如下:
Node.js
const {actionssdk} = require('actions-on-google'); const functions = require('firebase-functions'); const app = actionssdk({debug: true}); app.intent('actions.intent.MAIN', (conv) => { conv.ask(`Hi! Try this sample on a speaker device, ` + `and stay silent when the mic is open. If trying ` + `on the Actions console simulator, click the no-input ` + `button next to the text input field.`); }); app.intent('actions.intent.TEXT', (conv, input) => { conv.ask(`You said ${input}`); conv.ask(`Try this sample on a speaker device, ` + `and stay silent when the mic is open. If trying ` + `on the Actions console simulator, click the no-input ` + `button next to the text input field.`); }); app.intent('actions.intent.NO_INPUT', (conv) => { const repromptCount = parseInt(conv.arguments.get('REPROMPT_COUNT')); if (repromptCount === 0) { conv.ask(`What was that?`); } else if (repromptCount === 1) { conv.ask(`Sorry I didn't catch that. Could you repeat yourself?`); } else if (conv.arguments.get('IS_FINAL_REPROMPT')) { conv.close(`Okay let's try this again later.`); } }); exports.dialogflowFirebaseFulfillment = functions.https.onRequest(app);
Java
package com.example; import com.google.actions.api.ActionRequest; import com.google.actions.api.ActionResponse; import com.google.actions.api.ActionsSdkApp; import com.google.actions.api.ConstantsKt; import com.google.actions.api.ForIntent; import com.google.actions.api.response.ResponseBuilder; import com.google.actions.api.response.helperintent.Confirmation; import com.google.actions.api.response.helperintent.DateTimePrompt; import com.google.actions.api.response.helperintent.Permission; import com.google.actions.api.response.helperintent.Place; import com.google.api.services.actions_fulfillment.v2.model.DateTime; import com.google.api.services.actions_fulfillment.v2.model.Location; public class MyActionsApp extends ActionsSdkApp { @ForIntent("actions.intent.MAIN") public ActionResponse welcome(ActionRequest request) { ResponseBuilder responseBuilder = getResponseBuilder(request); responseBuilder.add("Hi! Try this sample on a speaker device, and stay silent when the mic is open. If trying on the Actions console simulator, click the no-input button next to the text input field."); return responseBuilder.build(); } @ForIntent("actions.intent.TEXT") public ActionResponse fallback(ActionRequest request) { ResponseBuilder responseBuilder = getResponseBuilder(request); responseBuilder.add("You said " + request.getRawInput().getQuery()); responseBuilder.add("Try this sample on a speaker device, and stay silent when the mic is open. If trying on the Actions console simulator, click the no-input button next to the text input field."); return responseBuilder.build(); } @ForIntent("actions.intent.NO_INPUT") public ActionResponse reprompt(ActionRequest request) { ResponseBuilder responseBuilder = getResponseBuilder(request); int repromptCount = request.getRepromptCount(); String response; if (repromptCount == 0) { response = "What was that?"; } else if (repromptCount == 1) { response = "Sorry, I didn't catch that. Could you repeat yourself?"; } else { responseBuilder.endConversation(); response = "Okay let's try this again later."; } return responseBuilder.add(response).build(); } }
要求 JSON
請注意,以下 JSON 說明 Webhook 要求。
{ "user": { "locale": "en-US", "userVerificationStatus": "VERIFIED" }, "conversation": { "conversationId": "ABwppHEVDuKUPjdZ4Ud-F2yBXN5ssRg2funUp59hSHQheAi-B5Y3EzehAKFtVwMkduqMRWscUp77ScrDjYnYxISqAM-qOXuXEuCw", "type": "ACTIVE", "conversationToken": "{\"data\":{}}" }, "inputs": [ { "intent": "actions.intent.NO_INPUT", "rawInputs": [ { "inputType": "VOICE" } ], "arguments": [ { "name": "REPROMPT_COUNT", "intValue": "2" }, { "name": "IS_FINAL_REPROMPT", "boolValue": true } ] } ], "surface": { "capabilities": [ { "name": "actions.capability.AUDIO_OUTPUT" }, { "name": "actions.capability.ACCOUNT_LINKING" }, { "name": "actions.capability.MEDIA_RESPONSE_AUDIO" } ] }, "availableSurfaces": [ { "capabilities": [ { "name": "actions.capability.SCREEN_OUTPUT" }, { "name": "actions.capability.WEB_BROWSER" }, { "name": "actions.capability.AUDIO_OUTPUT" } ] } ] }
回應 JSON
請注意,以下 JSON 說明 Webhook 回應。
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "simpleResponse": { "textToSpeech": "Okay let's try this again later." } } ] } } }