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()
。
这个错误和我问的类似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()
。