Module 4 source code
/**
* Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: LicenseRef-.amazon.com.-AmznSL-1.0
* Licensed under the Amazon Software License http://aws.amazon.com/asl/
**/
/* *
* This sample demonstrates handling intents from an Alexa skill using the Alexa Skills Kit SDK (v2).
* Please visit https://alexa.design/cookbook for additional examples on implementing slots, dialog management,
* session persistence, api calls, and more.
* */
const Alexa = require('ask-sdk-core');
const LaunchRequestHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'LaunchRequest';
},
handle(handlerInput) {
const speakOutput =
`Welcome to Cake Time. I'll tell you a celebrity name and you try
to guess the month and year they were born. See how many you can get!
Would you like to play?`;
//====================================================================
// Add a visual with Alexa Layouts
//====================================================================
// Import an Alexa Presentation Language (APL) template
var APL_simple = require('./documents/APL_simple.json');
// Check to make sure the device supports APL
if (
Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)[
'Alexa.Presentation.APL'
]
) {
// add a directive to render the simple template
handlerInput.responseBuilder.addDirective({
type: 'Alexa.Presentation.APL.RenderDocument',
document: APL_simple,
datasources: {
myData: {
//====================================================================
// Set a headline and subhead to display on the screen if there is one
//====================================================================
Title: 'Say "yes."',
Subtitle: 'Play some Cake Time.',
},
},
});
}
return handlerInput.responseBuilder
.speak(speakOutput)
.reprompt(speakOutput)
.getResponse();
}
};
const PlayGameHandler = {
canHandle(handlerInput) {
return (
Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' &&
Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.YesIntent'
);
},
handle(handlerInput) {
//====================================================================
// Set your speech output
//====================================================================
//Import the celebrity functions and get a random celebrity.
const cfunctions = require('./celebrityFunctions.js');
const celeb = cfunctions.getRandomCeleb();
var title = celeb.name;
//Ask the question
const speakOutput = `In what month and year was ${celeb.name} born?`;
//====================================================================
// Add a visual with Alexa Layouts
//====================================================================
// Import an Alexa Presentation Language (APL) template
var APL_simple = require('./documents/APL_simple.json');
// Check to make sure the device supports APL
if (
Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)[
'Alexa.Presentation.APL'
]
) {
// add a directive to render the simple template
handlerInput.responseBuilder.addDirective({
type: 'Alexa.Presentation.APL.RenderDocument',
document: APL_simple,
datasources: {
myData: {
//====================================================================
// Set a headline and subhead to display on the screen if there is one
//====================================================================
Title: title,
Subtitle: 'What month and year were they born?',
},
},
});
}
//====================================================================
// Send the response back to Alexa
//====================================================================
return handlerInput.responseBuilder
.speak(speakOutput)
.reprompt(speakOutput)
.getResponse();
}
};
const GetBirthdayIntentHandler = {
canHandle(handlerInput) {
return (
Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest' &&
Alexa.getIntentName(handlerInput.requestEnvelope) === 'GetBirthdayIntent'
);
},
handle(handlerInput) {
//====================================================================
// Set your speech output
//====================================================================
//Get the slot values
var year = handlerInput.requestEnvelope.request.intent.slots.year.value;
var month = handlerInput.requestEnvelope.request.intent.slots.month.value;
//Share the answer
const speakOutput = `Your answer was ${month} of ${year}. Would you like to try again?`;
//====================================================================
// Add a visual with Alexa Layouts
//====================================================================
// Import an Alexa Presentation Language (APL) template
var APL_simple = require('./documents/APL_simple.json');
// Check to make sure the device supports APL
if (
Alexa.getSupportedInterfaces(handlerInput.requestEnvelope)[
'Alexa.Presentation.APL'
]
) {
// add a directive to render the simple template
handlerInput.responseBuilder.addDirective({
type: 'Alexa.Presentation.APL.RenderDocument',
document: APL_simple,
datasources: {
myData: {
//====================================================================
// Set a headline and subhead to display on the screen if there is one
//====================================================================
Title: month + ', ' + year,
Subtitle: 'Try again?',
},
},
});
}
//====================================================================
// Send the response back to Alexa
//====================================================================
return handlerInput.responseBuilder
.speak(speakOutput)
.reprompt(speakOutput)
.getResponse();
}
};
const HelloWorldIntentHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'HelloWorldIntent';
},
handle(handlerInput) {
const speakOutput = 'Hello World!';
return handlerInput.responseBuilder
.speak(speakOutput)
//.reprompt('add a reprompt if you want to keep the session open for the user to respond')
.getResponse();
}
};
const HelpIntentHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.HelpIntent';
},
handle(handlerInput) {
const speakOutput = 'You can say hello to me! How can I help?';
return handlerInput.responseBuilder
.speak(speakOutput)
.reprompt(speakOutput)
.getResponse();
}
};
const CancelAndStopIntentHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& (Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.CancelIntent'
|| Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.StopIntent');
},
handle(handlerInput) {
const speakOutput = 'Goodbye!';
return handlerInput.responseBuilder
.speak(speakOutput)
.getResponse();
}
};
/* *
* FallbackIntent triggers when a customer says something that doesn't map to any intents in your skill
* It must also be defined in the language model (if the locale supports it)
* This handler can be safely added but will be ingnored in locales that do not support it yet
* */
const FallbackIntentHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest'
&& Alexa.getIntentName(handlerInput.requestEnvelope) === 'AMAZON.FallbackIntent';
},
handle(handlerInput) {
const speakOutput = 'Sorry, I don\'t know about that. Please try again.';
return handlerInput.responseBuilder
.speak(speakOutput)
.reprompt(speakOutput)
.getResponse();
}
};
/* *
* SessionEndedRequest notifies that a session was ended. This handler will be triggered when a currently open
* session is closed for one of the following reasons: 1) The user says "exit" or "quit". 2) The user does not
* respond or says something that does not match an intent defined in your voice model. 3) An error occurs
* */
const SessionEndedRequestHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'SessionEndedRequest';
},
handle(handlerInput) {
console.log(`~~~~ Session ended: ${JSON.stringify(handlerInput.requestEnvelope)}`);
// Any cleanup logic goes here.
return handlerInput.responseBuilder.getResponse(); // notice we send an empty response
}
};
/* *
* The intent reflector is used for interaction model testing and debugging.
* It will simply repeat the intent the user said. You can create custom handlers for your intents
* by defining them above, then also adding them to the request handler chain below
* */
const IntentReflectorHandler = {
canHandle(handlerInput) {
return Alexa.getRequestType(handlerInput.requestEnvelope) === 'IntentRequest';
},
handle(handlerInput) {
const intentName = Alexa.getIntentName(handlerInput.requestEnvelope);
const speakOutput = `You just triggered ${intentName}`;
return handlerInput.responseBuilder
.speak(speakOutput)
//.reprompt('add a reprompt if you want to keep the session open for the user to respond')
.getResponse();
}
};
/**
* Generic error handling to capture any syntax or routing errors. If you receive an error
* stating the request handler chain is not found, you have not implemented a handler for
* the intent being invoked or included it in the skill builder below
* */
const ErrorHandler = {
canHandle() {
return true;
},
handle(handlerInput, error) {
const speakOutput = 'Sorry, I had trouble doing what you asked. Please try again.';
console.log(`~~~~ Error handled: ${JSON.stringify(error)}`);
return handlerInput.responseBuilder
.speak(speakOutput)
.reprompt(speakOutput)
.getResponse();
}
};
/**
* This handler acts as the entry point for your skill, routing all request and response
* payloads to the handlers above. Make sure any new handlers or interceptors you've
* defined are included below. The order matters - they're processed top to bottom
* */
exports.handler = Alexa.SkillBuilders.custom()
.addRequestHandlers(
LaunchRequestHandler,
PlayGameHandler,
GetBirthdayIntentHandler,
HelloWorldIntentHandler,
HelpIntentHandler,
CancelAndStopIntentHandler,
FallbackIntentHandler,
SessionEndedRequestHandler,
IntentReflectorHandler)
.addErrorHandlers(
ErrorHandler)
.withCustomUserAgent('sample/hello-world/v1.2')
.lambda();
# -*- coding: utf-8 -*-
# Copyright 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: LicenseRef-.amazon.com.-AmznSL-1.0
# Licensed under the Amazon Software License http://aws.amazon.com/asl/
# This sample demonstrates handling intents from an Alexa skill using the Alexa Skills Kit SDK for Python.
# Please visit https://alexa.design/cookbook for additional examples on implementing slots, dialog management,
# session persistence, api calls, and more.
# This sample is built using the handler classes approach in skill builder.
import logging
import ask_sdk_core.utils as ask_utils
import json
from ask_sdk_model.interfaces.alexa.presentation.apl import (
RenderDocumentDirective)
from ask_sdk_core.skill_builder import SkillBuilder
from ask_sdk_core.dispatch_components import AbstractRequestHandler
from ask_sdk_core.dispatch_components import AbstractExceptionHandler
from ask_sdk_core.handler_input import HandlerInput
from ask_sdk_model import Response
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
class LaunchRequestHandler(AbstractRequestHandler):
"""Handler for Skill Launch."""
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return ask_utils.is_request_type("LaunchRequest")(handler_input)
def handle(self, handler_input):
# type: (HandlerInput) -> Response
speak_output = f"Welcome to Cake Time. " \
f"I'll tell you a celebrity name and you try " \
f"to guess the month and year they were born. " \
f"See how many you can get! " \
f"Would you like to play?"
#====================================================================
# Add a visual with Alexa Layouts
#====================================================================
# Import an Alexa Presentation Language (APL) template
with open("./documents/APL_simple.json") as apl_doc:
apl_simple = json.load(apl_doc)
if ask_utils.get_supported_interfaces(
handler_input).alexa_presentation_apl is not None:
handler_input.response_builder.add_directive(
RenderDocumentDirective(
document=apl_simple,
datasources={
"myData": {
#====================================================================
# Set a headline and subhead to display on the screen if there is one
#====================================================================
"Title": 'Say "yes."',
"Subtitle": 'Play some Cake Time.',
}
}
)
)
return (
handler_input.response_builder
.speak(speak_output)
.ask(speak_output)
.response
)
class PlayGameHandler(AbstractRequestHandler):
"""Handler for Skill Launch."""
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return (
ask_utils.is_request_type("IntentRequest")(handler_input)
and ask_utils.is_intent_name("AMAZON.YesIntent")(handler_input)
)
def handle(self, handler_input):
# type: (HandlerInput) -> Response
from celebrityFunctions import get_random_celeb
celeb = get_random_celeb()
title = celeb["name"]
speak_output = f'In what month and year was {celeb["name"]} born?'
#====================================================================
# Add a visual with Alexa Layouts
#====================================================================
# Import an Alexa Presentation Language (APL) template
with open("./documents/APL_simple.json") as apl_doc:
apl_simple = json.load(apl_doc)
if ask_utils.get_supported_interfaces(
handler_input).alexa_presentation_apl is not None:
handler_input.response_builder.add_directive(
RenderDocumentDirective(
document=apl_simple,
datasources={
"myData": {
#====================================================================
# Set a headline and subhead to display on the screen if there is one
#====================================================================
"Title": title,
"Subtitle": 'What month and year were they born?',
}
}
)
)
return (
handler_input.response_builder
.speak(speak_output)
.ask(speak_output)
.response
)
class GetBirthdayIntentHandler(AbstractRequestHandler):
"""Handler for Skill Launch."""
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return (
ask_utils.is_request_type("IntentRequest")(handler_input)
and ask_utils.is_intent_name("GetBirthdayIntent")(handler_input)
)
def handle(self, handler_input):
# type: (HandlerInput) -> Response
year = ask_utils.request_util.get_slot(handler_input, "year").value
month = ask_utils.request_util.get_slot(handler_input, "month").value
# Share the answer
speak_output = f'Your answer was {month} of {year}. Would you like to try again?'
#====================================================================
# Add a visual with Alexa Layouts
#====================================================================
# Import an Alexa Presentation Language (APL) template
with open("./documents/APL_simple.json") as apl_doc:
apl_simple = json.load(apl_doc)
if ask_utils.get_supported_interfaces(
handler_input).alexa_presentation_apl is not None:
handler_input.response_builder.add_directive(
RenderDocumentDirective(
document=apl_simple,
datasources={
"myData": {
#====================================================================
# Set a headline and subhead to display on the screen if there is one
#====================================================================
"Title": f'{month}, {year}',
"Subtitle": 'Try again?',
}
}
)
)
return (
handler_input.response_builder
.speak(speak_output)
.ask(speak_output)
.response
)
class HelloWorldIntentHandler(AbstractRequestHandler):
"""Handler for Hello World Intent."""
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return ask_utils.is_intent_name("HelloWorldIntent")(handler_input)
def handle(self, handler_input):
# type: (HandlerInput) -> Response
speak_output = "Hello World!"
return (
handler_input.response_builder
.speak(speak_output)
# .ask("add a reprompt if you want to keep the session open for the user to respond")
.response
)
class HelpIntentHandler(AbstractRequestHandler):
"""Handler for Help Intent."""
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return ask_utils.is_intent_name("AMAZON.HelpIntent")(handler_input)
def handle(self, handler_input):
# type: (HandlerInput) -> Response
speak_output = "You can say hello to me! How can I help?"
return (
handler_input.response_builder
.speak(speak_output)
.ask(speak_output)
.response
)
class CancelOrStopIntentHandler(AbstractRequestHandler):
"""Single handler for Cancel and Stop Intent."""
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return (ask_utils.is_intent_name("AMAZON.CancelIntent")(handler_input) or
ask_utils.is_intent_name("AMAZON.StopIntent")(handler_input))
def handle(self, handler_input):
# type: (HandlerInput) -> Response
speak_output = "Goodbye!"
return (
handler_input.response_builder
.speak(speak_output)
.response
)
class FallbackIntentHandler(AbstractRequestHandler):
"""Single handler for Fallback Intent."""
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return ask_utils.is_intent_name("AMAZON.FallbackIntent")(handler_input)
def handle(self, handler_input):
# type: (HandlerInput) -> Response
logger.info("In FallbackIntentHandler")
speech = "Hmm, I'm not sure. You can say Hello or Help. What would you like to do?"
reprompt = "I didn't catch that. What can I help you with?"
return handler_input.response_builder.speak(speech).ask(reprompt).response
class SessionEndedRequestHandler(AbstractRequestHandler):
"""Handler for Session End."""
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return ask_utils.is_request_type("SessionEndedRequest")(handler_input)
def handle(self, handler_input):
# type: (HandlerInput) -> Response
# Any cleanup logic goes here.
return handler_input.response_builder.response
class IntentReflectorHandler(AbstractRequestHandler):
"""The intent reflector is used for interaction model testing and debugging.
It will simply repeat the intent the user said. You can create custom handlers
for your intents by defining them above, then also adding them to the request
handler chain below.
"""
def can_handle(self, handler_input):
# type: (HandlerInput) -> bool
return ask_utils.is_request_type("IntentRequest")(handler_input)
def handle(self, handler_input):
# type: (HandlerInput) -> Response
intent_name = ask_utils.get_intent_name(handler_input)
speak_output = "You just triggered " + intent_name + "."
return (
handler_input.response_builder
.speak(speak_output)
# .ask("add a reprompt if you want to keep the session open for the user to respond")
.response
)
class CatchAllExceptionHandler(AbstractExceptionHandler):
"""Generic error handling to capture any syntax or routing errors. If you receive an error
stating the request handler chain is not found, you have not implemented a handler for
the intent being invoked or included it in the skill builder below.
"""
def can_handle(self, handler_input, exception):
# type: (HandlerInput, Exception) -> bool
return True
def handle(self, handler_input, exception):
# type: (HandlerInput, Exception) -> Response
logger.error(exception, exc_info=True)
speak_output = "Sorry, I had trouble doing what you asked. Please try again."
return (
handler_input.response_builder
.speak(speak_output)
.ask(speak_output)
.response
)
# The SkillBuilder object acts as the entry point for your skill, routing all request and response
# payloads to the handlers above. Make sure any new handlers or interceptors you've
# defined are included below. The order matters - they're processed top to bottom.
sb = SkillBuilder()
sb.add_request_handler(LaunchRequestHandler())
sb.add_request_handler(PlayGameHandler())
sb.add_request_handler(GetBirthdayIntentHandler())
sb.add_request_handler(HelloWorldIntentHandler())
sb.add_request_handler(HelpIntentHandler())
sb.add_request_handler(CancelOrStopIntentHandler())
sb.add_request_handler(FallbackIntentHandler())
sb.add_request_handler(SessionEndedRequestHandler())
sb.add_request_handler(IntentReflectorHandler()) # make sure IntentReflectorHandler is last so it doesn't override your custom intent handlers
sb.add_exception_handler(CatchAllExceptionHandler())
lambda_handler = sb.lambda_handler()