Leveraging Machine Learning capabilities of AWS Lex chatbot using AWS Lambda Functions

by | May 18, 2021

Overview

We have seen how to build a basic Lex bot. Check that out if you haven’t from our sidebar. In this blog we aim to get one level up using AWS Lambda.

AWS Lambda is a computing service that runs code in response to events and automatically manages the computing resources required by that code. It is very simple to implement and integrate with Lex Bot. I have used Python for this implementation

Implementation

  1. keep Recharge as the only intent
  2. slots were new recharge and amount
  3. recharge type: Data, SMS, talktime
  4. recharge amounts : 10,100,500 and 1000
  5. uncheck the return parameters to client in fulfillment
  6. check mark AWS lambda function in fulfillment and choose the trial Hello World function
  7. also check lambda initialization and validation and set it to trialHelloWorld function.(Note: unless your function is created it would not be shown in the drop down.

For Lambda function

  1. Search Lambda in aws search bar.
  2. Create new function.
  3. You can either choose a readymade function like oder_flower or use the snippet attached below.
  4. I have used python and latest version of language needs to be chosen by you too.
  5. There are a few code sections like close , get slots etc. These are aws Lex specific functions. do not touch them. Other parts are easy to understand if you have worked in python.
  6. Once you have code ready just deploy it and we are ready to go.

 

	
  	"""
This sample demonstrates an implementation of the Lex Code Hook Interface
in order to serve a sample bot which makes recharge.
Bot, Intent, and Slot models which are compatible with this sample can be found in the Lex Console
as part of the 'Recharge' 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
from pprint import pprint
import boto3

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 put_recharge(phone, amt, type):
    logger.debug('We have entered the put_recharge function')
    # if not dynamodb:
    amnt = int(amt)
    phn = int(phone)
    dynamodb = boto3.resource('dynamodb')

    table = dynamodb.Table('customerDB')
    response = table.put_item(
      Item={
            'phone': phn,
            'amt': amnt,
            'type': type
        }
    )
    print(response)
    

def validate_recharge(recharge_type,recharge_amt):
    
    """this fuction uses the input values and check if they are from the list below. if yes True is sent back else False is returned """
    logger.debug('We have entered the validate_recharge function')
    recharge_types = ['sms', 'data', 'talktime']
    if recharge_type is not None and recharge_type.lower() not in recharge_types:
        return build_validation_result(False,
                                       'newrechargeType',
                                       'We do not have {}, would you like a different type of recharge?  '
                                       'Our most popular recharge is data'.format(recharge_type))

    recharge_amts = ['10', '100', '500','1000']
    if recharge_amt is not None and recharge_amt not in recharge_amts:
        return build_validation_result(False,
                                       'rechargeAmount',
                                       'We do not have {} $ recharge, would you like a different amount of recharge? '.format(recharge_amt))

    
    return build_validation_result(True,True,None)


""" --- Functions that control the bot's behavior --- """
def dbupdate(intent_request):
    
    phoneNo = get_slots(intent_request)["phone"]
    recharge_type = get_slots(intent_request)["newrechargeType"]   # takes the value of recharge Type using get slots function
    recharge_amt = get_slots(intent_request)["rechargeAmount"]    
    
    logger.debug('We have entered the db function call')
    recharge_resp = put_recharge(phoneNo,recharge_amt,recharge_type)
    print("Put recharge succeeded:")
    pprint(recharge_resp, sort_dicts=False)
    
    return recharge_resp

def recharge(intent_request):
    """
    Performs dialog management and fulfillment for recharge action.
    """
    phoneNo = get_slots(intent_request)["phone"]
    recharge_type = get_slots(intent_request)["newrechargeType"]   # takes the value of recharge Type using get slots function
    recharge_amt = get_slots(intent_request)["rechargeAmount"]     # takes the value of recharge amount using get slots function
    source = intent_request['invocationSource']# source is fixed. Dont change this unless you know what you are doing


    if source == 'DialogCodeHook': # source is fixed. Dont change this unless you know what you are doing
        # 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)
        logger.debug('We have entered the if sourcce loop')
        validation_result = validate_recharge(recharge_type,recharge_amt)
        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'])
        output_session_attributes = intent_request['sessionAttributes'] if intent_request['sessionAttributes'] is not None else {}
      
        return delegate(output_session_attributes, get_slots(intent_request))
    
    
    if phoneNo is not None and recharge_type is not None and recharge_amt is not None:
        logger.debug('We have entered the db function call')
        recharge_resp = dbupdate(intent_request)
        print("Put recharge succeeded:")

            
   
    # 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': 'Recharge of {}$ {} for {} is successful.Thank you '.format(recharge_amt, recharge_type,phoneNo)})


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


def dispatch(intent_request):
    """
    Called when the user specifies an intent for this bot.
    """
    intent_name = intent_request['currentIntent']['name']   # takes the intent name in our code Recharge
    
    logger.debug('dispatch userId={}, intentName={}'.format(intent_request['userId'], intent_request['currentIntent']['name']))
    
    # Dispatch to your bot's intent handlers
    if intent_name == 'Foodorder':
        # logger.dispatch("recahrge is being updated")
        return recharge(intent_request)

    # if intent_name == 'Recharge':
    #     logger.dispatch("Db is being updated ")
    #     return dbupdate(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.
    logger.debug('event.bot.name={}'.format(event['bot']['name']))
    
    return dispatch(event)  # this calls the dispatch function 

  

Conclusion

The lambda service is highly scalable and we can also add database and other integrations in lambda. Lambda functions make our Lex bot highly dynamic. I hope you have learned something new from this blog. We work in cloud native domain so let us know if we can help you any way any time. Until next time happy learning!!

Post comments

Making a smart Contact Center Chatbot using AWS Lex

OverviewWith advent of google and amazon we all love to chat with bots. These bots automate a lot of routine tasks or chats to be specific. Imagine if you could drop off a bot with all FAQs known on your platform. This would reduce the number of questions and spams in...

read more
Share This