Response Building


Standard response

If you are using AWS lambda as your skill endpoint, you are only responsible for providing the response body in order for Alexa to respond to a customer request. The documentation on the JSON structure of the response body can be found here.

A response body may contain the following properties:

  • version
  • sessionAttributes
  • response

ASK SDK for Python helps filling the version and sessionAttributes so you can focus on building the response instead of writing boilerplate code.

Similar to standard requests, the SDK creates response objects as deserialized model objects (ask-sdk-model package) and internally handles serializing them to response JSON before sending to the Alexa service.

Response Factory

The SDK includes a ResponseFactory class that contains helper functions for constructing responses. A Response may contain multiple elements, and the helper functions aid in generating responses, reducing the need to initialize and set the elements of each response.

Interface

class ResponseFactory(object):
    def __init__(self):
        self.response = ....  # Response object

    def speak(self, speech, play_behavior=None):
        # type: (str, ask_sdk_model.ui.play_behavior.PlayBehavior) -> 'ResponseFactory'
        ....

    def ask(self, speech, play_behavior=None):
        # type: (str, ask_sdk_model.ui.play_behavior.PlayBehavior) -> 'ResponseFactory'
        ....

    def set_card(self, card):
        # type: (ask_sdk_model.ui.card.Card) -> 'ResponseFactory'
        ....

    def add_directive(self, directive):
        # type: (ask_sdk_model.directive.Directive) -> 'ResponseFactory'
        ....

    def add_directive_to_reprompt(self, directive):
        # type: (Directive) -> 'ResponseFactory'

    def set_should_end_session(self, end_session):
        # type: (bool) -> 'ResponseFactory'
        ....

    def set_can_fulfill_intent(self, can_fulfill_intent):
        # type: (ask_sdk_model.canfulfill.can_fulfill_intent.CanFulfillIntent) -> 'ResponseFactory'
        ....

response_builder, an instance of the ResponseFactory class, is provided to the skill developers through the HandlerInput object, which is the standard argument passed to the skill components.

Code example

The following example shows how to construct a response containing a StandardCard and a BodyTemplate2 display object through handler_input.response_builder.

from ask_sdk_core.dispatch_components import AbstractRequestHandler
from ask_sdk_core.handler_input import HandlerInput
from ask_sdk_core.utils import is_intent_name
from ask_sdk_core.response_helper import get_plain_text_content

from ask_sdk_model.response import Response
from ask_sdk_model.interfaces.display import (
    ImageInstance, Image, RenderTemplateDirective,
    BackButtonBehavior, BodyTemplate2)
from ask_sdk_model import ui

class HelloIntentHandler(AbstractRequestHandler):
    def can_handle(self, handler_input):
        # type: (HandlerInput) -> bool
        return is_intent_name("HelloIntent")(handler_input)

    def handle(self, handler_input):
        # type: (HandlerInput) -> Response
        response_builder = handler_input.response_builder

        speech = "This is a sample response"

        response_builder.set_card(
            ui.StandardCard(
                title="Card Title",
                text="Hey this is a sample card",
                image=ui.Image(
                    small_image_url="<Small Image URL>",
                    large_image_url="<Large Image URL>"
                )
            )
        )

        if supports_display(handler_input):
            img = Image(
                sources=[ImageInstance(url="<Large Image URL>")])
            title = "Template Title"
            primary_text = get_plain_text_content(
                primary_text="some text")

            response_builder.add_directive(
                RenderTemplateDirective(
                    BodyTemplate2(
                        back_button=BackButtonBehavior.VISIBLE,
                        image=img, title=title,
                        text_content=primary_text)))

        return response_builder.speak(speech).response

Text helpers

The following helper functions are provided to skill developers, to help with text content generation:

get_plain_text_content

def get_plain_text_content(primary_text, secondary_text, tertiary_text):
    # type: (str, str, str) -> TextContent
    # Create a text content object with text as PlainText type
    ....

get_rich_text_content

def get_rich_text_content(primary_text, secondary_text, tertiary_text):
    # type: (str, str, str) -> TextContent
    # Create a text content object with text as RichText type
    ....

get_text_content

def get_text_content(
    primary_text, primary_text_type,
    secondary_text, secondary_text_type,
    tertiary_text, tertiary_text_type):
    # type: (str, str, str, str, str, str) -> TextContent
    # Create a text content object with text as corresponding passed-type
    # Passed-in type is defaulted to PlainText
    ....

Construct a response using a template

The SDK allows you to use a template to construct a skill response. A template is similar to a view in the model–view–controller (MVC) pattern commonly used to build dynamic web pages.

Using a template can help you:

  • Generate a Response by separating the presentation logic from the request-handling logic.
  • More easily generate a Response with a complex and nested structure, for example when using Alexa Presentation Language.
  • Reduce duplicate code by reusing common templates across skills.

You can include multiple response components in a single template, for example outputSpeech, card, shouldEndSession, directives, and more. A component can contain static data and placeholders for dynamic data, and is built into a full skill response.

To generate a Response using a template, configure the template factory when building the skill.

Template factory

The template factory interface processes a response template by injecting dynamic data to generate the skill response. In a RequestHandler, the code that builds the skill response calls the template factory interface. You can implement your own unique template factory or use the TemplateFactory provided in the SDK, which consists of a list of Template Loader and Template Renderer objects.

Template loader

The template loader interface loads template content from data storage. The SDK provides the FileSystemTemplateLoader to load a template file from the local file system. You can implement your own loader to load a template from a different data storage location.

To use FileSystemTemplateLoader, provide the directory path, encoding scheme, and file name extension for the template files. If you host your skill on AWS Lambda, include the template files as resources in the skill project.

Template enumerator

You can generate different responses for different locales. To use different template files for different locales, the SDK provides the AbstractTemplateEnumerator interface and a LocaleTemplateEnumerator implementation to enumerate possible template locations and names based on the locale property in the skill request. For example, en-US is the locale property for a template file located at template/en/US or named template_en_US.

The LocaleTemplateEnumerator first tries to find the most specific template file, for example base_response_template/en/US, then falls back to a less specific file, for example base_response_template/en, and then finally a global file, for example base_response_template.

The following list shows the order of locale property combinations from most specific to least specific, assuming "/" as file separator.

  • base_response_template/en/US
  • base_response_template/en_US
  • base_response_template/en
  • base_response_template_en_US
  • base_response_template_en
  • base_response_template

You can implement your own template enumerator to enumerate templates according to your preference.

Template cache

To facilitate the template loading process, the SDK provides the AbstractTemplateCache interface, and provides a LRUCache to cache loaded templates for future use. The LRUCache supports concurrent caching, has a capacity of 5 MB, and a time-to-live of 24 hours by default. You can modify the values according to your needs, or implement your own template cache.

Template renderer

The template renderer interface renders a full template including dynamic data, and converts it into a skill Response. The SDK provides the JinjaTemplateRenderer implementation to render a Jinja template. You can also implement your own template renderer to support other template engines.

To use the JinjaTemplateRenderer, you need to install the package ask-sdk-jinja-renderer from PyPi. For example:

pip install ask-sdk-jinja-renderer

Example usage of template factory

The following example shows the basic setup and usage of template factory. You provide the root path of the templates, and the SDK generates a default implementation of template factory.

    from ask_sdk_core.skill_builder import SkillBuilder
    from ask_sdk_core.handler_input import HandlerInput
    from ask_sdk_core.dispatch_components import AbstractRequestHandler
    from ask_sdk_core.utils import is_request_type
    from ask_sdk_core.view_resolvers import FileSystemTemplateLoader
    from ask_sdk_jinja_renderer import JinjaTemplateRenderer
    from ask_sdk_model import Response

    sb = SkillBuilder()

    class LaunchRequestHandler(AbstractRequestHandler):
        """Handler for skill launch."""
        def can_handle(self, handler_input):
            # type: (HandlerInput) -> bool
            return is_request_type("LaunchRequest")(handler_input)

        def handle(self, handler_input):
            # type: (HandlerInput) -> Response
            speech_text = "Hello!!"

            template_name = "responses"

            data_map = {
                'speech_text': speech_text,
                'card': {
                    'type': 'Simple',
                    'title': 'Jinja2 Template',
                    'content': speech_text
                },
                'should_end_session': 'false'
            }

            return handler_input.generate_template_response(template_name, data_map, file_ext='jinja')

    # Other skill components here ....

    # Register all handlers, loaders, renderers, interceptors etc.
    sb.add_request_handler(LaunchRequestHandler())
    # Add default file system loader on skill builder
    sb.add_loader(FileSystemTemplateLoader(dir_path="templates", encoding='utf-8'))
    # Add default jinja renderer on skill builder
    sb.add_renderer(JinjaTemplateRenderer())

    skill = sb.create()

Using the preceding example code, the following example Jinja template has a full resource path of lambda/templates/responses.jinja, with the directory path templates and file extension jinja passed into the TemplateFactory, and the locale property of en-US from the Request passed into the LocaleTemplateEnumerator.

Example Jinja template

The following example shows a Jinja template for the OutputSpeech component in a skill response.

    {
        "outputSpeech": {
            "type": "SSML",
            "ssml": "<speak></speak>"
        },
        "card": {
            "type": "",
            "title": "",
            "content": ""
        },
        "shouldEndSession": ""
    }

Was this page helpful?

Last updated: Nov 28, 2023