Publishing An Alexa Skill

An Alexa Skill in Javascript – Part 6

We’ve done it!  We’ve built an Alexa skill!  Woohoo!  Now we need to publish our skill to the Alexa Skills Catalog and make it official.  Publishing your Alexa skill is the last step in the process of developing and deploying an Alexa Skill.

NOTE:  Pay attention to Amazon’s developer promotions.  You can get a free T-Shirt, Echo Dot, Echo Spot, and even the Echo Show if you publish your skill at the right time.

Prepping the skill.json File

There are a few things we can do to enhance the skill.json file so our skill is ready for publishing.

First, find two images that you can use to represent your skill.  These will appear in the catalog inside the speech bubble, like so:

The images should be png files in two sizes:  small (108 x 108 px) and large (512 x 512 px).  Create a new folder in your project called images and drop the two image files into it for safe-keeping.  We’ll add them to the distribution page later.

Next, we can add some keywords to our skill.json file to help people find our skill more easily, right after the description tag add a “keywords” tag:

                    "description": "Roll Some Dice will roll ...",
"keywords": [
"die", "dice", "rpg", "dice roller"
]
}
},

The last, and perhaps most difficult, task is to create the testing instructions.

Tip:  Test your own testing instructions.  Make sure Alexa actually does what you expect her to do.

Based on our intent’s sample phrases, the slots, the synonyms, and the edge conditions, we have quite a few testing instructions.  Here are those sample phrases we put in the en-US skill model file:

"samples": [
"roll a die {plusMinus} {modifier}",
"roll {diceCount} dice {plusMinus} {modifier}",
"roll {diceCount} dice",
"roll a die"
]

To test our intent, we need to test the following:

Basic Phrases:

1. Say “Alexa, start Roll Some Dice and roll a die.”  Alexa will generate a random number between 1 and 6 and say, for example, “You said roll 1 dice. I rolled a three.”
2. Say “Alexa, start Roll Some Dice and roll 10 dice.”  Alexa will generate 10 random numbers between 1 and 6 and report the results, for example, “You said roll 10 dice. I rolled 3 ones, 4 threes, a four, a five and a six.”

With a modifier:

1. Say “Alexa, start Roll Some Dice and roll a die plus one.”  Alexa will generate a random number between 1 and 6  and add 1, and say, for example, “You said roll 1 dice plus 1. I rolled a two.”
2. Say “Alexa, start Roll Some Dice and roll a die minus one.” Alexa will generate a random number between 1 and 6  and subtract 1, and say, for example, “You said roll 1 dice minus 1. I rolled a three.”

With a modifier using synonyms:

1. Say “Alexa, start Roll Some Dice and roll a die add one.”  Alexa will generate a random number between 1 and 6  and add 1, and say, for example, “You said roll 1 dice plus 1. I rolled a six.”
2. Say “Alexa, start Roll Some Dice and roll a die subtract one.” Alexa will generate a random number between 1 and 6  and subtract 1, and say, for example, “You said roll 1 dice minus 1. I rolled a three.”

With a modifier, testing the edge/limits we put in:

1. Say “Alexa, start Roll Some Dice and roll a die plus seven.”  Alexa will generate a random number between 1 and 6  and add 7, maxing out at 6, and say, for example, “You said roll 1 dice plus 7. I rolled a six.”
2. Say “Alexa, start Roll Some Dice and roll a die minus seven.” Alexa will generate a random number between 1 and 6  and subtract 7, with a minimum value of 0, and say, for example, “You said roll 1 dice minus 1. I rolled a zero.”

Testing missing slots and default values:

1. Say “Alexa, start Roll Some Dice and roll dice.”  Alexa will generate a random number between 1 and 6 and say, for example, “You said roll 1 dice. I rolled a three.”
2. Say “Alexa, start Roll some Dice and roll a die plus.”  Alexa will generate a random number between 1 and 6 and say, for example, “You said roll 1 dice. I rolled a three.”
3. Say “Alexa, start Roll some Dice and roll 1 die frog 3.”  Alexa will not understand and should respond, “Sorry, I can’t understand the command.”

Now we need to “stringify” those phrases and put them in our skill.json file here:

"isAvailableWorldwide": true,
"testingInstructions": "Sample Testing Instructions.",
"category": "GAME_INFO_AND_ACCESSORY",

The easiest way I’ve found to convert the text in the lists above into the correct format is in a text editor (like Notepad++) to replace the marks with \” and then MS Word to replace all paragraph marks (under Special…) with \n, and tab characters (also under Special…) with spaces.  When you’re done, the tests will look like this:

Basic Phrases:\n1. Say \"Alexa, start Roll Some Dice and roll a die.\"  Alexa will generate a random number between 1 and 6 and say, for example, \"You said roll 1 dice. I rolled a three.\"\n2. Say \"Alexa, start Roll Some Dice and roll 10 dice.\"  Alexa will generate 10 random numbers between 1 and 6 and report the results, for example, \"You said roll 10 dice. I rolled 3 ones, 4 threes, a four, a five and a six.\"\nWith a modifier:\n1. Say \"Alexa, start Roll Some Dice and roll a die plus one.\"  Alexa will generate a random number between 1 and 6 and add 1, and say, for example, \"You said roll 1 dice plus 1. I rolled a two.\"\n2. Say \"Alexa, start Roll Some Dice and roll a die minus one.\" Alexa will generate a random number between 1 and 6 and subtract 1, and say, for example, \"You said roll 1 dice minus 1. I rolled a three.\"\nWith a modifier using synonyms:\n1. Say \"Alexa, start Roll Some Dice and roll a die add one.\"  Alexa will generate a random number between 1 and 6 and add 1, and say, for example, \"You said roll 1 dice plus 1. I rolled a six.\"\n2. Say \"Alexa, start Roll Some Dice and roll a die subtract one.\" Alexa will generate a random number between 1 and 6 and subtract 1, and say, for example, \"You said roll 1 dice minus 1. I rolled a three.\"\nWith a modifier, testing the edge/limits we put in:\n1. Say \"Alexa, start Roll Some Dice and roll a die plus seven.\"  Alexa will generate a random number between 1 and 6 and add 7, maxing out at 6, and say, for example, \"You said roll 1 dice plus 7. I rolled a six.\"\n2. Say \"Alexa, start Roll Some Dice and roll a die minus seven.\" Alexa will generate a random number between 1 and 6 and subtract 7, with a minimum value of 0, and say, for example, \"You said roll 1 dice minus 1. I rolled a zero.\"\nTesting missing slots and default values:\n1. Say \"Alexa, start Roll Some Dice and roll dice.\"  Alexa will generate a random number between 1 and 6 and say, for example, \"You said roll 1 dice. I rolled a three.\"\n2. Say \"Alexa, start Roll some Dice and roll a die plus.\"  Alexa will generate a random number between 1 and 6 and say, for example, \"You said roll 1 dice. I rolled a three.\"\n3. Say \"Alexa, start Roll some Dice and roll 1 die frog 3.\"  Alexa will not understand and should respond, \"Sorry, I can't understand the command.\"\n

Now you can plug the new string in the place of Sample Testing Instructions.  Like so:

"isAvailableWorldwide": true,
"testingInstructions": "Basic Phrases:\n1. Say \"Alexa, start Roll Some Dice and roll a die.\"  Alexa will generate a random number between 1 and 6 and say, for example, \"You said roll 1 dice. I rolled a three.\"\n2. Say \"Alexa, start Roll Some Dice and roll 10 dice.\"  Alexa will generate 10 random numbers between 1 and 6 and report the results, for example, \"You said roll 10 dice. I rolled 3 ones, 4 threes, a four, a five and a six.\"\nWith a modifier:\n1. Say \"Alexa, start Roll Some Dice and roll a die plus one.\"  Alexa will generate a random number between 1 and 6 and add 1, and say, for example, \"You said roll 1 dice plus 1. I rolled a two.\"\n2. Say \"Alexa, start Roll Some Dice and roll a die minus one.\" Alexa will generate a random number between 1 and 6 and subtract 1, and say, for example, \"You said roll 1 dice minus 1. I rolled a three.\"\nWith a modifier using synonyms:\n1. Say \"Alexa, start Roll Some Dice and roll a die add one.\"  Alexa will generate a random number between 1 and 6 and add 1, and say, for example, \"You said roll 1 dice plus 1. I rolled a six.\"\n2. Say \"Alexa, start Roll Some Dice and roll a die subtract one.\" Alexa will generate a random number between 1 and 6 and subtract 1, and say, for example, \"You said roll 1 dice minus 1. I rolled a three.\"\nWith a modifier, testing the edge/limits we put in:\n1. Say \"Alexa, start Roll Some Dice and roll a die plus seven.\"  Alexa will generate a random number between 1 and 6 and add 7, maxing out at 6, and say, for example, \"You said roll 1 dice plus 7. I rolled a six.\"\n2. Say \"Alexa, start Roll Some Dice and roll a die minus seven.\" Alexa will generate a random number between 1 and 6 and subtract 7, with a minimum value of 0, and say, for example, \"You said roll 1 dice minus 1. I rolled a zero.\"\nTesting missing slots and default values:\n1. Say \"Alexa, start Roll Some Dice and roll dice.\"  Alexa will generate a random number between 1 and 6 and say, for example, \"You said roll 1 dice. I rolled a three.\"\n2. Say \"Alexa, start Roll some Dice and roll a die plus.\"  Alexa will generate a random number between 1 and 6 and say, for example, \"You said roll 1 dice. I rolled a three.\"\n3. Say \"Alexa, start Roll some Dice and roll 1 die frog 3.\"  Alexa will not understand and should respond, \"Sorry, I can't understand the command.\"\n",
"category": "GAME_INFO_AND_ACCESSORY",

Now, with all that in place, you should be able to push the skill to Amazon again.   At a PowerShell command prompt, from the root folder of your skill, enter the following command:

ask deploy --profile "default" --target "all"


Assuming your skill deployed properly and passes all your tests, we are ready to go through the Distribution and Certification steps in the Alexa Developer Console.

On the first page of Distribution, we can upload the icon files we found earlier.  Simply add them here:

Now click Save and Continue.

Then, because we already filled all this in the skill.json, you can just click Save and Continue again.

And again.

Now, you’re at the validation stage.  Your skill should pass validation.

Click on Functional Test, then click Run.

It passes!! Your skill is ready for Submission.  Go ahead.  Click that Submit button and relax for a bit.  Depending on the promotions and backlog, your skill may or may not get reviewed within the next 1-3 business days.

That’s it for now.

A few days later…  WOOHOO!

An Alexa Skill in Javascript – Part 5

Finally, the last post in the series.  Here, we will show Alexa how to Roll Some Dice with a modifier so that we can get our skill working properly.

We’re going to do this in two steps:

1. Create a function that will take the diceCount, plusMinus and modifier parameters and return the results as speech text.
2. We’ll modify the RollSomeDiceIntentHandler to pull those parameters from the Request and call the function we created in the first step.

Create a Function that can Roll Some Dice

To contain our function, we’ll create a new JavaScript file in the lambda\custom folder of our project.  Right-click on the lambda\custom folder and select New File from the menu.  Enter rollSomeDiceFunction.js as the file name.

In the new file, let’s stub out our function.  We need to export the function to be able to access it from the other file, index.js.  It will accept three parameters.  Like so:

exports.rollSomeDice = function rollSomeDice(diceCountParm,
plusMinusParm, modifierParm) {

}

Next, we need to verify that the diceCount Slot parameter (diceCountParm) has been provided (i.e. is not null):

if (diceCountParm == null) {
speechOutput = "Sorry, I did not hear that.  Please say something like roll 2 dice.";
return (speechOutput);
}

Then, we need to convert the string parameters into numbers.  Slot values are always provided as strings.  We need to verify that the diceCount and modifier contain numeric values and parse the strings to actual numbers.

var diceCount = (isNaN(diceCountParm)) ? null :
parseInt(diceCountParm);
const diceSize = 6;
var modifier = (isNaN(modifierParm)) ? 0 :
parseInt(modifierParm);

Now, we need to check again that diceCount is not null:

if (diceCount == null) {
speechOutput = "Sorry, I did not hear that.  Please say something like roll 2 dice.";
return (speechOutput);
}

Next, we’re going to set up an array of possible dice rolls so we can keep track of what we roll:

var buckets = [0, 0, 0, 0, 0, 0, 0];
var bucketSlots = ['zero', 'one', 'two', 'three', 'four', 'five', 'six'];

And then we can finally roll the dice:

for (var i = 0; i < diceCount; i++) {
let roll = 0;
roll = Math.floor(Math.random() * diceSize) + 1;

And if the user supplied a plusMinus Slot value (in plusMinusParm) and a modifier value, then we need to add or subtract the modifier to/from the dice roll:

if (plusMinusParm != null && modifier != 0) {
// add or subtract the modifier to each roll
if (plusMinusParm == 'plus') {
roll += modifier;
} else {
roll -= modifier;
}
}

Next, we need to put the roll in the correct bucket.  Note that because of the modifier, we could roll less than 1 or more than 6, so we need to handle those values too:

if (roll < 1) {     buckets[0]++; } else if (roll > 5) {
buckets[6]++;
} else {
buckets[roll]++;
}

Now, we’ve completed the for loop that loops over the diceCount and we can start putting together the speech phrases that we want Alexa to say in her response.  First, we’ll tackle the buckets so she can say “I rolled 3 ones, 2 twos, a four and 3 sixes.”  Note:  This code snippet uses apostrophes ( ‘ ‘ ) and backward tick marks (   ) to create the right strings.

var bucketsPhrase = 'I rolled ';
for (let i = 0; i < 7; i++) {     if (buckets[i] > 1) {
if (i < 6) {
bucketsPhrase += ${buckets[i]}${bucketSlots[i]}s, ;
} else {
bucketsPhrase += and ${buckets[i]}${bucketSlots[i]}es ;
}
} else if (buckets[i] == 1) {
if (i < 6) {
bucketsPhrase += a ${bucketSlots[i]}, ; } else { bucketsPhrase += and a${bucketSlots[i]} ;
}
}
}

The above code handles the fact that six is the only plural that ends in ‘es’.  And that six is the last number in the set, so put an ‘and’ in front of it.  It also differentiates between ‘a six’ and ‘two sixes’.

The next phrase to put together is the entire speech that we want Alexa to say.  We have two options:  with modifier and without, so the code looks like this:

if (modifier == 0 && target == null) {
speechOutput = You said roll ${diceCount} d${diceSize}. ${bucketsPhrase}.; } else if (target == null) { speechOutput = You said roll${diceCount} d ${diceSize}${plusMinusParm} ${modifier}.${bucketsPhrase}.;
}

Lastly, we return the speechOutput to Alexa:

return (speechOutput);

The Finished Function

Putting it all together, we get the following:

exports.rollSomeDice = function rollSomeDice(diceCountParm, plusMinusParm, modifierParm) {

var speechOutput = "";
if (diceCountParm == null) {
speechOutput = "Sorry, I did not hear that.  Please say something like roll 2 dice.";
return (speechOutput);
}
var diceCount = (isNaN(diceCountParm)) ? null :
parseInt(diceCountParm);
const diceSize = 6;
var modifier = (isNaN(modifierParm)) ? 0 :
parseInt(modifierParm);

if (diceCount == null) {
speechOutput = "Sorry, I did not hear the number of dice to roll.  Please say something like roll 2 dice.";
return (speechOutput);
}

var buckets = [0, 0, 0, 0, 0, 0, 0];
var bucketSlots = ['zero', 'one', 'two', 'three', 'four', 'five', 'six'];

for (var i = 0; i < diceCount; i++) {
let roll = 0;
roll = Math.floor(Math.random() * diceSize) + 1;

if (plusMinusParm != null && modifier != 0) {
// add or subtract the modifier to each roll
if (plusMinusParm == 'plus') {
roll += modifier;
} else {
roll -= modifier;
}
}

if (roll < 1) {             buckets[0]++;         } else if (roll > 5) {
buckets[6]++;
} else {
buckets[roll]++;
}
}

var bucketsPhrase = 'I rolled ';
for (let i = 0; i < 7; i++) {         if (buckets[i] > 1) {
if (i < 6) {
bucketsPhrase += ${buckets[i]}${bucketSlots[i]}s, ;
} else {
bucketsPhrase += and ${buckets[i]}${bucketSlots[i]}es ;
}
} else if (buckets[i] == 1) {
if (i < 6) {
bucketsPhrase += a ${bucketSlots[i]}, ; } else { bucketsPhrase += and a${bucketSlots[i]} ;
}
}
}

if (modifier == 0) {
speechOutput = You said roll ${diceCount} dice.${bucketsPhrase}.;
} else if (target == null) {
speechOutput = You said roll ${diceCount} dice${plusMinusParm} ${modifier}.${bucketsPhrase}.;
}

return (speechOutput);
}

Modify the RollSomeDiceIntentHandler

Now that we have a function that can roll some dice, we need to wire it up to the RollSomeDiceIntentHandler we stubbed out in the basic template code in index.js.

Open index.js, right at the top we’re going to import the function we just created above, like so:

const Alexa = require('ask-sdk-core');
const i18n = require('i18next');
const sprintf = require('i18next-sprintf-postprocessor');
const diceRoller = require("./rollSomeDiceFunction.js");

Next, find the RollSomeDiceIntentHandler.  We’re going to replace the red, bold text in this function:

const RollSomeDiceIntentHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'IntentRequest' &&
handlerInput.requestEnvelope.request.intent.name === 'RollSomeDiceIntent';
},
handle(handlerInput) {

const speechText = 'Hello World!';

return handlerInput.responseBuilder
.speak(speechText)
.withSimpleCard('Roll Some Dice', speechText)
.getResponse();
},
};

First, delete the line const speechText = ‘Hello World!’;

Next, we need to pull the Slot values out of the request:

var diceCount = handlerInput.requestEnvelope.request.intent.slots["diceCount"].value;
var plusMinusSlot = handlerInput.requestEnvelope.request.intent.slots["plusMinus"];
var plusMinus = '';
if (plusMinusSlot.resolutions) {
plusMinus = plusMinusSlot.resolutions.resolutionsPerAuthority[0].values[0].value.name;
}
var modifier = handlerInput.requestEnvelope.request.intent.slots["modifier"].value;

Next, we need to make sure the user supplied values for the Slots.  If not, we will assign a default value:

if (!(diceCount)) {
diceCount = '1';
}
if (!(plusMinus)) {
plusMinus = 'plus';
}
if (!(modifier)) {
modifier = '0';
}

Next, we need to get the speech from the RollSomeDice() function we created earlier.

const sessionAttributes = handlerInput.attributesManager.getSessionAttributes();
sessionAttributes.speakOutput = diceRoller.rollSomeDice(diceCount, plusMinus, modifier) + " ... Now, what shall I roll?";
sessionAttributes.repromptSpeech = 'What shall I roll?';

Lastly, we need to return the speech to Alexa:

return handlerInput.responseBuilder
.speak(sessionAttributes.speakOutput)
.reprompt(sessionAttributes.repromptSpeech)
.withSimpleCard('Roll Some Dice', sessionAttributes.speakOutput)
.getResponse();

The Completed RollSomeDiceIntentHandler

Putting it all together, we get:

const RollSomeDiceIntentHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'IntentRequest' &&
handlerInput.requestEnvelope.request.intent.name === 'RollSomeDiceIntent';
},
handle(handlerInput) {

var diceCount = handlerInput.requestEnvelope.request.intent.slots["diceCount"].value;
var plusMinusSlot = handlerInput.requestEnvelope.request.intent.slots["plusMinus"];
var plusMinus = '';
if (plusMinusSlot.resolutions) {
plusMinus = plusMinusSlot.resolutions.resolutionsPerAuthority[0].values[0].value.name;
}
var modifier = handlerInput.requestEnvelope.request.intent.slots["modifier"].value;

if (!(diceCount)) {
diceCount = '1';
}
if (!(plusMinus)) {
plusMinus = 'plus';
}
if (!(modifier)) {
modifier = '0';
}

const sessionAttributes = handlerInput.attributesManager.getSessionAttributes();
sessionAttributes.speakOutput = diceRoller.rollSomeDice(diceCount, plusMinus, modifier) + " ... Now, what shall I roll?";
sessionAttributes.repromptSpeech = 'What shall I roll?';

return handlerInput.responseBuilder
.speak(sessionAttributes.speakOutput)
.reprompt(sessionAttributes.repromptSpeech)
.withSimpleCard('Roll Some Dice', sessionAttributes.speakOutput)
.getResponse();
},
};

Publish the Code to Alexa and AWS Lambda

Now that the RollSomeDice() function and the RollSomeDiceIntentHandler are written, we can publish the skill to Alexa and AWS Lambda.

In VS Code, open the Command Palette (View | Command Palette…).  Type ASK.  Select Deploy the skill.

Wait a moment while the ASK initializes, then select the default profile:

Then select “All”:

Now, it will try, and probably fail, to deploy. If it succeeds, great.  If it fails, you probably need to change the working directory in the Terminal window at the bottom right of VS Code.  This is done with the CD command, like so:

Once you’ve changed the directory to the one with your skill in it, press the up arrow on the keyboard a couple of times to get the “ask deploy” command back.  Then press enter.

If all goes well, a few moments later, your skill will be deployed:

Now that your skill is deployed, we can switch over to the Alexa Developer Console to test it.  If you still have your template project open from earlier, click “Your Skills” in the top left corner.  Then you will see your deployed skill at the top of the list:

Click the Edit link on the far right.  On the Build tab, you should see a little popup saying your build was successful:

Click on the Test tab.  If it’s not enabled, enable testing for this skill:

In the Alexa Simulator, type in “start Roll Some Dice and roll 2 dice”.  Press enter.

Alexa should say that she rolled some dice and list the results:

I just realized, there’s one last step:  Submitting Your Skill for Amazon Approval.  This will be covered in my next blog entry.

An Alexa Skill in Javascript – Part 4

So far we’ve defined, gathered and installed the requisite tools in Part 1.  We’ve defined the Skill we’re creating in Part 2.  And, we’ve created the Intents for our skill in Part 3.

Now, we will code the Lambda function that is the brains of our skill in this entry, Part 4.

What is a Lambda Function?

Amazon Web Services (AWS) calls the functions you create in their cloud “Lambda Functions.”  For the purposes of Alexa skills, these functions are the brains behind the skill.  Alexa takes care of the speech part of the skill, and figures out how to interpret the Alexa User’s spoken words and which intent to choose and slots to fill based on those words, but you then have to make your Alexa skill actually do something to fulfill the intent you created on the Alexa side of your Skill development process.  In my case, that means writing a function that can roll some dice and add or subtract and specified modifier to the rolls.

Lambda functions can be written in a variety of languages.  I’ve blogged before about using C# to do this.  (Note:  Using C# is now SOOO much easier as the Lambda Function tools in AWS have been updated to use .Net Core as a standard platform.)  Today, I am using JavaScript (node.js).  Other options include Python, Java and Go.

A Little More Cleanup First

In our VS Code project, in the \lambda\custom folder is a file named package.json.  We need to correct the name of our package here.  My skill is called “Roll Some Dice” so I’ll have to name my code package “roll-some-dice”.  Note the lower case and replacing spaces with dashes.

{
"name": "hello-world",
"version": "1.0.0",
"description": "",
"main": "index.js",

I’m going to simply replace “hello-world” with “roll-some-dice” and save and close the file.

{
"name": "roll-some-dice",
"version": "1.0.0",
"description": "",
"main": "index.js",

In that same folder, is a file named package-lock.json.  We need to make the same edit to that file.  So:

{
"name": "hello-world",
"version": "1.0.0",
"lockfileVersion": 1,

Becomes:

{
"name": "roll-some-dice",
"version": "1.0.0",
"lockfileVersion": 1,

One More Thing Before We Can Code

In order to roll a dice, we need a random number generator.  This can be found in the node.js module named i18next.  We will also need the module named i18next-sprintf-postprocessor.  To get these, we will use the npm package manager.

On the left side of the VS Code screen, right click on the “custom” folder in the basic skill template and choose “Open in Terminal”:

In the bottom right of the VS Code screen is the Terminal panel.  When you get to the command prompt:

Type in the commands “npm install i18next” and then “npm install i18next-sprintf-postprocessor“:

Once completed, you should have a couple of new folders in the “custom\node_modules” folder of your project:

Finally, the Brains of the Operation (index.js)

Since we just added the modules above to the project, let’s also add them to index.js, then I’ll discuss what’s in there and what we need to do.

Include the i18next Modules in index.js

At the top of the index.js file, we need to include the i18next modules.  This is done by adding new constants for them below the Alexa constant, like so:

const Alexa = require('ask-sdk-core');
const i18n = require('i18next');
const sprintf = require('i18next-sprintf-postprocessor');

A Brief Tour of index.js

After the constants declared at the top of the file to include the required modules, there are several “Handler” functions.  The first is the LaunchRequestHandler:

const LaunchRequestHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
},
handle(handlerInput) {
const speechText = 'Welcome to the Alexa Skills Kit, you can say hello!';
return handlerInput.responseBuilder
.speak(speechText)
.reprompt(speechText)
.withSimpleCard('Hello World', speechText)
.getResponse();
},
};

Each of the Handler functions handles one specific request from the user to Alexa.  In this case, it the LaunchRequestHandler can handle requests with a type of “LaunchRequest”.  When this Handler is fired, it builds a response that is sent back to the user.  This response includes some speech (what Alexa will say), a reprompt (what she will say to remind the user what to do, and a Card (to be displayed on the Echo Show and other devices with screens).

The other Handler functions are set up to handle the different intents of the skill:

• HelloWorldIntentHandler  –  The main intent handler
• HelpIntentHandler  –  Handles the case where the user asks Alexa for help
• CancelAndStopIntentHandler  –  Handles Alexa, Stop and Alexa, Cancel\
• SessionEndedRequestHandler  –  Handles the final request sent to the skill when the session ends
• ErrorHandler  –  Handles any error situations

Next, we get to the lines that export the various Handlers so that the Alexa SkillBuilder knows which functions to call:

const skillBuilder = Alexa.SkillBuilders.custom();
exports.handler = skillBuilder
LaunchRequestHandler,
HelloWorldIntentHandler,
HelpIntentHandler,
CancelAndStopIntentHandler,
SessionEndedRequestHandler
)
.lambda();

What We Need to Change

First, we will change the LaunchRequestHandler, as shown in bold, blue text below:

const LaunchRequestHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'LaunchRequest';
},
handle(handlerInput) {
const speechText = 'Welcome to Roll Some Dice.  You can say, Roll 2 Dice, or Roll 4 Dice plus 1!';
return handlerInput.responseBuilder
.speak(speechText)
.reprompt(speechText)
.withSimpleCard('Roll Some Dice', speechText)
.getResponse();
},
};

Next, we will fix the Card lines in all the other intents so that this:

.withSimpleCard('Hello World', speechText)

becomes:

.withSimpleCard('Roll Some Dice', speechText)

Next, we will change the Help Speech Text in the HelpIntentHandler to:

const speechText = 'You can say roll 2 dice, roll 3 dice plus 1, roll 6 dice minus 1 or any number of dice with any modifier.';

Next, we will completely change the HelloWorldIntentHandler.  We will do this in stages.  First, we need to change the name of the Handler and its corresponding entry in the SkillBuilder at the bottom of the file, like so:

const RollSomeDiceIntentHandler = {
canHandle(handlerInput) {
return handlerInput.requestEnvelope.request.type === 'IntentRequest'
&& handlerInput.requestEnvelope.request.intent.name === 'RollSomeDiceIntent';
},
handle(handlerInput) {
var speechText = 'Hello World!';
return handlerInput.responseBuilder
.speak(speechText)
.withSimpleCard('Roll Some Dice', speechText)
.getResponse();
},
};

...

const skillBuilder = Alexa.SkillBuilders.custom();
exports.handler = skillBuilder
LaunchRequestHandler,
RollSomeDiceIntentHandler,
HelpIntentHandler,
CancelAndStopIntentHandler,
SessionEndedRequestHandler
)
.lambda();

Now, we have a Handler for our Intent that doesn’t actually do what it needs to do.
But, we do have a Handler.  At this point, we can deploy and test our Skill.

Deploying Your Skill to Alexa Developer Console and Amazon Web Services

It turns out, that with the ASK in VS Code, deploying our Skill to Alexa and Amazon is quite easy.  Open the Command Palette (View | Command Palette…).  Type ASK.  Select Deploy the skill.

Wait a moment while the ASK initializes, then select the default profile:

Then select “All”:

Now, it will try, and probably fail, to deploy. If it succeeds, great.  If it fails, you probably need to change the working directory in the Terminal window at the bottom right of VS Code.  This is done with the CD command, like so:

Once you’ve changed the directory to the one with your skill in it, press the up arrow on the keyboard a couple of times to get the “ask deploy” command back.  Then press enter.

If all goes well, a few moments later, your skill will be deployed:

Now  that your skill is deployed, we can switch over to the Alexa Developer Console to test it.  If you still have your template project open from earlier, click “Your Skills” in the top left corner.  Then you will see your newly deployed skill at the top of the list:

Click the Edit link on the far right.  On the Build tab, you should see a little popup saying your build was successful:

Click on the Test tab.  If it’s not enabled, enable testing for this skill:

In the Alexa Simulator, type in “start Roll Some Dice and roll 2 dice”.  Press enter.

Alexa should say, “Hello World”.  (Remember, we haven’t actually told her how to roll some dice yet.)

Notice the JSON Output from your Skill code in index.js:

And scroll down to see the Card visual that would be shown on the Echo Show:

That’s it for now.  In the final post in this series, I will teach Alexa to roll dice with a modifier and report the results.

An Alexa Skill in Javascript – Part 3

The Skill Model (en-US.json)

Open the en-US.json file in the models folder.  Notice the areas I’ve highlighted in bold, red text.  These are things we will change.

{
"interactionModel": {
"languageModel": {
"invocationName": "greeter",
"types": [
],
"intents": [
{
"name": "AMAZON.CancelIntent",
"samples": [
]
},
{
"name": "AMAZON.HelpIntent",
"samples": [
]
},
{
"name": "AMAZON.StopIntent",
"samples": [
]
},
{
"name": "HelloWorldIntent",
"slots": [
],
"samples": [
"hello",
"say hello",
"say hello world"
]
}
]
}
}
}

First, the invocation name.  This is the name by which users will invoke your skill and it should be the same as the name of the skill you put in the skill manifest.  In my case, in Part 2 I named the skill “Roll some dice”.  The invocation name has to follow these rules:

1. Your invocation name should be two or more words
2. Can contain only lower-case alphabetic characters, spaces between words, possessive apostrophes (for example, “sam’s science trivia”), or periods used in abbreviations (for example, “a. b. c.”).
3. Other characters like numbers must be spelled out. For example, “twenty one”.
4. Invocation names cannot contain any of the Alexa skill launch phrases.

I will enter the invocation name as “roll some dice”.

"invocationName": "roll some dice",

There are three AMAZON intents in the basic skill template.  Those are fine the way they are and should not be modified.

The meat of the skill model is your intent.  In the basic skill template, this is the HelloWorldIntent.  We will change this.

Using the Alexa Developer Console to build the JSON for an Intent

The easiest way to get the correct syntax for the Skill Intent is to use the Alexa Developer Console.

1.  Log in and click Create Skill.  Enter the name “My Template”. Pick Custom as the type.  On the next page, click Start from Scratch as the template.  You should end up here:

2.  Next to Intents, click Add.  Intent name can only contain case-insensitive alphabetical characters and underscores, and it must begin and end with an alphabetic character. Numbers, spaces, or other special characters are not allowed.  I will name my intent “RollSomeDiceIntent”:

3.  Next, you enter the sample utterances.  This is what the Alexa User needs to say to make your skill work.  In my case, I have entered four utterances:

Notice how I used braces { } to create “slots” (or variables).  These slots are placeholders for where the user can say a matching word.  For example, “Roll 10 dice plus 1” matches the second utterance “roll {diceCount} dice {plusMinus} {modifier}“.

4.  Now we need to define the slot types for the slots we named in the utterances.  This is done at the bottom of the sample utterances page.  Scroll down a bit and you will see this:

For the Slot Type, the first and third slot (diceCount and modifier) are both numeric, so pick AMAZON.Number from the drop down.  You can type AMAZON.N and it will show AMAZON.Number as the only choice if you want to save on scrolling.

For the other slot, plusMinus, we will want to make a custom slot type where it only responds to “plus” and “minus”.  Do this by clicking the Add button next to the Slot Type menu on the left side of the screen:

Give your new slot a name.  Note:  You cannot use a period in your name.  Amazon can, but you can’t.  So use an underscore.  I will name my slot: OMWTM_PlusMinus:

Next, enter the words that are valid in your slot.  For me, that is plus and minus.  I will also add the synonyms add and subtract, just in case the user gets creative.  Note: Make sure you click the plus sign next to the synonym so it actually gets saved into the slot.  The slot ends up looking like this:

Finally, click on a the {plusMinus} slot in the left panel and select your custom slot type as the slot type:

1. Now we’ve defined the intent, with sample utterances and slots.  Next, we need to get the JSON for the intent and copy it over to the en-US.json model file in VS Code.  The JSON for your intent is in the Alexa console under the JSON Editor menu option on the left side:

We want ONLY the custom intent and the slots, so scroll down past the AMAZON intents and find the section that defines your intent:

Copy the highlighted section over to the model file in VS Code.  Note:  When you paste it in, you will be replacing the last braces of the intents section.  If you don’t, your JSON file won’t have the right number of braces.  I.e.  Delete the HelloWorldIntent in its entirety and delete the extra square brace below it that ends the set of intents:

Also, the basic skill template inserts a blank types section at the top.  Delete this too:

Now, back at the bottom of the file, paste in the copied text from the Alexa console:

The finished intent model should look like this:

{
"interactionModel": {
"languageModel": {
"invocationName": "roll some dice",
"intents": [{
"name": "AMAZON.CancelIntent",
"samples": [
]
},
{
"name": "AMAZON.HelpIntent",
"samples": [

]
},
{
"name": "AMAZON.StopIntent",
"samples": [

]
},
{
"name": "RollSomeDiceIntent",
"slots": [{
"name": "diceCount",
"type": "AMAZON.NUMBER"
},
{
"name": "plusMinus",
"type": "OMWTM_PlusMinus"
},
{
"name": "modifier",
"type": "AMAZON.NUMBER"
}
],
"samples": [
"roll a die {plusMinus} {modifier}",
"roll {diceCount} dice {plusMinus} {modifier}",
"roll {diceCount} dice",
"roll a die"
]
}
],
"types": [{
"name": "OMWTM_PlusMinus",
"values": [{
"name": {
"value": "minus",
"synonyms": [
"subtract"
]
}
},
{
"name": {
"value": "plus",
"synonyms": [
]
}
}
]
}]
}
}
}

That’s it for now.  In the next post, we’ll start looking at the Lambda function files and what needs to be changed there to get this skill working.

Bye for now.

An Alexa Skill in JavaScript – Part 2

Now that we have the tools and a basic project, let’s see what the Alexa Skills Kit (ASK) has created for us.

What’s in the Basic Project?

The lambda folder contains your JavaScript files that are the code behind your skill.  The node_modules folder contains the downloaded node modules you use.  index.js is the main code file for your skill.  package.json and package-lock.json are files that describe some of the technical aspects of your code, such as dependencies.

The models folder contains the various language versions of your Json skill description, including the intents and slots.

The skill.json file is the skill manifest and is where you describe the skill for your end users and the Amazon publishing process.

Where to Start?

In the image above, we’ll start at the bottom with the skill manifest, then the model, then a couple of minor changes to the package files, then we’ll write a couple of lines of JavaScript code and finally check the .ask\config.

The Skill Manifest (skill.json)

Open the skill.json file.  Notice the areas I’ve highlighted in bold, red text.  These are things we will change.

{
"manifest": {
"publishingInformation": {
"locales": {
"en-US": {
"summary": "Sample Short Description",
"examplePhrases": [
"Alexa open hello world",
"Alexa tell hello world hello",
"Alexa ask hello world say hello"
],
"name": "omwtm-roll-a-dice",
"description": "Sample Full Description"
}
},
"isAvailableWorldwide": true,
"testingInstructions": "Sample Testing Instructions.",
"category": "EDUCATION_AND_REFERENCE",
"distributionCountries": []
},
"apis": {
"custom": {
"endpoint": {
"sourceDir": "lambda/custom"
}
}
},
"manifestVersion": "1.0"
}
}

The “summary” entry should be a short description of your skill, for example:

"summary": "Roll some dice, optionally adding a modifier to each die",

The “examplePhrases”: section contains 3, and only 3, sample phrases.  I’ll have two main intents:  “Roll {diceCount} dice” and “Roll {diceCount} dice {plusMinus} {modifier}”, so I want to show those in the example phrases.  For example:

"examplePhrases": [
"Alexa open roll some dice",
"Alexa tell roll some dice to roll 2 dice",
"Alexa ask roll some dice to roll 3 dice plus 1"
],

The “name” entry should be the plain, human-readable, name of your skill that people see in the Alexa Skills Catalog.  Note:  This does not have to be unique in the Catalog.  For example:

"name": "Roll Some Dice",

The “description” entry should describe your skill.  This can be a paragraph or two and will also display in the Alexa Skills Catalog.  Notice the description is all on one line.  In VS Code, you can turn on Word Wrap (View | Toggle Word Wrap) to see the entire description on screen.  For example:

"description": "Roll Some Dice will roll any number of standard dice (d 6's) and optionally add or subtract a modifier from each dice.  Alexa will then tell you the total of the rolls plus or minus the modifiers.  For example, you might say 'Roll 3 dice plus 1' and Alexa will roll 3 d 6, getting, say, 3, 4, and 6, then add 1 to each roll, getting 4, 5, and 7, and will tell you the total, 16.",

“testingInstructions” is something we’ll come back to later.  This is the instructions for the Alexa Skill evaluators to follow to test your skill intents thoroughly.  For now, I’ll leave it as is.

Lastly, the “category” entry is used to classify your skill in the Alexa Skills Catalog.  For this skill, I will pick:

"category": "GAME_INFO_AND_ACCESSORY",

There are a couple of additional settings you will want to add to your skill, if appropriate.  After the “manifest” setting, add this code:

"manifestVersion": "1.0",
"permissions": [],
"privacyAndCompliance": {
"allowsPurchases": false,
"isExportCompliant": true,
"isChildDirected": false,
"usesPersonalInfo": false
}

So, the completed file looks like this for now:

{
"manifest": {
"publishingInformation": {
"locales": {
"en-US": {
"summary": "Roll some dice, optionally adding a modifier to each die",
"examplePhrases": [
"Alexa open roll some dice",
"Alexa tell roll some dice to roll 2 dice",
"Alexa ask roll some dice to roll 3 dice plus 1"
],
"name": "Roll Some Dice",
"description": "Roll Some Dice will roll any number of standard dice (d 6's) and optionally add or subtract a modifier from each dice.  Alexa will then tell you the total of the rolls plus or minus the modifiers.  For example, you might say 'Roll 3 dice plus 1' and Alexa will roll 3 d 6, getting, say, 3, 4, and 6, then add 1 to each roll, getting 4, 5, and 7, and will tell you the total, 16."
}
},
"isAvailableWorldwide": true,
"testingInstructions": "Sample Testing Instructions.",
"category": "GAME_INFO_AND_ACCESSORY",
"distributionCountries": []
},
"apis": {
"custom": {
"endpoint": {
"sourceDir": "lambda/custom"
}
}
},
"manifestVersion": "1.0",
"permissions": [],
"privacyAndCompliance": {
"allowsPurchases": false,
"isExportCompliant": true,
"isChildDirected": false,
"usesPersonalInfo": false
}
}
}

Next up, the skill model, where you define your intents and slots.

Bye for now.

An Alexa Skill in JavaScript – Part 1

So I finally decided to stop fighting it…  Building Alexa Skills in C# is just difficult.  With the newly released Visual Studio Code plugin for Alexa ( ) the language of choice is JavaScript.  Ugh.  But, it turns out that Google is still my friend (even though the Google Home is a horrible platform for voice skill development).  A quick search turned up all sorts of free JavaScript training.  A few hours of interaction later and I’m a pro beginning to be barely capable in JavaScript.  So, what’s a Microsoft Developer to do to code an Alexa Skill?

Getting the Tools

Step 1 – From the command line (Start | cmd in Windows), run npm to install the ASK CLI:

npm install -g ask-cli

This command takes 2-5 minutes to run and doesn’t appear to be doing anything while it’s running.

TIP:  It’s a good idea to run that npm command every month or so to get the latest version of the ASK-CLI.  It is updated quite frequently.

Step 2 – Install Git, if you haven’t already.

Step 2 – Install Visual Studio Code if you haven’t already.  (I recommend the 64-bit User version for Windows developers.)

Step 3 – In VS Code, select the Help | Welcome menu.  On the right-hand side, under Customize, under Tools and languages, install support for JavaScript.

Step 4 – In VS Code, select the View | Extensions menu.  Search for Alexa Skills Kit (currently – 09/15/18 – in beta).  Install it.

I think that’s all I had to do to get the tools.

Configuring for Alexa Skill Development

AWS Lambda Credentials

Since we will be using an AWS Lambda function as the back-end for our skill, we need to set up the credentials in AWS IAM.

Add a User.  Give the user a name.  Select Programmatic access.  Click Next.

For this example, I’m going to Attach existing policies directly and select Administrator Access, but this is NOT best practice.  (I should create a user group that has the specific policies this account needs, but that’s a different blog entry.)  Click Next.

Click Create User.

IMPORTANT:  This is the ONLY time you can Download the .csv, so do it now.

Click Close.

In VS Code, view the Command Palette (Ctrl-Shift-P) or select the View | Command Palette menu.  Enter:  ASK in the palette and choose the “ASK: Initialize / Configure the ASK CLI” option.

Accept the default profile name.  Sign in to Amazon in the browser provided USING THE ACCOUNT YOU JUST CREATED ABOVE.  It should say “Profile [default] initialized successfully.”

If not, go here for assistance.

Starting the Alexa Skill

Create a folder for Alexa Skills.

View the Command Palette (Ctrl-Shift-P) or select the View | Command Palette menu.

Enter:  ASK in the palette and choose the “ASK: Create a basic skill package” option.

It should come back with an option to select your AWS profile.  Choose the profile you created above.  This profile needs to be linked to an IAM user who has the right to publish Lambda functions.  (Which is why I cheated above and gave it AdministratorAccess.)

Now it will ask you to enter a skill name.  I’ll be calling mine “OMWTM Roll A Dice”.

ASK will then create and run a command in the Terminal window at the bottom right of VS Code:

Once it’s finished, VS Code will open a folder with your basic skill defined:

In the next blog entry, we’ll go through the basic skill definition and customize it.

Bye for now.

Unit Testing an Alexa Skill in C# – Step 3a

In Step 3, we created the Lambda function that will provide the functionality of the Alexa Skill we defined in Step 1, we wired everything up and then we tested our Skill.  So far so good.  However, that’s an awful long way round to test the Skill Request and Response.  It would be nice if we could set up a unit test project and unit test our Lambda function without having to deploy it.

It turns out, we can.

When we created the Lambda function project in Step 3, we selected the AWS Lambda Project with Tests template.  So we already have a Tests project and a stubbed out xunit test.  (Note: Because we are using the .Net Core for our Lambda function, the normal Microsoft Unit Testing Framework doesn’t work (because it uses the full .Net platform) and so the AWS template uses xunit.)

The tricky part of Unit Testing our Lambda function is that we need to test them FunctionHandler method, which takes a SkillRequest and a Context as parameters:

public SkillResponse FunctionHandler(SkillRequest input, ILambdaContext ctx)


In order to Unit Test our simple GetTodaysDateIntent, we will need to set up a SkillRequest that names that Intent.  Like so:

using AlexaAPI;
using AlexaAPI.Request;
using AlexaAPI.Response;
using Amazon.Lambda.TestUtilities;
using System.Collections.Generic;
using Xunit;
var intent = new Intent();
intent.Name = "GetTodaysDateIntent";
intent.ConfirmationStatus = "NONE";
var request = new Request();
request.Intent = intent;
request.Locale = "en-US";
request.Type = AlexaConstants.IntentRequest;
var interfaces = new Dictionary<string, object>();
var device = new Device();
device.SupportedInterfaces = interfaces;
var sysObj = new SystemObject();
sysObj.Device = device;
var skillContext = new Context();
skillContext.System = sysObj;
var session = new Session();
var skillRequest = new SkillRequest();
skillRequest.Request = request;
skillRequest.Context = skillContext;
skillRequest.Session = session;

With that code to create the skillRequest, this line will create the Lambda Context:

var context = new TestLambdaContext();

Now we can create the Function instance:

var function = new MyAlexaSkill.Lambda.Function();


And then we can call the FunctionHandler method to test the Intent:

var result = function.FunctionHandler(skillRequest, context);


A few Assertions will make sure we got the response we are looking for:

Assert.NotNull(result);
Assert.NotNull(result.Response);
Assert.NotNull(result.Response.OutputSpeech);

Assert.Equal("<speak>Today's date is 5/15/2018 12:00:00 AM</speak>",
(result.Response.OutputSpeech as SsmlOutputSpeech).Ssml);

Putting it all together, we get this Unit Test:

[Fact]
public void TestGetTodaysDateIntent()
{

var intent = new Intent();
intent.Name = "GetTodaysDateIntent";
intent.ConfirmationStatus = "NONE";
var request = new Request();
request.Intent = intent;
request.Locale = "en-US";
request.Type = AlexaConstants.IntentRequest;
var interfaces = new Dictionary<string, object>();
var device = new Device();
device.SupportedInterfaces = interfaces;
var sysObj = new SystemObject();
sysObj.Device = device;
var skillContext = new Context();
skillContext.System = sysObj;
var session = new Session();
var skillRequest = new SkillRequest();
skillRequest.Request = request;
skillRequest.Context = skillContext;
skillRequest.Session = session;

var context = new TestLambdaContext();

var result = function.FunctionHandler(skillRequest, context);

Assert.NotNull(result);
Assert.NotNull(result.Response);
Assert.NotNull(result.Response.OutputSpeech);

Assert.Equal("<speak>Today's date is 5/15/2018 12:00:00 AM</speak>",
(result.Response.OutputSpeech as SsmlOutputSpeech).Ssml);
}

And there you have it, a Unit Test to test a simple Alexa Skill Intent.

Creating an Alexa Skill in C# – Step 3

Now that you’ve defined your Alexa Skill in Step 1, and you’ve configured the security and downloaded the sample in Step 2, we’re ready to take a look at the sample and see how to wire it up to the skill definition.

Open your copy of the sample solution in Visual Studio 2017.  I left my copy in this folder:

C:\_GitHub\Alexa\MyAlexaSkill\sampleFactCsharp.sln

At this point, I had a decision to make:  Do I start a new project and copy the stuff from the sample project, or do I just mess with the sample project?  I think I’ll actually create a new project, and leave the sample in pristine condition for comparison.

Creating the Alexa Skill Project from the Sample

First, create a new project in the solution, choosing AWS Lambda Project with Tests as the template:

We want an Empty Function:

Now that we have our own project, let’s check out the dependencies:

As of this writing, the NuGet package for Amazon.Lambda.Serialization.Json needs updating.  So I did that.  Also, the sample is for .NetCore 1.0.  My project has defaulted to using .NetCore 2.0.  I don’t expect this to be a problem.

Next, I might as well copy the code (both classes) and the AlexaAPI folder from the sample to my project.  This will at least give me a starting point.

Coding for the Alexa Intents

Now that the project is set up, we can start coding for the Intents in the Alexa Skill we created in Step 1.   To start off, we will crack open the Function class in our new project and locate the ProcessIntentRequest() function.  There’s a switch statement there that will handle our simplest Intent Request, which was GetTodaysDateIntent, like so:

switch (intentRequest.Intent.Name)
{
case "GetTodaysDateIntent":
innerResponse = new SsmlOutputSpeech();
(innerResponse as SsmlOutputSpeech).Ssml = \$"Today's date is {DateTime.Today.ToString()}";
break;

case "GetNewFactIntent":
innerResponse = new SsmlOutputSpeech();
(innerResponse as SsmlOutputSpeech).Ssml = GetNewFact(factdata, true);
break;
...

At this point, you’ll probably want to do a build and deployment to AWS.  First, make sure your project builds.

Creating an AWS Profile

Next, you need to set up a Publish Profile in AWS.  This is done by viewing the AWS Explorer on the left side of your VS screen and clicking the New Account Profile icon.

That will bring up the New Account Profile dialog.

Click the link near the bottom of the dialog to go to the documentation on how to add a user.  Then click on one of the links that open the Console to IAM.  Or just click on the link here.

Next, select the Users category on the left.  Then create a Deployment User that has programmatic access and is in the Developers group we created in Step 2.

When you click Create User, you will see the Success screen.  Be sure to click the Download .csv button (middle-left) to get the credentials file.  You can never get this file again, you will have to create a new Access Key and get a new credentials file.

Now, back in Visual Studio, click the Import from csv file button:

Give your profile a name, I called mine Deployment.  Account Number is optional and can be left blank.  Then click OK.  You will see the AWS Explorer switch to the Deployment profile.  You should then pick the default profile and delete it.

You are now ready to publish your AWS Lambda project.  Right-click on the project and select Publish to AWS Lambda….

If you don’t see this menu option, make sure you’re in the Lambda project, not the Test project.  Then, make sure you have installed the AWS Toolkit as described in Step 2.

When you see the publish dialog, give your function a name:

Then click next and pick the Role we defined in Step 2.

Uh-Oh.  Duplicate Compile Items

If you get the Duplicate Compile items error:

Duplicate Compile items were included. The .NET SDK includes Compile items from your project directory by default. You can either remove these items from your project file, or set the ‘EnableDefaultCompileItems’ property to ‘false’ if you want to explicitly include them in your project file.

The recommendation is to remove the Compile items from your project (*.csproj) file.  Right-click the project and choose to Edit your .csproj file:

Then delete all the *.cs files from the Compile section:

I also deleted the ItemGroups above that because they had Compile items in them too.  Now my project builds and deploys properly, and my .csproj file is much cleaner:

Now publish the fixed project to AWS.

Back on Track:  Wiring up the Skill and the Lambda function.

Alright, we have a Skill defined.  We have a Lambda function uploaded.  Now we need to tell them each about the other.  First, we’ll tell the Skill about the Lambda function.

Go to the Lambda functions list in the Lambda Management Console.  Click on your new Lambda function, which I named MyAlexaSkillsLambdaFunction.  In the top right corner of the screen you will see the ARN:

Copy the ARN to the clipboard and paste it into Notepad.  Now, switch over to the Alexa Skill Console.  Select your skill.  Click on the Build tab.  Click on the big “4. Endpoint >” button in the checklist on the right.

Paste the ARN from the Lambda Function into the Default Region box on the right.

Then, copy the Skill ID above it to the clipboard and paste that into Notepad too.

Switch back to the Lambda Management Console.  Under the Add Triggers list on the left, find the Alexa Skills Kit and drag it over to the Triggers area of your Lambda function:

Then scroll down to configure the trigger and paste in the Skill ID you copied from the Skill and click the Add button:

Lastly, in the top right corner of the Lambda screen, click the Save button:

And that’s that.  The Alexa Skill is defined, the Lambda function is defined.  The two know about each other.  You are ready to test your skill.

Testing the Alexa Skill

To test your Alexa Skill and make sure everything is wired up properly, click on the Test tab in the Alexa Console.   Then enable testing for this skill.

In the Alexa Simulator panel, in the text entry box, run your Skill:

Alexa should respond with the Launch Message from your skill (which we will modify in a later Step in this series):

Alexa should tell you the date:

Tada!  That’s it for Step 3.

Check out Step 3a to see how to Unit Test your Alexa Skill Intent without publishing anything to AWS.

In Step 4, we will look at setting up a Web Service project to feed data from an Azure SQL database to our Alexa Skill.

Creating an Alexa Skill in C# – Step 2

If you haven’t done so already, check out Step 1 to define your Alexa Skill.

After defining the Alexa Skill in Step 1, you are ready to set up Visual Studio in Step 2.

AWS Account and AWS Toolkit Extension

Before you can set up an Alexa project, you need to create an AWS Lambda project.  Lambda functions are just class libraries that are hosted in the AWS Lambda cloud service.   To create one, you need two things:  the Amazon AWS Toolkit Extension and an AWS Developer Account.  You can install the Extension in VS 2017.

You can create the AWS Developer Account at https://aws.amazon.com/.

With the AWS NuGet package installed and the Developer Account set up, you are ready to set up the AWS Security.  You do that here:  https://console.aws.amazon.com/iam.

Securing Your AWS Account and Lambda Function

In IAM Management Console, click on Groups on the left.  Create a group for your Developers that has Admin Access.  Create a group for your Apps that has AWSLambdaFullAccess

Then, click on Users on the left and create two accounts.  One for yourself, of type AWS Management Console access, assigned to the Developers group.  And, one for your app, of type Programmatic access, assigned to the Apps group:

Next, create an AWS Lambda Role by selecting Roles on the left side.  Then make the following selections:

With the security Groups, Users and Role configured, you are ready to create the Solution for your Alexa Skill.  The easiest way to do this is to use one of the sample projects in the Alexa Git repository.

Getting the Alexa Skill Sample Solution

Navigate to the Alexa GitHub repository in your browser to see what’s available.

I used the alexa/skill-sample-csharp-fact sample as my starting point.  It has a ton of code in it that is ready to go, I just had to add something specific to my skill and I was off to the races.  You can get the sample from the command line (Start | Run | Cmd).  Make the directory/folder you want to host the project in with the md command:

C:>  md \_GitHub
C:>  md \_GitHub\Alexa
C:>  cd \_GitHub\Alexa

And then type:

git clone https://github.com/alexa/skill-sample-csharp-fact.git

You will find the C# Solution file here:

C:\_GitHub\Alexa\skill-sample-csharp-fact\lambda\custom\sampleFactCsharp.sln

Copy the sample solution to your own folder:

C:\_GitHub\Alexa>  md MyAlexaSkill
C:\_GitHub\Alexa>  cd skill-sample-csharp-fact\lambda\custom
C:\_GitHub\Alexa\skill-sample-csharp-fact\lambda\custom>
xcopy *.* \_GitHub\Alexa\MyAlexaSkill\*.* /S

Open the solution in VS 2017.  (Be sure to update to the latest version of VS — 15.7 as of this writing — as it has some cool new features!)

In Step 3, we will look at the sample solution and start to modify it to work with the skill we defined in Step 1.

Creating an Alexa Skill in C# – Step 1

Recently, I decided to make an Alexa skill that I could play on my boss’s Alexa.  At first, I was doing it as a gag, but I figured that wouldn’t work as he has to actively install my skill onto his Alexa.  Now it reads some stats from one of our Azure databases and publishes those in a conversation.  Here’s how I built it.

Step 1:  Creating the Alexa Skill Model

I don’t know any of the other languages that you can write a skill in, so I chose to write it in C#.  That means getting a bunch of bits and loading them into Visual Studio.  But first, you’ll need to start the process of creating a skill.  At the time of this writing, these are the steps I took.

1. Start Here.
2. Click the Start a Skill button.
3. If you don’t have an Amazon Developer account, create one.
4. Eventually, you’ll get to the Alexa Skills Developers Console where you can click the Create Skill button.
5. Give your skill a name.  I’m calling mine:  Simon’s Example Skill.
6. On the Choose a Model screen, select Custom.
7. Then click Create Skill.
8. You should now be on the Build tab for your Skill.  Notice the tree view on the left and the checklist on the right.

Invocation Name

The Invocation Name is the phrase that an Alexa user will use to launch/run/start your Alexa Skill.  It could be “joe’s hot dog recipes” or some such.  It needs to be lower case, there are some restrictions on the characters you can use, and any abbreviations you use need periods to separate the letters so Alexa knows to read the letters and not pronounce the word.  Read the Invocation Name Requirements for more details.

Click the Invocation Name link in the tree view on the left or the first option in the checklist on the right.  Then give your skill an Invocation Name.  I named mine:  “simon’s example”.

Intents

The Intents are the various functions your skill can perform.  For example, stating today’s date, looking up some data, figuring something out, etc.  Let’s do all three.

First, my skill is going to provide today’s date, so I’m going to name my first Intent, “GetTodaysDateIntent”.  My skill is also going to look up some data in an Azure SQL Database, so I’m going to name my second Intent, “DataLookupIntent”.  Lastly, I want to figure something out, like the average temperature in a major US city.

Utterances

The Utterances are the phrases an Alexa user might say to trigger your Intent (function).  You should put in several Utterances using synonyms and different phrasing so Alexa has a better chance of triggering your Intent instead of responding with “I don’t know how to do that.”

For the GetTodaysDateIntent, I added the following utterances:

Slots

Within an Utterance, you can have Slots (or placeholders), that represent the multiple options for that slot.  For example, if my table has the count of animals per household per neighborhood per county in it, I might want to create slots for Animal Type, Household Size, Neighborhood Name, and County Name.  You can do this by typing a left brace { in the Utterance box.

Here are three of my sample utterances for the DataLookupIntent:

Once you have created a slot, you need to populate it with options.  You do this in the bottom half of the Utterance screen.

You can easily select one of the pre-defined Slot Types in the drop-down.  In my case, Amazon has a list of Animals, so I’ll pick AMAZON.Animal in the first slot.

I need to manually add a few Counties for the second slot though.  And at this time, you don’t want to click Edit Dialog (though it’s tempting).  Instead, you want to define your own Slot Type by clicking the Add (Plus) button next to Slot Type in the tree view on the left:

For example, here is the custom Slot Type for County Name:

Notice the synonyms column.  This is important if there are synonyms, for example, a 1 person household and a single person household are synonymous.  So be certain to add any synonyms you can think of.  Here is my custom Slot Type for Household Size, notice the synonyms off to the right:

Now that you’ve defined some custom Slot Types, you can click on the Slot names under the Intent in the tree view on the left and select the newly created Slot Type for each Slot.

For the GetAverageTemperatureIntent, I added one Utterance:

And configured the {City} slot as follows:

Finally, you can Save your Model and Build it by clicking the buttons at the top of the screen:

Hopefully, the model will build and we are ready to move on to Step 2.  If the model doesn’t build, check the bottom right of the screen for a list of the errors:

Fix the errors until the model builds:

Then go to Step 2.