How to create your first ALEXA skill using python ?
Alexa is the new immerging field in the automation. As there are many things around us which works with ALEXA, you might think that creating an ALEXA skill is tough but after reading this blog then you can create an ALEXA skill on your own.
Why build Alexa skills ?
Ease of access:
- VUIs are natural, conversational, and user-centric.
- A great voice experience allows for the many ways people express meaning and intent. It is rich and flexible. Because of this, building for voice isn’t the same as building graphical user interfaces (GUIs) for the web or mobile.
- The easier a skill is to use, the more speed and efficiency it offers.
Speed and efficiency
- Alexa skills bring speed and efficiency to habitual tasks — which is why voice is poised to become ubiquitous.
- Consider your room’s A/C. With Alexa, turning an A/C on is as easy as saying, “Alexa, turn on A/C.” Who would have guessed pushing a few buttons on the remote would become the less convenient option?
How an Alexa Skill Works
- The user says the wake word, Alexa.
- Alexa hears the wake word and listens.
- The Alexa service uses the interaction model to figure where to route the request.
- A JSON request is sent to the skill’s lambda function.
- The lambda function inspects the JSON request.
- The lambda function determines how to respond.
- The lambda function sends a JSON response to the Alexa service.
- The Alexa service receives the JSON response and converts the output text to an audio file.
- The Alexa-enabled device receives and plays the audio.
Steps to build an Alexa skills:
- Create a voice user interface in the Alexa developer console
- Create different Slots and Utterances as you needed.
- Write an appropriate code in the code section.
- Finally test your code and publish your skills.
Prerequisites:
- Sign up for Alexa Developer Console and Amazon Web Services.
- Kindly complete your procedure of signing up for AWS free tier account.
- You must have some basic knowledge of Programming languages like C,C++,Java,Python,Node.js,etc. whichever you are comfortable with.
- Optionally, you can have the Alexa devices like Amazon Echo, Echo Dot, etc. OR you can use the Alexa inbuilt simulator on Alexa Developer console to test your skills.
Basic introduction of the Alexa Skill that you’re going to create:
In this blog you’re going to create the alexa skills for SALES REPRESENTATIVE, which would first ask some data like store location, date and greeting. Also it would save the data that you have told to alexa for some particular time when the alexa skills has been called.
At the end of the blog the basic thing that you would be going to build is that when you ask ”Alexa, tell me about the sales data.” then it would ask for some of the required data that alexa required to fetch the data, and obviously many more thing like storing the data, fetching the data, configuring AWS lambda with Alexa, etc.
Now, let’s start to create Alexa skill:
Step 1: Log in
To get started, log into the Alexa developer console with your Amazon Developer account. If you do not have an account, click here to create one.
Step 2: Create your skill
- Enter the Skill name: Alexa for Sales Representative
- In choose a model to add to your skill select ‘custom’.
3. Select Alexa-Hosted(Python) as your back-end resource.
4. Finally click on the create skill.
Now, let’s edit the custom made alexa skills as per our requirement
Part 1: Building the interaction model
Interaction model is the important part of our skill. It contains the skill’s invocation name, intents and utterances, etc., which are crucial for the interaction with the skill services.
Invocation name is the name that will enable alexa skill when you will say that word.
First, let’s setup the invocation name in our interaction model:
- Select the “Invocation” tab.
- Enter “Sales Data” in the Skill Invocation Name:
Now, under the interaction model tab you will see the default BuiltInIntents which is provided when your skill is created:
Note: Built-in intents have built-in utterances. It is possible to extend the number of existing utterances by adding new utterances. When a skill is created, four built-in intents are added to the Interaction model by default. These are: AMAZON.HelpIntent, AMAZON.CancelIntent, AMAZON.FallbackIntent and AMAZON.StopIntent.
- Here in this skill we will need StatusIntent, which will ask user some data from where it should fetch the data. So create a new intent names SttusIntent.
- Under the statusIntent we will create different slots for ease of access and for the Alexa for fetching/storing the data.
Note: Slots are a very powerful accessory for building a custom Alexa skill. For example, the statement “Tell me about {player}” means that the user can ask our skill about any chess player from the slot player. Furthermore, multiple slots provide the possibility of using dialogs in which the Alexa skill prompts the user to fill all slot values in order to fulfill the intent.
- Click on the intents tab and create a new intents and name it as “HelloWorldIntent” and then on going into the HelloWorldIntent you’ll see the Sample Utterances in which you have to add sample’s such that this intent would be called by alexa if alexa would find similar words.
- Now, we want alexa to prompt something when this Intent has been invoked.
- So, now we have to create a slot-name into the HelloWorldIntent, which is created by just writing a word in between { }(Eg. {greetings} in my case). Thus, the slot is being created.
- You will find that word below the HelloWorldIntent.
- Now, first of all you have to create a slot-type into the slots types section.
- Click on the slot types and then add slot type and create a custom slot and add the slot values in regarding greetings.
- Now go to the greetings under the HelloWorldIntent and choose the slot type that is related to the greetings that you have created.
- Similarly You have to create a statusIntent which will tell ask me about which data that you want to fetch, so you have to add the sample utterances such that it will invoke statusIntent if you will say similar to that statements.
- Also you have to create different slot names like date, locationGujarat, etc. and thus you have to create slot-type respectively.
Note: While creating the slot type you can also use the inbuilt intent like AMAZON.DATE in date slot name.
- Also you have to set slot type in the particular slot name like in the data slot you have to choose the AMAZON.DATE in the slot type under the different inents.
- You can also find the reference of locationGujarat intent in the below image.
- Till now you have noticed that i have turn on slot filling in different slot names, this has been turned on because I want Alexa to store this user input for the particular time so that it can search that particular data.
- When you will turn on the slot filling at that time you’ll find two things Alexa speech prompts and User utterances. In Alexa speech prompts you have to write some sample utterances that Alexa will prompt if the respective intent is called. And in User utterances you have to write the sample utterances that the user may ask you.
- You may find below images for reference.
- Also you can turn on the slot confirmation tab if you want to verify that the user input data is correct or not.
- Now you will also find the JSON editor tab in which you have created the Virtual interface above is converted to the JSON form. It will be like below mentioned:
{
"interactionModel": {
"languageModel": {
"invocationName": "sales data",
"modelConfiguration": {
"fallbackIntentSensitivity": {
"level": "LOW"
}
},
"intents": [
{
"name": "AMAZON.CancelIntent",
"samples": []
},
{
"name": "AMAZON.HelpIntent",
"samples": [
"how to use you",
"how to use ",
"kindly help",
"please help",
"please help me",
"help "
]
},
{
"name": "AMAZON.StopIntent",
"samples": [
"can you please keep quite",
"keep quite",
"can please stop",
"can please shut up",
"kindly stop",
"please stop ",
"stop "
]
},
{
"name": "HelloWorldIntent",
"slots": [
{
"name": "greeting",
"type": "Greetings",
"samples": [
"sad",
"good",
"Fine "
]
}
],
"samples": [
"{greeting}",
"hello",
"how are you",
"say hi world",
"say hi",
"hi",
"say hello world",
"say hello"
]
},
{
"name": "AMAZON.NavigateHomeIntent",
"samples": [
"HelloWorldIntent",
"StatusIntent",
"please navigate me to statusIntent"
]
},
{
"name": "AMAZON.FallbackIntent",
"samples": []
},
{
"name": "StatusIntent",
"slots": [
{
"name": "date",
"type": "AMAZON.DATE",
"samples": [
"data on {date} of {locationGujarat}",
"please provide me the data of {locationGujarat} on {date}",
"can you provide me the data of {locationGujarat} on {date}",
"day after tomorrow",
"may eleven ",
"october twenty five",
"november twenty five",
"this friday",
"this monday"
]
},
{
"name": "locationGujarat",
"type": "StoreLocationInGujarat",
"samples": [
"vadodara",
"baroda",
"gandhinagar",
"rajkot",
"surat",
"ahmedabad"
]
}
],
"samples": [
"data of {locationGujarat} on {date}",
"provide me all data of {locationGujarat} on {date}",
"tell me all data of {locationGujarat} on {date}",
"data on {date} of {locationGujarat}",
"can you please provide me the data on {date} of {locationGujarat}",
"please provide me the data of the {locationGujarat} on {date}",
"what is {date} status",
"what about {date}",
"what about work load",
"what about todays order",
"what is {date} work load",
"what work load {date}",
"what work load on {date}",
"what about work",
"what work load at {locationGujarat}"
]
}
],
"types": [
{
"name": "StoreLocationInGujarat",
"values": [
{
"name": {
"value": "Ahmedabad",
"synonyms": [
"amdavad"
]
}
},
{
"name": {
"value": "Vadodara",
"synonyms": [
"baroda"
]
}
},
{
"name": {
"value": "Surat",
"synonyms": [
"hurat"
]
}
},
{
"name": {
"value": "Rajkot",
"synonyms": [
"rojkot"
]
}
},
{
"name": {
"value": "Gandhinagar",
"synonyms": [
"gondhinagar"
]
}
}
]
},
{
"name": "Greetings",
"values": [
{
"name": {
"value": "hii"
}
},
{
"name": {
"value": "hello"
}
},
{
"name": {
"value": "alexa"
}
},
{
"name": {
"value": "good morning"
}
},
{
"name": {
"value": "good evening"
}
},
{
"name": {
"value": "good night"
}
},
{
"name": {
"value": "hey alexa"
}
}
]
}
]
},
"dialog": {
"intents": [
{
"name": "StatusIntent",
"confirmationRequired": false,
"prompts": {},
"slots": [
{
"name": "date",
"type": "AMAZON.DATE",
"confirmationRequired": false,
"elicitationRequired": true,
"prompts": {
"elicitation": "Elicit.Slot.867268475988.1435074133862"
}
},
{
"name": "locationGujarat",
"type": "StoreLocationInGujarat",
"confirmationRequired": false,
"elicitationRequired": true,
"prompts": {
"elicitation": "Elicit.Slot.867268475988.397803401305"
}
}
]
},
{
"name": "HelloWorldIntent",
"confirmationRequired": false,
"prompts": {},
"slots": [
{
"name": "greeting",
"type": "Greetings",
"confirmationRequired": false,
"elicitationRequired": true,
"prompts": {
"elicitation": "Elicit.Slot.353512166593.1518986883486"
}
}
]
}
],
"delegationStrategy": "ALWAYS"
},
"prompts": [
{
"id": "Elicit.Slot.867268475988.1544387796744",
"variations": [
{
"type": "PlainText",
"value": "can you provide me the {day} ?"
},
{
"type": "PlainText",
"value": "can you provide me the {date} ?"
},
{
"type": "PlainText",
"value": "can you provide me the location ?"
},
{
"type": "PlainText",
"value": "ya sure at which {locationGujarat} ?"
}
]
},
{
"id": "Confirm.Slot.867268475988.1544387796744",
"variations": [
{
"type": "PlainText",
"value": "ohk will provide you the details on {date} , {day} at {locationGujarat} ."
}
]
},
{
"id": "Elicit.Slot.867268475988.1435074133862",
"variations": [
{
"type": "PlainText",
"value": "ohk sure on which date ?"
},
{
"type": "PlainText",
"value": "on which date ?"
}
]
},
{
"id": "Confirm.Slot.867268475988.1435074133862",
"variations": [
{
"type": "PlainText",
"value": "ok sure will provide you the data of {locationGujarat} on {date}"
},
{
"type": "PlainText",
"value": "are you sure you want to see work at that date {date}"
}
]
},
{
"id": "Elicit.Slot.867268475988.1119428064907",
"variations": [
{
"type": "PlainText",
"value": "can you provide me the day at which you want to see work load ?"
},
{
"type": "PlainText",
"value": "please provide the day"
},
{
"type": "PlainText",
"value": "can you provide me the day ?"
}
]
},
{
"id": "Confirm.Slot.867268475988.1119428064907",
"variations": [
{
"type": "PlainText",
"value": "ohk will tell you the load on {day}"
}
]
},
{
"id": "Elicit.Slot.353512166593.1518986883486",
"variations": [
{
"type": "PlainText",
"value": "Hi, What can I help you ?"
},
{
"type": "PlainText",
"value": "Hello, How are you ?"
}
]
},
{
"id": "Elicit.Slot.867268475988.397803401305",
"variations": [
{
"type": "PlainText",
"value": "At which location ?"
},
{
"type": "PlainText",
"value": "please provide me the location ?"
},
{
"type": "PlainText",
"value": "pls give me the location ?"
},
{
"type": "PlainText",
"value": "Can you provide me the loction ?"
}
]
},
{
"id": "Confirm.Slot.867268475988.397803401305",
"variations": [
{
"type": "PlainText",
"value": "ohk sure will provide you the data on {date} at {locationGujarat} ."
}
]
},
{
"id": "Confirm.Intent.698543170008",
"variations": [
{
"type": "PlainText",
"value": "ok"
},
{
"type": "PlainText",
"value": "ohk sure will provide you the data on {date} of {locationGujarat} ."
}
]
}
]
}
}
Part 2: Editing in the code section
- Now go to the code section in the Alexa developer console and kindly do appropriate editing in the code as per the requirements. Here kindly see the below code for reference only:
# -*- coding: utf-8 -*-# This sample demonstrates handling intents from an Alexa skill using the Alexa Skills Kit SDK for Python.
# Please visit https://alexa.design/cookbook for additional examples on implementing slots, dialog management,
# session persistence, api calls, and more.
# This sample is built using the handler classes approach in skill builder.
import logging
import boto3
import ask_sdk_core.utils as ask_utilsfrom ask_sdk_core.skill_builder import SkillBuilder
from ask_sdk_core.dispatch_components import AbstractRequestHandler
from ask_sdk_core.dispatch_components import AbstractExceptionHandler
from ask_sdk_core.handler_input import HandlerInputfrom ask_sdk_model import Responselogger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)class LaunchRequestHandler(AbstractRequestHandler):
"""Handler for Skill Launch."""
def can_handle(self, handler_input):
# type: (HandlerInput) -> boolreturn ask_utils.is_request_type("LaunchRequest")(handler_input)def handle(self, handler_input):
# type: (HandlerInput) -> Response
print('LaunchRequest')
speak_output = "Welcome, you can say Hello or Help. Which would you like to try?"return (
handler_input.response_builder
.speak(speak_output)
.ask(speak_output)
.response
)class StatusHandler(AbstractRequestHandler):
"""Handler for Skill Launch."""
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return ask_utils.is_intent_name("StatusIntent")(handler_input)def handle(self, handler_input):
# type: (HandlerInput) -> Response
print('StatusHandler')
speak_output = "What you want to know from me?"return (
handler_input.response_builder
.speak(speak_output)
.ask(speak_output)
.response
)class HelloWorldIntentHandler(AbstractRequestHandler):
"""Handler for Hello World Intent."""
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return ask_utils.is_intent_name("HelloWorldIntent")(handler_input)def handle(self, handler_input):
# type: (HandlerInput) -> Response
dynamodb_client = boto3.client('dynamodb')
existing_tables = dynamodb_client.list_tables()['TableNames']
print(existing_tables, end="\n\n")
print('HelloWorldIntentHandler')
speak_output = "HelloWorldIntentHandler"return (
handler_input.response_builder
.speak(speak_output)
# .ask("add a reprompt if you want to keep the session open for the user to respond")
.response
)class HelpIntentHandler(AbstractRequestHandler):
"""Handler for Help Intent."""
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return ask_utils.is_intent_name("AMAZON.HelpIntent")(handler_input)def handle(self, handler_input):
# type: (HandlerInput) -> Response
print('HelpIntentHandler')
speak_output = "You can say hello to me! How can I help?"return (
handler_input.response_builder
.speak(speak_output)
.ask(speak_output)
.response
)class CancelOrStopIntentHandler(AbstractRequestHandler):
"""Single handler for Cancel and Stop Intent."""
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return (ask_utils.is_intent_name("AMAZON.CancelIntent")(handler_input) or
ask_utils.is_intent_name("AMAZON.StopIntent")(handler_input))def handle(self, handler_input):
# type: (HandlerInput) -> Response
print('CancelOrStopIntentHandler')
speak_output = "Goodbye!"return (
handler_input.response_builder
.speak(speak_output)
.response
)class SessionEndedRequestHandler(AbstractRequestHandler):
"""Handler for Session End."""
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return ask_utils.is_request_type("SessionEndedRequest")(handler_input)def handle(self, handler_input):
# type: (HandlerInput) -> Response# Any cleanup logic goes here.
print('SessionEndedRequest')return handler_input.response_builder.responseclass IntentReflectorHandler(AbstractRequestHandler):
"""The intent reflector is used for interaction model testing and debugging.
It will simply repeat the intent the user said. You can create custom handlers
for your intents by defining them above, then also adding them to the request
handler chain below.
"""
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return ask_utils.is_request_type("IntentRequest")(handler_input)def handle(self, handler_input):
# type: (HandlerInput) -> Response
intent_name = ask_utils.get_intent_name(handler_input)
speak_output = "You just triggered " + intent_name + "."return (
handler_input.response_builder
.speak(speak_output)
# .ask("add a reprompt if you want to keep the session open for the user to respond")
.response
)class CatchAllExceptionHandler(AbstractExceptionHandler):
"""Generic error handling to capture any syntax or routing errors. If you receive an error
stating the request handler chain is not found, you have not implemented a handler for
the intent being invoked or included it in the skill builder below.
"""
def can_handle(self, handler_input, exception):
# type: (HandlerInput, Exception) -> bool
return Truedef handle(self, handler_input, exception):
# type: (HandlerInput, Exception) -> Response
logger.error(exception, exc_info=True)speak_output = "Sorry, I had trouble doing what you asked. Please try again."return (
handler_input.response_builder
.speak(speak_output)
.ask(speak_output)
.response
)# The SkillBuilder object acts as the entry point for your skill, routing all request and response
# payloads to the handlers above. Make sure any new handlers or interceptors you've
# defined are included below. The order matters - they're processed top to bottom.sb = SkillBuilder()sb.add_request_handler(LaunchRequestHandler())
sb.add_request_handler(StatusHandler())
sb.add_request_handler(HelloWorldIntentHandler())
sb.add_request_handler(HelpIntentHandler())
sb.add_request_handler(CancelOrStopIntentHandler())
sb.add_request_handler(SessionEndedRequestHandler())
sb.add_request_handler(IntentReflectorHandler()) # make sure IntentReflectorHandler is last so it doesn't override your custom intent handlerssb.add_exception_handler(CatchAllExceptionHandler())lambda_handler = sb.lambda_handler()
Part 3: Choosing the Endpoints
The skill service can be either a user implemented web service or the AWS service. This is configured in the “Endpoints”. For our skill, we are going to use the AWS service, which communicates with the skill interface via the AWS Lambda function.
To choose the AWS service:
- Click the “Endpoints” tab.
- Select the “AWS Lambda ARN”.
In order to connect our skill interface with the AWS Lambda function we need to pass the skill the skill ID to the Lambda function. The skill ID is located in the “Endpoints”, and we will copy it by clicking “Copy to Clipboard”.
Now visit the AWS Management Console page and after signing Go to lambda under the services section.
Now in that create a new function in it and name it as you want.
In my case I’ve already created a function called demo.
Now on going into the function you’ll find the trigger section, click on the add trigger and search for Alexa Skill kit and select that and in that you have to copy the skill Id from the Alexa Developer console and then it will show that your skill has been verified and enabled.
Now go back to the Alexa console and in the Endpoints section kindly paste the lambda function ARN in the default region so that the alexa would automatically use this lambda function.
Do the appropriate coding and then you are done creating your skill. Now you just have to test your skill and verify that it is working or not.
You can code in python and the basic python library used in aws is boto3. So i kindly request you to read the python boto3 library documentation.
Now finally, Deploy your Alexa skill to work with you in day-to-day life.
That is it! You now have a working custom Amazon Alexa Skill.
Let’s do a quick recap.
First, we have learned that an Alexa skill is voice-driven app for Alexa which preforms a specific task for the user at his request.
We then learned that the user request (to the skill) is handled first by the skill interface, using the interaction model, and then by the skill service that forms the response for the user, using the Lambda function.
Finally, by building our own custom skill we have learned the very basics of practical skill building and scratched the surface of the Amazon Alexa developers console and AWS Lambda services.
Have fun while making your own custom skills!