재프롬프트 (Dialogflow)

Dialogflow에서 탐색

계속을 클릭하여 Dialogflow에서 다시 프롬프트 샘플을 가져옵니다. 그런 다음 아래 단계에 따라 샘플을 배포하고 테스트합니다.

  1. 에이전트 이름을 입력하고 샘플의 새 Dialogflow 에이전트를 만듭니다.
  2. 에이전트 가져오기가 완료되면 Go to agent(에이전트로 이동)를 클릭합니다.
  3. 기본 탐색 메뉴에서 Fulfillment로 이동합니다.
  4. 인라인 편집기를 사용 설정한 다음 배포를 클릭합니다. 편집기에 샘플 코드가 포함되어 있습니다.
  5. 기본 탐색 메뉴에서 통합으로 이동한 다음 Google 어시스턴트를 클릭합니다.
  6. 표시되는 모달 창에서 Auto-preview changes를 사용 설정하고 Test를 클릭하여 작업 시뮬레이터를 엽니다.
  7. 시뮬레이터에서 Talk to my test app를 입력하여 샘플을 테스트합니다.
계속

다음 기능을 사용하여 사용자가 작업에 입력을 제공하지 않는 (입력 없음 오류)을 처리할 수 있습니다.

  • 시스템 기본값 다시 메시지 표시 - 모든 사례에 일반적으로 적용되는 미리 미리 준비된 재프롬프트를 사용하여 사용자에게 자동으로 메시지를 다시 표시합니다.
  • 동적 재프롬프트 - 직접 재프롬프트를 처리하고자 함을 선언하고 입력이 없을 때마다 인텐트 (Actions SDK) 또는 이벤트 (Dialogflow)를 수신하여 사례별로 처리할 수 있도록 합니다.

시스템 기본값 다시 메시지 표시

기본적으로 어시스턴트에 응답을 반환하면 시스템은 기본 다시 메시지를 사용하여 사용자에게 입력을 반복하거나 다시 입력하도록 요청합니다.

Dialogflow

Dialogflow는 일치하지 않는 입력과 입력 없음 입력을 최대 3개까지 강제 적용합니다. 대화가 세 번의 수집 시도에 도달하면 Dialogflow 에이전트가 기본 응답으로 대화를 종료합니다. Dialogflow의 일치하지 않는 입력은 대체 인텐트 중 하나가 트리거되는 경우입니다.

동적 다시 메시지 표시

작업이 입력을 수신하지 못할 때마다 인텐트 또는 Dialogflow 이벤트를 수신할 수 있습니다. 이를 통해 필요한 경우 일부 로직에 따라 다른 응답을 반환하고 사용자에게 적절하게 다시 메시지를 표시할 수 있습니다.

Dialogflow

다음과 같은 두 가지 유형의 입력이 없는 인텐트를 만들 수 있습니다.

  • 일반 인텐트 - 이 메서드는 컨텍스트를 적용하지 않으므로 트리거할 더 많은 문맥 인텐트가 없는 경우 트리거됩니다. 이는 대부분의 경우에 적용하려는 일반적인 재메시지에 유용합니다.

  • 후속 조치 인텐트 - 후속 조치 인텐트는 Dialogflow 컨텍스트를 통해 시행되어 대화의 특정 전환 후에만 다시 메시지가 트리거되도록 합니다. 이는 특정 상황에 적용할 맞춤형 재프롬프트에 유용합니다.

비입력 이벤트를 처리하려면 다음 단계를 따르세요.

  1. 왼쪽 탐색 메뉴에서 인텐트를 클릭합니다.
  2. 일반 인텐트 또는 후속 조치 인텐트를 만듭니다.
    • 일반 인텐트: Intent 메뉴 항목 옆에 있는 + 아이콘을 클릭하고 인텐트에 'Reprompt'와 같은 이름을 지정합니다.

    • 후속 조치 인텐트: 입력 없는 다시 메시지를 맞춤설정하려는 인텐트 위로 마우스를 가져가서 Addfollow-up intent(후속 인텐트 추가) > custom(커스텀)을 클릭합니다. 원래 인텐트 아래에 새 인텐트가 생성됩니다.

  3. 새로 만든 인텐트를 클릭하여 인텐트 편집기를 엽니다.
  4. 이벤트 섹션을 클릭하고 이벤트 추가 필드에 'actions_intent_NO_INPUT'을 입력합니다.
  5. 작업 섹션에서 작업 이름을 입력하거나 기본적으로 제공되는 이름을 사용합니다. 이 예에서는 'no.input'을 사용합니다.

  6. 저장을 클릭합니다.
  7. 왼쪽 탐색 메뉴에서 Integrations(통합)를 클릭합니다.
  8. Google Assistant를 선택하고 Test를 클릭하여 변경사항이 작업 프로젝트에 반영되었는지 확인합니다.

이 인텐트에 대해 입력이 없을 때마다 처리를 사용하여 적절한 응답을 반환하거나 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은 웹훅 요청을 설명합니다.

{
  "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."
            }
          }
        ]
      }
    }
  }
}

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

    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은 웹훅 요청을 설명합니다.

    {
      "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."
              }
            }
          ]
        }
      }
    }