Skip to content

Commit

Permalink
Add support for Alexa intent slot synonyms. (#10469)
Browse files Browse the repository at this point in the history
  • Loading branch information
kmdm authored and balloob committed Nov 10, 2017
1 parent 7d9d299 commit 16dd90a
Show file tree
Hide file tree
Showing 2 changed files with 146 additions and 2 deletions.
20 changes: 19 additions & 1 deletion homeassistant/components/alexa/intent.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,10 +138,28 @@ def __init__(self, hass, intent_info):
# Intent is None if request was a LaunchRequest or SessionEndedRequest
if intent_info is not None:
for key, value in intent_info.get('slots', {}).items():
underscored_key = key.replace('.', '_')

if 'value' in value:
underscored_key = key.replace('.', '_')
self.variables[underscored_key] = value['value']

if 'resolutions' in value:
self._populate_resolved_values(underscored_key, value)

def _populate_resolved_values(self, underscored_key, value):
for resolution in value['resolutions']['resolutionsPerAuthority']:
if 'values' not in resolution:
continue

for resolved in resolution['values']:
if 'value' not in resolved:
continue

if 'id' in resolved['value']:
self.variables[underscored_key] = resolved['value']['id']
elif 'name' in resolved['value']:
self.variables[underscored_key] = resolved['value']['name']

def add_card(self, card_type, title, content):
"""Add a card to the response."""
assert self.card is None
Expand Down
128 changes: 127 additions & 1 deletion tests/components/alexa/test_intent.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
SESSION_ID = "amzn1.echo-api.session.0000000-0000-0000-0000-00000000000"
APPLICATION_ID = "amzn1.echo-sdk-ams.app.000000-d0ed-0000-ad00-000000d00ebe"
REQUEST_ID = "amzn1.echo-api.request.0000000-0000-0000-0000-00000000000"
AUTHORITY_ID = "amzn1.er-authority.000000-d0ed-0000-ad00-000000d00ebe.ZODIAC"

# pylint: disable=invalid-name
calls = []
Expand Down Expand Up @@ -90,7 +91,7 @@ def mock_service(call):
"type": "plain",
"text": "LaunchRequest has been received.",
}
}
},
}
}))
return loop.run_until_complete(test_client(hass.http.app))
Expand Down Expand Up @@ -207,6 +208,131 @@ def test_intent_request_with_slots(alexa_client):
assert text == "You told us your sign is virgo."


@asyncio.coroutine
def test_intent_request_with_slots_and_id_resolution(alexa_client):
"""Test a request with slots and an id 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": "virgo",
"resolutions": {
"resolutionsPerAuthority": [
{
"authority": AUTHORITY_ID,
"status": {
"code": "ER_SUCCESS_MATCH"
},
"values": [
{
"value": {
"name": "Virgo",
"id": "VIRGO"
}
}
]
}
]
}
}
}
}
}
}
req = yield from _intent_req(alexa_client, data)
assert req.status == 200
data = yield from req.json()
text = data.get("response", {}).get("outputSpeech",
{}).get("text")
assert text == "You told us your sign is VIRGO."


@asyncio.coroutine
def test_intent_request_with_slots_and_name_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": "virgo",
"resolutions": {
"resolutionsPerAuthority": [
{
"authority": AUTHORITY_ID,
"status": {
"code": "ER_SUCCESS_MATCH"
},
"values": [
{
"value": {
"name": "Virgo"
}
}
]
}
]
}
}
}
}
}
}
req = yield from _intent_req(alexa_client, data)
assert req.status == 200
data = yield from req.json()
text = data.get("response", {}).get("outputSpeech",
{}).get("text")
assert text == "You told us your sign is Virgo."


@asyncio.coroutine
def test_intent_request_with_slots_but_no_value(alexa_client):
"""Test a request with slots but no value."""
Expand Down

0 comments on commit 16dd90a

Please sign in to comment.