Intents package combines sentences/responses per language (#109079)
parent
a1f36c25d4
commit
9752e70675
|
@ -6,7 +6,6 @@ from collections import defaultdict
|
||||||
from collections.abc import Awaitable, Callable, Iterable
|
from collections.abc import Awaitable, Callable, Iterable
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
import functools
|
import functools
|
||||||
import itertools
|
|
||||||
import logging
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import re
|
import re
|
||||||
|
@ -28,7 +27,7 @@ from hassil.recognize import (
|
||||||
recognize_all,
|
recognize_all,
|
||||||
)
|
)
|
||||||
from hassil.util import merge_dict
|
from hassil.util import merge_dict
|
||||||
from home_assistant_intents import get_domains_and_languages, get_intents
|
from home_assistant_intents import get_intents, get_languages
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from homeassistant import core, setup
|
from homeassistant import core, setup
|
||||||
|
@ -156,7 +155,7 @@ class DefaultAgent(AbstractConversationAgent):
|
||||||
@property
|
@property
|
||||||
def supported_languages(self) -> list[str]:
|
def supported_languages(self) -> list[str]:
|
||||||
"""Return a list of supported languages."""
|
"""Return a list of supported languages."""
|
||||||
return get_domains_and_languages()["homeassistant"]
|
return get_languages()
|
||||||
|
|
||||||
async def async_initialize(self, config_intents: dict[str, Any] | None) -> None:
|
async def async_initialize(self, config_intents: dict[str, Any] | None) -> None:
|
||||||
"""Initialize the default agent."""
|
"""Initialize the default agent."""
|
||||||
|
@ -387,6 +386,7 @@ class DefaultAgent(AbstractConversationAgent):
|
||||||
return maybe_result
|
return maybe_result
|
||||||
|
|
||||||
# Try again with missing entities enabled
|
# Try again with missing entities enabled
|
||||||
|
best_num_unmatched_entities = 0
|
||||||
for result in recognize_all(
|
for result in recognize_all(
|
||||||
user_input.text,
|
user_input.text,
|
||||||
lang_intents.intents,
|
lang_intents.intents,
|
||||||
|
@ -394,20 +394,28 @@ class DefaultAgent(AbstractConversationAgent):
|
||||||
intent_context=intent_context,
|
intent_context=intent_context,
|
||||||
allow_unmatched_entities=True,
|
allow_unmatched_entities=True,
|
||||||
):
|
):
|
||||||
# Remove missing entities that couldn't be filled from context
|
if result.text_chunks_matched < 1:
|
||||||
for entity_key, entity in list(result.unmatched_entities.items()):
|
# Skip results that don't match any literal text
|
||||||
if isinstance(entity, UnmatchedTextEntity) and (
|
continue
|
||||||
entity.text == MISSING_ENTITY
|
|
||||||
):
|
# Don't count missing entities that couldn't be filled from context
|
||||||
result.unmatched_entities.pop(entity_key)
|
num_unmatched_entities = 0
|
||||||
|
for entity in result.unmatched_entities_list:
|
||||||
|
if isinstance(entity, UnmatchedTextEntity):
|
||||||
|
if entity.text != MISSING_ENTITY:
|
||||||
|
num_unmatched_entities += 1
|
||||||
|
else:
|
||||||
|
num_unmatched_entities += 1
|
||||||
|
|
||||||
if maybe_result is None:
|
if maybe_result is None:
|
||||||
# First result
|
# First result
|
||||||
maybe_result = result
|
maybe_result = result
|
||||||
elif len(result.unmatched_entities) < len(maybe_result.unmatched_entities):
|
best_num_unmatched_entities = num_unmatched_entities
|
||||||
|
elif num_unmatched_entities < best_num_unmatched_entities:
|
||||||
# Fewer unmatched entities
|
# Fewer unmatched entities
|
||||||
maybe_result = result
|
maybe_result = result
|
||||||
elif len(result.unmatched_entities) == len(maybe_result.unmatched_entities):
|
best_num_unmatched_entities = num_unmatched_entities
|
||||||
|
elif num_unmatched_entities == best_num_unmatched_entities:
|
||||||
if (result.text_chunks_matched > maybe_result.text_chunks_matched) or (
|
if (result.text_chunks_matched > maybe_result.text_chunks_matched) or (
|
||||||
(result.text_chunks_matched == maybe_result.text_chunks_matched)
|
(result.text_chunks_matched == maybe_result.text_chunks_matched)
|
||||||
and ("name" in result.unmatched_entities) # prefer entities
|
and ("name" in result.unmatched_entities) # prefer entities
|
||||||
|
@ -536,14 +544,12 @@ class DefaultAgent(AbstractConversationAgent):
|
||||||
intents_dict = lang_intents.intents_dict
|
intents_dict = lang_intents.intents_dict
|
||||||
language_variant = lang_intents.language_variant
|
language_variant = lang_intents.language_variant
|
||||||
|
|
||||||
domains_langs = get_domains_and_languages()
|
supported_langs = set(get_languages())
|
||||||
|
|
||||||
if not language_variant:
|
if not language_variant:
|
||||||
# Choose a language variant upfront and commit to it for custom
|
# Choose a language variant upfront and commit to it for custom
|
||||||
# sentences, etc.
|
# sentences, etc.
|
||||||
all_language_variants = {
|
all_language_variants = {lang.lower(): lang for lang in supported_langs}
|
||||||
lang.lower(): lang for lang in itertools.chain(*domains_langs.values())
|
|
||||||
}
|
|
||||||
|
|
||||||
# en-US, en_US, en, ...
|
# en-US, en_US, en, ...
|
||||||
for maybe_variant in _get_language_variations(language):
|
for maybe_variant in _get_language_variations(language):
|
||||||
|
@ -558,23 +564,17 @@ class DefaultAgent(AbstractConversationAgent):
|
||||||
)
|
)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Load intents for all domains supported by this language variant
|
# Load intents for this language variant
|
||||||
for domain in domains_langs:
|
lang_variant_intents = get_intents(language_variant, json_load=json_load)
|
||||||
domain_intents = get_intents(
|
|
||||||
domain, language_variant, json_load=json_load
|
|
||||||
)
|
|
||||||
|
|
||||||
if not domain_intents:
|
|
||||||
continue
|
|
||||||
|
|
||||||
|
if lang_variant_intents:
|
||||||
# Merge sentences into existing dictionary
|
# Merge sentences into existing dictionary
|
||||||
merge_dict(intents_dict, domain_intents)
|
merge_dict(intents_dict, lang_variant_intents)
|
||||||
|
|
||||||
# Will need to recreate graph
|
# Will need to recreate graph
|
||||||
intents_changed = True
|
intents_changed = True
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
"Loaded intents domain=%s, language=%s (%s)",
|
"Loaded intents language=%s (%s)",
|
||||||
domain,
|
|
||||||
language,
|
language,
|
||||||
language_variant,
|
language_variant,
|
||||||
)
|
)
|
||||||
|
|
|
@ -7,5 +7,5 @@
|
||||||
"integration_type": "system",
|
"integration_type": "system",
|
||||||
"iot_class": "local_push",
|
"iot_class": "local_push",
|
||||||
"quality_scale": "internal",
|
"quality_scale": "internal",
|
||||||
"requirements": ["hassil==1.6.0", "home-assistant-intents==2024.1.2"]
|
"requirements": ["hassil==1.6.0", "home-assistant-intents==2024.1.29"]
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ hass-nabucasa==0.75.1
|
||||||
hassil==1.6.0
|
hassil==1.6.0
|
||||||
home-assistant-bluetooth==1.12.0
|
home-assistant-bluetooth==1.12.0
|
||||||
home-assistant-frontend==20240112.0
|
home-assistant-frontend==20240112.0
|
||||||
home-assistant-intents==2024.1.2
|
home-assistant-intents==2024.1.29
|
||||||
httpx==0.26.0
|
httpx==0.26.0
|
||||||
ifaddr==0.2.0
|
ifaddr==0.2.0
|
||||||
janus==1.0.0
|
janus==1.0.0
|
||||||
|
|
|
@ -1056,7 +1056,7 @@ holidays==0.41
|
||||||
home-assistant-frontend==20240112.0
|
home-assistant-frontend==20240112.0
|
||||||
|
|
||||||
# homeassistant.components.conversation
|
# homeassistant.components.conversation
|
||||||
home-assistant-intents==2024.1.2
|
home-assistant-intents==2024.1.29
|
||||||
|
|
||||||
# homeassistant.components.home_connect
|
# homeassistant.components.home_connect
|
||||||
homeconnect==0.7.2
|
homeconnect==0.7.2
|
||||||
|
|
|
@ -849,7 +849,7 @@ holidays==0.41
|
||||||
home-assistant-frontend==20240112.0
|
home-assistant-frontend==20240112.0
|
||||||
|
|
||||||
# homeassistant.components.conversation
|
# homeassistant.components.conversation
|
||||||
home-assistant-intents==2024.1.2
|
home-assistant-intents==2024.1.29
|
||||||
|
|
||||||
# homeassistant.components.home_connect
|
# homeassistant.components.home_connect
|
||||||
homeconnect==0.7.2
|
homeconnect==0.7.2
|
||||||
|
|
|
@ -48,14 +48,14 @@
|
||||||
'card': dict({
|
'card': dict({
|
||||||
}),
|
}),
|
||||||
'data': dict({
|
'data': dict({
|
||||||
'code': 'no_valid_targets',
|
'code': 'no_intent_match',
|
||||||
}),
|
}),
|
||||||
'language': 'en',
|
'language': 'en',
|
||||||
'response_type': 'error',
|
'response_type': 'error',
|
||||||
'speech': dict({
|
'speech': dict({
|
||||||
'plain': dict({
|
'plain': dict({
|
||||||
'extra_data': None,
|
'extra_data': None,
|
||||||
'speech': 'No device or entity named test transcript',
|
'speech': "Sorry, I couldn't understand that",
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
@ -67,7 +67,7 @@
|
||||||
'data': dict({
|
'data': dict({
|
||||||
'engine': 'test',
|
'engine': 'test',
|
||||||
'language': 'en-US',
|
'language': 'en-US',
|
||||||
'tts_input': 'No device or entity named test transcript',
|
'tts_input': "Sorry, I couldn't understand that",
|
||||||
'voice': 'james_earl_jones',
|
'voice': 'james_earl_jones',
|
||||||
}),
|
}),
|
||||||
'type': <PipelineEventType.TTS_START: 'tts-start'>,
|
'type': <PipelineEventType.TTS_START: 'tts-start'>,
|
||||||
|
@ -75,9 +75,9 @@
|
||||||
dict({
|
dict({
|
||||||
'data': dict({
|
'data': dict({
|
||||||
'tts_output': dict({
|
'tts_output': dict({
|
||||||
'media_id': 'media-source://tts/test?message=No+device+or+entity+named+test+transcript&language=en-US&voice=james_earl_jones',
|
'media_id': "media-source://tts/test?message=Sorry,+I+couldn't+understand+that&language=en-US&voice=james_earl_jones",
|
||||||
'mime_type': 'audio/mpeg',
|
'mime_type': 'audio/mpeg',
|
||||||
'url': '/api/tts_proxy/e5e8e318b536f0a5455f993243a34521e7ad4d6d_en-us_031e2ec052_test.mp3',
|
'url': '/api/tts_proxy/dae2cdcb27a1d1c3b07ba2c7db91480f9d4bfd8f_en-us_031e2ec052_test.mp3',
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
'type': <PipelineEventType.TTS_END: 'tts-end'>,
|
'type': <PipelineEventType.TTS_END: 'tts-end'>,
|
||||||
|
@ -137,14 +137,14 @@
|
||||||
'card': dict({
|
'card': dict({
|
||||||
}),
|
}),
|
||||||
'data': dict({
|
'data': dict({
|
||||||
'code': 'no_valid_targets',
|
'code': 'no_intent_match',
|
||||||
}),
|
}),
|
||||||
'language': 'en-US',
|
'language': 'en-US',
|
||||||
'response_type': 'error',
|
'response_type': 'error',
|
||||||
'speech': dict({
|
'speech': dict({
|
||||||
'plain': dict({
|
'plain': dict({
|
||||||
'extra_data': None,
|
'extra_data': None,
|
||||||
'speech': 'No device or entity named test transcript',
|
'speech': "Sorry, I couldn't understand that",
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
@ -156,7 +156,7 @@
|
||||||
'data': dict({
|
'data': dict({
|
||||||
'engine': 'test',
|
'engine': 'test',
|
||||||
'language': 'en-US',
|
'language': 'en-US',
|
||||||
'tts_input': 'No device or entity named test transcript',
|
'tts_input': "Sorry, I couldn't understand that",
|
||||||
'voice': 'Arnold Schwarzenegger',
|
'voice': 'Arnold Schwarzenegger',
|
||||||
}),
|
}),
|
||||||
'type': <PipelineEventType.TTS_START: 'tts-start'>,
|
'type': <PipelineEventType.TTS_START: 'tts-start'>,
|
||||||
|
@ -164,9 +164,9 @@
|
||||||
dict({
|
dict({
|
||||||
'data': dict({
|
'data': dict({
|
||||||
'tts_output': dict({
|
'tts_output': dict({
|
||||||
'media_id': 'media-source://tts/test?message=No+device+or+entity+named+test+transcript&language=en-US&voice=Arnold+Schwarzenegger',
|
'media_id': "media-source://tts/test?message=Sorry,+I+couldn't+understand+that&language=en-US&voice=Arnold+Schwarzenegger",
|
||||||
'mime_type': 'audio/mpeg',
|
'mime_type': 'audio/mpeg',
|
||||||
'url': '/api/tts_proxy/e5e8e318b536f0a5455f993243a34521e7ad4d6d_en-us_2657c1a8ee_test.mp3',
|
'url': '/api/tts_proxy/dae2cdcb27a1d1c3b07ba2c7db91480f9d4bfd8f_en-us_2657c1a8ee_test.mp3',
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
'type': <PipelineEventType.TTS_END: 'tts-end'>,
|
'type': <PipelineEventType.TTS_END: 'tts-end'>,
|
||||||
|
@ -226,14 +226,14 @@
|
||||||
'card': dict({
|
'card': dict({
|
||||||
}),
|
}),
|
||||||
'data': dict({
|
'data': dict({
|
||||||
'code': 'no_valid_targets',
|
'code': 'no_intent_match',
|
||||||
}),
|
}),
|
||||||
'language': 'en-US',
|
'language': 'en-US',
|
||||||
'response_type': 'error',
|
'response_type': 'error',
|
||||||
'speech': dict({
|
'speech': dict({
|
||||||
'plain': dict({
|
'plain': dict({
|
||||||
'extra_data': None,
|
'extra_data': None,
|
||||||
'speech': 'No device or entity named test transcript',
|
'speech': "Sorry, I couldn't understand that",
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
@ -245,7 +245,7 @@
|
||||||
'data': dict({
|
'data': dict({
|
||||||
'engine': 'test',
|
'engine': 'test',
|
||||||
'language': 'en-US',
|
'language': 'en-US',
|
||||||
'tts_input': 'No device or entity named test transcript',
|
'tts_input': "Sorry, I couldn't understand that",
|
||||||
'voice': 'Arnold Schwarzenegger',
|
'voice': 'Arnold Schwarzenegger',
|
||||||
}),
|
}),
|
||||||
'type': <PipelineEventType.TTS_START: 'tts-start'>,
|
'type': <PipelineEventType.TTS_START: 'tts-start'>,
|
||||||
|
@ -253,9 +253,9 @@
|
||||||
dict({
|
dict({
|
||||||
'data': dict({
|
'data': dict({
|
||||||
'tts_output': dict({
|
'tts_output': dict({
|
||||||
'media_id': 'media-source://tts/test?message=No+device+or+entity+named+test+transcript&language=en-US&voice=Arnold+Schwarzenegger',
|
'media_id': "media-source://tts/test?message=Sorry,+I+couldn't+understand+that&language=en-US&voice=Arnold+Schwarzenegger",
|
||||||
'mime_type': 'audio/mpeg',
|
'mime_type': 'audio/mpeg',
|
||||||
'url': '/api/tts_proxy/e5e8e318b536f0a5455f993243a34521e7ad4d6d_en-us_2657c1a8ee_test.mp3',
|
'url': '/api/tts_proxy/dae2cdcb27a1d1c3b07ba2c7db91480f9d4bfd8f_en-us_2657c1a8ee_test.mp3',
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
'type': <PipelineEventType.TTS_END: 'tts-end'>,
|
'type': <PipelineEventType.TTS_END: 'tts-end'>,
|
||||||
|
@ -338,14 +338,14 @@
|
||||||
'card': dict({
|
'card': dict({
|
||||||
}),
|
}),
|
||||||
'data': dict({
|
'data': dict({
|
||||||
'code': 'no_valid_targets',
|
'code': 'no_intent_match',
|
||||||
}),
|
}),
|
||||||
'language': 'en',
|
'language': 'en',
|
||||||
'response_type': 'error',
|
'response_type': 'error',
|
||||||
'speech': dict({
|
'speech': dict({
|
||||||
'plain': dict({
|
'plain': dict({
|
||||||
'extra_data': None,
|
'extra_data': None,
|
||||||
'speech': 'No device or entity named test transcript',
|
'speech': "Sorry, I couldn't understand that",
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
@ -357,7 +357,7 @@
|
||||||
'data': dict({
|
'data': dict({
|
||||||
'engine': 'test',
|
'engine': 'test',
|
||||||
'language': 'en-US',
|
'language': 'en-US',
|
||||||
'tts_input': 'No device or entity named test transcript',
|
'tts_input': "Sorry, I couldn't understand that",
|
||||||
'voice': 'james_earl_jones',
|
'voice': 'james_earl_jones',
|
||||||
}),
|
}),
|
||||||
'type': <PipelineEventType.TTS_START: 'tts-start'>,
|
'type': <PipelineEventType.TTS_START: 'tts-start'>,
|
||||||
|
@ -365,9 +365,9 @@
|
||||||
dict({
|
dict({
|
||||||
'data': dict({
|
'data': dict({
|
||||||
'tts_output': dict({
|
'tts_output': dict({
|
||||||
'media_id': 'media-source://tts/test?message=No+device+or+entity+named+test+transcript&language=en-US&voice=james_earl_jones',
|
'media_id': "media-source://tts/test?message=Sorry,+I+couldn't+understand+that&language=en-US&voice=james_earl_jones",
|
||||||
'mime_type': 'audio/mpeg',
|
'mime_type': 'audio/mpeg',
|
||||||
'url': '/api/tts_proxy/e5e8e318b536f0a5455f993243a34521e7ad4d6d_en-us_031e2ec052_test.mp3',
|
'url': '/api/tts_proxy/dae2cdcb27a1d1c3b07ba2c7db91480f9d4bfd8f_en-us_031e2ec052_test.mp3',
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
'type': <PipelineEventType.TTS_END: 'tts-end'>,
|
'type': <PipelineEventType.TTS_END: 'tts-end'>,
|
||||||
|
|
|
@ -46,14 +46,14 @@
|
||||||
'card': dict({
|
'card': dict({
|
||||||
}),
|
}),
|
||||||
'data': dict({
|
'data': dict({
|
||||||
'code': 'no_valid_targets',
|
'code': 'no_intent_match',
|
||||||
}),
|
}),
|
||||||
'language': 'en',
|
'language': 'en',
|
||||||
'response_type': 'error',
|
'response_type': 'error',
|
||||||
'speech': dict({
|
'speech': dict({
|
||||||
'plain': dict({
|
'plain': dict({
|
||||||
'extra_data': None,
|
'extra_data': None,
|
||||||
'speech': 'No device or entity named test transcript',
|
'speech': "Sorry, I couldn't understand that",
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
@ -64,16 +64,16 @@
|
||||||
dict({
|
dict({
|
||||||
'engine': 'test',
|
'engine': 'test',
|
||||||
'language': 'en-US',
|
'language': 'en-US',
|
||||||
'tts_input': 'No device or entity named test transcript',
|
'tts_input': "Sorry, I couldn't understand that",
|
||||||
'voice': 'james_earl_jones',
|
'voice': 'james_earl_jones',
|
||||||
})
|
})
|
||||||
# ---
|
# ---
|
||||||
# name: test_audio_pipeline.6
|
# name: test_audio_pipeline.6
|
||||||
dict({
|
dict({
|
||||||
'tts_output': dict({
|
'tts_output': dict({
|
||||||
'media_id': 'media-source://tts/test?message=No+device+or+entity+named+test+transcript&language=en-US&voice=james_earl_jones',
|
'media_id': "media-source://tts/test?message=Sorry,+I+couldn't+understand+that&language=en-US&voice=james_earl_jones",
|
||||||
'mime_type': 'audio/mpeg',
|
'mime_type': 'audio/mpeg',
|
||||||
'url': '/api/tts_proxy/e5e8e318b536f0a5455f993243a34521e7ad4d6d_en-us_031e2ec052_test.mp3',
|
'url': '/api/tts_proxy/dae2cdcb27a1d1c3b07ba2c7db91480f9d4bfd8f_en-us_031e2ec052_test.mp3',
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
# ---
|
# ---
|
||||||
|
@ -127,14 +127,14 @@
|
||||||
'card': dict({
|
'card': dict({
|
||||||
}),
|
}),
|
||||||
'data': dict({
|
'data': dict({
|
||||||
'code': 'no_valid_targets',
|
'code': 'no_intent_match',
|
||||||
}),
|
}),
|
||||||
'language': 'en',
|
'language': 'en',
|
||||||
'response_type': 'error',
|
'response_type': 'error',
|
||||||
'speech': dict({
|
'speech': dict({
|
||||||
'plain': dict({
|
'plain': dict({
|
||||||
'extra_data': None,
|
'extra_data': None,
|
||||||
'speech': 'No device or entity named test transcript',
|
'speech': "Sorry, I couldn't understand that",
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
@ -145,16 +145,16 @@
|
||||||
dict({
|
dict({
|
||||||
'engine': 'test',
|
'engine': 'test',
|
||||||
'language': 'en-US',
|
'language': 'en-US',
|
||||||
'tts_input': 'No device or entity named test transcript',
|
'tts_input': "Sorry, I couldn't understand that",
|
||||||
'voice': 'james_earl_jones',
|
'voice': 'james_earl_jones',
|
||||||
})
|
})
|
||||||
# ---
|
# ---
|
||||||
# name: test_audio_pipeline_debug.6
|
# name: test_audio_pipeline_debug.6
|
||||||
dict({
|
dict({
|
||||||
'tts_output': dict({
|
'tts_output': dict({
|
||||||
'media_id': 'media-source://tts/test?message=No+device+or+entity+named+test+transcript&language=en-US&voice=james_earl_jones',
|
'media_id': "media-source://tts/test?message=Sorry,+I+couldn't+understand+that&language=en-US&voice=james_earl_jones",
|
||||||
'mime_type': 'audio/mpeg',
|
'mime_type': 'audio/mpeg',
|
||||||
'url': '/api/tts_proxy/e5e8e318b536f0a5455f993243a34521e7ad4d6d_en-us_031e2ec052_test.mp3',
|
'url': '/api/tts_proxy/dae2cdcb27a1d1c3b07ba2c7db91480f9d4bfd8f_en-us_031e2ec052_test.mp3',
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
# ---
|
# ---
|
||||||
|
@ -220,14 +220,14 @@
|
||||||
'card': dict({
|
'card': dict({
|
||||||
}),
|
}),
|
||||||
'data': dict({
|
'data': dict({
|
||||||
'code': 'no_valid_targets',
|
'code': 'no_intent_match',
|
||||||
}),
|
}),
|
||||||
'language': 'en',
|
'language': 'en',
|
||||||
'response_type': 'error',
|
'response_type': 'error',
|
||||||
'speech': dict({
|
'speech': dict({
|
||||||
'plain': dict({
|
'plain': dict({
|
||||||
'extra_data': None,
|
'extra_data': None,
|
||||||
'speech': 'No device or entity named test transcript',
|
'speech': "Sorry, I couldn't understand that",
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
@ -238,16 +238,16 @@
|
||||||
dict({
|
dict({
|
||||||
'engine': 'test',
|
'engine': 'test',
|
||||||
'language': 'en-US',
|
'language': 'en-US',
|
||||||
'tts_input': 'No device or entity named test transcript',
|
'tts_input': "Sorry, I couldn't understand that",
|
||||||
'voice': 'james_earl_jones',
|
'voice': 'james_earl_jones',
|
||||||
})
|
})
|
||||||
# ---
|
# ---
|
||||||
# name: test_audio_pipeline_with_enhancements.6
|
# name: test_audio_pipeline_with_enhancements.6
|
||||||
dict({
|
dict({
|
||||||
'tts_output': dict({
|
'tts_output': dict({
|
||||||
'media_id': 'media-source://tts/test?message=No+device+or+entity+named+test+transcript&language=en-US&voice=james_earl_jones',
|
'media_id': "media-source://tts/test?message=Sorry,+I+couldn't+understand+that&language=en-US&voice=james_earl_jones",
|
||||||
'mime_type': 'audio/mpeg',
|
'mime_type': 'audio/mpeg',
|
||||||
'url': '/api/tts_proxy/e5e8e318b536f0a5455f993243a34521e7ad4d6d_en-us_031e2ec052_test.mp3',
|
'url': '/api/tts_proxy/dae2cdcb27a1d1c3b07ba2c7db91480f9d4bfd8f_en-us_031e2ec052_test.mp3',
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
# ---
|
# ---
|
||||||
|
@ -421,14 +421,14 @@
|
||||||
'card': dict({
|
'card': dict({
|
||||||
}),
|
}),
|
||||||
'data': dict({
|
'data': dict({
|
||||||
'code': 'no_valid_targets',
|
'code': 'no_intent_match',
|
||||||
}),
|
}),
|
||||||
'language': 'en',
|
'language': 'en',
|
||||||
'response_type': 'error',
|
'response_type': 'error',
|
||||||
'speech': dict({
|
'speech': dict({
|
||||||
'plain': dict({
|
'plain': dict({
|
||||||
'extra_data': None,
|
'extra_data': None,
|
||||||
'speech': 'No device or entity named test transcript',
|
'speech': "Sorry, I couldn't understand that",
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
@ -439,16 +439,16 @@
|
||||||
dict({
|
dict({
|
||||||
'engine': 'test',
|
'engine': 'test',
|
||||||
'language': 'en-US',
|
'language': 'en-US',
|
||||||
'tts_input': 'No device or entity named test transcript',
|
'tts_input': "Sorry, I couldn't understand that",
|
||||||
'voice': 'james_earl_jones',
|
'voice': 'james_earl_jones',
|
||||||
})
|
})
|
||||||
# ---
|
# ---
|
||||||
# name: test_audio_pipeline_with_wake_word_no_timeout.8
|
# name: test_audio_pipeline_with_wake_word_no_timeout.8
|
||||||
dict({
|
dict({
|
||||||
'tts_output': dict({
|
'tts_output': dict({
|
||||||
'media_id': 'media-source://tts/test?message=No+device+or+entity+named+test+transcript&language=en-US&voice=james_earl_jones',
|
'media_id': "media-source://tts/test?message=Sorry,+I+couldn't+understand+that&language=en-US&voice=james_earl_jones",
|
||||||
'mime_type': 'audio/mpeg',
|
'mime_type': 'audio/mpeg',
|
||||||
'url': '/api/tts_proxy/e5e8e318b536f0a5455f993243a34521e7ad4d6d_en-us_031e2ec052_test.mp3',
|
'url': '/api/tts_proxy/dae2cdcb27a1d1c3b07ba2c7db91480f9d4bfd8f_en-us_031e2ec052_test.mp3',
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
# ---
|
# ---
|
||||||
|
@ -778,7 +778,7 @@
|
||||||
'speech': dict({
|
'speech': dict({
|
||||||
'plain': dict({
|
'plain': dict({
|
||||||
'extra_data': None,
|
'extra_data': None,
|
||||||
'speech': 'No area named are',
|
'speech': 'Sorry, I am not aware of any area called are',
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -352,14 +352,14 @@
|
||||||
'card': dict({
|
'card': dict({
|
||||||
}),
|
}),
|
||||||
'data': dict({
|
'data': dict({
|
||||||
'code': 'no_valid_targets',
|
'code': 'no_intent_match',
|
||||||
}),
|
}),
|
||||||
'language': 'en',
|
'language': 'en',
|
||||||
'response_type': 'error',
|
'response_type': 'error',
|
||||||
'speech': dict({
|
'speech': dict({
|
||||||
'plain': dict({
|
'plain': dict({
|
||||||
'extra_data': None,
|
'extra_data': None,
|
||||||
'speech': 'No device or entity named do something',
|
'speech': "Sorry, I couldn't understand that",
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
@ -519,7 +519,7 @@
|
||||||
'speech': dict({
|
'speech': dict({
|
||||||
'plain': dict({
|
'plain': dict({
|
||||||
'extra_data': None,
|
'extra_data': None,
|
||||||
'speech': 'No device or entity named late added alias',
|
'speech': 'Sorry, I am not aware of any device or entity called late added alias',
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
@ -539,7 +539,7 @@
|
||||||
'speech': dict({
|
'speech': dict({
|
||||||
'plain': dict({
|
'plain': dict({
|
||||||
'extra_data': None,
|
'extra_data': None,
|
||||||
'speech': 'No device or entity named kitchen light',
|
'speech': 'Sorry, I am not aware of any device or entity called kitchen light',
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
@ -679,7 +679,7 @@
|
||||||
'speech': dict({
|
'speech': dict({
|
||||||
'plain': dict({
|
'plain': dict({
|
||||||
'extra_data': None,
|
'extra_data': None,
|
||||||
'speech': 'No device or entity named late added light',
|
'speech': 'Sorry, I am not aware of any device or entity called late added light',
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
@ -759,7 +759,7 @@
|
||||||
'speech': dict({
|
'speech': dict({
|
||||||
'plain': dict({
|
'plain': dict({
|
||||||
'extra_data': None,
|
'extra_data': None,
|
||||||
'speech': 'No device or entity named kitchen light',
|
'speech': 'Sorry, I am not aware of any device or entity called kitchen light',
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
@ -779,7 +779,7 @@
|
||||||
'speech': dict({
|
'speech': dict({
|
||||||
'plain': dict({
|
'plain': dict({
|
||||||
'extra_data': None,
|
'extra_data': None,
|
||||||
'speech': 'No device or entity named my cool light',
|
'speech': 'Sorry, I am not aware of any device or entity called my cool light',
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
@ -919,7 +919,7 @@
|
||||||
'speech': dict({
|
'speech': dict({
|
||||||
'plain': dict({
|
'plain': dict({
|
||||||
'extra_data': None,
|
'extra_data': None,
|
||||||
'speech': 'No device or entity named kitchen light',
|
'speech': 'Sorry, I am not aware of any device or entity called kitchen light',
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
@ -969,7 +969,7 @@
|
||||||
'speech': dict({
|
'speech': dict({
|
||||||
'plain': dict({
|
'plain': dict({
|
||||||
'extra_data': None,
|
'extra_data': None,
|
||||||
'speech': 'No device or entity named renamed light',
|
'speech': 'Sorry, I am not aware of any device or entity called renamed light',
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
@ -1252,14 +1252,14 @@
|
||||||
'card': dict({
|
'card': dict({
|
||||||
}),
|
}),
|
||||||
'data': dict({
|
'data': dict({
|
||||||
'code': 'no_valid_targets',
|
'code': 'no_intent_match',
|
||||||
}),
|
}),
|
||||||
'language': 'en',
|
'language': 'en',
|
||||||
'response_type': 'error',
|
'response_type': 'error',
|
||||||
'speech': dict({
|
'speech': dict({
|
||||||
'plain': dict({
|
'plain': dict({
|
||||||
'extra_data': None,
|
'extra_data': None,
|
||||||
'speech': 'No device or entity named test text',
|
'speech': "Sorry, I couldn't understand that",
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
@ -1292,14 +1292,14 @@
|
||||||
'card': dict({
|
'card': dict({
|
||||||
}),
|
}),
|
||||||
'data': dict({
|
'data': dict({
|
||||||
'code': 'no_valid_targets',
|
'code': 'no_intent_match',
|
||||||
}),
|
}),
|
||||||
'language': 'en',
|
'language': 'en',
|
||||||
'response_type': 'error',
|
'response_type': 'error',
|
||||||
'speech': dict({
|
'speech': dict({
|
||||||
'plain': dict({
|
'plain': dict({
|
||||||
'extra_data': None,
|
'extra_data': None,
|
||||||
'speech': 'No device or entity named test text',
|
'speech': "Sorry, I couldn't understand that",
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
@ -1312,14 +1312,14 @@
|
||||||
'card': dict({
|
'card': dict({
|
||||||
}),
|
}),
|
||||||
'data': dict({
|
'data': dict({
|
||||||
'code': 'no_valid_targets',
|
'code': 'no_intent_match',
|
||||||
}),
|
}),
|
||||||
'language': 'en',
|
'language': 'en',
|
||||||
'response_type': 'error',
|
'response_type': 'error',
|
||||||
'speech': dict({
|
'speech': dict({
|
||||||
'plain': dict({
|
'plain': dict({
|
||||||
'extra_data': None,
|
'extra_data': None,
|
||||||
'speech': 'No device or entity named test text',
|
'speech': "Sorry, I couldn't understand that",
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
@ -1352,14 +1352,14 @@
|
||||||
'card': dict({
|
'card': dict({
|
||||||
}),
|
}),
|
||||||
'data': dict({
|
'data': dict({
|
||||||
'code': 'no_valid_targets',
|
'code': 'no_intent_match',
|
||||||
}),
|
}),
|
||||||
'language': 'en',
|
'language': 'en',
|
||||||
'response_type': 'error',
|
'response_type': 'error',
|
||||||
'speech': dict({
|
'speech': dict({
|
||||||
'plain': dict({
|
'plain': dict({
|
||||||
'extra_data': None,
|
'extra_data': None,
|
||||||
'speech': 'No device or entity named test text',
|
'speech': "Sorry, I couldn't understand that",
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
|
@ -1510,29 +1510,7 @@
|
||||||
'unmatched_slots': dict({
|
'unmatched_slots': dict({
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
dict({
|
None,
|
||||||
'details': dict({
|
|
||||||
'domain': dict({
|
|
||||||
'name': 'domain',
|
|
||||||
'text': '',
|
|
||||||
'value': 'scene',
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
'intent': dict({
|
|
||||||
'name': 'HassTurnOn',
|
|
||||||
}),
|
|
||||||
'match': False,
|
|
||||||
'sentence_template': '[activate|<turn>] <name> [scene] [on]',
|
|
||||||
'slots': dict({
|
|
||||||
'domain': 'scene',
|
|
||||||
}),
|
|
||||||
'source': 'builtin',
|
|
||||||
'targets': dict({
|
|
||||||
}),
|
|
||||||
'unmatched_slots': dict({
|
|
||||||
'name': 'this will not match anything',
|
|
||||||
}),
|
|
||||||
}),
|
|
||||||
]),
|
]),
|
||||||
})
|
})
|
||||||
# ---
|
# ---
|
||||||
|
|
|
@ -147,8 +147,8 @@ async def test_conversation_agent(
|
||||||
conversation.HOME_ASSISTANT_AGENT
|
conversation.HOME_ASSISTANT_AGENT
|
||||||
)
|
)
|
||||||
with patch(
|
with patch(
|
||||||
"homeassistant.components.conversation.default_agent.get_domains_and_languages",
|
"homeassistant.components.conversation.default_agent.get_languages",
|
||||||
return_value={"homeassistant": ["dwarvish", "elvish", "entish"]},
|
return_value=["dwarvish", "elvish", "entish"],
|
||||||
):
|
):
|
||||||
assert agent.supported_languages == ["dwarvish", "elvish", "entish"]
|
assert agent.supported_languages == ["dwarvish", "elvish", "entish"]
|
||||||
|
|
||||||
|
@ -440,7 +440,7 @@ async def test_error_missing_entity(hass: HomeAssistant, init_components) -> Non
|
||||||
assert result.response.error_code == intent.IntentResponseErrorCode.NO_VALID_TARGETS
|
assert result.response.error_code == intent.IntentResponseErrorCode.NO_VALID_TARGETS
|
||||||
assert (
|
assert (
|
||||||
result.response.speech["plain"]["speech"]
|
result.response.speech["plain"]["speech"]
|
||||||
== "No device or entity named missing entity"
|
== "Sorry, I am not aware of any device or entity called missing entity"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -452,7 +452,10 @@ async def test_error_missing_area(hass: HomeAssistant, init_components) -> None:
|
||||||
|
|
||||||
assert result.response.response_type == intent.IntentResponseType.ERROR
|
assert result.response.response_type == intent.IntentResponseType.ERROR
|
||||||
assert result.response.error_code == intent.IntentResponseErrorCode.NO_VALID_TARGETS
|
assert result.response.error_code == intent.IntentResponseErrorCode.NO_VALID_TARGETS
|
||||||
assert result.response.speech["plain"]["speech"] == "No area named missing area"
|
assert (
|
||||||
|
result.response.speech["plain"]["speech"]
|
||||||
|
== "Sorry, I am not aware of any area called missing area"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def test_error_no_exposed_for_domain(
|
async def test_error_no_exposed_for_domain(
|
||||||
|
@ -467,7 +470,8 @@ async def test_error_no_exposed_for_domain(
|
||||||
assert result.response.response_type == intent.IntentResponseType.ERROR
|
assert result.response.response_type == intent.IntentResponseType.ERROR
|
||||||
assert result.response.error_code == intent.IntentResponseErrorCode.NO_VALID_TARGETS
|
assert result.response.error_code == intent.IntentResponseErrorCode.NO_VALID_TARGETS
|
||||||
assert (
|
assert (
|
||||||
result.response.speech["plain"]["speech"] == "kitchen does not contain a light"
|
result.response.speech["plain"]["speech"]
|
||||||
|
== "Sorry, I am not aware of any light in the kitchen area"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -483,7 +487,8 @@ async def test_error_no_exposed_for_device_class(
|
||||||
assert result.response.response_type == intent.IntentResponseType.ERROR
|
assert result.response.response_type == intent.IntentResponseType.ERROR
|
||||||
assert result.response.error_code == intent.IntentResponseErrorCode.NO_VALID_TARGETS
|
assert result.response.error_code == intent.IntentResponseErrorCode.NO_VALID_TARGETS
|
||||||
assert (
|
assert (
|
||||||
result.response.speech["plain"]["speech"] == "bedroom does not contain a window"
|
result.response.speech["plain"]["speech"]
|
||||||
|
== "Sorry, I am not aware of any window in the bedroom area"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -596,5 +601,5 @@ async def test_all_domains_loaded(
|
||||||
assert result.response.error_code == intent.IntentResponseErrorCode.NO_VALID_TARGETS
|
assert result.response.error_code == intent.IntentResponseErrorCode.NO_VALID_TARGETS
|
||||||
assert (
|
assert (
|
||||||
result.response.speech["plain"]["speech"]
|
result.response.speech["plain"]["speech"]
|
||||||
== "No device or entity named test light"
|
== "Sorry, I am not aware of any device or entity called test light"
|
||||||
)
|
)
|
||||||
|
|
|
@ -581,6 +581,7 @@ async def test_http_api_no_match(
|
||||||
|
|
||||||
assert data == snapshot
|
assert data == snapshot
|
||||||
assert data["response"]["response_type"] == "error"
|
assert data["response"]["response_type"] == "error"
|
||||||
|
assert data["response"]["data"]["code"] == "no_intent_match"
|
||||||
|
|
||||||
|
|
||||||
async def test_http_api_handle_failure(
|
async def test_http_api_handle_failure(
|
||||||
|
@ -738,6 +739,7 @@ async def test_ws_api(
|
||||||
|
|
||||||
assert msg["success"]
|
assert msg["success"]
|
||||||
assert msg["result"] == snapshot
|
assert msg["result"] == snapshot
|
||||||
|
assert msg["result"]["response"]["data"]["code"] == "no_intent_match"
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("agent_id", AGENT_ID_OPTIONS)
|
@pytest.mark.parametrize("agent_id", AGENT_ID_OPTIONS)
|
||||||
|
@ -1180,7 +1182,7 @@ async def test_ws_hass_agent_debug(
|
||||||
"turn my cool light off",
|
"turn my cool light off",
|
||||||
"turn on all lights in the kitchen",
|
"turn on all lights in the kitchen",
|
||||||
"how many lights are on in the kitchen?",
|
"how many lights are on in the kitchen?",
|
||||||
"this will not match anything", # unmatched in results
|
"this will not match anything", # None in results
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -1190,6 +1192,9 @@ async def test_ws_hass_agent_debug(
|
||||||
assert msg["success"]
|
assert msg["success"]
|
||||||
assert msg["result"] == snapshot
|
assert msg["result"] == snapshot
|
||||||
|
|
||||||
|
# Last sentence should be a failed match
|
||||||
|
assert msg["result"]["results"][-1] is None
|
||||||
|
|
||||||
# Light state should not have been changed
|
# Light state should not have been changed
|
||||||
assert len(on_calls) == 0
|
assert len(on_calls) == 0
|
||||||
assert len(off_calls) == 0
|
assert len(off_calls) == 0
|
||||||
|
|
Loading…
Reference in New Issue