Use Of Session Attributes In A Custom Alexa Skill

Introduction

 
This article is about session attributes in an Alexa skill. I am going to demonstrate how to use a session attribute in a custom Alexa skill on an Alexa Hosted node.js server. For that I will be creating a custom Alexa skill named session time. With the help of this skill, once a user invokes Alexa, Alexa will be making a request to ask users for their respective names. Once a user tells his/her name, Alexa can store that name in a session attribute variable. Next time if a user makes a request asking Alexa about his/her name, then because the user’s name was stored in a session attribute, Alexa fetches that username from session attribute and responds by telling users their respective names.
 
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 login into the Alexa developer console, we need to mention the unique skill name and select the default language according to our location.
 
 
 
After that we can choose a model to add to our skill. To create a custom skill, we can select custom model.
 
 
 
We can also choose a method or a template to host the skill’s backend code inside a lambda function.
 
 
 
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.
 
The 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 skill has been created, we need to make adjustments to skill’s frontend. Now I will be creating intents and sample utterances 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.
 
 
 
Now we have to create intents.
 
MyNameIsIntent
 
 
 
SayNameIntent
 
 
Here I have added two intents. MyNameIsIntent along with some sample utterances such as {name}, {name} is my name, My name is {name} where {name} is a slot.
 
SayNameIntent along with some sample utterances such as what is my name, say my name.
 
After creating a model for a particular skill, we can save and build the model by clicking on save model and build model button on the top.
 
 
A pre-defined slot type AMAZON.US_FIRST_NAME is also defined for slot name.
 
JSON code for above frontend is as follows,
  1. {  
  2.     "interactionModel": {  
  3.         "languageModel": {  
  4.             "invocationName""telling name",  
  5.             "intents": [  
  6.                 {  
  7.                     "name""AMAZON.NavigateHomeIntent",  
  8.                     "samples": []  
  9.                 },  
  10.                 {  
  11.                     "name""AMAZON.CancelIntent",  
  12.                     "samples": []  
  13.                 },  
  14.                 {  
  15.                     "name""AMAZON.HelpIntent",  
  16.                     "samples": []  
  17.                 },  
  18.                 {  
  19.                     "name""AMAZON.StopIntent",  
  20.                     "samples": []  
  21.                 },  
  22.                 {  
  23.                     "name""MyNameIsIntent",  
  24.                     "slots": [  
  25.                         {  
  26.                             "name""name",  
  27.                             "type""AMAZON.US_FIRST_NAME"  
  28.                         }  
  29.                     ],  
  30.                     "samples": [  
  31.                         "{name}",  
  32.                         "{name} is my name",  
  33.                         "my name is {name}",  
  34.                         "i am {name}",  
  35.                         "you can call me {name}"  
  36.                     ]  
  37.                 },  
  38.                 {  
  39.                     "name""SayNameIntent",  
  40.                     "slots": [],  
  41.                     "samples": [  
  42.                         "what's my name",  
  43.                         "say my name",  
  44.                         "tell me my name",  
  45.                         "what is my name"  
  46.                     ]  
  47.                 }  
  48.             ],  
  49.             "types": []  
  50.         }  
  51.     }  
  52. }  

Creating the backend resource for the Alexa skill

 
To create backend code inside 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 handlerInput.requestEnvelope.request.type === 'LaunchRequest';  
  6.   },  
  7.   handle(handlerInput) {  
  8.     const speechText = `Hello there. What's your name?`;  
  9.     const repromptText = 'Can you tell me your name?';  
  10.   
  11.     return handlerInput.responseBuilder  
  12.       .speak(speechText)  
  13.       .reprompt(repromptText)  
  14.       .getResponse();  
  15.   },  
  16. };  
  17.   
  18. const MyNameIsIntentHandler = {  
  19.   canHandle(handlerInput) {  
  20.     return handlerInput.requestEnvelope.request.type === 'IntentRequest'  
  21.       && handlerInput.requestEnvelope.request.intent.name === 'MyNameIsIntent';  
  22.   },  
  23.   async handle(handlerInput) {  
  24.   
  25.     const nameValue = handlerInput.requestEnvelope.request.intent.slots.name.value;  
  26.     let speechText = `Hello ${nameValue}. I saved your name as a session attribute. Ask me your name to make sure I have it.`;  
  27.   
  28.     const attributesManager = handlerInput.attributesManager;  
  29.     const responseBuilder = handlerInput.responseBuilder;  
  30.   
  31.     const attributes = await attributesManager.getSessionAttributes() || {};  
  32.     attributes.nameValue = nameValue;  
  33.     attributesManager.setSessionAttributes(attributes);  
  34.       
  35.     return responseBuilder  
  36.       .speak(speechText)  
  37.       .reprompt(`Ask me your name.`)  
  38.       .getResponse();  
  39.   },  
  40. };  
  41.   
  42. const SayNameIntentHandler = {  
  43.   canHandle(handlerInput) {  
  44.     return handlerInput.requestEnvelope.request.type === 'IntentRequest'  
  45.       && handlerInput.requestEnvelope.request.intent.name === 'SayNameIntent';  
  46.   },  
  47.   async handle(handlerInput) {  
  48.   
  49.     const attributesManager = handlerInput.attributesManager;  
  50.     const attributes = await attributesManager.getSessionAttributes() || {};  
  51.   
  52.     const nameValue = attributes.nameValue;  
  53.     let speechText = `Your name is ${nameValue}.`;  
  54.       
  55.     const responseBuilder = handlerInput.responseBuilder;  
  56.   
  57.     return responseBuilder  
  58.       .speak(speechText)  
  59.       .getResponse();  
  60.   },  
  61. };  
  62.   
  63. const HelpIntentHandler = {  
  64.   canHandle(handlerInput) {  
  65.     return handlerInput.requestEnvelope.request.type === 'IntentRequest'  
  66.       && handlerInput.requestEnvelope.request.intent.name === 'AMAZON.HelpIntent';  
  67.   },  
  68.   handle(handlerInput) {  
  69.     const speechText = 'You can me your name';  
  70.   
  71.     return handlerInput.responseBuilder  
  72.       .speak(speechText)  
  73.       .reprompt(speechText)  
  74.       .getResponse();  
  75.   },  
  76. };  
  77.   
  78. const CancelAndStopIntentHandler = {  
  79.   canHandle(handlerInput) {  
  80.     return handlerInput.requestEnvelope.request.type === 'IntentRequest'  
  81.       && (handlerInput.requestEnvelope.request.intent.name === 'AMAZON.CancelIntent'  
  82.         || handlerInput.requestEnvelope.request.intent.name === 'AMAZON.StopIntent');  
  83.   },  
  84.   handle(handlerInput) {  
  85.     const speechText = 'Goodbye!';  
  86.   
  87.     return handlerInput.responseBuilder  
  88.       .speak(speechText)  
  89.       .getResponse();  
  90.   },  
  91. };  
  92.   
  93. const SessionEndedRequestHandler = {  
  94.   canHandle(handlerInput) {  
  95.     return handlerInput.requestEnvelope.request.type === 'SessionEndedRequest';  
  96.   },  
  97.   handle(handlerInput) {  
  98.     console.log(`Session ended with reason: ${handlerInput.requestEnvelope.request.reason}`);  
  99.   
  100.     return handlerInput.responseBuilder.getResponse();  
  101.   },  
  102. };  
  103.   
  104. const ErrorHandler = {  
  105.   canHandle() {  
  106.     return true;  
  107.   },  
  108.   handle(handlerInput, error) {  
  109.     console.log(`Error handled: ${error.message}`);  
  110.   
  111.     return handlerInput.responseBuilder  
  112.       .speak('Sorry, I can\'t understand the command. Please say again.')  
  113.       .reprompt('Sorry, I can\'t understand the command. Please say again.')  
  114.       .getResponse();  
  115.   },  
  116. };  
  117.   
  118. const skillBuilder = Alexa.SkillBuilders.custom();  
  119.   
  120. exports.handler = skillBuilder  
  121.   .addRequestHandlers(  
  122.     LaunchRequestHandler,  
  123.     MyNameIsIntentHandler,  
  124.     SayNameIntentHandler,  
  125.     HelpIntentHandler,  
  126.     CancelAndStopIntentHandler,  
  127.     SessionEndedRequestHandler  
  128.   )  
  129.   .addErrorHandlers(ErrorHandler)  
  130.   .lambda();  
To receive a request from the user, request handlers are created for each intent to handle. Inside each handlers, 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, LaunchRequestHandler has been created. The canHandle() function inside LaunchRequestHandler contains LaunchRequest. The user can launch or invoke Alexa by saying open followed by Invocation name which in this case is telling name, which is a LaunchRequest. Alexa can also be invoked by saying “Alexa ask followed by invocation name and a sample utterance”. Therefore, the canHandle() function within the GetRemoteDataHandler will let the SDK know it can fulfill the request. In computer terms, the canHandle returns true to confirm it can do the work.
 
With the help of handle() function inside LaunchRequestHandler, Alexa will be making a request to greet user and then asking user to tell Alexa his/her first name.
 
Inside MyNameIsIntentHandler, request of type IntentRequest is defined. Once the user tells his/her first name, the handle function inside MyNameIsIntentHandler allows Alexa to prompt that the skill has stored the user’s first name in a session attribute and tells user to ask Alexa about his/her first name.
 
Inside SayNameIntentHandler, request of type IntentRequest is defined. The handle function inside SayyNameIntentHandler allows Alexa to prompt and tell user about his/her first name.
 
Output
 
 
As we can see from the output the skill has been invoked by saying “telling name” invocation name. Once a user invokes Alexa, Alexa will be making a request to ask users for their respective names. Once a user tells his/her name, Alexa can store that name in a session attribute variable. Next time if a user makes a request asking Alexa about his/her name, then as user’s name was stored in a session attribute, Alexa fetches username from session attribute and responds by telling users their respective names.
 

Summary

 
In this article, I created a custom Alexa skill demonstrating the use of session attributes. I also defined invocation name, intents and sample utterances. Proper coding snippets along with output for backend of skill was also provided.