Skip to content

Commit

Permalink
Merge pull request #2598 from forslund/bugfix/audio-startup
Browse files Browse the repository at this point in the history
Fix audio service startup without Internet
  • Loading branch information
krisgesling committed May 28, 2020
2 parents a0cccd4 + 86a978f commit 97b1e0f
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 10 deletions.
83 changes: 74 additions & 9 deletions mycroft/tts/google_tts.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,84 @@

from .tts import TTS, TTSValidator

supported_langs = tts_langs()
from mycroft.util.log import LOG

# Live list of languages
# Cached list of supported languages (2020-05-27)
_default_langs = {'af': 'Afrikaans', 'sq': 'Albanian', 'ar': 'Arabic',
'hy': 'Armenian', 'bn': 'Bengali', 'bs': 'Bosnian',
'ca': 'Catalan', 'hr': 'Croatian', 'cs': 'Czech',
'da': 'Danish', 'nl': 'Dutch', 'en': 'English',
'eo': 'Esperanto', 'et': 'Estonian', 'tl': 'Filipino',
'fi': 'Finnish', 'fr': 'French', 'de': 'German',
'el': 'Greek', 'gu': 'Gujarati', 'hi': 'Hindi',
'hu': 'Hungarian', 'is': 'Icelandic', 'id': 'Indonesian',
'it': 'Italian', 'ja': 'Japanese', 'jw': 'Javanese',
'kn': 'Kannada', 'km': 'Khmer', 'ko': 'Korean',
'la': 'Latin', 'lv': 'Latvian', 'mk': 'Macedonian',
'ml': 'Malayalam', 'mr': 'Marathi',
'my': 'Myanmar (Burmese)', 'ne': 'Nepali',
'no': 'Norwegian', 'pl': 'Polish', 'pt': 'Portuguese',
'ro': 'Romanian', 'ru': 'Russian', 'sr': 'Serbian',
'si': 'Sinhala', 'sk': 'Slovak', 'es': 'Spanish',
'su': 'Sundanese', 'sw': 'Swahili', 'sv': 'Swedish',
'ta': 'Tamil', 'te': 'Telugu', 'th': 'Thai', 'tr': 'Turkish',
'uk': 'Ukrainian', 'ur': 'Urdu', 'vi': 'Vietnamese',
'cy': 'Welsh', 'zh-cn': 'Chinese (Mandarin/China)',
'zh-tw': 'Chinese (Mandarin/Taiwan)',
'en-us': 'English (US)', 'en-ca': 'English (Canada)',
'en-uk': 'English (UK)', 'en-gb': 'English (UK)',
'en-au': 'English (Australia)', 'en-gh': 'English (Ghana)',
'en-in': 'English (India)', 'en-ie': 'English (Ireland)',
'en-nz': 'English (New Zealand)',
'en-ng': 'English (Nigeria)',
'en-ph': 'English (Philippines)',
'en-za': 'English (South Africa)',
'en-tz': 'English (Tanzania)', 'fr-ca': 'French (Canada)',
'fr-fr': 'French (France)', 'pt-br': 'Portuguese (Brazil)',
'pt-pt': 'Portuguese (Portugal)', 'es-es': 'Spanish (Spain)',
'es-us': 'Spanish (United States)'
}


_supported_langs = None


def get_supported_langs():
"""Get dict of supported languages.
Tries to fetch remote list, if that fails a local cache will be used.
Returns:
(dict): Lang code to lang name map.
"""
global _supported_langs
if not _supported_langs:
try:
_supported_langs = tts_langs()
except Exception:
LOG.warning('Couldn\'t fetch upto date language codes')
return _supported_langs or _default_langs


class GoogleTTS(TTS):
"""Interface to google TTS."""
def __init__(self, lang, config):
if lang.lower() not in supported_langs and \
lang[:2].lower() in supported_langs:
lang = lang[:2]
self._google_lang = None
super(GoogleTTS, self).__init__(lang, config, GoogleTTSValidator(
self), 'mp3')

@property
def google_lang(self):
"""Property containing a converted language code suitable for gTTS."""
supported_langs = get_supported_langs()
if not self._google_lang:
if self.lang.lower() in supported_langs:
self._google_lang = self.lang.lower()
elif self.lang[:2].lower() in supported_langs:
self._google_lang = self.lang[:2]
return self._google_lang or self.lang.lower()

def get_tts(self, sentence, wav_file):
"""Fetch tts audio using gTTS.
Expand All @@ -38,7 +104,7 @@ def get_tts(self, sentence, wav_file):
Returns:
Tuple ((str) written file, None)
"""
tts = gTTS(text=sentence, lang=self.lang)
tts = gTTS(text=sentence, lang=self.google_lang)
tts.save(wav_file)
return (wav_file, None) # No phonemes

Expand All @@ -48,10 +114,9 @@ def __init__(self, tts):
super(GoogleTTSValidator, self).__init__(tts)

def validate_lang(self):
lang = self.tts.lang
if lang.lower() not in supported_langs:
raise ValueError("Language not supported by gTTS: {}"
.format(lang))
lang = self.tts.google_lang
if lang.lower() not in get_supported_langs():
raise ValueError("Language not supported by gTTS: {}".format(lang))

def validate_connection(self):
try:
Expand Down
13 changes: 12 additions & 1 deletion test/unittests/tts/test_google_tts.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from unittest import mock

from mycroft.tts.google_tts import GoogleTTS, GoogleTTSValidator
import mycroft.tts.google_tts as google_tts_mod


@mock.patch('mycroft.tts.google_tts.gTTS')
Expand All @@ -13,7 +14,7 @@ def test_get_tts(self, _, gtts_mock):
tts = GoogleTTS('en-US', {})
sentence = 'help me Obi-Wan Kenobi, you are my only hope'
mp3_file, vis = tts.get_tts(sentence, 'output.mp3')
gtts_mock.assert_called_with(text=sentence, lang='en-US')
gtts_mock.assert_called_with(text=sentence, lang='en-us')
gtts_response.save.assert_called_with('output.mp3')

def test_validator(self, _, gtts_mock):
Expand All @@ -24,3 +25,13 @@ def sideeffect(**kwargs):
raise Exception
gtts_mock.side_effect = sideeffect
validator.validate_connection()

@mock.patch('mycroft.tts.google_tts.tts_langs')
def test_lang_connection_error(self, mock_get_langs, _, gtts_mock):
google_tts_mod._supported_langs = None

def sideeffect(**kwargs):
raise Exception
mock_get_langs.side_effect = sideeffect
tts = GoogleTTS('en-US', {})
self.assertEqual(tts.google_lang, 'en-us')

0 comments on commit 97b1e0f

Please sign in to comment.