From a86f0478a49f722b7edb7b608da07dce104e136d Mon Sep 17 00:00:00 2001 From: "Matthew D. Scholefield" Date: Fri, 16 Jun 2017 16:40:12 -0500 Subject: [PATCH] Add intent fallback system Also removes multi utterence intent fail. Only makes sense to emit an intent_failure regardless of the amount of intents --- mycroft/client/speech/main.py | 9 ++++++-- mycroft/skills/core.py | 38 ++++++++++++++++++++++++++++++++ mycroft/skills/intent_service.py | 7 +----- mycroft/skills/main.py | 4 +++- 4 files changed, 49 insertions(+), 9 deletions(-) diff --git a/mycroft/client/speech/main.py b/mycroft/client/speech/main.py index 5ff4b875d8..e72194223b 100644 --- a/mycroft/client/speech/main.py +++ b/mycroft/client/speech/main.py @@ -62,8 +62,8 @@ def handle_utterance(event): ws.emit(Message('recognizer_loop:utterance', event)) -def handle_multi_utterance_intent_failure(event): - logger.info("Failed to find intent on multiple intents.") +def handle_intent_failure(event): + logger.info("Failed to find intent.") # TODO: Localize data = {'utterance': "Sorry, I didn't catch that. Please rephrase your request."} @@ -126,9 +126,14 @@ def main(): loop.on('recognizer_loop:record_end', handle_record_end) loop.on('recognizer_loop:no_internet', handle_no_internet) ws.on('open', handle_open) +<<<<<<< HEAD ws.on( 'multi_utterance_intent_failure', handle_multi_utterance_intent_failure) +======= + ws.on('speak', handle_speak) + ws.on('intent_failure', handle_intent_failure) +>>>>>>> Add intent fallback system ws.on('recognizer_loop:sleep', handle_sleep) ws.on('recognizer_loop:wake_up', handle_wake_up) ws.on('mycroft.mic.mute', handle_mic_mute) diff --git a/mycroft/skills/core.py b/mycroft/skills/core.py index 5ab04789e0..6beb61825a 100644 --- a/mycroft/skills/core.py +++ b/mycroft/skills/core.py @@ -20,6 +20,7 @@ import abc import imp import time +import operator import os.path import re import time @@ -188,9 +189,14 @@ class MycroftSkill(object): Skills implementation. """ + fallback_handlers = {} + def __init__(self, name=None, emitter=None): self.name = name or self.__class__.__name__ + + def __init__(self, name, emitter=None): + self.name = name self.bind(emitter) self.config_core = ConfigurationManager.get() self.config = self.config_core.get(self.name) @@ -201,6 +207,38 @@ class MycroftSkill(object): self.reload_skill = True self.events = [] + @staticmethod + def on_intent_failure(message): + """Goes through all fallback handler until one returns true""" + for _, handler in sorted(MycroftSkill.fallback_handlers.items(), + key=operator.itemgetter(0)): + if handler(message): + return + logger.warn('No fallback could handle intent.') + + @staticmethod + def register_fallback(handler, priority): + """ + Register a function to be called as a general info fallback + Fallback should receive message and return + a boolean (True if succeeded or False if failed) + + Lower priority gets run first + 0 for high priority 100 for low priority + """ + while priority in MycroftSkill.fallback_handlers: + priority += 1 + + MycroftSkill.fallback_handlers[priority] = handler + + @staticmethod + def remove_fallback(handler_to_del): + for priority, handler in MycroftSkill.fallback_handlers.items(): + if handler == handler_to_del: + del MycroftSkill.fallback_handlers[priority] + return + logger.warn('Could not remove fallback!') + @property def location(self): """ Get the JSON data struction holding location information. """ diff --git a/mycroft/skills/intent_service.py b/mycroft/skills/intent_service.py index b274a4e5fb..ffc640fa39 100644 --- a/mycroft/skills/intent_service.py +++ b/mycroft/skills/intent_service.py @@ -63,16 +63,11 @@ class IntentService(object): reply = message.reply( best_intent.get('intent_type'), best_intent) self.emitter.emit(reply) - elif len(utterances) == 1: + else: self.emitter.emit(Message("intent_failure", { "utterance": utterances[0], "lang": lang })) - else: - self.emitter.emit(Message("multi_utterance_intent_failure", { - "utterances": utterances, - "lang": lang - })) def handle_register_vocab(self, message): start_concept = message.data.get('start') diff --git a/mycroft/skills/main.py b/mycroft/skills/main.py index e458751302..cb65e2acfb 100644 --- a/mycroft/skills/main.py +++ b/mycroft/skills/main.py @@ -30,7 +30,7 @@ from mycroft.lock import Lock # Creates PID file for single instance from mycroft.messagebus.client.ws import WebsocketClient from mycroft.messagebus.message import Message from mycroft.skills.core import load_skill, create_skill_descriptor, \ - MainModule, SKILLS_DIR + MainModule, SKILLS_DIR, MycroftSkill from mycroft.skills.intent_service import IntentService from mycroft.util import connected from mycroft.util.log import getLogger @@ -117,6 +117,8 @@ def _load_skills(): check_connection() + ws.on('intent_failure', MycroftSkill.on_intent_failure) + # Create skill_manager listener and invoke the first time ws.on('skill_manager', skills_manager) ws.on('mycroft.internet.connected', install_default_skills)