mirror of
https://github.com/home-assistant/core.git
synced 2025-07-17 18:27:09 +00:00
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:
parent
6970a8a87a
commit
07bd208c7d
@ -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
|
||||||
|
@ -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,
|
||||||
|
}
|
||||||
|
11
tests/testing_config/custom_sentences/en/beer.yaml
Normal file
11
tests/testing_config/custom_sentences/en/beer.yaml
Normal 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"
|
Loading…
x
Reference in New Issue
Block a user