node.jsamazon-web-servicesaws-lambdaaws-lexamazon-connect

Amazon Lex with Amazon Lambda Help for Ice Cream Shop


Based on a Date, I want Amazon Lex to respond with a flavor(s). It is for my ice cream shop. I am using this as part of my Amazon Connect system, whereas someone asks, "What is todays flavor" and Amazon Lex says, "Today's flavor is Mint Chip" for example.

I have a slot in Amazon Lex called "date".

I am working on a Lambda Function and receiving the error, "An error has occurred: Invalid Lambda Response: Received error response from Lambda: Unhandled". I know it is my sloppy Lambda function below that is causing this.

Here is the .js that I am using in Lambda:

'use strict'

//Handler function. This is the entry point to our Lambda function
exports.handler = function (event, context, callback) {

    //We obtain the sessionAttributes and the intent name from the event object, received as a parameter.
    var sessionAttributes = event.sessionAttributes;
    var intentName = event.currentIntent.name;

    //In order to use the same lambda function for several intents, we check against the intent name, which is unique.
    switch (intentName) {
        case "date": //In case we triggered the date intent, we'll execute the following code:
            //We obtain the 'date' slot
            var name = event.currentIntent.slots.date;
            //now we get the flavor of the date
            getFlavorDate(name, function (error, date) {
                var response = null;
                if (!error) {
                    //By default we create a message that states that we didn't find the birthday for the given name.
                    var message = "I'm sorry, I couldn't find " + Date + "'s flavor.";
                    if (date !== null) //In case we found a date, we generate a message with the dates info
                    {
                        message = date + "'s flavor is " + date.toLocaleDateString("en-US", {
                            month: "long",
                            day: "numeric",
                            year: undefined,
                        });
                    }
                    //We generate a response that has a 'Fulfilled' value for the attribute 'dialogAction.fulfillmentState' and we pass our message string
                    response = createFulfilledResponse(sessionAttributes, message);
                }
                else {
                    //In case an error ocurred, we pass an error message in a response that has the 'dialogAction.fulfillmentState' attribute set to 'Failed'
                    var message = "An error has occurred.";
                    response = createFailedResponse(sessionAttributes, message);
                }
                //Finally, we trigger the callback to notify the bot
                callback(null, response);
            });

            break;
    }
};
//Function used to get the birth date of someone's by providing their name. 
//The content of this function can be replaced in order for the data to be gotten from an API, database or other service.
function getFlavorDate(name, callback) {
    //We will use sample data instead of accessing an API or service, for practical purposes. This code can be reprogrammed in order to change the behavior.
    var FlavorDate = {

        "NUTTY ELEPHANT": new Date(2020, 1, 5),
        "CARAMEL CASHEW": new Date(2020, 2, 5),
        "CAMPFIRE S’MORES": new Date(2020, 3, 5),
        "LEMON POPPYSEED CAKE": new Date(2020, 4, 5),
        "DARK SIDE": new Date(2020, 5, 5),
        "DF PINA COLADA": new Date(2020, 5, 5),
        "DOGWOOD MUD PIE": new Date(2020, 6, 5),
        "BLACK RASPBERRY": new Date(2020, 7, 5),
        "DF SUPER RAINBOW UNICORN": new Date(2020, 7, 5),
        "ASKINOSIE DARK CHOCOLATE": new Date(2020, 8, 5),
        "STRAWBERRY BROWNIE": new Date(2020, 9, 5),
        "CHOCOLATE DECADENCE": new Date(2020, 10, 5),
        "FAT ELVIS": new Date(2020, 11, 5),
        "BUTTER PECAN": new Date(2020, 12, 5),
        "DF NEON ETHEREAL CHIP": new Date(2020, 12, 5),
        "CHERRY AMARETTO": new Date(2020, 13, 5),
        "COSMIC OREO": new Date(2020, 14, 5),
        "DF SINGLE ORIGIN CHOCOLATE": new Date(2020, 15, 5),
        "DOUBLE DRIBBLE": new Date(2020, 15, 5),
        "ORANGE CREAMSICLE": new Date(2020, 16, 5),
        "STEWARTS’ CHERRY CHEESECAKE": new Date(2020, 17, 5),
        "DF FUDGY COOKIES & CREAM": new Date(2020, 18, 5),
        "SINGLE ORIGIN MINT CHIP": new Date(2020, 18, 5),
        "PEANUT BUTTER COOKIE DOUGH": new Date(2020, 19, 5),
        "BIRTHDAY CAKE!": new Date(2020, 20, 5),
        "COCONUT": new Date(52020, 21, 5),
        "DF STRAWBERRY": new Date(2020, 21, 5),
        "DOUBLE ORIGIN CHOCOLATE": new Date(2020, 22, 5),
        "PIE FIGHT": new Date(2020, 23, 5),
        "SALTED CARAMEL OREO": new Date(2020, 24, 5),
        "DOUGH CRAZY!": new Date(2020, 25, 5),
        "HEATH BRICKLE CRUNCH": new Date(2020, 26, 5),
        "SUPER RAINBOW UNICORN": new Date(2020, 27, 5),
        "CHERRY GOAT CHEESE": new Date(2020, 28, 5),
        "DF VEGAN CHERRY CHEESECAKE": new Date(2020, 29, 5),
        "DARK CHOCOLATE AVOCADO": new Date(2020, 30, 5),
        "OREO PB BLOB DUE BASI": new Date(2020, 30, 5),
        "BURGUNDY CHERRY": new Date(2020, 31, 5)
    };

    var FlavorDate = null;
    name = name.toLowerCase(); //As our keys in the set are in lower case, we convert our 'name' parameter to lower case
    if (name in FlavorDate) {
        //If the name is in the set, we return the corresponding birth date.
        FlavorDate = FlavorDate[name];
    }
    callback(0, FlavorDate); //we return the value in the callback with error code 0.
}

//Function used to generate a response object, with its attribute dialogAction.fulfillmentState set to 'Fulfilled'. It also receives the message string to be shown to the user.
function createFulfilledResponse(sessionAttributes, message) {
    let response = {
        "sessionAttributes": session_attributes,
        "dialogAction": {
            "type": "Close",
            "fulfillmentState": "Fulfilled",
            "message": {
                "contentType": "PlainText",
                "content": message
            }
        }
    }
    return response;
}

Solution

  • Please try this solution to return todays flavour from the list of flavours added sequentially according to the day of the month. Current intent name needs to be changed on the lex dashboard. I have not used any slots, but they can be easily added to a new flow, for eg.

    1. What are the flavours available ? - intent becomes FetchFlavour
    2. What is todays/tomorrows/end of months/etc. flavour ?- slot can be an amazon date which needs validation on the lambda handler

    Hope this is the direction that you were looking for.

    // flavours corresponding to the days of the month
    const flavours = [
      "NUTTY ELEPHANT",
      "CARAMEL CASHEW",
      "CAMPFIRE S’MORES",
      "LEMON POPPYSEED CAKE",
      "DARK SIDE",
      "DF PINA COLADA",
      "DOGWOOD MUD PIE",
      "BLACK RASPBERRY",
      "DF SUPER RAINBOW UNICORN",
      "ASKINOSIE DARK CHOCOLATE",
      "STRAWBERRY BROWNIE",
      "CHOCOLATE DECADENCE",
      "FAT ELVIS",
      "BUTTER PECAN",
      "DF NEON ETHEREAL CHIP",
      "CHERRY AMARETTO",
      "COSMIC OREO",
      "DF SINGLE ORIGIN CHOCOLATE",
      "DOUBLE DRIBBLE",
      "ORANGE CREAMSICLE",
      "STEWARTS’ CHERRY CHEESECAKE",
      "DF FUDGY COOKIES & CREAM",
      "SINGLE ORIGIN MINT CHIP",
      "PEANUT BUTTER COOKIE DOUGH",
      "BIRTHDAY CAKE!",
      "COCONUT",
      "DF STRAWBERRY",
      "DOUBLE ORIGIN CHOCOLATE",
      "PIE FIGHT",
      "SALTED CARAMEL OREO",
      "DOUGH CRAZY!",
      "HEATH BRICKLE CRUNCH",
      "SUPER RAINBOW UNICORN",
      "CHERRY GOAT CHEESE",
      "DF VEGAN CHERRY CHEESECAKE",
      "DARK CHOCOLATE AVOCADO",
      "OREO PB BLOB DUE BASI",
      "BURGUNDY CHERRY"
    ];
    
    const closeResponse = (sessionAttributes, fulfillmentState, message) => {
      return {
        sessionAttributes: sessionAttributes,
        dialogAction: {
          type: "Close",
          fulfillmentState: fulfillmentState,
          message: message
        }
      };
    };
    
    // main handler
    exports.handler = function(event, context) {
      process.env.TZ = "utc"; // change this to your timezone https://www.iana.org/time-zones
      console.debug(
        "ENVIRONMENT VARIABLES\n" + JSON.stringify(process.env, null, 2)
      );
      console.info("EVENT\n" + JSON.stringify(event, null, 2));
    
      const intentName = event.currentIntent.name;
      // please check the spelling of flavour/flavor
      if (intentName === "TodaysFlavour") {
        return closeResponse(event.sessionAttributes, "Fulfilled", {
          contentType: "PlainText",
          content: `Todays flavour is ${flavours[new Date().getDate() - 1]}`
        });
      } else {
        throw new Error(`${intentName} is currently not supported`);
      }
    };