0

I am developing a Amazon Lex Chatbot in AWS Lambda in python which will make a API post call and get a response in JSON string as below

'{"_id":"598045d12e1f98980a00001e","unique_id":"ed7e4e17c7db499caee576a7761512","cerebro":{"_id":"59451b239db9fa8b0a000004","acc_id":"533a9f0d2eda783019000002","name":"cerebro","access_id":"g01n0XTwoYfEWSIP","access_token":"3Yxw8ZiUlfSPsbEVLI6Z93vZyKyBFFIV"},"bot":{"_id":"59452f42dbd13ad867000001","name":"helloword"},"rundata":{"arguments":"","target":"local"},"state":"created","queue_id":null,"s_ts":null,"e_ts":null,"response":{},"responses":[],"summary":null,"resolve_incident":false,"err":null}'

But i am interested in the id value only so i am converting the json into a dictionary as below and getting the id value

res = requests.post(botrun_api, json=botrun_payload, headers=headers)
data = json.loads(res.content)
new_id=json_data.get('_id', None)
return new_id

If i am testing the code in Lambda console i am getting the output

Output in AWS Lambda console

But i am getting output as below in my Chatbot

I was unable to process your message. DependencyFailedException: Invalid Lambda Response: Received invalid response from Lambda: Can not construct instance of IntentResponse: no String-argument constructor/factory method to deserialize from String value ('59832ba22e1f98980a00009b') at [Source: "59832ba22e1f98980a00009b"; line: 1, column: 1]

My Source code as below:

import math
import dateutil.parser
import datetime
import time
import os
import logging
import requests
import uuid

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 APIbot(intent_request):
    """
    Performs dialog management and fulfillment for cluster configuration input arguments.
    Beyond fulfillment, the implementation of this intent demonstrates the use of the elicitSlot dialog action
    in slot validation and re-prompting.
    """

    value1 = get_slots(intent_request)["myval1"]
    value2 = get_slots(intent_request)["myval2"]
    intense_type = get_slots(intent_request)["Instance"]
    source = intent_request['invocationSource'] 
    api_endpoint = 'url'
    api_creds = {
    'apiuser': 'user',
    'apikey': 'key'
    }

    #trigger a bot run
    botrun_api = api_endpoint + '/botruns'

    botrun_payload = {
        "botname":"helloword",
        "arguments":"",
        "target":"local",
        "unique_id": uuid.uuid4().hex[:30] #unique run id - 30 chars max
    }

    headers = {
        'Content-Type': 'application/json',
        'Authorization': 'Key apiuser=%(apiuser)s apikey=%(apikey)s' % api_creds
    }

    res = requests.post(botrun_api, json=botrun_payload, headers=headers)
    data = json.loads(res.content)  
    new_id=json_data.get('_id', None)   
    return new_id



    # Instiate a cluster setup, 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': 'Thanks, your values are {} and {} '.format(value1, value2)})


""" --- 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 == 'my_Values':
        return APIbot(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)

Please help me in resolving this thanks in advance :)

3
  • Why does your APIBot function have two return statements? Commented Aug 4, 2017 at 2:01
  • Possible duplicate of Getting response from AWS Lambda function to AWS Lex bot is giving error? Commented Aug 4, 2017 at 2:05
  • Hi thanks for responding i kept return statement for just testing purpose but this question little different to the one you gave in the comments Commented Aug 4, 2017 at 4:22

1 Answer 1

1

Lambda is showing your function succeeding when only the new_id is returned because it does not care about the format of the response.

When connected to AWS Lex, the response must be in the AWS defined response format.

In your above example, you can pass the new_id through in the close method, to output the response via Lex:

return close(intent_request['sessionAttributes'],
             'Fulfilled',
             {'contentType': 'PlainText',
              'content': str(new_id)}

You'll also need to remove the return new_id statement.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.