Skip to content

Commit

Permalink
Use the 'id' field and nearest resolutions
Browse files Browse the repository at this point in the history
Expose nearest Resolution (ID and Value) as Variables
  • Loading branch information
AzonInc committed Jan 26, 2023
1 parent cbcff64 commit 354e45c
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 5 deletions.
35 changes: 30 additions & 5 deletions homeassistant/components/alexa/intent.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,12 +181,17 @@ async def async_handle_intent(hass, message):
return alexa_response.as_dict()


def resolve_slot_synonyms(key, request):
def resolve_slot_data(key, request):
"""Check slot request for synonym resolutions."""
# Default to the spoken slot value if more than one or none are found. For
# Default to the spoken slot value if more than one or none are found. Always
# passes the id and name of the nearest possible slot resolution. For
# reference to the request object structure, see the Alexa docs:
# https://tinyurl.com/ybvm7jhs
resolved_value = request["value"]
resolved_id = ""

resolved_value_nearest = request["value"]
resolved_id_nearest = ""

if (
"resolutions" in request
Expand All @@ -197,25 +202,41 @@ def resolve_slot_synonyms(key, request):
# Extract all of the possible values from each authority with a
# successful match
possible_values = []
possible_ids = []

for entry in request["resolutions"]["resolutionsPerAuthority"]:
if entry["status"]["code"] != SYN_RESOLUTION_MATCH:
continue

possible_values.extend([item["value"]["name"] for item in entry["values"]])
possible_ids.extend([item["value"]["id"] for item in entry["values"]])

# Always set nearest name and id if available, otherwise the spoken slot
# value and an empty string as id is used
if len(possible_values) >= 1:
resolved_value_nearest = possible_values[0]
resolved_id_nearest = possible_ids[0]

# If there is only one match use the resolved value, otherwise the
# resolution cannot be determined, so use the spoken slot value
# resolution cannot be determined, so use the spoken slot value and empty string as id
if len(possible_values) == 1:
resolved_value = possible_values[0]
resolved_id = possible_ids[0]
else:
_LOGGER.debug(
"Found multiple synonym resolutions for slot value: {%s: %s}",
key,
resolved_value,
)

return resolved_value
# Combine Slot Data
resolved_data = {}
resolved_data["value"] = resolved_value
resolved_data["id"] = resolved_id
resolved_data["value_nearest"] = resolved_value_nearest
resolved_data["id_nearest"] = resolved_id_nearest

return resolved_data


class AlexaResponse:
Expand All @@ -239,8 +260,12 @@ def __init__(self, hass, intent_info):
continue

_key = key.replace(".", "_")
_slot_data = resolve_slot_data(key, value)

self.variables[_key] = resolve_slot_synonyms(key, value)
self.variables[_key] = _slot_data["value"]
self.variables[_key + "_ID"] = _slot_data["id"]
self.variables[_key + "_NEAREST"] = _slot_data["value_nearest"]
self.variables[_key + "_NEAREST_ID"] = _slot_data["id_nearest"]

def add_card(self, card_type, title, content):
"""Add a card to the response."""
Expand Down
50 changes: 50 additions & 0 deletions tests/components/alexa/test_intent.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,56 @@ async def test_intent_request_with_slots_and_synonym_resolution(alexa_client):
assert text == "You told us your sign is Virgo."


async def test_intent_request_with_slots_and_synonym_id_resolution(alexa_client):
"""Test a request with slots and a name synonym."""
data = {
"version": "1.0",
"session": {
"new": False,
"sessionId": SESSION_ID,
"application": {"applicationId": APPLICATION_ID},
"attributes": {
"supportedHoroscopePeriods": {
"daily": True,
"weekly": False,
"monthly": False,
}
},
"user": {"userId": "amzn1.account.AM3B00000000000000000000000"},
},
"request": {
"type": "IntentRequest",
"requestId": REQUEST_ID,
"timestamp": "2015-05-13T12:34:56Z",
"intent": {
"name": "GetZodiacHoroscopeIntent",
"slots": {
"ZodiacSign": {
"name": "ZodiacSign",
"value": "V zodiac",
"resolutions": {
"resolutionsPerAuthority": [
{
"authority": AUTHORITY_ID,
"status": {"code": "ER_SUCCESS_MATCH"},
"values": [
{"value": {"name": "Virgo", "id": "VIRGO"}}
],
}
]
},
}
},
},
},
}
req = await _intent_req(alexa_client, data)
assert req.status == HTTPStatus.OK
data = await req.json()
text = data.get("response", {}).get("outputSpeech", {}).get("text")
assert text == "You told us your sign is Virgo."


async def test_intent_request_with_slots_and_multi_synonym_resolution(alexa_client):
"""Test a request with slots and multiple name synonyms."""
data = {
Expand Down

0 comments on commit 354e45c

Please sign in to comment.