Raj Kumar
Raj Kumar

Reputation: 1

AWS LEX 'state' keyerror in Lambda function

I'm new to aws lex. I'm trying to create the chatbot to order taking. I have the lambda function here is my code:

appetizers = [
    "jalapeno poppers",
    "empanadas"
]

quesadilla_sizes = ["small quesadilla", "large quesadilla"]
small_quesadilla_options = [
    "cheese",
    "chicken"
]
large_quesadilla_options = [
    "cheese",
    "chicken"
]

user_order = []


def validate_order(intent, slots):
    food_item = None


    # Use specific slot names for each food category
    if intent == "QuesadillaIntent":
        quesadilla_size = slots["QuesadillaSize"]["value"]["originalValue"].lower()
        quesadilla_item = slots["QuesadillaItem"]["value"]["originalValue"].lower()
        food_item = f"{quesadilla_size} quesadilla with {quesadilla_item}"

        if quesadilla_size == "small":
            if quesadilla_item not in small_quesadilla_options:
                return {
                    "isValid": False,
                    "invalidSlot": "QuesadillaItem",
                    "message": f'Please select a valid small quesadilla from: {", ".join(small_quesadilla_options)}',
                }
        elif quesadilla_size == "large":
            if quesadilla_item not in large_quesadilla_options:
                return {
                    "isValid": False,
                    "invalidSlot": "QuesadillaItem",
                    "message": f'Please select a valid large quesadilla from: {", ".join(large_quesadilla_options)}',
                }

    elif intent == "AppetizerIntent":
        appetizer_item = slots["AppetizerItem"]["value"]["originalValue"].lower()
        food_item = appetizer_item

        if appetizer_item not in appetizers:
            return {
                "isValid": False,
                "invalidSlot": "AppetizerItem",
                "message": f'Please select a valid appetizer from: {", ".join(appetizers)}',
            }

    # Add the valid item to the order
    user_order.append(f"{intent}: {food_item}")
    return {"isValid": True}


def lambda_handler(event, context):
    print(event)


    slots = event["sessionState"]["intent"]["slots"]
    intent = event["sessionState"]["intent"]["name"]
    print(event)

    # Validate the order
    order_validation_result = validate_order(intent, slots)
    print(order_validation_result)


    # Check invocation source
    if event["invocationSource"] == "DialogCodeHook":
        print("\neventdata:", event)

        if not order_validation_result["isValid"]:
            response_message = order_validation_result["message"]

            # Customize response based on intent
            if intent == "QuesadillaIntent":
                response_card_buttons = [
                    {"text": item.title(), "value": item}
                    for item in small_quesadilla_options + large_quesadilla_options
                ]


            return {
                "sessionState": {
                    "dialogAction": {
                        "type": "ElicitSlot",
                        "slotToElicit": order_validation_result["invalidSlot"],
                    },
                    "intent": event["sessionState"]["intent"],
                },
                "messages": [{"contentType": "PlainText", "content": response_message}],
                "responseCard": {
                    "version": 1,
                    "contentType": "application/vnd.amazonaws.card.generic",
                    "genericAttachments": [
                        {"title": "Select a valid option", "buttons": response_card_buttons}
                    ],
                },
            }
        elif event["sessionState"]["intent"]["state"] == "Fulfilled":
            return {
                "sessionState": {
                    "dialogAction": {"type": "Close"},
                    "intent": {"name": intent, "slots": slots, "state": "Fulfilled"},
                },
                "messages": [
                    {
                        "contentType": "PlainText",
                        "content": f"Your order has been placed successfully with the following items: {', '.join(user_order)}. Is there anything else you'd like to add?",
                    }
                ],
            }

    elif event["invocationSource"] == "FulfillmentCodeHook":
        # Fulfillment when the user says no to adding more items
        if len(user_order) > 0:
            return {
                "sessionState": {
                    "dialogAction": {"type": "Close"},
                    "intent": {"name": intent, "slots": slots, "state": "Fulfilled"},
                },
                "messages": [
                    {
                        "contentType": "PlainText",
                        "content": f"Your order has been placed successfully with the following items: {', '.join(user_order)}. Is there anything else you'd like to add?",
                    }
                ],
            }
        else:
            return {
                "sessionState": {
                    "dialogAction": {"type": "ElicitSlot", "slotToElicit": "AppetizerItem"},
                    "intent": {"name": "AppetizerIntent"},
                },
                "messages": [
                    {
                        "contentType": "PlainText",
                        "content": "It seems you haven't chosen anything yet. Would you like to start with an appetizer?",
                    }
                ],
            }

    # Dynamically select the next slot to elicit based on the current intent and slots
    next_slot = None
    if intent == "QuesadillaIntent":
        if "QuesadillaSize" not in slots:
            next_slot = "QuesadillaSize"
        elif "QuesadillaItem" not in slots:
            next_slot = "QuesadillaItem"
    elif intent == "AppetizerIntent":
        if "AppetizerItem" not in slots:
            next_slot = "AppetizerItem"

    if next_slot:
        return {
            "sessionState": {
                "dialogAction": {"type": "ElicitSlot", "slotToElicit": next_slot},
                "intent": {"name": intent, "slots": slots},
            },
            "messages": [
                {"contentType": "PlainText", "content": f"Please specify the {next_slot}."}
            ],
        }

Here when i try to build in aws lex console it throwing error like 'ElicitSlot' next step at 'InitialResponse:CodeHook:Success' in intent 'QuesadillaIntent' contains invalid slotToElicit setting. slotToElicit must be a required Slot within the intent. Change the slot name in slotToElicit and try your request again.

here are the Intent name & slot name i have created **Intent name **

slot name

I think I have set all the name as correctly but I don't what slots name needs to be change

here is the image for the reference : enter image description here

Please give the solution.

Upvotes: 0

Views: 14

Answers (0)

Related Questions