Amazon Alexa: Testing my skill, convert a text to Lambda Request - amazon-web-services

I have defined my intent schema and sample utterances and it works fine. I can also test it with Service Simulator and Amazon dot.
I want to write a code which gets a text and create the IntentRequest based on it (knowing the intentSchema). I can see that Service Simulator is doing something similar: it receives the text, make the IntentRequest and show it in the left box named Lambda Request.
How can do the same? receive the text and recognize the intent and slots and convert it to IntentRequest (obviously, not manually).
example:
input: "How is the weather in Austin?"
output: a IntentRequest object similar to this:
{
"session": {
"sessionId": "....",
"application": {
"applicationId": "... "
},
"attributes": {},
"user": {...},
"new": true
},
"request": {
"type": "IntentRequest",
"requestId": "reqid",
"locale": "en-US",
"timestamp": "...",
"intent": {
"name": "WeatherIntent",
"slots": {...},
}
},
"version": "1.0"
}

You should use a dedicated dialog service such as Lex, API.AI, or Watson
They will get text and return the intent

Related

AWS LexV2 messenger channel integration not sending requestAttributes

I am building a AWS LexV2 chat bot that I want to integrate with Facebook Messenger via Channel Integration provided by LexV2. I am also using Lambda codehook to validate my inputs and fulfil my intents.
Following the docs, everything works as expected, except for one thing. When I log the event in my lambda function, requestAttributes field is missing from the object
My lambda function code:
import logging
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
def lambda_handler(event, context):
logger.error(event)
return ...
When I send a message to my app/page on facebook, this is what is logged:
{
"sessionId": "session-id",
"inputTranscript": "Intent utterance",
"interpretations":
[
{
"intent":
{
"slots":
{
"slot1": null,
"slot2": null
},
"confirmationState": "null",
"name": "IntentName",
"state": "InProgress"
},
"nluConfidence": 1.0
},
{
"intent":
{
"slots":
{},
"confirmationState": "null",
"name": "FallbackIntent",
"state": "InProgress"
}
}
],
"responseContentType": "text/plain; charset=utf-8",
"invocationSource": "DialogCodeHook",
"messageVersion": "1.0",
"sessionState":
{
"intent":
{
"slots":
{
"slot1": null,
"slot2": null
},
"confirmationState": "null",
"name": "IntentName",
"state": "InProgress"
},
"originatingRequestId": "req-id"
},
"bot":
{
"aliasId": "ALIASID",
"aliasName": "AliasName",
"name": "BotName",
"version": "DRAFT",
"localeId": "en_US",
"id": "bot-id"
},
"inputMode": "Text"
}
As you can see, no requestAttributes.
What's weird to me is that when I do the same thing for LexV1 bot (same facebook page/messenger app), I get these fields, e.g.
{
"requestAttributes":
{
"x-amz-lex:facebook-page-id": "page-id",
"x-amz-lex:channel-id": "channel-id",
"x-amz-lex:webhook-endpoint-url": "webhook-endpoint",
"x-amz-lex:accept-content-types": "PlainText",
"x-amz-lex:user-id": "user-id",
"x-amz-lex:channel-name": "channel-name",
"x-amz-lex:channel-type": "Facebook"
}
}
If anyone has any tips (other than "switch to V1") I would be very grateful. Thanks :))
Notes:
Changed Python Nones to nulls to easier format JSON
Replaced IDs and names from the logs with generic-id-slash-names

Amazon Lex Integration into AWS Lambda

I have been working with Alexa Skills Kit for some time now with my code deployed in AWS Lambda written in Node Js. Now i want to integrate chatbots into it via the amazon Lex service. So that i am able to control my device using both Amazon Alexa and Amazon lex. My question was that if i use the same intent and slots name in Amazon Lex as i have did in my Alexa Skill would the AWS Lambda code just work out of the box? Or would i have to modify the AWS Lambda code to accommodate the AWS Lex?
You will have to accommodate for the differences between Lex and Alexa. The most notable differences are the request and response formats.
Notable differences to be aware of:
Major differences between the formats and passing of sessionAttribtues and slots.
Lex has 4 built-in slotTypes that Alexa does not use (yet?): AMAZON.EmailAddress,, AMAZON.Percentage, AMAZON.PhoneNumber, AMAZON.SpeedUnit, and AMAZON.WeightUnit. (Reference.)
Lex always passes the full user input through inputTranscript. Alexa does not.
Alexa provides resolutions for slot values but fills the actual slot value with the raw data extracted from the input.
Lex will automatically resolve a slot value if you have synonyms set for that slotType.
After working with both of them quite a lot, and often dealing with this, I much prefer Lex to Alexa. I have found Lex to be simpler and provides more developer freedom and control, even though you do have to conform to the restrictions of each of Lex's output channels.
Compare Request / Response Formats:
Alexa JSON format
Lex JSON format
Example Alexa Request:
{
"version": "1.0",
"session": {
"new": true,
"sessionId": "amzn1.echo-api.session.[unique-value-here]",
"application": {
"applicationId": "amzn1.ask.skill.[unique-value-here]"
},
"attributes": {
"key": "string value"
},
"user": {
"userId": "amzn1.ask.account.[unique-value-here]",
"accessToken": "Atza|AAAAAAAA...",
"permissions": {
"consentToken": "ZZZZZZZ..."
}
}
},
"context": {
"System": {
"device": {
"deviceId": "string",
"supportedInterfaces": {
"AudioPlayer": {}
}
},
"application": {
"applicationId": "amzn1.ask.skill.[unique-value-here]"
},
"user": {
"userId": "amzn1.ask.account.[unique-value-here]",
"accessToken": "Atza|AAAAAAAA...",
"permissions": {
"consentToken": "ZZZZZZZ..."
}
},
"apiEndpoint": "https://api.amazonalexa.com",
"apiAccessToken": "AxThk..."
},
"AudioPlayer": {
"playerActivity": "PLAYING",
"token": "audioplayer-token",
"offsetInMilliseconds": 0
}
},
"request": {}
}
Example Lex Request:
{
"currentIntent": {
"name": "intent-name",
"slots": {
"slot name": "value",
"slot name": "value"
},
"slotDetails": {
"slot name": {
"resolutions" : [
{ "value": "resolved value" },
{ "value": "resolved value" }
],
"originalValue": "original text"
},
"slot name": {
"resolutions" : [
{ "value": "resolved value" },
{ "value": "resolved value" }
],
"originalValue": "original text"
}
},
"confirmationStatus": "None, Confirmed, or Denied (intent confirmation, if configured)"
},
"bot": {
"name": "bot name",
"alias": "bot alias",
"version": "bot version"
},
"userId": "User ID specified in the POST request to Amazon Lex.",
"inputTranscript": "Text used to process the request",
"invocationSource": "FulfillmentCodeHook or DialogCodeHook",
"outputDialogMode": "Text or Voice, based on ContentType request header in runtime API request",
"messageVersion": "1.0",
"sessionAttributes": {
"key": "value",
"key": "value"
},
"requestAttributes": {
"key": "value",
"key": "value"
}
}

Alexa is 'Unable to Reach the Requested Skill'

I'm receiving "I'm unable to reach the requested skill" message from an Alexa dashboard testing console for the skill that used to work before (with no modifications to any underlying infrastructure or code).
Here's the error obtained from Alexa's device logs:
{
"header": {
"namespace": "SkillDebugger",
"name": "CaptureError",
"messageId": "57d00be6-19d6-4529-b0b1-4c5d6c2760ac"
},
"payload": {
"skillId": "amzn1.ask.skill.db1bac88-183d-409c-9d3e-0e69fa0f5fe2",
"timestamp": "2018-09-27T19:11:51.066Z",
"dialogRequestId": "d9ec106d-2ef2-4526-a156-f4714ce5d034",
"skillRequestId": "amzn1.echo-api.request.1e166266-56e1-4c51-b40a-3ceb144f997f",
"code": "SKILL_ENDPOINT_ERROR",
"description": "An error occurred while issuing a SpeechletRequest for (requestId [amzn1.echo-api.request.1e166266-56e1-4c51-b40a-3ceb144f997f]",
"debuggingInfo": {
"type": "SkillExecutionInfo",
"content": {
"invocationRequest": {
"endpoint": "https://emptio.serveo.net/abc/api/v1/alexa",
"body": {
"version": "1.0",
"session": {
"new": false,
"sessionId": "amzn1.echo-api.session.bfc02d53-fe83-4c70-b731-ea7ede99d20a",
"application": {
"applicationId": "amzn1.ask.skill.db1bac88-183d-409c-9d3e-0e69fa0f5fe2"
},
"user": {
"userId": "amzn1.ask.account.AGX2NO3NXXDS6NLEZMDZXMRZZPJ3DLEERYK7J3NUPFUYRADFB2HRILB7BZVTN336OFVSNFFUP3VDVFHERK5PKQE5H32EQ5GGWTT67EMDQKP22Q7NTXXNYDUTYNCYI6EJUEODQ54VHKW4JSWVCS7JINWLYH2LICQVETFGZBY6NBDJVEX66VCGCZMRTFZYAG2E3IXDPMPVF3U4VMY",
"accessToken": "Atza|IwEBIM_YZylf-iVoydW0WhXTS4ykk6oA0FwI9Aa7Pdz_pysLPaL1AJwQLXA-Y1GJabHTWMJxfDEKyIiLFuxEPnTxuYaEDyany7WXzHMOd0-iiD9lYBxE6rIXkC3Z-I5PYU6DQtkT6DHxbusrkyGTb1bSfbznIaaFat3yNvKY9mXaNHEEhuuPRZJkXjffBA9WKzWrkGetOdHVvo-PLw2w9rWUiQQuJ6ryzQjugYILyCuTry3qz8lvqWGxYX0XB3dx_CGuzjEnNP0-X2ozhLXN8cBjtBrl7MlTffNyo6K94vi24-16bdIdFZG3mVL_bKSCXzAx2qzPJvBCn953FrPVw9zd7CtOintRSBDZ9Aw_QgKqTklliWTBP_8uRqq_nuMB8s992-Yhi6Zb-k7VvyYp7oLtJ8ggRqRlRk9vS4HBxyfKCxvfXmvlmZJlAtGjec_-Bx8UB2pf1ZH0xi-2LYpezVh2e7dgWenKU0PHvtduprVtpO4E72148mddcYyQRzAEdk8LYQx1SiamYY64_qmkv14h1qBPUIQPuv3MFt2PB7Mhm6cVTA"
}
},
"context": {
"System": {
"application": {
"applicationId": "amzn1.ask.skill.db1bac88-183d-409c-9d3e-0e69fa0f5fe2"
},
"user": {
"userId": "amzn1.ask.account.AGX2NO3NXXDS6NLEZMDZXMRZZPJ3DLEERYK7J3NUPFUYRADFB2HRILB7BZVTN336OFVSNFFUP3VDVFHERK5PKQE5H32EQ5GGWTT67EMDQKP22Q7NTXXNYDUTYNCYI6EJUEODQ54VHKW4JSWVCS7JINWLYH2LICQVETFGZBY6NBDJVEX66VCGCZMRTFZYAG2E3IXDPMPVF3U4VMY",
"accessToken": "Atza|IwEBIM_YZylf-iVoydW0WhXTS4ykk6oA0FwI9Aa7Pdz_pysLPaL1AJwQLXA-Y1GJabHTWMJxfDEKyIiLFuxEPnTxuYaEDyany7WXzHMOd0-iiD9lYBxE6rIXkC3Z-I5PYU6DQtkT6DHxbusrkyGTb1bSfbznIaaFat3yNvKY9mXaNHEEhuuPRZJkXjffBA9WKzWrkGetOdHVvo-PLw2w9rWUiQQuJ6ryzQjugYILyCuTry3qz8lvqWGxYX0XB3dx_CGuzjEnNP0-X2ozhLXN8cBjtBrl7MlTffNyo6K94vi24-16bdIdFZG3mVL_bKSCXzAx2qzPJvBCn953FrPVw9zd7CtOintRSBDZ9Aw_QgKqTklliWTBP_8uRqq_nuMB8s992-Yhi6Zb-k7VvyYp7oLtJ8ggRqRlRk9vS4HBxyfKCxvfXmvlmZJlAtGjec_-Bx8UB2pf1ZH0xi-2LYpezVh2e7dgWenKU0PHvtduprVtpO4E72148mddcYyQRzAEdk8LYQx1SiamYY64_qmkv14h1qBPUIQPuv3MFt2PB7Mhm6cVTA"
},
"device": {
"deviceId": "amzn1.ask.device.AGUTTO7VCXPCUUSXNDCNO6LK7LZHUKPDGZBOXUOBNRNOBGD7FHBJWHOK3LJNQX4U47HTFLUXJ6MHBL6V7UCDNTWOMBJIP5R4R2ZVK3XJX42PEZG6J6TCS3U7NSYZZ3PDCUSH22CY7LYGNIK2MGXCUGR4ITQQ",
"supportedInterfaces": {}
},
"apiEndpoint": "https://api.amazonalexa.com",
"apiAccessToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6IjEifQ.eyJhdWQiOiJodHRwczovL2FwaS5hbWF6b25hbGV4YS5jb20iLCJpc3MiOiJBbGV4YVNraWxsS2l0Iiwic3ViIjoiYW16bjEuYXNrLnNraWxsLmRiMWJhYzg4LTE4M2QtNDA5Yy05ZDNlLTBlNjlmYTBmNWZlMiIsImV4cCI6MTUzODA3OTEwNywiaWF0IjoxNTM4MDc1NTA3LCJuYmYiOjE1MzgwNzU1MDcsInByaXZhdGVDbGFpbXMiOnsiY29uc2VudFRva2VuIjpudWxsLCJkZXZpY2VJZCI6ImFtem4xLmFzay5kZXZpY2UuQUdVVFRPN1ZDWFBDVVVTWE5EQ05PNkxLN0xaSFVLUERHWkJPWFVPQk5STk9CR0Q3RkhCSldIT0szTEpOUVg0VTQ3SFRGTFVYSjZNSEJMNlY3VUNETlRXT01CSklQNVI0UjJaVkszWEpYNDJQRVpHNko2VENTM1U3TlNZWlozUERDVVNIMjJDWTdMWUdOSUsyTUdYQ1VHUjRJVFFRIiwidXNlcklkIjoiYW16bjEuYXNrLmFjY291bnQuQUdYMk5PM05YWERTNk5MRVpNRFpYTVJaWlBKM0RMRUVSWUs3SjNOVVBGVVlSQURGQjJIUklMQjdCWlZUTjMzNk9GVlNORkZVUDNWRFZGSEVSSzVQS1FFNUgzMkVRNUdHV1RUNjdFTURRS1AyMlE3TlRYWE5ZRFVUWU5DWUk2RUpVRU9EUTU0VkhLVzRKU1dWQ1M3SklOV0xZSDJMSUNRVkVURkdaQlk2TkJESlZFWDY2VkNHQ1pNUlRGWllBRzJFM0lYRFBNUFZGM1U0Vk1ZIn19.LzPCt8QPxkEa5jFK3IMGMQLWS3vXOopyGKBu0cAy1cnJzAk7wnbKwc9eyQYDMr3uH7MyHr4s7xUKpWlvspGOAL3LqKxFbxqpB5zIjhKifqdGQhB_nurOAjeyZOipZ0ZhSuPN9fqTwp7zwca4LdYz6Kuahklz7D7pU7ICNI1DNqNKDx9HmyWbJIwXWL3MvS9sEujDo15oTdiueNaCbC7kLnPi0adrukHy3J6HVN_XjWS5mSSawuObgiT2b9eLm4qntoMG7MnDTSrzxmhKgXm3WrbFxRW_ZKE3uu1wa7-412f8DPxvbVZkeYDRwWMTO8s7BtnzjPcKEcT6daLXKRgpVw"
}
},
"request": {
"type": "SessionEndedRequest",
"requestId": "amzn1.echo-api.request.1e166266-56e1-4c51-b40a-3ceb144f997f",
"timestamp": "2018-09-27T19:11:47Z",
"locale": "en-US",
"reason": "ERROR",
"error": {
"type": "INVALID_RESPONSE",
"message": "An exception occurred while dispatching the request to the skill."
}
}
}
},
"invocationResponse": null,
"metrics": {
"skillExecutionTimeInMilliseconds": 3107
}
}
}
}
}
As is seen from the above response, the skill is configured with an endpoint: https://emptio.serveo.net/abc/api/v1/alexa which is perfectly reachable.
Again, the same exact skill used to work just yesterday. The invocation name under which I am calling it used to work fine.
I'm able to reach and verify the above endpoint is functional and responsive outside Alexa, but it's somehow not reachable from the Alexa dashboard.
I'm monitoring the logs from Serveo - they don't show any activity, meaning that something is broken before the webhook is called.
What could be the reason for the error? How can I debug what is going on in the Alexa stack?
Make sure option for the endpoint's SSL certificate type is correct. You can change this in the endpoint option in the web development console.
Your host might be using a wildcard certificate so select the wildcard option, save your endpoint again - then test again using the console for reachability.

Amazon AWS Lex slot type list

This is a pretty simple question, but I can't find any evidence for an answer. I want to configure a slot type to me a list -- meaning that Lex will have to continue asking more elements in that list.
For example, here is what a back-and-forth should look like:
Lex: What flowers would you like to order?
Me: roses
Lex: Any other types?
Me: yes, I also want lillies
Lex: Anything else?
Me: that is all
An example payload that gets sent to a Lambda looks like this:
{
"currentIntent": {
"slots": {
"PickupDate": "2030-11-08",
"PickupTime": "10:00",
"FlowerType": "lilies"
},
"name": "OrderFlowers",
"confirmationStatus": "None"
},
"bot": {
"alias": "$LATEST",
"version": "$LATEST",
"name": "OrderFlowers"
},
"userId": "John",
"invocationSource": "DialogCodeHook",
"outputDialogMode": "Text",
"messageVersion": "1.0",
"sessionAttributes": {}
}
That ^^^ was taken directly from the examples Test Configurations in AWS Lambda console.
I want it to look like this:
{
"currentIntent": {
"slots": {
"PickupDate": "2030-11-08",
"PickupTime": "10:00",
"FlowerTypes": [
"roses",
"lilies"
]
},
"name": "OrderFlowers",
"confirmationStatus": "None"
},
"bot": {
"alias": "$LATEST",
"version": "$LATEST",
"name": "OrderFlowers"
},
"userId": "John",
"invocationSource": "DialogCodeHook",
"outputDialogMode": "Text",
"messageVersion": "1.0",
"sessionAttributes": {}
}
Lex slots are always strings, so you will have to come up with a more sophisticated solution. I would suggest:
Create an intent asking what flowers to order. You should be eliciting a slot called 'flower'.
When you run your code, take the input from the slot, and add it to a session attribute. Now ask a follow up question "Enter any more flowers you'd like to order, or 'done' if you are finished"
Elicit the slot again.
Every time you check the slot (before adding it to the session), see if it matches 'done'. If it does, you can fulfil the order and then the event.
Goofy, I know, but Lex has very limited options for slots right now!

Delete record Libcloud (GoDaddy api)

I try to implement delete method for Record delate-record, but its my first time to use python and this api.
The GoDaddy API doesn't have a delete record method, so this functionality is not exposed in the driver.
https://developer.godaddy.com/doc#!/_v1_domains/recordReplace
The driver could offer the 'replace records in zone' method, which would allow you to fetch the current list of records, and then set the new list minus the record you want to remove. But that feature is not implemented and quite risky.
First,
Send a GET request to https://api.godaddy.com/v1/domains/{DOMAIN}/records
Then, Enumerate over all records of API Response (JSON Array) and prepare new data by removing the one that needs to be deleted.
API Response (SAMPLE)
[
{
"data": "192.168.1.1",
"name": "#",
"ttl": 600,
"type": "A"
},
{
"data": "ns1.example.com",
"name": "#",
"ttl": 3600,
"type": "NS"
},
{
"data": "#",
"name": "www",
"ttl": 3600,
"type": "CNAME"
},
{
"data": "mail.example.com",
"name": "#",
"ttl": 3600,
"priority": 1,
"type": "MX"
}
]
New Data (After deleting record) (SAMPLE)
[
{
"data": "192.168.1.1",
"name": "#",
"ttl": 600,
"type": "A"
},
{
"data": "ns1.example.com",
"name": "#",
"ttl": 3600,
"type": "NS"
},
{
"data": "#",
"name": "www",
"ttl": 3600,
"type": "CNAME"
}
]
Now,
Send a PUT request to https://api.godaddy.com/v1/domains/{DOMAIN}/records with new data.
The most important thing is how you identify the records in above array which needs to be deleted. This would not be a difficult task, assuming you have good programming skills.
I managed to worked around it in kind of a hacky - we had bunch of records we wanted to delete, doing it manually seemed weird so I added a Javascript into the Chrome Developer Console, running on an authenticated session from the DNS manage page:
function deleteGoDaddyRecords(recordId) {
$.ajax({
url: 'https://dcc.godaddy.com/api/v3/domains/<YOUR-DOMAIN.com>/records?recordId='+recordId,
type: 'DELETE',
success: function(result) {
console.log(result)
}
});
}
which let me use the same call the UI is calling when you ask to delete a record.
the only thing you need to provide is the AttributeUid which is not available with the public API, but it is in the front-end API:
https://dcc.godaddy.com/api/v2/domains/runahr.com/records
So I managed to create a script that will generate bunch of
deleteGoDaddyRecords('<RECORD-UUID>');
deleteGoDaddyRecords('<RECORD-UUID>');
copy & paste the generated script into the Developers Console and that solved it for now.
I hope GoDaddy will add a public DELETE endpoint to their API in the future :)