mirror of
https://github.com/home-assistant/core.git
synced 2025-07-15 01:07:10 +00:00
Snips (new) added speech response, parse snips/duration (#11513)
* Snips changed to using <username>:intentName instead of user_IDSTRING__intentName * added response to snips * blank line * added unittests * houndy * sdtuff * more stuff * Update test_snips.py * Update snips.py * Split log tests to avoid dict ordering in py34 * Update test_snips.py * Update test_snips.py * still broken * fixed tests * fixed tests * removed fix submitted in another PR
This commit is contained in:
parent
efb83dde19
commit
4a6b5ba02b
@ -7,8 +7,10 @@ https://home-assistant.io/components/snips/
|
||||
import asyncio
|
||||
import json
|
||||
import logging
|
||||
from datetime import timedelta
|
||||
import voluptuous as vol
|
||||
from homeassistant.helpers import intent, config_validation as cv
|
||||
import homeassistant.components.mqtt as mqtt
|
||||
|
||||
DOMAIN = 'snips'
|
||||
DEPENDENCIES = ['mqtt']
|
||||
@ -59,21 +61,52 @@ def async_setup(hass, config):
|
||||
_LOGGER.error('Intent has invalid schema: %s. %s', err, request)
|
||||
return
|
||||
|
||||
snips_response = None
|
||||
|
||||
intent_type = request['intent']['intentName'].split('__')[-1]
|
||||
slots = {}
|
||||
for slot in request.get('slots', []):
|
||||
if 'value' in slot['value']:
|
||||
slots[slot['slotName']] = {'value': slot['value']['value']}
|
||||
else:
|
||||
slots[slot['slotName']] = {'value': slot['rawValue']}
|
||||
slots[slot['slotName']] = {'value': resolve_slot_values(slot)}
|
||||
|
||||
try:
|
||||
yield from intent.async_handle(
|
||||
intent_response = yield from intent.async_handle(
|
||||
hass, DOMAIN, intent_type, slots, request['input'])
|
||||
if 'plain' in intent_response.speech:
|
||||
snips_response = intent_response.speech['plain']['speech']
|
||||
except intent.UnknownIntent as err:
|
||||
_LOGGER.warning("Received unknown intent %s",
|
||||
request['intent']['intentName'])
|
||||
snips_response = "Unknown Intent"
|
||||
except intent.IntentError:
|
||||
_LOGGER.exception("Error while handling intent: %s.", intent_type)
|
||||
snips_response = "Error while handling intent"
|
||||
|
||||
notification = {'sessionId': request.get('sessionId', 'default'),
|
||||
'text': snips_response}
|
||||
|
||||
_LOGGER.debug("send_response %s", json.dumps(notification))
|
||||
mqtt.async_publish(hass, 'hermes/dialogueManager/endSession',
|
||||
json.dumps(notification))
|
||||
|
||||
yield from hass.components.mqtt.async_subscribe(
|
||||
INTENT_TOPIC, message_received)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def resolve_slot_values(slot):
|
||||
"""Convert snips builtin types to useable values."""
|
||||
if 'value' in slot['value']:
|
||||
value = slot['value']['value']
|
||||
else:
|
||||
value = slot['rawValue']
|
||||
|
||||
if slot.get('entity') == "snips/duration":
|
||||
delta = timedelta(weeks=slot['value']['weeks'],
|
||||
days=slot['value']['days'],
|
||||
hours=slot['value']['hours'],
|
||||
minutes=slot['value']['minutes'],
|
||||
seconds=slot['value']['seconds'])
|
||||
value = delta.seconds
|
||||
|
||||
return value
|
||||
|
@ -1,41 +1,42 @@
|
||||
"""Test the Snips component."""
|
||||
import asyncio
|
||||
import json
|
||||
|
||||
from homeassistant.core import callback
|
||||
from homeassistant.bootstrap import async_setup_component
|
||||
from tests.common import async_fire_mqtt_message, async_mock_intent
|
||||
|
||||
EXAMPLE_MSG = """
|
||||
{
|
||||
"input": "turn the lights green",
|
||||
"intent": {
|
||||
"intentName": "Lights",
|
||||
"probability": 1
|
||||
},
|
||||
"slots": [
|
||||
{
|
||||
"slotName": "light_color",
|
||||
"value": {
|
||||
"kind": "Custom",
|
||||
"value": "green"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_snips_call_action(hass, mqtt_mock):
|
||||
"""Test calling action via Snips."""
|
||||
def test_snips_intent(hass, mqtt_mock):
|
||||
"""Test intent via Snips."""
|
||||
result = yield from async_setup_component(hass, "snips", {
|
||||
"snips": {},
|
||||
})
|
||||
assert result
|
||||
payload = """
|
||||
{
|
||||
"input": "turn the lights green",
|
||||
"intent": {
|
||||
"intentName": "Lights",
|
||||
"probability": 1
|
||||
},
|
||||
"slots": [
|
||||
{
|
||||
"slotName": "light_color",
|
||||
"value": {
|
||||
"kind": "Custom",
|
||||
"value": "green"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
|
||||
intents = async_mock_intent(hass, 'Lights')
|
||||
|
||||
async_fire_mqtt_message(hass, 'hermes/intent/activateLights',
|
||||
EXAMPLE_MSG)
|
||||
async_fire_mqtt_message(hass, 'hermes/intent/Lights',
|
||||
payload)
|
||||
yield from hass.async_block_till_done()
|
||||
assert len(intents) == 1
|
||||
intent = intents[0]
|
||||
@ -43,3 +44,143 @@ def test_snips_call_action(hass, mqtt_mock):
|
||||
assert intent.intent_type == 'Lights'
|
||||
assert intent.slots == {'light_color': {'value': 'green'}}
|
||||
assert intent.text_input == 'turn the lights green'
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_snips_intent_with_snips_duration(hass, mqtt_mock):
|
||||
"""Test intent with Snips duration."""
|
||||
result = yield from async_setup_component(hass, "snips", {
|
||||
"snips": {},
|
||||
})
|
||||
assert result
|
||||
payload = """
|
||||
{
|
||||
"input": "set a timer of five minutes",
|
||||
"intent": {
|
||||
"intentName": "SetTimer"
|
||||
},
|
||||
"slots": [
|
||||
{
|
||||
"rawValue": "five minutes",
|
||||
"value": {
|
||||
"kind": "Duration",
|
||||
"years": 0,
|
||||
"quarters": 0,
|
||||
"months": 0,
|
||||
"weeks": 0,
|
||||
"days": 0,
|
||||
"hours": 0,
|
||||
"minutes": 5,
|
||||
"seconds": 0,
|
||||
"precision": "Exact"
|
||||
},
|
||||
"range": {
|
||||
"start": 15,
|
||||
"end": 27
|
||||
},
|
||||
"entity": "snips/duration",
|
||||
"slotName": "timer_duration"
|
||||
}
|
||||
]
|
||||
}
|
||||
"""
|
||||
intents = async_mock_intent(hass, 'SetTimer')
|
||||
|
||||
async_fire_mqtt_message(hass, 'hermes/intent/SetTimer',
|
||||
payload)
|
||||
yield from hass.async_block_till_done()
|
||||
assert len(intents) == 1
|
||||
intent = intents[0]
|
||||
assert intent.platform == 'snips'
|
||||
assert intent.intent_type == 'SetTimer'
|
||||
assert intent.slots == {'timer_duration': {'value': 300}}
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_intent_speech_response(hass, mqtt_mock):
|
||||
"""Test intent speech response via Snips."""
|
||||
event = 'call_service'
|
||||
events = []
|
||||
|
||||
@callback
|
||||
def record_event(event):
|
||||
"""Add recorded event to set."""
|
||||
events.append(event)
|
||||
|
||||
result = yield from async_setup_component(hass, "snips", {
|
||||
"snips": {},
|
||||
})
|
||||
assert result
|
||||
result = yield from async_setup_component(hass, "intent_script", {
|
||||
"intent_script": {
|
||||
"spokenIntent": {
|
||||
"speech": {
|
||||
"type": "plain",
|
||||
"text": "I am speaking to you"
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
assert result
|
||||
payload = """
|
||||
{
|
||||
"input": "speak to me",
|
||||
"sessionId": "abcdef0123456789",
|
||||
"intent": {
|
||||
"intentName": "spokenIntent"
|
||||
},
|
||||
"slots": []
|
||||
}
|
||||
"""
|
||||
hass.bus.async_listen(event, record_event)
|
||||
async_fire_mqtt_message(hass, 'hermes/intent/spokenIntent',
|
||||
payload)
|
||||
yield from hass.async_block_till_done()
|
||||
|
||||
assert len(events) == 1
|
||||
assert events[0].data['domain'] == 'mqtt'
|
||||
assert events[0].data['service'] == 'publish'
|
||||
payload = json.loads(events[0].data['service_data']['payload'])
|
||||
topic = events[0].data['service_data']['topic']
|
||||
assert payload['sessionId'] == 'abcdef0123456789'
|
||||
assert payload['text'] == 'I am speaking to you'
|
||||
assert topic == 'hermes/dialogueManager/endSession'
|
||||
|
||||
|
||||
@asyncio.coroutine
|
||||
def test_snips_unknown_intent(hass, mqtt_mock):
|
||||
"""Test calling unknown Intent via Snips."""
|
||||
event = 'call_service'
|
||||
events = []
|
||||
|
||||
@callback
|
||||
def record_event(event):
|
||||
"""Add recorded event to set."""
|
||||
events.append(event)
|
||||
result = yield from async_setup_component(hass, "snips", {
|
||||
"snips": {},
|
||||
})
|
||||
assert result
|
||||
payload = """
|
||||
{
|
||||
"input": "what to do",
|
||||
"intent": {
|
||||
"intentName": "unknownIntent"
|
||||
},
|
||||
"slots": []
|
||||
}
|
||||
"""
|
||||
intents = async_mock_intent(hass, 'knownIntent')
|
||||
hass.bus.async_listen(event, record_event)
|
||||
async_fire_mqtt_message(hass, 'hermes/intent/unknownIntent',
|
||||
payload)
|
||||
yield from hass.async_block_till_done()
|
||||
|
||||
assert len(intents) == 0
|
||||
assert len(events) == 1
|
||||
assert events[0].data['domain'] == 'mqtt'
|
||||
assert events[0].data['service'] == 'publish'
|
||||
payload = json.loads(events[0].data['service_data']['payload'])
|
||||
topic = events[0].data['service_data']['topic']
|
||||
assert payload['text'] == 'Unknown Intent'
|
||||
assert topic == 'hermes/dialogueManager/endSession'
|
||||
|
Loading…
x
Reference in New Issue
Block a user