How To Build A Custom Amazon Alexa Skill with AWS Lambda as a backend.
Hello everyone, a came across developing this Alexa skill project for my company and was struggling to get a smooth head start so I write this blog so as to help others. Hope this helps you. :)
Setting Up the ASK SDK
This guide describes how to install the ASK SDK for Python in preparation for developing an Alexa skill. I have used the AWS lambda function for backend because you can debug here as compared to the Alexa developer console and lots of other cool things.
Prerequisites
The ASK SDK for Python requires Python 2 (>= 2.7) or Python 3 (>= 3.6). Before continuing, make sure you have a supported version of Python installed. To show the version, from a command prompt run the following command:
$ python --version
Python 3.6.5
Adding the ASK SDK for Python to Your Project
Many Python developers prefer to work in a virtual environment, so do I, so in this blog, I’ll proceed with that only. The virtual environment is an isolated Python environment that helps manage project dependencies and package versions. The easiest way to get started is to install the SDK in a virtual environment.
$ pip install virtualenv
Next, create a new folder for your Alexa skill and navigate to the folder:
$ mkdir skill
$ cd skill
Next, create a virtual environment called skill_env
by issuing the following command:
$ virtualenv skill_env
Next, activate your virtual environment and install the SDK.
Run the following command to activate your virtual environment:
$ skill_env\Scripts\activate
The command prompt should now be prefixed with (skill_env), indicating that you are working inside the virtual environment. Use the following command to install the ASK Python SDK:
(skill_env)$ pip install ask-sdk
The SDK will be installed in the skill\Lib\site-packages
folder. The site-packages folder is populated with directories including:
ask_sdk
ask_sdk_core
ask_sdk_dynamodb
ask_sdk_model
boto3
...
Developing Your First Skill
Prerequisites
In addition to an installed version of the ASK SDK for Python you need:
- An Amazon Developer account. This is required to create and configure Alexa's skills.
- An Amazon Web Services (AWS) account. This is required for hosting a skill on AWS Lambda.
Creating Hello World
You’ll write your Hello World in a single python file named hello_world.py
. In the skill
the folder that you have created earlier, use your favorite text editor or IDE to create a file named hello_world.py
.
Implementing Hello World
Request handlers
A custom skill needs to respond to events sent by the Alexa service. For instance, when you ask your Alexa device (e.g. Echo, Echo Dot, Echo Show, etc.) to “open hello world,” your skill needs to respond to the LaunchRequest that is sent to your Hello World skill. With the ASK SDK for Python, you simply need to write a request handler, which is code to handle incoming requests and return a response. Your code is responsible for making sure that the right request handler is used to process incoming requests and for providing a response.
Start by creating a skill builder object. The skill builder object helps in adding components responsible for handling input requests and generating custom responses for your skill.
Type or paste the following code into your hello_world.py
file.
from ask_sdk_core.skill_builder import SkillBuildersb = SkillBuilder()
To use handler classes, each request handler is written as a class that implements two methods of the AbstractRequestHandler
class; can_handle
and handle
.
The can_handle
the method returns a Boolean value indicating if the request handler can create an appropriate response for the request. The can_handle
method has access to the request type and additional attributes that the skill may have set in previous requests or even saved from a previous interaction. The Hello World skill only needs to reference the request information to decide if each handler can respond to an incoming request.
LaunchRequest handler
The following code example shows how to configure a handler to be invoked when the skill receives a LaunchRequest. The LaunchRequest event occurs when the skill is invoked without specific intent.
Type or paste the following code into your hello_world.py
file, after the previous code.
from ask_sdk_core.dispatch_components import AbstractRequestHandler
from ask_sdk_core.utils import is_request_type, is_intent_name
from ask_sdk_core.handler_input import HandlerInput
from ask_sdk_model import Response
from ask_sdk_model.ui import SimpleCardclass LaunchRequestHandler(AbstractRequestHandler):
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return is_request_type("LaunchRequest")(handler_input) def handle(self, handler_input):
# type: (HandlerInput) -> Response
speech_text = "Welcome to the Alexa Skills Kit, you can say hello!" handler_input.response_builder.speak(speech_text).set_card(
SimpleCard("Hello World", speech_text)).set_should_end_session(
False)
return handler_input.response_builder.response
The can_handle function returns True if the incoming request is a LaunchRequest. The handle function generates and returns a basic greeting response.
HelloWorldIntent handler
The following code example shows how to configure a handler to be invoked when the skill receives an intent request with the name HelloWorldIntent. Type or paste the following code into your hello_world.py
file, after the previous handler.
class HelloWorldIntentHandler(AbstractRequestHandler):
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return is_intent_name("HelloWorldIntent")(handler_input) def handle(self, handler_input):
# type: (HandlerInput) -> Response
speech_text = "Hello World" handler_input.response_builder.speak(speech_text).set_card(
SimpleCard("Hello World", speech_text)).set_should_end_session(
True)
return handler_input.response_builder.response
The can_handle function detects if the incoming request is an IntentRequest, and returns True if the intent name is HelloWorldIntent. The handle function generates and returns a basic “Hello World” response.
HelpIntent handler
The following code example shows how to configure a handler to be invoked when the skill receives the built-in intent AMAZON.HelpIntent. Type or paste the following code into your hello_world.py file
, after the previous handler.
class HelpIntentHandler(AbstractRequestHandler):
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return is_intent_name("AMAZON.HelpIntent")(handler_input) def handle(self, handler_input):
# type: (HandlerInput) -> Response
speech_text = "You can say hello to me!" handler_input.response_builder.speak(speech_text).ask(speech_text).set_card(
SimpleCard("Hello World", speech_text))
return handler_input.response_builder.response
Similar to the previous handler, this handler matches an IntentRequest with the expected intent name. Basic help instructions are returned, and .ask(speech_text)
causes the user's microphone to open up for the user to respond.
CancelAndStopIntent handler
The CancelAndStopIntentHandler is similar to the HelpIntent handler, as it is also triggered by the built-In AMAZON.CancelIntent or AMAZON.StopIntent Intents. The following example uses a single handler to respond to both intents. Type or paste the following code into your hello_world.py
file, after the previous handler.
class CancelAndStopIntentHandler(AbstractRequestHandler):
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return is_intent_name("AMAZON.CancelIntent")(handler_input)
or is_intent_name("AMAZON.StopIntent")(handler_input) def handle(self, handler_input):
# type: (HandlerInput) -> Response
speech_text = "Goodbye!" handler_input.response_builder.speak(speech_text).set_card(
SimpleCard("Hello World", speech_text)).set_should_end_session(True)
return handler_input.response_builder.response
The response to both intents is the same, so having a single handler reduces repetitive code.
SessionEndedRequest handler
Although you cannot return a response with any speech, card or directives after receiving a SessionEndedRequest, the SessionEndedRequestHandler is a good place to put your cleanup logic. Type or paste the following code into your hello_world.py
file, after the previous handler.
class SessionEndedRequestHandler(AbstractRequestHandler):
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return is_request_type("SessionEndedRequest")(handler_input) def handle(self, handler_input):
# type: (HandlerInput) -> Response
# any cleanup logic goes here return handler_input.response_builder.response
Implementing exception handlers
The following sample adds a catch-all exception handler to your skill, to ensure the skill returns a meaningful message for all exceptions. Type or paste the following code into your hello_world.py
file, after the previous handler.
from ask_sdk_core.dispatch_components import AbstractExceptionHandlerclass AllExceptionHandler(AbstractExceptionHandler): def can_handle(self, handler_input, exception):
# type: (HandlerInput, Exception) -> bool
return True def handle(self, handler_input, exception):
# type: (HandlerInput, Exception) -> Response
# Log the exception in CloudWatch Logs
print(exception) speech = "Sorry, I didn't get it. Can you please say it again!!"
handler_input.response_builder.speak(speech).ask(speech)
return handler_input.response_builder.response
Creating the Lambda handler
The Lambda handler is the entry point for your AWS Lambda function. The following code example creates a Lambda handler function to route all inbound requests to your skill. The Lambda handler function creates an SDK skill instance configured with the request handlers that you just created. Type or paste the following code into your hello_world.py
file, after the previous handler.
sb.add_request_handler(LaunchRequestHandler())
sb.add_request_handler(HelloWorldIntentHandler())
sb.add_request_handler(HelpIntentHandler())
sb.add_request_handler(CancelAndStopIntentHandler())
sb.add_request_handler(SessionEndedRequestHandler())sb.add_exception_handler(AllExceptionHandler())handler = sb.lambda_handler()
Once you’ve created your AWS Lambda function, it’s time to give the Alexa service the ability to invoke it. To do this, navigate to the Triggers tabs in your Lambda’s configuration, and add Alexa Skills Kit as the trigger type. Once this is done, upload the skill.zip
the file produced in the previous step and fill in the handler information with module_name.handler which is hello_world.handler
for this example.
Configuring and testing your skill
Now that the skill code has been uploaded to AWS Lambda, you can configure the skill with Alexa.
- Create a new skill by following these steps:
- Log in to the Alexa Skills Kit Developer Console.
- Click the Create Skill button in the upper right.
- Enter “mark1” as your skill name and click Next.
- For the model, select Custom and click Create skill.
- Next, define the interaction model for the skill. Select the Invocation option from the sidebar and enter “greeter” for the Skill Invocation Name.
- Next, add an intent called
HelloWorldIntent
to the interaction model. Click the Add button under the Intents section of the Interaction Model. Leave Create custom intent selected, enter HelloWorldIntent for the intent name, and create the intent. On the intent detail page, add some sample utterances that users can say to invoke the intent. For this example, consider the following sample utterances, and feel free to add others.
- Since
AMAZON.CancelIntent
,AMAZON.HelpIntent
, andAMAZON.StopIntent
are built-in Alexa intents, you do not need to provide sample utterances for them. - Once you are done editing the interaction model, be sure to save and build the model.
- Next, configure the endpoint for the skill. To do this, follow these steps:
Open the AWS Developer Console in a new tab.
Navigate to the AWS Lambda function created in the previous step.
From the Designer menu, add the Alexa Skills Kit trigger menu, and scroll down to paste the skill ID into the Skill ID Verification configuration. Click Add and save once completed to update the AWS Lambda function.
Copy the AWS Lambda function ARN from the top right corner of the page. An ARN is a unique resource number that helps Alexa service identify the AWS Lambda function it needs to call during skill invocation.
Navigate to the Alexa Skills Kit Developer Console, and click on your mark1 skill.
Under your skill, click Endpoint tab, select AWS Lambda ARN and paste in the ARN under Default Region field.
The rest of the settings can be left at their default values. Click Save Endpoints.
Click Invocation tab, save and build the model.
At this point, you can test the skill. In the top navigation, click Test. Make sure that the Test is enabled for this skill option is enabled. You can use the Test page to simulate requests, in text and voice form.
Use the invocation name along with one of the sample utterances as a guide. For example, tell greeters to say hello should result in your skill responding with “Hello World” voice and “Hello World” card on devices with a display. You can also open the Alexa app on your phone or at https://alexa.amazon.com and see your skills listed under Your Skills.
Feel free to start experimenting with your intents as well as the corresponding request handlers in your skill code. Once you’re finished iterating, optionally move on to getting your skill certified and published so it can be used by customers worldwide.
You can find the full code of the above here.