Introduction
In this blog, I'll take you through the fundamentals of coding an Alexa skill to hopefully give you the foundation you'll need to create anything!
Let's dive right into it.
What is an Alexa skill
Alexa skills are just voice-driven apps for Alexa, that's it.
What we'll be creating
In this blog we'll be creating an Alexa skill that gives us the word of the day — Alexa already has word of the day built-in but it'll be a good exercise. Our Alexa skill will be called Logomaniac Pursuit, logomaniac meaning one who is obsessed with words, clever, I know.
A bit of terminology
In natural language and more specifically Alexa development, there are a few keywords that crop up that you'll need to understand.
- Utterance: what the user says to Alexa
- Invocation word: the word that boots up your Alexa skill, for example a user might say something like "Alexa open Logomaniac Pursuit" to open our skill.
- Intent: An intent represents an action that'll fulfill a user's request.
- Slot: input values provided in a user's request. For example "Alexa, what was the word of the day of the ninth of august", We could use the ninth of august as a date slot (This will all become clear when we start developing!)
Getting started
Signing up
The first thing you'll need to do is create an Alexa development account. Then when you've done that go to https://developer.amazon.com/alexa/console/ask which is the main development console where you'll see all your skills.
Creating a skill
Let's create a skill, in the development console click the Create Skill button
Give your skill the name Logomaniac Pursuit or some equally brilliant name:
Our skill is going to be a custom skill, the other options provide prebuilt development kits for Smart Home, Video, and Flash briefing but this won't be covered in this blog, so choose custom!
Next, we need to choose what backend we're going to use, in this tutorial we're going to be using the Alexa-host (Node.js) option, this way we don't need to worry about hosting and we can also use the pretty brilliant code editor within the Alexa development area.
Scroll up and click Create skill!
Next, choose the basic Hello World skill, we'll modify this to create our skill!
Hit continue with template.
Setting an invocation name
Go to Build | Invocation (on the left panel)
As explained earlier the invocation name is the word that the user will include in their request to open the skill.
"Alexa, open logomaniac pursuit" as an example.
Hit Save Model then Build Model, once built we should be able to invoke our skill with that invocation name, let's try it.
Testing your skill
Go to Test and set the testing for your skill to Development
This testing area is where we will come to try out our skill, you can either type out the text yourself within the text box or you can talk to it using your microphone. The wake word is not required for testing (We don't need to say Alexa).
Let's give this a go:
Alexa returns the default Hello World response that is prebuilt into the template we chose, but nonetheless it is using our invocation name, so that's a win!
The code editor
Go to the Code section, here you'll see the code that was generated from the template we chose. You'll notice that each object is split up like the following:
const LaunchRequestHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'LaunchRequest';
},
handle(handlerInput) {
const speakOutput = 'Welcome, you can say Hello or Help. Which would you like to try?';
return handlerInput.responseBuilder
.speak(speakOutput)
.reprompt(speakOutput)
.getResponse();
}
};
The code in this example is the LaunchRequestHandler
which is what gets called when the user invokes our skill.
Each object is a handler that is split into two functions:
-
canHandle()
is called first, this checks to see whether the request matches the condition of the handler -
handle()
does the actual handling of the request, which ultimately decides what to say back to the user. We build up a response using theresponseBuilder
thespeak()
function is the message that gets played to the user. If the skill is supposed to listen for the user's response then we will use thereprompt()
function.
Let's change the speakOutput
line to our own phrase:
const speakOutput = 'Welcome, if you would like to hear the word of the day or the word of the day for a previous date, just ask';
And let's also add a reprompt phrase:
const repromptOutput = 'If you would like to hear the word of the day or the word of the day for a previous date, just ask';
Remember to change the argument of the reprompt()
function to repromptOutput
. The handle code now should look like:
handle(handlerInput) {
const speakOutput = 'Welcome, if you would like to hear the word of the day or the word of the day for a previous date, just ask';
const repromptOutput = 'If you would like to hear the word of the day or the word of the day for a previous date, just ask';
return handlerInput.responseBuilder
.speak(speakOutput)
.reprompt(repromptOutput)
.getResponse();
}
Hit Save then Deploy.
You can then go to the Test section and see whether the new phrase is being returned when you invoke your skill!
Adding a new intent
When building an Alexa skill it is good to think of it as having a front-end and a back-end, the front-end is the part that matches the user's utterances to intents and the back-end — the code bit — decides how to handle the user's intent.
Go to Build | Intents, you'll notice that a few Intents already exist, any prefixed with AMAZON are required and should not be deleted, you'll also notice that a HelloWorldIntent
exists, which was created with the template, this is no longer needed and can be deleted.
Click Add Intent.
It is good practice to keep intents with no spaces and the first letter of words capitalised, also appending the word Intent at the end seems to be commonplace.
Adding utterances
In order for an Intent to be invoked the user must say something that you specify, this is where you specify what the user has to say.
So for my WordOfTheDayIntent
to be invoked, the user must say a phrase that more or less matches one of the utterances I've provided, Alexa does the heavy, natural language lifting here, it'll build a model and if the user's utterance is close enough, it'll make the decision to invoke my intent.
Click Save Model then Build Model.
Handling an intent in code
We now have an intent, but we don't actually return anything when that intent is invoked, we need to do that in code!
Go back to the Code section.
In the code there is a HelloWorldIntentHandler
Let's modify this for our intent.
Change the name of the handler to WordOfTheDayIntentHandler
. Scroll down to the bottom and add WordOfTheDayIntentHandler
to the exports.handler
(You can also get rid of the HelloWorldIntentHandler
we're replacing). Your code should look something like this:
exports.handler = Alexa.SkillBuilders.custom()
.addRequestHandlers(
LaunchRequestHandler,
WordOfTheDayIntentHandler,
HelpIntentHandler,
CancelAndStopIntentHandler,
FallbackIntentHandler,
SessionEndedRequestHandler,
IntentReflectorHandler)
.addErrorHandlers(
ErrorHandler)
.withCustomUserAgent('sample/hello-world/v1.2')
.lambda();
Next, back to the handler, let's modify this so that it uses our intent name. Change HelloWorldIntent
to WordOfTheDayIntent
, this is saying now that when the canhandle()
function gets called it'll check to see whether the intent name that's been invoked is WordOfTheDayIntent
and if it is, it'll call the handle()
function.
Let's add our word of the day! In this example I'll just hardcode the word of the day, but here you might want to call an API to get some information.
Your code should look something like this:
const WordOfTheDayIntentHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'WordOfTheDayIntent';
},
handle(handlerInput) {
const speakOutput = 'The word of the day is countenance. countenance is a persons facial expression. If you would like to hear the word of the day for a previous date, just ask';
const speakReprompt = 'If you would like to hear the word of the day for a previous date, just ask';
return handlerInput.responseBuilder
.speak(speakOutput)
.reprompt(speakReprompt)
.getResponse();
}
};
Testing an intent
Next, let's go back to Test and see if we can get our word of the day!
Bloody brilliant!
Slots
As explained earlier slots are input values provided in a user's request. As in our example, we want to have a slot so that we can gather the date the user has specified for retrieving the word of the day for that date, example:
"Alexa, what was the word of the day on the ninth of august".
We will be modifying our WordOfTheDayIntent
for this, we could potentially create a whole new intent for previous words of the day, but I think it fits nicely into this intent. So basically, if the user provides the date slot, we will return them the word of the day for that date!
Adding a slot
Go to Build | Intents | WordOfTheDayIntent next let's add some slots and new utterances. To add a slot you can just click a word in one of your utterances that will be replaced with the slot, or you can scroll down and click add new slot.
Alexa has a tonne of built-in slot types, in our example we're going to use the Amazon.Date
slot type. For more information on slot types.
Add a date slot.
Here's an example of what your new utterances with the slot will look like!
Hit Save Model then Build Model
Handling slots in code
Now that we can gather information from a slot we can handle this in our code, so if a user specifies a date for the word of the day, we can call a different API or perform some other function.
Go back to our code editor and back to our WordOfTheDayIntentHandler
.
We can retrieve our slot value using the following code:
const date = handlerInput.requestEnvelope.request.intent.slots.date.value;
we can do a check to see if that date has been filled and if so we can perform some other action, in this case, I'm simply going to change the reply to the user. So the final code will look like this:
const WordOfTheDayIntentHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'WordOfTheDayIntent';
},
handle(handlerInput) {
let speakOutput = 'The word of the day is countenance. countenance is a persons facial expression. If you would like to hear the word of the day for a previous date, just ask';
const speakReprompt = 'If you would like to hear the word of the day for a previous date, just ask';
const day = handlerInput.requestEnvelope.request.intent.slots.date.value;
if (date) {
speakOutput = `The word of the day on ${date} was clinomania. clinomania is an excessive desire to remain in bed`;
}
return handlerInput.responseBuilder
.speak(speakOutput)
.reprompt(speakReprompt)
.getResponse();
}
};
So if the user has specified a date, then we will output the word of the day being clinomania.
Testing our slot
Let's go back to the test environment and see if we can get the word of the day for a specific date!
Awesome!
Conclusion
And that's pretty much it, we've created our own Intents, Utterances and Slots and coded to handle them!
Hopefully this blog has put you in a position where you feel confident to have a crack at your own Alexa skill, I'd love to hear of some skill ideas you guys have in the comments, let me know if this blog has helped!
codeheir.com
If you happen to enjoy my writing, I'd bloody love it if you'd check out my personal programming blogging site, I blog a lot more on there!
https://codeheir.com
This blog is sponsored by Code Canvases
Make your room come alive with the coolest programming/coding canvases on the market. codecanvases.com is the number 1 seller for programming prints with 100% exclusively designed canvases. Get them now whilst they're 20% off!!
Top comments (0)