diff --git a/mycroft/client/speech/listener.py b/mycroft/client/speech/listener.py index 2d85ae05e4..7b8dfe9f27 100644 --- a/mycroft/client/speech/listener.py +++ b/mycroft/client/speech/listener.py @@ -402,7 +402,18 @@ class RecognizerLoop(EventEmitter): self.state.sleeping = False def run(self): - self.start_async() + """Start and reload mic and STT handling threads as needed. + + Wait for KeyboardInterrupt and shutdown cleanly. + """ + try: + self.start_async() + except Exception: + LOG.exception('Starting producer/consumer threads for listener ' + 'failed.') + return + + # Handle reload of consumer / producer if config changes while self.state.running: try: time.sleep(1) diff --git a/mycroft/client/speech/mic.py b/mycroft/client/speech/mic.py index d690093a40..db0e83f9d4 100644 --- a/mycroft/client/speech/mic.py +++ b/mycroft/client/speech/mic.py @@ -244,10 +244,25 @@ class ResponsiveRecognizer(speech_recognition.Recognizer): self.TEST_WW_SEC = num_phonemes * len_phoneme self.SAVED_WW_SEC = max(3, self.TEST_WW_SEC) - try: - self.account_id = DeviceApi().get()['user']['uuid'] - except (requests.RequestException, AttributeError): - self.account_id = '0' + self._account_id = None + + @property + def account_id(self): + """Fetch account from backend when needed. + + If an error occurs it's handled and a temporary value is returned. + When a value is received it will be cached until next start. + """ + if not self._account_id: + try: + self._account_id = DeviceApi().get()['user']['uuid'] + except (requests.RequestException, AttributeError): + pass # These are expected and won't be reported + except Exception as e: + LOG.debug('Unhandled exception while determining device_id, ' + 'Error: {}'.format(repr(e))) + + return self._account_id or '0' def record_sound_chunk(self, source): return source.stream.read(source.CHUNK, self.overflow_exc) diff --git a/mycroft/stt/__init__.py b/mycroft/stt/__init__.py index b1a7a5f806..9a6a93ea63 100644 --- a/mycroft/stt/__init__.py +++ b/mycroft/stt/__init__.py @@ -497,7 +497,17 @@ class STTFactory: @staticmethod def create(): - config = Configuration.get().get("stt", {}) - module = config.get("module", "mycroft") - clazz = STTFactory.CLASSES.get(module) - return clazz() + try: + config = Configuration.get().get("stt", {}) + module = config.get("module", "mycroft") + clazz = STTFactory.CLASSES.get(module) + return clazz() + except Exception as e: + # The STT backend failed to start. Report it and fall back to + # default. + LOG.exception('The selected STT backend could not be loaded, ' + 'falling back to default...') + if module != 'mycroft': + return MycroftSTT() + else: + raise