1 """Support for the Google Cloud TTS service."""
3 from __future__
import annotations
6 from pathlib
import Path
7 from typing
import Any, cast
9 from google.api_core.exceptions
import GoogleAPIError, Unauthenticated
10 from google.cloud
import texttospeech
11 import voluptuous
as vol
15 PLATFORM_SCHEMA
as TTS_PLATFORM_SCHEMA,
34 CONF_SERVICE_ACCOUNT_INFO,
41 from .helpers
import async_tts_voices, tts_options_schema, tts_platform_schema
43 _LOGGER = logging.getLogger(__name__)
51 discovery_info: DiscoveryInfoType |
None =
None,
53 """Set up Google Cloud TTS component."""
54 if key_file := config.get(CONF_KEY_FILE):
55 key_file = hass.config.path(key_file)
56 if not Path(key_file).is_file():
57 _LOGGER.error(
"File %s doesn't exist", key_file)
60 client = texttospeech.TextToSpeechAsyncClient.from_service_account_file(
63 if not hass.config_entries.async_entries(DOMAIN):
64 _LOGGER.debug(
"Creating config entry by importing: %s", config)
65 hass.async_create_task(
66 hass.config_entries.flow.async_init(
67 DOMAIN, context={
"source": SOURCE_IMPORT}, data=config
71 client = texttospeech.TextToSpeechAsyncClient()
74 except GoogleAPIError
as err:
75 _LOGGER.error(
"Error from calling list_voices: %s", err)
80 config.get(CONF_LANG, DEFAULT_LANG),
87 config_entry: ConfigEntry,
88 async_add_entities: AddEntitiesCallback,
90 """Set up Google Cloud text-to-speech."""
91 service_account_info = config_entry.data[CONF_SERVICE_ACCOUNT_INFO]
92 client: texttospeech.TextToSpeechAsyncClient = (
93 texttospeech.TextToSpeechAsyncClient.from_service_account_info(
99 except GoogleAPIError
as err:
100 _LOGGER.error(
"Error from calling list_voices: %s", err)
101 if isinstance(err, Unauthenticated):
102 config_entry.async_start_reauth(hass)
105 language = config_entry.options.get(CONF_LANG, DEFAULT_LANG)
120 """The Google Cloud TTS base provider."""
124 client: texttospeech.TextToSpeechAsyncClient,
125 voices: dict[str, list[str]],
127 options_schema: vol.Schema,
129 """Init Google Cloud TTS base provider."""
137 """Return a list of supported languages."""
142 """Return the default language."""
147 """Return a list of supported options."""
148 return [option.schema
for option
in self.
_options_schema_options_schema.schema]
152 """Return a dict including default options."""
157 """Return a list of supported voices for a language."""
158 if not (voices := self.
_voices_voices.
get(language)):
160 return [Voice(voice, voice)
for voice
in voices]
166 options: dict[str, Any],
168 """Load TTS from Google Cloud."""
171 except vol.Invalid
as err:
172 _LOGGER.error(
"Error: %s when validating options: %s", err, options)
175 encoding: texttospeech.AudioEncoding = texttospeech.AudioEncoding[
176 options[CONF_ENCODING]
178 gender: texttospeech.SsmlVoiceGender |
None = texttospeech.SsmlVoiceGender[
181 voice = options[CONF_VOICE]
184 if not voice.startswith(language):
187 request = texttospeech.SynthesizeSpeechRequest(
188 input=texttospeech.SynthesisInput(**{options[CONF_TEXT_TYPE]: message}),
189 voice=texttospeech.VoiceSelectionParams(
190 language_code=language,
194 audio_config=texttospeech.AudioConfig(
195 audio_encoding=encoding,
196 speaking_rate=options[CONF_SPEED],
197 pitch=options[CONF_PITCH],
198 volume_gain_db=options[CONF_GAIN],
199 effects_profile_id=options[CONF_PROFILES],
203 response = await self.
_client_client.synthesize_speech(request, timeout=10)
205 if encoding == texttospeech.AudioEncoding.MP3:
207 elif encoding == texttospeech.AudioEncoding.OGG_OPUS:
212 return extension, response.audio_content
216 """The Google Cloud TTS entity."""
221 client: texttospeech.TextToSpeechAsyncClient,
222 voices: dict[str, list[str]],
224 options_schema: vol.Schema,
226 """Init Google Cloud TTS entity."""
227 super().
__init__(client, voices, language, options_schema)
231 identifiers={(DOMAIN, entry.entry_id)},
232 manufacturer=
"Google",
234 entry_type=dr.DeviceEntryType.SERVICE,
239 self, message: str, language: str, options: dict[str, Any]
241 """Load TTS from Google Cloud."""
244 except GoogleAPIError
as err:
245 _LOGGER.error(
"Error occurred during Google Cloud TTS call: %s", err)
246 if isinstance(err, Unauthenticated):
247 self.
_entry_entry.async_start_reauth(self.
hasshass)
252 """The Google Cloud TTS API provider."""
256 client: texttospeech.TextToSpeechAsyncClient,
257 voices: dict[str, list[str]],
259 options_schema: vol.Schema,
261 """Init Google Cloud TTS service."""
262 super().
__init__(client, voices, language, options_schema)
263 self.
namename =
"Google Cloud TTS"
266 self, message: str, language: str, options: dict[str, Any]
268 """Load TTS from Google Cloud."""
271 except GoogleAPIError
as err:
272 _LOGGER.error(
"Error occurred during Google Cloud TTS call: %s", err)
str default_language(self)
list[Voice]|None async_get_supported_voices(self, str language)
dict[str, Any] default_options(self)
TtsAudioType _async_get_tts_audio(self, str message, str language, dict[str, Any] options)
list[str] supported_options(self)
None __init__(self, texttospeech.TextToSpeechAsyncClient client, dict[str, list[str]] voices, str language, vol.Schema options_schema)
list[str] supported_languages(self)
TtsAudioType async_get_tts_audio(self, str message, str language, dict[str, Any] options)
None __init__(self, ConfigEntry entry, texttospeech.TextToSpeechAsyncClient client, dict[str, list[str]] voices, str language, vol.Schema options_schema)
TtsAudioType async_get_tts_audio(self, str message, str language, dict[str, Any] options)
None __init__(self, texttospeech.TextToSpeechAsyncClient client, dict[str, list[str]] voices, str language, vol.Schema options_schema)
web.Response get(self, web.Request request, str config_key)
dict[str, list[str]] async_tts_voices(texttospeech.TextToSpeechAsyncClient client)
vol.Schema tts_options_schema(Mapping[str, Any] config_options, dict[str, list[str]] voices, bool from_config_flow=False)
vol.Schema tts_platform_schema()
None async_setup_entry(HomeAssistant hass, ConfigEntry config_entry, AddEntitiesCallback async_add_entities)
Provider|None async_get_engine(HomeAssistant hass, ConfigType config, DiscoveryInfoType|None discovery_info=None)