Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Building an Alexa-Based GitHub Follower Counter

DZone's Guide to

Building an Alexa-Based GitHub Follower Counter

Wish you could just ask your Echo how many GitHub followers you have? Now you can with this custom Alexa skill and a simple AWS Lambda function!

· IoT Zone
Free Resource

Download Red Hat’s blueprint for building an open IoT platform—open source from cloud to gateways to devices.

This post is part of my “Alexa” series. I will walk you through how to build an Amazon Alexa skill with Node.js and AWS Lambda to get the numbers of followers of repositories in GitHub in real-time.

Note: All the code is available in my GitHub.

Amazon Echo will capture voice commands and send them to the Alexa skill to convert them into structured text commands. A recognized command is sent to an AWS Lambda function that will call the GitHub API to get a response.

To get started, sign up to the Amazon Developer Console and create a new Alexa skill:

The invocation name is what the user will say to trigger the skill. In our case, it will be "GitHub".

Click on “Next” to bring up the Interaction Model page. Use the intent schema below:

{
    "intents":[
        {
            "intent":"GetGithubFollowerCount"
        },
        {
            "intent":"GetGithubRepositoryCount"
        },
        {
            "intent":"GetGithubRepositoryCountByLanguage",
            "slots":[
                {
                    "name":"Language",
                    "type":"LIST_OF_LANGUAGES"
                }
            ]
        }
    ]
}


Intents will map the user’s voice command to services that our Alexa skill can address. For instance, here I defined an intent called GetGithubFollowerCount, which will line up with a portion of code in my Lambda function that I leverage in a bit.

The programming languages are defined as a Custom Slot Type, with the following possible values:

Go
Java
Python
C
C++
Javascript
HTML
Scala
Ocaml
NodeJS
Ruby
PHP
CSS
C#
Perl
Shell
Objective C


Now that our intents are defined, we need to link them to a human request. To do this, multiple sentences (utterances) are listed to make the interaction as natural as possible.

GetGithubFollowerCount how many followers do I have
GetGithubFollowerCount current followers
GetGithubFollowerCount number of followers

GetGithubRepositoryCount how many repositories do I have
GetGithubRepositoryCount number of repositories
GetGithubRepositoryCount current repositories

GetGithubRepositoryCountByLanguage how many {Language} repositories
GetGithubRepositoryCountByLanguage number of {Language} repositories
GetGithubRepositoryCountByLanguage current {Language} repositories


Result:

Click on “Next” and you will move onto a page that allows us to use an ARN (Amazon Resource Name) to link to AWS Lambda.

Before that, let’s create our lambda function. Log into the AWS Management Console, then navigate to the Lambda Dashboard and create a new function from scratch:

Select the Alexa Skills Kit as the trigger:

I wrote the Lambda function in Node.js, although that code isn’t actually that interesting so I won’t go into it in much detail.

This function is fired when there is an incoming request from Alexa. The function will:

  • Process the request
  • Call the GitHub API
  • Send the response back to Alexa:
var request = require('request');

exports.handler = (event, context, callback) => {

  try {

    if (event.session.new) {
      console.log("NEW SESSION")
    }

    switch (event.request.type) {
      case "LaunchRequest":
        console.log(`LAUNCH REQUEST`)
        break;
      case "IntentRequest":
        console.log(`INTENT REQUEST`)

        switch(event.request.intent.name){
          case "GetGithubFollowerCount":
            getFollowerCount(function(count){
              context.succeed(buildResponse(`You have ${count} followers`))
            })
            break;
          case "GetGithubRepositoryCount":
            getRepositoryCount(function(count){
              context.succeed(buildResponse(`You have ${count} repositories`))
            })
            break;
          case "GetGithubRepositoryCountByLanguage":
            var language = event.request.intent.slots.Language.value
            getRepositoryCountByLanguage(language, function(count){
              context.succeed(buildResponse(`There are ${count} ${language} repositories in Github`))
            })
            break;
          default:
          context.succeed(buildResponse("Sorry I couldn't understand"))
        }
        break;
      case "SessionEndedRequest":
        console.log(`SESSION ENDED REQUEST`)
        break;
      default:
        context.fail(`INVALID REQUEST TYPE: ${event.request.type}`)
    }

  } catch(error) { context.fail(`Exception: ${error}`) }

}

getFollowerCount = (callback) =>{
  var options = {
    url: `https://api.github.com/users/${process.env.USERNAME}`,
    headers: {
      'User-Agent': 'alexa-skill'
    }
  };
  request(options, function(error, response, body){
    var data = JSON.parse(body)
    callback(data.followers)
  })
}

getRepositoryCount = (callback) =>{
  var options = {
    url: `https://api.github.com/users/${process.env.USERNAME}`,
    headers: {
      'User-Agent': 'alexa-skill'
    }
  };
  request(options, function(error, response, body){
    var data = JSON.parse(body)
    callback(data.public_repos)
  })
}

getRepositoryCountByLanguage = (language, callback) =>{
  var options = {
    url:  `https://api.github.com/search/repositories?q=language:${language}`,
    headers: {
      'User-Agent': 'alexa-skill'
    }
  };
  request(options, function(error, response, body){
    var data = JSON.parse(body)
    callback(data.total_count)
  })
}

buildResponse = (outputText) => {
  return {
    version: "1.0",
    sessionAttributes: {
      outputSpeech: {
        type: "PlainText",
        text: outputText
      },
      shouldEndSession: true
    },
    response: {}
  }
}


Create a ZIP file consisting of the function above and any dependencies (node_modules). Then, specify the .zip file name as your deployment package at the time you create the Lambda function. Don’t forget to set your GitHub username as an environment variable:

Back in the Alexa skill, we need to link our Lambda function as our skill's endpoint:

That’s it, let’s test it out using a Service Simulation by clicking on “Next“.

GetFollowerCount intent:

GetRepositoryCount intent:

GetGithubRepositoryCountByLanguage intent:

You can see that the Lambda responds as expected!

Test it now with your Amazon Echo!


Build an open IoT platform with Red Hat—keep it flexible with open source software.

Topics:
iot ,alexa skills ,github ,aws lambda ,tutorial

Published at DZone with permission of Mohamed Labouardy, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}