diff --git a/custom_components/openai_whisper_cloud/__init__.py b/custom_components/openai_whisper_cloud/__init__.py index 4d8406e..7429a1e 100644 --- a/custom_components/openai_whisper_cloud/__init__.py +++ b/custom_components/openai_whisper_cloud/__init__.py @@ -1,22 +1,24 @@ """OpenAI Whisper Cloud integration.""" -import logging - from homeassistant.config_entries import ConfigEntry -from homeassistant.const import CONF_NAME, Platform +from homeassistant.const import ( + CONF_API_KEY, + CONF_MODEL, + CONF_NAME, + CONF_SOURCE, + Platform, +) from homeassistant.core import HomeAssistant -from .const import DEFAULT_NAME +from .const import _LOGGER, CONF_PROMPT, CONF_TEMPERATURE PLATFORMS = [Platform.STT] -_LOGGER = logging.getLogger(__name__) - async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Load entry.""" - _LOGGER.info("Setting up %s", entry) + _LOGGER.info("Setting up %s", entry.entry_id) await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) @@ -24,6 +26,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: return True + async def async_update_listener(hass: HomeAssistant, entry: ConfigEntry): """Update entry.""" await hass.config_entries.async_reload(entry.entry_id) @@ -34,26 +37,47 @@ async def async_update_listener(hass: HomeAssistant, entry: ConfigEntry): async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: """Unload a config entry.""" - _LOGGER.info("Unloading %s", entry) + _LOGGER.info("Unloading %s", entry.entry_id) return await hass.config_entries.async_unload_platforms(entry, PLATFORMS) + async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry): """Migrate old entry.""" - _LOGGER.debug("Migrating configuration from version %s.%s", config_entry.version, config_entry.minor_version) + _LOGGER.info( + f"Migration of {config_entry.entry_id} from version: {config_entry.version}.{config_entry.minor_version}" + ) if config_entry.version > 1: # This means the user has downgraded from a future version return False if config_entry.version == 0: - new_data = {**config_entry.data} - new_data[CONF_NAME] = DEFAULT_NAME + new_data[CONF_NAME] = "OpenAI Whisper" + + hass.config_entries.async_update_entry( + config_entry, data=new_data, minor_version=0, version=1 + ) + + if config_entry.version == 1 and config_entry.minor_version == 0: + new_data = { + CONF_SOURCE: 0, + CONF_NAME: config_entry.data[CONF_NAME], + CONF_API_KEY: config_entry.data[CONF_API_KEY], + } + + new_options = { + CONF_MODEL: 0, + CONF_TEMPERATURE: config_entry.data[CONF_TEMPERATURE], + CONF_PROMPT: config_entry.data[CONF_PROMPT], + } - hass.config_entries.async_update_entry(config_entry, data=new_data, minor_version=0, version=1) + hass.config_entries.async_update_entry( + config_entry, data=new_data, options=new_options, minor_version=1, version=1 + ) - _LOGGER.debug("Migration to configuration version %s.%s successful", config_entry.version, config_entry.minor_version) + _LOGGER.info(f"Migration of {config_entry.entry_id} successful") return True diff --git a/custom_components/openai_whisper_cloud/config_flow.py b/custom_components/openai_whisper_cloud/config_flow.py index 2eae53a..f1aa72d 100644 --- a/custom_components/openai_whisper_cloud/config_flow.py +++ b/custom_components/openai_whisper_cloud/config_flow.py @@ -9,38 +9,48 @@ import voluptuous as vol from homeassistant import exceptions -from homeassistant.config_entries import ConfigFlow, ConfigFlowResult -from homeassistant.const import CONF_API_KEY, CONF_MODEL, CONF_NAME +from homeassistant.config_entries import ( + ConfigEntry, + ConfigFlow, + ConfigFlowResult, + OptionsFlowWithConfigEntry, +) +from homeassistant.const import CONF_API_KEY, CONF_MODEL, CONF_NAME, CONF_SOURCE +from homeassistant.core import callback import homeassistant.helpers.config_validation as cv +from homeassistant.helpers.selector import ( + SelectOptionDict, + SelectSelector, + SelectSelectorConfig, + SelectSelectorMode, +) -from . import _LOGGER from .const import ( + _LOGGER, CONF_PROMPT, CONF_TEMPERATURE, - DEFAULT_NAME, DEFAULT_PROMPT, DEFAULT_TEMPERATURE, - DEFAULT_WHISPER_MODEL, DOMAIN, - SUPPORTED_MODELS, ) +from .whisper_provider import WhisperModel, WhisperProvider, whisper_providers -STEP_USER_DATA_SCHEMA = vol.Schema( +PROVIDER_SELECTION_SCHEMA = vol.Schema( { - vol.Required(CONF_NAME, default=DEFAULT_NAME): cv.string, - vol.Required(CONF_API_KEY): cv.string, - vol.Required(CONF_MODEL, default=DEFAULT_WHISPER_MODEL): vol.In( - SUPPORTED_MODELS - ), - vol.Optional(CONF_TEMPERATURE, default=DEFAULT_TEMPERATURE): vol.All( - vol.Coerce(float), vol.Range(min=0, max=1) + vol.Required(CONF_SOURCE, default="0"): SelectSelector( + SelectSelectorConfig( + options=[ + SelectOptionDict(value=str(i), label=p.name) + for i, p in enumerate(whisper_providers) + ], + mode=SelectSelectorMode.DROPDOWN, + ) ), - vol.Optional(CONF_PROMPT): cv.string, } ) -async def validate_input(data: dict): +async def validate_input(data: dict, provider: WhisperProvider): """Validate the user input.""" obscured_api_key = data.get(CONF_API_KEY) @@ -55,14 +65,16 @@ async def validate_input(data: dict): response = await asyncio.to_thread( requests.get, - url="https://api.openai.com/v1/models", - headers={ - "Authorization": f"Bearer {data.get(CONF_API_KEY)}", - "Content-Type": "application/json" - }, + url=f"{provider.url}/v1/models/{data.get(CONF_MODEL)}", + headers={"Authorization": f"Bearer {data.get(CONF_API_KEY)}"}, ) - _LOGGER.debug("Models request took %f s and returned %d - %s", response.elapsed.seconds, response.status_code, response.reason) + _LOGGER.debug( + "Models request took %f s and returned %d - %s", + response.elapsed.seconds, + response.status_code, + response.reason, + ) if response.status_code == 401: raise InvalidAPIKey @@ -70,103 +82,241 @@ async def validate_input(data: dict): if response.status_code == 403: raise UnauthorizedError + if response.status_code == 404: + raise WhisperModelNotFound + if response.status_code != 200: raise UnknownError - for model in response.json().get("data", []): - if model.get("id") == data.get(CONF_MODEL): - break - if model == response.json().get("data")[-1]: - raise WhisperModelBlocked - _LOGGER.debug("User validation successful") +class OptionsFlowHandler(OptionsFlowWithConfigEntry): + """Handle OpenAI Whisper Cloud options.""" + + config_entry: ConfigEntry + + async def async_step_init( + self, user_input: dict[str, Any] | None = None + ) -> ConfigFlowResult: + """Manage the OpenAI options.""" + + errors = {} + if user_input is not None: + return self.async_create_entry( + title=self.config_entry.title, + data={ + CONF_MODEL: [ + x.name + for x in whisper_providers[ + self.config_entry.data[CONF_SOURCE] + ].models + ].index(user_input[CONF_MODEL]), + CONF_TEMPERATURE: user_input[CONF_TEMPERATURE], + CONF_PROMPT: user_input.get(CONF_PROMPT, ""), + }, + ) + + return self.async_show_form( + step_id="init", + data_schema=self.add_suggested_values_to_schema( + data_schema=vol.Schema( + { + vol.Required(CONF_MODEL): vol.In( + [ + x.name + for x in whisper_providers[ + self.config_entry.data[CONF_SOURCE] + ].models + ] + ), + vol.Optional(CONF_TEMPERATURE): vol.All( + vol.Coerce(float), vol.Range(min=0, max=1) + ), + vol.Optional(CONF_PROMPT): cv.string, + } + ), + suggested_values={ + CONF_MODEL: whisper_providers[self.config_entry.data[CONF_SOURCE]] + .models[self.config_entry.options[CONF_MODEL]] + .name, + CONF_TEMPERATURE: self.config_entry.options[CONF_TEMPERATURE], + CONF_PROMPT: self.config_entry.options.get(CONF_PROMPT, ""), + }, + ), + errors=errors, + ) + + class ConfigFlow(ConfigFlow, domain=DOMAIN): """Handle UI config flow.""" VERSION = 1 - MINOR_VERSION = 0 + MINOR_VERSION = 1 + + _provider: WhisperProvider | None = None + + @staticmethod + @callback + def async_get_options_flow( + config_entry: ConfigEntry, + ) -> OptionsFlowHandler: + """Options callback for Reolink.""" + return OptionsFlowHandler(config_entry) async def async_step_user( self, user_input: dict[str, Any] | None = None, errors: dict[str, str] | None = None, + ) -> ConfigFlowResult: + """Handle initial step.""" + errors = {} + if user_input is not None: + self._provider = whisper_providers[int(user_input[CONF_SOURCE])] + return await self.async_step_whisper() + + return self.async_show_form( + step_id="user", data_schema=PROVIDER_SELECTION_SCHEMA, errors=errors + ) + + async def async_step_whisper( + self, + user_input: dict[str, Any] | None = None, + errors: dict[str, str] | None = None, ) -> ConfigFlowResult: """Handle initial step.""" errors = {} if user_input is not None: try: - await validate_input(user_input) + await validate_input(user_input, self._provider) return self.async_create_entry( - title=user_input.get(CONF_NAME, DEFAULT_NAME), data=user_input + title=user_input.get(CONF_NAME), + data={ + CONF_SOURCE: whisper_providers.index(self._provider), + CONF_NAME: user_input[CONF_NAME], + CONF_API_KEY: user_input[CONF_API_KEY], + }, + options={ + CONF_MODEL: [x.name for x in self._provider.models].index( + user_input[CONF_MODEL] + ), + CONF_TEMPERATURE: user_input[CONF_TEMPERATURE], + CONF_PROMPT: user_input.get(CONF_PROMPT, ""), + }, ) except requests.exceptions.RequestException as e: _LOGGER.error(e) errors["base"] = "connection_error" except UnauthorizedError: - _LOGGER.exception("Unauthorized") errors["base"] = "unauthorized" except InvalidAPIKey: - _LOGGER.exception("Invalid API key") errors[CONF_API_KEY] = "invalid_api_key" - except WhisperModelBlocked: - _LOGGER.exception("Whisper Model Not Found") - errors["base"] = "whisper_blocked" + except WhisperModelNotFound: + errors["base"] = "whisper_not_found" except UnknownError: - _LOGGER.exception("Unknown error") errors["base"] = "unknown" return self.async_show_form( - step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors + step_id="whisper", + data_schema=vol.Schema( + { + vol.Required( + CONF_NAME, default=f"{self._provider.name} Whisper" + ): cv.string, + vol.Required(CONF_API_KEY): cv.string, + vol.Required( + CONF_MODEL, + default=self._provider.models[ + self._provider.default_model + ].name, + ): vol.In([x.name for x in self._provider.models]), + vol.Optional( + CONF_TEMPERATURE, default=DEFAULT_TEMPERATURE + ): vol.All(vol.Coerce(float), vol.Range(min=0, max=1)), + vol.Optional(CONF_PROMPT): cv.string, + } + ), + errors=errors, ) - async def async_step_reconfigure(self, user_input: dict[str, Any] | None = None): - """Handle UI reconfiguration flow.""" + async def async_step_reconfigure( + self, + user_input: dict[str, Any] | None = None, + errors: dict[str, str] | None = None, + ): + """Config Flow reconfiguration.""" + errors = {} - config_entry = self.hass.config_entries.async_get_entry( - self.context["entry_id"] - ) - if not config_entry: - return self.async_abort(reason="reconfigure_failed") + entry = self.hass.config_entries.async_get_entry(self.context["entry_id"]) - suggested_values = user_input or config_entry.data + provider: WhisperProvider = whisper_providers[entry.data.get(CONF_SOURCE)] + whisper: WhisperModel = provider.models[entry.options.get(CONF_MODEL)] - errors = {} if user_input is not None: + if CONF_API_KEY not in user_input: + user_input[CONF_API_KEY] = entry.data.get(CONF_API_KEY) + try: - await validate_input(user_input) - - return self.async_update_reload_and_abort( - config_entry, - title=user_input.get(CONF_NAME, DEFAULT_NAME), - unique_id=config_entry.unique_id, - data=user_input, - reason="reconfigure_successful", + await validate_input(user_input, provider) + + self.hass.config_entries.async_update_entry( + entry=entry, + title=user_input[CONF_NAME], + data={ + CONF_SOURCE: entry.data.get(CONF_SOURCE), + CONF_NAME: user_input[CONF_NAME], + CONF_API_KEY: user_input.get(CONF_API_KEY), + }, + options={ + CONF_MODEL: [x.name for x in provider.models].index( + user_input[CONF_MODEL] + ), + CONF_TEMPERATURE: user_input[CONF_TEMPERATURE], + CONF_PROMPT: user_input.get(CONF_PROMPT, ""), + }, ) + await self.hass.config_entries.async_reload(self.context["entry_id"]) + return self.async_abort(reason="reconfigure_successful") except requests.exceptions.RequestException as e: _LOGGER.error(e) errors["base"] = "connection_error" except UnauthorizedError: - _LOGGER.exception("Unauthorized") errors["base"] = "unauthorized" except InvalidAPIKey: - _LOGGER.exception("Invalid API key") errors[CONF_API_KEY] = "invalid_api_key" - except WhisperModelBlocked: - _LOGGER.exception("Whisper Model Not Found") - errors["base"] = "whisper_blocked" + except WhisperModelNotFound: + errors["base"] = "whisper_not_found" except UnknownError: - _LOGGER.exception("Unknown error") errors["base"] = "unknown" return self.async_show_form( step_id="reconfigure", data_schema=self.add_suggested_values_to_schema( - data_schema=STEP_USER_DATA_SCHEMA, suggested_values=suggested_values + data_schema=vol.Schema( + { + vol.Required( + CONF_NAME, default=f"{provider.name} Whisper" + ): cv.string, + vol.Optional(CONF_API_KEY): cv.string, + vol.Required( + CONF_MODEL, + default=provider.models[provider.default_model].name, + ): vol.In([x.name for x in provider.models]), + vol.Optional( + CONF_TEMPERATURE, default=DEFAULT_TEMPERATURE + ): vol.All(vol.Coerce(float), vol.Range(min=0, max=1)), + vol.Optional(CONF_PROMPT): cv.string, + } + ), + suggested_values={ + CONF_NAME: entry.data.get(CONF_NAME), + CONF_MODEL: whisper.name, + CONF_TEMPERATURE: entry.options.get(CONF_TEMPERATURE), + CONF_PROMPT: entry.options.get(CONF_PROMPT), + }, ), errors=errors, ) @@ -184,5 +334,5 @@ class InvalidAPIKey(exceptions.HomeAssistantError): """Invalid api_key error.""" -class WhisperModelBlocked(exceptions.HomeAssistantError): - """Whisper not found in the available OpenAI models.""" +class WhisperModelNotFound(exceptions.HomeAssistantError): + """Whisper Model Not Found error.""" diff --git a/custom_components/openai_whisper_cloud/const.py b/custom_components/openai_whisper_cloud/const.py index e13a0ac..3c66cd3 100644 --- a/custom_components/openai_whisper_cloud/const.py +++ b/custom_components/openai_whisper_cloud/const.py @@ -1,14 +1,14 @@ """Constants for the OpenAI Whisper Cloud integration.""" +import logging + DOMAIN = "openai_whisper_cloud" +_LOGGER = logging.getLogger(__name__) + CONF_PROMPT = "prompt" CONF_TEMPERATURE = "temperature" -SUPPORTED_MODELS = [ - "whisper-1" -] - SUPPORTED_LANGUAGES = [ "af", "ar", @@ -69,7 +69,5 @@ "cy" ] -DEFAULT_NAME = "OpenAI Whisper" -DEFAULT_WHISPER_MODEL = SUPPORTED_MODELS[0] DEFAULT_PROMPT = "" DEFAULT_TEMPERATURE = 0 diff --git a/custom_components/openai_whisper_cloud/manifest.json b/custom_components/openai_whisper_cloud/manifest.json index 0b4e707..1eaca94 100644 --- a/custom_components/openai_whisper_cloud/manifest.json +++ b/custom_components/openai_whisper_cloud/manifest.json @@ -1,7 +1,7 @@ { "domain": "openai_whisper_cloud", "name": "OpenAI Whisper Cloud", - "version": "1.0.2", + "version": "1.1.0", "codeowners": [ "@fabio-garavini" ], diff --git a/custom_components/openai_whisper_cloud/stt.py b/custom_components/openai_whisper_cloud/stt.py index cb2d8b1..682a46a 100644 --- a/custom_components/openai_whisper_cloud/stt.py +++ b/custom_components/openai_whisper_cloud/stt.py @@ -21,11 +21,13 @@ SpeechToTextEntity, ) from homeassistant.config_entries import ConfigEntry +from homeassistant.const import CONF_API_KEY, CONF_MODEL, CONF_NAME, CONF_SOURCE from homeassistant.core import HomeAssistant from homeassistant.helpers.entity_platform import AddEntitiesCallback from . import _LOGGER -from .const import SUPPORTED_LANGUAGES +from .const import CONF_PROMPT, CONF_TEMPERATURE +from .whisper_provider import WhisperModel, whisper_providers async def async_setup_entry( @@ -34,17 +36,27 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up Demo speech platform via config entry.""" - _LOGGER.debug("Setup Entry %s", config_entry.entry_id) - async_add_entities( - [OpenAIWhisperCloudEntity(**config_entry.data, unique_id=config_entry.entry_id)] - ) + _LOGGER.debug(f"STT setup Entry {config_entry.entry_id}") + + async_add_entities([ + OpenAIWhisperCloudEntity( + api_url=whisper_providers[config_entry.data[CONF_SOURCE]].url, + api_key=config_entry.data[CONF_API_KEY], + model=whisper_providers[config_entry.data[CONF_SOURCE]].models[config_entry.options[CONF_MODEL]], + temperature=config_entry.options[CONF_TEMPERATURE], + prompt=config_entry.options[CONF_PROMPT], + name=config_entry.data[CONF_NAME], + unique_id=config_entry.entry_id + ) + ]) class OpenAIWhisperCloudEntity(SpeechToTextEntity): """OpenAI Whisper API provider entity.""" - def __init__(self, api_key, model, temperature, prompt, name, unique_id) -> None: + def __init__(self, api_url: str, api_key: str, model: WhisperModel, temperature, prompt, name, unique_id) -> None: """Init STT service.""" + self.api_url = api_url self.api_key = api_key self.model = model self.temperature = temperature @@ -55,7 +67,7 @@ def __init__(self, api_key, model, temperature, prompt, name, unique_id) -> None @property def supported_languages(self) -> list[str]: """Return a list of supported languages.""" - return SUPPORTED_LANGUAGES + return self.model.languages @property def supported_formats(self) -> list[AudioFormats]: @@ -130,17 +142,17 @@ async def async_process_audio_stream( # Prepare the data payload data = { - "model": self.model, + "model": self.model.name, "language": metadata.language, "temperature": self.temperature, "prompt": self.prompt, - "response_format": "json" + "response_format": "json", } # Make the request in a separate thread response = await asyncio.to_thread( requests.post, - "https://api.openai.com/v1/audio/transcriptions", + f"{self.api_url}/v1/audio/transcriptions", headers={ "Authorization": f"Bearer {self.api_key}", }, diff --git a/custom_components/openai_whisper_cloud/translations/en.json b/custom_components/openai_whisper_cloud/translations/en.json index eac9aeb..9619b19 100644 --- a/custom_components/openai_whisper_cloud/translations/en.json +++ b/custom_components/openai_whisper_cloud/translations/en.json @@ -8,31 +8,62 @@ "error": { "invalid_api_key": "Invalid API Key", "unauthorized": "Make sure your api key has READ permission to 'Models' and WRITE permission to 'Model capabilities'", - "whisper_blocked": "Whisper is blocked on your OpenAI project" + "whisper_not_found": "Whisper model not found" }, "step": { "user": { + "data": { + "source": "API Provider" + } + }, + "whisper": { "data": { "name": "Name", "api_key": "API key", "model": "Model", "temperature": "Temperature", - "prompt": "Prompt" + "prompt": "Prompt (Optional)" }, "data_description": { - "prompt": "Prompt can be used to improve speech recognition of words or even names. You have to provide a list of words or names separated by a comma \", \".\nExample: \"open, close, Chat GPT-3, DALL·E\"" + "prompt": "Prompt can be used to improve speech recognition of words or even names.\nou have to provide a list of words or names separated by a comma \", \".\nExample: \"open, close, Chat GPT-3, DALL·E\"" } }, "reconfigure": { "data": { "name": "Name", - "api_key": "API key", + "api_key": "API key (Optional)", + "model": "Model", + "temperature": "Temperature", + "prompt": "Prompt (Optional)" + }, + "data_description": { + "prompt": "Prompt can be used to improve speech recognition of words or even names.\nou have to provide a list of words or names separated by a comma \", \".\nExample: \"open, close, Chat GPT-3, DALL·E\"" + } + } + } + }, + "options": { + "abort": { + "already_configured": "Device is already configured", + "reconfigure_successful": "Reconfigured", + "reconfigure_failed": "Reconfiguration failed" + }, + "error": { + "invalid_api_key": "Invalid API Key", + "unauthorized": "Make sure your api key has READ permission to 'Models' and WRITE permission to 'Model capabilities'", + "whisper_not_found": "Whisper model not found" + }, + "step": { + "init": { + "data": { + "name": "Name", + "api_key": "API key (leave blank to keep existing)", "model": "Model", "temperature": "Temperature", - "prompt": "Prompt" + "prompt": "Prompt (Optional)" }, "data_description": { - "prompt": "Prompt can be used to improve speech recognition of words or even names. You have to provide a list of words or names separated by a comma \", \".\nExample: \"open, close, Chat GPT-3, DALL·E\"" + "prompt": "Prompt can be used to improve speech recognition of words or even names.\nYou have to provide a list of words or names separated by a comma \", \".\nExample: \"open, close, Chat GPT-3, DALL·E\"" } } } diff --git a/custom_components/openai_whisper_cloud/translations/it.json b/custom_components/openai_whisper_cloud/translations/it.json index 08605f3..a103427 100644 --- a/custom_components/openai_whisper_cloud/translations/it.json +++ b/custom_components/openai_whisper_cloud/translations/it.json @@ -8,28 +8,59 @@ "error": { "invalid_api_key": "Chiave API non valida", "unauthorized": "Assicurati che la tua chiave api abbia i permessi di READ su 'Models' e di WRITE su 'Model capabilities'", - "whisper_blocked": "Whisper e' bloccato sul tuo Progetto OpenAI" + "whisper_not_found": "Modello Whisper non trovato" }, "step": { "user": { + "data": { + "source": "API Provider" + } + }, + "whisper": { "data": { "name": "Nome", "api_key": "Chiave API", "model": "Modello", "temperature": "Temperatura", - "prompt": "Prompt" + "prompt": "Prompt (Opzionale)" }, "data_description": { "prompt": "Prompt puo' essere utilizzato per migliorare il riconoscimento di alcune parole o di nomi.\nFornisci una lista di parole o nomi separate da una virgola \", \".\nEsempio: \"accendi, spegni, Chat GPT-3, DALL·E\"" } }, "reconfigure": { + "data": { + "name": "Nome", + "api_key": "Chiave API (Optional)", + "model": "Modello", + "temperature": "Temperatura", + "prompt": "Prompt (Opzionale)" + }, + "data_description": { + "prompt": "Prompt puo' essere utilizzato per migliorare il riconoscimento di alcune parole o di nomi.\nFornisci una lista di parole o nomi separate da una virgola \", \".\nEsempio: \"accendi, spegni, Chat GPT-3, DALL·E\"" + } + } + } + }, + "options": { + "abort": { + "already_configured": "Dispositivo gia' configurato", + "reconfigure_successful": "Dispositivo riconfigurato", + "reconfigure_failed": "Riconfigurazione fallita" + }, + "error": { + "invalid_api_key": "Chiave API non valida", + "unauthorized": "Assicurati che la tua chiave api abbia i permessi di READ su 'Models' e di WRITE su 'Model capabilities'", + "whisper_not_found": "Modello Whisper non trovato" + }, + "step": { + "init": { "data": { "name": "Nome", "api_key": "Chiave API", "model": "Modello", "temperature": "Temperatura", - "prompt": "Prompt" + "prompt": "Prompt (Opzionale)" }, "data_description": { "prompt": "Prompt puo' essere utilizzato per migliorare il riconoscimento di alcune parole o di nomi.\nFornisci una lista di parole o nomi separate da una virgola \", \".\nEsempio: \"accendi, spegni, Chat GPT-3, DALL·E\"" diff --git a/custom_components/openai_whisper_cloud/whisper_provider.py b/custom_components/openai_whisper_cloud/whisper_provider.py new file mode 100644 index 0000000..cc4f76d --- /dev/null +++ b/custom_components/openai_whisper_cloud/whisper_provider.py @@ -0,0 +1,42 @@ +"""OpenAI Whisper API Providers.""" + +from .const import SUPPORTED_LANGUAGES + + +class WhisperModel: + """Whisper Model.""" + + def __init__(self, name: str, languages: list) -> None: + """Init.""" + self.name = name + self.languages = languages + + +class WhisperProvider: + """Whisper API Provider.""" + + def __init__(self, name: str, url: str, models: list, default_model: int) -> None: + """Init.""" + self.name = name + self.url = url + self.models = models + self.default_model = default_model + + +whisper_providers = [ + WhisperProvider( + "OpenAI", + "https://api.openai.com", + [ WhisperModel("whisper-1", SUPPORTED_LANGUAGES) ], + 0 + ), + WhisperProvider( + "GroqCloud", + "https://api.groq.com/openai", + [ + WhisperModel("whisper-large-v3", SUPPORTED_LANGUAGES), + WhisperModel("distil-whisper-large-v3-en", [ "en" ]) + ], + 0 + ), +]