2

我们正在使用新发布的Java/Kotlin API通过 Dialogflow 实现来实现 Actions on Google 。

它被称为Speech Bank

在智能手机上进行帐户链接过程测试时,用户收到 MalformedResponse 错误,阻止了流程的完成并随后成功切换回常规流程。

日志(详情如下)包含MalformedResponse: Failed to parse Dialogflow response into AppResponse because of empty speech response消息,用户Speech bank isn't responding right now. Try again soon.在她的设备上接收消息。

以下是有关我们设置的更多详细信息:

在此处输入图像描述

该操作配置为使用我们自己的符合 OAuth 2 的模拟基础设施进行帐户链接。

在此处输入图像描述

RawText在 Dialogflow 中配置了一个意图(称为),其余交互将由自己的内部应用程序通过其 Web 挂钩处理。

在此处输入图像描述

到目前为止,这是状态机在 Java 中的编码方式:

    public class AoGApp extends DialogflowApp {

        private final static Logger log = LoggerFactory.getLogger(AoGApp.class);

       public static final String GREETING = "GOOGLE_ASSISTANT_WELCOME";

        @ForIntent("RawText")
        //@ForIntent("actions.intent.MAIN")
        public ActionResponse launchRequestHandler(ActionRequest request) {

            String userId = request.getAppRequest().getUser().getUserId();
            log.info("userId={}",userId);
            String queryText = request.getWebhookRequest().getQueryResult().getQueryText();
            log.info("queryText={}", queryText);


            String speech = null;

            ResponseBuilder responseBuilder = getResponseBuilder(request);

            if (isBlank(userId) || GREETING.equalsIgnoreCase(queryText)) {

                speech = "\nHi. I sense a great banking experience in your future, I see that your account isn't connected. "
                        + "I've sent a link to your Google Assistant app that will get you started and set up in just several simple steps. "
                        + "Don't worry, I'll be here waiting, just summon me when you're ready.";


                responseBuilder.add(
                        new SignIn()
                            .setContext(speech));
            } else {
                speech = "Welcome. You can say hello.";
                responseBuilder.add(speech);
            }


            return responseBuilder.build();
        }

        @ForIntent("actions.intent.SIGN_IN")
        public ActionResponse getSignInStatus(ActionRequest request) {
          ResponseBuilder responseBuilder = getResponseBuilder(request);
          String text = "Hello from sign-in handler";
          responseBuilder.add(text);
          log.info(text);
          return responseBuilder.build();

        }

    }


and the associated HttpRequest processing: 

    @Override
        protected void handlePOST(final Request request, final HttpServletResponse response) {

            try {
                String rawRequest = ControllerUtils.toString(request.getReader());


                String jsonResponse = app.handleRequest(rawRequest, getHeadersMap(request)).get();
                log.info("Generated response:\n {}", ControllerUtils.prettyPrint(jsonResponse));
                response.setContentType(APPLICATION_JSON.getMimeType());
                response.getWriter().write(jsonResponse);
            } catch (Exception e) {
                handleError(response, e);
            } 
        }

public final class ControllerUtils {

    private final static Logger log = LoggerFactory.getLogger(ControllerUtils.class);
    private static ObjectMapper mapper = new ObjectMapper();

    public static String toString(BufferedReader reader) throws Exception {

        String rawRequest = reader
                .lines()
                //.map(e -> e.concat(System.lineSeparator()))
                .collect(Collectors.joining(System.lineSeparator()));
        log.info("Received AoG Request {}",rawRequest);
        return rawRequest;
    }

    public static String prettyPrint(String json) throws Exception {
        return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(mapper.readValue(json, Object.class));
    }

    public static Map<String, String> getHeadersMap(org.eclipse.jetty.server.Request jettyRequest){
        return Collections.list((Enumeration<String>) jettyRequest.getHeaderNames())
                .stream()
                .collect(Collectors.toMap(
                        name -> name,
                        jettyRequest::getHeader));

    }


}

如上配置,OAuth 授权代码流执行正常的 OAuth 2 步骤:

  • 命中/login端点以提供凭据

  • 点击/token端点获取令牌(它的值token1在下面的日志中。我们有一个工具来生成和注入我们自己的令牌,这是一个测试环境,所以我们生成了这个token1值,它似乎已成功合并到后续请求中。)

以下是交互失败的详细屏幕截图,并附有 Actions on Google 控制台提供的日志:

在此处输入图像描述

[
 {
   "textPayload": "Sending request with post data: {\"user\":{\"userId\":\"ABwppHFQHUBr0RrWA_OuL-kK2sxTPUvQtL3D-x2Ydr-7uxLt9zzEFzJrGB-X96d9XY8k9XTJj-RUg9WpzGB9jg\",\"locale\":\"en-US\",\"lastSeen\":\"2019-02-20T21:32:22Z\",\"userStorage\":\"{\\\"data\\\":{}}\"},\"conversation\":{\"conversationId\":\"ABwppHE35s8T6qSdaaCMNiWuMdY7UsvQ3sHbLZJOQkVA4AFD2nhKuqTTvoJTkVh7yU81GCHbvlfZTxmULLd4Ug\",\"type\":\"NEW\"},\"inputs\":[{\"intent\":\"actions.intent.MAIN\",\"rawInputs\":[{\"inputType\":\"VOICE\",\"query\":\"open speech Bank\"}]}],\"surface\":{\"capabilities\":[{\"name\":\"actions.capability.AUDIO_OUTPUT\"},{\"name\":\"actions.capability.MEDIA_RESPONSE_AUDIO\"},{\"name\":\"actions.capability.SCREEN_OUTPUT\"},{\"name\":\"actions.capability.WEB_BROWSER\"}]},\"isInSandbox\":true,\"availableSurfaces\":[{\"capabilities\":[{\"name\":\"actions.capability.AUDIO_OUTPUT\"},{\"name\":\"actions.capability.SCREEN_OUTPUT\"},{\"name\":\"actions.capability.WEB_BROWSER\"}]}]}.",
   "insertId": "f9fzrtf3hjgn4",
   "resource": {
     "type": "assistant_action",
     "labels": {
       "project_id": "speechbank-e8a15",
       "version_id": "",
       "action_id": "actions.intent.MAIN"
     }
   },
   "timestamp": "2019-02-21T13:47:56.713587946Z",
   "severity": "DEBUG",
   "labels": {
     "channel": "preview",
     "source": "AOG_REQUEST_RESPONSE",
     "querystream": "GOOGLE_USER"
   },
   "logName": "projects/speechbank-e8a15/logs/actions.googleapis.com%2Factions",
   "trace": "projects/366800784520/traces/ABwppHE35s8T6qSdaaCMNiWuMdY7UsvQ3sHbLZJOQkVA4AFD2nhKuqTTvoJTkVh7yU81GCHbvlfZTxmULLd4Ug",
   "receiveTimestamp": "2019-02-21T13:47:57.205496026Z"
 },
 {
   "textPayload": "Received response from agent with body: HTTP/1.1 200 OK\r\nServer: nginx/1.13.6\r\nDate: Thu, 21 Feb 2019 13:47:57 GMT\r\nContent-Type: application/json;charset=UTF-8\r\nContent-Length: 426\r\nX-Cloud-Trace-Context: d8cb97627afa1d2977b9f567f29598de/11157405402824233090;o=0\r\nGoogle-Actions-API-Version: 2\r\nX-SHARD: shard-2\r\nVia: 1.1 google\r\nAlt-Svc: clear\r\n\r\n{\"conversationToken\":\"[\\\"_actions_on_google\\\"]\",\"expectUserResponse\":true,\"expectedInputs\":[{\"inputPrompt\":{},\"possibleIntents\":[{\"intent\":\"actions.intent.SIGN_IN\",\"inputValueData\":{\"@type\":\"type.googleapis.com/google.actions.v2.SignInValueSpec\"}}]}],\"responseMetadata\":{\"status\":{\"message\":\"Success (200)\"},\"queryMatchInfo\":{\"queryMatched\":true,\"intent\":\"f645f492-f6dc-4e7e-8da6-45711c654ad0\"}},\"userStorage\":\"{\\\"data\\\":{}}\"}.",
   "insertId": "f9fzrtf3hjgn5",
   "resource": {
     "type": "assistant_action",
     "labels": {
       "version_id": "",
       "action_id": "actions.intent.MAIN",
       "project_id": "speechbank-e8a15"
     }
   },
   "timestamp": "2019-02-21T13:47:57.190979036Z",
   "severity": "DEBUG",
   "labels": {
     "source": "AOG_REQUEST_RESPONSE",
     "querystream": "GOOGLE_USER",
     "channel": "preview"
   },
   "logName": "projects/speechbank-e8a15/logs/actions.googleapis.com%2Factions",
   "trace": "projects/366800784520/traces/ABwppHE35s8T6qSdaaCMNiWuMdY7UsvQ3sHbLZJOQkVA4AFD2nhKuqTTvoJTkVh7yU81GCHbvlfZTxmULLd4Ug",
   "receiveTimestamp": "2019-02-21T13:47:57.205496026Z"
 },
 {
   "textPayload": "Sending request with post data: {\"user\":{\"userId\":\"ABwppHFQHUBr0RrWA_OuL-kK2sxTPUvQtL3D-x2Ydr-7uxLt9zzEFzJrGB-X96d9XY8k9XTJj-RUg9WpzGB9jg\",\"accessToken\":\"token1\",\"locale\":\"en-US\",\"lastSeen\":\"2019-02-20T21:32:22Z\",\"userStorage\":\"{\\\"data\\\":{}}\"},\"conversation\":{\"conversationId\":\"ABwppHE35s8T6qSdaaCMNiWuMdY7UsvQ3sHbLZJOQkVA4AFD2nhKuqTTvoJTkVh7yU81GCHbvlfZTxmULLd4Ug\",\"type\":\"ACTIVE\",\"conversationToken\":\"[\\\"_actions_on_google\\\"]\"},\"inputs\":[{\"intent\":\"actions.intent.SIGN_IN\",\"rawInputs\":[{}],\"arguments\":[{\"name\":\"SIGN_IN\",\"extension\":{\"@type\":\"type.googleapis.com/google.actions.v2.SignInValue\",\"status\":\"OK\"}},{\"name\":\"text\"}]}],\"surface\":{\"capabilities\":[{\"name\":\"actions.capability.WEB_BROWSER\"},{\"name\":\"actions.capability.SCREEN_OUTPUT\"},{\"name\":\"actions.capability.MEDIA_RESPONSE_AUDIO\"},{\"name\":\"actions.capability.AUDIO_OUTPUT\"}]},\"isInSandbox\":true,\"availableSurfaces\":[{\"capabilities\":[{\"name\":\"actions.capability.WEB_BROWSER\"},{\"name\":\"actions.capability.SCREEN_OUTPUT\"},{\"name\":\"actions.capability.AUDIO_OUTPUT\"}]}]}.",
   "insertId": "120k9w1f3jmw55",
   "resource": {
     "type": "assistant_action",
     "labels": {
       "version_id": "",
       "action_id": "actions.intent.SIGN_IN",
       "project_id": "speechbank-e8a15"
     }
   },
   "timestamp": "2019-02-21T13:48:28.768213970Z",
   "severity": "DEBUG",
   "labels": {
     "source": "AOG_REQUEST_RESPONSE",
     "querystream": "GOOGLE_USER",
     "channel": "preview"
   },
   "logName": "projects/speechbank-e8a15/logs/actions.googleapis.com%2Factions",
   "trace": "projects/366800784520/traces/ABwppHE35s8T6qSdaaCMNiWuMdY7UsvQ3sHbLZJOQkVA4AFD2nhKuqTTvoJTkVh7yU81GCHbvlfZTxmULLd4Ug",
   "receiveTimestamp": "2019-02-21T13:48:28.912828815Z"
 },
 {
   "textPayload": "Received response from agent with body: HTTP/1.1 200 OK\r\nServer: nginx/1.13.6\r\nDate: Thu, 21 Feb 2019 13:48:28 GMT\r\nContent-Type: application/json;charset=UTF-8\r\nContent-Length: 570\r\nX-Cloud-Trace-Context: 664d8fdaf9cd3d880d41f11ac2176e0e/16724608154084655134;o=0\r\nGoogle-Actions-API-Version: 2\r\nAssistant-Interaction-Error-Code: -1\r\nAssistant-Interaction-Error-Message: Failed to parse Dialogflow response into AppResponse because of empty speech response\r\nX-SHARD: shard-2\r\nVia: 1.1 google\r\nAlt-Svc: clear\r\n\r\n{\n  \"responseMetadata\": {\n    \"status\": {\n      \"code\": 10,\n      \"message\": \"Failed to parse Dialogflow response into AppResponse because of empty speech response\",\n      \"details\": [{\n        \"@type\": \"type.googleapis.com/google.protobuf.Value\",\n        \"value\": \"{\\\"id\\\":\\\"5d4bed8d-c58c-4429-9838-f758d6f335f2\\\",\\\"timestamp\\\":\\\"2019-02-21T13:48:28.806Z\\\",\\\"lang\\\":\\\"en-us\\\",\\\"result\\\":{},\\\"status\\\":{\\\"code\\\":200,\\\"errorType\\\":\\\"success\\\"},\\\"sessionId\\\":\\\"ABwppHE35s8T6qSdaaCMNiWuMdY7UsvQ3sHbLZJOQkVA4AFD2nhKuqTTvoJTkVh7yU81GCHbvlfZTxmULLd4Ug\\\"}\"\n      }]\n    }\n  }\n}.",
   "insertId": "120k9w1f3jmw56",
   "resource": {
     "type": "assistant_action",
     "labels": {
       "project_id": "speechbank-e8a15",
       "version_id": "",
       "action_id": "actions.intent.SIGN_IN"
     }
   },
   "timestamp": "2019-02-21T13:48:28.899033790Z",
   "severity": "DEBUG",
   "labels": {
     "channel": "preview",
     "source": "AOG_REQUEST_RESPONSE",
     "querystream": "GOOGLE_USER"
   },
   "logName": "projects/speechbank-e8a15/logs/actions.googleapis.com%2Factions",
   "trace": "projects/366800784520/traces/ABwppHE35s8T6qSdaaCMNiWuMdY7UsvQ3sHbLZJOQkVA4AFD2nhKuqTTvoJTkVh7yU81GCHbvlfZTxmULLd4Ug",
   "receiveTimestamp": "2019-02-21T13:48:28.912828815Z"
 },
 {
   "textPayload": "MalformedResponse: Failed to parse Dialogflow response into AppResponse because of empty speech response",
   "insertId": "1b6j2e6f39jvuy",
   "resource": {
     "type": "assistant_action",
     "labels": {
       "project_id": "speechbank-e8a15",
       "version_id": "",
       "action_id": "actions.intent.SIGN_IN"
     }
   },
   "timestamp": "2019-02-21T13:48:28.899403302Z",
   "severity": "ERROR",
   "labels": {
     "channel": "preview",
     "source": "JSON_RESPONSE_VALIDATION",
     "querystream": "GOOGLE_USER"
   },
   "logName": "projects/speechbank-e8a15/logs/actions.googleapis.com%2Factions",
   "trace": "projects/366800784520/traces/ABwppHE35s8T6qSdaaCMNiWuMdY7UsvQ3sHbLZJOQkVA4AFD2nhKuqTTvoJTkVh7yU81GCHbvlfZTxmULLd4Ug",
   "receiveTimestamp": "2019-02-21T13:48:28.914061262Z"
 }
]

根据上面的设置描述,任何人都可以帮我们弄清楚是什么导致了MalformedResponse异常,以及需要改变什么来消除它。

这个例外是如此模糊,以至于它带来了无数的问题,让人不知从何开始接近它。我将在这里仅列出一些,非常感谢一些指导。

  • AoG 和 Dialogflow 中的意图名称之间是否存在关联?他们应该遵循任何命名约定吗?错误的原因可能在于它们以某种方式被错误命名吗?

  • MalformedResponse 是否可以解释为响应中缺少特定字段?由于 Google 选择公开不同消息格式(Dialogflow 和 AppResponse)之间转换的内部工作原理,是否在某处列出了 Dialogflow 响应所需的字段?

  • 这是否暗示即使在这种情况下传递的 OAuth 消息也需要包含一些语音?

  • 最初,userId从 Dialogflow 收到的数据似乎始终是null,但查询文本似乎填充了GOOGLE_ASSISTANT_WELCOME,因此我们基于它的假设来启动帐户链接流逻辑null。这是一个正确的假设吗?

  • 在什么情况下userId最初会被填充(比如在 Alexa 中,它是在为用户启用技能时自动生成的)以便else触发上述条件?

  • 由身份验证基础设施颁发并由 AoG 支持的 OAuth 令牌是否应该采用任何特定格式,即 OIDC 或 JWT。它可以是任何随机字符串吗?仍然是token1AoG 用语中的有效令牌(就像在 Alexa 中一样)?

  • 任何配置错误的 Java 意图处理程序?我们应该对来自 AoG 帐户链接流程的响应中的哪个意图名称做出反应?

  • 是否有一个包罗万象的意图名称,一个可以合并到 Java 应用程序中的处理程序,以促进对上述内容的进一步调试?

  • “空话响应”是什么意思,我们没有提供哪些预期值并导致损坏?

  • 我们配置了哪些不应该配置的东西?

如果这很重要,这里是来自我们 webhook 的日志:

     [java] 02-21-2019 13:47:57 [qtp2056234595-127] INFO  domain.lola.user.utils.http.ControllerUtils [toString:30]    - Received AoG Request {
 [java]   "responseId": "0156911c-d7e8-405b-bf8f-f23320c02030",
 [java]   "queryResult": {
 [java]     "queryText": "GOOGLE_ASSISTANT_WELCOME",
 [java]     "parameters": {
 [java]       "any": ""
 [java]     },
 [java]     "allRequiredParamsPresent": true,
 [java]     "fulfillmentMessages": [{
 [java]       "text": {
 [java]         "text": [""]
 [java]       }
 [java]     }],
 [java]     "outputContexts": [{
 [java]       "name": "projects/speechbank-e8a15/agent/sessions/ABwppHE35s8T6qSdaaCMNiWuMdY7UsvQ3sHbLZJOQkVA4AFD2nhKuqTTvoJTkVh7yU81GCHbvlfZTxmULLd4Ug/contexts/google_assistant_welcome",
 [java]       "parameters": {
 [java]         "any.original": "",
 [java]         "any": ""
 [java]       }
 [java]     }, {
 [java]       "name": "projects/speechbank-e8a15/agent/sessions/ABwppHE35s8T6qSdaaCMNiWuMdY7UsvQ3sHbLZJOQkVA4AFD2nhKuqTTvoJTkVh7yU81GCHbvlfZTxmULLd4Ug/contexts/actions_capability_screen_output",
 [java]       "parameters": {
 [java]         "any.original": "",
 [java]         "any": ""
 [java]       }
 [java]     }, {
 [java]       "name": "projects/speechbank-e8a15/agent/sessions/ABwppHE35s8T6qSdaaCMNiWuMdY7UsvQ3sHbLZJOQkVA4AFD2nhKuqTTvoJTkVh7yU81GCHbvlfZTxmULLd4Ug/contexts/actions_capability_audio_output",
 [java]       "parameters": {
 [java]         "any.original": "",
 [java]         "any": ""
 [java]       }
 [java]     }, {
 [java]       "name": "projects/speechbank-e8a15/agent/sessions/ABwppHE35s8T6qSdaaCMNiWuMdY7UsvQ3sHbLZJOQkVA4AFD2nhKuqTTvoJTkVh7yU81GCHbvlfZTxmULLd4Ug/contexts/google_assistant_input_type_voice",
 [java]       "parameters": {
 [java]         "any.original": "",
 [java]         "any": ""
 [java]       }
 [java]     }, {
 [java]       "name": "projects/speechbank-e8a15/agent/sessions/ABwppHE35s8T6qSdaaCMNiWuMdY7UsvQ3sHbLZJOQkVA4AFD2nhKuqTTvoJTkVh7yU81GCHbvlfZTxmULLd4Ug/contexts/actions_capability_web_browser",
 [java]       "parameters": {
 [java]         "any.original": "",
 [java]         "any": ""
 [java]       }
 [java]     }, {
 [java]       "name": "projects/speechbank-e8a15/agent/sessions/ABwppHE35s8T6qSdaaCMNiWuMdY7UsvQ3sHbLZJOQkVA4AFD2nhKuqTTvoJTkVh7yU81GCHbvlfZTxmULLd4Ug/contexts/actions_capability_media_response_audio",
 [java]       "parameters": {
 [java]         "any.original": "",
 [java]         "any": ""
 [java]       }
 [java]     }],
 [java]     "intent": {
 [java]       "name": "projects/speechbank-e8a15/agent/intents/f645f492-f6dc-4e7e-8da6-45711c654ad0",
 [java]       "displayName": "RawText"
 [java]     },
 [java]     "intentDetectionConfidence": 1.0,
 [java]     "languageCode": "en-us"
 [java]   },
 [java]   "originalDetectIntentRequest": {
 [java]     "source": "google",
 [java]     "version": "2",
 [java]     "payload": {
 [java]       "isInSandbox": true,
 [java]       "surface": {
 [java]         "capabilities": [{
 [java]           "name": "actions.capability.AUDIO_OUTPUT"
 [java]         }, {
 [java]           "name": "actions.capability.MEDIA_RESPONSE_AUDIO"
 [java]         }, {
 [java]           "name": "actions.capability.SCREEN_OUTPUT"
 [java]         }, {
 [java]           "name": "actions.capability.WEB_BROWSER"
 [java]         }]
 [java]       },
 [java]       "inputs": [{
 [java]         "rawInputs": [{
 [java]           "query": "open speech Bank",
 [java]           "inputType": "VOICE"
 [java]         }],
 [java]         "intent": "actions.intent.MAIN"
 [java]       }],
 [java]       "user": {
 [java]         "userStorage": "{\"data\":{}}",
 [java]         "lastSeen": "2019-02-20T21:32:22Z",
 [java]         "locale": "en-US",
 [java]         "userId": "ABwppHFQHUBr0RrWA_OuL-kK2sxTPUvQtL3D-x2Ydr-7uxLt9zzEFzJrGB-X96d9XY8k9XTJj-RUg9WpzGB9jg"
 [java]       },
 [java]       "conversation": {
 [java]         "conversationId": "ABwppHE35s8T6qSdaaCMNiWuMdY7UsvQ3sHbLZJOQkVA4AFD2nhKuqTTvoJTkVh7yU81GCHbvlfZTxmULLd4Ug",
 [java]         "type": "NEW"
 [java]       },
 [java]       "availableSurfaces": [{
 [java]         "capabilities": [{
 [java]           "name": "actions.capability.AUDIO_OUTPUT"
 [java]         }, {
 [java]           "name": "actions.capability.SCREEN_OUTPUT"
 [java]         }, {
 [java]           "name": "actions.capability.WEB_BROWSER"
 [java]         }]
 [java]       }]
 [java]     }
 [java]   },
 [java]   "session": "projects/speechbank-e8a15/agent/sessions/ABwppHE35s8T6qSdaaCMNiWuMdY7UsvQ3sHbLZJOQkVA4AFD2nhKuqTTvoJTkVh7yU81GCHbvlfZTxmULLd4Ug"
 [java] }
 [java] 02-21-2019 13:47:57 [qtp2056234595-127] INFO  domain.lola.user.utils.actionsongoogle.AoGApp [launchRequestHandler:26]    - userId=null
 [java] 02-21-2019 13:47:57 [qtp2056234595-127] INFO  domain.lola.user.utils.actionsongoogle.AoGApp [launchRequestHandler:28]    - queryText=GOOGLE_ASSISTANT_WELCOME
 [java] 02-21-2019 13:47:57 [qtp2056234595-127] INFO  domain.lola.user.utils.actionsongoogle.AoGBotService [handlePOST:103]    - Generated response:
 [java]  {
 [java]   "outputContexts" : [ {
 [java]     "lifespanCount" : 99,
 [java]     "name" : "projects/speechbank-e8a15/agent/sessions/ABwppHE35s8T6qSdaaCMNiWuMdY7UsvQ3sHbLZJOQkVA4AFD2nhKuqTTvoJTkVh7yU81GCHbvlfZTxmULLd4Ug/contexts/_actions_on_google",
 [java]     "parameters" : {
 [java]       "data" : "{}"
 [java]     }
 [java]   } ],
 [java]   "payload" : {
 [java]     "google" : {
 [java]       "expectUserResponse" : true,
 [java]       "isSsml" : false,
 [java]       "systemIntent" : {
 [java]         "intent" : "actions.intent.SIGN_IN",
 [java]         "data" : {
 [java]           "@type" : "type.googleapis.com/google.actions.v2.SignInValueSpec"
 [java]         }
 [java]       },
 [java]       "userStorage" : "{\"data\":{}}"
 [java]     }
 [java]   }
 [java] }
4

1 回答 1

1

这条线

responseBuilder.add(new SignIn().setContext(speech));

将使用 SIGN_IN 事件创建您的响应。因此,在您的 dialogFlow 中,您需要使用actions_intent_SIGN_IN添加另一个意图,并且在您的 Java 中您还需要实现它,在这里您可以找到更多信息。

示例对话框流: 在此处输入图像描述

于 2019-02-22T14:12:54.017 回答