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))
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)

View File

@ -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. """

View File

@ -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')

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.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)