Как использовать карточки быстрого ответа в AWS Lex - PullRequest
0 голосов
/ 27 мая 2019

Я пытаюсь создать чат-бота с помощью AWS Lex.

Я сделал карточки быстрого ответа, чтобы клиент выбрал пиццу. У него есть два слота, в которых используются карточки ответа на запрос, но когда я запускаю чат-бота, он застревает в первом слоте.

Проблема в том, что слот состоит из пяти карт, и чат-робот останавливается после того, как он автоматически пропустит все эти пять карт. Я понятия не имею, почему это не идет в следующий слот.

Вот лямбда-коды

"""
This sample demonstrates an implementation of the Lex Code Hook Interface
in order to serve a sample bot which manages orders for flowers.
Bot, Intent, and Slot models which are compatible with this sample can be found in the Lex Console
as part of the 'OrderFlowers' template.

For instructions on how to set up and test this bot, as well as additional samples,
visit the Lex Getting Started documentation http://docs.aws.amazon.com/lex/latest/dg/getting-started.html.
"""
import math
import dateutil.parser
import datetime
import time
import os
import logging

logger = logging.getLogger()
logger.setLevel(logging.DEBUG)


""" --- Helpers to build responses which match the structure of the necessary dialog actions --- """


def get_slots(intent_request):
    return intent_request['currentIntent']['slots']


def elicit_slot(session_attributes, intent_name, slots, slot_to_elicit, message):
    return {
        'sessionAttributes': session_attributes,
        'dialogAction': {
            'type': 'ElicitSlot',
            'intentName': intent_name,
            'slots': slots,
            'slotToElicit': slot_to_elicit,
            'message': message
        }
    }


def close(session_attributes, fulfillment_state, message):
    response = {
        'sessionAttributes': session_attributes,
        'dialogAction': {
            'type': 'Close',
            'fulfillmentState': fulfillment_state,
            'message': message
        }
    }

    return response


def delegate(session_attributes, slots):
    return {
        'sessionAttributes': session_attributes,
        'dialogAction': {
            'type': 'Delegate',
            'slots': slots
        }
    }


""" --- Helper Functions --- """


def parse_int(n):
    try:
        return int(n)
    except ValueError:
        return float('nan')


def build_validation_result(is_valid, violated_slot, message_content):
    if message_content is None:
        return {
            "isValid": is_valid,
            "violatedSlot": violated_slot,
        }

    return {
        'isValid': is_valid,
        'violatedSlot': violated_slot,
        'message': {'contentType': 'PlainText', 'content': message_content}
    }


def isvalid_date(date):
    try:
        dateutil.parser.parse(date)
        return True
    except ValueError:
        return False


def validate_order_flowers(flower_type, date, pickup_time):
    flower_types = ['lilies', 'roses', 'tulips']
    if flower_type is not None and flower_type.lower() not in flower_types:
        return build_validation_result(False,
                                       'FlowerType',
                                       'We do not have {}, would you like a different type of flower?  '
                                       'Our most popular flowers are roses'.format(flower_type))

    if date is not None:
        if not isvalid_date(date):
            return build_validation_result(False, 'PickupDate', 'I did not understand that, what date would you like to pick the flowers up?')
        elif datetime.datetime.strptime(date, '%Y-%m-%d').date() <= datetime.date.today():
            return build_validation_result(False, 'PickupDate', 'You can pick up the flowers from tomorrow onwards.  What day would you like to pick them up?')

    if pickup_time is not None:
        if len(pickup_time) != 5:
            # Not a valid time; use a prompt defined on the build-time model.
            return build_validation_result(False, 'PickupTime', None)

        hour, minute = pickup_time.split(':')
        hour = parse_int(hour)
        minute = parse_int(minute)
        if math.isnan(hour) or math.isnan(minute):
            # Not a valid time; use a prompt defined on the build-time model.
            return build_validation_result(False, 'PickupTime', None)

        if hour < 10 or hour > 16:
            # Outside of business hours
            return build_validation_result(False, 'PickupTime', 'Our business hours are from ten a m. to five p m. Can you specify a time during this range?')

    return build_validation_result(True, None, None)


""" --- Functions that control the bot's behavior --- """


def order_flowers(intent_request):
    """
    Performs dialog management and fulfillment for ordering flowers.
    Beyond fulfillment, the implementation of this intent demonstrates the use of the elicitSlot dialog action
    in slot validation and re-prompting.
    """

    flower_type = get_slots(intent_request)["FlowerType"]
    date = get_slots(intent_request)["PickupDate"]
    pickup_time = get_slots(intent_request)["PickupTime"]
    source = intent_request['invocationSource']

    if source == 'DialogCodeHook':
        # Perform basic validation on the supplied input slots.
        # Use the elicitSlot dialog action to re-prompt for the first violation detected.
        slots = get_slots(intent_request)

        validation_result = validate_order_flowers(flower_type, date, pickup_time)
        if not validation_result['isValid']:
            slots[validation_result['violatedSlot']] = None
            return elicit_slot(intent_request['sessionAttributes'],
                               intent_request['currentIntent']['name'],
                               slots,
                               validation_result['violatedSlot'],
                               validation_result['message'])

        # Pass the price of the flowers back through session attributes to be used in various prompts defined
        # on the bot model.
        output_session_attributes = intent_request['sessionAttributes'] if intent_request['sessionAttributes'] is not None else {}
        if flower_type is not None:
            output_session_attributes['Price'] = len(flower_type) * 5  # Elegant pricing model

        return delegate(output_session_attributes, get_slots(intent_request))

    # Order the flowers, and rely on the goodbye message of the bot to define the message to the end user.
    # In a real bot, this would likely involve a call to a backend service.
    return close(intent_request['sessionAttributes'],
                 'Fulfilled',
                 {'contentType': 'PlainText',
                  'content': 'Thanks, your order for {} has been placed and will be ready for pickup by {} on {}'.format(flower_type, pickup_time, date)})


""" --- Intents --- """


def dispatch(intent_request):
    """
    Called when the user specifies an intent for this bot.
    """

    logger.debug('dispatch userId={}, intentName={}'.format(intent_request['userId'], intent_request['currentIntent']['name']))

    intent_name = intent_request['currentIntent']['name']

    # Dispatch to your bot's intent handlers
    if intent_name == 'OrderFlowers':
        return order_flowers(intent_request)

    raise Exception('Intent with name ' + intent_name + ' not supported')


""" --- Main handler --- """


def lambda_handler(event, context):
    """
    Route the incoming request based on intent.
    The JSON body of the request is provided in the event slot.
    """
    # By default, treat the user request as coming from the America/New_York time zone.
    os.environ['TZ'] = 'America/New_York'
    time.tzset()
    logger.debug('event.bot.name={}'.format(event['bot']['name']))

    return dispatch(event)

и это ответ Inspect, который я получил, когда чат-робот остановился.

RequestID: 2ed05fb0-808e-11e9-8fc7-01b65259e3f8
{
  "dialogState": "ElicitSlot",
  "intentName": "OrderPizza",
  "message": "Welcome to the PizzaWorld! We make the best pizza in the world! What kind of pizza do you want?",
  "messageFormat": "PlainText",
  "responseCard": {
    "contentType": "application/vnd.amazonaws.card.generic",
    "genericAttachments": [
      {
        "attachmentLinkUrl": null,
        "buttons": [
          {
            "text": "Hawaiian",
            "value": "Hawaiian"
          }
        ],
        "imageUrl": "https://blogfiles.pstatic.net/MjAxOTA1MjdfMjI2/MDAxNTU4OTE4MTc0MjYx.K5WOYmaTn96siKlJz7evnUyxwl23_TNzDNwgKgn9geYg.f51aPps_nN3gabeDqJKtVxKZ-WvskAz11c6ebuYArjEg.JPEG.mapofworld55/Hwaiian.JPG?type=w2",
        "subTitle": "Taste of Hawaii",
        "title": "Hawaiian"
      },
      {
        "attachmentLinkUrl": null,
        "buttons": [
          {
            "text": "Pepperoni",
            "value": "Pepperoni"
          }
        ],
        "imageUrl": "https://blogfiles.pstatic.net/MjAxOTA1MjdfNCAg/MDAxNTU4OTE4MTc0NjU5.9NTYdc-W5LUgFVcHY4LGU_yzOEpkUIFXJrIaonr_tsog.4h4r8s8bhM9zU9uvqvzzr0upzE3uXDg7jWZn5vfs90Ag.JPEG.mapofworld55/Pepp.JPG?type=w2",
        "subTitle": "Lots of pepperoni on the top",
        "title": "Pepperoni"
      },
      {
        "attachmentLinkUrl": null,
        "buttons": [
          {
            "text": "Potato",
            "value": "Potato"
          }
        ],
        "imageUrl": "https://blogfiles.pstatic.net/MjAxOTA1MjdfMTQx/MDAxNTU4OTE4MTc0OTIz.SxWlCTxZFR0tfUl58ULexLrW3p7TDjZAqFnLS3IBc6Ag.gCrS1LEqvjeHd08e-Lf1BYYCMn8QMIWIPgWW_dQ9bX4g.JPEG.mapofworld55/Potato.JPG?type=w2",
        "subTitle": "Healthy potato pizza",
        "title": "Potato"
      },
      {
        "attachmentLinkUrl": null,
        "buttons": [
          {
            "text": "Black tiger shrimp",
            "value": "Black tiger shrimp"
          }
        ],
        "imageUrl": "https://blogfiles.pstatic.net/MjAxOTA1MjdfMTkw/MDAxNTU4OTE4MTc1MjMx.Inq0rWT3kzxo9--FKJ5lUqwDd_947rT5lRzMP3k9fuUg.2cnF3eWp_2IG9GRIImyJwetG3n8ANttm-ZYp4d2XpXMg.JPEG.mapofworld55/black.JPG?type=w2",
        "subTitle": "The best pizza in the world with tiger shrimps",
        "title": "Black tiger shrimp"
      },
      {
        "attachmentLinkUrl": null,
        "buttons": [
          {
            "text": "Super shimp",
            "value": "Super shrimp"
          }
        ],
        "imageUrl": "https://blogfiles.pstatic.net/MjAxOTA1MjdfMjIg/MDAxNTU4OTE4MTc1NTk5.ts5Sh6j0h-1ZGBgJHYeIo0wWAcYISyAiNn8HtvhOqQMg.TcJKhJhIlgAJjqJlxJqwK8FEP2i8DPUxenU3IH4-DoUg.JPEG.mapofworld55/super.JPG?type=w2",
        "subTitle": "A pizza with various ingredients.",
        "title": "Super shrimp"
      }
    ],
    "version": "1"
  },
  "sessionAttributes": {},
  "slotToElicit": "PizzaMenu",
  "slots": {
    "Destination": null,
    "PizzaMenu": null,
    "SideMenu": null,
    "TimeGet": null
  }
}

Пожалуйста, скажите мне, если вам нужна дополнительная информация. Спасибо.

...