Top Banner
RICK WARGO - MAR 2017 BUILD AN ALEXA SKILL STEP-BY-STEP 1
65

Build an Alexa Skill Step-by-Step

Mar 20, 2017

Download

Technology

Rick Wargo
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Build an Alexa Skill Step-by-Step

RICK WARGO - MAR 2017

BUILD AN ALEXA SKILL STEP-BY-STEP

1

Page 2: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Introduction

▸ This tutorial will guide you step-by-step to create a new Alexa skill

▸ This example skill will interface with Twitter and read recent tweets from a query

▸ The aim is to be able to extend this workflow for your own use

▸ This skill will be called Twitter News and will be private

▸ This tutorial will not cover publishing a new skill - there is plenty of available documentation on how to publish

▸ Please let me know if you use this to build a new skill — I welcome feedback!

2

Page 3: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Sample Interactions — Define Prior to Building New Skill▸ The critical path to creating a great skill is pre-visualization of the skill

▸ Try to define the interactions as much as possible and maintain in a file, for example, Examples.txt

▸ Q: What's the latest news?

▸ A: The last 1 tweet was: Rick Wargo tweeted: Join me this Sat at 11:30am - we'll build an Alexa skill that interfaces with Twitter at #PhillyCode @PhillyDotNet.

▸ Q: What's the latest popular tweet?

▸ A: There were no matching tweets.

▸ Q: What is the last 5 tweets?

▸ A: The last 5 tweets were: Rick Wargo tweeted: Join me this Sat at 11:30am - we'll build an Alexa skill that interfaces with Twitter at #PhillyCode @PhillyDotNet. Alina retweeted Stratisplatform's tweet: #Stratis are gold sponsors @PhillyDotNet on 24th-25th February explaining our #blockchain t…

▸ Q: What is the last tweet from Rick?

▸ A: The last 1 tweet was: Rick Wargo tweeted: Join me this Sat at 11:30am - we'll build an Alexa skill that interfaces with Twitter at #PhillyCode @PhillyDotNet.

▸ Q: Who tweeted?

▸ A: Recent tweets were from: Rick Wargo, Kucilo Oro, Alina, XTexplorer, and Mohammad Khalid.

▸ Q: Who shared?

▸ A: Recent tweets were from: Rick Wargo, Kucilo Oro, Alina, XTexplorer, and Mohammad Khalid.

3

Page 4: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Assumptions

▸ Implementing on OSX 10.12.3

▸ Using AWS Lambda and Node.js 4.3 to host code

▸ Linux-style commands used throughout

# Commands to be executed at the command line are in this style

▸ Input from interactive commands is in bold text

▸ References to files point to the completed version of the twitter-news-skill in Github

▸ Depending on copy/paste, some files may require retouching, mostly white-space, for lint to succeed

▸ All commands to be executed from skill directory unless otherwise noted

▸ Should work with slight modifications on Windows

4

Page 5: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

User Interaction Flow

5

Twitter API

User

Voice Request Audio StreamTwitter-News

Skill

Lambda

JSON Request

Node.js

JSON Response (SSML+Card)

Response (Audio)

Response (Text/Graphics)

Audio Response

App/Web

JSON Response (statuses)

GET search/tweets

Page 6: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Prerequisites — Follow Links to Install

▸ Node.js

▸ Gulp

▸ AWS Developer Account

▸ AWS CLI

▸ Twitter Account

6

Page 7: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

AWS Credentials

‣ For command line access to AWS, store credentials in ~/.aws/credentials

$ cat ~/.aws/credentials [default] aws_access_key_id = OATLIM5W7KKX1V6PQ792 aws_secret_access_key = I2WiUyTkPI7b36PQnin11oUqgZVX575tSUAB1FOm

‣ This may already be done when setting up the AWS CLI

‣ Development on Windows will require a different approach to storing this file

Not my real credentials :)

7

Page 8: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Create the Directory Structure

▸ Create a directory where both the Alexa skills and the Alexa App Server will live. All new skills will live under here.

▸ For this tutorial, we’ll use ~/Code/alexa-js

▸ In that directory:

cd ~/Code/alexa-js git clone https://github.com/rickwargo/alexa-app-root mkdir alexa-js-apps†

▸ Install the node modules for alexa-app-root

cd alexa-app-root npm install

8

†If you choose to call this directory something else, you’ll need to update filesPath.server in gulpfile.js. You’ll also need to update server.js and change app_dir to point to the directory.

Page 9: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Create Certificate for HTTPS (if using)▸ Install a self-signed certificate for HTTPS

gulp make-cert [18:06:51] Using gulpfile ~/Code/alexa-js/test/alexa-app-root/gulpfile.js [18:06:51] Starting 'make-cert'... Generating RSA private key, 1024 bit long modulus ...++++++ .............++++++ e is 65537 (0x10001) You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) [AU]:US State or Province Name (full name) [Some-State]:Pennsylvania Locality Name (eg, city) []:Blue Bell Organization Name (eg, company) [Internet Widgits Pty Ltd]:epicminds Organizational Unit Name (eg, section) []: Common Name (e.g. server FQDN or YOUR name) []:Rick Wargo Email Address []:[email protected] [18:07:21] Finished 'make-cert' after 30 s

9

Page 10: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Test Web Server is Running

▸ Browse to http://localhost:8003/test

▸ Also test https://localhost:8003/test

10

Page 11: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Start a New Skill

▸ Fork the alexa-app starter template, if desired

https://github.com/rickwargo/alexa-app-template

▸ Clone into a directory under alexa-js-apps

cd ~/Code/alexa-js/alexa-js-apps git clone https://github.com/rickwargo/alexa-app-template twitter-news

▸ Alternately, all code is available from Github (don’t do this if you want to code by hand)

cd ~/Code/alexa-js/alexa-js-apps git clone https://github.com/rickwargo/twitter-news

11

Page 12: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Install Node Modules

▸ Use npm install to download and install all modules in package.json

cd twitter-news npm install

12

Page 13: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Test Fresh Installation▸ Run the default tests using gulp

▸ test-mock runs the test runner framework (mocha, chai is the test framework) — only a few tests are shown below

gulp test-mock [12:14:16] Using gulpfile ~/Code/alexa-js/alexa-js-apps/twitter-news/gulpfile.js [12:14:16] Starting 'test-mock'... App Starter Tests starting up ✓ should fail if an unknown application id is provided ✓ should fail if a missing application is provided

... My Intents the story intent ✓ tells you the whole story ✓ tells a partial story when asked

Text for exception message ✓ returns exception message if supplied ✓ returns message if supplied

21 passing (23ms)

[12:14:16] Finished 'test-mock' after 569 ms

13

Page 14: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Create an AWS IAM Role for Lambda Code Execution▸ Name should be function name (later we’ll name it twitter-news-skill) followed by “-role”

aws iam create-role --role-name twitter-news-skill-role --assume-role-policy-document file://assets/json/aws/trust-policy.json { "Role": { "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": { "Action": "sts:AssumeRole", "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" } } }, "RoleId": "ZG7523QZS8J7R951Y3C0J", "CreateDate": "2017-02-27T17:59:56.785Z", "RoleName": "twitter-news-skill-role", "Path": "/", "Arn": "arn:aws:iam::123456789012:role/twitter-news-skill-role" } }

▸ From the create-role output, copy Arn JSON value and update the role in config/aws-config.js

14

Page 15: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Attach Policy to Newly Created Role

▸ Attach an Amazon-managed policy to the twitter-news-skill-role

aws iam attach-role-policy --role-name twitter-news-skill-role --policy-arn arn:aws:iam::aws:policy/AWSLambdaFullAccess

▸ Access can be changed by choosing a different policy below or roll your own

✦ AWSLambdaFullAccess

✦ AWSLambdaDynamoDBExecutionRole

✦ AWSLambdaBasicExecutionRole

15

Page 16: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Give the Alexa Service Access

▸ This is the same as adding the Alexa Skills Kit as a trigger to the Lambda function

aws lambda add-permission --function-name twitter-news-skill --statement-id 1 --action lambda:invokeFunction --principal alexa-appkit.amazon.com --region us-east-1 { "Statement": "{\"Sid\":\"1\",\"Resource\":\"arn:aws:lambda:us-east-1:100866613345:function:twitter-news-skill\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"alexa-appkit.amazon.com\"},\"Action\":[\"lambda:invokeFunction\"]}" }

▸ More information can be found in the AWS Lambda Developer Guide

16

Page 17: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Edit config/aws-config.js prior to Pushing Lambda Code to AWS

▸ Ensure role is updated per Create an AWS IAM Role for Lambda Code Execution

▸ The region defaults to us-east-1 — update as necessary

▸ If you use a specific AWS credentials profile, update the profile value — defaults to “default”.

▸ Update timeout and memorySize, if needed. The defaults of 3 seconds and 128MB are usually sufficient.

▸ Runtime should be nodejs4.3, unless a newer version was released after this documentation

17

Page 18: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Update config/app-config.js prior to Pushing Lambda Code to AWS

▸ The applicationId can be left as-is until the skill is created on the Amazon Alexa Developer Portal

▸ Update the applicationName to “twitter-news”

▸ Update the functionName to be the applicationName followed by “-skill”, so it would be “twitter-news-skill”

▸ Update the description to reflect the skill’s intent, i.e. “Grabs the latest or popular tweets about a specific topic”

18

Page 19: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Update Config Tests in test/test_config.js

▸ Due to changes to some default settings, tests need to be updated to reflect the change(s)

▸ Update AWS Config —> Property —> region test if changed from us-east-1

▸ Update AWS Config —> Property —> runtime test if changed from nodejs4.3

▸ Update AWS Config —> Property —> applicationName test to reflect the new application name

▸ For example, change test/test_config.js (around line 47) such that it reads:

it('applicationName is twitter-news', function () { var result = config.applicationName; return result.should.equal('twitter-news'); });

19

Page 20: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Push Code to AWS Lambda

▸ Upload the code to AWS Lambda using “gulp push”

gulp push

▸ Upon successful completion, the test-lambda gulp task will pass all tests

20

Page 21: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Connect to the Alexa Developer Portal

▸ Browse to the Alexa Developer Portal

▸ Press Get Started > on the Alexa Skills Kit button

21

Page 22: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Create The Skill on the Alexa Developer Portal

▸ Press Add a New Skill in the top-right of the following page

22

Page 23: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Fill Out the Skill Information

▸ Keep the Skill Type as Custom Interaction Model

▸ Set the Name to the application name (defined previously), Twitter News

▸ Set the invocation name to the application name (in lower case), twitter news

▸ Leave Audio Player defaulted to No

▸ Press the Save button

23

Page 24: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Get the AWS Lambda ARN for the Lambda Function▸ In the terminal window, get the function definition

aws lambda get-function --function-name twitter-news-skill { "Code": { "RepositoryType": "S3", "Location": “https://prod-04-2014-tasks.s3.amazonaws.com/snapshots/123456789012/twitter-news-skill-00000000-0000-0000-0000-000000000000?X-Amz-Security-Token=..." }, "Configuration": { "Version": "$LATEST", "CodeSha256": "JZKRixkiCQ5NQwHt5/tUna61fqDDfnWGKfgsWnyUJKA=", "FunctionName": "twitter-news-skill", "MemorySize": 128, "CodeSize": 6575734, "FunctionArn": "arn:aws:lambda:us-east-1:123456789012:function:twitter-news-skill", "Handler": "index.handler", "Role": "arn:aws:iam::123456789012:role/twitter-news-skill-role", "Timeout": 3, "LastModified": "2017-02-27T18:40:44.411+0000", "Runtime": "nodejs4.3", "Description": "Grabs the latest or popular tweets about a specific topic" } }

24

Page 25: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Configure the New Skill

▸ Click Configuration to set the skill’s endpoint

▸ We’ll skip the Interaction Model for now until we develop the code

▸ Select AWS Lambda ARN for the Service Endpoint Type and select the North America region

▸ Copy the FunctionARN value from the previous step into the text box under North America

▸ Keep the default of No in Account Linking

▸ Press Save

25

Page 26: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Update the Skill’s Application Id in config/applicationid.json

▸ From the previous step, copy the ID in the top-left of the page (under the application name Twitter News) and paste it into the value for applicationId in config/applicationid.json

▸ application.json is not stored in Github to keep the Id private

{ "applicationId": "amzn1.ask.skill.00000000-0000-0000-0000-000000000000" }

26

Page 27: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Update package.json

▸ Update package.json to set alexa.applicationId to the value Id found in Configure the New Skill

▸ Update name to “twitter-news” (the name of the application specified in config/app-config.js)

▸ Update the version, description, author, license, and other URLs as necessary

27

Page 28: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Remove Sample Code

▸ Remove the sample StoryIntent and supporting dictionary and custom slot type in index.js:

▸ Delete the block beginning with: Object.assign(app.dictionary, {

▸ Delete the block beginning with: app.customSlotType('STORY_TYPE',

▸ Delete the block beginning with: app.intent('StoryIntent', {

▸ Remove all the tests in test/test_intents.js — these were for the sample code

28

Page 29: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Create a New Twitter Application

▸ A new Twitter application is needed to gain keys and secrets for API access

▸ Browse to https://apps.twitter.com/

▸ Press Create New App and fill out details

▸ Name: My-Twitter-News

▸ Note the name may be taken by another application. Try to prefix with your organization or initials. This name is not important for the skill - only the access tokens and keys are necessary.

▸ Description: Grabs the latest or popular tweets about a specific topic

▸ Website: http://example.com/twitternews

29

Page 30: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Grant Permissions to Twitter Application

▸ For this skill, we’ll only need read permission

▸ On the Permissions tab, select Read only and press Update Settings

30

Page 31: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Twitter Application Keys and Access Tokens

▸ You’ll need both consumer and access token

▸ Click on the Keys and Access Tokens tab

▸ Near the bottom of the page press Create my access token. This will provide the Access Token and Access Token Secret necessary to connect to the Twitter API.

▸ Save the values and add to your environment under the following environment variable names:

▸ TWITTER_CONSUMER_KEY ▸ TWITTER_CONSUMER_SECRET ▸ TWITTER_ACCESS_TOKEN_KEY ▸ TWITTER_ACCESS_TOKEN_SECRET

31

Not my real keys :)

Don’t skip the step! You’ll need to take appropriate actions depending on your OS. For example, on Linux and OS X:# Keys for twitter-news-skillexport TWITTER_CONSUMER_KEY='consumer key'export TWITTER_CONSUMER_SECRET='consumer secret'export TWITTER_ACCESS_TOKEN_KEY='token key'export TWITTER_ACCESS_TOKEN_SECRET='token secret'

Page 32: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Configure Your Environment for Access to the Twitter

‣ Configure environment for keys for access to the Twitter API

‣ For OS X and Linux, add to ~/.bash_profile (or ~/.bashrc)

# Keys for twitter-news-skill export TWITTER_CONSUMER_KEY=hSYvOtda3Ri74PkyuTOHrLMdf export TWITTER_CONSUMER_SECRET=LXHvTRShADq0s8lOlHCPodPw1smNeJ5p6E8GyOlY9cM0Ti5QSX export TWITTER_ACCESS_TOKEN_KEY=WVUXxMzZPrszP2AO3eQIogJNFIA2vqkO5bmRkCiO1zCdr7KSt6 export TWITTER_ACCESS_TOKEN_SECRET=tMOuVnb3nrlwtNgUtr9qCZTdEqj6SpqbJrt7uysGuf5oU

‣ Log out and log in again to set up environment

Not my real keys :)

32

Page 33: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Set Lambda Environment Variables for Access to Twitter

▸ After configuring a New Twitter App, two pairs of Keys/Secrets are available for use

▸ Copy them and paste into the Environment variables section

▸ Enable encryption helpers for more security

33

Not my real keys :)

Page 34: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Create Twitter Module to Gain Access to Twitter API

▸ Create lib/twitter.js and add the following code:

var Twitter = require('twitter');/** * Connect to the Twitter API. Gain access via environment variables. * Optionally replace with actual strings (not recommended). */var client = new Twitter({ consumer_key: process.env.TWITTER_CONSUMER_KEY, consumer_secret: process.env.TWITTER_CONSUMER_SECRET, access_token_key: process.env.TWITTER_ACCESS_TOKEN_KEY, access_token_secret: process.env.TWITTER_ACCESS_TOKEN_SECRET});module.exports = client;

34

Page 35: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Add Tests for Twitter Module▸ Create test/test_twitter.js and add the following code:

/*global describe, it, beforeEach */'use strict';var chai = require('chai'), chaiAsPromised = require('chai-as-promised');chai.use(chaiAsPromised);chai.should();////////////// Tests Twitter //////////////describe('Twitter', function () { describe('New Client', function () { var twitter; beforeEach(function () { // here for code coverage twitter = require('../lib/twitter'); }); it('should return an object', function () { return twitter.should.be.an('object'); }); it('should have a version of at least 1.7.0', function () { var versionCompare = require('./../vendor/version_compare'); var comparison = versionCompare(twitter.VERSION, '1.7.0'); return comparison.should.be.at.least(0); // same or higher version }); });});

35

Page 36: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Run Twitter Tests

▸ Run tests again, testing recently added Twitter tests

gulp test-mock # (or simply use the alias test, gulp test) ... Twitter New Client ✓ should return an object ✓ should have a version of at least 1.7.0

21 passing (32ms)

[10:59:20] Finished 'test-mock' after 338 ms

36

Page 37: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Create the Intent — WhosTweeted

▸ This intent is designed to return the last N unique twitterers from tweets matching our search criteria

▸ This is a simple intent: it doesn’t take any slot values

▸ It is invoked when the Echo understands one of the following utterances while in the skill:

▸ Who tweeted recently

▸ Who shared recently

▸ Who recently tweeted

▸ Who recently shared

▸ It depends on being able to grab the latest tweets

▸ It depends on a function to take the latest tweets and find the last N unique twitterers (uniqueTwitterers)

▸ It depends on a function to take the last N unique twitterers and format them for output (recentTweetsFrom)

37

Page 38: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Create Unique Twitterers Function and Associated Tests

▸ Create the following files using the code available in https://github.com/rickwargo/twitter-news

▸ lib/helpers/unique_twitterers.js

▸ lib/constants.js

▸ test/test_unique_twitterers.js

38

Page 39: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Run Twitter Tests for Unique Twitterers Function

▸ Run tests again, testing recently added Twitter tests

gulp test ...

Unique Twitterers Users of no length ✓ should be an empty list of one unique user ✓ should be list of length one ✓ should be list of length one if duplicates of multiple unique users ✓ should be a list of the unique users ✓ should be list of the unique users

26 passing (34ms)

39

Page 40: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Create Recent Tweets From Function and Associated Tests▸ Create the following functions using the code available in https://github.com/rickwargo/twitter-news/blob/master/lib/text.js

▸ recentTweetsFrom

▸ noRecentTweets

▸ Add tests for recentTweetsFrom in test/test_text.js

describe('for recent tweets from', function () { it('returns no one if no recent tweets', function () { var result = Text.recentTweetsFrom([]); return result.should.equal(Text.noRecentTweets); }); it('returns one user if only one user', function () { var result = Text.recentTweetsFrom(['alpha']); return result.should.equal('Recent tweets were from: alpha.'); }); it('returns one user if only one user', function () { var result = Text.recentTweetsFrom(['alpha', 'beta', 'gamma']); return result.should.equal('Recent tweets were from: alpha, beta, and gamma.'); });});

▸ Run tests using “gulp test” — there should now be 29 passing tests

40

Page 41: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Create the WhoTweeted Intent Handler in index.js▸ Add the following code into index.js

app.intent('WhoTweeted', { utterances: [ 'Who {tweeted|shared} {recently|}', 'Who recently {tweeted|shared}' ]}, function (ignore, response) { return Twitter.get('search/tweets', TwitterParams) .then(function (tweets) { var users = uniqueTwitterers(tweets.statuses, Constants.MAX_USERS); var msg = Text.recentTweetsFrom(users); response.say(msg); });});

▸ Add the following requires to index.js

Twitter = require('./lib/twitter'),Text = require('./lib/text'),Constants = require('./lib/constants'), uniqueTwitterers = require('./lib/helpers/unique_twitterers');

41

Page 42: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

alexa-utterances

▸ Utterances are kept with the skill definition in the code

▸ Utterances are condensed using alternation, being able to expand the utterance with each word in the curly braces using the alexa-utterances node module

▸ This module is installed by default with the starter template

▸ For more information refer to the project’s README

42

Page 43: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Add Tests for WhosTweeted in test/test_intents.js▸ For testing, stub the Twitter.get() function with “sinon” returning a promise as the stub result instead of a call to the Twitter API

▸ To stub Twitter.get(), Add the following code before the tests

var sinon = require('sinon');var sinonStubPromise = require('sinon-stub-promise');sinonStubPromise(sinon);

▸ Add the following require’s

Text = require('./lib/text'),Twitter = require(‘./lib/twitter');

▸ Add the following tests

▸ Include code block from around line 41 starting with describe('#WhoTweeted', function () {

▸ Wrap the preceding code block with:

describe('using a mock client', function () { var get; beforeEach(function () { get = sinon.stub(Twitter, 'get').returnsPromise(); }); afterEach(function () { get.restore(); }); // #WhoTweeted tests go here });

▸ Run tests using “gulp test” — there should now be 32 passing tests

43

Page 44: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Create the Intent — LatestTweets

▸ This intent is designed to return the last N tweets matching our search criteria

▸ This intent takes three slot values, two standard Amazon slot types and one custom slot type

▸ It is invoked when the Echo understands one of the following utterances while in the skill:

▸ What’s the most recent tweet

▸ For the news

▸ What are the last three tweets

▸ The last tweet from Rick

▸ It depends on being able to grab the latest tweets

▸ It depends on a function to take the last N tweets and format them for output (tweet2say)

44

Page 45: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Create Text Functions and Associated Tests

▸ Create the following functions using the code available in https://github.com/rickwargo/twitter-news/blob/master/lib/text.js

▸ lastTweets

▸ noMatchingTweets

▸ Add tests for lastTweets in test/test_text.js

describe('for LastTweet', function () { describe('of a single item', function () { it('is singular in its response', function () { var result = Text.lastTweets(1); return result.should.equal('The last 1 tweet was: '); }); it('is plural in its response', function () { var result = Text.lastTweets(2); return result.should.equal('The last 2 tweets were: '); }); });});

▸ Run tests using “gulp test” — there should now be 34 passing tests

45

Page 46: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Create tweet2say Function and Associated Tests

▸ Create the tweet2say function using the code available in https://github.com/rickwargo/twitter-news/blob/master/lib/helpers/tweet2say.js

▸ Create tests for the tweet2say function using the code available in https://github.com/rickwargo/twitter-news/blob/master/test/test_tweet2say.js

▸ Run tests using “gulp test” — there should now be 41 passing tests

46

Page 47: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Prepare the LatestTweets Intent Handler in index.js

▸ Add the require for tweet2say to index.js

tweet2say = require('./lib/helpers/tweet2say'),

▸ Add dictionary near the top of index.js

Object.assign(app.dictionary, { tweet: ['tweet', 'tweets', 'item', 'items', 'story', 'stories', 'news', 'news item', 'news items', 'news story', 'news stories', 'post', 'posts', 'update', 'updates', 'message', 'messages'], whats: ['what is', 'what are', 'what\'s', 'about', 'give me', 'tell me'], the: ['the', 'a', 'an']});

▸ Add the custom slot for the intent handler to index.js

app.customSlotType('TWEET_CATEGORIES', ['popular', 'latest', 'recent', 'last']);

47

Page 48: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Create the LatestTweets Intent Handler in index.js

▸ Add the following code to index.js

var TwitterParams = { q: '#PhillyCode OR #PhillyCC OR @PhillyDotNet', result_type: 'recent', // options: 'recent', 'mixed', or 'popular' since_id: '', include_entities: false};

app.intent('LatestTweets', { slots: { Count: 'AMAZON.NUMBER', User: 'AMAZON.US_FIRST_NAME', TweetCategory: 'TWEET_CATEGORIES' }, utterances: [ '{whats|} {the} {tweet}', '{whats|} {-|Count} {tweet}', '{whats|} {the} {most|} {-|TweetCategory} {tweet}', '{whats|} {the} {most|} {-|TweetCategory} {-|Count} {tweet}', '{whats|} {the} {most|} {-|TweetCategory} {tweet} from {-|User}' ]}, function (request, response) {

48

Page 49: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Create the LatestTweets Intent Handler in index.js (cont’d)▸ Add the following code to the end of the intent handler for LatestTweets in index.js

}, function (request, response) { var max_tweets = Math.min(request.slot('Count') || 1, Constants.MAX_TWEETS); var user = request.slot('User') || null; var tweetCategory = request.slot('TweetCategory') || 'recent'; TwitterParams.result_type = tweetCategory.toLowerCase() === 'popular' ? 'popular' : 'recent'; return Twitter.get('search/tweets', TwitterParams) .then(function (tweets) { // Filter var counter = 0; return tweets.statuses.filter(function (tweet) { // select if within max tweets and user matches, if specified var select = (counter < max_tweets) && (!user || tweet.user.name.toLowerCase().indexOf(user.toLowerCase()) > -1); if (select) { counter += 1; } return select; }); }) .then(function (tweets) { // Say matching tweets var msg; if (tweets.length > 0) { msg = Text.lastTweets(tweets.length) + tweet2say(tweets); } else { msg = Text.noMatchingTweets; } response.say(msg); });});

49

Page 50: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Add Tests for LatestTweets in test/test_intents.js

▸ Add the following tests

▸ Include code block from around line 79 starting with describe('#LatestTweets', function () {

▸ Run tests using “gulp test” — there should now be 52 passing tests

▸ Add a test against the Twitter API instead of a mock

describe('against the Twitter API', function () { describe('#LatestTweets', function () { describe('response', function () { it('contains the latest tweets', function () { var result = request.intentRequest({name: 'LatestTweets'}); return result.should.eventually.match(/<speak>The\ last\ 1\ tweet\ was:/); }); }); });});

▸ Run tests again using “gulp test” — there should now be 53 passing tests

50

Page 51: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Start Web Server for Testing Using the Web-based Interface

▸ Start the server with “npm start”

npm start > [email protected] start /Users/rick/Code/alexa-js/alexa-app-root > node server.js --start

serving static content from: /Users/rick/Code/alexa-js/alexa-app-root/public_html loading server-side modules from: /Users/rick/Code/alexa-js/alexa-app-root/server loaded /Users/rick/Code/alexa-js/test/alexa-app-root/server/.gitkeep loading apps from: /Users/rick/Code/alexa-js/alexa-js-apps/ loaded app [twitter-news] at endpoint: /alexa/twitter-news enabling https listening on https port 8443 listening on http port 8003

51

Page 52: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Test Using the Web-based Interface

▸ Browse to http://localhost:8003/test/

▸ There should only be one app loaded: twitter-news

▸ Click on Launch Request and press submit; the welcome message should appear. You can update the welcome message in lib/text.js at onLaunchPrompt.

▸ Experiment with the various intents to see if they work as expected

52

Page 53: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Finalize Alexa Skill Configuration — Intent Schema

▸ Populate Interaction Model

▸ Using the test web page, copy the Schema (click on Schema in top-right and then clock Copy to Clipboard) and paste into Intent Schema in Alexa Skill page

53

Page 54: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Finalize Alexa Skill Configuration — Custom Slot Types

▸ Add a Custom Slot Type by pressing Add Slot Type and enter TWEET_CATEGORIES for the type and the list of slot types from the test web page under Values

54

Page 55: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Finalize Alexa Skill Configuration — Sample Utterances

▸ Add to Sample Utterances the list of utterances generated from the test web page. Note how only a few lines of utterances in the code expanded to over 2,600 different utterances!

55

Page 56: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Build the Alexa Skill Interaction Model

▸ When all three areas are populated, press Save to build the interaction model

▸ You’ll see a message while it is building. It may take up to a minute to build the model.

56

Page 57: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Test Skill from Lambda - Create Test Event

▸ Select Configure test event from the Actions menu

57

Page 58: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Test Skill from Lambda - Input Test Event

▸ Do not select a Sample event template - just paste over what is there

▸ Copy the JSON from the Request tab on the web test page and paste into the code area

▸ Press Save

58

Page 59: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Test Skill from Lambda - Perform the Test

▸ Press Test

▸ The Execution result should show succeeded

59

Page 60: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Test Skill from Alexa Skill Portal - Select Test Pane

▸ Press Test in the left panel to bring up the testing pane

60

Page 61: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Test Skill from Alexa Skill Portal - Perform Test

▸ In the Service Simulator, enter what is the latest news under Enter Utterance and press Ask Twitter News

▸ A valid Lambda Response should appear

61

Page 62: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Test Skill using echosim.io

▸ Go to https://echosim.io and sign in to Echosim.io using your Amazon account

▸ Don’t worry, it’s safe as it uses OAUTH

62

Page 63: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Test Skill using echosim.io by Speaking

▸ Press the record button and say Ask Twitter News for the latest

▸ You should hear the latest tweet

▸ Try testing other utterances

63

Page 64: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Test on Your Own Device

▸ If your Echo is linked to the same account as your Amazon developer account, the skill is automatically enabled on your Echo and any other devices linked to the same account

▸ Repeat the same questions to your Amazon Echo

▸ The skill is now ready for your enjoyment and tweaking!

64

Page 65: Build an Alexa Skill Step-by-Step

BUILD AN ALEXA SKILL STEP-BY-STEP

Contact Me

▸ https://www.rickwargo.com/

▸ https://github.com/rickwargo

▸ https://linkedin.com/in/rickwargo

[email protected]

▸ @rickwargo

▸ https://github.com/rickwargo/twitter-news

▸ https://github.com/rickwargo/alexa-app-root

▸ https://github.com/rickwargo/alexa-app-template

65