Dialogflow で探索
[続行] をクリックして、Dialogflow の再プロンプト サンプルをインポートします。次に、 サンプルをデプロイしてテストする手順は次のとおりです。
- エージェント名を入力し、サンプルの新しい Dialogflow エージェントを作成します。
- エージェントのインポートが完了したら、[Go to agent] をクリックします。
- メインのナビゲーション メニューから [Fulfillment] に移動します。
- [Inline Editor] を有効にして、[Deploy] をクリックします。エディタにはサンプルが含まれています。 できます。
- メイン ナビゲーション メニューから [Integrations] に移動し、[Google] をクリックします アシスタント。
- 表示されたモーダル ウィンドウで、[変更の自動プレビュー] を有効にして [テスト] をクリックします。 Actions シミュレータを開きます
- シミュレータで「
Talk to my test app
」と入力して、サンプルをテストします。
次の機能を使用して、ユーザーが提供しないケースに対応できます。 (未入力エラー):
- システムデフォルトの再プロンプト - 事前定義された汎用的な再プロンプトを自動的に提示します。
- 動的再プロンプト - プロンプトに対する再プロンプトの処理を インテント(Actions SDK)またはイベント(Dialogflow)を ケースバイケースで処理できます。
システムデフォルトの再プロンプト
デフォルトでは、アシスタントに応答を返す際、システムは ユーザーに入力を繰り返すか再入力するよう求める再プロンプトがデフォルトで表示されます。
Dialogflow
Dialogflow では、一致しない入力と未入力の入力を合わせて最大 3 つまで強制されます。 会話で収集の試行が 3 回に達すると、Dialogflow エージェントは デフォルトのレスポンスを返して会話を終了します。一致しない入力が Dialogflow では、いずれかのフォールバック インテントがトリガーされます。
動的再プロンプト
アクションが失敗するたびに、インテントまたは Dialogflow イベントを受け取ることができます。 入力を受け取れます。これにより、入力内容に基づいて異なるレスポンスを返すことができます。 ロジックを作成し、必要に応じてユーザーに再度プロンプトを表示します。
Dialogflow
次の 2 種類の未入力インテントを作成できます。
通常インテント - この方法はどのようなコンテキストも適用しません。そのため、トリガーすべき別のよりコンテキストに即したインテントがない場合にトリガーされます。これは、ほとんどのケースに適用できる汎用的な再プロンプトに役立ちます。
フォローアップ インテント - Dialogflow を通じてフォローアップ インテントが適用されます。 特定のターンの後でのみ再プロンプトがトリガーされるように あります。これは、特定のユースケースに適用するカスタマイズされた再プロンプトに 対応できます。
未入力イベントを処理するには:
- 左側のナビゲーションで [Intents] をクリックします。
- 通常のインテントまたはフォローアップ インテントを作成します。
- 通常インテントの場合: [Intent(インテント)] メニューの [+] アイコンをクリックします。 インテントに名前を付けます(「Reprompt」など)。
- フォローアップ インテントの場合: 未入力再プロンプトをカスタマイズする対象のインテントにカーソルを合わせ、[Add follow-up intent] > [custom] の順にクリックします。元のインテントの下に新しいインテントが作成されます。
- 新しく作成されたインテントをクリックしてインテント エディタを開きます。
- [Events] セクションをクリックして「actions_intent_NO_INPUT」と入力します。新しい [Add event] フィールド。
- [Actions] セクションで、アクション名を入力するか、デフォルトで提供されている名前を使用します。この例では「no.input」を使用します。
- [保存] をクリックします。
- 左側のナビゲーションで [Integrations] をクリックします。
- [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" } ] } } }
- アシスタントがユーザーから入力を受けなかったとき、次のフルフィルメントへのリクエストで未入力インテントを受け取ります。そのインテントを処理して適切な再プロンプトのレスポンスを返すことができます。次の例をご覧ください。
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." } } ] } } }