From e6e9788ecda78d45a4ec5e7ff96ca4e3a7ebff06 Mon Sep 17 00:00:00 2001 From: Simon <80467011+sorgfresser@users.noreply.github.com> Date: Mon, 16 Dec 2024 18:18:09 +0000 Subject: [PATCH] Add quality scale to ElevenLabs (#133276) --- .../components/elevenlabs/__init__.py | 4 +- .../components/elevenlabs/config_flow.py | 12 +-- .../components/elevenlabs/quality_scale.yaml | 92 +++++++++++++++++++ homeassistant/components/elevenlabs/tts.py | 3 + script/hassfest/quality_scale.py | 1 - 5 files changed, 101 insertions(+), 11 deletions(-) create mode 100644 homeassistant/components/elevenlabs/quality_scale.yaml diff --git a/homeassistant/components/elevenlabs/__init__.py b/homeassistant/components/elevenlabs/__init__.py index db7a7f64c97..84b2b61b8ed 100644 --- a/homeassistant/components/elevenlabs/__init__.py +++ b/homeassistant/components/elevenlabs/__init__.py @@ -10,7 +10,7 @@ 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 homeassistant.exceptions import ConfigEntryAuthFailed, ConfigEntryError from homeassistant.helpers.httpx_client import get_async_client from .const import CONF_MODEL @@ -49,7 +49,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: EleventLabsConfigEntry) try: model = await get_model_by_id(client, model_id) except ApiError as err: - raise ConfigEntryError("Auth failed") from err + raise ConfigEntryAuthFailed("Auth failed") from err if model is None or (not model.languages): raise ConfigEntryError("Model could not be resolved") diff --git a/homeassistant/components/elevenlabs/config_flow.py b/homeassistant/components/elevenlabs/config_flow.py index 55cdd3ea944..60df79d6eaa 100644 --- a/homeassistant/components/elevenlabs/config_flow.py +++ b/homeassistant/components/elevenlabs/config_flow.py @@ -9,12 +9,7 @@ from elevenlabs import AsyncElevenLabs from elevenlabs.core import ApiError import voluptuous as vol -from homeassistant.config_entries import ( - ConfigEntry, - ConfigFlow, - ConfigFlowResult, - OptionsFlow, -) +from homeassistant.config_entries import ConfigFlow, ConfigFlowResult, OptionsFlow from homeassistant.const import CONF_API_KEY from homeassistant.core import HomeAssistant from homeassistant.helpers.httpx_client import get_async_client @@ -24,6 +19,7 @@ from homeassistant.helpers.selector import ( SelectSelectorConfig, ) +from . import EleventLabsConfigEntry from .const import ( CONF_CONFIGURE_VOICE, CONF_MODEL, @@ -96,7 +92,7 @@ class ElevenLabsConfigFlow(ConfigFlow, domain=DOMAIN): @staticmethod def async_get_options_flow( - config_entry: ConfigEntry, + config_entry: EleventLabsConfigEntry, ) -> OptionsFlow: """Create the options flow.""" return ElevenLabsOptionsFlow(config_entry) @@ -105,7 +101,7 @@ class ElevenLabsConfigFlow(ConfigFlow, domain=DOMAIN): class ElevenLabsOptionsFlow(OptionsFlow): """ElevenLabs options flow.""" - def __init__(self, config_entry: ConfigEntry) -> None: + def __init__(self, config_entry: EleventLabsConfigEntry) -> None: """Initialize options flow.""" self.api_key: str = config_entry.data[CONF_API_KEY] # id -> name diff --git a/homeassistant/components/elevenlabs/quality_scale.yaml b/homeassistant/components/elevenlabs/quality_scale.yaml new file mode 100644 index 00000000000..49f0d7518f5 --- /dev/null +++ b/homeassistant/components/elevenlabs/quality_scale.yaml @@ -0,0 +1,92 @@ +rules: + # Bronze + action-setup: + status: done + comment: > + Only entity services + appropriate-polling: done + brands: done + common-modules: done + config-flow-test-coverage: + status: todo + comment: > + We should have every test end in either ABORT or CREATE_ENTRY. + test_invalid_api_key should assert the kind of error that is raised. + config-flow: done + dependency-transparency: done + docs-actions: done + docs-high-level-description: done + docs-installation-instructions: done + docs-removal-instructions: todo + entity-event-setup: + status: exempt + comment: > + Entities of this integration does not explicitly subscribe to events. + entity-unique-id: done + has-entity-name: todo + runtime-data: done + test-before-configure: done + test-before-setup: done + unique-config-entry: todo + # Silver + config-entry-unloading: done + log-when-unavailable: todo + entity-unavailable: + status: exempt + comment: > + There is no state in the TTS platform and we can't check poll if the TTS service is available. + action-exceptions: done + reauthentication-flow: todo + parallel-updates: done + test-coverage: todo + integration-owner: done + docs-installation-parameters: todo + docs-configuration-parameters: todo + + # Gold + entity-translations: todo + entity-device-class: + status: exempt + comment: There is no device class for Text To Speech entities. + devices: done + entity-category: done + entity-disabled-by-default: todo + discovery: + status: exempt + comment: > + This is not possible because there is no physical device. + stale-devices: + status: exempt + comment: > + This is not possible because there is no physical device. + diagnostics: todo + exception-translations: todo + icon-translations: todo + reconfiguration-flow: + status: todo + comment: > + I imagine this could be useful if the default voice is deleted from voice lab. + dynamic-devices: + status: exempt + comment: | + This is not possible because there is no physical device. + discovery-update-info: + status: exempt + comment: > + This is not needed because there are no physical devices. + repair-issues: todo + docs-use-cases: done + docs-supported-devices: + status: exempt + comment: > + This integration does not support any devices. + docs-supported-functions: todo + docs-data-update: todo + docs-known-limitations: todo + docs-troubleshooting: todo + docs-examples: todo + + # Platinum + async-dependency: done + inject-websession: done + strict-typing: done diff --git a/homeassistant/components/elevenlabs/tts.py b/homeassistant/components/elevenlabs/tts.py index 8b016b6af8b..c96a7161b72 100644 --- a/homeassistant/components/elevenlabs/tts.py +++ b/homeassistant/components/elevenlabs/tts.py @@ -16,6 +16,7 @@ from homeassistant.components.tts import ( TtsAudioType, Voice, ) +from homeassistant.const import EntityCategory from homeassistant.core import HomeAssistant from homeassistant.exceptions import HomeAssistantError from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo @@ -38,6 +39,7 @@ from .const import ( ) _LOGGER = logging.getLogger(__name__) +PARALLEL_UPDATES = 0 def to_voice_settings(options: MappingProxyType[str, Any]) -> VoiceSettings: @@ -84,6 +86,7 @@ class ElevenLabsTTSEntity(TextToSpeechEntity): """The ElevenLabs API entity.""" _attr_supported_options = [ATTR_VOICE] + _attr_entity_category = EntityCategory.CONFIG def __init__( self, diff --git a/script/hassfest/quality_scale.py b/script/hassfest/quality_scale.py index 43b4adc90e9..5ad3467dd79 100644 --- a/script/hassfest/quality_scale.py +++ b/script/hassfest/quality_scale.py @@ -338,7 +338,6 @@ INTEGRATIONS_WITHOUT_QUALITY_SCALE_FILE = [ "eight_sleep", "electrasmart", "electric_kiwi", - "elevenlabs", "eliqonline", "elkm1", "elmax",