16 from threading
import Thread
18 import speech_recognition
as sr
19 from pyee
import EventEmitter
20 from requests
import RequestException, HTTPError
21 from requests.exceptions
import ConnectionError
23 from mycroft
import dialog
33 from queue
import Queue, Empty
46 self.queue.put((STREAM_START,
None))
49 self.queue.put((STREAM_DATA, chunk))
52 self.queue.put((STREAM_STOP,
None))
58 given a mic and a recognizer implementation, continuously listens to the 59 mic for potential speech chunks and pushes them onto the queue. 62 def __init__(self, state, queue, mic, recognizer, emitter, stream_handler):
63 super(AudioProducer, self).
__init__()
73 with self.
mic as source:
74 self.recognizer.adjust_for_ambient_noise(source)
75 while self.state.running:
77 audio = self.recognizer.listen(source, self.
emitter,
79 self.queue.put((AUDIO_DATA, audio))
86 self.emitter.emit(
"recognizer_loop:ioerror", e)
89 self.stream_handler.stream_stop()
95 self.state.running =
False 96 self.recognizer.stop()
102 Consumes AudioData chunks off the queue 108 def __init__(self, state, queue, emitter, stt,
109 wakeup_recognizer, wakeword_recognizer):
110 super(AudioConsumer, self).
__init__()
121 while self.state.running:
126 message = self.queue.get(timeout=0.5)
135 if tag == AUDIO_DATA:
136 if self.state.sleeping:
140 elif tag == STREAM_START:
141 self.stt.stream_start()
142 elif tag == STREAM_DATA:
143 self.stt.stream_data(data)
144 elif tag == STREAM_STOP:
145 self.stt.stream_stop()
147 LOG.error(
"Unknown audio queue type %r" % message)
151 if self.wakeup_recognizer.found_wake_word(audio.frame_data):
152 SessionManager.touch()
153 self.state.sleeping =
False 154 self.emitter.emit(
'recognizer_loop:awoken')
155 self.metrics.increment(
"mycroft.wakeup")
159 return float(len(audio.frame_data)) / (
160 audio.sample_rate * audio.sample_width)
164 SessionManager.touch()
166 'utterance': self.wakeword_recognizer.key_phrase,
167 'session': SessionManager.get().session_id,
169 self.emitter.emit(
"recognizer_loop:wakeword", payload)
172 LOG.warning(
"Audio too short to be processed")
178 ident = str(stopwatch.timestamp) + str(hash(transcription))
181 'utterances': [transcription],
182 'lang': self.stt.lang,
183 'session': SessionManager.get().session_id,
186 self.emitter.emit(
"recognizer_loop:utterance", payload)
187 self.metrics.attr(
'utterances', [transcription])
189 ident = str(stopwatch.timestamp)
192 {
'transcription': transcription,
193 'stt': self.stt.__class__.__name__})
198 text = self.stt.execute(audio).lower().strip()
199 LOG.debug(
"STT: " + text)
201 except sr.RequestError
as e:
202 LOG.error(
"Could not request Speech Recognition {0}".format(e))
203 except ConnectionError
as e:
204 LOG.error(
"Connection Error: {0}".format(e))
206 self.emitter.emit(
"recognizer_loop:no_internet")
207 except HTTPError
as e:
208 if e.response.status_code == 401:
209 LOG.warning(
"Access Denied at mycroft.ai")
210 return "pair my device" 212 LOG.error(e.__class__.__name__ +
': ' + str(e))
213 except RequestException
as e:
214 LOG.error(e.__class__.__name__ +
': ' + str(e))
215 except Exception
as e:
216 self.emitter.emit(
'recognizer_loop:speech.recognition.unknown')
217 if isinstance(e, IndexError):
218 LOG.info(
'no words were transcribed')
221 LOG.error(
"Speech Recognition could not understand audio")
224 dialog_name =
'backend.down' 226 dialog_name =
'not connected to the internet' 227 self.emitter.emit(
'speak', {
'utterance': dialog.get(dialog_name)})
231 'utterance': utterance,
232 'session': SessionManager.get().session_id
234 self.emitter.emit(
"speak", payload)
245 EventEmitter loop running speech recognition. Local wake word 246 recognizer and remote general speech recognition. 250 super(RecognizerLoop, self).
__init__()
256 Load configuration parameters from configuration 258 config = Configuration.get()
263 rate = self.config.get(
'sample_rate')
265 device_index = self.config.get(
'device_index')
266 device_name = self.config.get(
'device_name')
267 if not device_index
and device_name:
270 LOG.debug(
'Using microphone (None = default): '+str(device_index))
284 LOG.info(
"creating wake word engine")
285 word = self.config.get(
"wake_word",
"hey mycroft")
287 phonemes = self.config.get(
"phonemes")
288 thresh = self.config.get(
"threshold")
289 config = self.config_core.get(
"hotwords", {word: {}})
291 if word
not in config:
292 config[word] = {
'module':
'precise'}
294 config[word][
"phonemes"] = phonemes
296 config[word][
"threshold"] = thresh
297 if phonemes
is None or thresh
is None:
299 return HotWordFactory.create_hotword(
300 word, config, self.
lang, loop=self
304 LOG.info(
"creating stand up word engine")
305 word = self.config.get(
"stand_up_word",
"wake up")
306 return HotWordFactory.create_hotword(word, lang=self.
lang, loop=self)
310 Start consumer and producer threads 312 self.state.running =
True 313 stt = STTFactory.create()
315 stream_handler =
None 321 self.producer.start()
325 self.consumer.start()
328 self.state.running =
False 336 Mute microphone and increase number of requests to mute 340 self.microphone.mute()
344 Unmute mic if as many unmute calls as mute calls have been 351 self.microphone.unmute()
356 Completely unmute mic regardless of the number of calls to mute 363 return self.microphone.is_muted()
368 self.state.sleeping =
True 371 self.state.sleeping =
False 375 while self.state.running:
379 str(Configuration().
get())):
380 LOG.debug(
'Config has changed, reloading...')
382 except KeyboardInterrupt
as e:
389 Reload configuration and restart consumer and producer 392 self.wakeword_recognizer.stop()
def report_timing(ident, system, timing, additional_data=None)
def find_input_device(device_name)
def stream_chunk(self, chunk)
def create_wakeup_recognizer(self)
def create_wake_word_recognizer(self)
def __speak(self, utterance)
def __init__(self, state, queue, mic, recognizer, emitter, stream_handler)
def __init__(self, queue)
def transcribe(self, audio)
def get(phrase, lang=None, context=None)
def __init__(self, state, queue, emitter, stt, wakeup_recognizer, wakeword_recognizer)