class MusicPlayerIntentParser():
    def __init__(self):
        self.engine = IntentDeterminationEngine()
        # define music vocabulary
        music_verbs = ["listen", "hear", "play", "stop"]

        for mv in music_verbs:
            self.engine.register_entity(mv, "MusicVerb")

        music_keywords = ["songs", "music"]

        for mk in music_keywords:
            self.engine.register_entity(mk, "MusicKeyword")

        self.engine.register_regex_entity(
            "(play|hear|listen|listen to)\s*(the)?\s*(song|album)?\s*(?P<Media>.*)$"  # NoQA
        )

        music_intent = IntentBuilder("MusicIntent")\
            .require("MusicVerb")\
            .optionally("MusicKeyword")\
            .optionally("Media")\
            .build()

        self.engine.register_intent_parser(music_intent)

    def parse(self, sentence):
        for intent in self.engine.determine_intent(sentence):
            if intent.get('confidence') > 0:
                return intent
예제 #2
0
class SmartHomeIntentParser():
    def __init__(self):
        self.engine = IntentDeterminationEngine()
        # smart home intent vocabalory
        switch_tasks_keyword = ["switch", "turn"]
        for stk in switch_tasks_keyword:
            self.engine.register_entity(stk, "SwitchTasksKeyword")

        on_off_keyword = ["on", "off"]

        for stk in on_off_keyword:
            self.engine.register_entity(stk, "OnOffKeyword")

        equipment_keyword = ["lights", "light", "fan"]

        for stk in equipment_keyword:
            self.engine.register_entity(stk, "EquipmentKeyword")

        smart_home_intent = IntentBuilder("SmartHomeIntent")\
            .require("SwitchTasksKeyword")\
            .require("OnOffKeyword")\
            .require("EquipmentKeyword")\
            .build()

        self.engine.register_intent_parser(smart_home_intent)

    def parse(self, sentence):
        for intent in self.engine.determine_intent(sentence):
            if intent.get('confidence') > 0:
                return intent
예제 #3
0
class JokeIntentParser():
    def __init__(self):
        self.engine = IntentDeterminationEngine()
        joke_verbs = [
            "tell",
            "crack"
        ]
        for mv in joke_verbs:
            self.engine.register_entity(mv, "JokeVerb")

        joke_keywords = [
            "joke"
        ]
        for mk in joke_keywords:
            self.engine.register_entity(mk, "JokeKeyword")

        joke_intent = IntentBuilder("JokeIntent")\
            .require("JokeVerb")\
            .optionally("JokeKeyword")\
            .build()

        self.engine.register_intent_parser(joke_intent)

    def parse(self, sentence):
        for intent in self.engine.determine_intent(sentence):
            if intent.get('confidence') > 0:
                return intent
예제 #4
0
    def testContextAndOneOf(self):
        # test to cover https://github.com/MycroftAI/adapt/issues/86
        engine = IntentDeterminationEngine()
        context_manager = ContextManager()

        # define vocabulary
        weather_keyword = ["weather"]

        for wk in weather_keyword:
            engine.register_entity(wk, "WeatherKeyword")

        # structure intent
        weather_intent = IntentBuilder("WeatherIntent") \
            .require("WeatherKeyword") \
            .one_of("Location", "LocationContext").build()

        engine.register_intent_parser(weather_intent)
        word = 'lizard'
        context = 'LocationContext'
        entity = {}
        entity['data'] = [(word, context)]
        entity['match'] = word
        entity['key'] = word
        context_manager.inject_context(entity)

        intents = list(
            engine.determine_intent('weather',
                                    context_manager=context_manager))
        self.assertEqual(1, len(intents), "Incorrect number of intents")
        result = intents[0]
        self.assertEqual("lizard", result.get("LocationContext"),
                         "Context not matched")
        self.assertEqual(0.75, result.get('confidence'),
                         "Context confidence not properly applied.")
예제 #5
0
def register_alarm_intent(engine: IntentDeterminationEngine):
    alarm_keywords = [
        "alarm"
    ]

    for ak in alarm_keywords:
        engine.register_entity(ak, "AlarmKeyword")

    engine.register_regex_entity("(for|at) (?P<Time>.*)")

    weekdays = [
        "monday",
        "tuesday",
        "wednesday",
        "thursday",
        "friday",
        "saturday",
        "sunday"
    ]

    for w in weekdays:
        engine.register_entity(w, "Weekday")

    # structure intent
    alarm_intent = IntentBuilder("AlarmIntent")\
        .require("AlarmKeyword")\
        .require("Time")\
        .optionally("Weekday")\
        .build()

    engine.register_intent_parser(alarm_intent)
예제 #6
0
class IntentEngineTests(unittest.TestCase):
    def setUp(self):
        self.engine = IntentDeterminationEngine()

    def testRegisterIntentParser(self):
        assert len(self.engine.intent_parsers) == 0
        try:
            self.engine.register_intent_parser("NOTAPARSER")
            assert "Did not fail to register invalid intent parser" and False
        except ValueError as e:
            pass
        parser = IntentBuilder("Intent").build()
        self.engine.register_intent_parser(parser)
        assert len(self.engine.intent_parsers) == 1

    def testRegisterRegexEntity(self):
        assert len(self.engine._regex_strings) == 0
        assert len(self.engine.regular_expressions_entities) == 0
        self.engine.register_regex_entity(".*")
        assert len(self.engine._regex_strings) == 1
        assert len(self.engine.regular_expressions_entities) == 1

    def testSelectBestIntent(self):
        parser1 = IntentBuilder("Parser1").require("Entity1").build()
        self.engine.register_entity("tree", "Entity1")
        self.engine.register_intent_parser(parser1)

        utterance = "go to the tree house"
        intent = next(self.engine.determine_intent(utterance))
        assert intent
        assert intent['intent_type'] == 'Parser1'

        parser2 = IntentBuilder("Parser2").require("Entity1").require(
            "Entity2").build()
        self.engine.register_entity("house", "Entity2")
        self.engine.register_intent_parser(parser2)
        intent = next(self.engine.determine_intent(utterance))
        assert intent
        assert intent['intent_type'] == 'Parser2'

    def testIntentMissingEntity(self):
        utterance1 = "give me One home"
        utterance2 = "give me One or Two"
        parser3 = IntentBuilder("Parser3").require("One").require(
            "Two").build()
        self.engine.register_entity("One", "One")
        self.engine.register_entity("Two", "Two")
        self.engine.register_intent_parser(parser3)
        intent2 = self.engine.determine_intent(utterance2)
        try:
            intent2 = next(intent2)
        except BaseException:
            pass
        intent1 = self.engine.determine_intent(utterance1)
        try:
            intent1 = next(intent1)
        except BaseException:
            pass
예제 #7
0
    def testEmptyTags(self):
        # Validates https://github.com/MycroftAI/adapt/issues/114
        engine = IntentDeterminationEngine()
        engine.register_entity("Kevin",
                               "who")  # same problem if several entities
        builder = IntentBuilder("Buddies")
        builder.optionally("who")  # same problem if several entity types
        engine.register_intent_parser(builder.build())

        intents = [i for i in engine.determine_intent("Julien is a friend")]
        assert len(intents) == 0
class ContextManagerIntegrationTest(unittest.TestCase):
    def setUp(self):
        self.context_manager = ContextManager()
        self.engine = IntentDeterminationEngine()

    def testBasicContextualFollowup(self):
        intent1 = IntentBuilder("TimeQueryIntent")\
            .require("TimeQuery")\
            .require("Location")\
            .build()
        intent2 = IntentBuilder("WeatherQueryIntent")\
            .require("WeatherKeyword")\
            .require("Location")\
            .build()

        self.engine.register_intent_parser(intent1)
        self.engine.register_intent_parser(intent2)

        self.engine.register_entity("what time is it", "TimeQuery")
        self.engine.register_entity("seattle", "Location")
        self.engine.register_entity("miami", "Location")

        self.engine.register_entity("weather", "WeatherKeyword")

        utterance1 = "what time is it in seattle"
        intent = next(self.engine.determine_intent(utterance1, include_tags=True, context_manager=self.context_manager))
        assert intent
        assert intent['intent_type'] == 'TimeQueryIntent'
        assert '__tags__' in intent
        for tag in intent['__tags__']:
            context_entity = tag.get('entities')[0]
            self.context_manager.inject_context(context_entity)

        utterance2 = "what's the weather like?"
        intent = next(self.engine.determine_intent(utterance2, context_manager=self.context_manager))
        assert intent
        assert intent['intent_type'] == 'WeatherQueryIntent'

    def testContextOnlyUsedOnce(self):
        intent_parser = IntentBuilder("DummyIntent")\
            .require("Foo")\
            .optionally("Foo", "Foo2")\
            .build()

        context_entity = {'confidence': 1.0, 'data': [('foo', 'Foo')], 'match': 'foo', 'key': 'foo'}
        self.context_manager.inject_context(context_entity)
        self.engine.register_intent_parser(intent_parser)
        self.engine.register_entity("foo", "Foo")
        self.engine.register_entity("fop", "Foo")

        intent = next(self.engine.determine_intent("foo", include_tags=True, context_manager=self.context_manager))
        assert intent
        assert intent['intent_type'] == "DummyIntent"
        assert not (intent.get("Foo") and intent.get("Foo2"))
class ContextManagerIntegrationTest(unittest.TestCase):
    def setUp(self):
        self.context_manager = ContextManager()
        self.engine = IntentDeterminationEngine()

    def testBasicContextualFollowup(self):
        intent1 = IntentBuilder("TimeQueryIntent")\
            .require("TimeQuery")\
            .require("Location")\
            .build()
        intent2 = IntentBuilder("WeatherQueryIntent")\
            .require("WeatherKeyword")\
            .require("Location")\
            .build()

        self.engine.register_intent_parser(intent1)
        self.engine.register_intent_parser(intent2)

        self.engine.register_entity("what time is it", "TimeQuery")
        self.engine.register_entity("seattle", "Location")
        self.engine.register_entity("miami", "Location")

        self.engine.register_entity("weather", "WeatherKeyword")

        utterance1 = "what time is it in seattle"
        intent = next(self.engine.determine_intent(utterance1, include_tags=True, context_manager=self.context_manager))
        assert intent
        assert intent['intent_type'] == 'TimeQueryIntent'
        assert '__tags__' in intent
        for tag in intent['__tags__']:
            context_entity = tag.get('entities')[0]
            self.context_manager.inject_context(context_entity)

        utterance2 = "what's the weather like?"
        intent = next(self.engine.determine_intent(utterance2, context_manager=self.context_manager))
        assert intent
        assert intent['intent_type'] == 'WeatherQueryIntent'

    def testContextOnlyUsedOnce(self):
        intent_parser = IntentBuilder("DummyIntent")\
            .require("Foo")\
            .optionally("Foo", "Foo2")\
            .build()

        context_entity = {'confidence': 1.0, 'data': [('foo', 'Foo')], 'match': 'foo', 'key': 'foo'}
        self.context_manager.inject_context(context_entity)
        self.engine.register_intent_parser(intent_parser)
        self.engine.register_entity("foo", "Foo")
        self.engine.register_entity("fop", "Foo")

        intent = next(self.engine.determine_intent("foo", include_tags=True, context_manager=self.context_manager))
        assert intent
        assert intent['intent_type'] == "DummyIntent"
        assert not (intent.get("Foo") and intent.get("Foo2"))
예제 #10
0
def register_time_intent(engine: IntentDeterminationEngine):
    time_keywords = [
        "time"
    ]

    for tk in time_keywords:
        engine.register_entity(tk, "TimeKeyword")

    time_intent = IntentBuilder("TimeIntent")\
        .require("TimeKeyword")\
        .build()

    engine.register_intent_parser(time_intent)
예제 #11
0
def register_agenda_intent(engine: IntentDeterminationEngine):
    # create and register weather vocabulary
    agenda_keyword = ["agenda"]

    for ak in agenda_keyword:
        engine.register_entity(ak, "AgendaKeyword")

    # structure intent
    agenda_intent = IntentBuilder("AgendaIntent")\
        .require("AgendaKeyword")\
        .build()

    engine.register_intent_parser(agenda_intent)
예제 #12
0
def register_joke_intent(engine: IntentDeterminationEngine):
    # create and register joke vocabulary
    joke_keywords = ["joke", "make me laugh"]

    for jk in joke_keywords:
        engine.register_entity(jk, "JokeKeyword")

    # structure intent
    joke_intent = IntentBuilder("JokeIntent")\
        .require("JokeKeyword")\
        .build()

    engine.register_intent_parser(joke_intent)
예제 #13
0
class IntentEngineTests(unittest.TestCase):
    def setUp(self):
        self.engine = IntentDeterminationEngine()

    def testRegisterIntentParser(self):
        assert len(self.engine.intent_parsers) == 0
        try:
            self.engine.register_intent_parser("NOTAPARSER")
            assert "Did not fail to register invalid intent parser" and False
        except ValueError, e:
            pass
        parser = IntentBuilder("Intent").build()
        self.engine.register_intent_parser(parser)
        assert len(self.engine.intent_parsers) == 1
예제 #14
0
class IntentEngineTests(unittest.TestCase):
    def setUp(self):
        self.engine = IntentDeterminationEngine()

    def testRegisterIntentParser(self):
        assert len(self.engine.intent_parsers) == 0
        try:
            self.engine.register_intent_parser("NOTAPARSER")
            assert "Did not fail to register invalid intent parser" and False
        except ValueError, e:
            pass
        parser = IntentBuilder("Intent").build()
        self.engine.register_intent_parser(parser)
        assert len(self.engine.intent_parsers) == 1
예제 #15
0
def register_timer_intent(engine: IntentDeterminationEngine):
    timer_keywords = ["timer"]

    for tk in timer_keywords:
        engine.register_entity(tk, "TimerKeyword")

    engine.register_regex_entity("for (?P<Time>.*)")

    # structure intent
    timer_intent = IntentBuilder("TimerIntent")\
        .require("TimerKeyword")\
        .optionally("Time")\
        .build()

    engine.register_intent_parser(timer_intent)
예제 #16
0
def register_todo_intent(engine: IntentDeterminationEngine):
    commands = ["add", "remove", "get", "tell me", "clear"]

    for c in commands:
        engine.register_entity(c, "TodoCommand")

    engine.register_regex_entity("(add|remove) (?P<Item>.*) (to|from) my")
    engine.register_regex_entity("my (?P<ListType>.*) list")

    todo_intent = IntentBuilder("TodoIntent")\
        .require("TodoCommand")\
        .optionally("Item")\
        .require("ListType")\
        .build()

    engine.register_intent_parser(todo_intent)
def register_weather_intent(engine: IntentDeterminationEngine):
    # create and register weather vocabulary
    weather_keyword = ["weather"]

    for wk in weather_keyword:
        engine.register_entity(wk, "WeatherKeyword")

    # create regex to parse out locations
    engine.register_regex_entity("in (?P<Location>.*)")

    # structure intent
    weather_intent = IntentBuilder("WeatherIntent")\
        .require("WeatherKeyword")\
        .optionally("Location")\
        .build()

    engine.register_intent_parser(weather_intent)
예제 #18
0
def __initialize__():
    engine = IntentDeterminationEngine()
    launch_keyword = parse_keyword('LaunchKeyword')
    for lk in launch_keyword:
        engine.register_entity(lk, "LaunchKeyword")
    launch_intent = IntentBuilder("LaunchIntent") \
        .require("LaunchKeyword") \
        .build()
    engine.register_intent_parser(launch_intent)

    play_keyword = parse_keyword('PlayKeyword')
    for pk in play_keyword:
        engine.register_entity(pk, "PlayKeyword")
    play_intent = IntentBuilder("PlayIntent") \
        .require("PlayKeyword") \
        .build()
    engine.register_intent_parser(play_intent)
예제 #19
0
def register_reminder_intent(engine: IntentDeterminationEngine):
    reminder_keywords = ["remind"]

    for rk in reminder_keywords:
        engine.register_entity(rk, "ReminderKeyword")

    engine.register_regex_entity("to (?P<Action>.*) in")
    engine.register_regex_entity("in (?P<Time>.*)")

    # structure intent
    reminder_intent = IntentBuilder("ReminderIntent")\
        .require("ReminderKeyword")\
        .require("Action") \
        .require("Time") \
        .build()

    engine.register_intent_parser(reminder_intent)
예제 #20
0
def register_what_is_intent(engine: IntentDeterminationEngine):
    # create and register what is vocabulary
    what_is_keywords = ["what is", "tell me"]

    for wk in what_is_keywords:
        engine.register_entity(wk, "WhatIsKeyword")

    # create regex to parse out subjects
    engine.register_regex_entity("is (?P<Subject>.*)")
    engine.register_regex_entity("about (?P<Subject>.*)")

    # structure intent
    what_is_intent = IntentBuilder("WhatIsIntent")\
        .require("WhatIsKeyword")\
        .require("Subject")\
        .build()

    engine.register_intent_parser(what_is_intent)
예제 #21
0
def register_news_intent(engine: IntentDeterminationEngine):
    # create and register news vocabulary
    news_keyword = ["news"]

    for nk in news_keyword:
        engine.register_entity(nk, "NewsKeyword")

    # create regex to parse out topics
    engine.register_regex_entity("about (?P<Topic>.*)")
    engine.register_regex_entity("for (?P<Topic>.*)")

    # structure intent
    news_intent = IntentBuilder("NewsIntent")\
        .require("NewsKeyword")\
        .optionally("Topic")\
        .build()

    engine.register_intent_parser(news_intent)
예제 #22
0
def train(keyword, types, locations):
    global engine
    engine = IntentDeterminationEngine()
    for kw in keyword:
        engine.register_entity(kw, "Keyword")

    for t in types:
        engine.register_entity(t, "Type")

    for loc in locations:
        engine.register_entity(loc, "Location")

    intent = IntentBuilder("Intent")\
        .require("Keyword")\
        .optionally("Type")\
        .require("Location")\
        .build()

    engine.register_intent_parser(intent)
예제 #23
0
파일: app.py 프로젝트: Ryan-Gadhi/Dallela
def put_in_engin(text):
    engine = IntentDeterminationEngine()

    # Register entities on engine
    for entity, keywords in entities.items():
        for keyword in keywords:
            engine.register_entity(keyword, entity)

    for entity in multi_regex_entities:
        for regex in entity:
            engine.register_regex_entity(regex)

    # Register intents on engine
    for intent in intents:
        engine.register_intent_parser(intent)

    for intent in engine.determine_intent(text):
        # return dict[intenct] # will return function
        print(intent)

    print('finished')
예제 #24
0
class input_engine:
    """Manages the intent engine and natural language input parser"""
    def __init__(self):
        self.engine = IntentDeterminationEngine()

    def register_entity(self, keywords, name):
        """Registers an intenty to be found in an input"""
        for k in keywords:
            self.engine.register_entity(k, name)

    def register_intent(self, intent):
        """Registers an intent that can be found in an input"""
        self.engine.register_intent_parser(intent)

    def get_intent(self, input_string):
        """Returns an intent from an input string if one is found"""
        intent = self.engine.determine_intent(input_string)
        for intent in self.engine.determine_intent(input_string):
            if intent.get("confidence") > 0:
                return intent
        return None
예제 #25
0
class WeatherIntentParser():
    def __init__(self):
        self.engine = IntentDeterminationEngine()
        weather_verbs = ["weather", "temperature", "forecast"]

        for mv in weather_verbs:
            self.engine.register_entity(mv, "WeatherVerb")

        self.engine.register_regex_entity(
            "in\s*(?P<Location>[A-Z][^\s]*\s*?)+.*$"  # NoQA
        )

        weather_intent = IntentBuilder("WeatherIntent")\
            .require("WeatherVerb")\
            .require("Location")\
            .build()

        self.engine.register_intent_parser(weather_intent)

    def parse(self, sentence):
        for intent in self.engine.determine_intent(sentence):
            if intent.get('confidence') > 0:
                return intent
예제 #26
0
def get_intent(message):
    engine = IntentDeterminationEngine()

    keywords = [
        'service',
        'med',
        'clinic',
        'walk in',
    ]

    for key in keywords:
        engine.register_entity(key, "KeyWords")
    print(os.getcwd())
    with open(os.getcwd() + '/home/addresses.csv', 'rb') as csvfile:
        records = csv.reader(csvfile, delimiter=',')
        street_number = []
        street_name = []

        for row in records:
            street_number.append(row[8])
            street_name.append(row[11])

    for key in street_number:
        engine.register_entity(key, "StreetNumber")

    for key in street_name:
        engine.register_entity(key, "StreetName")

    address_intent = IntentBuilder("AddressIntent")\
        .require("KeyWords")\
        .optionally("StreetNumber")\
        .optionally("StreetName")\
        .build()

    engine.register_intent_parser(address_intent)
    for intent in engine.determine_intent(''.join(message)):
        return intent
예제 #27
0
class IntentEngineTests(unittest.TestCase):
    def setUp(self):
        self.engine = IntentDeterminationEngine()

    def testRegisterIntentParser(self):
        assert len(self.engine.intent_parsers) == 0
        try:
            self.engine.register_intent_parser("NOTAPARSER")
            assert "Did not fail to register invalid intent parser" and False
        except ValueError as e:
            pass
        parser = IntentBuilder("Intent").build()
        self.engine.register_intent_parser(parser)
        assert len(self.engine.intent_parsers) == 1

    def testRegisterRegexEntity(self):
        assert len(self.engine._regex_strings) == 0
        assert len(self.engine.regular_expressions_entities) == 0
        self.engine.register_regex_entity(".*")
        assert len(self.engine._regex_strings) == 1
        assert len(self.engine.regular_expressions_entities) == 1

    def testSelectBestIntent(self):
        parser1 = IntentBuilder("Parser1").require("Entity1").build()
        self.engine.register_intent_parser(parser1)
        self.engine.register_entity("tree", "Entity1")

        utterance = "go to the tree house"
        intent = next(self.engine.determine_intent(utterance))
        assert intent
        assert intent['intent_type'] == 'Parser1'

        parser2 = IntentBuilder("Parser2").require("Entity1").require("Entity2").build()
        self.engine.register_intent_parser(parser2)
        self.engine.register_entity("house", "Entity2")
        intent = next(self.engine.determine_intent(utterance))
        assert intent
        assert intent['intent_type'] == 'Parser2'
예제 #28
0
    "listen",
    "hear",
    "play"
]

for mv in music_verbs:
    engine.register_entity(mv, "MusicVerb")

music_keywords = [
    "songs",
    "music"
]

for mk in music_keywords:
    engine.register_entity(mk, "MusicKeyword")

music_intent = IntentBuilder("MusicIntent")\
    .require("MusicVerb")\
    .optionally("MusicKeyword")\
    .optionally("Artist")\
    .build()

engine.register_intent_parser(weather_intent)
engine.register_intent_parser(music_intent)


if __name__ == "__main__":
    for intent in engine.determine_intent(' '.join(sys.argv[1:])):
        if intent and intent.get('confidence') > 0:
            print(json.dumps(intent, indent=4))
예제 #29
0
파일: intent.py 프로젝트: frkos/rhasspy
class AdaptIntentRecognizer(RhasspyActor):
    """Recognize intents with Mycroft Adapt."""
    def __init__(self) -> None:
        RhasspyActor.__init__(self)
        self.engine = None
        self.preload = False

    def to_started(self, from_state: str) -> None:
        """Transition to started state."""
        self.preload = self.config.get("preload", False)
        if self.preload:
            try:
                self.load_engine()
            except Exception as e:
                self._logger.warning("preload: %s", e)

        self.transition("loaded")

    def in_loaded(self, message: Any, sender: RhasspyActor) -> None:
        """Handle messages in loaded state."""
        if isinstance(message, RecognizeIntent):
            try:
                self.load_engine()
                intent = self.recognize(message.text)
            except Exception:
                self._logger.exception("in_loaded")
                intent = empty_intent()
                intent["text"] = message.text
                intent["raw_text"] = message.text

            intent["speech_confidence"] = message.confidence
            self.send(
                message.receiver or sender,
                IntentRecognized(intent, handle=message.handle),
            )

    # -------------------------------------------------------------------------

    def recognize(self, text: str) -> Dict[str, Any]:
        """Use Adapt engine to recognize intent."""
        # Get all intents
        assert self.engine is not None, "Adapt engine not loaded"
        intents = [
            intent for intent in self.engine.determine_intent(text) if intent
        ]

        if len(intents) > 0:
            # Return the best intent only
            intent = max(intents, key=lambda x: x.get("confidence", 0))
            intent_type = intent["intent_type"]
            entity_prefix = "{0}.".format(intent_type)

            slots = {}
            for key, value in intent.items():
                if key.startswith(entity_prefix):
                    key = key[len(entity_prefix):]
                    slots[key] = value

            # Try to match Rasa NLU format for future compatibility
            return {
                "text":
                text,
                "intent": {
                    "name": intent_type,
                    "confidence": intent.get("confidence", 0),
                },
                "entities": [{
                    "entity": name,
                    "value": value
                } for name, value in slots.items()],
            }

        return empty_intent()

    # -------------------------------------------------------------------------

    def load_engine(self) -> None:
        """Configure Adapt engine if not already cached."""
        if self.engine is None:
            from adapt.intent import IntentBuilder
            from adapt.engine import IntentDeterminationEngine

            config_path = self.profile.read_path("adapt_config.json")
            if not os.path.exists(config_path):
                return

            # Create empty engine
            self.engine = IntentDeterminationEngine()
            assert self.engine is not None

            # { intents: { ... }, entities: [ ... ] }
            with open(config_path, "r") as config_file:
                config = json.load(config_file)

            # Register entities
            for entity_name, entity_values in config["entities"].items():
                for value in entity_values:
                    self.engine.register_entity(value, entity_name)

            # Register intents
            for intent_name, intent_config in config["intents"].items():
                intent = IntentBuilder(intent_name)
                for required_entity in intent_config["require"]:
                    intent.require(required_entity)

                for optional_entity in intent_config["optionally"]:
                    intent.optionally(optional_entity)

                self.engine.register_intent_parser(intent.build())

            self._logger.debug("Loaded engine from config file %s",
                               config_path)
def register_add_event_intent(engine: IntentDeterminationEngine):

    # <event_name> - done
    # <event_location> - done
    # <start_date> - done
    # <start_time> - done
    # <end_date> - done
    # <end_time> - done

    # called <event_name> from the <start_date> to the <end_date>
    # schedule an event called OOP exam from the 21st of May to the 22nd of May

    # called <event_name> at <event_location> from the <start_date> to the<end_date>
    # schedule an event called OOP exam at FMI 325 from the 21st of May to the 22nd of May

    # called <event_name> on the <start_date> at <start_time> until the <end_date> at <end_time>
    # schedule an event called OOP exam on the 21st of May at 12:30 p.m. until the 22nd of May at 13:30 p.m.

    # called <event_name> at <event_location> on the <start_date> at <start_time> until the <end_date> at <end_time>
    # create an event called OOP exam at FMI 325 on the 21st of June at 12:30 p.m. until the 21nd of June at 13:30 p.m.

    # other key words:
    # from, to, at, on, until

    # (from|on)?.+?(?<!until).+?(the (?P<start_date>\d+?)(?=st|nd|td|th))
    event_keyword = ["event", "schedule"]

    for ek in event_keyword:
        engine.register_entity(ek, "AddEventKeyword")

    # event name
    engine.register_regex_entity(
        'called (?P<event_name>.+?)(?=from|to|at|on|until)')

    # matches location
    engine.register_regex_entity(
        "at (?P<location>[a-zA-Z0-9 ]+?)(?=from|to|at|on|until)")

    # start_date, when only date is present
    engine.register_regex_entity(
        '(from the)(?<!to the) ((?P<start_date>\d+?)(?=st|nd|rd|th))')

    # start_date, when time is present
    engine.register_regex_entity(
        '(on the)(?<!until the) ((?P<start_date>\d+?)(?=st|nd|rd|th))')

    # start_time
    engine.register_regex_entity(
        'at (?P<start_time>([0-9]{1,4}:?[0-9]{0,2} ?(p\.m\.|a\.m\.)?)).*')

    # end_date, when only date is present
    engine.register_regex_entity(
        '(to the) ((?P<end_date>\d+?)(?=st|nd|rd|th))')

    # end_date, when time is present
    engine.register_regex_entity(
        '(until the) ((?P<end_date>\d+?)(?=st|nd|rd|th))')

    # end_time
    engine.register_regex_entity(
        '(?<=until the \d{2}(st|nd|rd|th) of) \w*? at (?P<end_time>([0-9]{1,4}:?[0-9]{0,2} ?(p\.m\.|a\.m\.)?))'
    )

    # structure intent
    add_event_intent = IntentBuilder("AddEventIntent") \
        .require("AddEventKeyword")\
        .optionally("event_name")\
        .optionally("location")\
        .optionally("start_date")\
        .optionally("start_time")\
        .optionally("end_date")\
        .optionally("end_time")\
        .build()

    engine.register_intent_parser(add_event_intent)
예제 #31
0
for loc in locations:
    engine.register_entity(loc, 'Location')

weather_intent = IntentBuilder("WeatherIntent")\
        .require("WeatherKeyword")\
        .optionally("WeatherType")\
        .require('Location')\
        .build()

hide_keyword = ['hide']
for hk in hide_keyword:
    engine.register_entity(hk, "HideKeyword")

hide_intent = IntentBuilder("HideIntent").require("HideKeyword").build()

engine.register_intent_parser(weather_intent)
engine.register_intent_parser(hide_intent)

# Existing user
token = client.login_with_password(username="******",
                                   password=password)

room = client.join_room("#apebot:matrix.org")
room.add_listener(on_message)
room.send_text("ApeBot reporting for duty")

try:
    client.listen_forever()
except KeyboardInterrupt:
    pass
finally:
예제 #32
0
class IntentService(object):
    def __init__(self, emitter):
        self.config = Configuration.get().get('context', {})
        self.engine = IntentDeterminationEngine()

        # Dictionary for translating a skill id to a name
        self.skill_names = {}
        # Context related intializations
        self.context_keywords = self.config.get('keywords', [])
        self.context_max_frames = self.config.get('max_frames', 3)
        self.context_timeout = self.config.get('timeout', 2)
        self.context_greedy = self.config.get('greedy', False)
        self.context_manager = ContextManager(self.context_timeout)
        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)
        # Context related handlers
        self.emitter.on('add_context', self.handle_add_context)
        self.emitter.on('remove_context', self.handle_remove_context)
        self.emitter.on('clear_context', self.handle_clear_context)
        # Converse method
        self.emitter.on('skill.converse.response',
                        self.handle_converse_response)
        self.emitter.on('mycroft.speech.recognition.unknown',
                        self.reset_converse)
        self.emitter.on('mycroft.skills.loaded', self.update_skill_name_dict)

        def add_active_skill_handler(message):
            self.add_active_skill(message.data['skill_id'])
        self.emitter.on('active_skill_request', add_active_skill_handler)
        self.active_skills = []  # [skill_id , timestamp]
        self.converse_timeout = 5  # minutes to prune active_skills

    def update_skill_name_dict(self, message):
        """
            Messagebus handler, updates dictionary of if to skill name
            conversions.
        """
        self.skill_names[message.data['id']] = message.data['name']

    def get_skill_name(self, skill_id):
        """ Get skill name from skill ID.

        Args:
            skill_id: a skill id as encoded in Intent handlers.

        Returns:
            (str) Skill name or the skill id if the skill wasn't found
        """
        return self.skill_names.get(skill_id, skill_id)

    def reset_converse(self, message):
        """Let skills know there was a problem with speech recognition"""
        lang = message.data.get('lang', "en-us")
        for skill in self.active_skills:
            self.do_converse(None, skill[0], lang)

    def do_converse(self, utterances, skill_id, lang):
        self.emitter.emit(Message("skill.converse.request", {
            "skill_id": skill_id, "utterances": utterances, "lang": lang}))
        self.waiting = True
        self.result = False
        start_time = time.time()
        t = 0
        while self.waiting and t < 5:
            t = time.time() - start_time
            time.sleep(0.1)
        self.waiting = False
        return self.result

    def handle_converse_response(self, message):
        # id = message.data["skill_id"]
        # no need to crosscheck id because waiting before new request is made
        # no other skill will make this request is safe assumption
        result = message.data["result"]
        self.result = result
        self.waiting = False

    def remove_active_skill(self, skill_id):
        for skill in self.active_skills:
            if skill[0] == skill_id:
                self.active_skills.remove(skill)

    def add_active_skill(self, skill_id):
        # search the list for an existing entry that already contains it
        # and remove that reference
        self.remove_active_skill(skill_id)
        # add skill with timestamp to start of skill_list
        self.active_skills.insert(0, [skill_id, time.time()])

    def update_context(self, intent):
        """ Updates context with keyword from the intent.

        NOTE: This method currently won't handle one_of intent keywords
              since it's not using quite the same format as other intent
              keywords. This is under investigation in adapt, PR pending.

        Args:
            intent: Intent to scan for keywords
        """
        for tag in intent['__tags__']:
            if 'entities' not in tag:
                continue
            context_entity = tag['entities'][0]
            if self.context_greedy:
                self.context_manager.inject_context(context_entity)
            elif context_entity['data'][0][1] in self.context_keywords:
                self.context_manager.inject_context(context_entity)

    def send_metrics(self, intent, context, stopwatch):
        """
        Send timing metrics to the backend.

        NOTE: This only applies to those with Opt In.
        """
        LOG.debug('Sending metric if opt_in is enabled')
        ident = context['ident'] if context else None
        if intent:
            # Recreate skill name from skill id
            parts = intent.get('intent_type', '').split(':')
            intent_type = self.get_skill_name(parts[0])
            if len(parts) > 1:
                intent_type = ':'.join([intent_type] + parts[1:])
            report_timing(ident, 'intent_service', stopwatch,
                          {'intent_type': intent_type})
        else:
            report_timing(ident, 'intent_service', stopwatch,
                          {'intent_type': 'intent_failure'})

    def handle_utterance(self, message):
        """ Main entrypoint for handling user utterances with Mycroft skills

        Monitor the messagebus for 'recognizer_loop:utterance', typically
        generated by a spoken interaction but potentially also from a CLI
        or other method of injecting a 'user utterance' into the system.

        Utterances then work through this sequence to be handled:
        1) Active skills attempt to handle using converse()
        2) Adapt intent handlers
        3) Padatious intent handlers
        4) Other fallbacks

        Args:
            message (Message): The messagebus data
        """
        try:
            # Get language of the utterance
            lang = message.data.get('lang', "en-us")
            utterances = message.data.get('utterances', '')

            stopwatch = Stopwatch()
            with stopwatch:
                # Give active skills an opportunity to handle the utterance
                converse = self._converse(utterances, lang)

                if not converse:
                    # No conversation, use intent system to handle utterance
                    intent = self._adapt_intent_match(utterances, lang)

            if converse:
                # Report that converse handled the intent and return
                ident = message.context['ident'] if message.context else None
                report_timing(ident, 'intent_service', stopwatch,
                              {'intent_type': 'converse'})
                return
            elif intent:
                # Send the message to the intent handler
                reply = message.reply(intent.get('intent_type'), intent)
            else:
                # Allow fallback system to handle utterance
                # NOTE: Padatious intents are handled this way, too
                reply = message.reply('intent_failure',
                                      {'utterance': utterances[0],
                                       'lang': lang})
            self.emitter.emit(reply)
            self.send_metrics(intent, message.context, stopwatch)
        except Exception as e:
            LOG.exception(e)

    def _converse(self, utterances, lang):
        """ Give active skills a chance at the utterance

        Args:
            utterances (list):  list of utterances
            lang (string):      4 letter ISO language code

        Returns:
            bool: True if converse handled it, False if  no skill processes it
        """

        # check for conversation time-out
        self.active_skills = [skill for skill in self.active_skills
                              if time.time() - skill[
                                  1] <= self.converse_timeout * 60]

        # check if any skill wants to handle utterance
        for skill in self.active_skills:
            if self.do_converse(utterances, skill[0], lang):
                # update timestamp, or there will be a timeout where
                # intent stops conversing whether its being used or not
                self.add_active_skill(skill[0])
                return True
        return False

    def _adapt_intent_match(self, utterances, lang):
        """ Run the Adapt engine to search for an matching intent

        Args:
            utterances (list):  list of utterances
            lang (string):      4 letter ISO language code

        Returns:
            Intent structure, or None if no match was found.
        """
        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,
                    include_tags=True,
                    context_manager=self.context_manager))
                # TODO - Should Adapt handle this?
                best_intent['utterance'] = utterance
            except StopIteration:
                # don't show error in log
                continue
            except Exception as e:
                LOG.exception(e)
                continue

        if best_intent and best_intent.get('confidence', 0.0) > 0.0:
            self.update_context(best_intent)
            # update active skills
            skill_id = best_intent['intent_type'].split(":")[0]
            self.add_active_skill(skill_id)
            return best_intent

    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_id = message.data.get('skill_id')
        new_parsers = [
            p for p in self.engine.intent_parsers if
            not p.name.startswith(skill_id)]
        self.engine.intent_parsers = new_parsers

    def handle_add_context(self, message):
        """ Add context

        Args:
            message: data contains the 'context' item to add
                     optionally can include 'word' to be injected as
                     an alias for the context item.
        """
        entity = {'confidence': 1.0}
        context = message.data.get('context')
        word = message.data.get('word') or ''
        # if not a string type try creating a string from it
        if not isinstance(word, str):
            word = str(word)
        entity['data'] = [(word, context)]
        entity['match'] = word
        entity['key'] = word
        self.context_manager.inject_context(entity)

    def handle_remove_context(self, message):
        """ Remove specific context

        Args:
            message: data contains the 'context' item to remove
        """
        context = message.data.get('context')
        if context:
            self.context_manager.remove_context(context)

    def handle_clear_context(self, message):
        """ Clears all keywords from context """
        self.context_manager.clear_context()
예제 #33
0
class IntentService(object):
    def __init__(self, emitter):
        self.config = Configuration.get().get('context', {})
        self.engine = IntentDeterminationEngine()

        # Dictionary for translating a skill id to a name
        self.skill_names = {}
        # Context related intializations
        self.context_keywords = self.config.get('keywords', [])
        self.context_max_frames = self.config.get('max_frames', 3)
        self.context_timeout = self.config.get('timeout', 2)
        self.context_greedy = self.config.get('greedy', False)
        self.context_manager = ContextManager(self.context_timeout)
        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)
        # Context related handlers
        self.emitter.on('add_context', self.handle_add_context)
        self.emitter.on('remove_context', self.handle_remove_context)
        self.emitter.on('clear_context', self.handle_clear_context)
        # Converse method
        self.emitter.on('skill.converse.response',
                        self.handle_converse_response)
        self.emitter.on('mycroft.speech.recognition.unknown',
                        self.reset_converse)
        self.emitter.on('mycroft.skills.loaded', self.update_skill_name_dict)

        def add_active_skill_handler(message):
            self.add_active_skill(message.data['skill_id'])
        self.emitter.on('active_skill_request', add_active_skill_handler)
        self.active_skills = []  # [skill_id , timestamp]
        self.converse_timeout = 5  # minutes to prune active_skills

    def update_skill_name_dict(self, message):
        """
            Messagebus handler, updates dictionary of if to skill name
            conversions.
        """
        self.skill_names[message.data['id']] = message.data['name']

    def get_skill_name(self, skill_id):
        """
            Get skill name from skill ID.

            Args
                skill_id: a skill id as encoded in Intent handlers.

            Returns: (str) Skill name or the skill id if the skill
                     wasn't found in the dict.
        """
        return self.skill_names.get(int(skill_id), skill_id)

    def reset_converse(self, message):
        """Let skills know there was a problem with speech recognition"""
        lang = message.data.get('lang', "en-us")
        for skill in self.active_skills:
            self.do_converse(None, skill[0], lang)

    def do_converse(self, utterances, skill_id, lang):
        self.emitter.emit(Message("skill.converse.request", {
            "skill_id": skill_id, "utterances": utterances, "lang": lang}))
        self.waiting = True
        self.result = False
        start_time = time.time()
        t = 0
        while self.waiting and t < 5:
            t = time.time() - start_time
            time.sleep(0.1)
        self.waiting = False
        return self.result

    def handle_converse_response(self, message):
        # id = message.data["skill_id"]
        # no need to crosscheck id because waiting before new request is made
        # no other skill will make this request is safe assumption
        result = message.data["result"]
        self.result = result
        self.waiting = False

    def remove_active_skill(self, skill_id):
        for skill in self.active_skills:
            if skill[0] == skill_id:
                self.active_skills.remove(skill)

    def add_active_skill(self, skill_id):
        # search the list for an existing entry that already contains it
        # and remove that reference
        self.remove_active_skill(skill_id)
        # add skill with timestamp to start of skill_list
        self.active_skills.insert(0, [skill_id, time.time()])

    def update_context(self, intent):
        """
            updates context with keyword from the intent.

            NOTE: This method currently won't handle one_of intent keywords
                  since it's not using quite the same format as other intent
                  keywords. This is under investigation in adapt, PR pending.

            Args:
                intent: Intent to scan for keywords
        """
        for tag in intent['__tags__']:
            if 'entities' not in tag:
                continue
            context_entity = tag['entities'][0]
            if self.context_greedy:
                self.context_manager.inject_context(context_entity)
            elif context_entity['data'][0][1] in self.context_keywords:
                self.context_manager.inject_context(context_entity)

    def send_metrics(self, intent, context, stopwatch):
        """
            Send timing metrics to the backend.
        """
        LOG.debug('Sending metric')
        ident = context['ident'] if context else None
        if intent:
            # Recreate skill name from skill id
            parts = intent.get('intent_type', '').split(':')
            intent_type = self.get_skill_name(parts[0])
            if len(parts) > 1:
                intent_type = ':'.join([intent_type] + parts[1:])
            report_timing(ident, 'intent_service', stopwatch,
                          {'intent_type': intent_type})
        else:
            report_timing(ident, 'intent_service', stopwatch,
                          {'intent_type': 'intent_failure'})

    def handle_utterance(self, message):
        """
            Messagebus handler for the recognizer_loop:utterance message
        """
        try:
            # Get language of the utterance
            lang = message.data.get('lang', "en-us")
            utterances = message.data.get('utterances', '')

            stopwatch = Stopwatch()
            with stopwatch:
                # Parse the sentence
                converse = self.parse_converse(utterances, lang)
                if not converse:
                    # no skill wants to handle utterance
                    intent = self.parse_utterances(utterances, lang)

            if converse:
                # Report that converse handled the intent and return
                ident = message.context['ident'] if message.context else None
                report_timing(ident, 'intent_service', stopwatch,
                              {'intent_type': 'converse'})
                return
            elif intent:
                # Send the message on to the intent handler
                reply = message.reply(intent.get('intent_type'), intent)
            else:
                # or if no match send sentence to fallback system
                reply = message.reply('intent_failure',
                                      {'utterance': utterances[0],
                                       'lang': lang})
            self.emitter.emit(reply)
            self.send_metrics(intent, message.context, stopwatch)
        except Exception as e:
            LOG.exception(e)

    def parse_converse(self, utterances, lang):
        """
            Converse, check if a recently invoked skill wants to
            handle the utterance and override normal adapt handling.

            Returns: True if converse handled the utterance, else False.
        """

        # check for conversation time-out
        self.active_skills = [skill for skill in self.active_skills
                              if time.time() - skill[
                                  1] <= self.converse_timeout * 60]

        # check if any skill wants to handle utterance
        for skill in self.active_skills:
            if self.do_converse(utterances, skill[0], lang):
                # update timestamp, or there will be a timeout where
                # intent stops conversing whether its being used or not
                self.add_active_skill(skill[0])
                return True
        return False

    def parse_utterances(self, utterances, lang):
        """
            Parse the utteracne using adapt  to find a matching intent.

            Args:
                utterances (list):  list of utterances
                lang (string):      4 letter ISO language code

            Returns: Intent structure, or None if no match was found.
        """
        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,
                    include_tags=True,
                    context_manager=self.context_manager))
                # TODO - Should Adapt handle this?
                best_intent['utterance'] = utterance
            except StopIteration:
                # don't show error in log
                continue
            except Exception as e:
                LOG.exception(e)
                continue

        if best_intent and best_intent.get('confidence', 0.0) > 0.0:
            self.update_context(best_intent)
            # update active skills
            skill_id = int(best_intent['intent_type'].split(":")[0])
            self.add_active_skill(skill_id)
            return best_intent

    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_id = message.data.get('skill_id')
        new_parsers = [
            p for p in self.engine.intent_parsers if
            not p.name.startswith(skill_id)]
        self.engine.intent_parsers = new_parsers

    def handle_add_context(self, message):
        """
            Handles adding context from the message bus.
            The data field must contain a context keyword and
            may contain a word if a specific word should be injected
            as a match for the provided context keyword.

        """
        entity = {'confidence': 1.0}
        context = message.data.get('context')
        word = message.data.get('word') or ''
        # if not a string type try creating a string from it
        if not isinstance(word, basestring):
            word = str(word)
        entity['data'] = [(word, context)]
        entity['match'] = word
        entity['key'] = word
        self.context_manager.inject_context(entity)

    def handle_remove_context(self, message):
        """
            Handles removing context from the message bus. The
            data field must contain the 'context' to remove.
        """
        context = message.data.get('context')
        if context:
            self.context_manager.remove_context(context)

    def handle_clear_context(self, message):
        """
            Clears all keywords from context.
        """
        self.context_manager.clear_context()
예제 #34
0
class VoiceCommands:
    ACTIONS = 'Action'
    NAME = 'Name'
    ACTUATOR_TYPE = 'ActuatorType'

    @typechecked()
    def __init__(self, job_controll: AsyncActuatorCommands,
                 logging: RootLogger):
        self.__job_controll = job_controll
        self.__logging = logging

    def configure(self):
        self.__engine = IntentDeterminationEngine()
        actions = ['on', 'off']
        self.__register_entity(actions, self.ACTIONS)
        locations = ['living', 'kitchen', 'hollway', 'wemo']
        self.__register_entity(locations, self.NAME)
        actuator_types = ['light', 'switch', 'courtains', 'door']
        self.__register_entity(actuator_types, self.ACTUATOR_TYPE)

        actuator_intent = IntentBuilder("ActuatorIntent") \
            .require(self.ACTIONS) \
            .require(self.ACTUATOR_TYPE) \
            .require(self.NAME) \
            .build()
        self.__engine.register_intent_parser(actuator_intent)
        self.__commands_map = [
            {
                'entities': {
                    'name': 'living',
                    'type': 'light'
                },
                'actuator': 'livingLight'
            },
            {
                'entities': {
                    'name': 'living',
                    'type': 'courtains'
                },
                'actuator': 'livingCourtains'
            },
            {
                'entities': {
                    'name': 'hollway',
                    'type': 'light'
                },
                'actuator': 'holwayLight'
            },
            {
                'entities': {
                    'name': 'wemo',
                    'type': 'switch'
                },
                'actuator': 'wemoSwitch1'
            },
        ]

        return self

    @typechecked()
    def execute(self, command: str) -> None:
        command = self.__normalize_command(command)
        for intent in self.__engine.determine_intent(command):
            if intent and intent.get('confidence') > 0:
                self.__logging.info(intent)
                command = self.__get_matching_command(intent)
                self.__run_command(command, intent)

    def __register_entity(self, wordlist, name):
        for action in wordlist:
            self.__engine.register_entity(action, name)

    def __get_matching_command(self, intent):
        for command in self.__commands_map:
            if command['entities']['name'] == intent[self.NAME] and \
                command['entities']['type'] == intent[self.ACTUATOR_TYPE]:
                return command

    def __run_command(self, command, intent):
        if None == command:
            return
        actuator_state = (False, True)[intent[self.ACTIONS] == 'on']
        self.__logging.info('Changin actuator {0} value: {1}'.format(
            command['actuator'], actuator_state))
        self.__job_controll.change_actuator(command['actuator'],
                                            actuator_state)

    def __normalize_command(self, command):
        replaces = [('life', 'light'), ('leaving', 'living'),
                    ('hallway', 'hollway'), ('quarters', 'courtains')]
        for replace in replaces:
            command = re.sub(replace[0], replace[1], command)

        return command
예제 #35
0
class IntentService:
    def __init__(self, bus):
        self.config = Configuration.get().get('context', {})
        self.engine = IntentDeterminationEngine()

        # Dictionary for translating a skill id to a name
        self.skill_names = {}
        # Context related intializations
        self.context_keywords = self.config.get('keywords', [])
        self.context_max_frames = self.config.get('max_frames', 3)
        self.context_timeout = self.config.get('timeout', 2)
        self.context_greedy = self.config.get('greedy', False)
        self.context_manager = ContextManager(self.context_timeout)
        self.bus = bus
        self.bus.on('register_vocab', self.handle_register_vocab)
        self.bus.on('register_intent', self.handle_register_intent)
        self.bus.on('recognizer_loop:utterance', self.handle_utterance)
        self.bus.on('detach_intent', self.handle_detach_intent)
        self.bus.on('detach_skill', self.handle_detach_skill)
        # Context related handlers
        self.bus.on('add_context', self.handle_add_context)
        self.bus.on('remove_context', self.handle_remove_context)
        self.bus.on('clear_context', self.handle_clear_context)
        # Converse method
        self.bus.on('skill.converse.response', self.handle_converse_response)
        self.bus.on('skill.converse.error', self.handle_converse_error)
        self.bus.on('mycroft.speech.recognition.unknown', self.reset_converse)
        self.bus.on('mycroft.skills.loaded', self.update_skill_name_dict)

        def add_active_skill_handler(message):
            self.add_active_skill(message.data['skill_id'])

        self.bus.on('active_skill_request', add_active_skill_handler)
        self.active_skills = []  # [skill_id , timestamp]
        self.converse_timeout = 5  # minutes to prune active_skills
        self.waiting_for_converse = False
        self.converse_result = False
        self.converse_skill_id = ""

        # Intents API
        self.registered_intents = []
        self.registered_vocab = []
        self.bus.on('intent.service.adapt.get', self.handle_get_adapt)
        self.bus.on('intent.service.intent.get', self.handle_get_intent)
        self.bus.on('intent.service.skills.get', self.handle_get_skills)
        self.bus.on('intent.service.active_skills.get',
                    self.handle_get_active_skills)
        self.bus.on('intent.service.adapt.manifest.get', self.handle_manifest)
        self.bus.on('intent.service.adapt.vocab.manifest.get',
                    self.handle_vocab_manifest)

    def update_skill_name_dict(self, message):
        """
            Messagebus handler, updates dictionary of if to skill name
            conversions.
        """
        self.skill_names[message.data['id']] = message.data['name']

    def get_skill_name(self, skill_id):
        """ Get skill name from skill ID.

        Args:
            skill_id: a skill id as encoded in Intent handlers.

        Returns:
            (str) Skill name or the skill id if the skill wasn't found
        """
        return self.skill_names.get(skill_id, skill_id)

    def reset_converse(self, message):
        """Let skills know there was a problem with speech recognition"""
        lang = message.data.get('lang', "en-us")
        set_active_lang(lang)
        for skill in self.active_skills:
            self.do_converse(None, skill[0], lang)

    def do_converse(self, utterances, skill_id, lang, message):
        self.waiting_for_converse = True
        self.converse_result = False
        self.converse_skill_id = skill_id
        self.bus.emit(
            message.reply("skill.converse.request", {
                "skill_id": skill_id,
                "utterances": utterances,
                "lang": lang
            }))
        start_time = time.time()
        t = 0
        while self.waiting_for_converse and t < 5:
            t = time.time() - start_time
            time.sleep(0.1)
        self.waiting_for_converse = False
        self.converse_skill_id = ""
        return self.converse_result

    def handle_converse_error(self, message):
        skill_id = message.data["skill_id"]
        if message.data["error"] == "skill id does not exist":
            self.remove_active_skill(skill_id)
        if skill_id == self.converse_skill_id:
            self.converse_result = False
            self.waiting_for_converse = False

    def handle_converse_response(self, message):
        skill_id = message.data["skill_id"]
        if skill_id == self.converse_skill_id:
            self.converse_result = message.data.get("result", False)
            self.waiting_for_converse = False

    def remove_active_skill(self, skill_id):
        for skill in self.active_skills:
            if skill[0] == skill_id:
                self.active_skills.remove(skill)

    def add_active_skill(self, skill_id):
        # search the list for an existing entry that already contains it
        # and remove that reference
        self.remove_active_skill(skill_id)
        # add skill with timestamp to start of skill_list
        self.active_skills.insert(0, [skill_id, time.time()])

    def update_context(self, intent):
        """ Updates context with keyword from the intent.

        NOTE: This method currently won't handle one_of intent keywords
              since it's not using quite the same format as other intent
              keywords. This is under investigation in adapt, PR pending.

        Args:
            intent: Intent to scan for keywords
        """
        for tag in intent['__tags__']:
            if 'entities' not in tag:
                continue
            context_entity = tag['entities'][0]
            if self.context_greedy:
                self.context_manager.inject_context(context_entity)
            elif context_entity['data'][0][1] in self.context_keywords:
                self.context_manager.inject_context(context_entity)

    def send_metrics(self, intent, context, stopwatch):
        """
        Send timing metrics to the backend.

        NOTE: This only applies to those with Opt In.
        """
        ident = context['ident'] if 'ident' in context else None
        if intent:
            # Recreate skill name from skill id
            parts = intent.get('intent_type', '').split(':')
            intent_type = self.get_skill_name(parts[0])
            if len(parts) > 1:
                intent_type = ':'.join([intent_type] + parts[1:])
            report_timing(ident, 'intent_service', stopwatch,
                          {'intent_type': intent_type})
        else:
            report_timing(ident, 'intent_service', stopwatch,
                          {'intent_type': 'intent_failure'})

    def handle_utterance(self, message):
        """ Main entrypoint for handling user utterances with Mycroft skills

        Monitor the messagebus for 'recognizer_loop:utterance', typically
        generated by a spoken interaction but potentially also from a CLI
        or other method of injecting a 'user utterance' into the system.

        Utterances then work through this sequence to be handled:
        1) Active skills attempt to handle using converse()
        2) Padatious high match intents (conf > 0.95)
        3) Adapt intent handlers
        5) Fallbacks:
           - Padatious near match intents (conf > 0.8)
           - General fallbacks
           - Padatious loose match intents (conf > 0.5)
           - Unknown intent handler

        Args:
            message (Message): The messagebus data
        """
        try:
            # Get language of the utterance
            lang = message.data.get('lang', "en-us")
            set_active_lang(lang)

            utterances = message.data.get('utterances', [])
            # normalize() changes "it's a boy" to "it is a boy", etc.
            norm_utterances = [
                normalize(u.lower(), remove_articles=False) for u in utterances
            ]

            # Build list with raw utterance(s) first, then optionally a
            # normalized version following.
            combined = utterances + list(
                set(norm_utterances) - set(utterances))
            LOG.debug("Utterances: {}".format(combined))

            stopwatch = Stopwatch()
            intent = None
            padatious_intent = None
            with stopwatch:
                # Give active skills an opportunity to handle the utterance
                converse = self._converse(combined, lang, message)

                if not converse:
                    # No conversation, use intent system to handle utterance
                    intent = self._adapt_intent_match(utterances,
                                                      norm_utterances, lang)
                    for utt in combined:
                        _intent = PadatiousService.instance.calc_intent(utt)
                        if _intent:
                            best = padatious_intent.conf if padatious_intent \
                                else 0.0
                            if best < _intent.conf:
                                padatious_intent = _intent
                    LOG.debug("Padatious intent: {}".format(padatious_intent))
                    LOG.debug("    Adapt intent: {}".format(intent))

            if converse:
                # Report that converse handled the intent and return
                LOG.debug("Handled in converse()")
                ident = None
                if message.context and 'ident' in message.context:
                    ident = message.context['ident']
                report_timing(ident, 'intent_service', stopwatch,
                              {'intent_type': 'converse'})
                return
            elif (intent and intent.get('confidence', 0.0) > 0.0 and
                  not (padatious_intent and padatious_intent.conf >= 0.95)):
                # Send the message to the Adapt intent's handler unless
                # Padatious is REALLY sure it was directed at it instead.
                self.update_context(intent)
                # update active skills
                skill_id = intent['intent_type'].split(":")[0]
                self.add_active_skill(skill_id)
                # Adapt doesn't handle context injection for one_of keywords
                # correctly. Workaround this issue if possible.
                try:
                    intent = workaround_one_of_context(intent)
                except LookupError:
                    LOG.error('Error during workaround_one_of_context')
                reply = message.reply(intent.get('intent_type'), intent)
            else:
                # Allow fallback system to handle utterance
                # NOTE: A matched padatious_intent is handled this way, too
                # TODO: Need to redefine intent_failure when STT can return
                #       multiple hypothesis -- i.e. len(utterances) > 1
                reply = message.reply(
                    'intent_failure', {
                        'utterance': utterances[0],
                        'norm_utt': norm_utterances[0],
                        'lang': lang
                    })
            self.bus.emit(reply)
            self.send_metrics(intent, message.context, stopwatch)
        except Exception as e:
            LOG.exception(e)

    def _converse(self, utterances, lang, message):
        """ Give active skills a chance at the utterance

        Args:
            utterances (list):  list of utterances
            lang (string):      4 letter ISO language code
            message (Message):  message to use to generate reply

        Returns:
            bool: True if converse handled it, False if  no skill processes it
        """

        # check for conversation time-out
        self.active_skills = [
            skill for skill in self.active_skills
            if time.time() - skill[1] <= self.converse_timeout * 60
        ]

        # check if any skill wants to handle utterance
        for skill in self.active_skills:
            if self.do_converse(utterances, skill[0], lang, message):
                # update timestamp, or there will be a timeout where
                # intent stops conversing whether its being used or not
                self.add_active_skill(skill[0])
                return True
        return False

    def _adapt_intent_match(self, raw_utt, norm_utt, lang):
        """ Run the Adapt engine to search for an matching intent

        Args:
            raw_utt (list):  list of utterances
            norm_utt (list): same list of utterances, normalized
            lang (string):   language code, e.g "en-us"

        Returns:
            Intent structure, or None if no match was found.
        """
        best_intent = None

        def take_best(intent, utt):
            nonlocal best_intent
            best = best_intent.get('confidence', 0.0) if best_intent else 0.0
            conf = intent.get('confidence', 0.0)
            if conf > best:
                best_intent = intent
                # TODO - Shouldn't Adapt do this?
                best_intent['utterance'] = utt

        for idx, utt in enumerate(raw_utt):
            try:
                intents = [
                    i for i in self.engine.determine_intent(
                        utt,
                        100,
                        include_tags=True,
                        context_manager=self.context_manager)
                ]
                if intents:
                    take_best(intents[0], utt)

                # Also test the normalized version, but set the utterance to
                # the raw version so skill has access to original STT
                norm_intents = [
                    i for i in self.engine.determine_intent(
                        norm_utt[idx],
                        100,
                        include_tags=True,
                        context_manager=self.context_manager)
                ]
                if norm_intents:
                    take_best(norm_intents[0], utt)
            except Exception as e:
                LOG.exception(e)
        return best_intent

    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)
        self.registered_vocab.append(message.data)

    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_id = message.data.get('skill_id')
        new_parsers = [
            p for p in self.engine.intent_parsers
            if not p.name.startswith(skill_id)
        ]
        self.engine.intent_parsers = new_parsers

    def handle_add_context(self, message):
        """ Add context

        Args:
            message: data contains the 'context' item to add
                     optionally can include 'word' to be injected as
                     an alias for the context item.
        """
        entity = {'confidence': 1.0}
        context = message.data.get('context')
        word = message.data.get('word') or ''
        origin = message.data.get('origin') or ''
        # if not a string type try creating a string from it
        if not isinstance(word, str):
            word = str(word)
        entity['data'] = [(word, context)]
        entity['match'] = word
        entity['key'] = word
        entity['origin'] = origin
        self.context_manager.inject_context(entity)

    def handle_remove_context(self, message):
        """ Remove specific context

        Args:
            message: data contains the 'context' item to remove
        """
        context = message.data.get('context')
        if context:
            self.context_manager.remove_context(context)

    def handle_clear_context(self, message):
        """ Clears all keywords from context """
        self.context_manager.clear_context()

    def handle_get_adapt(self, message):
        utterance = message.data["utterance"]
        lang = message.data.get("lang", "en-us")
        norm = normalize(utterance, lang, remove_articles=False)
        intent = self._adapt_intent_match([utterance], [norm], lang)
        self.bus.emit(
            message.reply("intent.service.adapt.reply", {"intent": intent}))

    def handle_get_intent(self, message):
        utterance = message.data["utterance"]
        lang = message.data.get("lang", "en-us")
        norm = normalize(utterance, lang, remove_articles=False)
        intent = self._adapt_intent_match([utterance], [norm], lang)
        # Adapt intent's handler is used unless
        # Padatious is REALLY sure it was directed at it instead.
        padatious_intent = PadatiousService.instance.calc_intent(utterance)
        if not padatious_intent and norm != utterance:
            padatious_intent = PadatiousService.instance.calc_intent(norm)
        if intent is None or (padatious_intent
                              and padatious_intent.conf >= 0.95):
            intent = padatious_intent.__dict__
        self.bus.emit(
            message.reply("intent.service.intent.reply", {"intent": intent}))

    def handle_get_skills(self, message):
        self.bus.emit(
            message.reply("intent.service.skills.reply",
                          {"skills": self.skill_names}))

    def handle_get_active_skills(self, message):
        self.bus.emit(
            message.reply("intent.service.active_skills.reply",
                          {"skills": [s[0] for s in self.active_skills]}))

    def handle_manifest(self, message):
        self.bus.emit(
            message.reply("intent.service.adapt.manifest",
                          {"intents": self.registered_intents}))

    def handle_vocab_manifest(self, message):
        self.bus.emit(
            message.reply("intent.service.adapt.vocab.manifest",
                          {"vocab": self.registered_vocab}))
예제 #36
0
greeting_response = [
    'hi, how are you', 'hello, any physical illness',
    'hii, nice to hear from you', 'Hello', 'Howdy', "Hi", "hello"
]

greeting_word2 = ['thanks', 'thanks you', 'okay', 'nice']
greeting_response2 = [
    'You are welcome', 'Happy to help', 'Have a nice day', 'get well soon'
]

for word in greeting_word:
    engine.register_entity(word, "greeting")
intent1 = IntentBuilder("greetingIntent")\
    .require("greeting")\
    .build()
engine.register_intent_parser(intent1)
for word in greeting_word2:
    engine.register_entity(word, "greeting2")
intent2 = IntentBuilder("greeting2Intent")\
    .require("greeting2")\
    .build()
engine.register_intent_parser(intent2)

fever_word = ['temperature', 'fever', 'hot body', 'body hot', 'heat']
for word in fever_word:
    engine.register_entity(word, "fever")
intentfeaver = IntentBuilder("feverIntent")\
    .require("fever")\
    .build()
engine.register_intent_parser(intentfeaver)
예제 #37
0
from adapt.intent import IntentBuilder
from adapt.engine import IntentDeterminationEngine

engine = IntentDeterminationEngine()

schema = json.loads(sys.argv[1])

for entity in schema["entities"]:
	if entity["type"] == "string":
		for value in entity["values"]:
			engine.register_entity(value, entity["name"])
	elif entity["type"] == "regex":
		engine.register_regex_entity(entity["pattern"])

for intent in schema["intents"]:
	ib = IntentBuilder(intent["name"].encode("utf-8"))
	for requirement in intent["requirements"]:
		ib.require(requirement["entity"], requirement["attribute"])
	for optional in intent["optionals"]:
		ib.optionally(optional["entity"], optional["attribute"])
	engine.register_intent_parser(ib.build())

if __name__ == "__main__":
	while True:
		line = sys.stdin.readline()
		query = json.loads(line)
		intents = list(engine.determine_intent(query["input"]))
		response = {"intents": intents}
		print(json.dumps(response))
		sys.stdout.flush()
예제 #38
0
class IntentSkill(BoomerSkill):
    def __init__(self):
        BoomerSkill.__init__(self, name="IntentSkill")
        self.engine = IntentDeterminationEngine()

    def initialize(self):
        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)

    def handle_utterance(self, message):
        timer = Stopwatch()
        timer.start()

        metrics = MetricsAggregator()
        utterances = message.data.get('utterances', '')

        best_intent = None

        for utterance in utterances:
            metrics.increment("utterances.count")
            for intent in self.engine.determine_intent(
                    utterance, num_results=100):
                metrics.increment("intents.count")
                intent['utterance'] = utterance
                best_confidence = best_intent.get('confidence') \
                    if best_intent else 0.0
                cur_confidence = intent.get('confidence', 0.0)
                if best_confidence < cur_confidence:
                    best_intent = intent

        if best_intent and best_intent.get('confidence', 0.0) > 0.0:
            reply = message.reply(
                best_intent.get('intent_type'), data=best_intent)
            self.emitter.emit(reply)
        elif len(utterances) == 1:
            self.emitter.emit(
                Message("intent_failure",
                        data={"utterance": utterances[0]}))
        else:
            self.emitter.emit(
                Message("multi_utterance_intent_failure",
                        data={"utterances": utterances}))
        metrics.timer("parse.time", timer.stop())
        metrics.flush()

    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 stop(self):
        pass
예제 #39
0
    
]

for et in error_types:
    engine.register_entity(et, "ErrorType")

# create regex to parse out locations
#engine.register_regex_entity("in (?P<Location>.*)")

# structure intent
error_intent = IntentBuilder("ErrorIntent")\
    .require("ErrorKeyword")\
    .optionally("ErrorType")\
    .build()

engine.register_intent_parser(error_intent)

@app.route('/', methods=['GET'])
def parseString():
    string = request.args.get('string')
    for intent in engine.determine_intent(string):
        if intent.get('confidence') > 0:
            print intent.get("ErrorType")
            if intent.get("ErrorType") == "E16":
                return jsonify({"msg":"Transmission might be temporarily suspended. Press MENU on your remote control, then 4 to check your Mail Messages. If you have a notification from us to pay your account, then payment needs to be made before services can be reactivated. If your account is not suspended, then SMS E16 followed by your Smartcard number to 32472 or visit My DStv to clear the error code."})
            elif intent.get("ErrorType") == "E17":
                return jsonify({"msg":"Ensure Smartcard is inserted in the decoder and either: SMS E17 + Smartcard number to 32472 Reset the service yourself by logging into My DStv and fix errors. Use the Voice Self Help option through your local DStv Call Centre."})
            elif intent.get("ErrorType") == "E19":
                return jsonify({"msg":"Please wait a few minutes for your subscription status to be verified. Please contact your nearest DStv Call Centre if the message is not cleared in two minutes."})
            elif intent.get("ErrorType") == "E30":
                return jsonify({"msg":"Please check that the cables from the satellite dish are securely connected to the correct inputs on the back of the decoder. Then switch the decoder off at the  plug, wait 10 seconds, and switch it back on again. If this error is not cleared, visit Self Service on www.dstv.com for troubleshooting steps or contact the DStv Call Centre."})
예제 #40
0
class IntentService(object):
    def __init__(self, bus):
        self.config = Configuration.get().get('context', {})
        self.engine = IntentDeterminationEngine()

        # Dictionary for translating a skill id to a name
        self.skill_names = {}
        # Context related intializations
        self.context_keywords = self.config.get('keywords', [])
        self.context_max_frames = self.config.get('max_frames', 3)
        self.context_timeout = self.config.get('timeout', 2)
        self.context_greedy = self.config.get('greedy', False)
        self.context_manager = ContextManager(self.context_timeout)
        self.bus = bus
        self.bus.on('register_vocab', self.handle_register_vocab)
        self.bus.on('register_intent', self.handle_register_intent)
        self.bus.on('recognizer_loop:utterance', self.handle_utterance)
        self.bus.on('detach_intent', self.handle_detach_intent)
        self.bus.on('detach_skill', self.handle_detach_skill)
        # Context related handlers
        self.bus.on('add_context', self.handle_add_context)
        self.bus.on('remove_context', self.handle_remove_context)
        self.bus.on('clear_context', self.handle_clear_context)
        # Converse method
        self.bus.on('skill.converse.response', self.handle_converse_response)
        self.bus.on('skill.converse.error', self.handle_converse_error)
        self.bus.on('mycroft.speech.recognition.unknown', self.reset_converse)
        self.bus.on('mycroft.skills.loaded', self.update_skill_name_dict)

        def add_active_skill_handler(message):
            self.add_active_skill(message.data['skill_id'])
        self.bus.on('active_skill_request', add_active_skill_handler)
        self.active_skills = []  # [skill_id , timestamp]
        self.converse_timeout = 5  # minutes to prune active_skills
        self.waiting_for_converse = False
        self.converse_result = False
        self.converse_skill_id = ""

    def update_skill_name_dict(self, message):
        """
            Messagebus handler, updates dictionary of if to skill name
            conversions.
        """
        self.skill_names[message.data['id']] = message.data['name']

    def get_skill_name(self, skill_id):
        """ Get skill name from skill ID.

        Args:
            skill_id: a skill id as encoded in Intent handlers.

        Returns:
            (str) Skill name or the skill id if the skill wasn't found
        """
        return self.skill_names.get(skill_id, skill_id)

    def reset_converse(self, message):
        """Let skills know there was a problem with speech recognition"""
        lang = message.data.get('lang', "en-us")
        for skill in self.active_skills:
            self.do_converse(None, skill[0], lang)

    def do_converse(self, utterances, skill_id, lang):
        self.waiting_for_converse = True
        self.converse_result = False
        self.converse_skill_id = skill_id
        self.bus.emit(Message("skill.converse.request", {
            "skill_id": skill_id, "utterances": utterances, "lang": lang}))
        start_time = time.time()
        t = 0
        while self.waiting_for_converse and t < 5:
            t = time.time() - start_time
            time.sleep(0.1)
        self.waiting_for_converse = False
        self.converse_skill_id = ""
        return self.converse_result

    def handle_converse_error(self, message):
        skill_id = message.data["skill_id"]
        if message.data["error"] == "skill id does not exist":
            self.remove_active_skill(skill_id)
        if skill_id == self.converse_skill_id:
            self.converse_result = False
            self.waiting_for_converse = False

    def handle_converse_response(self, message):
        skill_id = message.data["skill_id"]
        if skill_id == self.converse_skill_id:
            self.converse_result = message.data.get("result", False)
            self.waiting_for_converse = False

    def remove_active_skill(self, skill_id):
        for skill in self.active_skills:
            if skill[0] == skill_id:
                self.active_skills.remove(skill)

    def add_active_skill(self, skill_id):
        # search the list for an existing entry that already contains it
        # and remove that reference
        self.remove_active_skill(skill_id)
        # add skill with timestamp to start of skill_list
        self.active_skills.insert(0, [skill_id, time.time()])

    def update_context(self, intent):
        """ Updates context with keyword from the intent.

        NOTE: This method currently won't handle one_of intent keywords
              since it's not using quite the same format as other intent
              keywords. This is under investigation in adapt, PR pending.

        Args:
            intent: Intent to scan for keywords
        """
        for tag in intent['__tags__']:
            if 'entities' not in tag:
                continue
            context_entity = tag['entities'][0]
            if self.context_greedy:
                self.context_manager.inject_context(context_entity)
            elif context_entity['data'][0][1] in self.context_keywords:
                self.context_manager.inject_context(context_entity)

    def send_metrics(self, intent, context, stopwatch):
        """
        Send timing metrics to the backend.

        NOTE: This only applies to those with Opt In.
        """
        ident = context['ident'] if context else None
        if intent:
            # Recreate skill name from skill id
            parts = intent.get('intent_type', '').split(':')
            intent_type = self.get_skill_name(parts[0])
            if len(parts) > 1:
                intent_type = ':'.join([intent_type] + parts[1:])
            report_timing(ident, 'intent_service', stopwatch,
                          {'intent_type': intent_type})
        else:
            report_timing(ident, 'intent_service', stopwatch,
                          {'intent_type': 'intent_failure'})

    def handle_utterance(self, message):
        """ Main entrypoint for handling user utterances with Mycroft skills

        Monitor the messagebus for 'recognizer_loop:utterance', typically
        generated by a spoken interaction but potentially also from a CLI
        or other method of injecting a 'user utterance' into the system.

        Utterances then work through this sequence to be handled:
        1) Active skills attempt to handle using converse()
        2) Adapt intent handlers
        3) Padatious intent handlers
        4) Other fallbacks

        Args:
            message (Message): The messagebus data
        """
        try:
            # Get language of the utterance
            lang = message.data.get('lang', "en-us")
            utterances = message.data.get('utterances', '')

            stopwatch = Stopwatch()
            with stopwatch:
                # Give active skills an opportunity to handle the utterance
                converse = self._converse(utterances, lang)

                if not converse:
                    # No conversation, use intent system to handle utterance
                    intent = self._adapt_intent_match(utterances, lang)
                    padatious_intent = PadatiousService.instance.calc_intent(
                                        utterances[0])

            if converse:
                # Report that converse handled the intent and return
                ident = message.context['ident'] if message.context else None
                report_timing(ident, 'intent_service', stopwatch,
                              {'intent_type': 'converse'})
                return
            elif intent and not (padatious_intent and
                                 padatious_intent.conf >= 0.95):
                # Send the message to the Adapt intent's handler unless
                # Padatious is REALLY sure it was directed at it instead.
                reply = message.reply(intent.get('intent_type'), intent)
            else:
                # Allow fallback system to handle utterance
                # NOTE: Padatious intents are handled this way, too
                reply = message.reply('intent_failure',
                                      {'utterance': utterances[0],
                                       'lang': lang})
            self.bus.emit(reply)
            self.send_metrics(intent, message.context, stopwatch)
        except Exception as e:
            LOG.exception(e)

    def _converse(self, utterances, lang):
        """ Give active skills a chance at the utterance

        Args:
            utterances (list):  list of utterances
            lang (string):      4 letter ISO language code

        Returns:
            bool: True if converse handled it, False if  no skill processes it
        """

        # check for conversation time-out
        self.active_skills = [skill for skill in self.active_skills
                              if time.time() - skill[
                                  1] <= self.converse_timeout * 60]

        # check if any skill wants to handle utterance
        for skill in self.active_skills:
            if self.do_converse(utterances, skill[0], lang):
                # update timestamp, or there will be a timeout where
                # intent stops conversing whether its being used or not
                self.add_active_skill(skill[0])
                return True
        return False

    def _adapt_intent_match(self, utterances, lang):
        """ Run the Adapt engine to search for an matching intent

        Args:
            utterances (list):  list of utterances
            lang (string):      4 letter ISO language code

        Returns:
            Intent structure, or None if no match was found.
        """
        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,
                    include_tags=True,
                    context_manager=self.context_manager))
                # TODO - Should Adapt handle this?
                best_intent['utterance'] = utterance
            except StopIteration:
                # don't show error in log
                continue
            except Exception as e:
                LOG.exception(e)
                continue

        if best_intent and best_intent.get('confidence', 0.0) > 0.0:
            self.update_context(best_intent)
            # update active skills
            skill_id = best_intent['intent_type'].split(":")[0]
            self.add_active_skill(skill_id)
            # adapt doesn't handle context injection for one_of keywords
            # correctly. Workaround this issue if possible.
            try:
                best_intent = workaround_one_of_context(best_intent)
            except LookupError:
                LOG.error('Error during workaround_one_of_context')
            return best_intent

    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_id = message.data.get('skill_id')
        new_parsers = [
            p for p in self.engine.intent_parsers if
            not p.name.startswith(skill_id)]
        self.engine.intent_parsers = new_parsers

    def handle_add_context(self, message):
        """ Add context

        Args:
            message: data contains the 'context' item to add
                     optionally can include 'word' to be injected as
                     an alias for the context item.
        """
        entity = {'confidence': 1.0}
        context = message.data.get('context')
        word = message.data.get('word') or ''
        origin = message.data.get('origin') or ''
        # if not a string type try creating a string from it
        if not isinstance(word, str):
            word = str(word)
        entity['data'] = [(word, context)]
        entity['match'] = word
        entity['key'] = word
        entity['origin'] = origin
        self.context_manager.inject_context(entity)

    def handle_remove_context(self, message):
        """ Remove specific context

        Args:
            message: data contains the 'context' item to remove
        """
        context = message.data.get('context')
        if context:
            self.context_manager.remove_context(context)

    def handle_clear_context(self, message):
        """ Clears all keywords from context """
        self.context_manager.clear_context()
예제 #41
0
class IntentService(object):
    def __init__(self, emitter):
        self.config = Configuration.get().get('context', {})
        self.engine = IntentDeterminationEngine()
        self.context_keywords = self.config.get('keywords', [])
        self.context_max_frames = self.config.get('max_frames', 3)
        self.context_timeout = self.config.get('timeout', 2)
        self.context_greedy = self.config.get('greedy', False)
        self.context_manager = ContextManager(self.context_timeout)
        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)
        # Context related handlers
        self.emitter.on('add_context', self.handle_add_context)
        self.emitter.on('remove_context', self.handle_remove_context)
        self.emitter.on('clear_context', self.handle_clear_context)
        # Converse method
        self.emitter.on('skill.converse.response',
                        self.handle_converse_response)
        self.active_skills = []  # [skill_id , timestamp]
        self.converse_timeout = 5  # minutes to prune active_skills

    def do_converse(self, utterances, skill_id, lang):
        self.emitter.emit(Message("skill.converse.request", {
            "skill_id": skill_id, "utterances": utterances, "lang": lang}))
        self.waiting = True
        self.result = False
        start_time = time.time()
        t = 0
        while self.waiting and t < 5:
            t = time.time() - start_time
            time.sleep(0.1)
        self.waiting = False
        return self.result

    def handle_converse_response(self, message):
        # id = message.data["skill_id"]
        # no need to crosscheck id because waiting before new request is made
        # no other skill will make this request is safe assumption
        result = message.data["result"]
        self.result = result
        self.waiting = False

    def remove_active_skill(self, skill_id):
        for skill in self.active_skills:
            if skill[0] == skill_id:
                self.active_skills.remove(skill)

    def add_active_skill(self, skill_id):
        # search the list for an existing entry that already contains it
        # and remove that reference
        self.remove_active_skill(skill_id)
        # add skill with timestamp to start of skill_list
        self.active_skills.insert(0, [skill_id, time.time()])

    def update_context(self, intent):
        """
            updates context with keyword from the intent.

            NOTE: This method currently won't handle one_of intent keywords
                  since it's not using quite the same format as other intent
                  keywords. This is under investigation in adapt, PR pending.

            Args:
                intent: Intent to scan for keywords
        """
        for tag in intent['__tags__']:
            if 'entities' not in tag:
                continue
            context_entity = tag['entities'][0]
            if self.context_greedy:
                self.context_manager.inject_context(context_entity)
            elif context_entity['data'][0][1] in self.context_keywords:
                self.context_manager.inject_context(context_entity)

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

        # check for conversation time-out
        self.active_skills = [skill for skill in self.active_skills
                              if time.time() - skill[
                                  1] <= self.converse_timeout * 60]

        # check if any skill wants to handle utterance
        for skill in self.active_skills:
            if self.do_converse(utterances, skill[0], lang):
                # update timestamp, or there will be a timeout where
                # intent stops conversing whether its being used or not
                self.add_active_skill(skill[0])
                return

        # no skill wants to handle utterance
        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,
                    include_tags=True,
                    context_manager=self.context_manager))
                # TODO - Should Adapt handle this?
                best_intent['utterance'] = utterance
            except StopIteration:
                # don't show error in log
                continue
            except e:
                LOG.exception(e)
                continue

        if best_intent and best_intent.get('confidence', 0.0) > 0.0:
            self.update_context(best_intent)
            reply = message.reply(
                best_intent.get('intent_type'), best_intent)
            self.emitter.emit(reply)
            # update active skills
            skill_id = int(best_intent['intent_type'].split(":")[0])
            self.add_active_skill(skill_id)

        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):
        print "Registering: " + str(message.data)
        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_id = message.data.get('skill_id')
        new_parsers = [
            p for p in self.engine.intent_parsers if
            not p.name.startswith(skill_id)]
        self.engine.intent_parsers = new_parsers

    def handle_add_context(self, message):
        """
            Handles adding context from the message bus.
            The data field must contain a context keyword and
            may contain a word if a specific word should be injected
            as a match for the provided context keyword.

        """
        entity = {'confidence': 1.0}
        context = message.data.get('context')
        word = message.data.get('word') or ''
        # if not a string type try creating a string from it
        if not isinstance(word, basestring):
            word = str(word)
        entity['data'] = [(word, context)]
        entity['match'] = word
        entity['key'] = word
        self.context_manager.inject_context(entity)

    def handle_remove_context(self, message):
        """
            Handles removing context from the message bus. The
            data field must contain the 'context' to remove.
        """
        context = message.data.get('context')
        if context:
            self.context_manager.remove_context(context)

    def handle_clear_context(self, message):
        """
            Clears all keywords from context.
        """
        self.context_manager.clear_context()
예제 #42
0
    engine.register_entity(d, "DayKeyword")

# structure intent
car_intent = IntentBuilder("CarIntent")\
    .require("CarTypeKeyword")\
    .optionally("MonthKeyword")\
    .optionally("DayKeyword")\
    .require("Location")\
    .build()


for loc in locations:
    engine.register_entity(loc, "Location")


engine.register_intent_parser(car_intent)

@app.route('/', methods=['GET'])
def parseString():
    string = request.args.get('string')
    for intent in engine.determine_intent(string):
        if intent.get('confidence') > 0:
            # Get the location code from the parsed intent
            locationKeyword = intent["Location"]
            loccode = loccodes[locationKeyword]

            # get the dates
            year = 2017
            daynum = intent["DayKeyword"][:-2]
            month = intent["MonthKeyword"]
            fromdatestr = str(daynum) + "/" + month + "/" + str(year)
예제 #43
0
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 as 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)
        elif len(utterances) == 1:
            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')
        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
class IntentService(object):
    def __init__(self, bus):
        self.config = Configuration.get().get('context', {})
        self.engine = IntentDeterminationEngine()

        # Dictionary for translating a skill id to a name
        self.skill_names = {}
        # Context related intializations
        self.context_keywords = self.config.get('keywords', [])
        self.context_max_frames = self.config.get('max_frames', 3)
        self.context_timeout = self.config.get('timeout', 2)
        self.context_greedy = self.config.get('greedy', False)
        self.context_manager = ContextManager(self.context_timeout)
        self.bus = bus
        self.bus.on('register_vocab', self.handle_register_vocab)
        self.bus.on('register_intent', self.handle_register_intent)
        self.bus.on('recognizer_loop:utterance', self.handle_utterance)
        self.bus.on('detach_intent', self.handle_detach_intent)
        self.bus.on('detach_skill', self.handle_detach_skill)
        # Context related handlers
        self.bus.on('add_context', self.handle_add_context)
        self.bus.on('remove_context', self.handle_remove_context)
        self.bus.on('clear_context', self.handle_clear_context)
        # Converse method
        self.bus.on('skill.converse.response', self.handle_converse_response)
        self.bus.on('skill.converse.error', self.handle_converse_error)
        self.bus.on('mycroft.speech.recognition.unknown', self.reset_converse)
        self.bus.on('mycroft.skills.loaded', self.update_skill_name_dict)

        def add_active_skill_handler(message):
            self.add_active_skill(message.data['skill_id'])

        self.bus.on('active_skill_request', add_active_skill_handler)
        self.active_skills = []  # [skill_id , timestamp]
        self.converse_timeout = 5  # minutes to prune active_skills
        self.waiting_for_converse = False
        self.converse_result = False
        self.converse_skill_id = ""

    def update_skill_name_dict(self, message):
        """
            Messagebus handler, updates dictionary of if to skill name
            conversions.
        """
        self.skill_names[message.data['id']] = message.data['name']

    def get_skill_name(self, skill_id):
        """ Get skill name from skill ID.

        Args:
            skill_id: a skill id as encoded in Intent handlers.

        Returns:
            (str) Skill name or the skill id if the skill wasn't found
        """
        return self.skill_names.get(skill_id, skill_id)

    def reset_converse(self, message):
        """Let skills know there was a problem with speech recognition"""
        lang = message.data.get('lang', "en-us")
        for skill in self.active_skills:
            self.do_converse(None, skill[0], lang)

    def do_converse(self, utterances, skill_id, lang):
        self.waiting_for_converse = True
        self.converse_result = False
        self.converse_skill_id = skill_id
        self.bus.emit(
            Message("skill.converse.request", {
                "skill_id": skill_id,
                "utterances": utterances,
                "lang": lang
            }))
        start_time = time.time()
        t = 0
        while self.waiting_for_converse and t < 5:
            t = time.time() - start_time
            time.sleep(0.1)
        self.waiting_for_converse = False
        self.converse_skill_id = ""
        return self.converse_result

    def handle_converse_error(self, message):
        skill_id = message.data["skill_id"]
        if message.data["error"] == "skill id does not exist":
            self.remove_active_skill(skill_id)
        if skill_id == self.converse_skill_id:
            self.converse_result = False
            self.waiting_for_converse = False

    def handle_converse_response(self, message):
        skill_id = message.data["skill_id"]
        if skill_id == self.converse_skill_id:
            self.converse_result = message.data.get("result", False)
            self.waiting_for_converse = False

    def remove_active_skill(self, skill_id):
        for skill in self.active_skills:
            if skill[0] == skill_id:
                self.active_skills.remove(skill)

    def add_active_skill(self, skill_id):
        # search the list for an existing entry that already contains it
        # and remove that reference
        self.remove_active_skill(skill_id)
        # add skill with timestamp to start of skill_list
        self.active_skills.insert(0, [skill_id, time.time()])

    def update_context(self, intent):
        """ Updates context with keyword from the intent.

        NOTE: This method currently won't handle one_of intent keywords
              since it's not using quite the same format as other intent
              keywords. This is under investigation in adapt, PR pending.

        Args:
            intent: Intent to scan for keywords
        """
        for tag in intent['__tags__']:
            if 'entities' not in tag:
                continue
            context_entity = tag['entities'][0]
            if self.context_greedy:
                self.context_manager.inject_context(context_entity)
            elif context_entity['data'][0][1] in self.context_keywords:
                self.context_manager.inject_context(context_entity)

    def send_metrics(self, intent, context, stopwatch):
        """
        Send timing metrics to the backend.

        NOTE: This only applies to those with Opt In.
        """
        ident = context['ident'] if context else None
        if intent:
            # Recreate skill name from skill id
            parts = intent.get('intent_type', '').split(':')
            intent_type = self.get_skill_name(parts[0])
            if len(parts) > 1:
                intent_type = ':'.join([intent_type] + parts[1:])
            report_timing(ident, 'intent_service', stopwatch,
                          {'intent_type': intent_type})
        else:
            report_timing(ident, 'intent_service', stopwatch,
                          {'intent_type': 'intent_failure'})

    def handle_utterance(self, message):
        """ Main entrypoint for handling user utterances with Mycroft skills

        Monitor the messagebus for 'recognizer_loop:utterance', typically
        generated by a spoken interaction but potentially also from a CLI
        or other method of injecting a 'user utterance' into the system.

        Utterances then work through this sequence to be handled:
        1) Active skills attempt to handle using converse()
        2) Adapt intent handlers
        3) Padatious intent handlers
        4) Other fallbacks

        Args:
            message (Message): The messagebus data
        """

        # JN: Code borrowed from get_scheduled_event_status() in core.py
        completed_callback = False
        completed_status = 'failed'  # assume fail

        def completion_handler(message):  #JN
            nonlocal completed_callback
            nonlocal completed_status

            LOG.debug("Calback called: " + message.serialize())
            LOG.debug('   type ' + str(type(message)))
            if message.data is not None:
                completed_status = message.data['status']
                LOG.debug('Completed status is ' + completed_status)
            completed_callback = True

        def wait_for_reply():  #JN
            nonlocal completed_callback
            num_tries = 0  # wait upto 30 secs. weather takes e.g. 8 seconds

            LOG.debug('Waiting for reply, completed callback is ' +
                      str(completed_callback))

            while completed_callback is False and num_tries < 300:
                #LOG.info('Sleepiong')
                time.sleep(0.1)
                num_tries += 1
            LOG.debug('Waited for reply, num_tries is ' + str(num_tries))
            LOG.debug('   completed callback is ' + str(completed_callback))
            completed_callback = False  # for next time

        try:
            # Get language of the utterance
            lang = message.data.get('lang', "en-us")
            utterances = message.data.get('utterances', '')

            self.bus.on('skill.handler.complete', completion_handler)

            #JN:  stopwatch doesn't seem to be used, so removed the with stopwatch...
            stopwatch = Stopwatch()

            #JN:  Give active skills an opportunity to handle the utterance
            converse = self._converse(utterances, lang)

            #JN:  code moved to here, finishes the converse stuff
            if converse:
                # Report that converse handled the intent and return
                LOG.debug('Converse handling intent')
                ident = message.context['ident'] if message.context else None
                report_timing(ident, 'intent_service', stopwatch,
                              {'intent_type': 'converse'})
                return

            # if not converse: - redundant
            # No conversation, use intent system to handle utterance
            for intent in self._adapt_intent_match(utterances,
                                                   lang):  # JN uses generator
                padatious_intent = PadatiousService.instance.calc_intent(
                    utterances[0])

                if intent and not (padatious_intent
                                   and padatious_intent.conf >= 0.95):
                    # Send the message to the Adapt intent's handler unless
                    # Padatious is REALLY sure it was directed at it instead.
                    reply = message.reply(intent.get('intent_type'), intent)
                else:
                    # Allow fallback system to handle utterance
                    # NOTE: Padatious intents are handled this way, too
                    LOG.info('Pedatious handing or failure?')
                    reply = message.reply('intent_failure', {
                        'utterance': utterances[0],
                        'lang': lang
                    })
                LOG.debug('Intent bus call msg ' + reply.serialize())
                self.bus.emit(reply)
                self.send_metrics(intent, message.context, stopwatch)

                wait_for_reply()

                if completed_status == 'succeeded':
                    # we are finished now with this utterance
                    LOG.debug('intent succeeded, utterance handled by ' +
                              str(intent))
                    self.bus.remove('skill.handler.complete',
                                    completion_handler)
                    return
                else:
                    LOG.debug('intent failed, trying next one ' + str(intent))

            LOG.info('Intent loop finished')
            # we couldn't find a successful handler
            # TODO: a handler that says why the semantics of every intent failed
            # rather than generic messages
            reply = message.reply('intent_failure', {
                'utterance': utterances[0],
                'lang': lang
            })
            self.bus.emit(reply)
            self.bus.remove('skill.handler.complete', completion_handler)

        except Exception as e:
            LOG.exception(e)

    def _converse(self, utterances, lang):
        """ Give active skills a chance at the utterance

        Args:
            utterances (list):  list of utterances
            lang (string):      4 letter ISO language code

        Returns:
            bool: True if converse handled it, False if  no skill processes it
        """

        # check for conversation time-out
        self.active_skills = [
            skill for skill in self.active_skills
            if time.time() - skill[1] <= self.converse_timeout * 60
        ]

        # check if any skill wants to handle utterance
        for skill in self.active_skills:
            if self.do_converse(utterances, skill[0], lang):
                # update timestamp, or there will be a timeout where
                # intent stops conversing whether its being used or not
                self.add_active_skill(skill[0])
                return True
        return False

    def _adapt_intent_match(self, utterances, lang):
        """ Run the Adapt engine to search for an matching intent

        Args:
            utterances (list):  list of utterances
            lang (string):      4 letter ISO language code

        Returns:
            Intent structure, or None if no match was found.
        """

        best_intent = None

        for utterance in utterances:
            try:
                # normalize() changes "it's a boy" to "it is boy", etc.
                normal_utterance = normalize(utterance, lang)
                #best_intent = next(self.engine.determine_intent(
                #    normal_utterance, 100,
                #    include_tags=True,
                #    context_manager=self.context_manager))
                # TODO - Should Adapt handle this?

                # JN changed from next(determine_intent), single value only
                for best_intent in self.engine.determine_good_intents(
                        normal_utterance,
                        100,
                        include_tags=True,
                        context_manager=self.context_manager):
                    best_intent['utterance'] = utterance
                    best_intent['retry_on_fail'] = True  #JN

                    if best_intent and best_intent.get('confidence',
                                                       0.0) > 0.0:
                        best_intent['utterance'] = utterance
                        self.update_context(best_intent)
                        # update active skills
                        skill_id = best_intent['intent_type'].split(":")[0]
                        self.add_active_skill(skill_id)
                        # adapt doesn't handle context injection for one_of keywords
                        # correctly. Workaround this issue if possible.
                        try:
                            best_intent = workaround_one_of_context(
                                best_intent)
                        except LookupError:
                            LOG.error('Error during workaround_one_of_context')
                        yield best_intent  # JN

            except StopIteration:
                # don't show error in log
                continue
            except Exception as e:
                LOG.exception(e)
                continue

    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_id = message.data.get('skill_id')
        new_parsers = [
            p for p in self.engine.intent_parsers
            if not p.name.startswith(skill_id)
        ]
        self.engine.intent_parsers = new_parsers

    def handle_add_context(self, message):
        """ Add context

        Args:
            message: data contains the 'context' item to add
                     optionally can include 'word' to be injected as
                     an alias for the context item.
        """
        entity = {'confidence': 1.0}
        context = message.data.get('context')
        word = message.data.get('word') or ''
        origin = message.data.get('origin') or ''
        # if not a string type try creating a string from it
        if not isinstance(word, str):
            word = str(word)
        entity['data'] = [(word, context)]
        entity['match'] = word
        entity['key'] = word
        entity['origin'] = origin
        self.context_manager.inject_context(entity)

    def handle_remove_context(self, message):
        """ Remove specific context

        Args:
            message: data contains the 'context' item to remove
        """
        context = message.data.get('context')
        if context:
            self.context_manager.remove_context(context)

    def handle_clear_context(self, message):
        """ Clears all keywords from context """
        self.context_manager.clear_context()
예제 #45
0
def skyAdapt():
    engine = IntentDeterminationEngine()

#dota vocabulary

    dota_keywords = [ 'dota', 'dotes', 'dote']

    for dk in dota_keywords:
        engine.register_entity(dk, "DotaKeyword")


    happening_keywords = [
            'happening',
            'anyone up for',
            'when is',
            'what time',
            'tonight',
            'this evening?',
            'anyone about for',
            'around',
            'want to',
            'fancy some',
            'playing some',
            'anyone playing'
            ]
    for hk in happening_keywords:
        engine.register_entity(hk, "HappeningKeyword")


    dota_query_intent = IntentBuilder("DotaIntent")\
        .require("DotaKeyword")\
        .require("HappeningKeyword")\
        .build()

    stack_intent_words = [
            'stack',
            'stacked'
            ]
    for sik in stack_intent_words:
        engine.register_entity(hk, "StackKeyword")


    stack_optionals = [
            'are we',
            'do we have a',
            'how many',
            'who\'s playing'
            ]

    for osk in stack_optionals:
        engine.register_entity(hk, "StackOptionalKeyword")

    stack_intent = IntentBuilder("StackIntent")\
        .require("StackKeyword")\
        .optionally("StackOptionalKeyword")\
        .build()


    engine.register_regex_entity("at (?P<Time>.*)")

    new_dota_intent = IntentBuilder("NewDotaIntent")\
        .require("DotaKeyword")\
        .require("Time")\
        .build()

    engine.register_intent_parser(dota_query_intent)
    engine.register_intent_parser(stack_intent)
    engine.register_intent_parser(new_dota_intent)


    return engine