I'm trying to add my own responses to custom intents. The LaunchRequest text works, but other than the AMAZON.HelpIntent and other default intents, my own do not get recognized.
Intents:
{
"interactionModel": {
"languageModel": {
"invocationName": "my personal heartbeat",
"intents": [
{
"name": "AMAZON.FallbackIntent",
"samples": []
},
{
"name": "AMAZON.CancelIntent",
"samples": []
},
{
"name": "AMAZON.HelpIntent",
"samples": []
},
{
"name": "AMAZON.StopIntent",
"samples": []
},
{
"name": "start",
"slots": [],
"samples": [
"Talk to my personal heartbeat"
]
},
{
"name": "currentbpm",
"slots": [],
"samples": [
"what's my current BPM",
"how fast is my heart beating right now",
"How many beats per minute is my heart making at the moment"
]
}
],
"types": []
}
}
}
index.js (adapted example from the nodejs tutorial found here: https://github.com/alexa/skill-sample-nodejs-fact/blob/en-US/lambda/custom/index.js I added the CurrentBPM function and added it to the addRequestHandlers at the bottom. The intent name it looks to match is the currentbpm intent in the list above.
/* eslint-disable func-names */
/* eslint-disable no-console */
const Alexa = require('ask-sdk');
const GetNewFactHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'LaunchRequest'
|| (request.type === 'IntentRequest'
&& request.intent.name === 'GetNewFactIntent');
},
handle(handlerInput) {
const speechOutput = "Welcome to your personal heart health monitor. What would you like to know?";
return handlerInput.responseBuilder
.speak(speechOutput)
.withSimpleCard(speechOutput)
.getResponse();
},
};
const CurrentBPMHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest'
&& request.intent.name === 'currentbpm';
},
handle(handlerInput) {
return handlerInput.responseBuilder
.speak('seventy five bpm')
.reprompt('seventy five bpm')
.getResponse();
},
};
const HelpHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest'
&& request.intent.name === 'AMAZON.HelpIntent';
},
handle(handlerInput) {
return handlerInput.responseBuilder
.speak(HELP_MESSAGE)
.reprompt(HELP_REPROMPT)
.getResponse();
},
};
const ExitHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest'
&& (request.intent.name === 'AMAZON.CancelIntent'
|| request.intent.name === 'AMAZON.StopIntent');
},
handle(handlerInput) {
return handlerInput.responseBuilder
.speak(STOP_MESSAGE)
.getResponse();
},
};
const SessionEndedRequestHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'SessionEndedRequest';
},
handle(handlerInput) {
console.log(`Session ended with reason: ${handlerInput.requestEnvelope.request.reason}`);
return handlerInput.responseBuilder.getResponse();
},
};
const ErrorHandler = {
canHandle() {
return true;
},
handle(handlerInput, error) {
console.log(`Error handled: ${error.message}`);
return handlerInput.responseBuilder
.speak('Sorry, an error occurred.')
.reprompt('Sorry, an error occurred.')
.getResponse();
},
};
const HELP_MESSAGE = 'You can say tell me a space fact, or, you can say exit... What can I help you with?';
const HELP_REPROMPT = 'What can I help you with?';
const STOP_MESSAGE = 'Goodbye!';
const skillBuilder = Alexa.SkillBuilders.standard();
exports.handler = skillBuilder
.addRequestHandlers(
GetNewFactHandler,
CurrentBPMHandler,
HelpHandler,
ExitHandler,
SessionEndedRequestHandler
)
.addErrorHandlers(ErrorHandler)
.lambda();
When I invoke the skill: 'Alexa start my personal heartbeat.' It does speak the welcome sentence from the script. But when I ask then 'how fast is my heart beating right now', it only responds 'Sorry, not sure' instead of speaking the hardcoded response.
Open the Alexa developer console, and then sign in. On the Skills tab, in the SKILL NAME column, click the name of your custom skill. From the left-hand sidebar, click Custom > Interaction Model > Intents. On the Intents page, click +Add Intent.
“Intent” describes the action that the skill is being asked to perform, such as PlayTune or ActivateAppliance. And “slot” describes the entities and classes of entities on which the action is to operate, such as “song,” “'Thriller,'” and “Michael Jackson” in the command “Play 'Thriller' by Michael Jackson.”
One simple way to debug this issue is copying the input JSON from Alexa skill simulator and paste it in the lambda's configure test events. Now run test and it'll generate all the error logs in the lambda itself, for your easy reference.
(transitive) To prompt again. The system reprompts the user at every logon.
The solution is to add a line to the response in the LaunchRequest:
.withShouldEndSession(false)
If you don't add it, the default is set to true, so the skill will end right after giving the first response (welcome intent). See the documentation:https://ask-sdk-for-nodejs.readthedocs.io/en/latest/Response-Building.html
Thanks to Suneet Patil I updated the script accordingly (see below) At first only this worked:
But I could not reach the intent:
With the new script below:
/* eslint-disable func-names */
/* eslint-disable no-console */
const Alexa = require('ask-sdk');
const GetNewFactHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'LaunchRequest'
|| (request.type === 'IntentRequest'
&& request.intent.name === 'start');
},
handle(handlerInput) {
const speechOutput = "Welcome to your personal heart health monitor. What would you like to know?";
return handlerInput.responseBuilder
.speak(speechOutput)
.withSimpleCard(speechOutput)
.withShouldEndSession(false)
.getResponse();
},
};
const CurrentBPMHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest'
&& request.intent.name === 'currentbpm';
},
handle(handlerInput) {
return handlerInput.responseBuilder
.speak('seventy five bpm')
.reprompt('seventy five bpm')
.getResponse();
},
};
const HelpHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest'
&& request.intent.name === 'AMAZON.HelpIntent';
},
handle(handlerInput) {
return handlerInput.responseBuilder
.speak(HELP_MESSAGE)
.reprompt(HELP_REPROMPT)
.getResponse();
},
};
const ExitHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'IntentRequest'
&& (request.intent.name === 'AMAZON.CancelIntent'
|| request.intent.name === 'AMAZON.StopIntent');
},
handle(handlerInput) {
return handlerInput.responseBuilder
.speak(STOP_MESSAGE)
.getResponse();
},
};
const SessionEndedRequestHandler = {
canHandle(handlerInput) {
const request = handlerInput.requestEnvelope.request;
return request.type === 'SessionEndedRequest';
},
handle(handlerInput) {
console.log(`Session ended with reason: ${handlerInput.requestEnvelope.request.reason}`);
return handlerInput.responseBuilder.getResponse();
},
};
const ErrorHandler = {
canHandle() {
return true;
},
handle(handlerInput, error) {
console.log(`Error handled: ${error.message}`);
return handlerInput.responseBuilder
.speak('Sorry, an error occurred.')
.reprompt('Sorry, an error occurred.')
.getResponse();
},
};
const HELP_MESSAGE = 'You can say tell me a space fact, or, you can say exit... What can I help you with?';
const HELP_REPROMPT = 'What can I help you with?';
const STOP_MESSAGE = 'Goodbye!';
const skillBuilder = Alexa.SkillBuilders.standard();
exports.handler = skillBuilder
.addRequestHandlers(
GetNewFactHandler,
CurrentBPMHandler,
HelpHandler,
ExitHandler,
SessionEndedRequestHandler
)
.addErrorHandlers(ErrorHandler)
.lambda();
This works now:
For any request, if not provided, shouldEndSession
defaults to true
. In your case, the response to LaunchRequest
will not have this shouldEndSession
parameter and the session closes.
Though you can always use ask-nodejs-sdk's shouldEndSession(false)
to keep-alive the session, you don't have to specifically set this to false every time. Instead, a better approach would be to use a reprompt
in your LaunchRequest
. And if you include a reprompt()
then, the sdk will automatically add "shouldEndSession": false
in your response.
With your code as it is right now, your LaunchRequest
will wait for 8 seconds and if there is no user response the session will close. But, for CurrentBPMHandler
or HelpHandler
you have included a reprompt and it will wait another additional 8 seconds after the reprompt
. It's always a good idea to include a reprompt when you expect a response from the user.
Your interaction model has an AMAZON.FallbackIntent
intent defined, but you haven't handled it in your code. The AMAZON.FallbackIntent
helps you handle unexpected utterances, or when a user says something that doesn’t map to any intents in your skill. If there is no handler, then it will be caught in your error handler. There is no issue to handle it as an error, but a better approach would be to add a handler specifically for this and give a response like "Sorry, I didn't understand, can you please rephrase your question" or something similar.
Please make these below changes it works. 1. In interaction model, for intent start just give same utterance as “to start” instead of current. Ex: Alexa, ask my personal heartbeat to start.
In your lambda code, in lambda code in getnewfact method you forgot to change the name of intent from getnewfactintent to start.
For invoking currentbpm intent, use “ Alexa, ask my personal heartbeat how fast is my heart beating right now.
Hope this helps.
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