Search code examples
alexa-skills-kit

Custom intent handler is not triggering and instead an alexa default intent is being called


so I have written a handler for an intent where the user asks Alexa to recommend a service i.e. "Alexa could you recommend a plumber". The problem is that Alexa comes in an triggers its default recommendation action.

The conversation is as follows:

User: Alexa open Bucharest insight

Alexa: Hi, welcome to Bucharest Insight, how are you? you can ask me questions about the local news or ask me for a recommendation.

User: I need a plumber

Alexa: Here are a few top-rated ones

I was expecting my getRecommendationIntentHandler to be triggered as I have setup the intent correctly ( See the below JSON) - "I need a {serviceName}",

The result from Alexa seems like a build in response instead of my custom intent handler below:

const getRecommendationIntentHandler = {


canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'IntentRequest'
      && handlerInput.requestEnvelope.request.intent.name === 'getRecommendationIntent';
  },
  handle(handlerInput) {
    console.log('Called getRecommendationIntentHandler');

    const responseBuilder = handlerInput.responseBuilder;
    const filledSlots = handlerInput.requestEnvelope.request.intent.slots;

    // Get the filled slots inputted by the user
    const slotValues = getSlotValues(filledSlots);

    console.log(JSON.stringify(slotValues));

    const speechText = 'getRecommendationIntentHandler called';
    return responseBuilder
      .speak(speechText)
      .getResponse();
  },
};

I have attached my JSON from Alexa Skills Kit below)

{
"interactionModel": {
    "languageModel": {
        "invocationName": "bucharest insight",
        "intents": [
            {
                "name": "AMAZON.CancelIntent",
                "samples": []
            },
            {
                "name": "AMAZON.HelpIntent",
                "samples": []
            },
            {
                "name": "AMAZON.StopIntent",
                "samples": []
            },
            {
                "name": "NewsIntent",
                "slots": [],
                "samples": [
                    "What's the latest news",
                    "Tell me the news",
                    "Can you tell me the news please",
                    "I want the news",
                    "Play the news"
                ]
            },
            {
                "name": "getRecommendationIntent",
                "slots": [
                    {
                        "name": "serviceName",
                        "type": "AMAZON.ProfessionalType",
                        "samples": [
                            "Do you have {serviceName}",
                            "I would like to get a {serviceName}",
                            "An {serviceName}",
                            "A {serviceName}",
                            "{serviceName}",
                            "I would like a {serviceName}"
                        ]
                    }
                ],
                "samples": [
                    "Have you got any plumbers",
                    "Do you know a good {serviceName}",
                    "Do you know of a good {serviceName}",
                    "Can you recommend me a {serviceName} please",
                    "I want a {serviceName} do you know anyone",
                    "Have you got any good {serviceName}",
                    "Can you find me a {serviceName}",
                    "I need a {serviceName}",
                    "Can you find me a good {serviceName}",
                    "Do you know of any good {serviceName}",
                    "Can you recommend me a {serviceName}"
                ]
            },
            {
                "name": "AMAZON.PauseIntent",
                "samples": []
            },
            {
                "name": "AMAZON.ResumeIntent",
                "samples": []
            }
        ],
        "types": [
            {
                "name": "AMAZON.ProfessionalType",
                "values": [
                    {
                        "name": {
                            "value": "fashion designer",
                            "synonyms": [
                                "Fashion",
                                "clothes designer"
                            ]
                        }
                    },
                    {
                        "name": {
                            "value": "Interior designer",
                            "synonyms": [
                                "Home designer"
                            ]
                        }
                    },
                    {
                        "name": {
                            "value": "Painter",
                            "synonyms": [
                                "Painting"
                            ]
                        }
                    },
                    {
                        "name": {
                            "value": "Electrician",
                            "synonyms": [
                                "Electric man"
                            ]
                        }
                    },
                    {
                        "name": {
                            "value": "Plumber",
                            "synonyms": [
                                "plumber",
                                "Water man"
                            ]
                        }
                    }
                ]
            }
        ]
    },
    "dialog": {
        "intents": [
            {
                "name": "getRecommendationIntent",
                "confirmationRequired": true,
                "prompts": {
                    "confirmation": "Confirm.Intent.508140955512"
                },
                "slots": [
                    {
                        "name": "serviceName",
                        "type": "AMAZON.ProfessionalType",
                        "confirmationRequired": true,
                        "elicitationRequired": true,
                        "prompts": {
                            "confirmation": "Confirm.Slot.508140955512.325067758753",
                            "elicitation": "Elicit.Slot.508140955512.325067758753"
                        }
                    }
                ]
            }
        ]
    },
    "prompts": [
        {
            "id": "Elicit.Slot.508140955512.325067758753",
            "variations": [
                {
                    "type": "PlainText",
                    "value": "What service do you want?"
                },
                {
                    "type": "PlainText",
                    "value": "Can you tell me what you're looking for ?"
                },
                {
                    "type": "PlainText",
                    "value": "What's the serivice you are looking for?"
                }
            ]
        },
        {
            "id": "Confirm.Slot.508140955512.325067758753",
            "variations": [
                {
                    "type": "PlainText",
                    "value": "So you want to find a {serviceName} , correct?"
                }
            ]
        },
        {
            "id": "Confirm.Intent.508140955512",
            "variations": [
                {
                    "type": "PlainText",
                    "value": "So you want me to find a {serviceName} , is that correct?"
                },
                {
                    "type": "PlainText",
                    "value": "So you want me to recommend you a {serviceName} , am I right ?"
                }
            ]
        }
    ]
    }
}

Any help would be much appreciated and I am open to further questions about this.

-- New comment 06/09/2018 - This is the JSON created by Alexa:

JSON Input:

{
    "version": "1.0",
    "session": {
        "new": true,
        "sessionId": "amzn1.echo-api.session.5688bb9b-0f5c-4616-9c8d-46d2218a167b",
        "application": {
            "applicationId": "amzn1.ask.skill.180e6d66-06c5-412c-8fe0-90f2fcc31a3a"
        },
        "user": {
            "userId": "amzn1.ask.account.AEHB6UB7SDQU6TCKZOEADQ2ICGLSXETSXC6LOJSRXWAPGWLBBXQIKKH2GTFRLO6NIKLCXIRJBQLXAT45OCKP4UHMPSCM33M5ZE4M4EE5MARUBLF7BNTL6WWAIWKOL3WMYCWT7SCOKQHROFD3VEJTPN3JFCLWQ46ZRY6UGSENVLPFIHPQGQZNV3T6UQ4TEXGFNMHX6PCLTHZUS5I"
        }
    },
    "context": {
        "AudioPlayer": {
            "playerActivity": "IDLE"
        },
        "System": {
            "application": {
                "applicationId": "amzn1.ask.skill.180e6d66-06c5-412c-8fe0-90f2fcc31a3a"
            },
            "user": {
                "userId": "amzn1.ask.account.AEHB6UB7SDQU6TCKZOEADQ2ICGLSXETSXC6LOJSRXWAPGWLBBXQIKKH2GTFRLO6NIKLCXIRJBQLXAT45OCKP4UHMPSCM33M5ZE4M4EE5MARUBLF7BNTL6WWAIWKOL3WMYCWT7SCOKQHROFD3VEJTPN3JFCLWQ46ZRY6UGSENVLPFIHPQGQZNV3T6UQ4TEXGFNMHX6PCLTHZUS5I"
            },
            "device": {
                "deviceId": "amzn1.ask.device.AFYZEJWCDICBPMGAGXM2TNFW4MMZCWWGVFATSXL6ARKMXBENBTS5U2M2PAQJRTBQB2OR2X5HHCM4A7CWIWNOCFIP4LF2LXH6F5OND5425SXYUONA6NTJ67LM2Z27OOAAJ4WXW4COPWZXNP7KMK2YIHDOMUSQ",
                "supportedInterfaces": {
                    "AudioPlayer": {}
                }
            },
            "apiEndpoint": "https://api.eu.amazonalexa.com",
            "apiAccessToken": "Redacted by me"
        }
    },
    "request": {
        "type": "LaunchRequest",
        "requestId": "amzn1.echo-api.request.c17bb90f-8c8d-4b4c-ab1f-0462ab5f2c05",
        "timestamp": "2018-09-06T06:29:14Z",
        "locale": "en-US",
        "shouldLinkResultBeReturned": false
    }
}

JSON Output

{
    "body": {
        "version": "1.0",
        "response": {
            "outputSpeech": {
                "type": "SSML",
                "ssml": "<speak>Hi, welcome to Bucharest Insight, how are you ? you can ask me questions about the local news or ask me for a recommendation</speak>"
            }
        },
        "sessionAttributes": {},
        "userAgent": "ask-node/2.0.5 Node/v8.10.0"
    }
}

Event.TextMessage

{
    "event": {
        "header": {
            "namespace": "Text",
            "name": "TextMessage",
            "messageId": "messageId",
            "dialogRequestId": "6ecb05d5-905f-4c9f-aae0-bbeb028062db"
        },
        "payload": {
            "textMessage": "i need a plumber"
        }
    },
    "context": [
        {
            "header": {
                "namespace": "SpeechSynthesizer",
                "name": "SpeechState"
            },
            "payload": {
                "token": "amzn1.as-ct.v1.ThirdPartySdkSpeechlet#ACRI#ValidatedSpeakDirective_amzn1.ask.skill.180e6d66-06c5-412c-8fe0-90f2fcc31a3a_0b040a2a-a5bc-4d43-9452-95c49c3cca1c",
                "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": "VisualFocusManager",
                "name": "VisualFocusState"
            },
            "payload": {
                "inFocus": {
                    "component": "ListRenderer",
                    "idleTimeInMilliseconds": 0
                }
            }
        },
        {
            "header": {
                "namespace": "AudioFocusManager",
                "name": "AudioFocusState"
            },
            "payload": {
                "alert": {
                    "component": null,
                    "idleTimeInMilliseconds": 0
                },
                "dialog": {
                    "component": "SpeechSynthesizer",
                    "idleTimeInMilliseconds": 1000
                },
                "content": {
                    "component": null,
                    "idleTimeInMilliseconds": 0
                }
            }
        },
        {
            "header": {
                "namespace": "ListRenderer",
                "name": "RenderedListState"
            },
            "payload": {
                "listToken": "amzn1.as-lt.v1.ThirdPartySdkSpeechlet#LRID#amzn1.ask.skill.180e6d66-06c5-412c-8fe0-90f2fcc31a3a::Latuc",
                "itemsVisibleOnScreen": [],
                "selectedItems": [],
                "focusedItem": {},
                "renderedItemDetail": {
                    "listItemIdentifier": "amzn1.as-lt.v1.ThirdPartySdkSpeechlet#LRID#amzn1.ask.skill.180e6d66-06c5-412c-8fe0-90f2fcc31a3a::Latuc",
                    "ordinalNumber": 1
                },
                "highestOrdinalSeen": 1,
                "lastItemOrdinal": 1
            }
        }
    ]
}

Directive: SpeechSynthesizer.Speak

    {
        "header": {
            "namespace": "SpeechSynthesizer",
            "name": "Speak",
            "messageId": "aa79a5f3-9293-4f49-9fda-22abeaedbe03",
            "dialogRequestId": "6ecb05d5-905f-4c9f-aae0-bbeb028062db"
        },
        "payload": {
            "caption": "Here are a few top-rated ones",
            "url": "https://kopytko-eu-west-1.amazon.com/3/72c80478-b19e-11e8-aeb5-15393a31d62e-9eedcf/5/1536301872334/10f6885702786ce70473a6560e8b09fdc9a5d548d7c5f6072eaf3a18c498fce1/resource.mp3",
            "format": "AUDIO_MPEG",
            "token": "amzn1.as-ct.v1.DOMAIN:POI#ACRI#DeeAppPOISpeechlet",
            "ssml": "<speak><prosody volume=\"x-loud\">Here are a few top-rated ones</prosody><metadata><promptMetadata><promptId>POICategory#Knight#MultipleResults</promptId><namespace>POI</namespace><locale>en_US</locale><overrideId>default</overrideId><variant>1</variant><condition/><weight>1</weight><stageVersion>Adm-20180810_234837-1</stageVersion></promptMetadata></metadata></speak>"
        }
    }

Directive.ListRenderer.RenderList

{
"header": {
    "namespace": "ListRenderer",
    "name": "RenderList",
    "messageId": "d79a03bb-b1cf-4722-a24a-a982f2b89da7",
    "dialogRequestId": "6ecb05d5-905f-4c9f-aae0-bbeb028062db"
},
"payload": {
    "name": "renderList",
    "namespace": "ListRenderer",
    "listToken": "amzn1.as-lt.v1.DOMAIN:POI#LRID#a1be83a5-35d9-41c9-94c1-066e7152fc45",
    "totalNumberOfItems": 4,
    "listPage": {
        "listItems": [

..... (Too long to display here)

Directive: ListRenderer.ReadListItems

{
    "header": {
        "namespace": "ListRenderer",
        "name": "ReadListItems",
        "messageId": "57b1df77-1175-42bd-99a1-86ded50e7525",
        "dialogRequestId": "6ecb05d5-905f-4c9f-aae0-bbeb028062db"
    },
    "payload": {
        "listToken": "amzn1.as-lt.v1.DOMAIN:POI#LRID#a1be83a5-35d9-41c9-94c1-066e7152fc45",
        "beginOrdinal": 1,
        "count": 4
    }
}

Directive: SpeechRecognizer.RequestProcessingCompleted

{
    "header": {
        "namespace": "SpeechRecognizer",
        "name": "RequestProcessingCompleted",
        "messageId": "59a2194d-f04f-43f4-9269-8bbe0c3c3809",
        "dialogRequestId": "6ecb05d5-905f-4c9f-aae0-bbeb028062db"
    },
    "payload": {}
}

Solution

  • Your first response does not have shouldEndSession parameter. If not provided, defaults to true. What that means is that, once your response is read, Alexa will end the session and closes the skill. You are no longer inside the skill. Whenever you want Alexa to wait for user response, keep the session alive by setting shouldEndSession parameter set to false.

    Your first response should be like this:

    {
        "body": {
            "version": "1.0",
            "response": {
                "outputSpeech": {
                    "type": "SSML",
                    "ssml": "<speak>Hi, welcome to Bucharest Insight, how are you ? you can ask me questions about the local news or ask me for a recommendation</speak>"
                },
               "shouldEndSession": false
            },
            "sessionAttributes": {},
            "userAgent": "ask-node/2.0.5 Node/v8.10.0"
        }
    }
    

    The good thing is that, you don't have to set this parameter manually and the SDK will take care of it. For that use a reprompt. Including a reprompt in your response is a good design.

     return responseBuilder
          .speak(speechText)
          .reprompt(repromptSpeechOutput)
          .getResponse();
    

    If you don't want to use a reprompt you can use withShouldEndSession(false).

    Read this answer for more.