Michael Hansen e16f17f5a8
Voice assistant integration with pipelines (#89822)
* Initial commit

* Add websocket test tool

* Small tweak

* Tiny cleanup

* Make pipeline work with frontend branch

* Add some more info to start event

* Fixes

* First voice assistant tests

* Remove run_task

* Clean up for PR

* Add config_flow.py

* Remove CLI tool

* Simplify by removing stt/tts for now

* Clean up and fix tests

* More clean up and API changes

* Add quality_scale

* Remove data from run-finish

* Use StrEnum backport

---------

Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
2023-03-16 20:42:26 -04:00

68 lines
1.9 KiB
Python

"""Voice Assistant Websocket API."""
from typing import Any
import voluptuous as vol
from homeassistant.components import websocket_api
from homeassistant.core import HomeAssistant, callback
from .const import DOMAIN
from .pipeline import DEFAULT_TIMEOUT, PipelineRequest
@callback
def async_register_websocket_api(hass: HomeAssistant) -> None:
"""Register the websocket API."""
websocket_api.async_register_command(hass, websocket_run)
@websocket_api.websocket_command(
{
vol.Required("type"): "voice_assistant/run",
vol.Optional("pipeline", default="default"): str,
vol.Required("intent_input"): str,
vol.Optional("conversation_id"): vol.Any(str, None),
vol.Optional("timeout"): vol.Any(float, int),
}
)
@websocket_api.async_response
async def websocket_run(
hass: HomeAssistant,
connection: websocket_api.ActiveConnection,
msg: dict[str, Any],
) -> None:
"""Run a pipeline."""
pipeline_id = msg["pipeline"]
pipeline = hass.data[DOMAIN].get(pipeline_id)
if pipeline is None:
connection.send_error(
msg["id"], "pipeline_not_found", f"Pipeline not found: {pipeline_id}"
)
return
# Run pipeline with a timeout.
# Events are sent over the websocket connection.
timeout = msg.get("timeout", DEFAULT_TIMEOUT)
run_task = hass.async_create_task(
pipeline.run(
hass,
connection.context(msg),
request=PipelineRequest(
intent_input=msg["intent_input"],
conversation_id=msg.get("conversation_id"),
),
event_callback=lambda event: connection.send_event(
msg["id"], event.as_dict()
),
timeout=timeout,
)
)
# Cancel pipeline if user unsubscribes
connection.subscriptions[msg["id"]] = run_task.cancel
connection.send_result(msg["id"])
# Task contains a timeout
await run_task