|
12 | 12 | # See the License for the specific language governing permissions and |
13 | 13 | # limitations under the License. |
14 | 14 | # |
| 15 | +import json |
15 | 16 | import time |
| 17 | +from queue import Queue, Empty |
16 | 18 | from threading import Thread |
| 19 | + |
17 | 20 | import pyaudio |
18 | 21 | from pyee import EventEmitter |
| 22 | + |
19 | 23 | from mycroft.client.speech.hotword_factory import HotWordFactory |
20 | 24 | from mycroft.client.speech.mic import MutableMicrophone, ResponsiveRecognizer |
21 | 25 | from mycroft.configuration import Configuration |
22 | 26 | from mycroft.metrics import Stopwatch, report_timing |
23 | 27 | from mycroft.session import SessionManager |
24 | 28 | from mycroft.stt import STTFactory |
25 | | -from mycroft.util.log import LOG |
26 | 29 | from mycroft.util import find_input_device |
27 | | -from queue import Queue, Empty |
28 | | -import json |
| 30 | +from mycroft.util.log import LOG |
29 | 31 |
|
30 | 32 | MAX_MIC_RESTARTS = 20 |
31 | 33 |
|
@@ -195,7 +197,14 @@ def send_unknown_intent(): |
195 | 197 |
|
196 | 198 | try: |
197 | 199 | # Invoke the STT engine on the audio clip |
198 | | - text = self.loop.stt.execute(audio, language=lang) |
| 200 | + try: |
| 201 | + text = self.loop.stt.execute(audio, language=lang) |
| 202 | + except Exception as e: |
| 203 | + if self.loop.fallback_stt: |
| 204 | + LOG.warning(f"Using fallback STT, main plugin failed: {e}") |
| 205 | + text = self.loop.fallback_stt.execute(audio, language=lang) |
| 206 | + else: |
| 207 | + raise e |
199 | 208 | if text is not None: |
200 | 209 | text = text.lower().strip() |
201 | 210 | LOG.debug("STT: " + text) |
@@ -240,23 +249,25 @@ class RecognizerLoop(EventEmitter): |
240 | 249 | (optional, can be set later via self.bind ) |
241 | 250 | """ |
242 | 251 |
|
243 | | - def __init__(self, bus, watchdog=None, stt=None): |
| 252 | + def __init__(self, bus, watchdog=None, stt=None, fallback_stt=None): |
244 | 253 | super(RecognizerLoop, self).__init__() |
245 | 254 | self._watchdog = watchdog |
246 | 255 | self.mute_calls = 0 |
247 | 256 | self.stt = stt |
| 257 | + self.fallback_stt = fallback_stt |
248 | 258 | self.bus = bus |
249 | 259 | self.engines = {} |
250 | | - self.stt = None |
251 | 260 | self.queue = None |
252 | 261 | self.audio_consumer = None |
253 | 262 | self.audio_producer = None |
254 | 263 | self.responsive_recognizer = None |
255 | 264 |
|
256 | 265 | self._load_config() |
257 | 266 |
|
258 | | - def bind(self, stt): |
| 267 | + def bind(self, stt, fallback_stt=None): |
259 | 268 | self.stt = stt |
| 269 | + if fallback_stt: |
| 270 | + self.fallback_stt = fallback_stt |
260 | 271 |
|
261 | 272 | def _load_config(self): |
262 | 273 | """Load configuration parameters from configuration.""" |
@@ -325,6 +336,20 @@ def start_async(self): |
325 | 336 | self.state.running = True |
326 | 337 | if not self.stt: |
327 | 338 | self.stt = STTFactory.create() |
| 339 | + if not self.fallback_stt: |
| 340 | + stt_config = Configuration.get().get('stt', {}) |
| 341 | + engine = stt_config.get("fallback_module") |
| 342 | + if not engine: |
| 343 | + LOG.warning("No fallback STT configured") |
| 344 | + else: |
| 345 | + plugin_config = stt_config.get(engine) or {} |
| 346 | + plugin_config["lang"] = plugin_config.get("lang") or \ |
| 347 | + self.config_core.get("lang", "en-us") |
| 348 | + try: |
| 349 | + self.fallback_stt = STTFactory.create({"module": engine, |
| 350 | + engine: plugin_config}) |
| 351 | + except Exception as e: |
| 352 | + LOG.error(f"Failed to create fallback STT") |
328 | 353 | self.queue = Queue() |
329 | 354 | self.audio_consumer = AudioConsumer(self) |
330 | 355 | self.audio_consumer.start() |
|
0 commit comments