Search code examples
jsonpython-3.xalexa-skills-kitalexa-slot

Problem parsing Alexa json response in python to get value name


I have the following intent passed to my handler:

"request": {
    "type": "IntentRequest",
    "requestId": "amzn1.echo-api.request.3af5c8c3-1d1f-4169-8ce8-fde1a99a7c8d",
    "timestamp": "2019-04-03T04:08:06Z",
    "locale": "en-US",
    "intent": {
        "name": "get_speeds",
        "confirmationStatus": "NONE",
        "slots": {
            "direction": {
                "name": "direction",
                "value": "inbound",
                "resolutions": {
                    "resolutionsPerAuthority": [
                        {
                            "authority": "amzn1.er-authority.echo-sdk.amzn1.ask.skill.e76bf13b-71ac-4a90-94d4-597aa597ae87.direction",
                            "status": {
                                "code": "ER_SUCCESS_MATCH"
                            },
                            "values": [
                                {
                                    "value": {
                                        "name": "inbound",
                                        "id": "a8e6fe5b9e68f30a146cefebaa7edcc3"
                                    }
                                }
                            ]
                        }
                    ]
                },
                "confirmationStatus": "NONE",
                "source": "USER"
            }
        }
    },
    "dialogState": "COMPLETED"
}

I want to extract the actual value, not the utterance, e.g., the value name, in this case, "inbound". I've tried this and various similar iterations (the prints are for debugging):

    slots = handler_input.request_envelope.request.intent.slots
    resolutions = slots["direction"].resolutions
    print(resolutions)
    print(resolutions["resolutions_per_authority"])
    direction = resolutions["resolutions_per_authority"][0]["values"][0]["value"]["name"]
    session_attr = handler_input.attributes_manager.session_attributes

I've also tried the same with "resolutionsPerAuthority" which is the JSON that is passed, but apparently not what comes out to my program, as the log has:

04:08:07
{'resolutions_per_authority': [{'authority': 'amzn1.er-authority.echo-sdk.amzn1.ask.skill.e76bf13b-71ac-4a90-94d4-597aa597ae87.direction',

04:08:07
'status': {'code': 'ER_SUCCESS_MATCH'},

04:08:07
'values': [{'value': {'id': 'a8e6fe5b9e68f30a146cefebaa7edcc3',

04:08:07
'name': 'inbound'}}]}]}

04:08:07
'Resolutions' object is not subscriptable

This is the error I keep getting with all my approaches: 'Resolutions' object is not subscriptable. Can someone help me with how to extract the canonical slot values? I need to do the same thing for several other intents, but I figure if I can get this one working, it will be a model for the others.


Solution

  • As you already pointed out, your problem was that you treated the resolution object as it was subscriptable, accessing it via

    resolutions.resolutions_per_authority[0].values[0].value
    

    is the right way to obtain it.

    It may be helpful to point out that, in case of multiple matches, Alexa will return the resolutions in the order of the most likely to match the user intent.

    This code snippet iterates the slots and return a python dictionary with just the keys to know if it was validated and the id of the matched value:

    from ask_sdk_model.slu.entityresolution import StatusCode
    
    @staticmethod
    def get_slot_values(filled_slots):
        """Return slot values with additional info."""
        slot_values = {}
        logger.info("Filled slots: {}".format(filled_slots).replace("\n", "\r"))
    
        for key, slot_item in six.iteritems(filled_slots):
            name = slot_item.name
            try:
                status_code = slot_item.resolutions.resolutions_per_authority[0].status.code
    
                if status_code == StatusCode.ER_SUCCESS_MATCH:
                    slot_values[name] = {
                        "synonym": slot_item.value,
                        "resolved": slot_item.resolutions.resolutions_per_authority[0].values[0].value.__dict__,  # to make it JSON serializable
                        "is_validated": True,
                    }
                elif status_code == StatusCode.ER_SUCCESS_NO_MATCH:
                    slot_values[name] = {
                        "synonym": slot_item.value,
                        "resolved": slot_item.value,
                        "is_validated": False,
                    }
                else:
                    pass
            except (AttributeError, ValueError, KeyError, IndexError, TypeError) as e:
                # for BUILT-IN intents, there are no resolutions, but the value is specified
                if slot_item.value is not None and slot_item.value != 'NONE':
                    slot_values[name] = {
                        "synonym": slot_item.value,
                        "resolved": slot_item.value,
                        "is_validated": True,
                    }
                else:
                    logger.info("SLOT {} UNRESOLVED".format(name))
                    slot_values[name] = {
                        "synonym": slot_item.value,
                        "resolved": slot_item.value,
                        "is_validated": False,
                    }
        return slot_values
    

    where filled_slots = handler_input.request_envelope.request.intent.slots