Skip to content

Commit

Permalink
Intents package combines sentences/responses per language (#109079)
Browse files Browse the repository at this point in the history
  • Loading branch information
synesthesiam committed Jan 30, 2024
1 parent a1f36c2 commit 9752e70
Show file tree
Hide file tree
Showing 10 changed files with 107 additions and 119 deletions.
52 changes: 26 additions & 26 deletions homeassistant/components/conversation/default_agent.py
Expand Up @@ -6,7 +6,6 @@
from collections.abc import Awaitable, Callable, Iterable
from dataclasses import dataclass
import functools
import itertools
import logging
from pathlib import Path
import re
Expand All @@ -28,7 +27,7 @@
recognize_all,
)
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

from homeassistant import core, setup
Expand Down Expand Up @@ -156,7 +155,7 @@ def __init__(self, hass: core.HomeAssistant) -> None:
@property
def supported_languages(self) -> list[str]:
"""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:
"""Initialize the default agent."""
Expand Down Expand Up @@ -387,27 +386,36 @@ def _recognize(
return maybe_result

# Try again with missing entities enabled
best_num_unmatched_entities = 0
for result in recognize_all(
user_input.text,
lang_intents.intents,
slot_lists=slot_lists,
intent_context=intent_context,
allow_unmatched_entities=True,
):
# Remove missing entities that couldn't be filled from context
for entity_key, entity in list(result.unmatched_entities.items()):
if isinstance(entity, UnmatchedTextEntity) and (
entity.text == MISSING_ENTITY
):
result.unmatched_entities.pop(entity_key)
if result.text_chunks_matched < 1:
# Skip results that don't match any literal text
continue

# Don't count missing entities that couldn't be filled from context
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:
# First 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
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 (
(result.text_chunks_matched == maybe_result.text_chunks_matched)
and ("name" in result.unmatched_entities) # prefer entities
Expand Down Expand Up @@ -536,14 +544,12 @@ def _get_or_load_intents(
intents_dict = lang_intents.intents_dict
language_variant = lang_intents.language_variant

domains_langs = get_domains_and_languages()
supported_langs = set(get_languages())

if not language_variant:
# Choose a language variant upfront and commit to it for custom
# sentences, etc.
all_language_variants = {
lang.lower(): lang for lang in itertools.chain(*domains_langs.values())
}
all_language_variants = {lang.lower(): lang for lang in supported_langs}

# en-US, en_US, en, ...
for maybe_variant in _get_language_variations(language):
Expand All @@ -558,23 +564,17 @@ def _get_or_load_intents(
)
return None

# Load intents for all domains supported by this language variant
for domain in domains_langs:
domain_intents = get_intents(
domain, language_variant, json_load=json_load
)

if not domain_intents:
continue
# Load intents for this language variant
lang_variant_intents = get_intents(language_variant, json_load=json_load)

if lang_variant_intents:
# Merge sentences into existing dictionary
merge_dict(intents_dict, domain_intents)
merge_dict(intents_dict, lang_variant_intents)

# Will need to recreate graph
intents_changed = True
_LOGGER.debug(
"Loaded intents domain=%s, language=%s (%s)",
domain,
"Loaded intents language=%s (%s)",
language,
language_variant,
)
Expand Down
2 changes: 1 addition & 1 deletion homeassistant/components/conversation/manifest.json
Expand Up @@ -7,5 +7,5 @@
"integration_type": "system",
"iot_class": "local_push",
"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"]
}
2 changes: 1 addition & 1 deletion homeassistant/package_constraints.txt
Expand Up @@ -29,7 +29,7 @@ hass-nabucasa==0.75.1
hassil==1.6.0
home-assistant-bluetooth==1.12.0
home-assistant-frontend==20240112.0
home-assistant-intents==2024.1.2
home-assistant-intents==2024.1.29
httpx==0.26.0
ifaddr==0.2.0
janus==1.0.0
Expand Down
2 changes: 1 addition & 1 deletion requirements_all.txt
Expand Up @@ -1056,7 +1056,7 @@ holidays==0.41
home-assistant-frontend==20240112.0

# homeassistant.components.conversation
home-assistant-intents==2024.1.2
home-assistant-intents==2024.1.29

# homeassistant.components.home_connect
homeconnect==0.7.2
Expand Down
2 changes: 1 addition & 1 deletion requirements_test_all.txt
Expand Up @@ -849,7 +849,7 @@ holidays==0.41
home-assistant-frontend==20240112.0

# homeassistant.components.conversation
home-assistant-intents==2024.1.2
home-assistant-intents==2024.1.29

# homeassistant.components.home_connect
homeconnect==0.7.2
Expand Down
40 changes: 20 additions & 20 deletions tests/components/assist_pipeline/snapshots/test_init.ambr
Expand Up @@ -48,14 +48,14 @@
'card': dict({
}),
'data': dict({
'code': 'no_valid_targets',
'code': 'no_intent_match',
}),
'language': 'en',
'response_type': 'error',
'speech': dict({
'plain': dict({
'extra_data': None,
'speech': 'No device or entity named test transcript',
'speech': "Sorry, I couldn't understand that",
}),
}),
}),
Expand All @@ -67,17 +67,17 @@
'data': dict({
'engine': 'test',
'language': 'en-US',
'tts_input': 'No device or entity named test transcript',
'tts_input': "Sorry, I couldn't understand that",
'voice': 'james_earl_jones',
}),
'type': <PipelineEventType.TTS_START: 'tts-start'>,
}),
dict({
'data': 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',
'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'>,
Expand Down Expand Up @@ -137,14 +137,14 @@
'card': dict({
}),
'data': dict({
'code': 'no_valid_targets',
'code': 'no_intent_match',
}),
'language': 'en-US',
'response_type': 'error',
'speech': dict({
'plain': dict({
'extra_data': None,
'speech': 'No device or entity named test transcript',
'speech': "Sorry, I couldn't understand that",
}),
}),
}),
Expand All @@ -156,17 +156,17 @@
'data': dict({
'engine': 'test',
'language': 'en-US',
'tts_input': 'No device or entity named test transcript',
'tts_input': "Sorry, I couldn't understand that",
'voice': 'Arnold Schwarzenegger',
}),
'type': <PipelineEventType.TTS_START: 'tts-start'>,
}),
dict({
'data': 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',
'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'>,
Expand Down Expand Up @@ -226,14 +226,14 @@
'card': dict({
}),
'data': dict({
'code': 'no_valid_targets',
'code': 'no_intent_match',
}),
'language': 'en-US',
'response_type': 'error',
'speech': dict({
'plain': dict({
'extra_data': None,
'speech': 'No device or entity named test transcript',
'speech': "Sorry, I couldn't understand that",
}),
}),
}),
Expand All @@ -245,17 +245,17 @@
'data': dict({
'engine': 'test',
'language': 'en-US',
'tts_input': 'No device or entity named test transcript',
'tts_input': "Sorry, I couldn't understand that",
'voice': 'Arnold Schwarzenegger',
}),
'type': <PipelineEventType.TTS_START: 'tts-start'>,
}),
dict({
'data': 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',
'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'>,
Expand Down Expand Up @@ -338,14 +338,14 @@
'card': dict({
}),
'data': dict({
'code': 'no_valid_targets',
'code': 'no_intent_match',
}),
'language': 'en',
'response_type': 'error',
'speech': dict({
'plain': dict({
'extra_data': None,
'speech': 'No device or entity named test transcript',
'speech': "Sorry, I couldn't understand that",
}),
}),
}),
Expand All @@ -357,17 +357,17 @@
'data': dict({
'engine': 'test',
'language': 'en-US',
'tts_input': 'No device or entity named test transcript',
'tts_input': "Sorry, I couldn't understand that",
'voice': 'james_earl_jones',
}),
'type': <PipelineEventType.TTS_START: 'tts-start'>,
}),
dict({
'data': 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',
'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'>,
Expand Down

0 comments on commit 9752e70

Please sign in to comment.