Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Build an Alexa Skill Step-by-Step

1,589 views

Published on

A follow-up the the Code Camp 2017.1 presentation, this slide deck walks you through building a skill from start to finish in good detail.

Published in: Technology
  • Be the first to comment

Build an Alexa Skill Step-by-Step

  1. 1. RICK WARGO - MAR 2017 BUILD AN ALEXA SKILL STEP-BY-STEP 1
  2. 2. 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
  3. 3. 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
  4. 4. 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
  5. 5. BUILD AN ALEXA SKILL STEP-BY-STEP User Interaction Flow 5 Twitter API User Voice Request Audio Stream Twitter-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
  6. 6. BUILD AN ALEXA SKILL STEP-BY-STEP Prerequisites — Follow Links to Install ▸ Node.js ▸ Gulp ▸ AWS Developer Account ▸ AWS CLI ▸ Twitter Account 6
  7. 7. 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
  8. 8. 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.
  9. 9. 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 []:cert@epicminds.com [18:07:21] Finished 'make-cert' after 30 s 9
  10. 10. 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
  11. 11. 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
  12. 12. 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
  13. 13. 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
  14. 14. 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
  15. 15. 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
  16. 16. 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
  17. 17. 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
  18. 18. 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
  19. 19. 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
  20. 20. 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
  21. 21. 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
  22. 22. 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
  23. 23. 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
  24. 24. 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
  25. 25. 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
  26. 26. 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
  27. 27. 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
  28. 28. 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
  29. 29. 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
  30. 30. 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
  31. 31. 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-skill
 export 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'
  32. 32. 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
  33. 33. 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 :)
  34. 34. 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
  35. 35. 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
  36. 36. 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
  37. 37. 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
  38. 38. 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
  39. 39. 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
  40. 40. 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
  41. 41. 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
  42. 42. 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
  43. 43. 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
  44. 44. 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
  45. 45. 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
  46. 46. 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
  47. 47. 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
  48. 48. 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
  49. 49. 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
  50. 50. 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
  51. 51. 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 > alexa-app-root@1.0.0 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
  52. 52. 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
  53. 53. 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
  54. 54. 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
  55. 55. 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
  56. 56. 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
  57. 57. BUILD AN ALEXA SKILL STEP-BY-STEP Test Skill from Lambda - Create Test Event ▸ Select Configure test event from the Actions menu 57
  58. 58. 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
  59. 59. BUILD AN ALEXA SKILL STEP-BY-STEP Test Skill from Lambda - Perform the Test ▸ Press Test ▸ The Execution result should show succeeded 59
  60. 60. 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
  61. 61. 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
  62. 62. 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
  63. 63. 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
  64. 64. 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
  65. 65. BUILD AN ALEXA SKILL STEP-BY-STEP Contact Me ▸ https://www.rickwargo.com/ ▸ https://github.com/rickwargo ▸ https://linkedin.com/in/rickwargo ▸ contact@epicminds.com ▸ @rickwargo ▸ https://github.com/rickwargo/twitter-news ▸ https://github.com/rickwargo/alexa-app-root ▸ https://github.com/rickwargo/alexa-app-template 65

×