99 lines
3.6 KiB
Python
99 lines
3.6 KiB
Python
# Copyright 2016 Mycroft AI, Inc.
|
|
#
|
|
# This file is part of Mycroft Core.
|
|
#
|
|
# Mycroft Core is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# Mycroft Core is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with Mycroft Core. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
|
from adapt.engine import IntentDeterminationEngine
|
|
|
|
from mycroft.messagebus.message import Message
|
|
from mycroft.skills.core import open_intent_envelope
|
|
from mycroft.util.log import getLogger
|
|
from mycroft.util.parse import normalize
|
|
|
|
__author__ = 'seanfitz'
|
|
|
|
logger = getLogger(__name__)
|
|
|
|
|
|
class IntentService(object):
|
|
def __init__(self, emitter):
|
|
self.engine = IntentDeterminationEngine()
|
|
self.emitter = emitter
|
|
self.emitter.on('register_vocab', self.handle_register_vocab)
|
|
self.emitter.on('register_intent', self.handle_register_intent)
|
|
self.emitter.on('recognizer_loop:utterance', self.handle_utterance)
|
|
self.emitter.on('detach_intent', self.handle_detach_intent)
|
|
self.emitter.on('detach_skill', self.handle_detach_skill)
|
|
|
|
def handle_utterance(self, message):
|
|
# Get language of the utterance
|
|
lang = message.data.get('lang', None)
|
|
if not lang:
|
|
lang = "en-us"
|
|
|
|
utterances = message.data.get('utterances', '')
|
|
|
|
best_intent = None
|
|
for utterance in utterances:
|
|
try:
|
|
# normalize() changes "it's a boy" to "it is boy", etc.
|
|
best_intent = next(self.engine.determine_intent(
|
|
normalize(utterance, lang), 100))
|
|
|
|
# TODO - Should Adapt handle this?
|
|
best_intent['utterance'] = utterance
|
|
except StopIteration, e:
|
|
logger.exception(e)
|
|
continue
|
|
|
|
if best_intent and best_intent.get('confidence', 0.0) > 0.0:
|
|
reply = message.reply(
|
|
best_intent.get('intent_type'), best_intent)
|
|
self.emitter.emit(reply)
|
|
else:
|
|
self.emitter.emit(Message("intent_failure", {
|
|
"utterance": utterances[0],
|
|
"lang": lang
|
|
}))
|
|
|
|
def handle_register_vocab(self, message):
|
|
start_concept = message.data.get('start')
|
|
end_concept = message.data.get('end')
|
|
regex_str = message.data.get('regex')
|
|
alias_of = message.data.get('alias_of')
|
|
if regex_str:
|
|
self.engine.register_regex_entity(regex_str)
|
|
else:
|
|
self.engine.register_entity(
|
|
start_concept, end_concept, alias_of=alias_of)
|
|
|
|
def handle_register_intent(self, message):
|
|
intent = open_intent_envelope(message)
|
|
self.engine.register_intent_parser(intent)
|
|
|
|
def handle_detach_intent(self, message):
|
|
intent_name = message.data.get('intent_name')
|
|
new_parsers = [
|
|
p for p in self.engine.intent_parsers if p.name != intent_name]
|
|
self.engine.intent_parsers = new_parsers
|
|
|
|
def handle_detach_skill(self, message):
|
|
skill_name = message.data.get('skill_name')
|
|
new_parsers = [
|
|
p for p in self.engine.intent_parsers if
|
|
not p.name.startswith(skill_name)]
|
|
self.engine.intent_parsers = new_parsers
|