Alexa Intent sends two requests and fails - alexa-skill

What I am trying to do:
I have a very simple Alexa Skill which listens for a command word:
{
"intents": [{
"intent": "AffiliateEmpire",
"slots": [
{
"name": "affiliate_action",
"type": "AFFILIATE_ACTIONS"
},
{
"name": "date",
"type": AMAZON.DATE
}
}]
}
The custom slot type is:
AFFILIATE_ACTIONS commissions | earnings | sales | summary
My sample utterances are:
AffiliateEmpire for affiliate {affiliate_action}
AffiliateEmpire get {affiliate_action} for {date}
This communicates with my PHP server where I listen for the request type.
What is the problem?
When I invoke the command word without any intent, it makes a "LaunchRequest" to my server and correctly returns a card and outputSpeech
If I ask for an intent, it makes an IntentRequest to my server but then also sends a SessionEndedRequest.
I handle the IntentRequest and send it a json encoded response along the lines of:
array(
'version' => '1.0',
'response' => array(
'outputSpeech' => array(
'type' => 'PlainText',
'text' => 'Some simple response'
)),
'shouldEndSession' => true,
'sessionAttributes' => array()
));
My Amazon Echo never speaks the Some simple response but instead gives me There was a problem communicating with the requested skill
I had a very similar skill working before this, but cannot see what I am doing wrong.
What I have tried.
I am using php to write a log file for each raw request, json_decoded request and the response I sent back to Amazon. I am also using the testing tool, however this gives me The remote endpoint could not be called, or the response it returned was invalid.. I know it can call my endpoint as I see the log file written to each time.
Why is it calling my intent but then causing an error by ending the session?

Try the SSML for responding the alexa request,
Ex:
{
"version": "1.0",
"response": {
"directives": [],
"shouldEndSession": false,
"outputSpeech": {
"type": "SSML",
"ssml": "<speak>I am going to book a cab for you # your provided time.</speak>"
}
}
}

The error you're getting... endpoint could not be called, or the response it returned was invalid suggests that the json you're sending back to the Alexa service is not formatted correctly. You're receiving the request, which is how it's getting logged. Now, you just need to troubleshoot the response your sending back. It's likely something minor. Here are the docs for the json response format: https://developer.amazon.com/docs/custom-skills/request-and-response-json-reference.html. If you can share the json output from the php code it would be easier to help troubleshoot.
Also, I believe you need to change to 'shouldEndSession' => false
array(
'version' => '1.0',
'response' => array(
'outputSpeech' => array(
'type' => 'PlainText',
'text' => 'Some simple response'
)),
'shouldEndSession' => false,
'sessionAttributes' => array()
));

Related

How can i get the call-sid from response of callback in twilios AddOn's "IBM Watson"

We enable the Twilios AddOn "IBM Watson Speech to Text" for recording transcribe.and we set our server webhook while enabling the addon. Now twilio calling webhook once call is completely done. after completing call twilio give response in that webhook In Nodejs.For handling that call response we need "Call Sid".In webhook response we cannot get "callSid".So how we can identify that response is for this particular call...?
anyone help me to how can find call-sid in response?
Callback response is
{
"status": "successful",
"message": null,
"code": null,
"results": {
"ibm_watson_speechtotext": {
"request_sid": "**************",
"status": "successful",
"message": null,
"code": null,
"payload": [{
"content_type": "application/json",
"url": "*************/Data"
}],
"links": {
"add_on_result": "***********/Accounts/********/Recordings/**********/AddOnResults/******",
"payloads": "https://api.twilio.com/2010-04-01/Accounts/******/Recordings/*******/AddOnResults/******/Payloads",
"recording": "https://api.twilio.com/2010-04-01/Accounts/******/Recordings/*******"
}
}
}
}
Thank you for help
When you get the Add-on result it comes as part of the Twilio voice webhook, with all the normal request parameters as well as an extra AddOns parameter which contains the JSON that you have shared above.
Webhook requests from Twilio are in the format application/x-www-form-urlencoded and then within the AddOns parameter the data is a JSON string. In a (Ruby-like) pseudo code, you can access the call sid and the add on data like this:
post "/webhook" do
call_sid = params["CallSid"]
add_on_json = params["AddOns"]
add_on_data = JSON.parse(add_on_json)
# return TwiML
end

How to accept plain text in a route handler

I'm using FilePond to upload files to a hapi.js 17.9 API. FilePond allows automatic uploads after a user selects a file, and has a UI for deleting/reverting/undoing an uploaded file. Per FilePond's documentation...
FilePond sends DELETE request with 12345 as body by tapping the undo button
Where 12345 is an ID supplied by the server when the file was uploaded. Note this is not JSON, it's a plain text body.
I have a hapi.js route that's set up to handle DELETE methods, with the default validation settings. When FilePond sends it's request, Hapi responds with a 400 error before my handler code executes, and prints this message in the console:
Validation-failAction:error ValidationError: "value" must be an object
at Object.exports.process (/home/lamont/projects/rooster/api/node_modules/hapi/node_modules/joi/lib/errors.js:203:19)
at internals.Object._validateWithOptions (/home/lamont/projects/rooster/api/node_modules/hapi/node_modules/joi/lib/types/any/index.js:764:31)
at module.exports.internals.Any.root.validate (/home/lamont/projects/rooster/api/node_modules/hapi/node_modules/joi/lib/index.js:147:23)
at Object.internals.input (/home/lamont/projects/rooster/api/node_modules/hapi/lib/validation.js:83:63)
at exports.payload (/home/lamont/projects/rooster/api/node_modules/hapi/lib/validation.js:50:22)
at Request._lifecycle (/home/lamont/projects/rooster/api/node_modules/hapi/lib/request.js:263:62)
at process._tickCallback (internal/process/next_tick.js:68:7)
The hapi docs strongly imply the default payload validation options don't do any payload validation, so I'm a little surprised that this scenario is even a problem.
I've tried the following:
options.payload= {parse: false}
options.payload= {allow: "text\*"}
options.validate= { payload: async (v, o) => { return v } }
options.validate= { payload: true }
options.validate= { payload: false }
options.validate= undefined
options.validate= null
Edit:
Based on the suggestion of one of the guys on my team, I've also tried
options.validate : { payload: (() => { return Joi.string(); })() }
and defining my route options with no validate property at all (which ought to be functionally equivalent to an explicit undefined but who knows).
In all these cases, I still get the above validation error. Is it just not possible to write a hapi route that accepts plain, non-json text?

Can a webhook server have no response?

I have a dialogflow implementation using Google assistant, a nodeJS server to serve the webhook calls. Some of the user intents are empty phrases, and they do not need any response from webhook server. However, the webhook must be called with every user sentence.
Can the webhook response return an empty response and not crash while doing so?
The server returns the response in predefined JSON format known to google assistant. When I set this response to NULL OR when I set the payload part of this response to BLANK, the application crashes.
var simpleChatResponse = {
"payload": {
"google": {
"expectUserResponse": true,
"richResponse": {
"items": [
]
}
}
},
"outputContexts": [
]
};
Actual results: "myAgent1 is not responding" and the application crashes.
No, you can not send an empty response. As the docs state:
The first item in a rich response must be a simple response.

Cannot fetch internet message headers for some emails

I'm using the Microsoft Graph Client for Node.js to fetch email messages. I'm only interested in the headers. The code is working, but recently I got some errors in fetching internetMessageHeaders via the API.
For some messages, the API doesn't return any data for this field (and the code wasn't checking for this, hence the errors).
I tried to manually run the queries using POSTMAN. Using ?$select=internetMessageHeaders as a query param to only fetch the headers. If I remove the query param, I can fetch the message normally (body, etc.).
I haven't been able to find anywhere in the docs why this would happen.
Any ideas on what it's happening?
Edit: Here is the node.js code I am using
const MicrosoftGraphClient = require("#microsoft/microsoft-graph-client").Client
async function fetchEmailMessageHeaders(id, credentials) {
let client = MicrosoftGraphClient.init({
authProvider: callback => callback(null, credentials.access_token)
});
let req = client.api(id).select("internetMessageHeaders");
let message = await req.get();
return message.internetMessageHeaders;
}
Sample output (value of message var):
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('156751349d3cc68b')/messages(internetMessageHeaders)/$entity",
"#odata.etag": "W/\"CQAAABYAAABcr9US8aH2RIGaOGQZwDg3AAKyfdpk\"",
"id": "AQMkADAwATM0MDAAMS1hZWIxLThjZmYALTAwAi0wMAoARgAAA3wcQrEUgfhHoZ0BD2jmyXYHAFyv1RLxofZEgZo4ZBnAODcAAAIBDAAAAFyv1RLxofZEgZo4ZBnAODcAArJaPEcAAAA=",
"internetMessageHeaders": [
{
"name": "Received",
"value": "from BY2NAM01HT225.eop-nam01.prod.protection.outlook.com (2603:10a6:803:118::39) by VI1PR0301MB2221.eurprd03.prod.outlook.com with HTTPS via VE1PR03CA0050.EURPRD03.PROD.OUTLOOK.COM; Wed, 10 Apr 2019 11:41:55 +0000"
}
...
]
}
The problem is that for some emails, the message does not contain internetMessageHeaders.
I am using an inbox subscription to receive events for new email messages from Outlook. When an event is received I use the API to retrieve the message and extract headers from it.
API reference here
Edit2:
Here is an example JSON output of an event that fails to also retrieve headers:
{
"#odata.context": "https://graph.microsoft.com/v1.0/$metadata#users('53e07bf4-bb6a-4a82-a724-37dadfb1cf11')/messages(internetMessageHeaders)/$entity",
"#odata.etag": "W/\"CQAAABQAAADdeU+v2VzbRpZMSJGral7kAAXJkA==\"",
"id": "AAMkADhmMmVmM2NjLWFhNGMtNDBlYy04NzBkLTg5MmU2OWI0ODU4MgBGAAAAAAALg6E-e6CxRLEbZfrhFaDBBwAzAAMgKF1iTp242t34rFy5AAAAAAAOAAB5l_O62bUUTqTLk6KYrl4sAAGrJcjfAAA="
}
It seems internetMessageHeaders are not set when an email is replied to using outlook.office365.com. I'm also not able to see message headers when inspecting the message using Outlook on Mac.

postman POST request doesn't work in nodejs (accessing 3rd party API)

I've been playing around with some web scraping but I've run into an issue I can't figure out; Using a nodejs server (on my local computer) I cannot get passed a permission error barring me from accessing the data. What is confusing to me most is that using the chrome extension "Postman" I don't run into the permission errors, but using the code generated by postman, I do (as well as fiddling with variations of my own scratch code).
Do I have to be using a live server? Do I need to include some extra items in the headers that aren't being put there by Postman? Is there some layer of security around the API that for some reason Postman has access do that a local machine doesnt?
Any light that can be shed would be of use. Note that there is no public documentation of the SmithsFoodAndDrug API (that I can find), so there aren't necessarily APIKeys that are going to be used. But the fact that Postman can access the information makes me think I should be able to on a node server without any special authentication set up.
In Summary:
I'm looking at SmithsFoodAndDrug product information, and found the API where they are grabbing information from.
I figured out the headers needed in order to get local price information on products (on top of the json body format for the POST request)
Using postman I can generate the POST request and retrieve the desired API results
Using nodejs (and the code generated by postman to replicate the request) with both 'request' module and standard 'http' module request module I receive permission errors from the server.
Details: (assume gathering data on honeycrisp apples (0000000003283) with division-id of 706 and store-id of 00144)
http://www.smithsfoodanddrug.com/products/api/products/details
Headers are 'division-id' and 'store-id'. Body is in format of {"upcs":["XXX"],"filterBadProducts":false} where XXX is the specific product code.
Here are the Request Headers in postman. Here are the Request Body settings in postman. The following is a portion of the json response (which is what I want).
{"products": [
{
"brandName": null,
"clickListItem": true,
"countryOfOrigin": "Check store for country of origin details",
"customerFacingSize": "price $2.49/lb",
...
"calculatedPromoPrice": "2.49",
"calculatedRegularPrice": "2.99",
"calculatedReferencePrice": null,
"displayTemplate": "YellowTag",
"division": "706",
"minimumAdvertisedPrice": null,
"orderBy": "Unit",
"regularNFor": "1",
"referenceNFor": "1",
"referencePrice": null,
"store": "00144",
"endDate": "2018-09-19T00:00:00",
"priceNormal": "2.55",
"priceSale": "2.12",
"promoDescription": "About $2.12 for each",
"promoType": null,
...
"upc": "0000000003283",
...
}
],
"coupons": {},
"departments": [],
"priceHasError": false,
"totalCount": 1 }
When using the code given by postman to replicate the request, I get the error saying 'You don't have permission to access "http://www.smithsfoodanddrug.com/products/api/products/details" on this server.
Reference #18.1f3de93f.1536955806.1989a2b1.' .
// Code given by postman
var request = require("request");
var options = { method: 'POST',
url: 'http://www.smithsfoodanddrug.com/products/api/products/details',
headers:
{ 'postman-token': 'ad9638c1-1ea5-1afc-925e-fe753b342f91',
'cache-control': 'no-cache',
'store-id': '00144',
'division-id': '706',
'content-type': 'application/json' },
body: { upcs: [ '0000000003283' ], filterBadProducts: false },
json: true };
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(body);
});
change headers
headers:
{
'store-id': '00144',
'division-id': '706'
//'content-type': 'application/json'
}

Resources