Get languages and voices from the API in Google Cloud TTS (#120852)

This commit is contained in:
tronikos 2024-07-05 11:03:06 -07:00 committed by GitHub
parent 178655647d
commit ad2d794fd6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 53 additions and 74 deletions

View file

@ -0,0 +1,19 @@
"""Helper classes for Google Cloud integration."""
from __future__ import annotations
from google.cloud import texttospeech
async def async_tts_voices(
client: texttospeech.TextToSpeechAsyncClient,
) -> dict[str, list[str]]:
"""Get TTS voice model names keyed by language."""
voices: dict[str, list[str]] = {}
list_voices_response = await client.list_voices()
for voice in list_voices_response.voices:
language_code = voice.language_codes[0]
if language_code not in voices:
voices[language_code] = []
voices[language_code].append(voice.name)
return voices

View file

@ -11,9 +11,13 @@ from homeassistant.components.tts import (
CONF_LANG,
PLATFORM_SCHEMA as TTS_PLATFORM_SCHEMA,
Provider,
Voice,
)
from homeassistant.core import HomeAssistant, callback
import homeassistant.helpers.config_validation as cv
from .helpers import async_tts_voices
_LOGGER = logging.getLogger(__name__)
CONF_KEY_FILE = "key_file"
@ -26,70 +30,12 @@ CONF_GAIN = "gain"
CONF_PROFILES = "profiles"
CONF_TEXT_TYPE = "text_type"
SUPPORTED_LANGUAGES = [
"af-ZA",
"ar-XA",
"bg-BG",
"bn-IN",
"ca-ES",
"cmn-CN",
"cmn-TW",
"cs-CZ",
"da-DK",
"de-DE",
"el-GR",
"en-AU",
"en-GB",
"en-IN",
"en-US",
"es-ES",
"es-US",
"eu-ES",
"fi-FI",
"fil-PH",
"fr-CA",
"fr-FR",
"gl-ES",
"gu-IN",
"he-IL",
"hi-IN",
"hu-HU",
"id-ID",
"is-IS",
"it-IT",
"ja-JP",
"kn-IN",
"ko-KR",
"lv-LV",
"lt-LT",
"ml-IN",
"mr-IN",
"ms-MY",
"nb-NO",
"nl-BE",
"nl-NL",
"pa-IN",
"pl-PL",
"pt-BR",
"pt-PT",
"ro-RO",
"ru-RU",
"sk-SK",
"sr-RS",
"sv-SE",
"ta-IN",
"te-IN",
"th-TH",
"tr-TR",
"uk-UA",
"vi-VN",
"yue-HK",
]
DEFAULT_LANG = "en-US"
DEFAULT_GENDER = "NEUTRAL"
VOICE_REGEX = r"[a-z]{2,3}-[A-Z]{2}-(Standard|Wavenet)-[A-Z]|"
LANG_REGEX = r"[a-z]{2,3}-[A-Z]{2}|"
VOICE_REGEX = r"[a-z]{2,3}-[A-Z]{2}-.*-[A-Z]|"
DEFAULT_VOICE = ""
DEFAULT_ENCODING = "MP3"
@ -143,7 +89,7 @@ TEXT_TYPE_SCHEMA = vol.All(vol.Lower, vol.In(SUPPORTED_TEXT_TYPES))
PLATFORM_SCHEMA = TTS_PLATFORM_SCHEMA.extend(
{
vol.Optional(CONF_KEY_FILE): cv.string,
vol.Optional(CONF_LANG, default=DEFAULT_LANG): vol.In(SUPPORTED_LANGUAGES),
vol.Optional(CONF_LANG, default=DEFAULT_LANG): cv.matches_regex(LANG_REGEX),
vol.Optional(CONF_GENDER, default=DEFAULT_GENDER): GENDER_SCHEMA,
vol.Optional(CONF_VOICE, default=DEFAULT_VOICE): VOICE_SCHEMA,
vol.Optional(CONF_ENCODING, default=DEFAULT_ENCODING): SCHEMA_ENCODING,
@ -163,10 +109,21 @@ async def async_get_engine(hass, config, discovery_info=None):
if not os.path.isfile(key_file):
_LOGGER.error("File %s doesn't exist", key_file)
return None
if key_file:
client = texttospeech.TextToSpeechAsyncClient.from_service_account_json(
key_file
)
else:
client = texttospeech.TextToSpeechAsyncClient()
try:
voices = await async_tts_voices(client)
except GoogleAPIError as err:
_LOGGER.error("Error from calling list_voices: %s", err)
return None
return GoogleCloudTTSProvider(
hass,
key_file,
client,
voices,
config[CONF_LANG],
config[CONF_GENDER],
config[CONF_VOICE],
@ -184,8 +141,9 @@ class GoogleCloudTTSProvider(Provider):
def __init__(
self,
hass,
key_file=None,
hass: HomeAssistant,
client: texttospeech.TextToSpeechAsyncClient,
voices: dict[str, list[str]],
language=DEFAULT_LANG,
gender=DEFAULT_GENDER,
voice=DEFAULT_VOICE,
@ -195,10 +153,12 @@ class GoogleCloudTTSProvider(Provider):
gain=0,
profiles=None,
text_type=DEFAULT_TEXT_TYPE,
):
) -> None:
"""Init Google Cloud TTS service."""
self.hass = hass
self.name = "Google Cloud TTS"
self._client = client
self._voices = voices
self._language = language
self._gender = gender
self._voice = voice
@ -209,17 +169,10 @@ class GoogleCloudTTSProvider(Provider):
self._profiles = profiles
self._text_type = text_type
if key_file:
self._client = (
texttospeech.TextToSpeechAsyncClient.from_service_account_json(key_file)
)
else:
self._client = texttospeech.TextToSpeechAsyncClient()
@property
def supported_languages(self):
"""Return list of supported languages."""
return SUPPORTED_LANGUAGES
return list(self._voices)
@property
def default_language(self):
@ -245,6 +198,13 @@ class GoogleCloudTTSProvider(Provider):
CONF_TEXT_TYPE: self._text_type,
}
@callback
def async_get_supported_voices(self, language: str) -> list[Voice] | None:
"""Return a list of supported voices for a language."""
if not (voices := self._voices.get(language)):
return None
return [Voice(voice, voice) for voice in voices]
async def async_get_tts_audio(self, message, language, options):
"""Load TTS from google."""
options_schema = vol.Schema(