Skip to content
This repository has been archived by the owner on Sep 8, 2024. It is now read-only.

Fix audio service startup without Internet #2598

Merged
merged 1 commit into from
May 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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')