Incorrect Intent State Resolution In Alexa Skill - alexa

I have 2 intents in 2 different states.
TriviaState.AnswerIntent and StartState.ChooseQuizIntent.
Both intents accept a required slot type of AMAZON.Number
{
"name": "AnswerIntent",
"slots": [
{
"name": "answernum",
"type": "AMAZON.NUMBER",
"samples": [
"number {answernum}",
"answer number {answernum}",
"{answernum}",
"answer {answernum}"
]
}
],
"samples": [
"number {answernum}",
"answer {answernum}",
"{answernum}",
"answer number {answernum}"
]
},
{
"name": "ChooseQuizIntent",
"slots": [
{
"name": "quiznumber",
"type": "AMAZON.NUMBER",
"samples": [
"quiz {quiznumber}",
"{quiznumber}",
"quiz number {quiznumber}",
"{quiznumber} please",
"number {quiznumber}",
"number {quiznumber} please"
]
}
],
"samples": [
"{quiznumber}",
"quiz number {quiznumber}",
"number {quiznumber}",
"I'd like to play number {quiznumber}",
"{quiznumber} please",
"number {quiznumber} please",
"quiz {quiznumber}"
]
},
When in StartState, if the user says 'number 2', StartState.ChooseQuizIntent is called correctly. However, if the user says '2', alexa maps this to the TriviaState.AnswerIntent which results in StartState.unhandled being called.
Conversely, when in the TriviaState, if the user says '2', TriviaState.AnswerIntent is correctly called but if the user says 'number 2', alexa maps it to StartState.ChooseQuizIntent which results in TriviaState.unhandled being called.
I realise both slots are receiving identical inputs from alexa's point of view but I thought that the states would be respected which they clearly are not.

Related

Defining a JSON schema with a nested array

I'm new to JSON so bear with me please (especially if I use the wrong terminology).
I'm trying to define a JSON schema with a nested array. The idea is that there could be up to 5 customers, and each customer could have up to 40 account types.
This is what I've defined, but I have a feeling it's incorrect. Could someone help me please ?
(I hope I've included enough of the relevant data to make sense)
"type":"object",
"properties":,
{
"customers":{
"description": "Contains up to 5 customers",
"type":"array",
"maxItems":5, /* Here are your 5 customers */
"minItems":0,
"items":{
"type":"object",
"properties":,
{
"customerid_cl":{
"description": "ID-KUNDNR",
"type":"integer",
"maximum":999999999,
"minimum":000000000
},
"ssn_number":{
"description": "id_persnr",
"type":"string",
"maxLength":12,
"minLength":12
},
"first_name":{
"description": "be_fnamn",
"type":"string",
"maxLength":15,
"minLength":15
},
"last_name":{
"description": "be_enamn",
"type":"string",
"maxLength":27,
"minLength":27
},
"deceased":{
"description": "FL-AVLIDEN",
"type":"boolean",
},
},
"Accounts":{
"description": "Contains up to 40 account types",
"type":"array",
"maxItems":40, /* and here are the 40 account types (potentially) for EACH customer */
"minItems":0,
"items":{
"type":"object",
"properties":,
{
"account_number":
{
"description": "id_kontonr",
"type":"string",
"maxLength":9,
"minLength":1
},
"currentbalance":
{
"description": "Current account balance - how do we indicate that negative values are okay ????",
"type": "number",
"format":"decimal",
"maximum":999999999.99,
"minimum":-999999999.99
},**strong text**

Use number and phrase in a single custom slot for alexa

Is there a way to create a custom slot type which contains both a phrase and a number. Something like:
{
"name": "mycustomslot",
"values": [
{
"name": {
"value": "eating",
"synonyms": [
"eat something",
"are you eating",
"eat"
]
}
},
{
"name": {
"value": "drinking",
"synonyms": [
"drink something",
"drinking",
"drink",
]
}
}
{
"name": {
"value": AMAZON.NUMBER,
"synonyms": []
}
}
}
]
},
So, I can get "eating" from utterances "eat something", "are you eating" etc. and a number on uttering a number from a single slot type.
You can use this type: AMAZON.SearchQuery
This type can get all the phrase which user speaks.
Utterance: I eat {query} (with type of "query" is AMAZON.SearchQuery)
Speech: I eat 9 plates of meat
=> The value handler will receive is something like this: { name: "query", value: "9 plates of meat"}

How does a predefined slot return a resolution?

I'm building a simple Guess Who skill game for Alexa. I have two intents right now: GenderIntent and HairColorIntent.
GenderIntent has a custom slot to handle gender and related synonyms such as mapping "boy" and "man" to "Male". This is working great. It returns a resolution within the slot. Exactly what I need.
HairColorIntent has a predefined Amazon slot, AMAZON.Color. This is not working great as it never returns a resolution regardless of the color supplied.
Here is my model for GenderIntent and HairColorIntent:
{
"name": "GenderIntent",
"samples": [
"are you a {Gender}"
],
"slots": [
{
"name": "Gender",
"type": "GENDER_TYPES",
"samples": []
}
]
},
{
"name": "HairColorIntent",
"samples": [
"is your hair {HairColor}",
"do you have {HairColor} hair"
],
"slots": [
{
"name": "HairColor",
"type": "AMAZON.Color"
}
]
}
GenderIntent returns the following slot WITH resolutions:
{
"Gender": {
"name": "Gender",
"value": "male",
"resolutions": {
"resolutionsPerAuthority": [
{
"authority": "amzn1.er-authority.echo-sdk.amzn1.ask.skill.2ed972f4-1c5a-4cc1-8fd7-3f440f5b8968.GENDER_TYPES",
"status": {
"code": "ER_SUCCESS_MATCH"
},
"values": [
{
"value": {
"name": "Male",
"id": "63889cfb9d3cbe05d1bd2be5cc9953fd"
}
}
]
}
]
},
"confirmationStatus": "NONE",
"source": "USER"
}
}
HairColorIntent returns the following WITHOUT resolutions:
{
"HairColor": {
"name": "HairColor",
"value": "brown",
"confirmationStatus": "NONE",
"source": "USER"
}
}
I'd like HairColorIntent's HairColor slot to return the resolution. What am I doing wrong?
Resolution is only returned if you use synonyms in your slot type.
Not exactly sure how you handle it in your code, for example Node.js would be:
handlerInput.requestEnvelope.request.intent.slots.Gender.resolutions.resolutionPerAuthority[0].values[0].value.name
If you do not use synonyms (for example for the HairColor slot), you can get the value simply by handlerInput.requestEnvelope.request.intent.slots.HairColor.value
Working with predefined slot types this should work well with your code. If you want custom slot types to also return resolution whether you actually use synonyms or not, you can always just simply give the value as a synonym and it should return the full resolution tree.
Hope that answered your question.

"Alexa, open Mighty Righty" - works /// "Alexa, ask Mighty Righty who is right, me or my husband" doesn't work (hmm, I don't know that one)

My published skill can be invoked by "Alexa, open Mighty Righty," but it won't work if a user says "Alexa, ask Mighty Righty who is right, me or my husband," how to do that?
https://www.amazon.com/dp/B07SGBR24G/
This is the link to the working published skill.
#------------------------------Part1--------------------------------
# In this part we define a list that contains the player names, and
# a dictionary with player biographies
Player_LIST = ["me or my wife", "me or my husband", "me or you"]
Player_BIOGRAPHY = {"me or my wife": ["She is. Do as she says, and you'll be OK.", "You", "Of course, your wife", "No doubt, it's you"],
"me or my husband": ["He is", "You are right", "He is not right", "Your husband. He is always right."],
"me or you": ["me", "You are, ... I mean... you are wrong, of course", "of course me", "It's me, don't you know that, my friend?", "you yourself, what do you think? Of course it's me", "I always know who is right, me or not me, so, it's me", "what do you think? I am Mighty Righty, so I am RIGHT"]}
#------------------------------Part2--------------------------------
# Here we define our Lambda function and configure what it does when
# an event with a Launch, Intent and Session End Requests are sent. # The Lambda function responses to an event carrying a particular
# Request are handled by functions such as on_launch(event) and
# intent_scheme(event).
def lambda_handler(event, context):
if event['session']['new']:
on_start()
if event['request']['type'] == "LaunchRequest":
return on_launch(event)
elif event['request']['type'] == "IntentRequest":
return intent_scheme(event)
elif event['request']['type'] == "SessionEndedRequest":
return on_end()
#------------------------------Part3--------------------------------
# Here we define the Request handler functions
def on_start():
print("Session Started.")
def on_launch(event):
onlunch_MSG = "Hi, start with the word. Me. For example: who is right, me or my husband?"
reprompt_MSG = "you can say, who is right, me or my wife?"
card_TEXT = "Who is right, me or... ?."
card_TITLE = "Choose your question."
return output_json_builder_with_reprompt_and_card(onlunch_MSG, card_TEXT, card_TITLE, reprompt_MSG, False)
def on_end():
print("Session Ended.")
#-----------------------------Part3.1-------------------------------
# The intent_scheme(event) function handles the Intent Request.
# Since we have a few different intents in our skill, we need to
# configure what this function will do upon receiving a particular
# intent. This can be done by introducing the functions which handle
# each of the intents.
def intent_scheme(event):
intent_name = event['request']['intent']['name']
if intent_name == "playerBio":
return player_bio(event)
elif intent_name in ["AMAZON.NoIntent", "AMAZON.StopIntent", "AMAZON.CancelIntent"]:
return stop_the_skill(event)
elif intent_name == "AMAZON.HelpIntent":
return assistance(event)
elif intent_name == "AMAZON.FallbackIntent":
return fallback_call(event)
#---------------------------Part3.1.1-------------------------------
# Here we define the intent handler functions
import random # this can be at the top of the file too
def player_bio(event):
name=event['request']['intent']['slots']['player']['value']
player_list_lower=[w.lower() for w in Player_LIST]
if name.lower() in player_list_lower:
reprompt_MSG = "Try to say something like. who is right me or them"
card_TEXT = "You've picked " + name.lower()
card_TITLE = "You've picked " + name.lower()
return output_json_builder_with_reprompt_and_card(random.choice(Player_BIOGRAPHY[name.lower()]), card_TEXT, card_TITLE, reprompt_MSG, False)
else:
wrongname_MSG = "Some questions may not yet be present in my database. Try to rephrase your sentence."
reprompt_MSG = "For example, who is right, me or my wife?"
card_TEXT = "Use the full question."
card_TITLE = "Wrong question."
return output_json_builder_with_reprompt_and_card(wrongname_MSG, card_TEXT, card_TITLE, reprompt_MSG, False)
def stop_the_skill(event):
stop_MSG = "Bye for now and feel free to ask mighty righty who is right"
reprompt_MSG = "next time just tell me. Open Mighty righty"
card_TEXT = "Bye."
card_TITLE = "Bye Bye."
return output_json_builder_with_reprompt_and_card(stop_MSG, card_TEXT, card_TITLE, reprompt_MSG, True)
def assistance(event):
assistance_MSG = "start with the word. Me."
reprompt_MSG = "For example, who is right me or him"
card_TEXT = "You've asked for help."
card_TITLE = "Help"
return output_json_builder_with_reprompt_and_card(assistance_MSG, card_TEXT, card_TITLE, reprompt_MSG, False)
def fallback_call(event):
fallback_MSG = "Try to say, for example, who is right, me or him?"
reprompt_MSG = "Certain answers may not yet be in my database. Use personal pronouns, for example: me, or her, me, or him, me, or them. They can cover pretty much everybody"
card_TEXT = "You've asked a wrong question."
card_TITLE = "Wrong question."
return output_json_builder_with_reprompt_and_card(fallback_MSG, card_TEXT, card_TITLE, reprompt_MSG, False)
#------------------------------Part4--------------------------------
# The response of our Lambda function should be in a json format.
# That is why in this part of the code we define the functions which
# will build the response in the requested format. These functions
# are used by both the intent handlers and the request handlers to
# build the output.
def plain_text_builder(text_body):
text_dict = {}
text_dict['type'] = 'PlainText'
text_dict['text'] = text_body
return text_dict
def reprompt_builder(repr_text):
reprompt_dict = {}
reprompt_dict['outputSpeech'] = plain_text_builder(repr_text)
return reprompt_dict
def card_builder(c_text, c_title):
card_dict = {}
card_dict['type'] = "Simple"
card_dict['title'] = c_title
card_dict['content'] = c_text
return card_dict
def response_field_builder_with_reprompt_and_card(outputSpeach_text, card_text, card_title, reprompt_text, value):
speech_dict = {}
speech_dict['outputSpeech'] = plain_text_builder(outputSpeach_text)
speech_dict['card'] = card_builder(card_text, card_title)
speech_dict['reprompt'] = reprompt_builder(reprompt_text)
speech_dict['shouldEndSession'] = value
return speech_dict
def output_json_builder_with_reprompt_and_card(outputSpeach_text, card_text, card_title, reprompt_text, value):
response_dict = {}
response_dict['version'] = '1.0'
response_dict['response'] = response_field_builder_with_reprompt_and_card(outputSpeach_text, card_text, card_title, reprompt_text, value)
return response_dict
This Is the JSON file. It might be slightly different, because I tried to shorten the file as much as possible for the purpose of this question, but it doesn't matter because the main components here - are present in the current working app:
{
"interactionModel": {
"languageModel": {
"invocationName": "mighty righty",
"intents": [
{
"name": "AMAZON.FallbackIntent",
"samples": []
},
{
"name": "AMAZON.CancelIntent",
"samples": []
},
{
"name": "AMAZON.HelpIntent",
"samples": []
},
{
"name": "AMAZON.StopIntent",
"samples": []
},
{
"name": "playerBio",
"slots": [
{
"name": "player",
"type": "playerNames"
}
],
"samples": [
"who is right {player}"
]
},
{
"name": "AMAZON.NoIntent",
"samples": []
},
{
"name": "AMAZON.NavigateHomeIntent",
"samples": []
}
],
"types": [
{
"name": "playerNames",
"values": [
{
"name": {
"value": "me or you",
"synonyms": [
"you or me"
]
}
},
{
"name": {
"value": "me or them",
"synonyms": [
"I am or they are",
"I am or them",
"I am or they",
"I or they are",
"I or them",
"me or they are",
"me or they"
]
}
},
{
"name": {
"value": "me or him",
"synonyms": [
"I or him",
"I or he",
"I'm or he is",
"I'm or him",
"me or he is",
"me or he's"
]
}
},
{
"name": {
"value": "me or her",
"synonyms": [
"I'm or she's",
"I am or she is",
"I'm or she",
"I'm or her",
"me or she is",
"me or she"
]
}
},
{
"name": {
"value": "me or my wife",
"synonyms": [
"me or my wifey"
]
}
},
{
"name": {
"value": "me or my husband",
"synonyms": [
"my husband"
]
}
}
]
}
]
}
}
}
By the way, as you can see there are synonyms, but Alexa won't use them. Very good example:
Alexa, who is right, me or you? (works)
Alexa, who is right, you or me? (won't work)
But in the JSON it says:
"value": "me or you",
"synonyms": [
"you or me"
]
But I think for that I need to ask another question...
I went to Alexa Developer Console, Test tab, wrote:
"alexa, ask mighty righty who is right, me or my husband"
She said:
Hmm, I don't know that.
Nothing in JSON input and output windows, but I found this line in device logs:
[21:11:35:676] - Event: Text.TextMessage
I clicked there and it opened this (if this is what is needed):
{
"event": {
"header": {
"namespace": "Text",
"name": "TextMessage",
"messageId": "messageId",
"dialogRequestId": "numbers-and-letters-separated-with-sashes-that-i-deletedxxxxxxxxxxxxxxxxxxxxxxxxxxx506"
},
"payload": {
"textMessage": "alexa, ask mighty righty who is right, me or my husband"
}
},
"context": [
{
"header": {
"namespace": "System",
"name": "SettingsState",
"payloadVersion": "1"
},
"payload": {
"settings": [
{
"key": "com.amazon.alexa.characteristics.viewport.experiences",
"value": "[{\"arcMinuteWidth\":\"246\",\"arcMinuteHeight\":\"144\",\"canRotate\":\"false\",\"canResize\":\"false\"}]"
},
{
"key": "com.amazon.alexa.characteristics.viewport.shape",
"value": "RECTANGLE"
},
{
"key": "com.amazon.alexa.characteristics.viewport.pixelWidth",
"value": "1024"
},
{
"key": "com.amazon.alexa.characteristics.viewport.pixelHeight",
"value": "600"
},
{
"key": "com.amazon.alexa.characteristics.viewport.dpi",
"value": "160"
},
{
"key": "com.amazon.alexa.characteristics.viewport.currentPixelWidth",
"value": "1024"
},
{
"key": "com.amazon.alexa.characteristics.viewport.currentPixelHeight",
"value": "600"
},
{
"key": "com.amazon.alexa.characteristics.viewport.touch",
"value": "[\"SINGLE\"]"
},
{
"key": "com.amazon.alexa.characteristics.viewport.video",
"value": "{\"codecs\": [\"H_264_42\",\"H_264_41\"]}"
}
]
}
},
{
"header": {
"namespace": "SpeechSynthesizer",
"name": "SpeechState"
},
"payload": {
"token": "amzn1.as-ct.v1.ThirdPartySdkSpeechlet#ACRI#ValidatedSpeakDirective_amzn1.ask.skill.some-kind-of-numbers-and-letters-here-i-deleted-it_they-are-seperated-with-dashes-and-1-underscore-in-the-middlexxxxxxxxxxxxxxxxxxxxxxxx",
"offsetInMilliseconds": 1000,
"playerActivity": "FINISHED"
}
},
{
"header": {
"namespace": "AudioPlayer",
"name": "PlaybackState"
},
"payload": {
"token": "",
"offsetInMilliseconds": 0,
"playerActivity": "IDLE"
}
},
{
"header": {
"namespace": "Alerts",
"name": "AlertsState"
},
"payload": {
"activeAlerts": [],
"allAlerts": []
}
},
{
"header": {
"namespace": "AudioFocusManager",
"name": "AudioFocusState"
},
"payload": {
"dialog": {
"component": "SpeechSynthesizer",
"idleTimeInMilliseconds": 0
}
}
}
]
}
After that the next log
[21:11:36:703] - Directive: SkillDebugger.CaptureDebuggingInfo
It says
{
"header": {
"namespace": "SkillDebugger",
"name": "CaptureDebuggingInfo",
"messageId": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx38"
},
"payload": {
"skillId": null,
"timestamp": "2019-06-02T01:11:34.189Z",
"dialogRequestId": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx506",
"skillRequestId": null,
"type": "ConsideredIntents",
"content": {
"intents": [
{
"name": "<IntentForDifferentSkill>",
"confirmationStatus": null,
"slots": null
},
{
"name": "<IntentForDifferentSkill>",
"confirmationStatus": null,
"slots": null
},
{
"name": "<IntentForDifferentSkill>",
"confirmationStatus": null,
"slots": null
}
]
}
}
}
the next one [21:11:36:932] - Directive: SpeechSynthesizer.Speak:
{
"header": {
"namespace": "SpeechSynthesizer",
"name": "Speak",
"messageId": "xxxxxxxxxxxxxxxxxxxxxxxxxxx",
"dialogRequestId": "xxxxxxxxxxxxxxxxxxxxxxxxxxx506",
"keys": {
"isBlocking": true,
"channel": "audio"
}
},
"payload": {
"caption": "Hmm, I don't know that.",
"url": "https://tinytts.amazon.com/path to file here/resource.mp3",
"format": "AUDIO_MPEG",
"token": "amzn1.as-ct.v1.Domain:Global:Fallback#ACRI#DeviceTTSRendererV4_xxxxxxxxx5c",
"ssml": "<speak><prosody volume=\"x-loud\">Hmm, I don&apos;t know that.</prosody><metadata><promptMetadata><promptId>NotUnderstood</promptId><namespace>SmartDJ.MusicQA</namespace><locale>en_US</locale><overrideId>default</overrideId><variant>2017_Variant 5</variant><condition/><weight>1</weight><stageVersion>Adm-xxxxxxxxxxxxxx</stageVersion></promptMetadata></metadata></speak>"
}
}
and a couple of more of these logs and that's it, that's what I found.
Expected result:
Alexa, ask Mighty Righty who is right, me or my wife?
your wife
(or another random response from Player_BIOGRAPHY "me or my wife")
Actual result:
Alexa, open Mighty Righty.
Hi, you can say ......
Who is right, me or my wife?
your wife
(or another random response from Player_BIOGRAPHY "me or my wife")
As you can see, the way to get to the response is much longer (depending on Mighty Righty's welcome response)
Please, help! (I am not a coder, I just followed a tutorial)
This error message of "Hmm, I don't know that" is delivered when Alexa cannot understand the input outside of a skill, and so does not recognize what you are asking or what skill to use. So it shouldn't be an error with the slots or intents.
When Alexa captures voice input, it does not insert any punctuation, and the punctuation such as commas seem to break Alexa's ability to understand the input.
So when using the Alexa Console test chat, do not write any punctuation into the text input.
And when testing with voice, pronounce your input clearly and double check your logs to view how Alexa interpretted the voice. The more you use your skill, the better Alexa should learn to capture the key words correctly.

Error code: InvalidIntentSamplePhraseSlot -

I got the error code Error code: InvalidIntentSamplePhraseSlot when I built the model using the new skills console.
The full error message is
Sample utterance "AddBookmarkIntent i am at {pageno} of {mybook}" in intent "AddBookmarkIntent" cannot include both a phrase slot and another intent slot. Error code: InvalidIntentSamplePhraseSlot -
where {pageno} is AMAZON.NUMBER and {mybook} is AMAZON.SearchQuery
What is the error about and how can I solve it?
edit: add the JSON for the intent
{
"name": "AddBookmarkIntent",
"slots": [
{
"name": "mybook",
"type": "AMAZON.SearchQuery"
},
{
"name": "pageno",
"type": "AMAZON.NUMBER"
}
],
"samples": [
"i am at {pageno} of the book {mybook}",
"save page {pageno} to the book {mybook}",
"save page {pageno} to {mybook}",
"i am at {pageno} of {mybook}"
]
}
It's not allowed to have a slot of the type AMAZON.SearchQuery in the same Utterance with another slot, in your case AMAZON.NUMBER.
Mark one of the slots as required and ask for them separately.
A little example:
Create the Intent put in the utterances and slots:
"intents": [
{
"name": "AddBookmarkIntent",
"samples": [
"I am at {pageno}"
],
"slots": [
{
"name": "mybook",
"type": "AMAZON.SearchQuery",
"samples": [
"For {mybook}"
]
},
{
"name": "pageno",
"type": "AMAZON.NUMBER"
}
]
}
Mark the specific slot as required so Alexa will automatically ask for it:
"dialog": {
"intents": [
{
"name": "AddBookmarkIntent",
"confirmationRequired": false,
"prompts": {},
"slots": [
{
"name": "mybook",
"type": "AMAZON.SearchQuery",
"elicitationRequired": true,
"confirmationRequired": false,
"prompts": {
"elicitation": "Elicit.Intent-AddBookmarkIntent.IntentSlot-mybook"
}
}
]
}
]
}
and create the prompts to ask for the slot:
"prompts": [
{
"id": "Elicit.Intent-AddBookmarkIntent.IntentSlot-mybook",
"variations": [
{
"type": "PlainText",
"value": "For which book you like to save the page?"
}
]
}
]
This is probably much easier with the skill builder BETA and not its editor because it will automatically create the JSON in the background.
The error is telling you that you have an Intent name in your Sample Utterance where it should only have Slots and it looks like you do.
"AddBookmarkIntent i am at {pageno} of {mybook}"
"AddBookmarkIntent" shouldn't actually be inside of the utterance. So turn your utterance into:
"i am at {pageno} of {mybook}"
I know that some of the documents show an example of the sample utterances with the Intent Name first, such as here. But that has a big warning near the top:
So you have to be careful about which documents you read and follow based on which way you are building your Alexa Skill.
Follow this if you are using the Skill Builder.
It unfortunately seems like an utterance can only reference 1 "Phrase" slot type.
For your specific case, it does look like there is now a non-phrase slot type AMAZON.Book in public beta; if you use that instead of AMAZON.SearchQuery it might work?
Src: https://developer.amazon.com/en-US/docs/alexa/custom-skills/slot-type-reference.html

Resources