Add intent fallback system

Also removes multi utterence intent fail. Only makes sense to emit an intent_failure regardless of the amount of intents
pull/938/head
Matthew D. Scholefield 2017-06-16 16:40:12 -05:00
parent 4c1fbcb596
commit a86f0478a4
4 changed files with 49 additions and 9 deletions

View File

@ -62,8 +62,8 @@ def handle_utterance(event):
ws.emit(Message('recognizer_loop:utterance', event)) ws.emit(Message('recognizer_loop:utterance', event))
def handle_multi_utterance_intent_failure(event): def handle_intent_failure(event):
logger.info("Failed to find intent on multiple intents.") logger.info("Failed to find intent.")
# TODO: Localize # TODO: Localize
data = {'utterance': data = {'utterance':
"Sorry, I didn't catch that. Please rephrase your request."} "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:record_end', handle_record_end)
loop.on('recognizer_loop:no_internet', handle_no_internet) loop.on('recognizer_loop:no_internet', handle_no_internet)
ws.on('open', handle_open) ws.on('open', handle_open)
<<<<<<< HEAD
ws.on( ws.on(
'multi_utterance_intent_failure', 'multi_utterance_intent_failure',
handle_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:sleep', handle_sleep)
ws.on('recognizer_loop:wake_up', handle_wake_up) ws.on('recognizer_loop:wake_up', handle_wake_up)
ws.on('mycroft.mic.mute', handle_mic_mute) ws.on('mycroft.mic.mute', handle_mic_mute)

View File

@ -20,6 +20,7 @@ import abc
import imp import imp
import time import time
import operator
import os.path import os.path
import re import re
import time import time
@ -188,9 +189,14 @@ class MycroftSkill(object):
Skills implementation. Skills implementation.
""" """
fallback_handlers = {}
def __init__(self, name=None, emitter=None): def __init__(self, name=None, emitter=None):
self.name = name or self.__class__.__name__ self.name = name or self.__class__.__name__
def __init__(self, name, emitter=None):
self.name = name
self.bind(emitter) self.bind(emitter)
self.config_core = ConfigurationManager.get() self.config_core = ConfigurationManager.get()
self.config = self.config_core.get(self.name) self.config = self.config_core.get(self.name)
@ -201,6 +207,38 @@ class MycroftSkill(object):
self.reload_skill = True self.reload_skill = True
self.events = [] 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 @property
def location(self): def location(self):
""" Get the JSON data struction holding location information. """ """ Get the JSON data struction holding location information. """

View File

@ -63,16 +63,11 @@ class IntentService(object):
reply = message.reply( reply = message.reply(
best_intent.get('intent_type'), best_intent) best_intent.get('intent_type'), best_intent)
self.emitter.emit(reply) self.emitter.emit(reply)
elif len(utterances) == 1: else:
self.emitter.emit(Message("intent_failure", { self.emitter.emit(Message("intent_failure", {
"utterance": utterances[0], "utterance": utterances[0],
"lang": lang "lang": lang
})) }))
else:
self.emitter.emit(Message("multi_utterance_intent_failure", {
"utterances": utterances,
"lang": lang
}))
def handle_register_vocab(self, message): def handle_register_vocab(self, message):
start_concept = message.data.get('start') start_concept = message.data.get('start')

View File

@ -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.client.ws import WebsocketClient
from mycroft.messagebus.message import Message from mycroft.messagebus.message import Message
from mycroft.skills.core import load_skill, create_skill_descriptor, \ 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.skills.intent_service import IntentService
from mycroft.util import connected from mycroft.util import connected
from mycroft.util.log import getLogger from mycroft.util.log import getLogger
@ -117,6 +117,8 @@ def _load_skills():
check_connection() check_connection()
ws.on('intent_failure', MycroftSkill.on_intent_failure)
# Create skill_manager listener and invoke the first time # Create skill_manager listener and invoke the first time
ws.on('skill_manager', skills_manager) ws.on('skill_manager', skills_manager)
ws.on('mycroft.internet.connected', install_default_skills) ws.on('mycroft.internet.connected', install_default_skills)