https://github.com/oreillymedia/hello-alexa
https://github.com/oreillymedia/hello-alexa
Last synced: 21 days ago
JSON representation
- Host: GitHub
- URL: https://github.com/oreillymedia/hello-alexa
- Owner: oreillymedia
- Created: 2016-09-09T14:10:52.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2016-12-28T15:54:34.000Z (over 8 years ago)
- Last Synced: 2025-03-21T08:51:20.312Z (about 1 month ago)
- Language: JavaScript
- Size: 2.15 MB
- Stars: 5
- Watchers: 20
- Forks: 4
- Open Issues: 3
-
Metadata Files:
- Readme: README.asciidoc
Awesome Lists containing this project
README
= Build Your Own Alexa Skill
== Introduction
In this Lesson, you'll learn how to create an Amazon Alexa Skill. You'll see how to set up and configure the voice interactions, and also how to create an AWS Lambda function that handles the requests and responses that users initiate.
== Prerequisites
You'll need a few things before you can follow this lesson:
* You'll need to be comfortable with using your computer's terminal or command prompt and know how to create and edit plain text files.
////
* Install Git on your computer.
macOS::: you can get Git by installing Xcode or its command line tools. Type `xcode-select --install` in a Terminal window, and macOS should prompt you to install the command line tools. If not, you may need to install Xcode first.
Windows::: You can install Git for Windows from here: https://git-scm.com/download/win
Linux::: You can install Git from your package repository. For example, on Ubuntu, `apt-get install git` will do the trick.
////* Install Node.js (version 5 or later) and update npm using these instructions: https://docs.npmjs.com/getting-started/installing-node
* You will need an AWS account; the https://aws.amazon.com/free/[free tier] is sufficient for this lesson.
* You will also need to register as a developer in https://developer.amazon.com/[Amazon's developer portal].== Setting up your skill
With all the prerequisites in place, you're ready to define your skill. There are several steps in this process. First, log into the https://developer.amazon.com[Amazon Developer Portal], and then click the Alexa link at the top of the page. You'll be prompted to choose a starting point (Alexa Skills Kit or Alexa Voice Service). Click Get Started under the Alexa Skills Kit option:
image::images/alexa-skills-portal.png[]
=== Step 1: Add the New Skill
* Click the Add a New Skill button
In this step, you'll define the basic characteristics of the skill: its name, the name that people use to invoke it, and a couple of other settings.
image::images/add-new-skill.png[]
* Set the following options:
Skill type::: Make sure this is set to Custom Interaction Model.
Name::: This is what appears in the Alexa app. Call it "Tide Pooler."
Invocation Name::: This is how users will activate the skill. Use "Tide Pooler" here as well.
Audio Player::: You can leave this set to No for this skill. If you were playing audio, such a music, that you wanted to allow users to stop or pause, you'd need this. You won't need it here.
* Click Next.image::images/set-skill-information.png[]
=== Step 2: Define the Skill's Interaction Model
Now you're in the Interaction Model section of the setup process. This is where you describe what sorts of things you can say to the skill. The first part is the _intent schema_, which defines the _intents_, or kinds of interactions your skill has. A given intent corresponds to a function that you'll define later; it will look up tide info, format it into a nice result, and that will be read back to the user. The second part is a collection of utterances, and they are (mostly) human-readable sentences with optional _slots_ for one or more parameters. Not all skills will need a parameter, but Tide Pooler needs to know what city the user is curious about.
NOTE: You can also copy this schema from this Lesson's https://github.com/oreillymedia/hello-alexa/blob/master/config/intents.json[GitHub repository].
Put the following schema into the Intent Schema. The first intent is _GetTideIntent_, which is the intent for asking about the high tide. The other intents allow users to ask the skill for help, or to stop or cancel it.
----
{
"intents": [
{
"intent": "GetTideIntent",
"slots": [
{
"name": "City",
"type": "AMAZON.US_CITY"
}
]
},
{
"intent": "AMAZON.HelpIntent"
},
{
"intent": "AMAZON.StopIntent"
},
{
"intent": "AMAZON.CancelIntent"
}
]
}
----Now you're ready to get into the actual things you can ask the skill. Put the following text into the Sample Utterances field. Note how each utterance refers to the City slot:
GetTideIntent when is high tide in {City}
GetTideIntent when will it be high tide in {City}
GetTideIntent what time is high tide for {City}
GetTideIntent what time is high tide in {City}NOTE: You can also copy the list of utterances from this Lesson's https://github.com/oreillymedia/hello-alexa/blob/master/config/utterances.txt[GitHub repository].
The GetTideIntent signifies that the user wants to know when high tide is. They can ask it in several ways:
* When is high tide in Newport, Rhode Island?
* When will it be high tide in New Bedford, Massachusetts?
* What time is high tide for Gloucester, Massachusetts?
* What time is high tide in Gloucester, Massachusetts?Because this skill is only using the built-in `AMAZON.US_CITY` slot type, you won't need to define any Custom Slot Types.
Click Save, and wait while the interaction model is built. When it's done, the message below the Save button should read "Successfully updated the interaction model."
== Building the Sample Skill
Now you're ready to build an AWS Lambda function that you'll install in AWS. It will be called on demand, when it's needed.
=== Step 1: Create the package.json File
Open a Terminal or Command Prompt, create a new directory named _tide-pooler_, and cd into it. Next, create a file named package.json in the _tide-pooler_ directory and add these lines to it:
{
"name": "tide-pooler",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"alexa-sdk": "^1.0.5",
"dotenv": "^2.0.0",
"node-lambda": "^0.8.9"
}
}Save the file, and in your terminal or command prompt, run this command to pull down all the dependencies you need for your skill: `npm install`. Now you should see a _node_modules_ directory alongside the package.json file:
$ ls -l
total 8
drwxr-xr-x 40 bjepson staff 1360 Sep 9 15:28 node_modules
-rw-r--r-- 1 bjepson staff 197 Sep 9 15:28 package.json=== Step 2: Create the JavaScript Handlers
Next, create a file named _index.js_, and put the following code in it:
NOTE: You can also copy this file from this Lesson's https://github.com/oreillymedia/hello-alexa/blob/master/index.js[GitHub repository].
----
'use strict';var Alexa = require('alexa-sdk'); // <1>
require('dotenv').config(); // <2>
var SKILL_NAME = 'Tide Pooler'; // <3>
exports.handler = function(event, context, callback) { // <4>
var alexa = Alexa.handler(event, context);
alexa.APP_ID = APP_ID;
alexa.registerHandlers(handlers);
alexa.execute();
};var handlers = {
'LaunchRequest': function () { // <5>
this.emit('AMAZON.HelpIntent');
},
'GetTideIntent': function () {
var citySlot = this.event.request.intent.slots.City; // <6>
var cityName;
if (citySlot && citySlot.value) { // <7>
cityName = citySlot.value;var cardTitle = SKILL_NAME + " High Tide For - " + cityName; // <8>
var time = "5:00pm";
var speechOutput = "It will be high tide in " +
cityName + " at " + time;
this.emit(':tellWithCard', speechOutput, SKILL_NAME, // <9>
cardTitle, time);} else { // <10>
var speechOutput =
'I\'m sorry, I don\'t know when high tide is for that location';
this.emit(':tell', speechOutput);
}
},
'AMAZON.HelpIntent': function () { // <11>
var speechOutput = "You can say when is high tide in city name, or, " +
"you can say exit... What can I help you with?";
var reprompt = "What can I help you with?";
this.emit(':ask', speechOutput, reprompt);
},
'AMAZON.CancelIntent': function () { // <12>
this.emit(':tell', 'Goodbye!');
},
'AMAZON.StopIntent': function () {
this.emit(':tell', 'Goodbye!');
}
};
----<1> This brings in the Node.js Alexa SDK. When you upload this function to AWS Lambda, you'll be sending a zip file that includes _index.js_ as well as the _node_modules_ directory, which includes the Alexa SDK and many other dependencies.
<2> The _dotenv_ module is a helper utility that will pull in the code from the .env file, which you'll create later. This file will contain your AWS API and app keys.
<3> You'll use the name of the skill in various places, so it's in a handy variable here.
<4> This function sets things up so that all requests are routed to the appropriate handlers, defined next.
<5> `LaunchRequest` is called if the skill is invoked without a command. Since you need a city name to do anything, this handler just calls the help handler.
<6> Inside the handler for the GetTideIntent, the code tries to obtain the city the user asked about.
<7> If there was indeed a city in the request, and it has a name, the handler can do its job.
<8> Here, the handler creates three strings: one for the card title (which will be displayed in the Alexa app), another for the high tide time (hardcoded for now), and the speech output that Alexa will speak to the user.
<9> This causes Alexa to speak her response, and to display a card in the user's Alexa app.
<10> If the handler couldn't discern a city name, Alexa will ask the user to try again.
<11> This causes Alexa to speak the help text for this skill.
<12> These last two handlers take care of a user stopping or cancelling the skill. In most skills, these will have the same behavior. See https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/implementing-the-built-in-intents[Implementing the Built-in Intents] for more information.
////
* Clone this repository
* run `npm install`
////=== Step 3: Set up Your API Keys
Create a file called `.env` to store all the various keys you'll need. For now, you'll just need your App Id. Return to https://developer.amazon.com, sign in, and then click the Alexa link. Click the Get Started link under Alexa Skills Kit, and choose Tide Pooler from the list of skills. You should see the application id; copy that value into the _.env_ file as shown, replacing `` with the app ID from Amazon:
```
APP_ID=
```In your program, you'll refer to this as `process.env.APP_ID`.
NOTE: If you are putting this into a Git repo, you should be sure to add a line for the `.env` file to your `.gitignore` file so that you don't accidentally check your keys into a public repository, which would be bad!
Now you need to zip up everything in the folder into a zip file called _hello-alexa.zip_. Using the command line version of zip, run this command:
----
zip -r hello-alexa.zip index.js package.json .env node_modules
----== Deploy the Lambda Function
Next, sign into the https://aws.amazon.com/console/[AWS Console]. Click Lambda from the list of services. Then:
* In the upper right, click the menu to the right of your name, and make sure your availability zone is set to N. Virginia, as this is the only zone with support for Alexa Skills:
image::images/availability-zones.png[]
* Next, click Get Started Now. You'll be prompted to choose a Blueprint. Scroll down to the bottom of the screen and click Skip.
image::images/select-blueprint.png[]
* Now you're prompted to configure the trigger for this function. Click the dotted shape to the left of Lambda, and choose Alexa Skills Kit, then click Next:
image::images/configure-triggers.png[]
* On the next screen, configure your function as follows:
Name::: Call it TidePooler
Description::: Give it a short description like "High Tide Lookup".
Runtime::: Leave this set at Node.js 4.3
Code Entry Type::: Select Upload a Zip File from the menu.image::images/configure-function.png[]
* Click the Upload button, and select the _hello-alexa.zip_ file you created earlier. Scroll down, and under Role, select Create a New Custom Role. The IAM manager will open in a new tab. Make sure Create a New IAM Role is selected, and that the Role Name is lambda_basic_execution. Click Allow to create the role and you'll return to the previous tab.
image::images/new_role.png[]
* Leave the other values at their defaults, scroll down, and click Next. You'll be prompted to review your function, as shown here:
image::images/review_function.png[]
* Click Create Function, and you'll be taken to the AWS dashboard page for the function. The Lambda function's ARN will appear in the upper right, and begins with _arn:aws:lambda:us-east_. Copy the entire ARN. You will need it in the next step.
== Connect the Alexa Skill to the Lambda function
Return to https://developer.amazon.com, sign in, and then click the Alexa link. Click the Get Started link under Alexa Skills Kit, and choose Tide Pooler from the list of skills. Click Configuration from the list on the left, then:
* Under the Endpoint section, choose Lambda ARN.
* Paste your Lambda function's ARN into the field.
image::images/connect-lambda.png[]
* Leave Account Linking set to No, and click Next. You'll be taken to the service simulator.
Now you're ready to test the skill. Scroll down to the Enter Utterance field, and type in a supported utterance, such as "When is high tide in Boston?" Click Ask Tide Pooler, and you should see the JSON for both the request and response appear in the text fields below. You can click the Play button to the right of the Listen label to hear the response:
image::images/test-skill.png[]
=== Where Next?
There is a lot more you can do from here. The most obvious upgrade is to actually look up high tide information by calling a web service like the Weather Underground API. Right now, Alexa is just telling us that high tide is always at 5pm.
One thing you didn't learn how to do was test this on your own Amazon Echo. To do this, you'll need to register your device for testing, among other things. See https://developer.amazon.com/public/solutions/alexa/alexa-skills-kit/docs/testing-an-alexa-skill[Testing a Custom Skill] for more details.
What if you don't have an Amazon Echo? You could build your own with the $35 Rapsberry Pi: https://www.raspberrypi.org/blog/amazon-echo-homebrew-version/
=== Testing Locally
You might get tired of having to upload a zip file every time you want to test. To test locally, you can install https://www.npmjs.com/package/lambda-local[lambda-local], which allows you to send a JSON file containing a request to a Lambda function.
Install it according to the instructions, then create a file called _event-sample.js_ with the following contents:
----
module.exports = {
"session": {
"application": {
"applicationId": "TEST"
},
"user": {
"userId": "Anonymous"
}
},
"request": {
"type": "IntentRequest",
"intent": {
"name": "GetTideIntent",
"slots": {
"City": {
"name": "City",
"value": "Boston"
}
}
}
}
}
----NOTE: You can also copy this file from this Lesson's https://github.com/oreillymedia/hello-alexa/blob/master/event-sample.js[GitHub repository].
Save that in the same folder as _index.js_, and test it with this command:
----
lambda-local -l index.js -h handler -e event-sample.js
----In the output, you'll see the response that would have been spoken:
----
{
"version": "1.0",
"response": {
"outputSpeech": {
"type": "SSML",
"ssml": " It will be high tide in Boston at 5:00pm "
},
"shouldEndSession": true,
"card": {
"type": "Simple",
"title": "Tide Pooler",
"content": "Tide Pooler High Tide For - Boston"
}
},
"sessionAttributes": {}
}
----