[PYTHON] Teach Alexa the garbage day in Nakano Ward by linking with lambda

Thing you want to do

Call lambda from Alexa and return the day of the week for garbage in Nakano Ward. I wrote it so that even people who have never touched it can make it from scratch.

alexa.png

I tried to introduce development with ALEXA, so I will summarize it in my own way I made it with reference to this article. It was very educational because it was explained in detail, I stumbled on the way because of a change in AWS specifications, so I will describe that area in this article as well.

Things necessary

Alexa Skill Kit

Extract ** variables ** from the voice received from echo Create a skill to pass to lambda.

Creating skills

Press ʻAlexa Skills Kit` from Amazon developer

alexa-Page-3.png

Press Create Skill from the Amazon developer console

alexa-Page-2.png

Enter the following and press Create Skill

Skill name: TrashDay Default language: Japanese Select a model to add to your skill: Custom Choose how to host your skill's backend resources: User-defined provisioning (this time hosting on lambda independently)

alexa-Page-4.png

Call name

Enter the call name to call the skill

Skill call name: Thermy Gomi

"Alexa, open Thermy Gomie" activates the skill alexa2-Page-2.png

Slot type

Prepare variables included in the statement in advance when calling the action.

Click Add next to the slot type to create a new one. alexa2-Page-3.png

Set the slot type name to type and press Create custom slot type alexa2-Page-4.png

Added the following slot values. The value of Alexa is not essential (a little playful * described later). alexa2-Page-1.png

Intent

Defines the action to be performed by the called skill (= Thermy Gomi). This time, only the action that responds to the day of the week of garbage is created.

Click Add next to the intent to create a new one. alexa2-Page-5.png

Set the intent name to TellTrashDay and press Create Custom Intent alexa2-Page-6.png

Set the intent slot name to type and select the slot type type created earlier. alexa2-Page-7.png

Added the following to the sample utterance. Note that there is a ** half-width space ** after {type}. alexa2-Page-8.png

From the above, the {type} part is extracted as a variable when you make a statement in the sample utterance.

AWS lambda

Hosts a function that selects and responds to a response based on the variables passed by Alexa.

Creating a function

Move to the lambda screen from the AWS management console and press Create function alexa2-Page-9.png

Select ʻalexa-skills-kit-color-expert-python` provided by AWS It includes a sample application that asks Alexa for her favorite color. alexa2-Page-10.png

Set the application name and TopicNameParameter to TrashDay and press Deploy TopicNameParameter is stored in the parameter passed by CloudFormation, There is no evidence that it is used in the function, so any value is fine. alexa2-Page-11.png

Deploy TrashDay.py

Select a function from the left menu and press the function with the application name mentioned earlier. alexa2-Page-12.png

Select the lambda function and replace the editor on the bottom screen with the contents of TrashDay.py alexa2-Page-13.png

TrashDay.py


# coding:utf-8
"""
This sample demonstrates a simple skill built with the Amazon Alexa Skills Kit.
The Intent Schema, Custom Slots, and Sample Utterances for this skill, as well
as testing instructions are located at http://amzn.to/1LzFrj6

For additional samples, visit the Alexa Skills Kit Getting Started guide at
http://amzn.to/1LGWsLG
"""

from __future__ import print_function


# --------------- Helpers that build all of the responses ----------------------

###A function used to return to Alexa after processing each intent
def build_speechlet_response(title, output, reprompt_text, should_end_session):
    return {
        'outputSpeech': {
            'type': 'PlainText',
            'text': output
        },
        'card': {
            'type': 'Simple',
            'title': "SessionSpeechlet - " + title,
            'content': "SessionSpeechlet - " + output
        },
        'reprompt': {
            'outputSpeech': {
                'type': 'PlainText',
                'text': reprompt_text
            }
        },
        'shouldEndSession': should_end_session
    }

### build_speechlet_A function that stores the JSON created by response in the JSON for response and returns it.
def build_response(session_attributes, speechlet_response):
    return {
        'version': '1.0',
        'sessionAttributes': session_attributes,
        'response': speechlet_response
    }


# --------------- Functions that control the skill's behavior ------------------

def get_welcome_response():
    """ If we wanted to initialize the session to have some attributes we could
    add those here
    """

    session_attributes = {}
    card_title = "Welcome"
    speech_output = "Hi, this is Thermy Gomie," \
                    "We will respond to the designated day of the week for the garbage you want to throw away!" 
    
    # If the user either does not reply to the welcome message or says something
    # that is not understood, they will be prompted again with this text.
    reprompt_text = "We will respond to the designated day of the week for the garbage you want to throw away!" 

    should_end_session = False
    return build_response(session_attributes, build_speechlet_response(
        card_title, speech_output, reprompt_text, should_end_session))


def handle_session_end_request():
    card_title = "Session Ended"
    speech_output = "Please come again" 

    # Setting this to true ends the session and exits the skill.
    should_end_session = True
    return build_response({}, build_speechlet_response(
        card_title, speech_output, None, should_end_session))


# --------------- Events ------------------

def on_session_started(session_started_request, session):
    """ Called when the session starts """

    print("on_session_started requestId=" + session_started_request['requestId']
          + ", sessionId=" + session['sessionId'])


def on_launch(launch_request, session):
    """ Called when the user launches the skill without specifying what they
    want
    """

    print("on_launch requestId=" + launch_request['requestId'] +
          ", sessionId=" + session['sessionId'])
    # Dispatch to your skill's launch
    return get_welcome_response()

###A function that determines the intent corresponding to a statement and branches to each function
def on_intent(intent_request, session):
    """ Called when the user specifies an intent for this skill """

    print("on_intent requestId=" + intent_request['requestId'] +
          ", sessionId=" + session['sessionId'])

    intent = intent_request['intent']
    intent_name = intent_request['intent']['name']

    # Dispatch to your skill's intent handlers

    ###Branch to each intent including TellTrashDay
    if intent_name == "TellTrashDay":
        return set_TellTrashDay_text(intent, session)
    elif intent_name == "AMAZON.HelpIntent":
        return get_welcome_response()
    elif intent_name == "AMAZON.CancelIntent" or intent_name == "AMAZON.StopIntent":
        return handle_session_end_request()
    else:
        raise ValueError("Invalid intent")


def on_session_ended(session_ended_request, session):
    """ Called when the user ends the session.

    Is not called when the skill returns should_end_session=true
    """
    print("on_session_ended requestId=" + session_ended_request['requestId'] +
          ", sessionId=" + session['sessionId'])
    # add cleanup logic here


# --------------- Main handler ------------------
###The first function to be executed when lambda is called
###Request information to lambda is stored in event
def lambda_handler(event, context):
    """ Route the incoming request based on type (LaunchRequest, IntentRequest,
    etc.) The JSON body of the request is provided in the event parameter.
    """
    # get applicationId from request.json
    print("event.session.application.applicationId=" +
          event['session']['application']['applicationId'])

    """
    Uncomment this if statement and populate with your skill's application ID to
    prevent someone else from configuring a skill that sends requests to this
    function.
    """
    # if (event['session']['application']['applicationId'] !=
    #         "amzn1.echo-sdk-ams.app.[unique-value-here]"):
    #     raise ValueError("Invalid Application ID")

    if event['session']['new']:
        on_session_started({'requestId': event['request']['requestId']},
                           event['session'])
    ###Skill name only call, executed when no intent is included
    if event['request']['type'] == "LaunchRequest":
        return on_launch(event['request'], event['session'])
    ###Executed when the user makes a statement corresponding to the intent
    elif event['request']['type'] == "IntentRequest":
        return on_intent(event['request'], event['session'])
    ###Executed on exit, when there is no responsive intent, or on error
    elif event['request']['type'] == "SessionEndedRequest":
        return on_session_ended(event['request'], event['session'])


###A function that returns the day of the week of garbage that matches the slot type
def set_TellTrashDay_text(intent, session):
    """ Sets the color in the session and prepares the speech to reply to the
    user.
    """

    card_title = intent['name']
    session_attributes = {}
    should_end_session = False
    speech_output = "Say it fast, you can throw you in a junk basket"

    ###Burning garbage list
    burn_list = ['burn', 'Raw', 'Of waste paper']
    ###Non-burnable garbage list
    notburn_list = ['Nonflammable', 'Of plastic', 'Plastic', 'Plastic']
    ###Aluminum can garbage list
    can_list = ['Of aluminum cans', 'Aluminum cans', 'Of empty cans', 'Of PET bottles', 'Of the bottle', 'Of the can', 'can', 'スチールOf the can']
    ###Cardboard garbage list
    paper_list = ['Cardboard', 'Newsprint', 'Of used paper', 'paper', 'paper']
    ###Dangerous goods garbage list
    glass_list = ['Of glass', 'Metal', 'Of pottery']
    ###If you say
    alexa_list = ['Alexa', 'Alexa']

    if 'type' in intent['slots']:
        ### 3rd part was 'name' so changed to 'value'
        trash_type = intent['slots']['type']['value'] 

        if trash_type in burn_list:
            speech_output = 'Tuesday and friday'
        elif trash_type in notburn_list:
            speech_output = 'It's monday'
        elif trash_type in can_list:
            speech_output = 'It's wednesday'
        elif trash_type in paper_list:
            speech_output = 'It's monday'
        elif trash_type in glass_list:
            speech_output = 'It's saturday'
        elif trash_type in alexa_list:
            speech_output = 'I think I want to be space debris'
    else:
        speech_output = "I'm sorry, I don't know what you're saying"

    print(speech_output)
    reprompt_text = speech_output
    return build_response(session_attributes, build_speechlet_response(
        card_title, speech_output, reprompt_text, should_end_session))

Specify the trigger Alexa Skills Kit

Press Add Trigger alexa2-Page-14.png

Go back to the Alexa developer console and copy the skill ID from the endpoint alexa2-Page-16.png

Go back to AWS, select ʻAlexa Skills Kit, paste the copied skill ID and press Add` alexa2-Page-15.png

If it is added normally, the setting on the lambda side is complete. Another breath.

Specify lambda for endpoint

Finally, specify the lambda function created earlier on the Alexa side.

Copy the ARN at the top of the AWS lambda screen alexa2-Page-18.png

Paste to default region for Alexa endpoints alexa2-Page-17.png

Press Save Endpoint

Now that all the settings are complete, save the model and build the model. alexa2-Page-19.png

test

Test the alexa developer console to see if it works.

Changed the stage where skill testing is enabled to Under Development alexa2-Page-20.png

Activate the skill and try the action you added to the intent. alexa2-Page-21.png

It worked! !!

Humor is perfect. alexa2-Page-22.png

By the way, even if you don't publish your skills in the store With my echo, I could use the skill without setting anything. (When I was testing on the browser, my echo responded and I was surprised lol) It seems that it is automatically linked with your Amazon account.

trouble shooting

Encoding error if there is Japanese in the lambda function

# Coding: utf-8 is added to the beginning of the code so that Japanese can be read.

If it doesn't work

Since the JSON input is displayed on the Alexa test screen, you can isolate whether the cause is Alexa or lambda by copying it to the lambda test and trying it.

Recommended Posts

Teach Alexa the garbage day in Nakano Ward by linking with lambda
"Classify garbage by image!" App creation diary day4 ~ Prepare the front end with Bootstrap ~