How to Effectively Manage Your Client-Partner Relationships
Clients Project StrategyClients leave when they feel that their needs aren’t being met. The strength of your client-partner relationship relies on a deep understanding of your client’s...
Editor’s note: This is the second in a series of posts about developing Alexa skills. Read the rest of the posts in this series to learn how to build and deploy an Alexa skill.
In our last post on building Alexa skills, we implemented a model that knows how to talk to the FAA. Now we’ll see how to hook it up to a new Alexa skill. We’ll be using alexa-app as a framework to build our skill, and alexa-app-server will allow us to test interacting with the skill locally.
We will be using these libraries because they grant a path to supporting a local development and testing workflow with an Alexa skill, which allows us to rapidly test and develop. (H/T Matt Kruse!).
The source code for this project is available on GitHub. To begin, pull down the alexa-app-server GitHub repo with the following command:
git clone https://github.com/matt-kruse/alexa-app-server.git
Once you have cloned the repository, install any required dependencies by running:
npm install
Move the faa-info
folder you created in the previous post (or via Github) into the alexa-app-server repository’s ./examples/apps
directory and create a new index.js file
in the faa-info
directory. This is where we’ll implement our skill using the alexa-app Node module we installed just above.
Within the repository, change to the examples directory and run:
node server
You should see:
Loading apps from: apps
Listening on HTTP port 8080
You should now have a running local “skill server,” which gives us a way to test interaction with our skill locally as we build it.
Now we can begin building out our skill.
The first thing our Airport Info skill should do is respond to a launch request from Alexa. This is what will ultimately happen if a user says, “Alexa, launch Airport Info.”
Because we’re developing this skill using the alexa-app module, we have a nice shorthand syntax for defining both the launch request and the speech response. Add the following to the index.js
file you’ve created in the faa-info
directory.
'use strict';
module.change_code = 1;
var _ = require('lodash');
var Alexa = require('alexa-app');
var app = new Alexa.app('airportinfo');
var FAADataHelper = require('./faa_data_helper');
app.launch(function(req, res) {
var prompt = 'For delay information, tell me an Airport code.';
res.say(prompt).reprompt(prompt).shouldEndSession(false);
});
module.exports = app;
Notice the line var app = new Alexa.app('airportinfo');
. This will be what our skill is known as within the context of alexa-app-server.
We recommend having two separate Terminal tabs open at this point: one for directory navigation and one for running your alexa-app-server.
Restart alexa-app-server using “node server” as you did earlier, and open a web browser to http://localhost:8080/alexa/airportinfo. You should see a page with a dropdown for selecting a Request Type. Select “LaunchRequest” and hit “Send Request.” You should see a response similar to the following:
{
"version": "1.0",
"sessionAttributes": {},
"response": {
"shouldEndSession": false,
"outputSpeech": {
"type": "SSML",
"ssml": "<speak>For delay information, tell me an Airport code.</speak>"
},
"reprompt": {
"outputSpeech": {
"type": "SSML",
"ssml": "<speak>For delay information, tell me an Airport code.</speak>"
}
}
},
"dummy": "text"
}
This looks like exactly what we want: instructions that show a user how to use the Airport Info skill.
Let’s take a moment to understand what output was just generated for us as a launch request through Alexa. If you refer to the index.js
file we’ve just created, you’ll see an app.launch
method. This method will be automatically triggered any time the skill is invoked, and it requires a response to be sent to the user. In this case, we’re calling a response.say(prompt)
, which will output the text provided in the var prompt
above it.
Afterwards, you will see a reprompt(prompt)
. This is used any time a user is given the opportunity to say something, and will trigger approximately 8 seconds after the user is prompted the first time. Depending upon the design of your Alexa skill, you may want to shorten this to your liking, e.g. “Tell me an Airport code.”
Lastly, the shouldEndSession(false)
method is the key determining factor as to whether your skill will continue listening for user interaction, or close the skill completely. When designing your skill, it’s important to weigh the benefits of keeping your stream open, as it may feel cumbersome to users if you expect them to continually interact with your skill. In this case, however, we want the user to be able to follow up after the welcome message with a desired airport code, so we’re choosing to leave this stream open (shouldEndSession(false)).
We need to map utterances (training data of what the user may say) to intents (requests to perform functions on your skill service). Then in our web service, we take those intents and run any logic we need. If you are new to the concept of utterance and schema, you can learn more by reading the Amazon documentation for a detailed inquiry into those topics.
Here, we’ll get started on the Intent Schema. First, let’s specify the airportinfo
intent schema and the utterances that can be used to invoke it using the alexa-app and alexa-utterances module. These will define the voice interface for how our user will interact with the skill.
Add the following to index.js
before the module.exports
:
app.intent('airportinfo', {
'slots': {
'AIRPORTCODE': 'FAACODES'
},
'utterances': ['{|flight|airport} {|delay|status} {|info} {|for} {-|AIRPORTCODE}']
},
function(req, res) {
}
);
Now visit http://localhost:8080/alexa/airportinfo again. Select “IntentRequest” and then “airportinfo” from the list.
Since we haven’t yet implemented anything, these “Response” fields won’t contain anything interesting—but check out the rather lengthy sample utterances list that was generated for the airportinfo
intent:
airportinfo {AIRPORTCODE}
airportinfo flight {AIRPORTCODE}
airportinfo airport {AIRPORTCODE}
airportinfo delay {AIRPORTCODE}
airportinfo flight delay {AIRPORTCODE}
airportinfo airport delay {AIRPORTCODE}
airportinfo status {AIRPORTCODE}
airportinfo flight status {AIRPORTCODE}
airportinfo airport status {AIRPORTCODE}
airportinfo info {AIRPORTCODE}
airportinfo flight info {AIRPORTCODE}
airportinfo airport info {AIRPORTCODE}
airportinfo delay info {AIRPORTCODE}
airportinfo flight delay info {AIRPORTCODE}
airportinfo airport delay info {AIRPORTCODE}
airportinfo status info {AIRPORTCODE}
airportinfo flight status info {AIRPORTCODE}
airportinfo airport status info {AIRPORTCODE}
airportinfo for {AIRPORTCODE}
airportinfo flight for {AIRPORTCODE}
airportinfo airport for {AIRPORTCODE}
airportinfo delay for {AIRPORTCODE}
airportinfo flight delay for {AIRPORTCODE}
airportinfo airport delay for {AIRPORTCODE}
airportinfo status for {AIRPORTCODE}
airportinfo flight status for {AIRPORTCODE}
airportinfo airport status for {AIRPORTCODE}
airportinfo info for {AIRPORTCODE}
airportinfo flight info for {AIRPORTCODE}
airportinfo airport info for {AIRPORTCODE}
airportinfo delay info for {AIRPORTCODE}
airportinfo flight delay info for {AIRPORTCODE}
airportinfo airport delay info for {AIRPORTCODE}
airportinfo status info for {AIRPORTCODE}
airportinfo flight status info for {AIRPORTCODE}
airportinfo airport status info for {AIRPORTCODE}
This was generated for us by this line:
'utterances': ['{|flight|airport} {|delay|status} {|info} {|for} {-|AIRPORTCODE}']
Under the hood, alexa-app uses the alexa-utterances module to generate this list. Check that link to get details on the allowed syntax.
We have our intent schema visible here as well. Notice the line in our skill code:
'slots': {
'AIRPORTCODE': 'FAACODES'
}
This defined AIRPORTCODE
, which is a slot with a custom type of FAACODES
we will share with Amazon when registering our skill, and gave alexa-app enough info to generate the schema for us:
{
"intents": [
{
"intent": "airportinfo",
"slots": [
{
"name": "AIRPORTCODE",
"type": "FAACODES"
}
]
}
]
}
Now that we have an intent schema definition including an airportcode
slot, and sample utterances defined for the airportinfo
intent, we can now put to work the FAADataHelper
we built in our first post on developing Alexa Skills locally.
To do that, we will need to update the airportinfo
intent definition located inside the index.js
file we created in the faa-info
directory. Update it to the following:
app.intent('airportinfo', {
'slots': {
'AIRPORTCODE': 'FAACODES'
},
'utterances': ['{|flight|airport} {|delay|status} {|info} {|for} {-|AIRPORTCODE}']
},
function(req, res) {
//get the slot
var airportCode = req.slot('AIRPORTCODE');
var reprompt = 'Tell me an airport code to get delay information.';
if (_.isEmpty(airportCode)) {
var prompt = 'I didn't hear an airport code. Tell me an airport code.';
res.say(prompt).reprompt(reprompt).shouldEndSession(false);
return true;
} else {
var faaHelper = new FAADataHelper();
faaHelper.requestAirportStatus(airportCode).then(function(airportStatus) {
console.log(airportStatus);
res.say(faaHelper.formatAirportStatus(airportStatus)).send();
}).catch(function(err) {
console.log(err.statusCode);
var prompt = 'I didn't have data for an airport code of ' + airportCode;
res.say(prompt).reprompt(reprompt).shouldEndSession(false).send();
});
return false;
}
}
);
//hack to support custom utterances in utterance expansion string
var utterancesMethod = app.utterances;
app.utterances = function() {
return utterancesMethod().replace(/{-|/g, '{');
};
Now we can test how this behaves from alexa-app-server.
We have three cases to test:
Given an airportInfo intent request:
airportCode
slot is empty, I should should get “I didn’t hear an airport code. Tell me an airport code.”airportCode
, I should get “I didn’t have data for an airport code of AIRPORTCODE.”airportCode
was a code the FAA Server recognized, then I should get a response matching the FAADataHelper
’s response we tested earlier.Let’s try the first test case. Hit http://localhost:8080/alexa/airportinfo and select “IntentRequest” and “airportinfo” from the list. Don’t type anything into “AIRPORTCODE.” Hit “Send Request,” and you should then see the following in the Response box:
{
"version": "1.0",
"sessionAttributes": {},
"response": {
"shouldEndSession": false,
"outputSpeech": {
"type": "SSML",
"ssml": "<speak>I didn't hear an airport code. Tell me an airport code.</speak>"
},
"reprompt": {
"outputSpeech": {
"type": "SSML",
"ssml": "<speak>Tell me an airport code to get delay information.</speak>"
}
}
},
"dummy": "text"
}
Nice! That looks right. Now let’s try the second case. Do the same thing but enter “PUNKYBREWSTER” for the AIPRORTCODE field.
{
"version": "1.0",
"sessionAttributes": {},
"response": {
"shouldEndSession": false,
"outputSpeech": {
"type": "SSML",
"ssml": "<speak>I didn't have data for an airport code of PUNKYBREWSTER</speak>"
},
"reprompt": {
"outputSpeech": {
"type": "SSML",
"ssml": "<speak>Tell me an airport code to get delay information.</speak>"
}
}
},
"dummy": "text"
}
Just what we expected. Now for the last case, let’s try entering “ATL” for the AIRPORTCODE.
{
"version": "1.0",
"sessionAttributes": {},
"response": {
"shouldEndSession": true,
"outputSpeech": {
"type": "SSML",
"ssml": "<speak>There is currently no delay at Hartsfield-Jackson Atlanta International. The current weather conditions are A Few Clouds, 51.0 F (10.6 C) and wind North at 0.0mph.</speak>"
}
},
"dummy": "text"
}
Success! Thanks to these local results, we can begin the process of deploying to Amazon while feeling fairly confident that our skill works as expected. We’ll still need to test interaction with the the actual device, but with this workflow, we should have greatly improved our chances of deploying without bugs.
At this point, you’ve been given some useful tools and techniques for more easily developing an Alexa skill locally. With a local development environment setup, you will gain access to the debugger and the stack trace, and you’ll be able to work more efficiently by quickly testing changes without uploading files to a remote server.
In Part 3 of this series, we move from local to live. We’ll go over how you can test your skill on an Amazon Echo or another Alexa-enabled device by creating a new skill on the Amazon Alexa Developer Console, and then deploying your code to AWS Lambda.
Don’t wait until then. Check out the source code for the project we built above and get going!
Clients leave when they feel that their needs aren’t being met. The strength of your client-partner relationship relies on a deep understanding of your client’s...
Responding to change is a key tenant of Agile Software Development. Predicting change is difficult, but software can be developed in a manner that...
A lot of this confusion surfaces around the scope of machine learning. While there is a lot of hype around deep learning, it is...