I want to create a skill for Amazon Alexa that - when triggered by voice commands - gets some information from an API via a HTTPS request and uses the result as spoken answer to the Alexa user.
There is a little challenge here (especially for node.js newbies) due to the event-driven concept of node.js and the internals of the Alexa Skills Kit for Node.js. And getting a hand on parameters from the user isn't that easy, either.
Can somebody provide some sample code to start with?
Preliminaries
- To get started you need an Amazon account, and you must enable AWS for the account.
- Then there is a nice step-by-step guide on the Amazon Website: https://developer.amazon.com/edw/home.html#/skills
- It walks you through step-by-step through the process of creating a "skill". A skill is the ability for Alexa to answer questions in natural language.
During this process you also create a Lambda function (select to create one of the demo script applications, and you get all required libraries automatically)
- Then you can then edit the code in the WebUI of the AWS Console).
- The "skill" is automatically enabled on all your personal Alexa Devices, like my Amazon Echo dot at home.
- remember that you can look at the console output in your AWS Cloudwatch section of the AWS console.
The two things I had to understand (and that others may run into, too)
While I created my first Alexa Skill I was new node.js, Lambda and the Alexa Skills SDK. So I ran into a few problems. I'd like to document the solutions here for the next person who runs into the same problem.
- When you make an http get request in node.js using https.get() you need to provide a handler for the end callback like res.on('end', function(res) {});
- The answer is sent back from the Lambda script to the Alexa Service when you call this.emit(':tell', 'blabla'); (this is what is used in the samples from AWS). But in the end-handler "this" isn't the right "this" anymore, you need to store the handle beforehand (I am doing this a little crookedly using mythis, I am sure there are smarter solutions, but it works).
I would have easily saved two hours of debugging had I had the following code snippet. :-)
The code
I my sample the lambda script already gets the preformatted text from the API. If you call an XML/JSON or whatever API you need to work with the answer a bit more.
'use strict';
const Alexa = require('alexa-sdk');
var https = require('https');
const APP_ID = ''; // TODO replace with your app ID (OPTIONAL).
const handlers = {
'functionwithoutdata': function() {
var responseString = '';
var mythis = this;
https.get('**YOURURL**?**yourparameters**', (res) => {
console.log('statusCode:', res.statusCode);
console.log('headers:', res.headers);
res.on('data', (d) => {
responseString += d;
});
res.on('end', function(res) {
const speechOutput = responseString;
console.log('==> Answering: ', speechOutput);
mythis.emit(':tell', 'The answer is'+speechOutput);
});
}).on('error', (e) => {
console.error(e);
});
},
'functionwithdata': function() {
var mydata = this.event.request.intent.slots.mydata.value;
console.log('mydata:', mydata);
var responseString = '';
var mythis = this;
https.get('**YOURURL**?**yourparameters**&mydata=' + mydata, (res) => {
console.log('statusCode:', res.statusCode);
console.log('headers:', res.headers);
res.on('data', (d) => {
responseString += d;
});
res.on('end', function(res) {
const speechOutput = responseString;
console.log('==> Answering: ', speechOutput);
mythis.emit(':tell', 'The answer is'+speechOutput);
});
}).on('error', (e) => {
console.error(e);
});
}
};
exports.handler = (event, context) => {
const alexa = Alexa.handler(event, context);
alexa.APP_ID = APP_ID;
alexa.registerHandlers(handlers);
alexa.execute();
};
How to create an Amazon Alexa bot from scratch?
If you’re looking for a way to create an Alexa voice enabled bot then you’re on the right place!
Let’s create an Amazon Alexa bot from scratch using node server running on our localhost and tunneled through ngrok.
Sign up for an Amazon developer account, if you don’t have one
Go to Alexa developer page
Go to the Alexa console
Click on Create skill
Give a name to the skill, I have named mine TestSkill and click on Next
Choose a model to add to your skill, I’ve selected custom for my experiments
Click on Create skill
This way you reach to the Alexa skill dashboard
Now, we need to provide the endpoint to Alexa console but first we need to setup an endpoint.
Creating a node server
Create a server which can accept POST requests on default location i.e. “/”.
There are so many techniques for creating a server, I personally prefer node.
I assume that you’ve node, npm and Visual studio code already installed
For the specific requirements of this tutorial, we will create a Hello World node app following the steps below:
- Run
npm init
on a terminal and when asked for the package name Alexa
- Follow the terminal wizard
- Run
cd Alexa
- In the
package.json
file
Run npm i express http -save
and this will add the following entry in the package.json
file:
“dependencies”: {
“express”: “4.16.3”,
“http”: “0.0.0”
}
Set value to index.js
of the main key in the package.json
file
- Add a file
index.js
on same level
Àdd the following code to the index.js
file:
const express = require('express');
const app = express();
app.post('/', (req, res) =>
res.send({
version: '1.0',
response: {
shouldEndSession: false,
outputSpeech: {
type: 'SSML',
text: 'Hello World!',
ssml: 'Hello World!'
}
}
}));
app.listen(8080, () => console.log('Example app listening on port 8080!'));
Set value of scripts
to { “start”: “node index.js” }
- Run
npm start
on the terminal
Tunnel your localhost
Add a tunnel to the localhost on PORT 8080
running the node server using ngrok following the below steps:
- Download and install ngrok, if not already done
- Run
ngrok http 8080
on a terminal
- Copy the SSL enabled forwarded link, in my case https://6d0d6e60.ngrok.io is the SSL link
- provide the link in the Enter URL link
- Select HTTPS, and under SSL certificate type drop down select the 2nd option:
My development endpoint is a sub-domain of a domain that has a wildcard certificate from a certificate authority
{
"interactionModel": {
"languageModel": {
"invocationName": "get me pizza",
"intents": [
{
"name": "PizzaOrderIntent",
"slots": [],
"samples": [
"Give me a pizza"
]
},
{
"name": "AMAZON.FallbackIntent",
"samples": [
"I didn't understand"
]
},
{
"name": "AMAZON.CancelIntent",
"samples": [
"cancel plz"
]
},
{
"name": "AMAZON.HelpIntent",
"samples": [
"help"
]
},
{
"name": "AMAZON.StopIntent",
"samples": [
"stop"
]
}
],
"types": []
}
}
}
- Click on Save Model and click on Build Model
Once, the skill model is build - we need to test it. Click on the Test tab and toggle ON the “Test is enabled for this skill”.
That’s it, you’ve created an Alexa bot connected to your locally running node project.
Questions? Comments? Do reach me at info@nordible.com
Read the full article
This is a sample code (not mine) that uses the alexa sdk which doesnt need to use awsLambda and works with just express, pure nodejs server
https://github.com/Glogo/alexa-skill-sample-nodejs-express