menu
arrow_back

Building an Alexa Skill with Lambda, API Gateway, DynamoDB and SageMaker

11m setup · 120m access · 90m completion
Connection Details

Warning: Do not transmit data into the AWS Console that is not related to Qwiklabs or the lab you are taking.

8 Credits

info_outline
This lab costs 8 Credits to run. You can purchase credits or a subscription under My Account.

Building an Alexa Skill with Lambda, API Gateway, DynamoDB and SageMaker

SPL-203 - Version 1.0.0

© 2018 Amazon Web Services, Inc. and its affiliates. All rights reserved. This work may not be reproduced or redistributed, in whole or in part, without prior written permission from Amazon Web Services, Inc. Commercial copying, lending, or selling is prohibited.

Errors or corrections? Email us at aws-course-feedback@amazon.com.

Other questions? Contact us at https://aws.amazon.com/contact-us/aws-training/

Overview

In this lab, you will create an Alexa skill called Bootcamp Assistant. The Bootcamp Assistant skill guides conference attendees by giving information such as breakfast/lunch time, directions to a meeting room, and whether a particular meeting room is on a floor. You will create the skill using the Amazon Alexa Developer Console. You will sign in to the console, create a new skill, define the necessary utterances, intents and slots and test the skill using the Alexa Simulator.

The Bootcamp Assistant skill has an AWS Lambda backend. The Lambda function contains all the code necessary for the intents. You will front some of the Lambda functions of the skill with Amazon API Gateway APIs. The data for the skill is stored in a DynamoDB table. In the last task of this lab, you will create an Amazon Sagemaker Notebook and train the model with sample data. The model will then be able to predict activities for the skill user.

All of the backend components such as the Lambda functions, the DynamoDB table, and some of the API Gateway APIs are being created as a part of your lab setup. You will be given instructions to review the code at the appropriate locations in the lab. You will also be given instructions to configure the necessary variables and run the scripts to set up the backend components.

Topics Covered

By the end of this lab, you will be able to:

  • Log in to the Alexa Developer Console and define custom slots and intents.
  • Create an utterance that uses the defined slots and intents.
  • Create and integrate a Lambda function that backs an Alexa skill.
  • Integrate your skill with APIs.
  • Create an Amazon SageMaker notebook instance.
  • Create an Amazon SageMaker machine learning model.
  • Run a real-time prediction using Amazon SageMaker endpoint.

Prerequisites

This lab requires:

  • An Amazon Developer account - Sign up at https://developer.amazon.com/alexa
  • Success logging into the Amazon Developer Console.
  • Access to a notebook computer with Wi-Fi, a working microphone and Microsoft Windows, Mac OS X, or Linux (Ubuntu, SuSE, or Red Hat).
    • The qwikLABS lab environment is not accessible using an iPad or tablet device, but you can use these devices to access the student guide.
  • For Microsoft Windows users: Administrator access to the computer.
  • An Internet browser such as Chrome, Firefox, or IE9 (previous versions of Internet Explorer are not supported).
  • An SSH client such as PuTTY.
  • Familiarity with basic navigation of the AWS Management Console and comfort with editing scripts using a text editor.

Start Lab

Notice the lab properties below the lab title:

  • setup - The estimated time to set up the lab environment
  • access - The time the lab will run before automatically shutting down
  • completion - The estimated time the lab should take to complete
  1. At the top of your screen, launch your lab by clicking Start Lab

If you are prompted for a token, use the one distributed to you (or credits you have purchased).

A status bar shows the progress of the lab environment creation process. The AWS Management Console is accessible during lab resource creation, but your AWS resources may not be fully available until the process is complete.

  1. Open your lab by clicking Open Console

This will automatically log you into the AWS Management Console.

Please do not change the Region unless instructed.

Common login errors

Error : Federated login credentials

If you see this message:

  • Close the browser tab to return to your initial lab window
  • Wait a few seconds
  • Click Open Console again

You should now be able to access the AWS Management Console.

Error: You must first log out

If you see the message, You must first log out before logging into a different AWS account:

  • Click click here
  • Close your browser tab to return to your initial Qwiklabs window
  • Click Open Console again

Task 1: Build an Alexa Skill with AWS Lambda Backend

In this task, you will create an Alexa skill called Bootcamp Assistant and add intents to the skill which will give you information about breakfast/lunch time and whether a particular meeting room exists on a floor. You will also create and integrate the backend Lambda function for the skill. The task is divided into sections with step-by-step instructions.

Below is a high level diagram of the task.

Below is the sample map of the meeting rooms used for this lab.

Section A: Build the Skill in Alexa Developer Console

  1. Open a web browser and paste the following link: https://developer.amazon.com/alexa

  2. Click Sign In at the top right corner.

  3. Log in using your Amazon.com account credentials.

  4. At the top left of the screen, click Skill Builders.

  5. Click Start a Skill.

  6. Click Create Skill then configure:

  • Skill name:
  • Click Create skill.
  1. On the Choose a template page, select Start from scratch and click Choose.

  2. In the left navigation pane, click Invocation, then configure:

  • Skill Invocation Name:
  • At the top of the screen, click Save Model.
  1. In the left navigation pane, next to Slot Types, click Add, then configure:
  • Create custom slot type:
  • Click Create custom slot type.
  1. For Slot Values, enter the values below one at a time. Click the button in the text box for each value.
Day 1
Ruby
Otter
Arizona
Coral
Kumo
Doppler
Oscar
Registration

  1. In the list of slot values you just added, locate the Registration row add the below synonyms under the SYNONYMS (OPTIONAL) column one by one and click the button for each synonym.
check in
Register

  1. In the left navigation pane, next to Intents, click Add, then configure:
  • Create custom intent:
  • Click Create custom intent.
  1. For Sample Utterances, add the following one by one. Click the button in the textbox for each utterance.
Does this floor have {RoomName}
Is {RoomName} on this floor

Bonus: Following the same pattern, add any other utterance you feel appropriate.

Note: The current backend logic in AWS Lambda only has the ability to respond Yes or No to whether a room is on this floor. Any additional utterances will need to adhere to what the backend logic is capable of responding to. Suggested utterance:

  1. Scroll down to Intent Slots.

  2. In the Intent Slots list, under the SLOT TYPE column, select RoomName from the dropdown list.

  3. In the left navigation pane, next to Slot Type, click Add, then configure:

  • Create custom slot type:
  • Click Create custom slot type.
  1. For Slot Values, add the following values one at a time. Click the button in the text box each time you add the value.
Breakfast
Lunch
Dinner
  1. At the top of the screen, click Save Model.

  2. In the left navigation pane, next to Intents, Click Add, then configure:

  • Create custom intent:
  • Click Create custom intent.
  1. For Sample Utterances, add the following sample utterances. You do not need to use the Select an Existing Slot pop up. Simply click the button in the text box each time you add the utterance.
When is {Activity}
When {Activity}
  1. Feel free to add any other utterance you feel appropriate. Suggested utterance:

  2. Scroll down to the Intent Slots section.

  3. In the Intent Slots section, under the SLOT TYPE column, select Activity from the dropdown list.

  4. On the left side navigation pane, click JSON Editor and review the code to validate that there are no errors.

Note: The Skill Builder will do syntax checking to ensure the JSON is well formed.

  1. Click Build Model at the top. Note: The Build Model icon changes to a processing icon. In the meantime, you may proceed to the next section.

Section B: Create the Lambda Backend for the Skill

In this section, you will create the Lambda function to power your Alexa skill.

  1. Click Open Console found to the left side of these instructions.

  2. At the top right corner of the AWS Management Console, make sure that the region is US East (N. Virginia).

  3. In the AWS Management Console, click Services, then click Lambda to open the Lambda dashboard.

  4. Click Create function, then configure:

  • Name:
  • Runtime: Python 2.7
  • Role: Choose an existing role
  • Existing role: lambda_lab_role
  • Click Create function.
  1. At the top of the screen, copy the Lambda function ARN to your text editor.

The Lambda function ARN will look similar to: arn:aws:lambda:us-east-1:823938157884:function:task1_meeting_assistant

  1. Scroll down to the Function code section.

  2. Delete the existing code and copy the following code and paste it in the lambda_function file:

#!/usr/bin/env python

"""
Code for the AWS Lambda backing the Alexa skill.

Purpose:
1) Return whether a room type is on this floor
2) What time is a given meal served
"""


from __future__ import print_function
import traceback
import boto3
import time
import json
import uuid
import datetime
from boto3.dynamodb.conditions import Key, Attr

def lambda_handler(event, context):
    """
    The controller for how all the different Alexa event types are handled.  Later, a sub controller will handle
    the intent routing.

    :param event: The event object, describing type and attributes of the event
    :param context: The context for which the event occured, namely the Lambda configuration
    :return: The speech and card info for alexa
    """

    # Debugging info

    print("event.session.application.applicationId=" +
          event['session']['application']['applicationId'])
    print(event)

    if event['session']['new']:
        on_session_started({'requestId': event['request']['requestId']},
                           event['session'])

    # Switch for request type
    if event['request']['type'] == "LaunchRequest":
        return on_launch(event['request'], event['session'])
    elif event['request']['type'] == "IntentRequest":
        return on_intent(event['request'], event['session'])
    elif event['request']['type'] == "SessionEndedRequest":
        return on_session_ended(event['request'], event['session'])


def on_session_started(session_started_request, session):
    """
    Handler for new sessions
    For this purpose, only debug
    :param session_started_request:
    :param session: The session associated with this request
    :return: None
    """
    print("on_session_started requestId=" + session_started_request['requestId']
          + ", sessionId=" + session['sessionId'])


def on_launch(launch_request, session):
    """
    Handler for a empty launch request

    :param launch_request:
    :param session: The session associated with this request
    :return: None
    """

    print("on_launch requestId=" + launch_request['requestId'] +
          ", sessionId=" + session['sessionId'])
    # Dispatch general welcome message
    return get_welcome_response()


def on_intent(intent_request, session):
    """
    Handler for all events - This is the central intent controller, determining how each intent is routed.

    :param intent_request: Request object associated with this intent
    :param session: Any existing session information
    :return: The card and speech for Alexa to render
    """

    print("on_intent requestId=" + intent_request['requestId'] +
          ", sessionId=" + session['sessionId'])

    intent = intent_request['intent']
    intent_name = intent_request['intent']['name']

    try:
        # Dispatch to your skills intent handlers
        if intent_name == 'CheckRoom':
            return check_room_existence(intent, session)
        if intent_name == 'WhenActivity':
            return check_when_activity(intent, session)
        else:
            raise ValueError("Invalid intent")
    except Exception as ex:
        traceback.print_exc()
        return build_response({}, build_speechlet_response(
        "Error processing your request", "I was unable to properly process your request", "I was unable to properly process your request", True))

def on_session_ended(session_ended_request, session):
    """
    How to end the session when requested (Cleanup)

    :param session_ended_request:
    :param session: Session object associated with termination
    :return:
    """

    print("on_session_ended requestId=" + session_ended_request['requestId'] +
          ", sessionId=" + session['sessionId'])
    # add cleanup logic here

# --------------- Functions that control the skills behavior ------------------


def get_welcome_response():
    """
    A basic welcome skill response if opened without parameters - Not used
    :return: The speech and card associated with the skill
    """

    session_attributes = {}
    card_title = "Welcome"
    speech_output = "Welcome to the Bootcamp Assistant skill. " \
                    "To use this application please ask, " \
                    "Hi Alexa, please ask Bootcamp Assistant if this floor has a registration"
    # If the user either does not reply to the welcome message or says something
    # that is not understood, they will be prompted again with this text.
    reprompt_text = speech_output
    should_end_session = False
    return build_response(session_attributes, build_speechlet_response(
        card_title, speech_output, reprompt_text, should_end_session))


def handle_session_end_request():
    """
    Handler to output when everything is cleaned up
    :return: The speech and card associated with the skill
    """
    card_title = "Session Ended"
    speech_output = "Thank you for using our bootcamp assistant. " \
                    "Have a nice day! "
    # Setting this to true ends the session and exits the skill.
    should_end_session = True
    return build_response({}, build_speechlet_response(
        card_title, speech_output, None, should_end_session))


def check_access(intent, session):
    """
    An access handler to be defined to handle who can access this lambda.  At a minimum this should include a check
    on the skill id.

    :param intent: What intent object was invoked
    :param session: Session associated with the intent
    :return: a Boolean whether access is allowed
    """

    # Consider checking the Skill ID
    return True




def check_when_activity(intent, session):
    """
    Checks when a given activity is occuring using a pre-defined table.

    :param intent: Intent object (including slots for the intent)
    :param session: Any existing session information
    :return:
    """
    card_title = 'Response'
    error_speech_output = 'I was unable to understand what activity you were referring to'
    session_attributes = {}
    should_end_session = True

    activities = {
        'breakfast': {
            'start' : datetime.time(6,0,0),
            'end': datetime.time(9,0,0)
        },
        'lunch': {
            'start': datetime.time(11, 0, 0),
            'end': datetime.time(13, 0, 0)
        },
        'dinner': {
            'start': datetime.time(17, 0, 0),
            'end': datetime.time(19, 0, 0)
        },

    }

    if check_access(intent, session) == False:
        return build_response(session_attributes, build_speechlet_response(
            card_title, error_speech_output, error_speech_output, should_end_session))

    try:
        activity = intent['slots']['Activity']['value']
    except KeyError:
        return build_response(session_attributes, build_speechlet_response(
            card_title,  error_speech_output, error_speech_output, should_end_session))
    # We are assuming these are not unicode
    if activity in activities:
        start = activities[activity]['start'].strftime("%H:%M")
        end = activities[activity]['end'].strftime("%H:%M")

        speech_output = activity + " starts at " + start + " and ends at " + end

    else:
        speech_output = "I was unable to understand what activity you were referring to"

    return build_response(session_attributes, build_speechlet_response(
        card_title, speech_output, speech_output, should_end_session))


def check_room_existence(intent, session):
    """
    Specific skill intent, checking the existence of a room.

    This uses a pre-defined dictionary of rooms to determine what is available and what is not.  In more advanced
    intents, this will be done with DynamoDB.

    :param intent: The context object associated with the intent
    :param session:  The session object associated with the intent
    :return: the speed and card associated with the intent
    """

    card_title = "Response"
    session_attributes = {}
    should_end_session = True
    room_dict = {
        'day 1': {
            'speech': 'Day 1'
        },
        'ruby': {
            'speech': 'Ruby'
        },
        'otter': {
            'speech': 'otter'
        },
        'arizona': {
            'speech': 'arizona'
        },
        'coral': {
            'speech': 'coral'
        },
        'kumo': {
            'speech': 'kumo'
        },
        'doppler': {
            'speech': 'doppler'
        },
        'oscar': {
            'speech': 'oscar'
        },
        'registration': {
            'speech': 'registration'
        }
    }


    if check_access(intent, session):
        try:
            room_name = intent['slots']['RoomName']['value']
        except KeyError:
            speech_output = "I was unable to understand which point of interest you were referring to"
            reprompt_text = speech_output
            return build_response(session_attributes, build_speechlet_response(
                card_title,  speech_output, reprompt_text, should_end_session))
        # We are assuming these are not unicode
        if room_name.lower() in room_dict:
            room = room_dict[room_name.lower()]
            print (room)
            speech_output = "Yes, " + room['speech'] + " is on this floor"

        else:
            speech_output = "Hello, I cannot find that room on this floor"
        reprompt_text = speech_output
    else:
        speech_output = "I do not see a device with that id registered in your interested group"
        reprompt_text = speech_output
    return build_response(session_attributes, build_speechlet_response(
        card_title, speech_output, reprompt_text, should_end_session))

def build_speechlet_response(title, output, reprompt_text, should_end_session):
    """
    Converts the coded parameters to the expected response object

    :param title: Card title to be displayed
    :param output: The speech
    :param reprompt_text: If reprompt is required, what is the reprompt test
    :param should_end_session: Should this end the session?
    :return: object response
    """

    return {
        'outputSpeech': {
            'type': 'PlainText',
            'text': output
        },
        'card': {
            'type': 'Standard',
            'title': title,
            'content': output,
            'text': output
        },
        'reprompt': {
            'outputSpeech': {
                'type': 'PlainText',
                'text': reprompt_text
            }
        },
        'shouldEndSession': should_end_session
    }


def build_response(session_attributes, speechlet_response):
    """
    Builds the wrapped response for Alexa
    :param session_attributes: Session attributes to be maintained
    :param speechlet_response: The speech response object (including card information)
    :return: The wrapped object
    """

    return {
        'version': '1.0',
        'sessionAttributes': session_attributes,
        'response': speechlet_response
    }

  1. At the top of the screen, click Save.

  2. Scroll to the top of the screen and expand Designer.

  3. In the Add triggers list, click Alexa Skills Kit.

  4. Scroll down to the Configure triggers section, then configure:

  • Skill ID verification: Disable
  • Click Add at the bottom right corner.

You may ignore the error below, if you see it. For the purpose of this lab, you are not setting the Skill ID verification to Enable.

  1. At the top of the screen, click Save.

Section C: Integrate the Lambda Function with the Skill

  1. Go back to the Alexa Developer Console. You should see the Bootcamp Assistant skill you just created.

  2. In the left side navigation pane, click Endpoint.

  3. Select the AWS Lambda ARN option.

  4. In the AWS Lambda ARN option, for Default Region, type the task1_meeting_assistant Lambda ARN you made a note of in an earlier step.

  1. At the top of the screen, click Save Endpoints.

Section D: Test the Skill

  1. On the top menu bar of the Alexa Developer Console, click Test.

  2. Toggle the Test is disabled for this skill button to ON to turn on the tests.

It should now show Test is enabled for this skill.

  1. In the Alexa Simulator section of the page, type the first question from the list below in the text box:
ask bootcamp assistant is Kumo on this floor
ask bootcamp assistant is Oscar on this floor
ask bootcamp assistant when is lunch
ask bootcamp assistant when lunch
  1. Press ENTER on your keyboard. You should hear Alexa's response.

  2. You can see the request JSON on the left, and the response JSON on the right. They should look similar to the image below.

  1. Type the second question from the list and press ENTER again to hear Alexa's response.

  2. You can also click the blue colored play icon to listen to the JSON response.

  3. In the AWS Management Console, go to the Lambda dashboard and open the task1_meeting_assistant Lambda function.

  4. Scroll down to the function code and review the function code to understand how intents are being handled.

  5. Look at the def on_intent(intent_request, session) function. This is the main intent handler. This function is handling two intents. The first intent, CheckRoom, is the intent you created in the Alexa Developer Console to check for the existence of a meeting room. The second intent, WhenActivity, is the intent which tells you the time when breakfast/lunch is served. Look at the def check_room_existence(intent, session): function definition. In the check_room_existence function, you define a list of allowed rooms and check if the RoomName is in the list. Look at the def check_when_activity(intent, session): function definition. Similar to the previous function, you set up a dictionary of activities (for example, lunch) along with start and end times. If the user asks for an activity, the function returns the start and end time for that activity.

You have successfully completed Task 1 of the lab!

Join Qwiklabs to read the rest of this lab...and more!

  • Get temporary access to the Amazon Web Services Console.
  • Over 200 labs from beginner to advanced levels.
  • Bite-sized so you can learn at your own pace.
Join to Start This Lab
home
Home
school
Catalog
menu
More
More