Merge pull request #2718 from forslund/bugfix/mimic-missing-exceptions
Handle Mimic missing properlypull/2769/head
commit
b9c974bc1b
|
@ -134,17 +134,31 @@ def mute_and_speak(utterance, ident, listen=False):
|
|||
LOG.error('TTS execution failed ({})'.format(repr(e)))
|
||||
|
||||
|
||||
def mimic_fallback_tts(utterance, ident, listen):
|
||||
def _get_mimic_fallback():
|
||||
"""Lazily initializes the fallback TTS if needed."""
|
||||
global mimic_fallback_obj
|
||||
# fallback if connection is lost
|
||||
config = Configuration.get()
|
||||
tts_config = config.get('tts', {}).get("mimic", {})
|
||||
lang = config.get("lang", "en-us")
|
||||
if not mimic_fallback_obj:
|
||||
mimic_fallback_obj = Mimic(lang, tts_config)
|
||||
tts = mimic_fallback_obj
|
||||
config = Configuration.get()
|
||||
tts_config = config.get('tts', {}).get("mimic", {})
|
||||
lang = config.get("lang", "en-us")
|
||||
tts = Mimic(lang, tts_config)
|
||||
tts.validator.validate()
|
||||
tts.init(bus)
|
||||
mimic_fallback_obj = tts
|
||||
|
||||
return mimic_fallback_obj
|
||||
|
||||
|
||||
def mimic_fallback_tts(utterance, ident, listen):
|
||||
"""Speak utterance using fallback TTS if connection is lost.
|
||||
|
||||
Arguments:
|
||||
utterance (str): sentence to speak
|
||||
ident (str): interaction id for metrics
|
||||
listen (bool): True if interaction should end with mycroft listening
|
||||
"""
|
||||
tts = _get_mimic_fallback()
|
||||
LOG.debug("Mimic fallback, utterance : " + str(utterance))
|
||||
tts.init(bus)
|
||||
tts.execute(utterance, ident, listen)
|
||||
|
||||
|
||||
|
|
|
@ -12,15 +12,18 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
"""Mimic TTS, a local TTS backend.
|
||||
|
||||
This Backend uses the mimic executable to render text into speech.
|
||||
"""
|
||||
import os
|
||||
import os.path
|
||||
from os.path import exists, join, expanduser
|
||||
import stat
|
||||
import subprocess
|
||||
from threading import Thread
|
||||
from time import sleep
|
||||
|
||||
import os.path
|
||||
from os.path import exists, join, expanduser
|
||||
|
||||
from mycroft import MYCROFT_ROOT_PATH
|
||||
from mycroft.api import DeviceApi
|
||||
from mycroft.configuration import Configuration
|
||||
|
@ -54,8 +57,8 @@ def download_subscriber_voices(selected_voice):
|
|||
"""Call back function to make the downloaded file executable."""
|
||||
LOG.info('Make executable new voice binary executable')
|
||||
# make executable
|
||||
st = os.stat(dest)
|
||||
os.chmod(dest, st.st_mode | stat.S_IEXEC)
|
||||
file_stat = os.stat(dest)
|
||||
os.chmod(dest, file_stat.st_mode | stat.S_IEXEC)
|
||||
|
||||
# First download the selected voice if needed
|
||||
voice_file = SUBSCRIBER_VOICES.get(selected_voice)
|
||||
|
@ -64,9 +67,9 @@ def download_subscriber_voices(selected_voice):
|
|||
url = DeviceApi().get_subscriber_voice_url(selected_voice)
|
||||
# Check we got an url
|
||||
if url:
|
||||
dl = download(url, voice_file, make_executable)
|
||||
dl_status = download(url, voice_file, make_executable)
|
||||
# Wait for completion
|
||||
while not dl.done:
|
||||
while not dl_status.done:
|
||||
sleep(1)
|
||||
else:
|
||||
LOG.debug('{} is not available for this architecture'
|
||||
|
@ -79,9 +82,9 @@ def download_subscriber_voices(selected_voice):
|
|||
url = DeviceApi().get_subscriber_voice_url(voice)
|
||||
# Check we got an url
|
||||
if url:
|
||||
dl = download(url, voice_file, make_executable)
|
||||
dl_status = download(url, voice_file, make_executable)
|
||||
# Wait for completion
|
||||
while not dl.done:
|
||||
while not dl_status.done:
|
||||
sleep(1)
|
||||
else:
|
||||
LOG.debug('{} is not available for this architecture'
|
||||
|
@ -95,25 +98,26 @@ class Mimic(TTS):
|
|||
lang, config, MimicValidator(self), 'wav',
|
||||
ssml_tags=["speak", "ssml", "phoneme", "voice", "audio", "prosody"]
|
||||
)
|
||||
self.dl = None
|
||||
self.clear_cache()
|
||||
|
||||
# Download subscriber voices if needed
|
||||
self.is_subscriber = DeviceApi().is_subscriber
|
||||
if self.is_subscriber:
|
||||
t = Thread(target=download_subscriber_voices, args=[self.voice])
|
||||
t.daemon = True
|
||||
t.start()
|
||||
trd = Thread(target=download_subscriber_voices, args=[self.voice])
|
||||
trd.daemon = True
|
||||
trd.start()
|
||||
|
||||
def modify_tag(self, tag):
|
||||
for key, value in [
|
||||
('x-slow', '0.4'),
|
||||
('slow', '0.7'),
|
||||
('medium', '1.0'),
|
||||
('high', '1.3'),
|
||||
('x-high', '1.6'),
|
||||
('speed', 'rate')
|
||||
]:
|
||||
"""Modify the SSML to suite Mimic."""
|
||||
ssml_conversions = {
|
||||
'x-slow': '0.4',
|
||||
'slow': '0.7',
|
||||
'medium': '1.0',
|
||||
'high': '1.3',
|
||||
'x-high': '1.6',
|
||||
'speed': 'rate'
|
||||
}
|
||||
for key, value in ssml_conversions.items():
|
||||
tag = tag.replace(key, value)
|
||||
return tag
|
||||
|
||||
|
@ -175,22 +179,26 @@ class Mimic(TTS):
|
|||
|
||||
|
||||
class MimicValidator(TTSValidator):
|
||||
def __init__(self, tts):
|
||||
super(MimicValidator, self).__init__(tts)
|
||||
|
||||
"""Validator class checking that Mimic can be used."""
|
||||
def validate_lang(self):
|
||||
"""Verify that the language is supported."""
|
||||
# TODO: Verify version of mimic can handle the requested language
|
||||
pass
|
||||
|
||||
def validate_connection(self):
|
||||
"""Check that Mimic executable is found and works."""
|
||||
try:
|
||||
subprocess.call([BIN, '--version'])
|
||||
except Exception:
|
||||
LOG.info("Failed to find mimic at: " + BIN)
|
||||
except Exception as err:
|
||||
if BIN:
|
||||
LOG.error('Failed to find mimic at: {}'.format(BIN))
|
||||
else:
|
||||
LOG.error('Mimic executable not found')
|
||||
raise Exception(
|
||||
'Mimic was not found. Run install-mimic.sh to install it.')
|
||||
'Mimic was not found. Run install-mimic.sh to install it.') \
|
||||
from err
|
||||
|
||||
def get_tts_class(self):
|
||||
"""Return the TTS class associated with the validator."""
|
||||
return Mimic
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue