4

I am trying to create a lex bot that lets users learn about different options. For example, it can tell a user about the three different products available. I can't seem to find documentation about how to do this without using a lambda function, and I can't figure out how to pass the user input from the bot itself into the lambda function in order to use a simple "if/then" and then return the appropriate message. It seems excessive to have to use an lambda function to just give a response based on input, but I am stuck. Thanks.

  • 1
    Hi Jeff, Welcome to SO and thank you for asking. Why do you think using a Lambda is excessive maybe you can provide some code example you tried to help understand your question better – Tamir Klein Mar 19 '19 at 19:49
  • While the question you ask in the title is answered with the responses below, it's hard to provide additional suggestions for your use case without understanding why Lambda is not a viable option currently – Nick Walsh Mar 20 '19 at 16:09

2 Answers2

3

To shed a little more light on how a Lex bot works, the service enables you to define utterances ("if" conditions), that it will intelligently try to perform fuzzy-matching to determine whether a user has said something that fits one of the utterances you've defined. You can declare and modify these utterances within the AWS console, examples of this are available here.

The "then" part of this conditional application is where you get to define what happens after the user input matches a defined utterance (state), where some basic computation is handled, most easily in the form of a Lambda function.

For something simple like returning static text/info once a condition is met: Return from your lambda_handler function a string with the proper result. A barebones pseudocodey Python implementation of this would look like the following:

# Here's an implementation where you have an intent of a user asking 
# for more info about a particular object (info_type as defined in Lex console). 

def lambda_handler(event, context):    
  info_name = event['info_type']

  if info_name = 'business_hours':
      return "Our business hours are 9am-5pm"
  elif info_name = 'slogan':
      return "We're customer obsessed"
  else:
      return "Sorry, we don't have info about this!"

Depending on how you want to set up your application, you can decide how you want to split up the logic between different utterances and if/then cases with prop data passed in. If you have more complex queries, question types, and computation involved, these will all determine what the optimal way to architect your Lex chat bot will be.

Nick Walsh
  • 1,807
  • 5
  • 16
  • Thank you for your prompt response. I see that the function you wrote expects to receive two items, "event" and "context." How, in Lex, do I designate what should be passed to the Lambda function? – Jeff Nosanov Mar 20 '19 at 19:49
  • No problem! In the "Defining Static Response Cards" section of this page in the docs (https://docs.aws.amazon.com/lex/latest/dg/howitworks-manage-prompts.html), you can see examples of defining how a particular term that the user responds with (called a Slot) will be matched to an utterance, with example images – Nick Walsh Mar 20 '19 at 20:18
1

A Lex bot by itself is really only good enough for simple FAQ conversations where certain inputs have pre-defined responses. But you cannot set the responses based on the slot values Lex captures. You could have a very limited dynamic response where those slot values are simply placed inside a response (imagine a Mad Libs game), but that's about it.

As soon as you want to create a truly dynamic response based on the user input, then you will need to use a Lambda function to compare the Lex request and build an appropriate response based on the user input or slot values.


Documentation

Amazon Lex - Using Lambda Functions
Create a Lambda Function (example Order Flowers)
Set the Lambda Function as the Lex Intent's Code Hook

Once you have your Lambda function set up and Lex ready to pass the processed user input through as a Lex Request (also referred to as "Event"), then you will have to pay close attention to this document:

Lex Request and Response Format

The incoming request has a consistent format for delivering the currentIntent, the sessionAttributes, the slots, the inputTranscript (the full user input), and more. It might look like a lot to take in but once you parse it into its main components, then it's really quite easy to work with in order to build dynamic responses. Just make sure you are following the Lex Request and Response format precisely.


Example

Here is an example for the start of your Lambda Function (Node.js):

// The JSON body of the request is provided in 'event'.
// 'respondToLex' is the callback function used to return the Lex formatted JSON response

exports.handler = (event, context, respondToLex) => {
    console.log( "REQUEST= "+JSON.stringify(event) ); //view logs in CloudWatch

    // INCOMING VARIABLES FROM REQUEST EVENT
    // -------------------------------------
    var intentName = event.currentIntent.name;
    var slots = event.currentIntent.slots
    var sessionAttributes = event.sessionAttributes
    var userInput = event.inputTranscript

    // OUTGOING VARIABLES FOR RESPONSE
    // -------------------------------
    var responseMsg = "";
    var responseType = "";
    var slotToElicit = "";
    var error = null;
    var fulfillmentState = null;


    // DETERMINE RESPONSE BASED ON INTENTS AND SLOT VALUES
    // ---------------------------------------------------
    if (intentName == "intentA") {
        responseType = "Close";
        responseMsg = "I am responding to intentA";
        fulfillmentState = "fulfilled';
    }
    elseif (intentName == "intentB") {
        if (slots["productChoice"] == null) {
            responseMsg = "I can tell that productChoice slot is empty, so I should elicit for it here. Which product would you like? Hat or Shoes?";
            responseType = "ElicitSlot";
            slotToElicit = "productChoice";
        }
        else {
            if (slots["productChoice"]=="hat") {
                 responseMsg = "I can tell you selected a hat, here is my dynamic response based on that slot selection.";
            }
            elseif (slots["productChoice"]=="shoes") {
                 responseMsg = "I can tell you selected shoes, here is my dynamic response based on that slot selection.";
            }
        }
    }
    else {
        error = "Throw Error: Unknown Intent";
    }

    // CREATE RESPONSE BUILDER for each responseType (could turn into functions)
    // -------------------------------------------------------------------------
    if (responseType=="Close") {

        var response = [
              "sessionAttributes" = sessionAttributes,
              "dialogAction" = [
                    "type" = responseType,
                    "fulfillmentState" = fulfillmentState,
                    "message" = [
                         "contentType" = "PlainText";
                         "content" = responseMsg,
                    ]
              ]
        ];


    }
    elseif (responseType == "ElicitSlot) {

        var response = [
              "sessionAttributes" = sessionAttributes,
              "dialogAction" = [
                    "type" = responseType,
                    "intentName" = intentName,
                    "slots" = slots
                    "slotToElicit" = slotToElicit,
                    "message" = [
                         "contentType" = "PlainText";
                         "content" = responseMsg,
                    ]
              ]
        ];

    }

    responseJSON = JSON.stringify(response);
    console.log("RESPONSE= "+ responseJSON); // view logs in CloudWatch
    respondToLex(error, responseJSON);  
}
Jay A. Little
  • 3,239
  • 2
  • 11
  • 32