Повторные подсказки (диалоговый поток)

Исследуйте в Dialogflow

Нажмите «Продолжить» , чтобы импортировать наш образец повторных подсказок в Dialogflow. Затем выполните следующие действия, чтобы развернуть и протестировать образец:

  1. Введите имя агента и создайте новый агент Dialogflow для примера.
  2. После завершения импорта агента нажмите Перейти к агенту .
  3. В главном навигационном меню перейдите в раздел «Выполнение» .
  4. Включите встроенный редактор и нажмите «Развернуть» . Редактор содержит пример кода.
  5. В главном меню навигации выберите «Интеграции» и нажмите «Google Ассистент» .
  6. В появившемся модальном окне включите автоматический просмотр изменений и нажмите «Тест» , чтобы открыть симулятор действий.
  7. В симуляторе введите Talk to my test app , чтобы протестировать образец!
Продолжить

Вы можете использовать следующие функции для обработки случаев, когда пользователи не предоставляют данные для ваших действий (ошибки отсутствия ввода):

  • Системные повторные подсказки по умолчанию . Они автоматически повторяют подсказки пользователю с помощью заранее подготовленных повторных подсказок, которые являются общими для всех случаев.
  • Динамические повторные запросы . Заявление о том, что вы хотите обрабатывать повторные запросы самостоятельно, и получение намерения (Actions SDK) или события (Dialogflow) каждый раз, когда происходит отсутствие ввода, поэтому вы можете обрабатывать их в каждом конкретном случае.

Системные повторы по умолчанию

По умолчанию, когда вы возвращаете ответ Ассистенту, система использует повторные запросы по умолчанию, чтобы попросить пользователей повторить или повторно ввести введенные данные.

Диалоговый поток

Dialogflow обеспечивает объединение максимум трех входных данных без совпадений и ввода. Как только в разговоре будет три попытки сбора данных, ваш агент Dialogflow завершит разговор, выдав ответ по умолчанию. Несоответствующий ввод в Dialogflow — это когда срабатывает одно из ваших резервных намерений.

Динамические повторы

Вы можете получать событие Intent или Dialogflow каждый раз, когда ваше действие не получает никаких входных данных. Это позволяет при необходимости вернуть другой ответ на основе некоторой логики и соответствующим образом повторно запросить пользователя.

Диалоговый поток

Вы можете создать два типа намерений без ввода:

  • Обычное намерение . Этот метод не применяет никаких контекстов, поэтому будет срабатывать, когда нет другого, более контекстуального намерения, которое можно было бы активировать. Это полезно для общих подсказок, которые вы хотите применить в большинстве случаев.

  • Намерение отслеживания . Намерения отслеживания реализуются через контексты Dialogflow, гарантируя, что повторные запросы запускаются только после определенных поворотов разговора. Это полезно для индивидуальных повторов, которые вы хотите применить к конкретным ситуациям.

Для обработки событий отсутствия ввода:

  1. В левой панели навигации нажмите «Намерения» .
  2. Создайте обычное намерение или последующее намерение.
    • Для обычных намерений : нажмите значок + рядом с пунктом меню «Намерение » и дайте своему намерению имя, например «Повторное приглашение».

    • Для последующих намерений : наведите указатель мыши на намерение, для которого вы хотите настроить повторное приглашение без ввода данных, и нажмите «Добавить последующее намерение» > «Пользовательский» . Новое намерение создается ниже исходного намерения.

  3. Нажмите на вновь созданное намерение, чтобы открыть редактор намерений.
  4. Щелкните раздел «События» и введите «actions_intent_NO_INPUT» в поле «Добавить событие» .
  5. В разделе «Действия» введите имя действия или используйте имя, указанное по умолчанию. В этом примере мы будем использовать «no.input».

  6. Нажмите Сохранить .
  7. В левой навигационной панели нажмите «Интеграции» .
  8. Выберите Google Assistant и нажмите «Тестировать» , чтобы убедиться, что изменения отражены в вашем проекте Actions.

Всякий раз, когда для этого намерения происходит отсутствие ввода, вы можете использовать свое выполнение, чтобы вернуть соответствующий ответ или создать его в Dialogflow. Например, вот некоторый код выполнения, который использует клиентскую библиотеку для обработки обычного намерения без ввода, называемого «Повторное приглашение».

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);

Джава

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 описывает запрос веб-перехватчика.

{
  "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 описывает ответ веб-перехватчика.

{
  "payload": {
    "google": {
      "expectUserResponse": false,
      "richResponse": {
        "items": [
          {
            "simpleResponse": {
              "textToSpeech": "Okay let's try this again later."
            }
          }
        ]
      }
    }
  }
}

SDK действий

Чтобы обработать намерения без ввода:

  1. В объекте 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"
            }
          ]
        }
      }
    }
    
  2. Если Ассистент не получает никаких данных от пользователя, вы получите намерение не вводить данные в следующем запросе для вашего выполнения. Затем вы можете обработать намерение и вернуть соответствующий ответ на повторное приглашение. Вот пример:

    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);

    Джава

    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 описывает запрос веб-перехватчика.

    {
      "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 описывает ответ веб-перехватчика.

    {
      "expectUserResponse": false,
      "finalResponse": {
        "richResponse": {
          "items": [
            {
              "simpleResponse": {
                "textToSpeech": "Okay let's try this again later."
              }
            }
          ]
        }
      }
    }