API.ai Actions on Google - Failed to parse JSON response string with 'INVALID_ARGUMENT' error: ": Cannot find field."

API.ai Actions on Google - Failed to parse JSON response string with 'INVALID_ARGUMENT' error: ": Cannot find field."

这个错误和我问的类似here,但是这次是NodeJs客户端。

我正在尝试查找某个位置的方向。一旦在我的 webhook 上触发了意图,我就会使用 GoogleMapAPI 计算方向。但在它完成并发送响应之前,我在我的操作控制台上收到错误。

我检查了总响应时间,它不到 2 秒,也就是不到 5 秒超时 Google.

我哪里错了???

我的 API.ai 意图

将 express.js 与 Action-on-Google 节点客户端一起使用

'use strict';

const express = require('express');
const bodyParser = require('body-parser');
const intentHandler = require('./intent_handler')

const app = express();
app.use(bodyParser.json());

const ApiAiAssistant = require('actions-on-google').ApiAiAssistant;

// Create functions to handle requests here
....
....
const DIRECTION_INTENT = 'action_direction';

function MyAssistant(req, res) {
    const assistant = new ApiAiAssistant({request: req, response: res});
    assistant.handleRequest(responseHandler(assistant));
}


function responseHandler (assistant) {
    // intent contains the name of the intent you defined in the Actions area of API.AI
    let intent = assistant.getIntent();
    switch (intent) {
        case WELCOME_INTENT:
            ...
            break;
        case WELCOME_FALLBACK_PERMISSION_INTENT:
            ...
            break;
        case DIRECTION_INTENT:
            console.log(">>>>>>>DIRECTION_INTENT<<<<<<<");
            intentHandler.directionIntent(assistant);
            break;
    }
}
app.post('/', function (req, res) {
   MyAssistant(req, res);
});
app.listen(8080, function () {
    console.log('app listening on port 8080!')
});


处理程序代码

'use strict';
const speech = require("./speech_template");

const direction = require("./directionModule");

const intent_handler = {

    'welcomeIntent': function (assistant) {
        .....
    },

    'welcomeFallbackPermissionIntent': function (assistant) {
        .....

    },

    'directionIntent':function (assistant) {
        console.log('direction intent');
        direction.getDirectionWithSavedAddress(function (response) {
            assistant.ask(response);
        });
    }
};

module.exports = intent_handler;


方向提取 --- 在此完成之前操作控制台出现错误

'use strict';

const striptags = require('striptags');
const speech = require("./speech_template");

let googleMapsClient = require('@google/maps').createClient({
    key: global.GOOGLE_DIRECTION_KEY
});

const directionModule = {
    'getDirectionWithSavedAddress': function (eventCallback) {
        let myAdd = <From Saved Data>;
        if (myAdd === undefined) {
            console.log("error......");
        }
        let destination = <From Saved Data>;
        this.getDirectionWithAddress(myAdd, destination, function (dir) {
            ....
            if(SUCCESS){
                eventCallback(`<speak> ${steps} </speak>`);
            }else{
                eventCallback(`<speak> ${speech.ERROR_DIRECTIONS} </speak>`);
            }
        });
    },
    'getDirectionWithAddress': function (add1, add2, eventCallback) {
        let dir = {};
        googleMapsClient.directions({
            origin: add1,
            destination: add2,
            mode: "driving",
            departure_time: "now"
        }, function (err, response) {
            if (!err) {
                console.log(response.json.routes[0]);
                ....
                ....
                ....
            } else {
                console.log(`Error --> ${err.toString()}`);
                ....
            }
            eventCallback(dir);
        });
    }
};

module.exports = directionModule;

更新 我是 运行 通过 WebStorm 在本地编写代码,并使用 ngrok 通过端口转发公开 webhook。

更新2
错误请求 400

{
    "originalRequest": {
        "source": "google",
        "version": "2",
        "data": {
            "isInSandbox": true,
            "surface": {
                "capabilities": [
                    {
                        "name": "actions.capability.AUDIO_OUTPUT"
                    }
                ]
            },
            "inputs": [
                {
                    "rawInputs": [
                        {
                            "query": "get me there",
                            "inputType": "VOICE"
                        }
                    ],
                    "arguments": [
                        {
                            "rawText": "get me there",
                            "textValue": "get me there",
                            "name": "text"
                        }
                    ],
                    "intent": "actions.intent.TEXT"
                }
            ],
            "user": {
                "locale": "en-US",
                "userId": "<uID>"
            },
            "device": {},
            "conversation": {
                "conversationId": "<cID>",
                "type": "ACTIVE",
                "conversationToken": "[\"_actions_on_google_\",\"defaultwelcomeintent-followup\"]"
            }
        }
    },
    "id": "<ID>",
    "timestamp": "2017-09-12T17:08:10.321Z",
    "lang": "en",
    "result": {
        "source": "agent",
        "resolvedQuery": "get me there",
        "speech": "",
        "action": "action_direction",
        "actionIncomplete": false,
        "parameters": {},
        "contexts": [
            {
                "name": "_actions_on_google_",
                "parameters": {},
                "lifespan": 99
            },
            {
                "name": "google_assistant_input_type_voice",
                "parameters": {},
                "lifespan": 0
            },
            {
                "name": "actions_capability_audio_output",
                "parameters": {},
                "lifespan": 0
            },
            {
                "name": "defaultwelcomeintent-followup",
                "parameters": {},
                "lifespan": 4
            }
        ],
        "metadata": {
            "intentId": "<iID>",
            "webhookUsed": "true",
            "webhookForSlotFillingUsed": "false",
            "nluResponseTime": 15,
            "intentName": "DirectionIntent"
        },
        "fulfillment": {
            "speech": "",
            "messages": [
                {
                    "type": 0,
                    "speech": ""
                }
            ]
        },
        "score": 1
    },
    "status": {
        "code": 200,
        "errorType": "success"
    },
    "sessionId": "<sID>"
}

这看起来像是在我的回调完成之前,我的 webhook 正在向 Google 操作发送空响应。
为什么会这样,如何解决?????

问题在于您的 directionIntent() 函数如何调用和处理 getDirectionWithSavedAddress() 函数的结果。它期望 getDirectionWithSavedAddress() returns 一个函数,但实际上没有。相反,getDirectionWithSavedAddress() 期望将其结果发送到 回调

因此在调用 getDirectionWithAddress() 后,函数结束,不返回任何内容。 "nothing" 被发送到 assistant.ask(),returns 被发送到 Google 的服务器。这是一个无效的响应,所以你收到了错误。

解决这个问题应该很简单。您需要使用回调函数调用 getDirectionWithSavedAddress()。在此函数中,您应该使用发送到回调的值调用 assistant.ask()

所以 directionIntent() 可能看起来像

    'directionIntent':function (assistant) {
      console.log('direction intent');
      direction.getDirectionWithSavedAddress( function( msg ){
        assistant.ask( msg );
      } );
    }

已更新

这一行没有意义:

assistant.handleRequest(responseHandler(assistant));

assistant.handleRequest() 函数应该传递一个 Intent 名称映射到函数来调用以处理事件。您在 responseHandler() 函数中手动执行此操作并且您没有返回地图。由于您没有返回地图,因此在尝试执行 handleRequest() 时失败并生成错误 "Action Error: Request handler can NOT be empty".

您可以通过调用 responseHandler(assistant) 而根本不处理 handleRequest() 来解决这个问题。或者您可以创建 handleRequest() 期望的地图并完全摆脱 responseHandler()