Explorar no Dialogflow
Clique em Continuar para importar nossa amostra de reprompts no Dialogflow. Depois, siga as etapas abaixo para implantar e testar o exemplo:
- Insira um nome de agente e crie um novo agente do Dialogflow para a amostra.
- Depois que a importação do agente for concluída, clique em Go to agent.
- No menu de navegação principal, acesse Fulfillment.
- Ative o Inline Editor e clique em Implantar. O editor contém o código de amostra.
- No menu de navegação principal, acesse Integrações e clique em Google Assistente.
- Na janela modal exibida, ative a opção Auto-preview changes e clique em Test para abrir o simulador do Actions.
- No simulador, insira
Talk to my test app
para testar a amostra.
É possível usar os seguintes recursos para lidar com casos em que os usuários não fornecem entrada para suas ações (erros sem entrada):
- Novas solicitações padrão do sistema: reenviam o usuário automaticamente com novas solicitações automáticas que são genéricas para todos os casos.
- Novas solicitações dinâmicas: declaram que você quer processar as novas solicitações por conta própria e receber uma intent (SDK das Ações) ou um evento (Dialogflow) sempre que não ocorrer uma entrada. Assim, você poderá gerenciá-las caso a caso.
Novas solicitações padrão do sistema
Por padrão, quando você retorna uma resposta ao Google Assistente, o sistema usa novas solicitações padrão para pedir que os usuários repitam ou redigitem a entrada.
Dialogflow
O Dialogflow aplica um máximo combinado de três entradas sem e sem entrada. Quando uma conversa atingir três tentativas de coleta, o agente do Dialogflow a encerrará com uma resposta padrão. Uma entrada sem correspondência no Dialogflow é quando uma das intents substitutas é acionada.
Novas solicitações dinâmicas
É possível receber uma intent ou um evento do Dialogflow sempre que a ação não receber nenhuma entrada. Isso permite que você retorne uma resposta diferente com base em alguma lógica, se necessário, e solicite uma nova solicitação ao usuário da maneira adequada.
Dialogflow
É possível criar dois tipos de intents sem entrada:
Intent normal: esse método não aplica nenhum contexto. Portanto, será acionado quando não houver outra intent mais contextual para acionar. Isso é útil para novas solicitações gerais que você quer aplicar na maioria dos casos.
Intent de continuidade: as intents de continuidade são aplicadas por meio dos contextos do Dialogflow, garantindo que as novas solicitações sejam acionadas somente após algumas interações na conversa. Isso é útil para novas solicitações personalizadas que você quer aplicar a situações específicas.
Para processar eventos sem entrada:
- No painel de navegação à esquerda, clique em Intents.
- Crie uma intent normal ou uma intent de continuidade.
- Para intents normais: clique no ícone + ao lado do item de menu Intent e dê um nome a ela, como "Reprompt".
- Para intents de continuidade: passe o cursor sobre a intent para a qual você quer personalizar a nova solicitação sem entrada e clique em Add follow-up intent > custom. Uma nova intent é criada abaixo da original.
- Clique na intent recém-criada para abrir o editor.
- Clique na seção Eventos e digite "actions_intent_NO_INPUT" no campo Adicionar evento.
- Na seção Ações, digite um nome de ação ou use o fornecido por padrão. Neste exemplo, usaremos "no.input".
- Clique em Salvar.
- Na navegação à esquerda, clique em Integrações.
- Escolha Google Assistant e clique em Test para garantir que as mudanças apareçam no seu projeto do Actions.
Sempre que ocorrer uma entrada sem entrada para essa intent, será possível usar o fulfillment para retornar uma resposta apropriada ou criar uma no Dialogflow. Por exemplo, veja um código de fulfillment que usa a biblioteca de cliente para processar uma intent normal sem entrada chamada "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(); } }
Solicitar JSON
Observe que o JSON abaixo descreve uma solicitação de 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" }
Resposta JSON
Observe que o JSON abaixo descreve uma resposta do webhook.
{ "payload": { "google": { "expectUserResponse": false, "richResponse": { "items": [ { "simpleResponse": { "textToSpeech": "Okay let's try this again later." } } ] } } } }
SDK do Actions
Para processar intents sem entrada:
- Em um objeto
conversations
dentro do seu pacote de ações, declare que você quer receber a intentactions.intent.NO_INPUT
sempre que um usuário não fornecer entrada.{ "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" } ] } } }
- Quando o Google Assistente não receber nenhuma entrada do usuário, você vai receber
a intent sem entrada na próxima solicitação para o fulfillment. Em seguida,
processe a intent e retorne uma resposta de nova solicitação adequada. Veja um
exemplo:
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(); } }
Solicitar JSON
Observe que o JSON abaixo descreve uma solicitação de 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" } ] } ] }
Resposta JSON
Observe que o JSON abaixo descreve uma resposta do webhook.
{ "expectUserResponse": false, "finalResponse": { "richResponse": { "items": [ { "simpleResponse": { "textToSpeech": "Okay let's try this again later." } } ] } } }