Add support to reprompt user (#65256)
parent
0cfc7112fa
commit
076faaa4a4
|
@ -166,7 +166,10 @@ async def async_handle_intent(hass, message):
|
|||
alexa_response.add_speech(
|
||||
alexa_speech, intent_response.speech[intent_speech]["speech"]
|
||||
)
|
||||
break
|
||||
if intent_speech in intent_response.reprompt:
|
||||
alexa_response.add_reprompt(
|
||||
alexa_speech, intent_response.reprompt[intent_speech]["reprompt"]
|
||||
)
|
||||
|
||||
if "simple" in intent_response.card:
|
||||
alexa_response.add_card(
|
||||
|
@ -267,10 +270,9 @@ class AlexaResponse:
|
|||
|
||||
key = "ssml" if speech_type == SpeechType.ssml else "text"
|
||||
|
||||
self.reprompt = {
|
||||
"type": speech_type.value,
|
||||
key: text.async_render(self.variables, parse_result=False),
|
||||
}
|
||||
self.should_end_session = False
|
||||
|
||||
self.reprompt = {"type": speech_type.value, key: text}
|
||||
|
||||
def as_dict(self):
|
||||
"""Return response in an Alexa valid dict."""
|
||||
|
|
|
@ -12,6 +12,7 @@ DOMAIN = "intent_script"
|
|||
|
||||
CONF_INTENTS = "intents"
|
||||
CONF_SPEECH = "speech"
|
||||
CONF_REPROMPT = "reprompt"
|
||||
|
||||
CONF_ACTION = "action"
|
||||
CONF_CARD = "card"
|
||||
|
@ -39,6 +40,10 @@ CONFIG_SCHEMA = vol.Schema(
|
|||
vol.Optional(CONF_TYPE, default="plain"): cv.string,
|
||||
vol.Required(CONF_TEXT): cv.template,
|
||||
},
|
||||
vol.Optional(CONF_REPROMPT): {
|
||||
vol.Optional(CONF_TYPE, default="plain"): cv.string,
|
||||
vol.Required(CONF_TEXT): cv.template,
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -72,6 +77,7 @@ class ScriptIntentHandler(intent.IntentHandler):
|
|||
async def async_handle(self, intent_obj):
|
||||
"""Handle the intent."""
|
||||
speech = self.config.get(CONF_SPEECH)
|
||||
reprompt = self.config.get(CONF_REPROMPT)
|
||||
card = self.config.get(CONF_CARD)
|
||||
action = self.config.get(CONF_ACTION)
|
||||
is_async_action = self.config.get(CONF_ASYNC_ACTION)
|
||||
|
@ -93,6 +99,12 @@ class ScriptIntentHandler(intent.IntentHandler):
|
|||
speech[CONF_TYPE],
|
||||
)
|
||||
|
||||
if reprompt is not None and reprompt[CONF_TEXT].template:
|
||||
response.async_set_reprompt(
|
||||
reprompt[CONF_TEXT].async_render(slots, parse_result=False),
|
||||
reprompt[CONF_TYPE],
|
||||
)
|
||||
|
||||
if card is not None:
|
||||
response.async_set_card(
|
||||
card[CONF_TITLE].async_render(slots, parse_result=False),
|
||||
|
|
|
@ -249,6 +249,7 @@ class IntentResponse:
|
|||
"""Initialize an IntentResponse."""
|
||||
self.intent = intent
|
||||
self.speech: dict[str, dict[str, Any]] = {}
|
||||
self.reprompt: dict[str, dict[str, Any]] = {}
|
||||
self.card: dict[str, dict[str, str]] = {}
|
||||
|
||||
@callback
|
||||
|
@ -258,14 +259,25 @@ class IntentResponse:
|
|||
"""Set speech response."""
|
||||
self.speech[speech_type] = {"speech": speech, "extra_data": extra_data}
|
||||
|
||||
@callback
|
||||
def async_set_reprompt(
|
||||
self, speech: str, speech_type: str = "plain", extra_data: Any | None = None
|
||||
) -> None:
|
||||
"""Set reprompt response."""
|
||||
self.reprompt[speech_type] = {"reprompt": speech, "extra_data": extra_data}
|
||||
|
||||
@callback
|
||||
def async_set_card(
|
||||
self, title: str, content: str, card_type: str = "simple"
|
||||
) -> None:
|
||||
"""Set speech response."""
|
||||
"""Set card response."""
|
||||
self.card[card_type] = {"title": title, "content": content}
|
||||
|
||||
@callback
|
||||
def as_dict(self) -> dict[str, dict[str, dict[str, Any]]]:
|
||||
"""Return a dictionary representation of an intent response."""
|
||||
return {"speech": self.speech, "card": self.card}
|
||||
return (
|
||||
{"speech": self.speech, "reprompt": self.reprompt, "card": self.card}
|
||||
if self.reprompt
|
||||
else {"speech": self.speech, "card": self.card}
|
||||
)
|
||||
|
|
|
@ -13,6 +13,9 @@ from homeassistant.setup import async_setup_component
|
|||
|
||||
SESSION_ID = "amzn1.echo-api.session.0000000-0000-0000-0000-00000000000"
|
||||
APPLICATION_ID = "amzn1.echo-sdk-ams.app.000000-d0ed-0000-ad00-000000d00ebe"
|
||||
APPLICATION_ID_SESSION_OPEN = (
|
||||
"amzn1.echo-sdk-ams.app.000000-d0ed-0000-ad00-000000d00ebf"
|
||||
)
|
||||
REQUEST_ID = "amzn1.echo-api.request.0000000-0000-0000-0000-00000000000"
|
||||
AUTHORITY_ID = "amzn1.er-authority.000000-d0ed-0000-ad00-000000d00ebe.ZODIAC"
|
||||
BUILTIN_AUTH_ID = "amzn1.er-authority.000000-d0ed-0000-ad00-000000d00ebe.TEST"
|
||||
|
@ -102,6 +105,16 @@ def alexa_client(loop, hass, hass_client):
|
|||
"text": "LaunchRequest has been received.",
|
||||
}
|
||||
},
|
||||
APPLICATION_ID_SESSION_OPEN: {
|
||||
"speech": {
|
||||
"type": "plain",
|
||||
"text": "LaunchRequest has been received.",
|
||||
},
|
||||
"reprompt": {
|
||||
"type": "plain",
|
||||
"text": "LaunchRequest has been received.",
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
)
|
||||
|
@ -139,6 +152,36 @@ async def test_intent_launch_request(alexa_client):
|
|||
data = await req.json()
|
||||
text = data.get("response", {}).get("outputSpeech", {}).get("text")
|
||||
assert text == "LaunchRequest has been received."
|
||||
assert data.get("response", {}).get("shouldEndSession")
|
||||
|
||||
|
||||
async def test_intent_launch_request_with_session_open(alexa_client):
|
||||
"""Test the launch of a request."""
|
||||
data = {
|
||||
"version": "1.0",
|
||||
"session": {
|
||||
"new": True,
|
||||
"sessionId": SESSION_ID,
|
||||
"application": {"applicationId": APPLICATION_ID_SESSION_OPEN},
|
||||
"attributes": {},
|
||||
"user": {"userId": "amzn1.account.AM3B00000000000000000000000"},
|
||||
},
|
||||
"request": {
|
||||
"type": "LaunchRequest",
|
||||
"requestId": REQUEST_ID,
|
||||
"timestamp": "2015-05-13T12:34:56Z",
|
||||
},
|
||||
}
|
||||
req = await _intent_req(alexa_client, data)
|
||||
assert req.status == HTTPStatus.OK
|
||||
data = await req.json()
|
||||
text = data.get("response", {}).get("outputSpeech", {}).get("text")
|
||||
assert text == "LaunchRequest has been received."
|
||||
text = (
|
||||
data.get("response", {}).get("reprompt", {}).get("outputSpeech", {}).get("text")
|
||||
)
|
||||
assert text == "LaunchRequest has been received."
|
||||
assert not data.get("response", {}).get("shouldEndSession")
|
||||
|
||||
|
||||
async def test_intent_launch_request_not_configured(alexa_client):
|
||||
|
|
|
@ -40,3 +40,48 @@ async def test_intent_script(hass):
|
|||
|
||||
assert response.card["simple"]["title"] == "Hello Paulus"
|
||||
assert response.card["simple"]["content"] == "Content for Paulus"
|
||||
|
||||
|
||||
async def test_intent_script_wait_response(hass):
|
||||
"""Test intent scripts work."""
|
||||
calls = async_mock_service(hass, "test", "service")
|
||||
|
||||
await async_setup_component(
|
||||
hass,
|
||||
"intent_script",
|
||||
{
|
||||
"intent_script": {
|
||||
"HelloWorldWaitResponse": {
|
||||
"action": {
|
||||
"service": "test.service",
|
||||
"data_template": {"hello": "{{ name }}"},
|
||||
},
|
||||
"card": {
|
||||
"title": "Hello {{ name }}",
|
||||
"content": "Content for {{ name }}",
|
||||
},
|
||||
"speech": {"text": "Good morning {{ name }}"},
|
||||
"reprompt": {
|
||||
"text": "I didn't hear you, {{ name }}... I said good morning!"
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
response = await intent.async_handle(
|
||||
hass, "test", "HelloWorldWaitResponse", {"name": {"value": "Paulus"}}
|
||||
)
|
||||
|
||||
assert len(calls) == 1
|
||||
assert calls[0].data["hello"] == "Paulus"
|
||||
|
||||
assert response.speech["plain"]["speech"] == "Good morning Paulus"
|
||||
|
||||
assert (
|
||||
response.reprompt["plain"]["reprompt"]
|
||||
== "I didn't hear you, Paulus... I said good morning!"
|
||||
)
|
||||
|
||||
assert response.card["simple"]["title"] == "Hello Paulus"
|
||||
assert response.card["simple"]["content"] == "Content for Paulus"
|
||||
|
|
Loading…
Reference in New Issue