- flask-ask
- Amazon + flask-ask Intro
- ngrok
- NodeJS Alexa Skillkit
- Example of Skill written in Node (work in prog. see various branches)
You can think of an Alexa Skill as an app for a smartphone, except the primary interface is speech/voice. While apps can provide a visually rich interface, they require the user's active attention (for the most part). On the other hand, Alexa skills tend to be hands free and quick bursts of information.
In the simplest sense we can think of Alexa skills in a similiar way as we think about REST APIs. With Alexa, the Echo Dot, or Alexa-enabled device, is the client which consumes your Skill's API.
Utterances
->Urls
Interaction Model
->Url Mapping
Intents
->The functions which handle requests
A set of likely spoken phrases mapped to the intents. This should include as many representative phrases as possible.
In the above example the utterances are:
AddContactInitIntent add to contact
AddContactNameIntent {name}
AddContactNumberIntent Their number is {number}
AddToContactBookConfirmIntent {name} {number}
SendToContactIntent Send {name} {query}
These are the phrases Alexa will be monitoring for while the skill is active. Anything inside of the curly brackets is a data type variable which will be parsed and passed along to the function handling that intent.
A structure that identifies the steps for a multi-turn conversation between your skill and the user to collect all the information needed to fulfill each intent. This simplifies the code you need to write to ask the user for information.
In the above example the interaction model is:
{
"intents": [
{
"intent": "AddContactInitIntent"
},
{
"slots": [
{
"name": "name",
"type": "LIST_OF_NAMES"
}
],
"intent": "AddContactNameIntent"
},
{
"slots": [
{
"name": "number",
"type": "AMAZON.NUMBER"
}
],
"intent": "AddContactNumberIntent"
},
{
"slots": [
{
"name": "name",
"type": "LIST_OF_NAMES"
},
{
"name": "number",
"type": "AMAZON.NUMBER"
}
],
"intent": "AddToContactBookConfirmIntent"
},
{
"slots": [
{
"name": "name",
"type": "LIST_OF_NAMES"
},
{
"name": "query",
"type": "AMAZON.Animal"
}
],
"intent": "SendToContactIntent"
}
]
}
We can see that the model maps an Intent
to an array of slots
. The slots
are a representative list of possible values. Custom slot types are used for lists of items that are not covered by one of Amazon’s built-in slot types. Here is the list of built in slot types provided by Amazon.
To create a custom slot
type like we have above with LIST_OF_NAMES
we need to provide Amazon witgh a newline seperated list of possible values. In our case, it is simply:
Adrian
James
Scott
Arnaud
Stephen
An intent represents an action that fulfills a user’s spoken request. Intents can optionally have arguments called slots. Intents are specified in a JSON structure called the intent schema.
We can call our intents
whatever we want. When we define the function to handle these intents in our flask app, we must decorate the function with the appropriate @ask
decorator.
@ask.intent("AddContactNameIntent", convert={'name': str})
def prompt_new_contact_number(name):
session.attributes['name'] = name
msg = render_template('prompt_for_number', name=name)
return question(msg)
The above function does a few things. It first maps the AddContactNameIntent
we defined in the Interaction Model to the prompt_new_contact_number
function. It passes along the name
slot value as a parameter to the function as well and declares its data type. These functions must all return a response which can be of the question
or statement
form, much like how a REST API must return some type of response.
question
responses expect the user to input a new command, therefore the application Alexa Skill session persists.
statement
responses do not expect further input so after they are done the Alexa Skill session ends.
Both the above respones expect either a string
input or an identifier to a template in the templates.yaml
file. This file defines the templates in basic jinja
templating syntax. For more see here
In this example we make use of the session
object which is a session-only layer of persistance. We can use this object to share data and maintain state throughout the skill session.
Here is the template used for the aboce intent
:
prompt_for_number: What is {{ name }} phone number?
To write to the session
:
session.attributes[KEY] = VALUE
To read from the session
:
foo = session.attributes[KEY]
Of course you can make use of a databse (as simple as a JSON file to complex as postgres).
- NYC Open Data: API for NYC public data
- Twilio: API For automating SMS and Calls
- Braintree: API for automating payments (and sandbox/testing payments)
- Sendgrid: API for automating emails
- Watson: API for Machine Learning / NLP
- Clarifai: Image and Video Recognition API
- Google Maps: Mappign API
- Giphy: API for searching Gifs
- Auth0: Authentication API
- New York Times: API for news
- Weather Underground: API for weather
- Foursquare: API for venues
- Meetup: API for events