Upload
rick-wargo
View
154
Download
1
Embed Size (px)
Citation preview
RICK WARGO - MAR 2017
BUILD AN ALEXA SKILL STEP-BY-STEP
1
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
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
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
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
BUILD AN ALEXA SKILL STEP-BY-STEP
Prerequisites — Follow Links to Install
▸ Node.js
▸ Gulp
▸ AWS Developer Account
▸ AWS CLI
▸ Twitter Account
6
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
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.
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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'
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
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 :)
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
BUILD AN ALEXA SKILL STEP-BY-STEP
Test Skill from Lambda - Create Test Event
▸ Select Configure test event from the Actions menu
57
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
BUILD AN ALEXA SKILL STEP-BY-STEP
Test Skill from Lambda - Perform the Test
▸ Press Test
▸ The Execution result should show succeeded
59
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
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
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
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
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
BUILD AN ALEXA SKILL STEP-BY-STEP
Contact Me
▸ https://www.rickwargo.com/
▸ https://github.com/rickwargo
▸ https://linkedin.com/in/rickwargo
▸ @rickwargo
▸ https://github.com/rickwargo/twitter-news
▸ https://github.com/rickwargo/alexa-app-root
▸ https://github.com/rickwargo/alexa-app-template
65