I have written my lambda function and it works perfectly but when I try to communicate with it from Lex I get dependency exception.How can i debug this or solve this issue? The variable REST_END_POINT has been defined. Below is my code please kindly look at it and tell me what I might be doing wrong?
I researched the issue on Amazon Lex doc. And it is mentioned the following:
DependencyFailedException 1. One of the dependencies, such as AWS Lambda or Amazon Polly, threw an exception. For example,
If Amazon Lex does not have sufficient permissions to call a Lambda function.
If a Lambda function takes longer than 30 seconds to execute.
If a fulfillment Lambda function returns a Delegate dialog action without removing any slot values.
HTTP Status Code: 424
These are the actions I have undertaken:
- I have checked that my lambda function does not take more than 30 seconds to execute
- And Amazon Lex has the right permissions to call my lambda function
The third point i don't quite understand but I think its solved too from the code i provided please correct me if am wrong.
def elicit_slot(session_attributes, intent_name, slots, slot_to_elicit, message, response_card):
return {
'sessionAttributes': session_attributes,
'dialogAction': {
'type': 'ElicitSlot',
'intentName': intent_name,
'slots': slots,
'slotToElicit': slot_to_elicit,
'message': message,
'responseCard': response_card
}
}
def confirm_intent(session_attributes, intent_name, slots, message, response_card):
return {
'sessionAttributes': session_attributes,
'dialogAction': {
'type': 'ConfirmIntent',
'intentName': intent_name,
'slots': slots,
'message': message,
'responseCard': response_card
}
}
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
}
}
def build_response_card(title, subtitle, options):
"""
Build a responseCard with a title, subtitle, and an optional set of options which should be displayed as buttons.
"""
buttons = None
if options is not None:
buttons = []
for i in range(min(5, len(options))):
buttons.append(options[i])
return {
'contentType': 'application/vnd.amazonaws.card.generic',
'version': 1,
'genericAttachments': [{
'title': title,
'subTitle': subtitle,
'buttons': buttons
}]
}
""" --- Helper Functions --- """
def parse_int(n):
try:
return int(n)
except ValueError:
return float('nan')
def try_ex(func):
"""
Call passed in function in try block. If KeyError is encountered return None.
This function is intended to be used to safely access dictionary.
Note that this function would have negative impact on performance.
"""
try:
return func()
except KeyError:
return None
def isvalid_date(date):
try:
dateutil.parser.parse(date)
return True
except ValueError:
return False
def build_validation_result(is_valid, violated_slot, message_content):
return {
'isValid': is_valid,
'violatedSlot': violated_slot,
'message': {'contentType': 'PlainText', 'content': message_content}
}
def validate_oms_count(oms_type, date):
if oms_type:
if len(oms_type) == 0 or (oms_type != 'transport' and oms_type != 'overtime'):
return build_validation_result(False, 'OmsType', 'I did not recognize that, can I make an overtime request?')
if date:
if not isvalid_date(date):
return build_validation_result(False, 'Date', 'I did not understand that, what date works best for you?')
return build_validation_result(True, None, None)
def validate_menu_date(date):
if date:
if not isvalid_date(date):
return build_validation_result(False, 'Date', 'I did not understand that, what date works best for you?')
return build_validation_result(True, None, None)
def get_token(output_session_attributes):
token = json.loads(try_ex(lambda: output_session_attributes['token']) or '{}')
if not token:
try:
data = bytes(json.dumps({"username": "admin","password": "Oms2017@","rememberMe": "false"}), 'utf-8')
f = urllib.request.urlopen(urllib.request.Request(REST_END_POINT+'/authenticate', data, {'Content-Type': 'application/json'}))
result = json.loads(f.read().decode())
output_session_attributes['token'] = result['id_token']
logger.debug('Token {}'.format(result['id_token']))
return result['id_token']
except Exception as e:
logger.debug('An error occurred at the backend1 {}'.format(e))
else:
return token
def build_options(slot, oms_type):
"""
Build a list of potential options for a given slot, to be used in responseCard generation.
"""
if slot == 'OmsType':
return [
{'text': 'Transport', 'value': 'transport'},
{'text': 'Overtime', 'value': 'overtime'}
]
""" --- Functions that control the bot's behavior --- """
def get_menu_of_day(intent_request):
"""
Performs dialog management and fulfillment for getting the menu of the day.
Beyond fulfillment, the implementation for this intent demonstrates the following:
1) Use of elicitSlot in slot validation and re-prompting
2) Use of confirmIntent to support the confirmation of inferred slot values, when confirmation is required
on the bot model and the inferred slot values fully specify the intent.
"""
date = intent_request['currentIntent']['slots']['Date']
source = intent_request['invocationSource']
output_session_attributes = intent_request['sessionAttributes'] if intent_request['sessionAttributes'] is not None else {}
data_map = json.loads(try_ex(lambda: output_session_attributes['dataMap']) or '{}')
if source == 'DialogCodeHook':
# Perform basic validation on the supplied input slots.
slots = intent_request['currentIntent']['slots']
validation_result = validate_menu_date(date)
if not validation_result['isValid']:
slots[validation_result['violatedSlot']] = None
return elicit_slot(
output_session_attributes,
intent_request['currentIntent']['name'],
slots,
validation_result['violatedSlot'],
validation_result['message'],
build_response_card(
'Specify {}'.format(validation_result['violatedSlot']),
validation_result['message']['content'],
build_options(validation_result['violatedSlot'], None)
)
)
if not date:
slots['Date'] = None
return elicit_slot(
output_session_attributes,
intent_request['currentIntent']['name'],
intent_request['currentIntent']['slots'],
'Date',
{'contentType': 'PlainText', 'content': 'What date works for you?'},
build_response_card(
'Specify Date', 'What date works for you?',
build_options('Date', None)
)
)
if date:
get_token(output_session_attributes)
data_map['date'] = date
output_session_attributes['dataMap'] = json.dumps(data_map)
return delegate(output_session_attributes, slots)
# Send request to the backend service to perform user action.
token = get_token(output_session_attributes)
extractedMenu = []
try:
data_map['date'] = date
output_session_attributes['dataMap'] = json.dumps(data_map)
params = urllib.parse.urlencode({'day':date})
response = urllib.request.urlopen(urllib.request.Request(REST_END_POINT+'/menuOfdays?'+ params, headers={'Authorization': 'Bearer '+token}))
convertedResponse = json.loads(response.read().decode())
extractedMenu = [item['menu']['name'] for item in convertedResponse]
logger.debug(extractedMenu)
except Exception as e:
logger.debug('An error occurred at the backend2 {}'.format(e))
return close(
output_session_attributes,
'Fulfilled',
{
'contentType': 'PlainText',
'content': 'Menu of the day include: {} '.format(extractedMenu)
}
)
""" --- 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 == 'GetMenuOfDay':
return get_menu_of_day(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)
If everything works, when the question What is the menu for {Date} is asked, the response is: Menu of the day include a list of menu items