def __init__(self): self.builder = StatementBuilder() self.adder = StatementSafeAdder() self.question_handler = QuestionHandler() self.sfactory = SentenceFactory() self.output_sentence = []
def _references_resolution_replace_current_object_with_ua_exception( self, sentence, uae_object, uae_object_with_more_info, uae_object_list): """This attempts to replace a nominal group that has failled from identifying the anaphoric word with one that holds more information. """ current_object = None if uae_object_with_more_info[1]: current_object = uae_object_with_more_info[0] else: sf = SentenceFactory() raise UnidentifiedAnaphoraError({ 'object': uae_object, 'object_to_confirm': uae_object_with_more_info[0], 'object_with_more_info': None, 'objects_list': uae_object_list, 'sentence': sentence, 'question': sf.create_do_you_mean_reference(uae_object_with_more_info[0]) }) return current_object
def _references_resolution_with_anaphora_matcher(self, nominal_group, matcher, current_speaker, current_object): """ This attempts to match the nominal group containing anaphoric words with an object identifed from the dialog history. If several candidates are found, a confirmation is asked to user. """ if current_object: self._current_object = None return current_object # Trying to match anaphora if not self.sentences_store: raise DialogError("Empty Dialog history") sf = SentenceFactory() #object = [ng, [List]] # Where ng is the first nominal group to match with the anaphoric word # and List contains nominal group that are to be explored if ng is not confirmed from the user object = matcher.match_first_object(get_last(self.sentences_store, 10), nominal_group) if not object: raise DialogError("No anaphora matches in dialog history") # Case there exist only one nominal group identified from anaphora matching if len(object[1]) == 1: nominal_group = object[0] logger.debug("Found anaphoric match " + str(nominal_group)) # Else, ask for confirmation to the user else: raise UnidentifiedAnaphoraError({ 'object': nominal_group, 'object_to_confirm': object[0], 'object_with_more_info': None, 'objects_list': object[1], 'sentence': self._current_sentence, 'question': sf.create_do_you_mean_reference(object[0]) }) ResourcePool().mark_active(nominal_group.id) return nominal_group
def _references_resolution_replace_current_object_with_ua_exception(self, sentence, uae_object, uae_object_with_more_info, uae_object_list): """This attempts to replace a nominal group that has failled from identifying the anaphoric word with one that holds more information. """ current_object = None if uae_object_with_more_info[1]: current_object = uae_object_with_more_info[0] else: sf = SentenceFactory() raise UnidentifiedAnaphoraError({'object': uae_object, 'object_to_confirm': uae_object_with_more_info[0], 'object_with_more_info': None, 'objects_list': uae_object_list, 'sentence': sentence, 'question': sf.create_do_you_mean_reference(uae_object_with_more_info[0])}) return current_object
def _references_resolution_with_anaphora_matcher(self, nominal_group, matcher, current_speaker, current_object): """ This attempts to match the nominal group containing anaphoric words with an object identifed from the dialog history. If several candidates are found, a confirmation is asked to user. """ if current_object: self._current_object = None return current_object # Trying to match anaphora if not self.sentences_store: raise DialogError("Empty Dialog history") sf = SentenceFactory() #object = [ng, [List]] # Where ng is the first nominal group to match with the anaphoric word # and List contains nominal group that are to be explored if ng is not confirmed from the user object = matcher.match_first_object(get_last(self.sentences_store, 10), nominal_group) if not object: raise DialogError("No anaphora matches in dialog history") # Case there exist only one nominal group identified from anaphora matching if len(object[1]) == 1: nominal_group = object[0] logger.debug("Found anaphoric match " + str(nominal_group)) # Else, ask for confirmation to the user else: raise UnidentifiedAnaphoraError({'object': nominal_group, 'object_to_confirm': object[0], 'object_with_more_info': None, 'objects_list': object[1], 'sentence': self._current_sentence, 'question': sf.create_do_you_mean_reference(object[0])}) ResourcePool().mark_active(nominal_group.id) return nominal_group
class ContentAnalyser(object): def __init__(self): self.builder = StatementBuilder() self.adder = StatementSafeAdder() self.question_handler = QuestionHandler() self.sfactory = SentenceFactory() self.output_sentence = [] def analyse(self, sentence, current_speaker): """Analyse a sentence intent and perform the corresponding behaviour. :returns: a pair with - a list of symbolic statements produced during the analyse. Note that these statements have already been sent to the knowledge base - a situation ID that identifies a situation the speaker is desiring (for an imperative sentence or an order) or experiencing (like an 'InterrogativeState' for a question). These two values can be None. Note also that an answer to the speaker is stored in self.output_sentence after analyse() completes. It can be used to tell the human to acknowledge an order, answer a gratulation, the answer a question (or the fact the answer is not known), etc. """ self.builder.clear_all() self.output_sentence = [] sentence = self.pre_analyse_content(sentence) if sentence.data_type == [INTERJECTION, EXCLAMATION]: pass if sentence.data_type in [START, END]: self.output_sentence.append(sentence) if sentence.data_type == GRATULATION: self.output_sentence.extend( self.sfactory.create_gratulation_reply()) if sentence.data_type in [AGREEMENT, DISAGREEMENT]: self.output_sentence.extend(self.sfactory.create_agree_reply()) if sentence.data_type in [IMPERATIVE, STATEMENT]: logger.debug( colored_print( "Processing the content of " + ("an imperative sentence" if sentence.data_type == IMPERATIVE else "a statement "), "magenta")) return self.process_sentence(sentence, current_speaker) if sentence.data_type in [W_QUESTION, YES_NO_QUESTION]: logger.debug( colored_print( "Processing the content of " + ("a W question " if sentence.data_type == W_QUESTION else "a YES/NO question"), "magenta")) return self.process_question(sentence, current_speaker) return None, None # default: no statement generated, no situation ID def process_sentence(self, sentence, current_speaker): self.builder.set_current_speaker(current_speaker) stmts, situation_id = self.builder.process_sentence(sentence) if stmts: self.add_stmts(stmts) emotions.satisfied() if situation_id: # If a new situation has been created, mark it as # active. self.output_sentence.extend(self.sfactory.create_agree_reply()) ResourcePool().mark_active(situation_id) else: logger.info("No statements produced") # Class grounding if self.builder.lear_more_concept: self.output_sentence.extend( self.sfactory.create_what_is_a_reference( sentence, self.builder.lear_more_concept)) return stmts, situation_id def process_question(self, sentence, current_speaker): self.question_handler.set_current_speaker(current_speaker) # 'stmts' contains a list of statement describing the current # 'interrogative state' of the interactor. answer, stmts, situation_id = self.question_handler.process_sentence( sentence) if stmts: self.add_stmts(stmts) else: logger.info("No statements produced") if answer: emotions.satisfied() logger.info( level_marker(level=2, color="yellow") + "Found: \n" + colored_print(str(answer), None, "magenta")) else: emotions.sorry() logger.info( level_marker(level=2, color="yellow") + "Couldn't find anything!") if sentence.data_type == W_QUESTION: self.output_sentence.extend( self.sfactory.create_w_question_answer( sentence, answer, self.question_handler._current_speaker, self.question_handler.get_query_on_field())) if sentence.data_type == YES_NO_QUESTION: self.output_sentence.extend( self.sfactory.create_yes_no_answer(sentence, answer)) return stmts, situation_id def add_stmts(self, stmts): logger.info("Generated statements: ") for s in stmts: logger.info(">> " + colored_print(s, None, 'magenta')) self.adder._current_speaker = self.builder._current_speaker self.adder._unclarified_ids = self.builder._unclarified_ids self.adder._statements = stmts self.adder._statements_to_remove = self.builder._statements_to_remove stmts = self.adder.process() logger.debug("...added to the ontology") def analyse_output(self): return self.output_sentence def pre_analyse_content(self, sentence): """ this method analyse the content of a sentence and possibly changes its purpose. E.g: Can you give me the bottle? The sentence above is of YES_NO_QUESTION type but should actually be processed as an order in which the current speaker desires 'the bottle'. Therefore, we turn it into 'give me the bottle'. """ # Case of : # -INPUT: Yes_no_question + can + action verb # -OUTPUT: Imperative + action verb # if sentence.data_type == YES_NO_QUESTION: for sv in sentence.sv: for verb in sv.vrb_main: if 'can+' in verb: vrb_main = verb.lstrip('can+') if not vrb_main in ResourcePool().state + ResourcePool( ).action_verb_with_passive_behaviour.keys( ) + ResourcePool().goal_verbs: logger.debug( colored_print( "Interpreting the <can + action verb> sequence as a desire.\nApplying transformation:", "magenta")) sv.vrb_main[sv.vrb_main.index(verb)] = verb.lstrip( 'can+') sentence.data_type = IMPERATIVE logger.debug(str(sentence)) return sentence return sentence
def clarify(self, description, ignoreFeatureL=None): if not ignoreFeatureL: ignoreFeatureL = [] objL = self.get_all_objects_with_desc(description) if len(objL) == 0: logger.debug(colored_print('Nothing found!', "magenta")) else: logger.debug( colored_print('Found these possible concepts ID: ', "magenta") + colored_print(str(objL), 'blue')) if not self.oro: #No ontology server return 'UNKNOWN_CONCEPT_' + generate_id(with_question_mark=False) if not objL: questions = SentenceFactory().create_i_dont_understand() raise UnsufficientInputError({ 'status': 'FAILURE', 'question': questions }) #return "I don't understand" else: # Check if the speaker sees only some of the object. # If he sees none of them, discriminate on the whole set. # Else, discriminate only on visible objects. agent = description[0][0] logger.debug("Checking which of these objects are visible for " + agent) visible_objects = self.visible_subset(agent, objL) if visible_objects: objL = visible_objects logger.debug( colored_print('Only ', "magenta") + colored_print(str(objL), 'blue') + colored_print(" are visible by " + agent, "magenta")) else: logger.debug( colored_print('None are visible by ' + agent, "magenta")) if len(objL) == 1: return objL[0] if len(objL) == 2 and self.oro.check( ['%s owl:sameAs %s' % (objL[0], objL[1])]): return objL[0] agent, descriptor = self.get_descriptor(description, ignoreFeatureL) object = self.get_type_description(description) if descriptor: sentence_builder = SentenceFactory() question = None values = self.get_values_for_descriptor( agent, descriptor, objL) if not object: object = 'object' if descriptor == 'hasColor' or descriptor == 'mainColorOfObject': questions = sentence_builder.create_w_question_choice( object, 'color', values) elif descriptor == 'hasShape': questions = sentence_builder.create_w_question_choice( object, 'shape', values) elif descriptor == 'hasSize': questions = sentence_builder.create_w_question_choice( object, 'size', values) elif descriptor == 'isOn': questions = sentence_builder.create_w_question_location( object, 'on', values) elif descriptor == 'isIn': questions = sentence_builder.create_w_question_location( object, 'in', values) elif descriptor == 'isNextTo': questions = sentence_builder.create_w_question_location( object, 'next to', values) elif descriptor == 'isAt': questions = sentence_builder.create_w_question_location( object, 'at', values) elif descriptor == 'isLocated': questions = sentence_builder.create_w_question_location_PT( values, agent) elif descriptor == 'rdf:type': questions = sentence_builder.create_w_question_choice( object, 'type', values) else: questions = sentence_builder.create_w_question_generic_descriptor( object, descriptor, values) raise UnsufficientInputError({ 'status': 'SUCCESS', 'question': questions }) #return questions else: questions = [ Sentence(IMPERATIVE, '', [], [ VerbalGroup(['give'], [], 'present simple', [ NominalGroup([], ['information'], [['more', []]], [], []) ], [ IndirectComplement( [], [NominalGroup([], ['me'], [], [], [])]), IndirectComplement( ['about'], [NominalGroup(['the'], [object], [], [], [])]) ], [], [], VerbalGroup.affirmative, []) ]) ] raise UnsufficientInputError({ 'status': 'SUCCESS', 'question': questions })
def _resolve_nouns(self, nominal_group, current_speaker, discriminator, builder): """This attempts to resolve a single nominal group by the use of discrimiation routines. The output is the ID of the nominal group """ if nominal_group._resolved: #already resolved: possible after asking human for more details. return nominal_group logger.debug(str(nominal_group)) #Creating a concept description builder.process_nominal_group(nominal_group, '?concept', None, False) stmts = builder.get_statements() builder.clear_statements() # Special case of "other" occuring in the nominal group if builder.process_on_other: nominal_group, stmts = self.resolve_different_from_dialog_history(nominal_group, current_speaker, stmts, builder) if nominal_group._resolved: ResourcePool().mark_active(nominal_group.id) return nominal_group if nominal_group._quantifier in ['SOME']: #enforce object visibility stmtsAndVisibility = stmts + [current_speaker + " sees ?concept"] # Pick a random id logger.debug(colored_print("Looking for at least one visible concept matching in " + \ current_speaker + "'s model: \n", "magenta") + \ '[' + colored_print(', '.join(stmtsAndVisibility), None, 'magenta') + ']') concepts = [] try: concepts = ResourcePool().ontology_server.findForAgent(current_speaker, '?concept', stmtsAndVisibility) except AttributeError: # No ontology server pass except KbError: #The agent does not exist in the ontology pass if not concepts: # no acceptable concepts that are visible. Look for concepts that are not visible." logger.debug(colored_print("No visible concepts found. Removing the visibility constraint")) try: concepts = ResourcePool().ontology_server.findForAgent(current_speaker, '?concept', stmts) except AttributeError: # No ontology server pass except KbError: #The agent does not exist in the ontology pass if concepts: id = random.choice(concepts) else: sf = SentenceFactory() uie = UnsufficientInputError({'status': 'FAILURE'}) uie.value['question'] = sf.create_what_do_you_mean_reference(nominal_group) uie.value['object'] = nominal_group uie.value['sentence'] = self._current_sentence uie.value['object_with_more_info'] = None raise uie else: #Try to discriminate logger.debug(colored_print("Looking for the concept matching in " + \ current_speaker + "'s model: \n", "magenta") + \ '[' + colored_print(', '.join(stmts), None, 'magenta') + ']') description = [[current_speaker, '?concept', stmts]] # Features to ignore from discrimination features = [] if self._current_sentence.data_type in [W_QUESTION, YES_NO_QUESTION]: if self._current_sentence.aim in ResourcePool().adjectives_ontology_classes: # feature =["hasColor"] features = ["has" + self._current_sentence.aim.capitalize()] else: features = ["rdf:type"] # Discriminate try: id = discriminator.clarify(description, features) except UnsufficientInputError as uie: # Create a new concept instead of raising unsificient input error, as the current sentence start with "learn that ..." if self._current_sentence.islearning(): id = self._ontology_learns_new_concept(stmts, current_speaker) else: sf = SentenceFactory() if uie.value['status'] != 'SUCCESS': uie.value['question'][:0] = sf.create_what_do_you_mean_reference(nominal_group) uie.value['object'] = nominal_group uie.value['sentence'] = self._current_sentence uie.value['object_with_more_info'] = None raise uie logger.debug(colored_print("Hurra! Found \"" + id + "\"", 'magenta')) nominal_group.id = id nominal_group._resolved = True ResourcePool().mark_active(nominal_group.id) return nominal_group
def _resolve_references(self, nominal_group, verb, matcher, current_speaker, current_object): # Case of a resolved nominal group if nominal_group._resolved: return nominal_group # Case of a nominal group built by only adjectives # E.g, 'big' in 'the yellow banana is big'. if nominal_group.adjectives_only(): nominal_group.id = nominal_group.adj[0][0] nominal_group._resolved = True return nominal_group # Case of an anaphoric word in the determiner # E.g: This , that cube if nominal_group.det and \ nominal_group.det[0].lower() in ResourcePool().demonstrative_det: onto_focus = '' logger.debug( colored_print("Found a demonstrative (this/that...). Trying to resolve it based on current focus...", "magenta")) if nominal_group.noun and nominal_group.noun[ 0].lower() != 'one': # case "this + category" -> eg "this phone" class_name = self._get_class_name_from_ontology(current_speaker, nominal_group) logger.debug(colored_print("Looking for : ", "magenta") + colored_print( current_speaker + ' pointsAt ?concept, ?concept rdf:type ' + class_name, None, "magenta")) try: onto_focus = ResourcePool().ontology_server.findForAgent( current_speaker, '?concept', [current_speaker + ' pointsAt ?concept', '?concept rdf:type ' + class_name]) except AttributeError: pass except KbError: #Agent not found in the ontology pass else: # case "this" alone or "this one" logger.debug( colored_print("Looking for : ", "magenta") + colored_print(current_speaker + ' pointsAt ?concept', None, "magenta")) try: onto_focus = ResourcePool().ontology_server.findForAgent( current_speaker, '?concept', [current_speaker + ' pointsAt ?concept']) except AttributeError: pass except KbError: #Agent not found in the ontology pass if onto_focus: logger.debug(colored_print("OK, found ", "magenta") + colored_print(str(onto_focus), "blue")) nominal_group.id = onto_focus[0] nominal_group._resolved = True ResourcePool().mark_active(nominal_group.id) return nominal_group logger.debug(colored_print("No focus. Processing is as a classic anaphora.", "magenta")) # Case of # this + noun - E.g: Take this cube: if nominal_group.noun and nominal_group.noun[0].lower() != 'one': pass # Nothing to do appart from processing "this" as "the" # Case of # this + one - E.g: Take this one # this + None - E.g: Take this else: try: nominal_group.noun = self._references_resolution_with_anaphora_matcher( nominal_group, matcher, current_speaker, current_object) except DialogError: #...no dialog history yet! or nothing found in history. Can not do any matching over past sentences uie = UnsufficientInputError({'status': 'FAILURE'}) sf = SentenceFactory() uie.value['question'] = sf.create_what_do_you_mean_reference(nominal_group) uie.value['object'] = nominal_group uie.value['sentence'] = self._current_sentence uie.value['object_with_more_info'] = None raise uie # Case of a nominal group with no Noun if not nominal_group.noun: return nominal_group # Case of an existing ID in the Ontology onto = [] try: onto = ResourcePool().ontology_server.lookupForAgent(current_speaker, nominal_group.noun[0]) except AttributeError: #the ontology server is not started or doesn't know the method pass except KbError: #The agent does not exist in the ontology pass if onto: for c in onto: if "INSTANCE" in c: nominal_group.id = c[0] logger.debug("... \t" + nominal_group.noun[0] + " is an existing ID (" + nominal_group.id + \ ") in " + current_speaker + "'s model.") nominal_group._resolved = True ResourcePool().mark_active(nominal_group.id) break # Case of personal prounouns if current_speaker and nominal_group.noun[0].lower() in ['me', 'i']: logger.debug(colored_print("Replaced \"me\" or \"I\" by \"" + current_speaker + "\"", "magenta")) nominal_group.id = current_speaker nominal_group._resolved = True return nominal_group if nominal_group.noun[0].lower() in ['you']: logger.debug(colored_print("Replaced \"you\" by \"myself\"", "magenta")) nominal_group.id = 'myself' nominal_group._resolved = True return nominal_group #Anaphoric words in the noun if nominal_group.noun[0].lower() in ['it', 'one']: nominal_group = self._references_resolution_with_anaphora_matcher(nominal_group, matcher, current_speaker, current_object) # Case of a quantifier different from ONE # means the nominal group holds an indefinite determiner. # E.g a robot, every plant, fruits, ... if nominal_group._quantifier in ['SOME', 'ALL']: class_name = self._get_class_name_from_ontology(current_speaker, nominal_group) if verb and verb in ResourcePool().state and nominal_group.noun[0] not in ["everything", "anything"]: # Case of a state verb # id = the class name # E.g: an apple is a fruit # the id of apple is Apple # TODO: adjectives are discarded: we do not handle 'A green apple is a fruit' for instance logger.debug("Found indefinite quantifier " + nominal_group._quantifier + \ " for " + nominal_group.noun[0] + " and state verb " + verb + \ ". Replacing it by its class.") nominal_group.id = class_name else: if nominal_group._quantifier in ['SOME']: # Do not deal further here with existential quantifier. It will be processed # later in noun_resolution. return nominal_group if nominal_group.noun[0] in ["everything", "anything"]: # case of everything/anything # -> we get all *Artifact* ids existing in the ontology logger.debug("Found " + nominal_group.noun[0] + ": retrieving all existing instances.") onto_id = [] try: # TODO: anything -> all Artifact: is that right? onto_id = ResourcePool().ontology_server.findForAgent(current_speaker, '?concept', ['?concept rdf:type Artifact']) except KbError: # The agent does not exist in the ontology pass else: # case of an action verbs # id = generated # E.g: An apple grows on a tree # e.g.: show me the books -> books replaced by all book instance # we get the ids of all existing books in the ontology otherwise we generate one logger.debug("Found indefinite quantifier " + nominal_group._quantifier + \ " for " + nominal_group.noun[0] + ((" and with verb " + verb) if verb else "") + \ ". Replacing it by all its instances.") onto_id = [] try: onto_id = ResourcePool().ontology_server.findForAgent(current_speaker, '?concept', ['?concept rdf:type ' + class_name]) except KbError: # The agent does not exist in the ontology pass if not onto_id: sf = SentenceFactory() raise InterruptedInteractionError(sf.create_no_instance_of(nominal_group)) elif len(onto_id) == 1: [nominal_group.id] = onto_id else: # More than one value! Add all ids nominal_group.id = onto_id nominal_group._resolved = True ResourcePool().mark_active(nominal_group.id) return nominal_group return nominal_group
def clarify(self, description, ignoreFeatureL=None): if not ignoreFeatureL: ignoreFeatureL = [] objL = self.get_all_objects_with_desc(description) if len(objL) == 0: logger.debug(colored_print('Nothing found!', "magenta")) else: logger.debug( colored_print('Found these possible concepts ID: ', "magenta") + colored_print(str(objL), 'blue')) if not self.oro: #No ontology server return 'UNKNOWN_CONCEPT_' + generate_id(with_question_mark=False) if not objL: questions = SentenceFactory().create_i_dont_understand() raise UnsufficientInputError({'status': 'FAILURE', 'question': questions}) #return "I don't understand" else: # Check if the speaker sees only some of the object. # If he sees none of them, discriminate on the whole set. # Else, discriminate only on visible objects. agent = description[0][0] logger.debug("Checking which of these objects are visible for " + agent) visible_objects = self.visible_subset(agent, objL) if visible_objects: objL = visible_objects logger.debug(colored_print('Only ', "magenta") + colored_print(str(objL), 'blue') + colored_print(" are visible by " + agent, "magenta")) else: logger.debug(colored_print('None are visible by ' + agent, "magenta")) if len(objL) == 1: return objL[0] if len(objL) == 2 and self.oro.check(['%s owl:sameAs %s' % (objL[0], objL[1])]): return objL[0] agent, descriptor = self.get_descriptor(description, ignoreFeatureL) object = self.get_type_description(description) if descriptor: sentence_builder = SentenceFactory() question = None values = self.get_values_for_descriptor(agent, descriptor, objL) if not object: object = 'object' if descriptor == 'hasColor' or descriptor == 'mainColorOfObject': questions = sentence_builder.create_w_question_choice(object, 'color', values) elif descriptor == 'hasShape': questions = sentence_builder.create_w_question_choice(object, 'shape', values) elif descriptor == 'hasSize': questions = sentence_builder.create_w_question_choice(object, 'size', values) elif descriptor == 'isOn': questions = sentence_builder.create_w_question_location(object, 'on', values) elif descriptor == 'isIn': questions = sentence_builder.create_w_question_location(object, 'in', values) elif descriptor == 'isNextTo': questions = sentence_builder.create_w_question_location(object, 'next to', values) elif descriptor == 'isAt': questions = sentence_builder.create_w_question_location(object, 'at', values) elif descriptor == 'isLocated': questions = sentence_builder.create_w_question_location_PT(values, agent) elif descriptor == 'rdf:type': questions = sentence_builder.create_w_question_choice(object, 'type', values) else: questions = sentence_builder.create_w_question_generic_descriptor(object, descriptor, values) raise UnsufficientInputError({'status': 'SUCCESS', 'question': questions}) #return questions else: questions = [Sentence(IMPERATIVE, '', [], [Verbal_Group(['give'], [], 'present simple', [Nominal_Group([], ['information'], [['more', []]], [], [])], [Indirect_Complement([], [Nominal_Group([], ['me'], [], [], [])]), Indirect_Complement(['about'], [ Nominal_Group(['the'], [object], [], [], [])])], [], [], Verbal_Group.affirmative, [])])] raise UnsufficientInputError({'status': 'SUCCESS', 'question': questions})
class ContentAnalyser(object): def __init__(self): self.builder = StatementBuilder() self.adder = StatementSafeAdder() self.question_handler = QuestionHandler() self.sfactory = SentenceFactory() self.output_sentence = [] def analyse(self, sentence, current_speaker): """Analyse a sentence intent and perform the corresponding behaviour. :returns: a pair with - a list of symbolic statements produced during the analyse. Note that these statements have already been sent to the knowledge base - a situation ID that identifies a situation the speaker is desiring (for an imperative sentence or an order) or experiencing (like an 'InterrogativeState' for a question). These two values can be None. Note also that an answer to the speaker is stored in self.output_sentence after analyse() completes. It can be used to tell the human to acknowledge an order, answer a gratulation, the answer a question (or the fact the answer is not known), etc. """ self.builder.clear_all() self.output_sentence = [] sentence = self.pre_analyse_content(sentence) if sentence.data_type == [INTERJECTION, EXCLAMATION]: pass if sentence.data_type in [START, END]: self.output_sentence.append(sentence) if sentence.data_type == GRATULATION: self.output_sentence.extend(self.sfactory.create_gratulation_reply()) if sentence.data_type in [AGREEMENT, DISAGREEMENT]: self.output_sentence.extend(self.sfactory.create_agree_reply()) if sentence.data_type in [IMPERATIVE, STATEMENT]: logger.debug(colored_print("Processing the content of " + ( "an imperative sentence" if sentence.data_type == IMPERATIVE else "a statement "), "magenta")) return self.process_sentence(sentence, current_speaker) if sentence.data_type in [W_QUESTION, YES_NO_QUESTION]: logger.debug(colored_print("Processing the content of " + ( "a W question " if sentence.data_type == W_QUESTION else "a YES/NO question"), "magenta")) return self.process_question(sentence, current_speaker) return None, None # default: no statement generated, no situation ID def process_sentence(self, sentence, current_speaker): self.builder.set_current_speaker(current_speaker) stmts, situation_id = self.builder.process_sentence(sentence) if stmts: self.add_stmts(stmts) emotions.satisfied() if situation_id: # If a new situation has been created, mark it as # active. self.output_sentence.extend(self.sfactory.create_agree_reply()) ResourcePool().mark_active(situation_id) else: logger.info("No statements produced") # Class grounding if self.builder.lear_more_concept: self.output_sentence.extend( self.sfactory.create_what_is_a_reference(sentence, self.builder.lear_more_concept)) return stmts, situation_id def process_question(self, sentence, current_speaker): self.question_handler.set_current_speaker(current_speaker) # 'stmts' contains a list of statement describing the current # 'interrogative state' of the interactor. answer, stmts, situation_id = self.question_handler.process_sentence(sentence) if stmts: self.add_stmts(stmts) else: logger.info("No statements produced") if answer: emotions.satisfied() logger.info( level_marker(level=2, color="yellow") + "Found: \n" + colored_print(str(answer), None, "magenta")) else: emotions.sorry() logger.info(level_marker(level=2, color="yellow") + "Couldn't find anything!") if sentence.data_type == W_QUESTION: self.output_sentence.extend(self.sfactory.create_w_question_answer(sentence, answer, self.question_handler._current_speaker, self.question_handler.get_query_on_field())) if sentence.data_type == YES_NO_QUESTION: self.output_sentence.extend(self.sfactory.create_yes_no_answer(sentence, answer)) return stmts, situation_id def add_stmts(self, stmts): logger.info("Generated statements: ") for s in stmts: logger.info(">> " + colored_print(s, None, 'magenta')) self.adder._current_speaker = self.builder._current_speaker self.adder._unclarified_ids = self.builder._unclarified_ids self.adder._statements = stmts self.adder._statements_to_remove = self.builder._statements_to_remove stmts = self.adder.process() logger.debug("...added to the ontology") def analyse_output(self): return self.output_sentence def pre_analyse_content(self, sentence): """ this method analyse the content of a sentence and possibly changes its purpose. E.g: Can you give me the bottle? The sentence above is of YES_NO_QUESTION type but should actually be processed as an order in which the current speaker desires 'the bottle'. Therefore, we turn it into 'give me the bottle'. """ # Case of : # -INPUT: Yes_no_question + can + action verb # -OUTPUT: Imperative + action verb # if sentence.data_type == YES_NO_QUESTION: for sv in sentence.sv: for verb in sv.vrb_main: if 'can+' in verb: vrb_main = verb.lstrip('can+') if not vrb_main in ResourcePool().state + ResourcePool().action_verb_with_passive_behaviour.keys() + ResourcePool().goal_verbs: logger.debug(colored_print( "Interpreting the <can + action verb> sequence as a desire.\nApplying transformation:", "magenta")) sv.vrb_main[sv.vrb_main.index(verb)] = verb.lstrip('can+') sentence.data_type = IMPERATIVE logger.debug(str(sentence)) return sentence return sentence
def _resolve_nouns(self, nominal_group, current_speaker, discriminator, builder): """This attempts to resolve a single nominal group by the use of discrimiation routines. The output is the ID of the nominal group """ if nominal_group._resolved: #already resolved: possible after asking human for more details. return nominal_group logger.debug(str(nominal_group)) #Creating a concept description builder.process_nominal_group(nominal_group, '?concept', None, False) stmts = builder.get_statements() builder.clear_statements() # Special case of "other" occuring in the nominal group if builder.process_on_other: nominal_group, stmts = self.resolve_different_from_dialog_history( nominal_group, current_speaker, stmts, builder) if nominal_group._resolved: ResourcePool().mark_active(nominal_group.id) return nominal_group if nominal_group._quantifier in ['SOME']: #enforce object visibility stmtsAndVisibility = stmts + [current_speaker + " sees ?concept"] # Pick a random id logger.debug(colored_print("Looking for at least one visible concept matching in " + \ current_speaker + "'s model: \n", "magenta") + \ '[' + colored_print(', '.join(stmtsAndVisibility), None, 'magenta') + ']') concepts = [] try: concepts = ResourcePool().ontology_server.findForAgent( ResourcePool().get_model_mapping(current_speaker), '?concept', stmtsAndVisibility) except KbError: #The agent does not exist in the ontology pass if not concepts: # no acceptable concepts that are visible. Look for concepts that are not visible." logger.debug( colored_print( "No visible concepts found. Removing the visibility constraint" )) try: concepts = ResourcePool().ontology_server.findForAgent( ResourcePool().get_model_mapping(current_speaker), '?concept', stmts) except KbError: #The agent does not exist in the ontology pass if concepts: id = random.choice(concepts) else: sf = SentenceFactory() uie = UnsufficientInputError({'status': 'FAILURE'}) uie.value['question'] = sf.create_what_do_you_mean_reference( nominal_group) uie.value['object'] = nominal_group uie.value['sentence'] = self._current_sentence uie.value['object_with_more_info'] = None raise uie else: #Try to discriminate logger.debug(colored_print("Looking for the concept matching in " + \ current_speaker + "'s model: \n", "magenta") + \ '[' + colored_print(', '.join(stmts), None, 'magenta') + ']') description = [[current_speaker, '?concept', stmts]] # Features to ignore from discrimination features = [] if self._current_sentence.data_type in [ W_QUESTION, YES_NO_QUESTION ]: if self._current_sentence.aim in ResourcePool( ).adjectives_ontology_classes: # feature =["hasColor"] features = [ "has" + self._current_sentence.aim.capitalize() ] else: features = ["rdf:type"] # Discriminate try: id = discriminator.clarify(description, features) except UnsufficientInputError as uie: # Create a new concept instead of raising unsificient input error, as the current sentence start with "learn that ..." if self._current_sentence.islearning(): id = self._ontology_learns_new_concept( stmts, current_speaker) else: sf = SentenceFactory() if uie.value['status'] != 'SUCCESS': uie.value[ 'question'][: 0] = sf.create_what_do_you_mean_reference( nominal_group) uie.value['object'] = nominal_group uie.value['sentence'] = self._current_sentence uie.value['object_with_more_info'] = None raise uie logger.debug(colored_print("Hurra! Found \"" + id + "\"", 'magenta')) nominal_group.id = id nominal_group._resolved = True ResourcePool().mark_active(nominal_group.id) return nominal_group
def _resolve_references(self, nominal_group, verb, matcher, current_speaker, current_object): # Case of a resolved nominal group if nominal_group._resolved: return nominal_group # Case of a nominal group built by only adjectives # E.g, 'big' in 'the yellow banana is big'. if nominal_group.adjectives_only(): nominal_group.id = nominal_group.adj[0][0] nominal_group._resolved = True return nominal_group # Case of an anaphoric word in the determiner # E.g: This , that cube if nominal_group.det and \ nominal_group.det[0].lower() in ResourcePool().demonstrative_det: onto_focus = '' logger.debug( colored_print( "Found a demonstrative (this/that...). Trying to resolve it based on current focus...", "magenta")) if nominal_group.noun and nominal_group.noun[0].lower( ) != 'one': # case "this + category" -> eg "this phone" class_name = self._get_class_name_from_ontology( current_speaker, nominal_group) logger.debug( colored_print("Looking for : ", "magenta") + colored_print( current_speaker + ' focusesOn ?concept, ?concept rdf:type ' + class_name, None, "magenta")) try: onto_focus = ResourcePool().ontology_server.findForAgent( ResourcePool().get_model_mapping(current_speaker), '?concept', [ current_speaker + ' focusesOn ?concept', '?concept rdf:type ' + class_name ]) except KbError: #Agent not found in the ontology pass else: # case "this" alone or "this one" logger.debug( colored_print("Looking for : ", "magenta") + colored_print(current_speaker + ' focusesOn ?concept', None, "magenta")) try: onto_focus = ResourcePool().ontology_server.findForAgent( ResourcePool().get_model_mapping(current_speaker), '?concept', [current_speaker + ' focusesOn ?concept']) except KbError: #Agent not found in the ontology pass if onto_focus: logger.debug( colored_print("OK, found ", "magenta") + colored_print(str(onto_focus), "blue")) nominal_group.id = onto_focus[0] nominal_group._resolved = True ResourcePool().mark_active(nominal_group.id) return nominal_group logger.debug( colored_print("No focus. Processing is as a classic anaphora.", "magenta")) # Case of # this + noun - E.g: Take this cube: if nominal_group.noun and nominal_group.noun[0].lower() != 'one': pass # Nothing to do appart from processing "this" as "the" # Case of # this + one - E.g: Take this one # this + None - E.g: Take this else: try: nominal_group.noun = self._references_resolution_with_anaphora_matcher( nominal_group, matcher, current_speaker, current_object) except DialogError: #...no dialog history yet! or nothing found in history. Can not do any matching over past sentences uie = UnsufficientInputError({'status': 'FAILURE'}) sf = SentenceFactory() uie.value[ 'question'] = sf.create_what_do_you_mean_reference( nominal_group) uie.value['object'] = nominal_group uie.value['sentence'] = self._current_sentence uie.value['object_with_more_info'] = None raise uie # Case of a nominal group with no Noun if not nominal_group.noun: return nominal_group # Case of an existing ID in the Ontology onto = [] try: onto = ResourcePool().ontology_server.lookupForAgent( ResourcePool().get_model_mapping(current_speaker), nominal_group.noun[0]) except KbError: #The agent does not exist in the ontology pass if onto: for c in onto: if "instance" in c: nominal_group.id = c[0] logger.debug("... \t" + nominal_group.noun[0] + " is an existing ID (" + nominal_group.id + \ ") in " + current_speaker + "'s model.") nominal_group._resolved = True ResourcePool().mark_active(nominal_group.id) break # Case of personal prounouns if current_speaker and nominal_group.noun[0].lower() in ['me', 'i']: logger.debug( colored_print( "Replaced \"me\" or \"I\" by \"" + current_speaker + "\"", "magenta")) nominal_group.id = current_speaker nominal_group._resolved = True return nominal_group if nominal_group.noun[0].lower() in ['you']: logger.debug( colored_print("Replaced \"you\" by \"myself\"", "magenta")) nominal_group.id = 'myself' nominal_group._resolved = True return nominal_group #Anaphoric words in the noun if nominal_group.noun[0].lower() in ['it', 'one']: nominal_group = self._references_resolution_with_anaphora_matcher( nominal_group, matcher, current_speaker, current_object) # Case of a quantifier different from ONE # means the nominal group holds an indefinite determiner. # E.g a robot, every plant, fruits, ... if nominal_group._quantifier in ['SOME', 'ALL']: class_name = self._get_class_name_from_ontology( current_speaker, nominal_group) if verb and verb in ResourcePool( ).state and nominal_group.noun[0] not in [ "everything", "anything" ]: # Case of a state verb # id = the class name # E.g: an apple is a fruit # the id of apple is Apple # TODO: adjectives are discarded: we do not handle 'A green apple is a fruit' for instance logger.debug("Found indefinite quantifier " + nominal_group._quantifier + \ " for " + nominal_group.noun[0] + " and state verb " + verb + \ ". Replacing it by its class.") nominal_group.id = class_name else: if nominal_group._quantifier in ['SOME']: # Do not deal further here with existential quantifier. It will be processed # later in noun_resolution. return nominal_group if nominal_group.noun[0] in ["everything", "anything"]: # case of everything/anything # -> we get all *Artifact* ids existing in the ontology logger.debug("Found " + nominal_group.noun[0] + ": retrieving all existing instances.") onto_id = [] try: # TODO: anything -> all Artifact: is that right? onto_id = ResourcePool().ontology_server.findForAgent( ResourcePool().get_model_mapping(current_speaker), '?concept', ['?concept rdf:type Artifact']) except KbError: # The agent does not exist in the ontology pass else: # case of an action verbs # id = generated # E.g: An apple grows on a tree # e.g.: show me the books -> books replaced by all book instance # we get the ids of all existing books in the ontology otherwise we generate one logger.debug("Found indefinite quantifier " + nominal_group._quantifier + \ " for " + nominal_group.noun[0] + ((" and with verb " + verb) if verb else "") + \ ". Replacing it by all its instances.") onto_id = [] try: onto_id = ResourcePool().ontology_server.findForAgent( ResourcePool().get_model_mapping(current_speaker), '?concept', ['?concept rdf:type ' + class_name]) except KbError: # The agent does not exist in the ontology pass if not onto_id: sf = SentenceFactory() raise InterruptedInteractionError( sf.create_no_instance_of(nominal_group)) elif len(onto_id) == 1: [nominal_group.id] = onto_id else: # More than one value! Add all ids nominal_group.id = onto_id nominal_group._resolved = True ResourcePool().mark_active(nominal_group.id) return nominal_group return nominal_group