Slot Values Comparison Using Comparison Operators In Alexa Skill

Introduction

 
In this article on custom Alexa skills, I am going to create a custom Alexa skill on an Alexa-hosted node.js server. The custom Alexa skill will consist of different intent slots. The intent slot will have custom slot types with various values defined inside the slot type. Alexa will be taking inputs from users and using these slot values, and compare user inputs with the values defined inside custom slot type.
 
Depending on user’s input and Alexa’s comparison, different statements will be executed. The backend code required for the Alexa skill to work will be stored in a lambda function inside the Amazon developer console.
 

Creating Alexa Skills

 
To create a new skill, first we need to log in into the Alexa developer console, mention the unique skill name and select the default language according to our location.
 
Slot Values Comparison Using Comparison Operators In Alexa Skill 
 
After that we can choose a model to add to our skill. To create a custom skill, we can select custom model.
 
Slot Values Comparison Using Comparison Operators In Alexa Skill
 
We can also choose a method or a template to host the skill’s backend code inside a lambda function.
 
Slot Values Comparison Using Comparison Operators In Alexa Skill
 
We can choose Alexa hosted node.js or Python template. We can also mention our own endpoint or server to store backend resources for the required Alexa skills.
 
Next step is to choose a template to add to our skill, which we customize later according to our need and click on create skill button. Now as the skill has been created, we need to make adjustments to the skill’s frontend. Now I will be creating intents, slots and custom slot types to create skill’s frontend.
 
First we need to mention the invocation name. Users say a skill's invocation name to begin an interaction with a particular custom skill.
 
Slot Values Comparison Using Comparison Operators In Alexa Skill
 
Now we have to create intents
 
Slot Values Comparison Using Comparison Operators In Alexa Skill
 
Here I have added a new intent named GetNameOfPlant along with a sample utterance {plant}. Inside the utterance plant is a slot defined for the skill. Slots are defined within curly brackets.
 
Slots and slot type of each slot is defined as follows,
 
Slot Values Comparison Using Comparison Operators In Alexa Skill
 
Here plant is a slot created for intent named GetNameOfPlant.
 
The slot type of plant slot is a custom slot type. Custom slot type can also be created by clicking on Add Slot Type button under slot types menu.
 
Slot Values Comparison Using Comparison Operators In Alexa Skill
 
To create a custom slot type, type the name of the custom slot, and also fill in the required slot values along with Id and synonyms.
 

Defining Dialogs

 
We can also create dialogs such as Alexa speech prompts and user utterances for each and every slot being created. When the slot required to fulfil the intent is not mentioned in the sample utterance of a user then dialogs are created to ask the user to mention the slot values to fulfil the intent.
 
Here Alexa speech prompt is whatever Alexa will say to prompt the user to fill a particular slot, and user utterances are whatever a user might say in response to Alexa prompts.
 
To create a dialog under each slot
  • Enable option “is this slot required to fulfil the intent”.
  • Type Alexa speech prompts and user utterances accordingly. 
The json code for alexa frontend is as follows,
  1. {  
  2.     "interactionModel": {  
  3.         "languageModel": {  
  4.             "invocationName""hydro plant",  
  5.             "intents": [  
  6.                 {  
  7.                     "name""AMAZON.CancelIntent",  
  8.                     "samples": []  
  9.                 },  
  10.                 {  
  11.                     "name""AMAZON.HelpIntent",  
  12.                     "samples": []  
  13.                 },  
  14.                 {  
  15.                     "name""AMAZON.StopIntent",  
  16.                     "samples": []  
  17.                 },  
  18.                 {  
  19.                     "name""AMAZON.NavigateHomeIntent",  
  20.                     "samples": []  
  21.                 },  
  22.                 {  
  23.                     "name""GetNameOfPlant",  
  24.                     "slots": [  
  25.                         {  
  26.                             "name""plant",  
  27.                             "type""PLANTS"  
  28.                         }  
  29.                     ],  
  30.                     "samples": [  
  31.                         "{plant}"  
  32.                     ]  
  33.                 },  
  34.                                
  35.             ],  
  36.             "types": [  
  37.                 {  
  38.                     "name""PLANTS",  
  39.                     "values": [  
  40.                         {  
  41.                             "name": {  
  42.                                 "value""delran"  
  43.                             }  
  44.                         },  
  45.                         {  
  46.                             "name": {  
  47.                                 "value""parkville"  
  48.                             }  
  49.                         }  
  50.                     ]  
  51.                 }  
  52.             ]  
  53.         }  
  54.     }  
  55. }  
After creating a model for a particular skill, we can save and build the model by clicking on save model and building model button on the top.

 
Creating the backend resource for the Alexa skill

 
To create backend code inside the lambda function, we can write code inside index.js node.js file. The code for the custom Alexa skill is as follows,
  1. const Alexa = require('ask-sdk-core');  
  2.   
  3. const LaunchRequestHandler = {  
  4.     canHandle(handlerInput) {  
  5.         return Alexa.getRequestType(handlerInput.requestEnvelope) === 'LaunchRequest';  
  6.     },  
  7.     handle(handlerInput) {  
  8.           
  9.         const speakOutput = "Welcome to the Hydro Plant. Would you like to learn about plant name?"+  
  10.         "You could just say, name of a plant such as “Parkville” or “Delran”.";  
  11.         return handlerInput.responseBuilder  
  12.             .speak(speakOutput)  
  13.               
  14.             .reprompt()  
  15.             .getResponse();  
  16.     }  
  17. };  
  18.   
  19. const GetNameOfPlantHandler = {  
  20.     canHandle(handlerInput) {  
  21.         return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'  
  22.             && Alexa.getIntentName(handlerInput.requestEnvelope) === 'GetNameOfPlant';  
  23.     },  
  24.     handle(handlerInput) {  
  25.        let speakOutput='';  
  26.        let slot = handlerInput.requestEnvelope.request.intent.slots.plant.value;  
  27.   
  28.      if (slot === 'parkville') {  
  29.             speakOutput += "Welcome to the Parkville plant located in Parkville, Missouri."  
  30.         + " The Parkville water plant has five million gallons per day capacity and serves six thousand customers in the state.";  
  31.         }   
  32.         else if(slot === 'delran'){  
  33.               speakOutput += "Welcome to the Delran plant located in Delran, New Jersey."  
  34.         + " The Delran water plant has three million gallons per day capacity and serves two thousand customers in the state.";  
  35.         }  
  36.  return handlerInput.responseBuilder  
  37.             .speak(speakOutput)  
  38.             .reprompt(speakOutput)  
  39.             .getResponse();  
  40.     }  
  41. };  
  42.   
  43. const HelpIntentHandler = {  
  44.     canHandle(handlerInput) {  
  45.         return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'  
  46.             && Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.HelpIntent';  
  47.     },  
  48.     handle(handlerInput) {  
  49.         const speakOutput = 'You can say hello to me! How can I help?';  
  50.   
  51.         return handlerInput.responseBuilder  
  52.             .speak(speakOutput)  
  53.             .reprompt(speakOutput)  
  54.             .getResponse();  
  55.     }  
  56. };  
  57. const CancelAndStopIntentHandler = {  
  58.     canHandle(handlerInput) {  
  59.         return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'  
  60.             && (Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.CancelIntent'  
  61.                 || Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.StopIntent');  
  62.     },  
  63.     handle(handlerInput) {  
  64.         const speakOutput = 'Goodbye!';  
  65.         return handlerInput.responseBuilder  
  66.             .speak(speakOutput)  
  67.             .getResponse();  
  68.     }  
  69. };  
  70. const SessionEndedRequestHandler = {  
  71.     canHandle(handlerInput) {  
  72.         return Alexa.getRequestType(handlerInput.requestEnvelope) === 'SessionEndedRequest';  
  73.     },  
  74.     handle(handlerInput) {  
  75.         // Any cleanup logic goes here.  
  76.         return handlerInput.responseBuilder.getResponse();  
  77.     }  
  78. };  
  79.   
  80. // The intent reflector is used for interaction model testing and debugging.  
  81. // It will simply repeat the intent the user said. You can create custom handlers  
  82. // for your intents by defining them above, then also adding them to the request  
  83. // handler chain below.  
  84. const IntentReflectorHandler = {  
  85.     canHandle(handlerInput) {  
  86.         return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest';  
  87.     },  
  88.     handle(handlerInput) {  
  89.         const intentName = Alexa.getIntentName(handlerInput.requestEnvelope);  
  90.         const speakOutput = `You just triggered ${intentName}`;  
  91.   
  92.         return handlerInput.responseBuilder  
  93.             .speak(speakOutput)  
  94.             //.reprompt('add a reprompt if you want to keep the session open for the user to respond')  
  95.             .getResponse();  
  96.     }  
  97. };  
  98.   
  99. // Generic error handling to capture any syntax or routing errors. If you receive an error  
  100. // stating the request handler chain is not found, you have not implemented a handler for  
  101. // the intent being invoked or included it in the skill builder below.  
  102. const ErrorHandler = {  
  103.     canHandle() {  
  104.         return true;  
  105.     },  
  106.     handle(handlerInput, error) {  
  107.         console.log(`~~~~ Error handled: ${error.stack}`);  
  108.         const speakOutput = `Sorry, I had trouble doing what you asked. Please try again.`;  
  109.   
  110.         return handlerInput.responseBuilder  
  111.             .speak(speakOutput)  
  112.             .reprompt(speakOutput)  
  113.             .getResponse();  
  114.     }  
  115. };  
  116.   
  117. // The SkillBuilder acts as the entry point for your skill, routing all request and response  
  118. // payloads to the handlers above. Make sure any new handlers or interceptors you've  
  119. // defined are included below. The order matters - they're processed top to bottom.  
  120. exports.handler = Alexa.SkillBuilders.custom()  
  121.     .addRequestHandlers(  
  122.         LaunchRequestHandler,  
  123.         GetNameOfPlantHandler,  
  124.         HelpIntentHandler,  
  125.         CancelAndStopIntentHandler,  
  126.         SessionEndedRequestHandler,  
  127.         IntentReflectorHandler, // make sure IntentReflectorHandler is last so it doesn't override your custom intent handlers  
  128.     )  
  129.     .addErrorHandlers(  
  130.         ErrorHandler,  
  131.     )  
  132.     .lambda();  
To receive a request from the user, request handlers are created for each intent to handle. Inside each handler, canHandle and handle functions are defined.
 
The canHandle() function is where you define what requests the handler responds to. The handle() function returns a response to the user. If your skill receives a request, the canHandle() function within each handler determines whether or not that handler can service the request.
 
In this case, the user wants to launch the skill, which is a LaunchRequest. Therefore, the canHandle() function within the LaunchRequestHandler will let the SDK know it can fulfill the request. In computer terms, the canHandle returns true to confirm it can do the work.
 
The LaunchRequestHandler will greet the user by "Welcome to Hydro Plant Platform. Would you like to learn about the plant name? You could just say, name of a plant such as “Parkville” or “Delran”."
 
After that GetNameOfPlantHandler is defined to handle each and every user’s reservation request. This handler will receive input plant as requested slot parameter and give a response accordingly. The code defined inside GetNameOfPlantHandler extracts slot values from the skill being created. These slot values are then compared with values inside if and else if statements using triple equals (===) comparison operators.
 
If slot values extracted from skill - that is values provided as input - from user matches the value defined inside if and else if statements then corresponding statements are executed.
 
Output
 
Slot Values Comparison Using Comparison Operators In Alexa Skill
 
As we can see from the output above, to invoke a skill, user can say open,  followed by the skill name. Once the skill is invoked, Alexa will greet the user by saying “Welcome to the Hydro Plant. Would you like to learn about plant name? You could just say the name of a plant such as “Parkville” or “Delran”.” and ask the user to provide a name of a hydro power plant.
 
As there are two values defined inside custom slot type, so we can check for both Parkville and Delran. As we can see from the output, when user provides a name of a hydro power plant, Alexa will provide information about both plants.
 

Summary

 
In this article, I created a custom Alexa skill. I also defined intents, slots and custom slot types for each slot. I demonstrated the method to create custom slot types and slot type values. I also demonstrated how we can use triple equals comparison operator to compare slot values against values defined inside if else statements. Proper coding snippets along with output for backend of skill was also provided.