Load custom sentences from config directory (#85558)

* Load custom sentences from config directory

* Load custom sentences from config directory

* Custom sentences in custom_sentences/<language>/

* Load custom sentences from config directory

* Custom sentences in custom_sentences/<language>/

* Add custom_sentences test
This commit is contained in:
Michael Hansen 2023-01-09 16:48:59 -06:00 committed by GitHub
parent 6970a8a87a
commit 07bd208c7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 92 additions and 0 deletions

View File

@ -3,6 +3,7 @@ from __future__ import annotations
from dataclasses import dataclass from dataclasses import dataclass
import logging import logging
from pathlib import Path
import re import re
from typing import Any from typing import Any
@ -10,6 +11,7 @@ from hassil.intents import Intents, SlotList, TextSlotList
from hassil.recognize import recognize from hassil.recognize import recognize
from hassil.util import merge_dict from hassil.util import merge_dict
from home_assistant_intents import get_intents from home_assistant_intents import get_intents
import yaml
from homeassistant import core, setup from homeassistant import core, setup
from homeassistant.helpers import area_registry, entity_registry, intent from homeassistant.helpers import area_registry, entity_registry, intent
@ -147,6 +149,32 @@ class DefaultAgent(AbstractConversationAgent):
# Will need to recreate graph # Will need to recreate graph
intents_changed = True intents_changed = True
_LOGGER.debug(
"Loaded intents component=%s, language=%s", component, language
)
# Check for custom sentences in <config>/custom_sentences/<language>/
if lang_intents is None:
# Only load custom sentences once, otherwise they will be re-loaded
# when components change.
custom_sentences_dir = Path(
self.hass.config.path("custom_sentences", language)
)
if custom_sentences_dir.is_dir():
for custom_sentences_path in custom_sentences_dir.rglob("*.yaml"):
with custom_sentences_path.open(
encoding="utf-8"
) as custom_sentences_file:
# Merge custom sentences
merge_dict(intents_dict, yaml.safe_load(custom_sentences_file))
# Will need to recreate graph
intents_changed = True
_LOGGER.debug(
"Loaded custom sentences language=%s, path=%s",
language,
custom_sentences_path,
)
if not intents_dict: if not intents_dict:
return None return None

View File

@ -12,6 +12,19 @@ from homeassistant.setup import async_setup_component
from tests.common import async_mock_service from tests.common import async_mock_service
class OrderBeerIntentHandler(intent.IntentHandler):
"""Handle OrderBeer intent."""
intent_type = "OrderBeer"
async def async_handle(self, intent_obj: intent.Intent) -> intent.IntentResponse:
"""Return speech response."""
beer_style = intent_obj.slots["beer_style"]["value"]
response = intent_obj.create_response()
response.async_set_speech(f"You ordered a {beer_style}")
return response
@pytest.fixture @pytest.fixture
async def init_components(hass): async def init_components(hass):
"""Initialize relevant components with empty configs.""" """Initialize relevant components with empty configs."""
@ -314,3 +327,43 @@ async def test_ws_api(hass, hass_ws_client, payload):
}, },
"conversation_id": payload.get("conversation_id") or ANY, "conversation_id": payload.get("conversation_id") or ANY,
} }
async def test_custom_sentences(hass, hass_client, hass_admin_user):
"""Test custom sentences with a custom intent."""
assert await async_setup_component(hass, "homeassistant", {})
assert await async_setup_component(hass, "conversation", {})
assert await async_setup_component(hass, "intent", {})
# Expecting testing_config/custom_sentences/en/beer.yaml
intent.async_register(hass, OrderBeerIntentHandler())
# Invoke intent via HTTP API
client = await hass_client()
for beer_style in ("stout", "lager"):
resp = await client.post(
"/api/conversation/process",
json={"text": f"I'd like to order a {beer_style}, please"},
)
assert resp.status == HTTPStatus.OK
data = await resp.json()
assert data == {
"response": {
"card": {},
"speech": {
"plain": {
"extra_data": None,
"speech": f"You ordered a {beer_style}",
}
},
"language": hass.config.language,
"response_type": "action_done",
"data": {
"targets": [],
"success": [],
"failed": [],
},
},
"conversation_id": None,
}

View File

@ -0,0 +1,11 @@
language: "en"
intents:
OrderBeer:
data:
- sentences:
- "I'd like to order a {beer_style} [please]"
lists:
beer_style:
values:
- "stout"
- "lager"