-
-
Save vessenes/111046b90c5d140ab5726a31ff70e903 to your computer and use it in GitHub Desktop.
| """ | |
| Support for the google speech service. | |
| For more details about this component, please refer to the documentation at | |
| https://home-assistant.io/components/tts.google/ | |
| Note - this is a hack. It makes no attempt to update tests. It does not have all wavenet voices listed. | |
| It attempts to respect language requests from hass but this has not been tested. | |
| Google cloud gives the first 1 million characters of wavenet generation for free per month, if you exceed | |
| that number they meter and charge. | |
| For this to work, you must have downloaded a provisioning key from google as detailed in this quickstart: | |
| https://cloud.google.com/text-to-speech/docs/quickstart-client-libraries | |
| Follow the instructions there, and make sure that you have the GOOGLE_APPLICATION_CREDENTIALS environment variable | |
| set properly before booting hass. | |
| """ | |
| import asyncio | |
| import logging | |
| import re | |
| import async_timeout | |
| import voluptuous as vol | |
| import yarl | |
| from homeassistant.components.tts import CONF_LANG, PLATFORM_SCHEMA, Provider | |
| from homeassistant.helpers.aiohttp_client import async_get_clientsession | |
| from google.cloud import texttospeech | |
| REQUIREMENTS = ['gTTS-token==1.1.3'] | |
| _LOGGER = logging.getLogger(__name__) | |
| GOOGLE_SPEECH_URL = "https://translate.google.com/translate_tts" | |
| MESSAGE_SIZE = 148 | |
| SUPPORT_LANGUAGES = [ | |
| 'af', 'sq', 'ar', 'hy', 'bn', 'ca', 'zh', 'zh-cn', 'zh-tw', 'zh-yue', | |
| 'hr', 'cs', 'da', 'nl', 'en', 'en-au', 'en-uk', 'en-us', 'eo', 'fi', | |
| 'fr', 'de', 'el', 'hi', 'hu', 'is', 'id', 'it', 'ja', 'ko', 'la', 'lv', | |
| 'mk', 'no', 'pl', 'pt', 'pt-br', 'ro', 'ru', 'sr', 'sk', 'es', 'es-es', | |
| 'es-mx', 'es-us', 'sw', 'sv', 'ta', 'th', 'tr', 'vi', 'cy', 'uk', 'bg-BG' | |
| ] | |
| DEFAULT_LANG = 'fr' | |
| WAVENET_LOOKUP = {'en': 'en-US-Wavenet-C', 'en-au': 'en-AU-Wavenet-A', | |
| 'en-uk': 'en-GB-Wavenet-A', 'fr': 'fr-FR-Wavenet-A', 'de': 'de-DE-Wavenet-A', | |
| 'it': 'it-IT-Wavenet-A', 'sv': 'sv-SE-Wavenet-A'} | |
| PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ | |
| vol.Optional(CONF_LANG, default=DEFAULT_LANG): vol.In(SUPPORT_LANGUAGES), | |
| }) | |
| async def async_get_engine(hass, config): | |
| """Set up Google speech component.""" | |
| return GoogleProvider(hass, config[CONF_LANG]) | |
| class GoogleProvider(Provider): | |
| """The Google speech API provider.""" | |
| def __init__(self, hass, lang): | |
| """Init Google TTS service.""" | |
| self.hass = hass | |
| self._lang = lang | |
| self.name = 'Google' | |
| self.client = texttospeech.TextToSpeechClient() | |
| if self._lang in WAVENET_LOOKUP: | |
| language_code = WAVENET_LOOKUP[self._lang] | |
| else: | |
| language_code = WAVENET_LOOKUP['fr'] | |
| self.voice = texttospeech.types.VoiceSelectionParams( | |
| language_code=language_code) | |
| self.audio_config = texttospeech.types.AudioConfig( | |
| audio_encoding=texttospeech.enums.AudioEncoding.MP3) | |
| @property | |
| def default_language(self): | |
| """Return the default language.""" | |
| return self._lang | |
| @property | |
| def supported_languages(self): | |
| """Return list of supported languages.""" | |
| return SUPPORT_LANGUAGES | |
| async def async_get_tts_audio(self, message, language, options=None): | |
| """Load TTS from google.""" | |
| synthesis_input = texttospeech.types.SynthesisInput(text=message) | |
| try: | |
| with async_timeout.timeout(10, loop=self.hass.loop): | |
| response = self.client.synthesize_speech( | |
| synthesis_input, | |
| self.voice, | |
| self.audio_config) | |
| return ("mp3", response.audio_content) | |
| except Exception as e: | |
| _LOGGER.error("Timeout for google speech. Or some other problem.", e) | |
| return (None, None) | |
| @staticmethod | |
| def _split_message_to_parts(message): | |
| """Split message into single parts.""" | |
| if len(message) <= MESSAGE_SIZE: | |
| return [message] | |
| punc = "!()[]?.,;:" | |
| punc_list = [re.escape(c) for c in punc] | |
| pattern = '|'.join(punc_list) | |
| parts = re.split(pattern, message) | |
| def split_by_space(fullstring): | |
| """Split a string by space.""" | |
| if len(fullstring) > MESSAGE_SIZE: | |
| idx = fullstring.rfind(' ', 0, MESSAGE_SIZE) | |
| return [fullstring[:idx]] + split_by_space(fullstring[idx:]) | |
| return [fullstring] | |
| msg_parts = [] | |
| for part in parts: | |
| msg_parts += split_by_space(part) | |
| return [msg for msg in msg_parts if len(msg) > 0] |
Looking to give this a try as the Wavenet voices are so much better. Do you know where I can set environment variables when using hassio inside docker? I set it inside the homeassistant container, but each restart starts a new container and the variable is lost.
Did you find a solution for this?
Did you find a solution for this?
I think you can just hardcode that:
import os
os.environ["GOOGLE_APPLICATION_CREDENTIALS"] = "your-key-path.json"
This works for me (with hardcoded app credentials) and is the best tts so far, so thanks!
One minor issue, I can't get it to change the voice. I'm trying to switch to "en-US-Wavenet-F" but it sounds like "en-US-Wavenet-D" is the default. I can see it's pinging the app console, and switching between languages works too, it's just not recognizing the name specified in WAVENET_LOOKUP.
Any hints?
It's only important because Wavenet-F sounds more like Janet 😄
Looking to give this a try as the Wavenet voices are so much better. Do you know where I can set environment variables when using hassio inside docker? I set it inside the homeassistant container, but each restart starts a new container and the variable is lost.