I'm working on a Claudia.js bot that can be reached through Slack, FB messenger, and as an Alexa skill. Supposedly in claudia, you can return plain text and the framework will give it back to the "frontend" correctly... What I have currently have here works fine with FB and Slack, but when I access it through the Alexa "Service Simulator" I always get "The response is invalid." Here is the lambda that uses Claudia.js. Basically it gets messages from the client and then shunts them to another Lambda that is the "AI". Alexa seems to be choking on line 67. Ideas?
const promiseDelay = require('promise-delay');
// const aws = require('aws-sdk');
// const lambda = new aws.Lambda();
const lambda = require('aws-lambda-invoke');
const botBuilder = require('claudia-bot-builder');
const stackTrace = require('stack-trace');
//const slackDelayedReply = botBuilder.slackDelayedReply;
const getIntentName = alexaPayload =>
alexaPayload &&
alexaPayload.request &&
alexaPayload.request.type === 'IntentRequest' &&
alexaPayload.request.intent &&
alexaPayload.request.intent.name;
const api = botBuilder((message, apiRequest) => {
console.log = console.log.bind(null, '[LOG]');
console.info = console.info.bind(null, '[INFO]');
console.error = console.error.bind(null, '[ERROR]');
console.warn = console.warn.bind(null, '[WARN]');
console.info(message, apiRequest);
console.log(apiRequest.body);
const requestData = {
'user-id': {
type: message.type,
ID: message.sender
},
epoch: 1484771343.01,
'payload-type': 'luis',
facets: {},
utterance: 'Seek Showtimes',
payload: {
query: 'Seek Showtime',
topScoringIntent: {
intent: 'SeekShowtime',
score: 1.0
},
intents: [{
intent: 'SeekShowtime',
score: 1
}],
entities: []
}
};
if (message.text) {
return new Promise((resolve, reject) => {
lambda.raw.invoke({
FunctionName: 'ca2',
Payload: JSON.stringify(requestData),
}, (err, done) => {
if (err) {
const trace = stackTrace.parse(err);
console.warn(err);
console.error(trace);
return reject(err);
}
resolve(done);
});
}).then((result) => { // the initial response
const payload = JSON.parse(result.Payload);
console.log(payload.utterance);
return payload.utterance;
}).catch((error) => {
const trace = stackTrace.parse(error);
console.warn(error);
console.error(trace);
return 'Could not setup';
});
} else if (getIntentName(apiRequest.body) === 'ExitApp') {
return {
response: {
outputSpeech: {
type: 'PlainText',
text: 'Bye from Bot!'
},
shouldEndSession: true
}
};
} else {
return {};
}
},
{ platforms: ['facebook', 'slackSlashCommand', 'alexa'] }
);
module.exports = api;
Update -- even if I hardcode a plain text string response or use Alexa Message Builder I still get "The response is invalid." as the Service Response is coming back "undefined."
Looking at logs, as soon as the response is returned (for parsing by botBuilder and a pass to Alexa) this error occurs [TypeError: Cannot read property 'replace' of undefined]
Another update:
If I replace return payload.utterance
with something like
if (type === 'alexa-skill') {
Console.warn('trying to contact alexa');
return "Hi from Alexa";
}
The problem persists.
Here is where the Json Request comes in, no problem:
2017-04-27T18:06:30.552Z 3d70c273-2b74-11e7-a1c8-bf3fec00cbff STORE Map { "user-id": Map { "type": "alexa-skill", "ID": "amzn1.ask.account.AF6FUNJDSHGCXPVSAO5HUSRYFBD3SPCJJLILC4HLPS3K3L4AOWIMXPS4ZDDCXQ3ZVIV5L4FOMYD23PWZXEIAKYQBVXIQTPE2WW2PMBIXQIY3TUATXADCVNYO7NYUR2B45EU5GRIWBFHQIPLQVDQZMXD7IYVGTKAV3OWPHROCPR7XIUGNSJEAGQZJOMULSKT5HYSNUNJONASE34Y" }, "epoch": 1484771343.01, "payload-type": "luis", "utterance": "when is Logan playing", "payload": Map { "query": "when is Logan playing" } }
Here is the response I get back from the other lambda (the payload):
017-04-27T18:06:32.513Z 3d70c273-2b74-11e7-a1c8-bf3fec00cbff [LOG] mnlpData { StatusCode: 200,
Payload: '{"utterance": "To find movies playing near you, I need to know where you are. Please tell me your zip code.", "AskLocation": 1, "context": {"updated": 1493316392.162429, "user_id": "TEST_ID_TUES_14", "sessions": [{"intents": ["SeekShowtime", "SeekShowtime"], "facet-delta": {}, "facets": {"ity.location": {"ity.zip": "", "ity.code": "", "ity.theatre-name": ""}, "ity.movie": {"ity.title": "", "ity.code": ""}, "ity.time": [], "ity.date": []}, "modes": ["", "SHOWTIME_SWITCH", "AskLocation", "SHOWTIME_SWITCH", "AskLocation"]}], "created": 1493316379.950335, "mode_process_count": 2, "user-id": {"type": "alexa-skill", "ID": "amzn1.ask.account.AF6FUNJDSHGCXPVSAO5HUSRYFBD3SPCJJLILC4HLPS3K3L4AOWIMXPS4ZDDCXQ3ZVIV5L4FOMYD23PWZXEIAKYQBVXIQTPE2WW2PMBIXQIY3TUATXADCVNYO7NYUR2B45EU5GRIWBFHQIPLQVDQZMXD7IYVGTKAV3OWPHROCPR7XIUGNSJEAGQZJOMULSKT5HYSNUNJONASE34Y"}, "utterance": ["To find movies playing near you, I need to know where you are. Please tell me your zip code."]}}' }
then:
2017-04-27T18:06:32.514Z 3d70c273-2b74-11e7-a1c8-bf3fec00cbff [WARN] trying to contact alexa
and then the error:
2017-04-27T18:06:32.514Z 3d70c273-2b74-11e7-a1c8-bf3fec00cbff [TypeError: Cannot read property 'replace' of undefined]
First, if you notice the payload that is sent to you from the other lambda, you can see the utterance
is an array, so you might have to pass the first element if present.
By looking at the code of the bot builder, my best bet is that the error you're getting is due to the fact your alexaAppName
is undefined, and when passing it down to the responder that is encoded in base64, it's not possible to run a replace of this variable.
I would try to make sure my app name is correctly configured and what's given is a valid string as shown in the alexa claudia example.
If you haven't already, run claudia update --configure-alexa-skill
and enter your bot's name, then use the url it gives in your alexa skill builder setup. Select HTTPS instead of lambda arn.
Currently, message.text
is being passed as an empty string, which means that none of your log blocks are firing, and you are returning an empty object at the very bottom of your code. Test it yourself by replacing that empty object with a string, the alexa tester no longer complains.
So why is message.text an empty string? Claudia js populates the text field by concatenating all the slots that have been filled for your intent. If your intent has no slots, then claudia passes an empty string.
Add slots to your intent, make sure the skill is configured, and fix the logic statement issues.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With