Tutorial: Build an Engaging Skill

Module 4: Collect Slots Turn-by-Turn

Welcome to module 4 of our introductory tutorial on building an engaging Alexa skill. In this module, we'll learn how to collect slots turn-by-turn with auto delegation to make the skill conversational.
Time required: 15 - 30 minutes
What you’ll learn:

  • How to collect slots turn-by-turn
  • How to use utterances, intents, slots, and auto-delegation
  • How to create a new IntentHandler to capture the slots and repeat them to the user

Introduction

In module 3, you built an Alexa skill that says, “Hello! Welcome to Cake Time. That was a piece of cake! Bye!”. In this module, you will make the skill more useful by having it ask the user for their birthday. When the user responds, the skill will understand and repeat the user's birthday back to them. To do this, you will need to use utterances, intents, and slots.
You will also learn how to use dialog management to have your skill automatically ask follow-up questions to collect required information. For example, if the user says, "I was born July 12th," dialog management will automatically ask the user what year they were born.

At the end of this module, your Cake Time skill will be able to ask the user a question, listen for the answer and respond to the user.

Use the Alexa developer console for this module. Log in to the console and open the Cake Time skill.

Step 1: Ask the user for their birthday

At the moment, the skill simply greets the user and exits. The welcome message helps set the context of the interaction—the user knows they are interacting with Cake Time. Now you need to capture the user's birthday to eventually calculate the number of days until the user's next birthday. To do that, update the skill with programming logic that instructs Alexa to ask for the user's birthday.

a. In the developer console, click the Code tab.

code nav link screenshot

Find the LaunchRequestHandler. Within the handler, the speakOutput variable is passed to the .speak() function. In the next step, update the string to ask the user for their birthday.

b. Within the LaunchRequestHandler, in the handle() function, find the line that begins with const speakOutput. Replace that line with the following:

const speakOutput = 'Hello! Welcome to Caketime. What is your birthday?';

Your code should now look like:

const LaunchRequestHandler = {

    canHandle(handlerInput) {

        return Alexa.getRequestType(handlerInput.requestEnvelope) === 'LaunchRequest';

    },

    handle(handlerInput) {

        const speakOutput = 'Hello! Welcome to Caketime. What is your birthday?';

Now, remember that after Alexa responds, the skill exits. You need to tell Alexa to listen for the user to respond. To do that, you will use the .reprompt() function, which you previously commented out.

c. Within the LaunchRequestHandler, in the handle() function, remove the double forward slash (//) before the .reprompt() function.

The .reprompt() function does two things:

  • Tells the skill to wait for the user to reply, rather than simply exiting
  • Allows you to specify a way to ask the question to the user again, if they don't respond

const speakOutput = 'Hello! Welcome to Caketime. What is your birthday?';

Note

A best practice is to make your reprompt text different from your initial speech text.

The user may not have responded for a variety of reasons. The skill should pose the initial question again but do so in a natural way. The reprompt should provide more context to help the user provide an answer. Specify the reprompt text by creating a new variable named repromptText.

 

d. Within the LaunchRequestHandler, in the handle() function, find the line that begins const speakOutput. Create a new line below it by clicking at the end of the line and pressing ENTER.

e. Copy and paste the following code on the new line: const repromptText = 'I was born November sixth, two thousand fourteen. When were you born?';

   handle(handlerInput) {

        const speakOutput = 'Hello! Welcome to Caketime. What is your birthday?';

        const repromptText = 'I was born Nov. 6th, 2014. When were you born?';    

 

        return handlerInput.responseBuilder

Notice the reprompt gives an example of what Alexa expects the user to say by having Alexa provide her own birthday in the format she is looking for. Providing examples like this is a best practice.

Note

Notice the numbers are spelled out in the reprompt text. You can use Speech Synthesis Markup Language (SSML) to have Alexa read "2014."

Now you want the code to pass the repromptText variable to the .reprompt() function.

 

f. Within the LaunchRequestHandler, in the handle() function, replace .reprompt(speakOutput) with .reprompt(repromptText) for Node.js, replace .ask(speak_output) with .ask(reprompt_text)

The handle() function within the LaunchRequestHandler should now look like the following:

    handle(handlerInput) {

        const speakOutput = 'Hello! Welcome to Caketime. What is your birthday?';

        const repromptText = 'I was born Nov. 6th, 2014. When were you born?';    

 

        return handlerInput.responseBuilder

            .speak(speakOutput)

            .reprompt(repromptText)

            .getResponse();

There is a potential complication with asking the user for their birthday. They might respond in many different ways. For example, the user might give only the month and day, or they might say something like, "Next Tuesday."

In this course, you won't handle all the different ways a user might respond, but we challenge you to account for them when you finish the course. Let's focus on a way to ensure that Alexa is able to collect the month, day, and year from the user.

Before moving on, save and deploy your updated code.

g. Click Save.

save button

h. Click Deploy.

deploy button

Note

Get into the habit of saving and deploying your changes regularly to ensure you don't lose anything. Save as you go!

The Cake Time skill can now ask and listen, but it can't respond yet. You need to update our skill's front end before testing it. Specifically, you need to create an intent to interpret the user's response to the skill's question.

Step 2: Use an intent and slots to capture information

Now make some adjustments to the skill's front end. Specifically, you need to create an intent that will interpret how the user responds to Alexa's question.

When you name an intent, think about what the intent is going to do. In this case, the intent is going to capture the user's birthday, so name it CaptureBirthdayIntent. Notice the words are not separated by spaces, and each new word begins with an uppercase letter.

a. Click the Build tab.

 

b. To the right of Intents, click Add. The Add Intent window opens.

add intent screenshot

c. Select Create custom intent and enter the following text for the name of the intent: CaptureBirthdayIntent

add intent screenshot

d. Click Create custom intent. The intent is created.

Note

Remember, an intent is an action to fulfill a user's request. An utterance is what invokes the intent. In response to the birthday question, a user might say, "I was born on November seventh, nineteen eighty three." You will add this utterance to the CaptureBirthdayIntent by typing it in exactly the way the user is expected to say it.

e. In the Sample Utterances field, type the following, and then press ENTER or click the + icon: I was born on November seventh nineteen eighty three

Notice that the text does not include punctuation.

add intent screenshot

Note

When finished, the Cake Time skill will be able to capture any birthday.

From this utterance, there are three key pieces of information to collect: month, day, and year. These are called slots. You need to let Alexa know which words are slots and what kind of slots they are.

Start with the month slot. In the utterance, you will replace the word representing the month (November) with the word month in curly brackets ({ }). This creates a slot called month. The utterance will then look like this: I was born on {month} seventh nineteen eighty three

There are two ways to create a slot. The first way is to select the word in the sample utterance where the slot should go and type the name of the slot in curly brackets (for example, {month}).

The second way is to select the word in the sample utterance and use the Select an Existing Slot dialog box when it appears. In the dialog box, click the field under Create a new slot, type the name of the slot without curly brackets (for example, month), and click Add.

intents screenshot

f. In the utterance, use either method of creating a slot to create a slot called month over the word November.

 

g. Repeat this process for the other variable pieces of information (day and year).

Your utterance should now look like this: I was born on {month} {day} {year}

What if the user omits the words I was born on? Account for this by adding a second utterance with only the slots.

h. In the Sample Utterances field, type the following, and then press ENTER or click the + icon: {month} {day} {year}

add intent screenshot

Note

When entering a sample utterance, you may need to press ENTER twice for the utterance to be added. You can also click the + icon.

Now, you should account for a few other potential slot combinations.

i. Enter each of the examples below as sample utterances. When you are finished, you should have six utterances.

{month} {day}
{month} {day} {year}
{month} {year}
I was born on {month} {day}
I was born on {month} {day} {year}
I was born in {month} {year}

You have let Alexa know what slots need to be collected (and covered some of the different patterns users might provide that information in). Now you need to define exactly what those slots are by assigning a slot type to each slot.

Scroll down the page to Intent Slots. This area displays the slots you have created.

intent slots screenshot

Slots are assigned from the Slot Type drop-down menu to the right of each slot.

There are two types of slot types: custom and built-in. Wherever possible, use built-in slots. Alexa manages the definitions of built-in slots. These slots begin with AMAZON followed by what they define (for example, AMAZON.Month).

If an applicable built-in slot does not exist, create a custom slot and define the values it represents. For this course, you will only use built-in slots.

intent slots screenshot

j. To the right of the month slot, select AMAZON.Month from the Slot Type drop-down menu.

k. For the day slot, select AMAZON.Ordinal as the slot type.

l. For the year slot, select AMAZON.FOUR_DIGIT_NUMBER as the slot type.

month day year slots

You have created an intent to collect the user's birthday.

But what about a user who doesn't respond with all three slot values? For example, a user who responds, "In July." Let's take a look at solving that problem.

m. At the top of the page, click Save Model.

save model button

Step 3: Use dialog management

Slots can be required or optional. That is, if you need a given value from the user, you can designate a slot as required using dialog management. Marking a slot as required triggers Alexa to actively work to fill it. Start by making each of the slots required.

a. In the Intent Slots section, to the right of the month slot, click Edit Dialog.

b. Under Slot Filling, toggle to make the slot required.

slot filling screenshot

The Alexa speech prompts field appears. Here, you will enter text for Alexa to say if the user fails to provide a value for the month slot.

c. In the field, type What month were you born in? and then press ENTER or click the + icon.

slot filling screenshot

d. Repeat the process for the day and year slots.

Note: Return to the screen where you entered the sample utterances by clicking CaptureBirthdayIntent in the left-hand panel.

Note

Now that the slots are required, if a user responds, "July nineteen eighty two," Alexa recognizes that the month and year slots are filled, but the day slot is not.

Alexa will prompt the user for each unfilled slot. In this example, Alexa would ask, "What day were you born?"

One of the great things about dialog management is that the skill doesn't break or get confused if the user leaves out a piece of information or provides it out of the expected order. Instead, Alexa takes on the responsibility of collecting information designated as required to ensure a useful experience.

You have built an intent that listens for the user's answer to the birthday question. When the user responds, Alexa collects the user's birthday month, day, and year. This information will be sent to the skill's backend code in a JSON request.

Before moving on, notice the HelloWorld intent in the left-hand panel. That is a leftover from the starter template that you don't need.

e. Delete the HelloWorldIntent intent by clicking the trash can icon to the right of it. When prompted, click Delete Intent.

Be careful to delete HelloWorldIntent and not CaptureBirthdayIntent.

helloworldintent screenshot

Note

You may notice other intents (such as AMAZON.HelpIntent) were automatically added to your skill. These are required for every skill and provide the user a means to cancel, stop, and get help. Do not remove these.

f. At the top of the page, click Save Model.

save model button

g. Click Build Model.

build model button

When you click Build Model, your skill starts to build the training data that will help Alexa know how to map what the user says to your skill's intents. It may take a minute for the model to build.

At this point, your skill can ask and listen. Now, make it respond.

Step 4: Define a new handler

To make the Cake Time skill respond, you need to update the backend.

a. Click the Code tab.

code nav link screenshot

Remember modifying the LaunchRequestHandler? This time, you are going to build a new handler. This handler will acknowledge that the user provided their birthday and repeat the birthday back to the user.

If you look at the code, you will notice the HelloWorldIntentHandler. But you deleted the HelloWorldIntent, right? Not entirely. The intent is gone from the front end, but the backend handler is still there. You need a new handler, so make things easier and reuse this handler for a new one called CaptureBirthdayIntentHandler.

b. Find the line that starts const HelloWorldIntentHandler. On that line, rename HelloWorldIntentHandler to CaptureBirthdayIntentHandler

c. Within the CaptureBirthdayIntentHandler, on the line that begins && handlerInput, change 'HelloWorldIntent' to 'CaptureBirthdayIntent'

This change ensures that the canHandle() function will be invoked when a CaptureBirthdayIntent request comes through. The handler code should now look like the following:

const CaptureBirthdayIntentHandler = {

    canHandle(handlerInput) {

        return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'

            && Alexa.getIntentName(handlerInput.requestEnvelope) === 'CaptureBirthdayIntent';

Now you need to update the logic within the handler so Alexa will confirm to the user that she heard their birthday. In this case, you will have Alexa read the birthday back to the user, like this: “Thanks, I'll remember that you were born on {month} {day} {year}.”

Start by creating three variables in the handler to save the slots the skill is collecting.

d. Within the CaptureBirthdayIntentHandler, find the line that begins handle(handlerInput) {. Create a new line below it.

e. Copy and paste the following code on the new line:

const year = handlerInput.requestEnvelope.request.intent.slots.year.value;
const month = handlerInput.requestEnvelope.request.intent.slots.month.value;
const day = handlerInput.requestEnvelope.request.intent.slots.day.value;

The handler code should now look like the following:

const CaptureBirthdayIntentHandler = {

    canHandle(handlerInput) {

        return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'

            && Alexa.getIntentName(handlerInput.requestEnvelope) === 'CaptureBirthdayIntent';

    },

    handle(handlerInput) {

        const year = handlerInput.requestEnvelope.request.intent.slots.year.value;

        const month = handlerInput.requestEnvelope.request.intent.slots.month.value;

        const day = handlerInput.requestEnvelope.request.intent.slots.day.value;

            

        const speakOutput = `Thanks, I'll remember that you were born ${month} ${day} ${year}.`;

        return handlerInput.responseBuilder

            .speak(speakOutput)

            //.reprompt('add a reprompt if you want to keep the session open for the user to respond')

            .getResponse();

    }

};

Next, update the speakOutput. To do this, use string interpolation. This allows you to drop the new variables into a text string. Here is an example of a string interpolation:

`Looks like you were born in ${month}`

This looks similar to a slot declaration, but there are two differences. First, notice the dollar sign ($) before the curly brackets ({ }). Second, the statement is encapsulated in backticks (`) instead of single or double quotation marks.

f. Within the CaptureBirthdayIntentHandler, in the handle() function, find the line that begins with const speakOutput. Replace that line with the following code:

const speakOutput = `Thanks, I'll remember that your birthday is ${month} ${day} ${year}.`;

You are almost finished. Remember changing the HelloWorldIntentHandler to CaptureBirthdayIntentHandler? In every skill that uses the SDK, there is a place to notify the SDK of the available handlers. This is called registering. Update the code to register the new handler.

g. Scroll down in the code until you find the line that begins exports.handler.

Under this line, notice the .addRequestHandlers() function. Within that function, notice the list of handlers in the skill. HelloWorldIntentHandler is listed, and you need to change it to CaptureBirthdayIntentHandler. Otherwise, the skill will give an error.

h. Within the .addRequestHandlers() function, replace HelloWorldIntentHandler with CaptureBirthdayIntentHandler

Be sure to leave the comma (,) after CaptureBirthdayIntentHandler when you make the replacement.

The handler code should now look like the following:

exports.handler = Alexa.SkillBuilders.custom()

    .addRequestHandlers(

        LaunchRequestHandler,

        CaptureBirthdayIntentHandler,

        HelpIntentHandler,

        CancelAndStopIntentHandler,

        SessionEndedRequestHandler,

i. Click Save.

save button

j. Click Deploy. Because of the new handler, your skill will take a few moments to deploy.

deploy button

Step 5: Test your skill

It is time to test! The Cake Time skill should now be able to do the following:

  • Ask the user for their birthday
  • Listen to the answer from the user and automatically follow up with questions if any required slots (month, day, year) are missing
  • Respond to the user by repeating their birthday

Let's test the skill.

a. Click the Test tab.

Remember that you can test by typing what the user would say in the box at the top left, or you can speak to the skill by clicking and holding the microphone icon and speaking.

b. Test your skill by opening Cake Time and responding when Alexa asks for your birthday.

test screenshot

Note

If you are testing by typing what the user would say, spell out the numbers (for example, November seventh nineteen eighty three). Otherwise, the numbers won't be understood. You may have noticed that numbers have been have purposefully spelled out throughout the course. This is only a requirement when typing. If you speak to the skill, the numbers are automatically converted.

Alexa should respond with, "Thanks, I'll remember that your birthday is {month} {day} {year}."

Go ahead and test what happens if you provide only the year, the year and the day, or other combinations. Alexa should prompt you for any slot values that you omit.

Wrap-up

At this point, your skill has become slightly more nuanced. It can ask the user for their birthday and repeat it back to the user. Congratulations!

However, while your skill can ask for a user's birthday, your skill doesn't remember it the next time the skill is opened. It would be a better user experience if Cake Time remembered the user's birthday. In the next section, you will learn how to make your skill remember things.

Code

If your skill isn't working or you're getting some kind of syntax error, download the code sample in Node.js or Python from the links below. Then, go to the Code tab in the Alexa developer console and copy and paste the code into the index.js file. Be sure to save and deploy the code before testing it.

Great job!

Continue to module 5 to learn how to add memory to your skill.