AlexaOps

Controlling AWS using Alexa

Created by Chris Lennon using reveal.js

Source code available for both control code and the presentation

Introduction

This presentation is to guide you through the creation of an application(skill) for the Alexa platform.

This presentation will give you an overview of (1) the Alexa platform, (2) the usage of a skill to control AWS as an example usecase.

An Overview of Alexa

This section is designed to give an overview of the Alexa ecosystem.

A non technical overview of components.


Alexa, Say Hello.

  • Voice and interaction model service by Amazon launched at the end of 2014.
  • Hardware devices available from Amazon & third party integrations.
  • Application operate around a skill/app model.

Lineup

Example of skills

Builtin

  • Alexa, set a timer for 5 minutes.
  • Alexa, add bread to my shopping list.
  • Alexa, what is the weather tomorrow?

Skill store

  • Alexa, play music on Spotify.
  • Alexa, turn off the bedroom lights.
  • Alexa, ask Gordon Ramsay what he thinks of my food.
  • Alexa, how do I craft a torch using Minecraft helper?

Build your own...


↑ Back To Top

Overview of a skill

This section gives an overview of the components in a skill.

Flow of a Skill

Skill Flow
  1. Stating an action
  2. Calculating the intent
  3. Trigger function
  4. Do action / Get data
  5. Respond to Alexa service

Setup a skill

This section walks through the creation of a skill.

Requirements

The example skill has the following requirements.

AWS CLI

We need to install the AWS CLI and configure it.

                            
                                aws iam get-user

                                {
                                    "User": {
                                        ...
                                    }
                                }
                            
                        

Create a new skill

Naming things is hard...

  • Invocation name
    • Alexa, ask Cloud Control for development status
    • Alexa, What is the status of development using Cloud Control
  • Language - Setup each locale independently
  • Skill ID - amzn1.ask.skill.98a0d5f4-56e6-42bb-9168-63d4235dee83
  • Alexa Docs - the good and the bad

Quickstart

Update ALEXA_SKILL_ID variable in serverless.yml

If using the example code you are good to go.

                            
                                serverless deploy
                            
                        

But what did we actually deploy?...


↑ Back To Top

Interacting with Alexa

Request from Alexa

A JSON payload following a particular format

                            
                                {
                                    ...
                                    "request": {
                                        "type": "IntentRequest",
                                        "intent": {
                                            "name": "GetServices",
                                            "slots": {
                                                "Environment": {
                                                    "name": "Environment",
                                                    "value": "development"
                                                }
                                            }
                                        }
                                    }
                                    ...
                                }
                            
                        

TODO - Something useful

... this bit is kind of up to you, example in a minute...

Responding to Alexa

Actual speech is written in Speech Synthesis Markup Language (SSML)

                            
                                
                                    I want to tell you a secret. 
                                    I am not a real human..
                                    Can you believe it?
                                
                            
                        

Responding to Alexa ... pt2

A JSON payload following a particular format

                            
                                {
                                    ...
                                    "response": {
                                        "outputSpeech": {
                                            "type": "PlainText",
                                            "text": "Plain text string to speak",
                                            "ssml": "SSML text string to speak"
                                        },
                                        "card": {
                                            "type": "Standard",
                                            "title": "Title of the card",
                                            "content": "Content of a simple card",
                                            "text": "Text content for a standard card",
                                            "image": {
                                                "smallImageUrl": "https://url-to-small-card-image...",
                                                "largeImageUrl": "https://url-to-large-card-image..."
                                            }
                                        },
                                        "reprompt": {
                                            "outputSpeech": {
                                                "type": "PlainText",
                                                "text": "Plain text string to speak",
                                                "ssml": "SSML text string to speak"
                                            }
                                        }
                                    }
                                    ...
                                }
                            
                        

But what about the middle part?

... What can I make it do?

Whatever you want!

My example ties uses Lambda to control AWS


↑ Back To Top

AlexaOps

Running the example

Creating: 'Alexa, list development servers'

Create First Intent

  1. Open skill in the skill builder
  2. Create a skill - mentioned earlier

Create First Intent... pt2

Create a slot type

  • Create new entry in 'Slot Types'
  • Call it Environments
  • Add expected values: development, production

Create First Intent... pt3

Setup the intent

  • Create a new intent called GetServices
  • Create a new intent slot called env of type Environments

Create First Intent... pt4

Populate example phrases

  • How many {env} servers are running
  • What is the status of the {env} environment

Create Lambda Function

Create a new blank function

  • Name it AlexaAWSControl
  • Pick a runtime - For this example python
  • Create a new role from the Basic Edge Lambda permissions template
  • Click 'Create Function'
  • Add a trigger of type Alexa Skills Kit

The above is what serverless.yaml handles for us.

Link Lambda and Alexa

Two points to connect

  • In the Alexa skill config add the Lambda ARN:
    • arn:aws:lambda:eu-west-1:6766234252:function:AlexaAWSControl
  • In Lambda add the ALEXA_SKILL_ID environment variable
    • amzn1.ask.skill.97a0d6f3-48f6-54cb-3049-64e46e5ffe81

Pick up the request

Basic structure of function

                            
                                def handler(event, context):
                                    if (event["session"]["application"]["applicationId"] !=
                                            os.environ.get('ALEXA_SKILL_ID')):
                                        raise ValueError("Invalid Application ID")
                                    if event["request"]["type"] == "LaunchRequest":
                                        ...
                                    if event["request"]["type"] == "IntentRequest":
                                        ...
                                   
                            
                        

Route the request

Assuming we are handling an IntentRequest

                            
                                
                                    if event["request"]["intent"]["name"] == "GetServices"
                                        return get_service_status(event["request"]["intent"]["slots"])
                            
                        

Pass the slot data to a function basaed on the intent name.

Action the request

Query AWS using boto3 (built into Lambda)

                            
                            ec2_resource = boto3.resource('ec2')
                            
                            def get_service_status(slots):
                                filters = [{
                                    'Name': name,
                                    'Values': [slots['environment']['name']]
                                }]

                                instances = ec2_resource.instances.filter(Filters=filters)

                                for instance in instances:
                                    if instance.state['Code'] == 16:
                                        online_instances.append(instance.id)
                                    else:
                                        offline_instances.append(instance.id)
                            
                        

A word on permissions

The previous function would need the AmazonEC2ReadOnlyAccess policy to be successful.

  • Policies can be added to the role we created for this function
  • Please dont just give it root...

Build a response

The goal is to respond with a SSML string.

                            
                            {
                                ...
                                "ssml" : "There are 2 development servers online."
                                ...
                            }
                            
                        

Considerations to grammar:

  • number of server(s)
  • they/it is/are online

Testing

Many places to test!

  • SSML Speech Simulator - In the 'Test' of Skill Builder
  • Function logs - Your app or CloudWatch for Lambda
  • Alexa app or webapp
  • Serverless local test and Lambda online test
                            
                                serverless invoke local --function functionName -p test/data.json
                            
                        

↑ Back To Top