hass-core/homeassistant/components/elevenlabs/__init__.py
Simon 5fefa606b6
Add ElevenLabs text-to-speech integration (#115645)
* Add ElevenLabs text-to-speech integration

* Remove commented out code

* Use model_id instead of model_name for elevenlabs api

* Apply suggestions from code review

Co-authored-by: Sid <27780930+autinerd@users.noreply.github.com>

* Use async client instead of sync

* Add ElevenLabs code owner

* Apply suggestions from code review

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>

* Set entity title to voice

* Rename to elevenlabs

* Apply suggestions from code review

Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>

* Allow multiple voices and options flow

* Sort default voice at beginning

* Rework config flow to include default model and reloading on options flow

* Add error to strings

* Add ElevenLabsData and suggestions from code review

* Shorten options and config flow

* Fix comments

* Fix comments

* Add wip

* Fix

* Cleanup

* Bump elevenlabs version

* Add data description

* Fix

---------

Co-authored-by: Sid <27780930+autinerd@users.noreply.github.com>
Co-authored-by: Paulus Schoutsen <paulus@home-assistant.io>
Co-authored-by: Michael Hansen <mike@rhasspy.org>
Co-authored-by: Joostlek <joostlek@outlook.com>
Co-authored-by: Marc Mueller <30130371+cdce8p@users.noreply.github.com>
2024-07-31 21:31:09 +02:00

71 lines
2.1 KiB
Python

"""The ElevenLabs text-to-speech integration."""
from __future__ import annotations
from dataclasses import dataclass
from elevenlabs import Model
from elevenlabs.client import AsyncElevenLabs
from elevenlabs.core import ApiError
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_API_KEY, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryError
from .const import CONF_MODEL
PLATFORMS: list[Platform] = [Platform.TTS]
async def get_model_by_id(client: AsyncElevenLabs, model_id: str) -> Model | None:
"""Get ElevenLabs model from their API by the model_id."""
models = await client.models.get_all()
for maybe_model in models:
if maybe_model.model_id == model_id:
return maybe_model
return None
@dataclass(kw_only=True, slots=True)
class ElevenLabsData:
"""ElevenLabs data type."""
client: AsyncElevenLabs
model: Model
type EleventLabsConfigEntry = ConfigEntry[ElevenLabsData]
async def async_setup_entry(hass: HomeAssistant, entry: EleventLabsConfigEntry) -> bool:
"""Set up ElevenLabs text-to-speech from a config entry."""
entry.add_update_listener(update_listener)
client = AsyncElevenLabs(api_key=entry.data[CONF_API_KEY])
model_id = entry.options[CONF_MODEL]
try:
model = await get_model_by_id(client, model_id)
except ApiError as err:
raise ConfigEntryError("Auth failed") from err
if model is None or (not model.languages):
raise ConfigEntryError("Model could not be resolved")
entry.runtime_data = ElevenLabsData(client=client, model=model)
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True
async def async_unload_entry(
hass: HomeAssistant, entry: EleventLabsConfigEntry
) -> bool:
"""Unload a config entry."""
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
async def update_listener(
hass: HomeAssistant, config_entry: EleventLabsConfigEntry
) -> None:
"""Handle options update."""
await hass.config_entries.async_reload(config_entry.entry_id)