Collect Slots Turn-by-Turn

Step 2: Ask a question, get an answer

Now comes the fun part. You start to play the game. By the end of Step 2, you will ask the user a question, receive the user's answer, and repeat the user's answer.

"Why don't I check the user's answer?" you ask. Because your skill has to remember which question it asked the user. In the next module, you learn how to add memory to your skill. For now, all your skill knows is the last thing the user said to it.

Step 2 has four sub-steps:

  • First, add a custom GetBirthday intent with custom slots and dialog delegation
  • Next, update PlayGameHandler to ask a quiz question
  • Next, add the GetBirthdayIntentHandler code to receive data from the GetBirthday intent
  • Last, test your skill to make sure it works so far

First, add a custom GetBirthday intent with custom slots and dialog delegation

  1. In the developer console, click the Build tab.

  2. In the left-hand menu, click Interaction Model, and then click Intents.

  3. In the right-hand pane, under Intents, click the +Add Intent button. This action opens the Add Intent page, where you previously added AMAZON.YesIntent.

    Add Intent existing

  4. Next to Create custom intent, select the radio button.

  5. In the box underneath, enter GetBirthdayIntent, and then click the Create custom intent button. This action takes you to your configuration panel for the intent, where you can add sample utterances.

    Quick review of sample utterances and slots As you learned about in Module 2, to create an interaction model, you define requests (intents) and words (sample utterances). Sample utterances are things your user might say. For example, your user might say, "He was born in November 1973," or just "November 1973." You'll need to enter a list of ways users might phrase their answer to the birthday question. The words or phrases that represent variable information in the utterances are the slots for your intents. You define this variable information so you can extract it from the utterances. For example, instead of "November 1973," you would use "{month} {year}." Instead of " "He was born in November 1973," you would use "He was born in {month} {year}."

  6. In the text box below Sample Utterances, enter {month} {year}.

    GetBirthdayIntent

  7. On the right side of the Sample Utterances text box, click the plus sign (+) to add your slots. After you click the plus sign (+), you should see something like the following screenshot.

    GetBirthdayIntent

  8. In the Sample Utterances text box, add more sample utterances. They help train Alexa to recognize when a customer is trying to answer a quiz question, and where to find the important information in the answer.

    Tip: How to write sample utterances

    A great way to come up with sample utterances is to role-play. Get a few celebrity birthdays together, and then go out and quiz friends, family, or co-workers. You're Alexa, they're the player, and you write down the way they answer the questions. The following list shows some sample utterances:
    - Oh she was born in {month} of {year}
    - I'm guessing {year} and maybe {month}
    - Okay I know it was {year} but the month maybe {month}

    Notice how many of these samples have words around the month and year that aren't of much value to you. That's how people speak conversationally. People rephrase the question as they answer it ("she was born in"). People add personal information ("I'm guessing"). People take a position ("I'm going to say"). The more sample utterances you provide, the more ways Alexa has to recognize that the user is trying to answer the question.
  9. In the Sample Utterances text box, add the individual slots all by themselves. Add a sample utterance of just {month}. Next add a sample utterance of just {year}. Sometimes you'll get an incomplete answer and Alexa still needs to know it belongs to this intent.

    When you finish adding possible sample utterances, it's time to define your slots. You've named them, but now you need to tell Alexa what will be in them.

  10. Scroll down the page to view the Intent Slots section that lists the slots you created.

  11. In the month row, click the Select a slot type menu, and begin to enter month. This action returns an Amazon built-in slot type, AMAZON.Month.

    AMAZON.Month

  12. Select AMAZON.Month.

    Just as Amazon has an AMAZON.YesIntent default intent, Amazon has optimized many common slot types for you. Not all of the slot types are as simple as months. There are actors, movies, books, and more.

  13. In the year row, click the Select a slot type menu, and begin to enter four. This action returns an Amazon built-in slot type, AMAZON.FOUR_DIGIT_NUMBER.

  14. Select AMAZON.FOUR_DIGIT_NUMBER.

  15. Scroll back up to the top of the screen, and click Save Model to save your work on the interaction model.

    About dialog delegation

    The last part of Step 2 deals with dialog delegation. You apply dialog delegation so that your skill can deal with incomplete answers. For example, when a user answers the birthday question with just the year or just the month, you use dialog delegation so that Alexa follows up with the user to get the complete answer before sending it to the access-layer code to be handled.

  16. In the Intent Slots section, locate the month row.

  17. Under the ACTIONS column of the month row, click the Edit Dialog link.

  18. Under Slot Filling, next to Is this slot required to fulfill the intent?, click the switch to turn it on. Two new boxes appear: Alexa speech prompts and User utterances.

    Slot Filling

    About Alexa speech prompts

    Alexa speech prompts are ways Alexa might ask for the month that the user left out of their answer. You might have Alexa say, "Thanks. What month were they born in?" It's okay to end sentences Alexa says with a preposition. Speaking with Alexa is supposed to feel natural and conversational. In conversations, many people end sentences in prepositions. You don't have to go out of your way to be informal, but you don't need to avoid it either.

  19. In the Alexa speech prompts and User utterances boxes, enter prompts and utterances to provide variety of ways you want Alexa to request the information and the ways you anticipate users might answer.

  20. When you're done adding prompts and utterances, scroll to the top of the screen, click Save Model, and use your browser's back control to go back to the Intents/GetBirthdayIntent page, then and perform all the same steps with the year intent slot.

  21. When you're done with year, click Save Model again, and use your browser's back control to go back to the Intents/GetBirthdayIntent page.

  22. From the Dialog Delegation Strategy menu, select enable auto delegation. This setting allows Alexa to ask the user follow-up questions until all the required slots are filled.

  23. Click Save Model, and then click Build Model. The build step might take a couple of minutes.

Next, update PlayGameHandler to ask a quiz question

  1. In the developer console, click the Code tab.
  1. In the left file nav, under Skill Code click on lambda to select the folder. Next click New File. Next enter "lambda/celebrityFunctions.js" under File Path and click Create File. A new tab on the editor will open named celebrityFunctions.js.

You don't need to learn how to pick a random celebrity from a list. This workshop provides a set of helper functions to do that and a few other things for you.

  1. Paste the following code into the new tab named celebrityFunctions.js (Node.js) or celebrityFunctions.py (Python) and click Save.
/**
 * Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: LicenseRef-.amazon.com.-AmznSL-1.0
 * Licensed under the Amazon Software License  http://aws.amazon.com/asl/
**/

const celebs = require('./documents/birthday.json');

const MONTHS = {"january": 0, "february": 1, "march": 2, "april": 3, "may": 4, "june": 5, "july": 6, "august": 7, "september": 8, "october": 9, "november": 10, "december": 11}

const getRandomCeleb = function(pastCelebs = []) {
  const filtered = celebs.filter(c => !pastCelebs.find(pc => pc.id === c.id));
  return filtered.length > 0
    ? filtered[Math.floor(Math.random() * filtered.length)]
    : {"id":0, "name":null, "birthday": null};
};

const checkAnswer = function(currentCeleb, month, year) {
  const birthday = new Date(currentCeleb.birthday);
  return birthday.getMonth() === MONTHS[month.toLowerCase()] && birthday.getFullYear() === parseInt(year);
};

const getHour = function(userTimeZone) {
  const currentDateTime = new Date(new Date().toLocaleString("en-US", {timeZone: userTimeZone}));
  return currentDateTime.getHours();
};

module.exports = {
  getRandomCeleb,
  checkAnswer,
  getHour
};
  1. In the left file nav, under Skill Code click on lambda to select the folder. Next click New File. Next enter "lambda/celebrityFunctions.py" under File Path and click Create File. A new tab on the editor will open named celebrityFunctions.py.

You don't need to learn how to pick a random celebrity from a list. This workshop provides a set of helper functions to do that and a few other things for you.

  1. Paste the following code into the new tab named celebrityFunctions.js (Node.js) or celebrityFunctions.py (Python) and click Save.
# Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: LicenseRef-.amazon.com.-AmznSL-1.0
# Licensed under the Amazon Software License  http://aws.amazon.com/asl/

import json
import random
import datetime
import pytz

CELEBS = []
MONTHS = {"january": 1, "february": 2, "march": 3, "april": 4, "may": 5, "june": 6, "july": 7, "august": 8, "september": 9, "october": 10, "november": 11, "december": 12}

with open("./documents/birthday.json") as birthday_doc:
    CELEBS = json.load(birthday_doc)

def get_random_celeb(past_celebs = []):

    remaining = [d for d in CELEBS if d not in past_celebs]

    if len(remaining) > 0:
        random.shuffle(remaining)
        return remaining[0]
    else:
        return {
            "id": 0,
            "name": None,
            "birthday": None
        }

def check_answer(current_celeb, month, year):
    d = datetime.datetime.strptime(current_celeb["birthday"], '%Y-%m-%d')
    return d.month == MONTHS[month.lower()] and d.year == int(year)

def get_hour(user_time_zone):
    d = datetime.datetime.now(pytz.timezone(user_time_zone))
    return d.hour

In the left file nav, under Skill Code double click to open requirements.txt. Add a new line at the bottom of the file so the contents look like below and click Save.

boto3==1.9.216
ask-sdk-core==1.11.0
pytz

Next, we will provide a simple JSON file that has famous individuals' birthdays to use as our list to randomly pull from.

  1. In the left file nav, under Skill Code click the documents folder to select it. Next click New File. Next enter "lambda/documents/birthday.json" under File Path and click Create File. A new tab on the editor will open named birthday.json.

  2. Paste the following JSON document into this new tab named birthday.json and click Save.

[
  {"id":1, "name":"Kevin Bacon", "birthday":"1958-07-08"},
  {"id":2, "name":"Antonio Banderas", "birthday":"1960-08-10"},
  {"id":3, "name":"Pierce Brosnan", "birthday":"1953-05-16"},
  {"id":4, "name":"Sandra Bullock", "birthday":"1964-07-26"},
  {"id":5, "name":"Steve Buscemi", "birthday":"1957-12-13"},
  {"id":6, "name":"Nicolas Cage", "birthday":"1964-01-07"},
  {"id":7, "name":"Jim Carrey", "birthday":"1962-01-17"},
  {"id":8, "name":"George Clooney", "birthday":"1961-05-06"},
  {"id":9, "name":"Sean Connery", "birthday":"1930-08-25"},
  {"id":10, "name":"Leonardo DiCaprio", "birthday":"1974-11-11"},
  {"id":11, "name":"Samuel L. Jackson", "birthday":"1948-12-21"},
  {"id":12, "name":"Jennifer Lopez", "birthday":"1969-07-24"},
  {"id":13, "name":"Keanu Reeves", "birthday":"1964-09-02"},
  {"id":14, "name":"Robert Downey Jr.", "birthday":"1965-04-04"},
  {"id":15, "name":"Spike Lee", "birthday":"1957-03-20"},
  {"id":16, "name":"Aishwarya Rai", "birthday":"1973-11-01"},
  {"id":17, "name":"Awkwafina", "birthday": "1988-06-02"},
  {"id":18, "name":"Priyanka Chopra", "birthday":"1982-07-18"},
  {"id":19, "name":"Randall Park", "birthday":"1974-03-23"},
  {"id":20, "name":"John Boyega", "birthday":"1992-03-17"}
]
  1. Click back on the index.js or lambda_function.py tab to continue editing the handlers. Find your PlayGameHandler handler. Now you'll add a few lines of code to get a random celebrity birthday and ask about it.

  2. Replace this code.

const speakOutput = 'Welcome to the yes handler.';
speak_output =  f"Welcome to the Yes handler."

With the following code, by copying and pasting it into the index.js or or lambda_function.py file.

//Import the celebrity functions and get a random celebrity.
const cfunctions = require('./celebrityFunctions.js');
const celeb = cfunctions.getRandomCeleb();
var title = celeb.name;
//Ask the question
const speakOutput = `In what month and year was ${celeb.name} born?`;

The handler calls the celebrityFunctions getRandomCeleb method, and to return a random celebrity. Then, the workshop uses a template string (with backticks) introduced in Module 3.

Rather than adding together pieces of a string, the workshop just includes the variable with ${variable name}, so long as the string is between backticks instead of single or double quotes. This is convenient and much more readable; especially if you have many variables to include.

from celebrityFunctions import get_random_celeb
celeb = get_random_celeb()
title = celeb["name"]
speak_output =  f'In what month and year was {celeb["name"]} born?'

The handler calls the celebrityFunctions get_random_celeb method, and to return a random celebrity. Then, the workshop uses a f-string introduced in Module 3.

Rather than adding together pieces of a string, the workshop just includes the variable with f'{variable name}', so long as the string starts with f' or f". This is convenient and much more readable; especially if you have many variables to include.

Replace the following strings that appear with the APL document on-screen.

  1. Replace this code.
Title: 'You said "yes"!!!',
Subtitle: 'You have made me so happy!',
"Title": 'You said "yes"!!!',
"Subtitle": 'You have made me so happy!',

With the following code, by copying and pasting it into the index.js or lambda_function.pyfile.

Title: title,
Subtitle: 'What month and year were they born?',
"Title": title,
"Subtitle": 'What month and year were they born?',
  1. In the upper-right corner of the Code tab page, click Save, and then click Deploy to deploy your code.

  2. (Optional) Test your new code to make sure you're getting a celebrity question asked by clicking the Test tab, and then following the instructions in Step 1, sub-step 4: Test your skill to make sure your code works so far.

Next, add the GetBirthdayIntentHandler code to receive data from the GetBirthday intent

In this sub-step, you add the GetBirthdayIntentHandler code to receive data from the GetBirthday intent in the same way that you earlier created the PlayGameHandler by copying the LaunchIntentHandler, and then pasting a copy of LaunchIntentHandler in under the original.

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

  2. Copy the PlayGameHandler and paste it in a couple of lines after the original PlayGameHandler definition, but before the beginning of the HelloWorldIntentHandler.

  3. Change PlayGameHandler to GetBirthdayIntentHandler in the newly pasted code.

  4. Scroll down to the list of handlers at the bottom of the index.js or lambda_function.pyfile, and then add GetBirthdayIntentHandler, below PlayGameHandler,.

  5. Next, change the canHandle() or can_handle() of the GetBirthdayIntentHandler to return true if the intent is GetBirthdayIntent. Replace this code.

Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.YesIntent'
and ask_utils.is_intent_name("AMAZON.YesIntent")(handler_input)

With the following code, by copying and pasting it into the index.js or lambda_function.py file.

Alexa.getIntentName(handlerInput.requestEnvelope) === 'GetBirthdayIntent'
and ask_utils.is_intent_name("GetBirthdayIntent")(handler_input)

Now, when a user answers a question, the slot values are sent to this handler to be handled. But how do you get the slot values?

  1. Scroll down into the handle function, and then replace in this code.
//Import the celebrity functions and get a random celebrity.
const cfunctions = require('./celebrityFunctions.js');
const celeb = cfunctions.getRandomCeleb();
var title = celeb.name;
//Ask the question
const speakOutput = `In what month and year was ${celeb.name} born?`;
from celebrityFunctions import get_random_celeb
celeb = get_random_celeb()
title = celeb["name"]
speak_output =  f'In what month and year was {celeb["name"]} born?'

With the following code, by copying and pasting it into the index.js or lambda_function.py file.

//Get the slot values
var year = handlerInput.requestEnvelope.request.intent.slots.year.value;
var month = handlerInput.requestEnvelope.request.intent.slots.month.value;

//Share the answer
const speakOutput = `Your answer was ${month} of ${year}. Would you like to try again?`;
year = ask_utils.request_util.get_slot(handler_input, "year").value
month = ask_utils.request_util.get_slot(handler_input, "month").value

# Share the answer
speak_output = f'Your answer was {month} of {year}. Would you like to try again?'
  1. Scroll down to the APL section, and then replace this code.
Title: title,
Subtitle: 'What month and year were they born?',
"Title": title,
"Subtitle": 'What month and year were they born?',

With the following code, by copying and pasting it into the index.js or lambda_function.py file.

Title: month + ', ' + year,
Subtitle: 'Try again?',
"Title": f'{month}, {year}',
"Subtitle": 'Try again?',
  1. In the upper-right corner of the Code tab page, click Save, and then click Deploy to deploy your code.

    These code replacements are placeholders. In the next module, you'll learn how to add short-term and long-term memory to your skill so it can remember which question it asked, the score for the session, and more.

  2. Test your new code with the random celebrity birthday quiz by clicking the Test tab, and then following the instructions in Step 1, sub-step 4: Test your skill to make sure your code works so far.

    March 1992 screenshot

    The basic structure of your skill's game is in place.