Adam Nutt
Created December 1, 2016 © MIT

Are We Running Today?

This skill checks the current weather based upon your zip code and tells you whether it's a good time for a run or not. Powered by DarkSky.

BeginnerFull instructions provided4 hours38
Are We Running Today?

Things used in this project

Software apps and online services

DarkSky API
AWS Lambda
Amazon Web Services AWS Lambda
Alexa Skills Kit
Amazon Alexa Alexa Skills Kit

Story

Read more

Schematics

Visual User Interface Diagram

Code

Alexa Lamda function

Python
from __future__ import print_function
import zipcode
import urllib2
import json

"""
This sample demonstrates a simple skill built with the Amazon Alexa Skills Kit.
This skill is built for the re:Invent 2016 Alexa Skills Challenge.

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


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

def build_speechlet_response(title, output, reprompt_text, should_end_session):
    return {
        'outputSpeech': {
            'type': 'SSML',
            'ssml': output
        },
        'card': {
            'type': 'Simple',
            'title': "SessionSpeechlet - " + title,
            'content': "SessionSpeechlet - " + output
        },
        'reprompt': {
            'outputSpeech': {
                'type': 'PlainText',
                'text': reprompt_text
            }
        },
        'shouldEndSession': should_end_session
    }


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 = "<speak>Welcome to the Alexa Skills Challenge Run Club sample. " \
                    "Please tell me the zip code where you run by saying, " \
                    "my zip code is <say-as interpret-as=\"spell-out\">98670</say-as>.</speak>"
    # 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 = "<speak>Please tell me the zip code where you run by saying, " \
                    "my zip code is <say-as interpret-as=\"spell-out\">98670</say-as>.</speak>"
    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 = "<speak>Thank you for trying the Alexa Skills Challenge Run Club sample. " \
                    "Have a nice day!</speak>"
    # 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))


def create_zip_code_attribute(zip_code):
    return {"zipCode": zip_code}


def set_zip_code_in_session(intent, session):
    """ Sets the zip code in the session and prepares the speech to reply to the
    user.
    """

    card_title = intent['name']
    session_attributes = {}
    should_end_session = False

    if 'zipCode' in intent['slots']:
        zip_code = intent['slots']['zipCode']['value']
        session_attributes = create_zip_code_attribute(zip_code)
        speech_output = "<speak>I now know your zip code is <say-as interpret-as=\"spell-out\">" + \
                        zip_code + \
                        "</say-as>. You can ask me if the weather is good for running by saying, " \
                        "are we running today?</speak>"
        reprompt_text = "<speak>You can ask me if the weather is good for running by saying, " \
                        "are we running today?</speak>"
    else:
        speech_output = "<speak>I'm not sure what your zip code is. " \
                        "Please try again.</speak>"
        reprompt_text = "<speak>I'm not sure what your zip code is. " \
                        "You can tell me your zip code by saying, " \
                        "my zip code is <say-as interpret-as=\"spell-out\">98670</say-as>.</speak>"
    return build_response(session_attributes, build_speechlet_response(
        card_title, speech_output, reprompt_text, should_end_session))


def get_running_status_from_session(intent, session):
    session_attributes = {}
    reprompt_text = None
    should_end_session = False

    if session.get('attributes', {}) and "zipCode" in session.get('attributes', {}):
        zip_code = session['attributes']['zipCode']
        zip_info = zipcode.isequal(str(zip_code))
        if zip_info is not None:
            base_url = 'https://api.darksky.net/forecast/'
            secret = '57918eaadad536824c2f7e98d9a701bc'
            url = base_url + secret + '/' + str(zip_info.lat) + ',' + str(zip_info.lon)
            print("url = " + url)
            req = urllib2.Request(url)
            response = urllib2.urlopen(req)
            forecast = json.load(response)

            if forecast['currently']['precipIntensity'] < 0.01:
                speech_output = '<speak>Now is a great time for a run!</speak>'
                should_end_session = True
            else:
                speech_output = '<speak>I currently see ' + forecast['currently'][
                    'summary'] + '. Try a Nike Training Club session instead.</speak>'
                should_end_session = True

        else:
            speech_output = '<speak>I was unable to locate zip code <say-as interpret-as=\"spell-out\">' + zip_code + '</say-as>.</speak>'
            should_end_session = True
    else:
        speech_output = "<speak>I'm not sure what your zip code is. " \
                        "You can say, my zip code is <say-as interpret-as=\"spell-out\">98670</say-as>.</speak>"
        should_end_session = False

    # Setting reprompt_text to None signifies that we do not want to reprompt
    # the user. If the user does not respond or says something that is not
    # understood, the session will end.
    return build_response(session_attributes, build_speechlet_response(
        intent['name'], speech_output, reprompt_text, 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()


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']

    print("intent_name = " + intent_name)

    # Dispatch to your skill's intent handlers
    if intent_name == "MyZipCodeIsIntent":
        return set_zip_code_in_session(intent, session)
    elif intent_name == "AreWeRunningIntent":
        return get_running_status_from_session(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 ------------------

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.
    """
    print("event.session.application.applicationId=" +
          event['session']['application']['applicationId'])

    if (event['session']['application']['applicationId'] !=
            "amzn1.echo-sdk-ams.app.28482808-70ba-4ada-bc33-2654227f2aa5"):
        raise ValueError("Invalid Application ID")

    if event['session']['new']:
        on_session_started({'requestId': event['request']['requestId']},
                           event['session'])

    if event['request']['type'] == "LaunchRequest":
        return on_launch(event['request'], event['session'])
    elif event['request']['type'] == "IntentRequest":
        return on_intent(event['request'], event['session'])
    elif event['request']['type'] == "SessionEndedRequest":
        return on_session_ended(event['request'], event['session'])

Credits

Adam Nutt

Adam Nutt

1 project • 0 followers

Comments