Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I create an Alexa Skill that gets data from an HTTP/HTTPS API (using "Alexa Skills Kit" for Node.js on AWS Lambda)

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?

like image 478
Dirk Paessler Avatar asked Feb 23 '17 19:02

Dirk Paessler


People also ask

Can Alexa send HTTP requests?

It abstracts the complexities of making requests behind a simple interface, and makes HTTP requests easy and simple. If you're using Alexa Hosted as the backend for your skills, there's an added advantage of the Requests library being built-in, so you don't need to install or upload it manually.


2 Answers

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.

  1. 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) {});
  2. 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();
};
like image 58
Dirk Paessler Avatar answered Sep 19 '22 10:09

Dirk Paessler


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

  • Provide an invocation name, I’ve named it “give me pizza” and click on Save Model

  • Click on the Endpoint

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

  • Click Save Endpoints

  • Click on JSON editor and provide the following model:


    {
        "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 [email protected]

Read the full article

like image 44
xameeramir Avatar answered Sep 20 '22 10:09

xameeramir