Building an Amazon Echo (Alexa) Skill

We got Amazon Echo in our home sometime last year, and both Kunal Mudgal (dear husband!) and I have become very dependent on Alexa. Some of the first conversations of our day are with Alexa. “Alexa, what’s the weather” or “Alexa, what’s happening in Jersey City” are some of the questions we throw at device almost every day. With all the amazing skills offered, we thought it would be great if Alexa could tell us the Next PATH Train between two PATH stations and wanting to work on a project together we set out to build our skill — “Unofficial Path Train Guide” (in Node.js). You can check the whole code base here and our skill here.

Understanding the sdk

The first step was understanding the framework. Amazon has built an awesome sdk for interacting with Alexa — alexa-sdk. It is well documented, light weight package. To install this package run:

npm install alexa-sdk --save

Design requirements and mapping to intents

Next step was deciding on the key phase 1 requirements. We decided at the very least Amazon Echo should be able to respond to the following questions

Alexa, Ask Train Guide when is the next train from Grove Street to Hoboken
Alexa, Ask Train Guide World Trade Center to 33rd street

Thus we needed to define at least one intent and have it accept 2 inputs or slots. Intents and slots are defined on the Alexa developer interface. For each intent there is a handler which get called and executed when the intent is invoked.

Thus programmatically the command we invoke on Echo can be thought of as:

Alexa, Ask {{skill invocation}} when is the next train from {{source}} to {{destination}}

alexa-sdk ships with some predefined intents which can be readily used in the handler code. In addition to using AMAZON.RepeatIntent, AMAZON.HelpIntent, AMAZON.StopIntent, AMAZON.CancelIntent we added one more intent :

Intent Definitions
Slot and Utterances Definition

Handler

Intents need to to be backed by handlers. Handlers are basically functions that get invoked as response to an intent. For our custom PathGuideIntent, we defined the handler as follows:

'PathGuideIntent': function() {
if (_.isUndefined(this.event.request.intent.slots.Source.value) || _.isUndefined(this.event.request.intent.slots.Destination.value)) {
const speechOutput = `$ {
languageString.SOURCE_DEST_NOT_FOUND
}
$ {
languageString.ITEM_NOT_FOUND_REPROMPT
}`;
this.emit(':ask', speechOutput, languageString.ITEM_NOT_FOUND_REPROMPT);
} else {
const sourceStation = this.event.request.intent.slots.Source.value.toLowerCase();
const destStation = this.event.request.intent.slots.Destination.value.toLowerCase();
const self = this;
return transitController.getNextTrain(sourceStation, destStation).then(function(output) {
console.log(`API Response: $ {
JSON.stringify(output, null, 2)
}`);
        if (output.isError) {
self.attributes['speechOutput'] = languageString.ERROR_MESSAGE;
self.attributes['repromptSpeech'] = languageString.ITEM_NOT_FOUND_REPROMPT;
const speechOutput = `$ {
languageString.ERROR_MESSAGE
}, $ {
languageString.ITEM_NOT_FOUND_REPROMPT
}`;
self.emit(':ask', speechOutput, languageString.ITEM_NOT_FOUND_REPROMPT);
} else {
self.attributes['speechOutput'] = output.data;
const cardTitle = `Path Guide: Next train from $ {
sourceStation
}
to $ {
destStation
}`;
self.emit(':tellWithCard', output.data, cardTitle, output.data);
}
});
}
},

As we can see, the code is quite straightforward. The source and destination are accessible from this object this.event.request.intent.slots.{slot name}.

We obtained the next train’s schedule using Google Maps API. The detailed implementation of that logic can be found here.

Notice, the :tellWithCard event — this event renders a card on your phone’s Alexa app with the contents that you pass to the event. For our skill, this is the example of the card:

Card as seen in the Alexa App

Deploying using lambda

Following the documentation in the examples around the sdk, we too opted to use lambda for deploying our skill. The guide we followed is here.

Certification process

After thoroughly testing our skill, it was time to submit for certification. Sadly, our first attempt was met with rejection. However the email from the Alexa Skills Team was very elaborate and explained the reasons for rejection and possible fixes in a detailed way. Our skill got rejected because of 2 reasons:

  1. Since we were using the word PATH which is copyrighted by NJ Transit, we were asked to indicate that the skill was unofficial or provide a letter from NJ Transit giving us the right to use the name. We opted to do the former since it was easier ! Hence our skill is named “Unofficial Path Train Guide”
  2. Our “Welcome” prompt didn’t indicate to the user that the session was open. We fixed this by appending “For help, say help me” to our welcome prompt message.

After making these changes, we resubmitted the skill for certification and it was approved within one day !

Conclusion

Overall, building the skill using the sdk was really easy. We hope to enhance the skill to have preset source location and extend the ambit to query trains on the NJ Transit schedule. If you have any feature suggestions, feel free to put it in the comments below !