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 __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 __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 __init__(self): self.engine = IntentDeterminationEngine() self.bot = BotLogger() self.ps = PorterStemmer() self.stop_cor = set(stopwords.words('english')) self.first_time = True self.st = 0 self.card_lost_intent = []
def __init__(self, config): self.config = config self.engine = IntentDeterminationEngine() # 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)
def __init__(self): """ Init for logger Intent engine Corpus """ self.engine = IntentDeterminationEngine() self.bot = BotLogger() self.cr = BotNextCorpus() self.first_time = True self.intent = [] self.train_intent()
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
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
def __init__(self): """ Init for logger Intent engine Corpus """ self.engine = IntentDeterminationEngine() self.bot = BotLogger() self.cr = BotNextCorpus() self.first_time = True self.intent = [] self.train_data = {'intent': "", 'user_text': "", 'bot_response': ""} self.train_intent() self.senti = SentimentIntensityAnalyzer()
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)
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)
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)
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
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)
def train(self, keywords, types, locations): """ Build and train the intent parser. keywords -- list of keywords types -- list of types locations -- list of locations """ with self.server.engine_lock: self.server.engine = IntentDeterminationEngine() for kw in keywords: self.server.engine.register_entity(kw, 'Keyword') for t in types: self.server.engine.register_entity(t, 'Type') for loc in locations: self.server.engine.register_entity(loc, 'Location') intent = IntentBuilder('Intent')\ .require('Keyword')\ .optionally('Type')\ .require('Location')\ .build() self.server.engine.register_intent_parser(intent)
class IntentSkill(MycroftSkill): def __init__(self): MycroftSkill.__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): utterances = message.data.get('utterances', '') best_intent = None for utterance in utterances: try: best_intent = next(self.engine.determine_intent( utterance, 100)) # TODO - Should Adapt handle this? best_intent['utterance'] = utterance except StopIteration, e: logger.exception(e) continue if best_intent and best_intent.get('confidence', 0.0) > 0.0: reply = message.reply(best_intent.get('intent_type'), best_intent) self.emitter.emit(reply) elif len(utterances) == 1: self.emitter.emit( Message("intent_failure", {"utterance": utterances[0]})) else: self.emitter.emit( Message("multi_utterance_intent_failure", {"utterances": utterances}))
def initialize(self): self.engine = IntentDeterminationEngine() self.enable_fallback = self.settings.get('enable_fallback_ex') \ if self.settings.get('enable_fallback_ex') is not None else True self.public_path = self.settings.get('public_path_ex') \ if self.settings.get('public_path_ex') else self.file_system.path+"/public" self.local_path = self.settings.get('local_path_ex') \ if self.settings.get('local_path_ex') else self.file_system.path+"/private" self.allow_category = self.settings.get('allow_category_ex') \ if self.settings.get('allow_category_ex') else "humor,love,science" LOG.debug('local path enabled: %s' % self.local_path) self.save_path = self.file_system.path+"/mycroft-skills" self.saved_utt = "" self.save_answer = "" if self.enable_fallback is True: self.register_fallback(self.handle_fallback, 6) self.register_fallback(self.handle_save_fallback, 99) ############## todo: fallback load skill intents self.add_event('speak', self.save_action) LOG.debug('Learning-skil-fallback enabled: %s' % self.enable_fallback) skillfolder = Configuration.get()['skills']['directory'] self.lang_paths = [] if 'translations_dir' in Configuration.get(): ##path of second language files self.lang_paths.append(Configuration.get()['translations_dir']) self.log.info("set lang path to translation_dir") if os.path.isdir(os.path.expanduser(skillfolder+"/PootleSync/mycroft-skills")): self.lang_paths.append(os.path.expanduser(skillfolder+"/PootleSync/mycroft-skills")) self.log.info("set lang path to PootleSync") ##intents self.register_intent_file('will_let_you_know.intent', self.will_let_you_know_intent) self.register_intent_file('say.differently.intent', self.say_differently_intent) self.register_intent_file('work.on.dialog.intent', self.work_on_dialog) self.register_intent_file('something_for_my_skill.intent', self.something_for_my_skill_intent)
class IntentSkill(MycroftSkill): def __init__(self): MycroftSkill.__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): utterances = message.metadata.get('utterances', '') best_intent = None for utterance in utterances: try: best_intent = next(self.engine.determine_intent(utterance, num_results=100)) best_intent['utterance'] = utterance # TODO - Should Adapt handle this? except StopIteration, e: continue if best_intent and best_intent.get('confidence', 0.0) > 0.0: reply = message.reply(best_intent.get('intent_type'), metadata=best_intent) self.emitter.emit(reply) elif len(utterances) == 1: self.emitter.emit(Message("intent_failure", metadata={"utterance": utterances[0]})) else: self.emitter.emit(Message("multi_utterance_intent_failure", metadata={"utterances": utterances}))
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
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 build_engine(rdb_conn): """Build a recycling intent determination engine.""" engine = IntentDeterminationEngine() recycle_keywords = ["recycle", "recycled", "recyclable"] for keyword in recycle_keywords: engine.register_entity(keyword, "RecycleKeyword") plastic_keywords = [ item["name"] for item in r.table("items").filter({ "type": "plastic" }).run(rdb_conn) ] register_intent("plastic", engine, *plastic_keywords, descriptor=["number"], numbers=["1", "2", "3", "4", "5", "6", "7"]) glass_keywords = [ item["name"] for item in r.table("items").filter({ "type": "glass" }).run(rdb_conn) ] register_intent("glass", engine, *glass_keywords) paper_keywords = [ item["name"] for item in r.table("items").filter({ "type": "paper" }).run(rdb_conn) ] register_intent("paper", engine, *paper_keywords) other_keywords = [ item["name"] for item in r.table("items").filter( ~r.row.has_fields("type")).run(rdb_conn) ] register_intent("other", engine, *other_keywords) return engine
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)
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.")
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
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)
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 __init__(self, object_type="tnalagmes_object", adapt=None): self.adapt = adapt or IntentDeterminationEngine() self.context_manager = ContextManager(self.adapt) self.object_type = object_type self.container = IntentContainer(self.cache_dir) self.intents = {} self.register_default_intents() self.register_core_intents() self.container.train() self.waiting_for_user = False self._output = "" self.input = ""
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
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 __init__(self, emitter): self.config = ConfigurationManager.get().get('context', {}) self.engine = IntentDeterminationEngine() self.context_keywords = self.config.get('keywords', ['Location']) 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 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
class IntentSkill(MycroftSkill): def __init__(self): MycroftSkill.__init__(self, name="IntentSkill") self.engine = IntentDeterminationEngine() self.reload_skill = False 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): # Get language of the utterance lang = message.data.get('lang', None) if not lang: lang = "en-us" utterances = message.data.get('utterances', '') best_intent = None for utterance in utterances: try: # normalize() changes "it's a boy" to "it is boy", etc. best_intent = next( self.engine.determine_intent(normalize(utterance, lang), 100)) # TODO - Should Adapt handle this? best_intent['utterance'] = utterance except StopIteration, e: logger.exception(e) continue if best_intent and best_intent.get('confidence', 0.0) > 0.0: reply = message.reply(best_intent.get('intent_type'), best_intent) self.emitter.emit(reply) 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 }))
class IntentService(object): def __init__(self, emitter): self.engine = IntentDeterminationEngine() self.emitter = emitter self.emitter.on('register_vocab', self.handle_register_vocab) self.emitter.on('register_intent', self.handle_register_intent) self.emitter.on('recognizer_loop:utterance', self.handle_utterance) self.emitter.on('detach_intent', self.handle_detach_intent) self.emitter.on('detach_skill', self.handle_detach_skill) def handle_utterance(self, message): # Get language of the utterance lang = message.data.get('lang', None) if not lang: lang = "en-us" utterances = message.data.get('utterances', '') best_intent = None for utterance in utterances: try: # normalize() changes "it's a boy" to "it is boy", etc. best_intent = next(self.engine.determine_intent( normalize(utterance, lang), 100)) # TODO - Should Adapt handle this? best_intent['utterance'] = utterance except StopIteration, e: logger.exception(e) continue if best_intent and best_intent.get('confidence', 0.0) > 0.0: reply = message.reply( best_intent.get('intent_type'), best_intent) self.emitter.emit(reply) 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 __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
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
def setUp(self): self.context_manager = ContextManager() self.engine = IntentDeterminationEngine()
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"))
__author__ = 'seanfitz' """ A sample intent that uses a regular expression entity to extract location from a query try with the following: PYTHONPATH=. python examples/regex_intent_parser.py "what's the weather like in tokyo" """ import json import sys from adapt.intent import IntentBuilder from adapt.engine import IntentDeterminationEngine engine = IntentDeterminationEngine() # create and register weather vocabulary weather_keyword = [ "weather" ] for wk in weather_keyword: engine.register_entity(wk, "WeatherKeyword") weather_types = [ "snow", "rain", "wind", "sleet", "sun" ]
__author__ = 'seanfitz' """ A sample intent that uses a fixed vocabulary to extract entities for an intent try with the following: PYTHONPATH=. python examples/single_intent_parser.py "what's the weather like in tokyo" """ import json import sys from adapt.intent import IntentBuilder from adapt.engine import IntentDeterminationEngine engine = IntentDeterminationEngine() weather_keyword = [ "weather" ] for wk in weather_keyword: engine.register_entity(wk, "WeatherKeyword") weather_types = [ "snow", "rain", "wind", "sleet", "sun" ] for wt in weather_types: engine.register_entity(wt, "WeatherType")
from flask import request from adapt.entity_tagger import EntityTagger from adapt.tools.text.tokenizer import EnglishTokenizer from adapt.tools.text.trie import Trie from adapt.intent import IntentBuilder from adapt.parser import Parser from adapt.engine import IntentDeterminationEngine app = Flask(__name__) tokenizer = EnglishTokenizer() trie = Trie() tagger = EntityTagger(trie, tokenizer) parser = Parser(tokenizer, tagger) engine = IntentDeterminationEngine() # create and register weather vocabulary error_keyword = [ "error", "e", "E" ] for er in error_keyword: engine.register_entity(er, "ErrorKeyword") error_types = [ "E16", "E17", "E19",
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()
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()
from flask import request from adapt.entity_tagger import EntityTagger from adapt.tools.text.tokenizer import EnglishTokenizer from adapt.tools.text.trie import Trie from adapt.intent import IntentBuilder from adapt.parser import Parser from adapt.engine import IntentDeterminationEngine app = Flask(__name__) tokenizer = EnglishTokenizer() trie = Trie() tagger = EntityTagger(trie, tokenizer) parser = Parser(tokenizer, tagger) engine = IntentDeterminationEngine() # create and register weather vocabulary weather_keyword = [ "weather" ] for wk in weather_keyword: engine.register_entity(wk, "WeatherKeyword") weather_types = [ "snow", "rain", "wind", "sleet", "sun"
from adapt.tools.text.trie import Trie from adapt.intent import IntentBuilder from adapt.parser import Parser from adapt.engine import IntentDeterminationEngine from datetime import datetime from datetime import timedelta import urllib2 app = Flask(__name__) tokenizer = EnglishTokenizer() trie = Trie() tagger = EntityTagger(trie, tokenizer) parser = Parser(tokenizer, tagger) engine = IntentDeterminationEngine() # create and register weather vocabulary cartype_keyword = [ "rent", "transfer" ] for ck in cartype_keyword: engine.register_entity(ck, "CarTypeKeyword") months = [ "January", "February", "March", "April",
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'
def setUp(self): self.engine = IntentDeterminationEngine()
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
class IntentService(object): def __init__(self, emitter): self.config = ConfigurationManager.get().get('context', {}) self.engine = IntentDeterminationEngine() self.context_keywords = self.config.get('keywords', ['Location']) 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, 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 }))
import json import sys from adapt.entity_tagger import EntityTagger from adapt.tools.text.tokenizer import EnglishTokenizer from adapt.tools.text.trie import Trie from adapt.intent import IntentBuilder from adapt.parser import Parser from adapt.engine import IntentDeterminationEngine tokenizer = EnglishTokenizer() trie = Trie() tagger = EntityTagger(trie, tokenizer) parser = Parser(tokenizer, tagger) engine = IntentDeterminationEngine() # define vocabulary weather_keyword = [ "weather" ] for wk in weather_keyword: engine.register_entity(wk, "WeatherKeyword") weather_types = [ "snow", "rain", "wind", "sleet", "sun"
def __init__(self): self.engine = IntentDeterminationEngine()
self.intent = 'courtesyIntent' # define vocabulary self.courtesy_keyword = [ "bonjour" ] # structure intent self.courtesy_intent = IntentBuilder(self.intent)\ .require("CourtesyKeyword")\ .build() def register(self, engine): for wk in self.courtesy_keyword: engine.register_entity(wk, "courtesyKeyword") engine.register_intent_parser(self.courtesy_intent) def process(self, json): result = sympy.sympify(json.get('CourtesyKeyword')) if json.get('CourtesyKeyword') == "bonjour": return "Bonjour monsieur" if __name__ == "__main__": engine = IntentDeterminationEngine() skill = courtesySkill() skill.register(engine) for intent in engine.determine_intent(' '.join(sys.argv[1:])): if intent and intent.get('confidence') > 0: print(json.dumps(intent, indent=4))
import json import sys # If there's a second argument given, use that to insert an import path # This enables users to use their own Adapt installation directories. if len(sys.argv) > 2: sys.path.insert(0, sys.argv[2]) 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__":
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
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
def __init__(self): BoomerSkill.__init__(self, name="IntentSkill") self.engine = IntentDeterminationEngine()
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()