Add preannounce_media_id to Assist Satellite (#141317)

Add preannounce_media_id
This commit is contained in:
Michael Hansen 2025-03-24 16:04:13 -05:00 committed by GitHub
parent 61a76b4064
commit 33198cd704
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 83 additions and 4 deletions

View File

@ -56,6 +56,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
{
vol.Optional("message"): str,
vol.Optional("media_id"): str,
vol.Optional("preannounce_media_id"): str,
}
),
cv.has_at_least_one_key("message", "media_id"),
@ -70,6 +71,7 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
{
vol.Optional("start_message"): str,
vol.Optional("start_media_id"): str,
vol.Optional("preannounce_media_id"): str,
vol.Optional("extra_system_prompt"): str,
}
),

View File

@ -101,6 +101,9 @@ class AssistSatelliteAnnouncement:
media_id_source: Literal["url", "media_id", "tts"]
"""Source of the media ID."""
preannounce_media_id: str | None = None
"""Media ID to be played before announcement."""
class AssistSatelliteEntity(entity.Entity):
"""Entity encapsulating the state and functionality of an Assist satellite."""
@ -177,6 +180,7 @@ class AssistSatelliteEntity(entity.Entity):
self,
message: str | None = None,
media_id: str | None = None,
preannounce_media_id: str | None = None,
) -> None:
"""Play and show an announcement on the satellite.
@ -186,6 +190,8 @@ class AssistSatelliteEntity(entity.Entity):
If media_id is provided, it is played directly. It is possible
to omit the message and the satellite will not show any text.
If preannounce_media_id is provided, it is played before the announcement.
Calls async_announce with message and media id.
"""
await self._cancel_running_pipeline()
@ -193,7 +199,9 @@ class AssistSatelliteEntity(entity.Entity):
if message is None:
message = ""
announcement = await self._resolve_announcement_media_id(message, media_id)
announcement = await self._resolve_announcement_media_id(
message, media_id, preannounce_media_id
)
if self._is_announcing:
raise SatelliteBusyError
@ -220,6 +228,7 @@ class AssistSatelliteEntity(entity.Entity):
start_message: str | None = None,
start_media_id: str | None = None,
extra_system_prompt: str | None = None,
preannounce_media_id: str | None = None,
) -> None:
"""Start a conversation from the satellite.
@ -229,6 +238,8 @@ class AssistSatelliteEntity(entity.Entity):
If start_media_id is provided, it is played directly. It is possible
to omit the message and the satellite will not show any text.
If preannounce_media_id is provided, it is played before the announcement.
Calls async_start_conversation.
"""
await self._cancel_running_pipeline()
@ -244,7 +255,7 @@ class AssistSatelliteEntity(entity.Entity):
start_message = ""
announcement = await self._resolve_announcement_media_id(
start_message, start_media_id
start_message, start_media_id, preannounce_media_id
)
if self._is_announcing:
@ -470,7 +481,10 @@ class AssistSatelliteEntity(entity.Entity):
return vad.VadSensitivity.to_seconds(vad_sensitivity)
async def _resolve_announcement_media_id(
self, message: str, media_id: str | None
self,
message: str,
media_id: str | None,
preannounce_media_id: str | None = None,
) -> AssistSatelliteAnnouncement:
"""Resolve the media ID."""
media_id_source: Literal["url", "media_id", "tts"] | None = None
@ -478,7 +492,6 @@ class AssistSatelliteEntity(entity.Entity):
if media_id:
original_media_id = media_id
else:
media_id_source = "tts"
# Synthesize audio and get URL
@ -530,10 +543,26 @@ class AssistSatelliteEntity(entity.Entity):
# Resolve to full URL
media_id = async_process_play_media_url(self.hass, media_id)
# Resolve preannounce media id
if preannounce_media_id:
if media_source.is_media_source_id(preannounce_media_id):
preannounce_media = await media_source.async_resolve_media(
self.hass,
preannounce_media_id,
None,
)
preannounce_media_id = preannounce_media.url
# Resolve to full URL
preannounce_media_id = async_process_play_media_url(
self.hass, preannounce_media_id
)
return AssistSatelliteAnnouncement(
message=message,
media_id=media_id,
original_media_id=original_media_id,
tts_token=tts_token,
media_id_source=media_id_source,
preannounce_media_id=preannounce_media_id,
)

View File

@ -14,6 +14,10 @@ announce:
required: false
selector:
text:
preannounce_media_id:
required: false
selector:
text:
start_conversation:
target:
entity:
@ -34,3 +38,7 @@ start_conversation:
required: false
selector:
text:
preannounce_media_id:
required: false
selector:
text:

View File

@ -23,6 +23,10 @@
"media_id": {
"name": "Media ID",
"description": "The media ID to announce instead of using text-to-speech."
},
"preannounce_media_id": {
"name": "Preannounce Media ID",
"description": "The media ID to play before the announcement."
}
}
},
@ -41,6 +45,10 @@
"extra_system_prompt": {
"name": "Extra system prompt",
"description": "Provide background information to the AI about the request."
},
"preannounce_media_id": {
"name": "Preannounce Media ID",
"description": "The media ID to play before the start message or media."
}
}
}

View File

@ -217,6 +217,20 @@ async def test_new_pipeline_cancels_pipeline(
media_id_source="url",
),
),
(
{
"media_id": "http://example.com/bla.mp3",
"preannounce_media_id": "http://example.com/preannounce.mp3",
},
AssistSatelliteAnnouncement(
message="",
media_id="http://example.com/bla.mp3",
original_media_id="http://example.com/bla.mp3",
tts_token=None,
media_id_source="url",
preannounce_media_id="http://example.com/preannounce.mp3",
),
),
],
)
async def test_announce(
@ -551,6 +565,24 @@ async def test_vad_sensitivity_entity_not_found(
),
),
),
(
{
"start_media_id": "http://example.com/given.mp3",
"preannounce_media_id": "http://example.com/preannounce.mp3",
},
(
"mock-conversation-id",
None,
AssistSatelliteAnnouncement(
message="",
media_id="http://example.com/given.mp3",
tts_token=None,
original_media_id="http://example.com/given.mp3",
media_id_source="url",
preannounce_media_id="http://example.com/preannounce.mp3",
),
),
),
],
)
@pytest.mark.usefixtures("mock_chat_session_conversation_id")