def download_skills(self, speak=False): """ Invoke MSM to install default skills and/or update installed skills Args: speak (bool, optional): Speak the result? Defaults to False """ # Don't invoke msm if already running if exists(MSM_BIN) and self.__msm_lock.acquire(): try: # Invoke the MSM script to do the hard work. LOG.debug("==== Invoking Mycroft Skill Manager: " + MSM_BIN) p = subprocess.Popen(MSM_BIN + " default", stderr=subprocess.STDOUT, stdout=subprocess.PIPE, shell=True) (output, err) = p.communicate() res = p.returncode # Always set next update to an hour from now if successful if res == 0: self.next_download = time.time() + 60 * MINUTES if res == 0 and speak: self.ws.emit( Message( "speak", {'utterance': dialog.get("skills updated")})) return True elif not connected(): LOG.error('msm failed, network connection not available') if speak: self.ws.emit( Message( "speak", { 'utterance': dialog.get("not connected to the internet") })) self.next_download = time.time() + 5 * MINUTES return False elif res != 0: LOG.error('msm failed with error {}: {}'.format( res, output)) if speak: self.ws.emit( Message( "speak", { 'utterance': dialog.get( "sorry I couldn't install default skills" ) })) self.next_download = time.time() + 5 * MINUTES return False finally: self.__msm_lock.release() else: LOG.error("Unable to invoke Mycroft Skill Manager: " + MSM_BIN)
def transcribe(self, audio): try: # Invoke the STT engine on the audio clip text = self.stt.execute(audio).lower().strip() LOG.debug("STT: " + text) return text except sr.RequestError as e: LOG.error("Could not request Speech Recognition {0}".format(e)) except ConnectionError as e: LOG.error("Connection Error: {0}".format(e)) self.emitter.emit("recognizer_loop:no_internet") except HTTPError as e: if e.response.status_code == 401: LOG.warning("Access Denied at mycroft.ai") return "pair my device" # phrase to start the pairing process else: LOG.error(e.__class__.__name__ + ': ' + str(e)) except RequestException as e: LOG.error(e.__class__.__name__ + ': ' + str(e)) except Exception as e: self.emitter.emit('recognizer_loop:speech.recognition.unknown') if isinstance(e, IndexError): LOG.info('no words were transcribed') else: LOG.error(e) LOG.error("Speech Recognition could not understand audio") return None if connected(): dialog_name = 'backend.down' else: dialog_name = 'not connected to the internet' self.emitter.emit('speak', {'utterance': dialog.get(dialog_name)})
def transcribe(self, audio): def send_unknown_intent(): """ Send message that nothing was transcribed. """ self.emitter.emit('recognizer_loop:speech.recognition.unknown') try: # Invoke the STT engine on the audio clip text = self.stt.execute(audio) if text is not None: text = text.lower().strip() LOG.debug("STT: " + text) else: send_unknown_intent() LOG.info('no words were transcribed') return text except sr.RequestError as e: LOG.error("Could not request Speech Recognition {0}".format(e)) except ConnectionError as e: LOG.error("Connection Error: {0}".format(e)) self.emitter.emit("recognizer_loop:no_internet") except RequestException as e: LOG.error(e.__class__.__name__ + ': ' + str(e)) except Exception as e: send_unknown_intent() LOG.error(e) LOG.error("Speech Recognition could not understand audio") return None if connected(): dialog_name = 'backend.down' else: dialog_name = 'not connected to the internet' self.emitter.emit('speak', {'utterance': dialog.get(dialog_name)})
def handle_complete_intent_failure(event): """Extreme backup for answering completely unhandled intent requests.""" LOG.info("Failed to find intent.") data = {'utterance': dialog.get('not.loaded')} context = {'client_name': 'mycroft_listener', 'source': 'audio'} bus.emit(Message('speak', data, context))
def transcribe(self, audio): try: # Invoke the STT engine on the audio clip text = self.stt.execute(audio).lower().strip() LOG.debug("STT: " + text) return text except sr.RequestError as e: LOG.error("Could not request Speech Recognition {0}".format(e)) except ConnectionError as e: LOG.error("Connection Error: {0}".format(e)) self.emitter.emit("recognizer_loop:no_internet") except HTTPError as e: if e.response.status_code == 401: LOG.warning("Access Denied at mycroft.ai") return "pair my device" # phrase to start the pairing process else: LOG.error(e.__class__.__name__ + ': ' + str(e)) except RequestException as e: LOG.error(e.__class__.__name__ + ': ' + str(e)) except Exception as e: self.emitter.emit('recognizer_loop:speech.recognition.unknown') if isinstance(e, IndexError): LOG.info('no words were transcribed') else: LOG.error(e) LOG.error("Speech Recognition could not understand audio") return None if connected(): dialog_name = 'backend.down' else: dialog_name = 'not connected to the internet' self.emitter.emit('speak', {'utterance': dialog.get(dialog_name)})
def test_get(self): phrase = 'i didn\'t catch that' res_file = pathlib.Path('text/en-us/').joinpath(phrase + '.dialog') print(res_file) resource = resolve_resource_file(str(res_file)) with open(resource) as f: results = [line.strip() for line in f] string = get(phrase) self.assertIn(string, results) # Check that the filename is returned if phrase is missing for lang string = get(phrase, lang='ne-ne') self.assertEqual(string, phrase) # Check that name is retured if phrase is missing string = get('testing aardwark') self.assertEqual(string, 'testing aardwark')
def test_get(self): phrase = 'i didn\'t catch that' res_file = pathlib.Path('text/en-us/').joinpath(phrase + '.dialog') print(res_file) resource = resolve_resource_file(str(res_file)) with open(resource) as f: results = [line.strip() for line in f] string = get(phrase) self.assertIn(string, results) # Check that the filename is returned if phrase is missing for lang string = get(phrase, lang='ne-ne') self.assertEqual(string, phrase) # Check that name is retured if phrase is missing string = get('testing aardwark') self.assertEqual(string, 'testing aardwark')
def on_error(e): """Speak and log the error.""" # Convert "MyFancySkill" to "My Fancy Skill" for speaking handler_name = camel_case_split(self.name) msg_data = {'skill': handler_name} msg = dialog.get('skill.error', self.lang, msg_data) self.speak(msg) LOG.exception(msg) # append exception information in message skill_data['exception'] = repr(e)
def schedule_update_skills(self, message=None): """ Schedule a skill update to take place directly. """ if direct_update_needed(): # Update skills at next opportunity LOG.info('Skills will be updated directly') self.schedule_now() # Skip the message when unpaired because the prompt to go # to home.mycrof.ai will be displayed by the pairing skill if not is_paired(): self.enclosure.mouth_text(dialog.get("message_updating")) else: LOG.info('Skills will be updated at a later time') self.next_download = time.time() + 60 * MINUTES
def on_error(e): """Speak and log the error.""" if not isinstance(e, AbortEvent): # Convert "MyFancySkill" to "My Fancy Skill" for speaking handler_name = camel_case_split(self.name) msg_data = {'skill': handler_name} msg = dialog.get('skill.error', self.lang, msg_data) self.speak(msg) LOG.exception(msg) else: LOG.info("Skill execution aborted") # append exception information in message skill_data['exception'] = repr(e)
def _update_system_clock(self): """Force a sync of the local clock with the Network Time Protocol. The NTP sync is only forced on Raspberry Pi based devices. The assumption being that these devices are only running Mycroft services. We don't want to sync the time on a Linux desktop device, for example, because it could have a negative impact on other software running on that device. """ if self.platform in RASPBERRY_PI_PLATFORMS: LOG.info('Updating the system clock via NTP...') if self.is_paired: # Only display time sync message when paired because the prompt # to go to home.mycroft.ai will be displayed by the pairing # skill when pairing self.enclosure.mouth_text(dialog.get("message_synching.clock")) self.bus.wait_for_response(Message('system.ntp.sync'), 'system.ntp.sync.complete', 15)
def wrapper(message): skill_data = {'name': get_handler_name(handler)} stopwatch = Stopwatch() try: message = unmunge_message(message, self.skill_id) # Indicate that the skill handler is starting if handler_info: # Indicate that the skill handler is starting if requested msg_type = handler_info + '.start' self.bus.emit(message.reply(msg_type, skill_data)) if once: # Remove registered one-time handler before invoking, # allowing them to re-schedule themselves. self.remove_event(name) with stopwatch: if len(signature(handler).parameters) == 0: handler() else: handler(message) self.settings.store() # Store settings if they've changed except Exception as e: # Convert "MyFancySkill" to "My Fancy Skill" for speaking handler_name = camel_case_split(self.name) msg_data = {'skill': handler_name} msg = dialog.get('skill.error', self.lang, msg_data) self.speak(msg) LOG.exception(msg) # append exception information in message skill_data['exception'] = repr(e) finally: # Indicate that the skill handler has completed if handler_info: msg_type = handler_info + '.complete' self.bus.emit(message.reply(msg_type, skill_data)) # Send timing metrics context = message.context if context and 'ident' in context: report_timing(context['ident'], 'skill_handler', stopwatch, {'handler': handler.__name__})
def _reboot(self): """If the NTP sync skewed system time significantly, reboot. If system time moved by over an hour in the NTP sync, force a reboot to prevent weird things from occurring due to the 'time warp'. """ LOG.warning( 'Clock sync altered system time by more than one hour,' ' rebooting...' ) self._speak_dialog(dialog_id="time.changed.reboot", wait=True) # provide visual indicators of the reboot self.enclosure.mouth_text(dialog.get("message_rebooting")) self.enclosure.eyes_color(70, 65, 69) # soft gray self.enclosure.eyes_spin() # give the system time to finish processing enclosure messages time.sleep(1.0) # reboot self.bus.emit(Message("system.reboot"))
def wrapper(message): skill_data = {'name': get_handler_name(handler)} stopwatch = Stopwatch() try: message = unmunge_message(message, self.skill_id) # Indicate that the skill handler is starting if handler_info: # Indicate that the skill handler is starting if requested msg_type = handler_info + '.start' self.emitter.emit(Message(msg_type, skill_data)) with stopwatch: is_bound = bool(getattr(handler, 'im_self', None)) num_args = len(getargspec(handler).args) - is_bound if num_args == 0: handler() else: handler(message) self.settings.store() # Store settings if they've changed except Exception as e: # Convert "MyFancySkill" to "My Fancy Skill" for speaking handler_name = re.sub(r"([a-z])([A-Z])", r"\1 \2", self.name) msg_data = {'skill': handler_name} msg = dialog.get('skill.error', self.lang, msg_data) self.speak(msg) LOG.exception(msg) # append exception information in message skill_data['exception'] = e.message finally: if once: self.remove_event(name) # Indicate that the skill handler has completed if handler_info: msg_type = handler_info + '.complete' self.emitter.emit(Message(msg_type, skill_data)) # Send timing metrics context = message.context if context and 'ident' in context: report_timing(context['ident'], 'skill_handler', stopwatch, {'handler': handler.__name__})
def _speak_dialog(self, dialog_id, wait=False): data = {'utterance': dialog.get(dialog_id)} self.bus.emit(Message("speak", data)) if wait: wait_while_speaking()
def _display_skill_loading_notification(self): """Indicate to the user that skills are being loaded.""" self.enclosure.eyes_color(189, 183, 107) # dark khaki self.enclosure.mouth_text(dialog.get("message_loading.skills"))
def check_connection(): """ Check for network connection. If not paired trigger pairing. Runs as a Timer every second until connection is detected. """ if connected(): enclosure = EnclosureAPI(bus) if is_paired(): # Skip the sync message when unpaired because the prompt to go to # home.mycrof.ai will be displayed by the pairing skill enclosure.mouth_text(dialog.get("message_synching.clock")) # Force a sync of the local clock with the internet config = Configuration.get() platform = config['enclosure'].get("platform", "unknown") if platform in ['mycroft_mark_1', 'picroft']: bus.wait_for_response(Message('system.ntp.sync'), 'system.ntp.sync.complete', 15) if not is_paired(): try_update_system(platform) # Check if the time skewed significantly. If so, reboot skew = abs((time.monotonic() - start_ticks) - (time.time() - start_clock)) if skew > 60 * 60: # Time moved by over an hour in the NTP sync. Force a reboot to # prevent weird things from occcurring due to the 'time warp'. # data = {'utterance': dialog.get("time.changed.reboot")} bus.emit(Message("speak", data)) wait_while_speaking() # provide visual indicators of the reboot enclosure.mouth_text(dialog.get("message_rebooting")) enclosure.eyes_color(70, 65, 69) # soft gray enclosure.eyes_spin() # give the system time to finish processing enclosure messages time.sleep(1.0) # reboot bus.emit(Message("system.reboot")) return else: bus.emit(Message("enclosure.mouth.reset")) time.sleep(0.5) enclosure.eyes_color(189, 183, 107) # dark khaki enclosure.mouth_text(dialog.get("message_loading.skills")) bus.emit(Message('mycroft.internet.connected')) # check for pairing, if not automatically start pairing try: if not is_paired(ignore_errors=False): payload = {'utterances': ["pair my device"], 'lang': "en-us"} bus.emit(Message("recognizer_loop:utterance", payload)) else: from mycroft.api import DeviceApi api = DeviceApi() api.update_version() except BackendDown: data = {'utterance': dialog.get("backend.down")} bus.emit(Message("speak", data)) bus.emit(Message("backend.down")) else: thread = Timer(1, check_connection) thread.daemon = True thread.start()
def download_skills(self, speak=False): """ Invoke MSM to install default skills and/or update installed skills Args: speak (bool, optional): Speak the result? Defaults to False """ if not connected(): LOG.error('msm failed, network connection not available') if speak: self.ws.emit( Message("speak", { 'utterance': dialog.get("not connected to the internet") })) self.next_download = time.time() + 5 * MINUTES return False installed_skills = self.load_installed_skills() default_groups = dict(self.msm.repo.get_default_skill_names()) default_names = set( chain(default_groups['default'], default_groups[self.msm.platform])) default_skill_errored = False def install_or_update(skill): """Install missing defaults and update existing skills""" try: if skill.is_local: skill.update() if skill.name not in installed_skills: skill.update_deps() elif skill.name in default_names: skill.install() except Exception: if skill.name in default_names: nonlocal default_skill_errored default_skill_errored = True raise installed_skills.add(skill.name) try: self.msm.apply(install_or_update, self.msm.list()) except MsmException as e: LOG.error('Failed to update skills: {}'.format(repr(e))) self.save_installed_skills(installed_skills) if speak: data = {'utterance': dialog.get("skills updated")} self.ws.emit(Message("speak", data)) if default_skill_errored: self.next_download = time.time() + 5 * MINUTES return False with open(self.dot_msm, 'a'): os.utime(self.dot_msm, None) self.next_download = time.time() + self.update_interval return True
def download_skills(self, speak=False): """ Invoke MSM to install default skills and/or update installed skills Args: speak (bool, optional): Speak the result? Defaults to False """ if not connected(): LOG.error('msm failed, network connection not available') if speak: self.bus.emit(Message("speak", { 'utterance': dialog.get( "not connected to the internet")})) self.next_download = time.time() + 5 * MINUTES return False installed_skills = self.load_installed_skills() default_groups = dict(self.msm.repo.get_default_skill_names()) if self.msm.platform in default_groups: platform_groups = default_groups[self.msm.platform] else: LOG.info('Platform defaults not found, using DEFAULT skills only') platform_groups = [] default_names = set(chain(default_groups['default'], platform_groups)) default_skill_errored = False skills_data = self.load_skills_data() def install_or_update(skill): """Install missing defaults and update existing skills""" if skills_data.get(skill.name, {}).get('beta'): skill.sha = 'HEAD' if skill.is_local: skill.update() if skill.name not in installed_skills: skill.update_deps() elif skill.name in default_names: try: skill.install() except Exception: if skill.name in default_names: LOG.warning( 'Failed to install default skill: ' + skill.name ) nonlocal default_skill_errored default_skill_errored = True raise installed_skills.add(skill.name) try: self.msm.apply(install_or_update, self.msm.list()) except MsmException as e: LOG.error('Failed to update skills: {}'.format(repr(e))) for skill_name in installed_skills: skills_data.setdefault(skill_name, {})['installed'] = True self.write_skills_data(skills_data) self.save_installed_skills(installed_skills) if speak: data = {'utterance': dialog.get("skills updated")} self.bus.emit(Message("speak", data)) if default_skill_errored and self.num_install_retries < 10: self.num_install_retries += 1 self.next_download = time.time() + 5 * MINUTES return False self.num_install_retries = 0 with open(self.dot_msm, 'a'): os.utime(self.dot_msm, None) self.next_download = time.time() + self.update_interval return True
def download_skills(self, speak=False): """ Invoke MSM to install default skills and/or update installed skills Args: speak (bool, optional): Speak the result? Defaults to False """ if not connected(): LOG.error('msm failed, network connection not available') if speak: self.bus.emit( Message("speak", { 'utterance': dialog.get("not connected to the internet") })) self.next_download = time.time() + 5 * MINUTES return False installed_skills = self.load_installed_skills() msm = SkillManager.create_msm() with msm.lock, self.thread_lock: default_groups = dict(msm.repo.get_default_skill_names()) if msm.platform in default_groups: platform_groups = default_groups[msm.platform] else: LOG.info('Platform defaults not found, using DEFAULT ' 'skills only') platform_groups = [] default_names = set( chain(default_groups['default'], platform_groups)) default_skill_errored = False def get_skill_data(skill_name): """ Get skill data structure from name. """ for e in msm.skills_data.get('skills', []): if e.get('name') == skill_name: return e # if skill isn't in the list return empty structure return {} def install_or_update(skill): """Install missing defaults and update existing skills""" if get_skill_data(skill.name).get('beta'): skill.sha = None # Will update to latest head if skill.is_local: skill.update() if skill.name not in installed_skills: skill.update_deps() elif skill.name in default_names: try: msm.install(skill, origin='default') except Exception: if skill.name in default_names: LOG.warning('Failed to install default skill: ' + skill.name) nonlocal default_skill_errored default_skill_errored = True raise installed_skills.add(skill.name) try: msm.apply(install_or_update, msm.list()) if SkillManager.manifest_upload_allowed and is_paired(): try: DeviceApi().upload_skills_data(msm.skills_data) except Exception: LOG.exception('Could not upload skill manifest') except MsmException as e: LOG.error('Failed to update skills: {}'.format(repr(e))) self.save_installed_skills(installed_skills) if speak: data = {'utterance': dialog.get("skills updated")} self.bus.emit(Message("speak", data)) if default_skill_errored and self.num_install_retries < 10: self.num_install_retries += 1 self.next_download = time.time() + 5 * MINUTES return False self.num_install_retries = 0 with open(self.dot_msm, 'a'): os.utime(self.dot_msm, None) self.next_download = time.time() + self.update_interval return True
def handle_complete_intent_failure(event): LOG.info("Failed to find intent.") data = {'utterance': dialog.get('not.loaded')} bus.emit(Message('speak', data))
def check_connection(): """ Check for network connection. If not paired trigger pairing. Runs as a Timer every second until connection is detected. """ if connected(): enclosure = EnclosureAPI(bus) if is_paired(): # Skip the sync message when unpaired because the prompt to go to # home.mycrof.ai will be displayed by the pairing skill enclosure.mouth_text(dialog.get("message_synching.clock")) # Force a sync of the local clock with the internet config = Configuration.get() platform = config['enclosure'].get("platform", "unknown") if platform in ['mycroft_mark_1', 'picroft']: bus.emit(Message("system.ntp.sync")) time.sleep(15) # TODO: Generate/listen for a message response... # Check if the time skewed significantly. If so, reboot skew = abs((time.monotonic() - start_ticks) - (time.time() - start_clock)) if skew > 60 * 60: # Time moved by over an hour in the NTP sync. Force a reboot to # prevent weird things from occcurring due to the 'time warp'. # data = {'utterance': dialog.get("time.changed.reboot")} bus.emit(Message("speak", data)) wait_while_speaking() # provide visual indicators of the reboot enclosure.mouth_text(dialog.get("message_rebooting")) enclosure.eyes_color(70, 65, 69) # soft gray enclosure.eyes_spin() # give the system time to finish processing enclosure messages time.sleep(1.0) # reboot bus.emit(Message("system.reboot")) return else: bus.emit(Message("enclosure.mouth.reset")) time.sleep(0.5) bus.emit(Message('mycroft.internet.connected')) # check for pairing, if not automatically start pairing try: if not is_paired(ignore_errors=False): payload = { 'utterances': ["pair my device"], 'lang': "en-us" } bus.emit(Message("recognizer_loop:utterance", payload)) else: from mycroft.api import DeviceApi api = DeviceApi() api.update_version() except BackendDown: data = {'utterance': dialog.get("backend.down")} bus.emit(Message("speak", data)) bus.emit(Message("backend.down")) else: thread = Timer(1, check_connection) thread.daemon = True thread.start()
def download_skills(self, speak=False): """ Invoke MSM to install default skills and/or update installed skills Args: speak (bool, optional): Speak the result? Defaults to False """ if not connected(): LOG.error('msm failed, network connection not available') if speak: self.bus.emit(Message("speak", { 'utterance': dialog.get( "not connected to the internet")})) self.next_download = time.time() + 5 * MINUTES return False installed_skills = self.load_installed_skills() default_groups = dict(self.msm.repo.get_default_skill_names()) if self.msm.platform in default_groups: platform_groups = default_groups[self.msm.platform] else: LOG.info('Platform defaults not found, using DEFAULT skills only') platform_groups = [] default_names = set(chain(default_groups['default'], platform_groups)) default_skill_errored = False skills_data = self.load_skills_data() new_installs = [] updated_skills = [] def install_or_update(skill): """Install missing defaults and update existing skills""" if skills_data.get(skill.name, {}).get('beta'): skill.sha = None # Will update to latest version if skill.is_local: skill.update() updated_skills.append(skill.name) if skill.name not in installed_skills: skill.update_deps() installed_skills.add(skill.name) elif skill.name in default_names: try: new_installs.append(skill.name) skill.install() except Exception: if skill.name in default_names: LOG.warning( 'Failed to install default skill: ' + skill.name ) nonlocal default_skill_errored default_skill_errored = True raise installed_skills.add(skill.name) try: self.msm.apply(install_or_update, self.msm.list()) except MsmException as e: LOG.error('Failed to update skills: {}'.format(repr(e))) for skill_name in new_installs + updated_skills: if skill_name not in skills_data or skill_name in new_installs: t = time.time() if skill_name in new_installs else 1 skills_data.setdefault(skill_name, {})['installed'] = t skills_data[skill_name]['updated'] = 0 self.write_skills_data(skills_data) self.save_installed_skills(installed_skills) if speak: data = {'utterance': dialog.get("skills updated")} self.bus.emit(Message("speak", data)) if default_skill_errored and self.num_install_retries < 10: self.num_install_retries += 1 self.next_download = time.time() + 5 * MINUTES return False self.num_install_retries = 0 with open(self.dot_msm, 'a'): os.utime(self.dot_msm, None) self.next_download = time.time() + self.update_interval return True
def download_skills(self, speak=False): """ Invoke MSM to install default skills and/or update installed skills Args: speak (bool, optional): Speak the result? Defaults to False """ if not connected(): LOG.error('msm failed, network connection not available') if speak: self.bus.emit(Message("speak", { 'utterance': dialog.get( "not connected to the internet")})) self.next_download = time.time() + 5 * MINUTES return False installed_skills = self.load_installed_skills() msm = SkillManager.create_msm() with msm.lock, self.thread_lock: default_groups = dict(msm.repo.get_default_skill_names()) if msm.platform in default_groups: platform_groups = default_groups[msm.platform] else: LOG.info('Platform defaults not found, using DEFAULT ' 'skills only') platform_groups = [] default_names = set(chain(default_groups['default'], platform_groups)) default_skill_errored = False def get_skill_data(skill_name): """ Get skill data structure from name. """ for e in msm.skills_data.get('skills', []): if e.get('name') == skill_name: return e # if skill isn't in the list return empty structure return {} def install_or_update(skill): """Install missing defaults and update existing skills""" if get_skill_data(skill.name).get('beta'): skill.sha = None # Will update to latest head if skill.is_local: skill.update() if skill.name not in installed_skills: skill.update_deps() elif skill.name in default_names: try: msm.install(skill, origin='default') except Exception: if skill.name in default_names: LOG.warning('Failed to install default skill: ' + skill.name) nonlocal default_skill_errored default_skill_errored = True raise installed_skills.add(skill.name) try: msm.apply(install_or_update, msm.list()) if SkillManager.manifest_upload_allowed and is_paired(): try: DeviceApi().upload_skills_data(msm.skills_data) except Exception: LOG.exception('Could not upload skill manifest') except MsmException as e: LOG.error('Failed to update skills: {}'.format(repr(e))) self.save_installed_skills(installed_skills) if speak: data = {'utterance': dialog.get("skills updated")} self.bus.emit(Message("speak", data)) if default_skill_errored and self.num_install_retries < 10: self.num_install_retries += 1 self.next_download = time.time() + 5 * MINUTES return False self.num_install_retries = 0 with open(self.dot_msm, 'a'): os.utime(self.dot_msm, None) self.next_download = time.time() + self.update_interval return True
def handle_complete_intent_failure(event): """Extreme backup for answering completely unhandled intent requests.""" LOG.info("Failed to find intent.") data = {'utterance': dialog.get('not.loaded')} bus.emit(Message('speak', data))