16 from time
import sleep
23 from contextlib
import suppress
25 from os.path
import dirname, exists, join, abspath, expanduser, isfile, isdir
26 from petact
import install_package
27 from shutil
import rmtree
28 from threading
import Timer, Event, Thread
29 from urllib.error
import HTTPError
34 RECOGNIZER_DIR = join(abspath(dirname(__file__)),
"recognizer")
47 def __init__(self, key_phrase="hey mycroft", config=None, lang="en-us"):
52 config = Configuration.get().
get(
"hot_words", {})
56 self.
lang = str(self.config.get(
"lang", lang)).lower()
65 """ Perform any actions needed to shut down the hot word engine. 67 This may include things such as unload loaded data or shutdown 73 class PocketsphinxHotWord(HotWordEngine):
74 def __init__(self, key_phrase="hey mycroft", config=None, lang="en-us"):
75 super(PocketsphinxHotWord, self).
__init__(key_phrase, config, lang)
77 from pocketsphinx
import Decoder
79 self.
phonemes = self.config.get(
"phonemes",
"HH EY . M AY K R AO F T")
81 self.
threshold = self.config.get(
"threshold", 1e-90)
82 self.
sample_rate = self.listener_config.get(
"sample_rate", 1600)
84 config = self.
create_config(dict_name, Decoder.default_config())
88 (fd, file_name) = tempfile.mkstemp()
89 words = key_phrase.split()
90 phoneme_groups = phonemes.split(
'.')
91 with os.fdopen(fd,
'w')
as f:
92 for word, phoneme
in zip(words, phoneme_groups):
93 f.write(word +
' ' + phoneme +
'\n')
97 model_file = join(RECOGNIZER_DIR,
'model', self.
lang,
'hmm')
98 if not exists(model_file):
99 LOG.error(
'PocketSphinx model not found at ' + str(model_file))
100 config.set_string(
'-hmm', model_file)
101 config.set_string(
'-dict', dict_name)
102 config.set_string(
'-keyphrase', self.
key_phrase)
103 config.set_float(
'-kws_threshold', float(self.
threshold))
105 config.set_int(
'-nfft', 2048)
106 config.set_string(
'-logfn',
'/dev/null')
111 self.decoder.start_utt()
112 self.decoder.process_raw(byte_data,
False,
False)
113 self.decoder.end_utt()
115 metrics.timer(
"mycroft.stt.local.time_s", time.time() - start)
116 return self.decoder.hyp()
120 return hyp
and self.
key_phrase in hyp.hypstr.lower()
124 def __init__(self, key_phrase="hey mycroft", config=None, lang="en-us"):
125 super(PreciseHotword, self).
__init__(key_phrase, config, lang)
126 from precise_runner
import (
127 PreciseRunner, PreciseEngine, ReadWriteStream
129 local_conf = LocalConf(USER_CONFIG)
130 if local_conf.get(
'precise', {}).
get(
'dist_url') == \
131 'http://bootstrap.mycroft.ai/artifacts/static/daily/':
132 del local_conf[
'precise'][
'dist_url']
134 Configuration.updated(
None)
139 precise_config = Configuration.get()[
'precise']
140 precise_exe = self.
install_exe(precise_config[
'dist_url'])
142 local_model = self.config.get(
'local_model_file')
147 precise_config[
'model_url'], key_phrase.replace(
' ',
'-')
148 ).replace(
'.tar.gz',
'.pb')
156 trigger_level = self.config.get(
'trigger_level', 3)
157 sensitivity = self.config.get(
'sensitivity', 0.5)
161 trigger_level, sensitivity,
162 stream=self.
stream, on_activation=on_activation,
168 return join(expanduser(
'~'),
'.mycroft',
'precise')
171 url = url.format(arch=platform.machine())
172 if not url.endswith(
'.tar.gz'):
173 url = requests.get(url).text.strip()
179 return join(self.
folder,
'precise-engine',
'precise-engine')
182 model_url = url.format(wake_word=wake_word)
183 model_file = join(self.
folder, posixpath.basename(model_url))
187 on_download=
lambda: LOG.info(
'Updated precise model')
189 except (HTTPError, ValueError):
190 if isfile(model_file):
191 LOG.info(
"Couldn't find remote model. Using local file")
198 with suppress(OSError):
199 with open(
'/dev/ttyAMA0',
'w')
as f:
203 LOG.info(
'Downloading Precise executable...')
204 if isdir(join(self.
folder,
'precise-stream')):
205 rmtree(join(self.
folder,
'precise-stream'))
206 for old_package
in glob(join(self.
folder,
'precise-engine_*.tar.gz')):
207 os.remove(old_package)
212 self.show_download_progress.start()
215 LOG.info(
'Still downloading executable...')
217 self.
_snd_msg(
'mouth.text=Updating listener...')
220 self.show_download_progress.start()
223 LOG.info(
'Precise download complete!')
225 self.show_download_progress.cancel()
229 self.stream.write(chunk)
243 def __init__(self, key_phrase="hey mycroft", config=None, lang="en-us"):
244 super(SnowboyHotWord, self).
__init__(key_phrase, config, lang)
246 from snowboydecoder
import HotwordDetector
248 module = self.config.get(
"module")
249 if module !=
"snowboy":
250 LOG.warning(module +
" module does not match with Hotword class " 253 models = self.config.get(
"models", {})
256 paths.append(models[key])
257 sensitivity = self.config.get(
"sensitivity", 0.5)
259 sensitivity=[sensitivity] * len(paths))
264 wake_word = self.snowboy.detector.RunDetection(frame_data)
265 return wake_word == 1
270 "pocketsphinx": PocketsphinxHotWord,
271 "precise": PreciseHotword,
272 "snowboy": SnowboyHotWord
277 LOG.info(
'Loading "{}" wake word via {}'.format(hotword, module))
282 nonlocal instance, complete
284 clazz = HotWordFactory.CLASSES[module]
285 instance = clazz(hotword, config, lang=lang)
286 except TriggerReload:
290 except NoModelAvailable:
291 LOG.warning(
'Could not found find model for {} on {}.'.format(
297 'Could not create hotword. Falling back to default.')
301 Thread(target=initialize, daemon=
True).start()
302 if not complete.wait(INIT_TIMEOUT):
303 LOG.info(
'{} is taking too long to load'.format(module))
309 lang=
"en-us", loop=
None):
311 config = Configuration.get()[
'hotwords']
312 config = config[hotword]
314 module = config.get(
"module",
"precise")
315 return cls.
load_module(module, hotword, config, lang, loop)
or \
316 cls.
load_module(
'pocketsphinx', hotword, config, lang, loop)
or \
def found_wake_word(self, frame_data)
def during_download(self, first_run=False)
def transcribe(self, byte_data, metrics=None)
def found_wake_word(self, frame_data)
def __init__(self, key_phrase="hey mycroft", config=None, lang="en-us")
def __init__(self, key_phrase="hey mycroft", config=None, lang="en-us")
def load_module(module, hotword, config, lang, loop)
def create_dict(self, key_phrase, phonemes)
def __init__(self, key_phrase="hey mycroft", config=None, lang="en-us")
def found_wake_word(self, frame_data)
def create_config(self, dict_name, config)
def found_wake_word(self, frame_data)
def __init__(self, key_phrase="hey mycroft", config=None, lang="en-us")
def get(phrase, lang=None, context=None)
def create_hotword(cls, hotword="hey mycroft", config=None, lang="en-us", loop=None)