def _handle_answer_whose_song(self, state, triggered_answers): question_name = 'QuestionWhoseSong' musician_wiki_entity = self.state_manager.current_state.entity_linker.best_ent_of_type( WikiEntityInterface.EntityGroup.MUSICIAN) if not musician_wiki_entity or musician_wiki_entity.name is WikiEntityInterface.PageName.MUSICIAN: if question_name in triggered_answers and 'answer' in triggered_answers[ question_name]: musician_name = triggered_answers[question_name]['answer'] musician_wiki_entity = WikiEntityInterface.link_span( musician_name) rg_result = None if musician_wiki_entity and WikiEntityInterface.is_in_entity_group( musician_wiki_entity, WikiEntityInterface.EntityGroup.MUSICIAN): musician_entity = MusicEntity( pref_label=musician_wiki_entity.common_name, wiki_entity=musician_wiki_entity) rg_result = self.create_rg_result_ask_another_song_of_musician( state, musician_entity) if rg_result: response = self.choose(ACKNOWLEDGE_WHOSE_SONG) rg_result.text = f"{response} {rg_result.text}" if not rg_result: response = self.choose(ACKNOWLEDGE_COULDNT_GET_MUSICIAN) rg_result = self.prepare_rg_result(response, state) rg_result.conditional_state.needs_internal_prompt = False return rg_result
def get_prompt(self, state, conditional_state=None, trigger_entity = None): question_candidates = [q for q in list(QUESTION_TEMPLATES.keys()) if q not in state.asked_questions] is_correct_entity_group = trigger_entity and WikiEntityInterface.is_in_entity_group(trigger_entity, WikiEntityInterface.EntityGroup.MUSICIAN) undiscussed_titles = [title for title in EXAMPLE_MUSICIAN_WIKI_PAGES.keys() if not WikiEntityInterface.is_title_in_entities(title, state.discussed_entities)] # Prepare prompt. prompt = self.prepare_prompt_result('Placeholder', state, priority=PromptType.GENERIC, cur_entity=None, conditional_state=conditional_state) prompt.conditional_state.turn_treelet_history.append(self.name) prompt.conditional_state.next_treelet = self.name prompt.conditional_state.needs_internal_prompt = False # Give current topic response if possible. if trigger_entity and is_correct_entity_group: prompt.priority = PromptType.CURRENT_TOPIC prompt.cur_entity = trigger_entity prompt.conditional_state.musician_entity = MusicEntity(pref_label=trigger_entity.common_name, wiki_entity=trigger_entity) prompt.conditional_state.discussed_entities.append(trigger_entity) prompt.conditional_state.asked_question = 'QuestionLikedMusicianTemplate' # This is the handler function for the question we are asking. prompt.conditional_state.acknowledged_entity = True acknowledgment = random.choice(['', self.choose(ACKNOWLEDGE_MENTIONED_MUSICIAN)]) question = self.choose(QUESTION_DO_YOU_LIKE) response = "{} {}".format(acknowledgment, question) prompt.text = response.replace(WikiEntityInterface.ENTITY_PLACEHOLDER, trigger_entity.common_name) return prompt # Generic response. if question_candidates: prompt.priority = PromptType.GENERIC prompt.cur_entity = WikiEntityInterface.get_by_name(WikiEntityInterface.PageName.MUSICIAN) prompt.expected_type = WikiEntityInterface.EntityGroup.MUSICIAN question_name = random.choice(question_candidates) prompt.conditional_state.asked_question = question_name question = self.construct_response_from_templates(QUESTION_TEMPLATES, question_name, question=True) transition = random.choice(NO_ENTITY_TRANSITIONS) prompt.text = " ".join((transition, question)) return prompt # Ask a question about a musician we know about. if undiscussed_titles: selected_title = undiscussed_titles[0] cur_entity = WikiEntityInterface.get_by_name(selected_title) if cur_entity: prompt.priority = PromptType.GENERIC prompt.cur_entity = cur_entity prompt.conditional_state.musician_entity = MusicEntity(pref_label=cur_entity.common_name, wiki_entity=cur_entity) prompt.conditional_state.discussed_entities.append(cur_entity) prompt.conditional_state.asked_question = 'QuestionLikedMusicianTemplate' # This is the handler function for the question we are asking. question = self.choose(QUESTION_DO_YOU_LIKE_POPULAR) question = Pronoun.replace_pronouns(question, EXAMPLE_MUSICIAN_WIKI_PAGES[selected_title]) question = question.replace(WikiEntityInterface.ENTITY_PLACEHOLDER, cur_entity.common_name) transition = random.choice(ENTITY_TRANSITIONS) prompt.text = " ".join((transition, question)) return prompt # We ran out of prompts. return None
def get_response_trigger_phrase(self, state, trigger_phrase = None): utterance = self.state_manager.current_state.text triggered_templates = self.process_templates(QUESTION_TEMPLATES, utterance) sentiment_answers = self.process_templates(SENTIMENT_TEMPLATES, utterance) triggered_templates = {**triggered_templates, **sentiment_answers} undiscussed_titles = [title for title in EXAMPLE_MUSICIAN_WIKI_PAGES.keys() if not WikiEntityInterface.is_title_in_entities(title, state.discussed_entities)] trigger_entity = None if trigger_phrase: trigger_entity = WikiEntityInterface.link_span(trigger_phrase) if trigger_entity and not WikiEntityInterface.is_in_entity_group(trigger_entity, WikiEntityInterface.EntityGroup.MUSICIAN): trigger_entity = None if 'QuestionLikedMusicianTemplate' in triggered_templates: response = self._handle_question_like(state, triggered_templates) elif trigger_entity: response = self.get_response_trigger_entity(state, trigger_entity) elif undiscussed_titles: selected_title = undiscussed_titles[0] cur_entity = WikiEntityInterface.get_by_name(selected_title) question = self.choose(QUESTION_DO_YOU_LIKE_POPULAR) question = Pronoun.replace_pronouns(question, EXAMPLE_MUSICIAN_WIKI_PAGES[selected_title]) question = question.replace(WikiEntityInterface.ENTITY_PLACEHOLDER, cur_entity.common_name) response = self.prepare_rg_result(question, state, cur_entity=cur_entity) response.conditional_state.musician_entity = MusicEntity(pref_label=cur_entity.common_name, wiki_entity=cur_entity) response.conditional_state.discussed_entities.append(cur_entity) response.conditional_state.asked_question = 'QuestionLikedMusicianTemplate' # This is the handler function for the question we are asking. response.conditional_state.next_treelet = self.name response.conditional_state.needs_internal_prompt = False else: response = self._handle_expression_chat_musician(state, None) return response
def _handle_answer_favorite_question(self, state, triggered_answers): question_name = 'QuestionFavoriteSongTemplate' # Prepare responses if self.is_no_answer( ) or 'NegativeTemplate' in triggered_answers or 'DontKnowTemplate' in triggered_answers: response = self.choose(ACKNOWLEDGE_FAVORITE_SONG_NEGATIVE) rg_result = self.prepare_rg_result(response, state) rg_result.conditional_state.needs_internal_prompt = False rg_result.needs_prompt = True else: # Check if the user mentioned a song. song_wiki_entity = None if not song_wiki_entity and question_name in triggered_answers and 'answer' in triggered_answers[ question_name]: song_name = triggered_answers[question_name]['answer'] song_wiki_entity = WikiEntityInterface.link_span(song_name) # If the user mentioned a song, ask a follow up question. if song_wiki_entity and WikiEntityInterface.is_in_entity_group( song_wiki_entity, WikiEntityInterface.EntityGroup.SONG): response = self.choose(ACKNOWLEDGE_FAVORITE_SONG) followup = self.choose(QUESTION_WHY_DO_YOU_LIKE) response = "{} {}".format(response, followup) rg_result = self.prepare_rg_result(response, state) song_entity = MusicEntity( pref_label=song_wiki_entity.common_name, wiki_entity=song_wiki_entity) musician_entity = MusicianTreelet.get_musician( song_wiki_entity.name) rg_result.conditional_state.song_entity = song_entity rg_result.conditional_state.musician_entity = musician_entity rg_result.text = response.replace( WikiEntityInterface.ENTITY_PLACEHOLDER, song_wiki_entity.common_name) rg_result.cur_entity = song_wiki_entity rg_result.conditional_state.discussed_entities.append( song_wiki_entity) rg_result.conditional_state.needs_internal_prompt = False rg_result.conditional_state.next_treelet = self.name rg_result.conditional_state.asked_question = 'QuestionWhyDoYouLikeSong' # We don't know which song the user mentioned. elif state.num_repeats < REPEAT_THRESHOLD: response = self.choose(QUESTION_COULD_YOU_REPEAT) rg_result = self.prepare_rg_result(response, state) rg_result.conditional_state.repeated_question = True rg_result.conditional_state.needs_internal_prompt = False rg_result.conditional_state.next_treelet = self.name rg_result.conditional_state.asked_question = 'QuestionWhyDoYouLikeSong' else: response = self.choose(ACKNOWLEDGE_COULDNT_GET_SONG) rg_result = self.prepare_rg_result(response, state) rg_result.conditional_state.needs_internal_prompt = False return rg_result
def _handle_answer_like_question(self, state, triggered_answers): question_name = 'QuestionLikedMusicianTemplate' if 'NegativeTemplate' in triggered_answers or 'DontKnowTemplate' in triggered_answers: response = self.choose(ACKNOWLEDGE_LIKED_MUSICIAN_NEGATIVE) rg_result = self.prepare_rg_result(response, state) rg_result.conditional_state.needs_internal_prompt = False rg_result.needs_prompt = True else: # Check if the user mentioned a musician. musician_wiki_entity = self.state_manager.current_state.entity_linker.best_ent_of_type( WikiEntityInterface.EntityGroup.MUSICIAN) if state.musician_entity: musician_wiki_entity = state.musician_entity.wiki_entity if not musician_wiki_entity and question_name in triggered_answers and 'answer' in triggered_answers[question_name]: musician_name = triggered_answers[question_name]['answer'] musician_wiki_entity = WikiEntityInterface.link_span(musician_name) # If we know the musician. if musician_wiki_entity and WikiEntityInterface.is_in_entity_group(musician_wiki_entity, WikiEntityInterface.EntityGroup.MUSICIAN): if state.acknowledged_entity: response = self.choose(ACKNOWLEDGE_LIKED_MUSICIAN) else: response = self.choose(ACKNOWLEDGE_MENTIONED_MUSICIAN) response = response.replace(WikiEntityInterface.ENTITY_PLACEHOLDER, musician_wiki_entity.common_name) rg_result = self.prepare_rg_result(response, state) rg_result.conditional_state.discussed_entities.append(musician_wiki_entity) musician_entity = MusicEntity(pref_label=musician_wiki_entity.common_name, wiki_entity=musician_wiki_entity) song_entity = self.get_song_of_musician(musician_entity, state.discussed_entities) if song_entity: expression = self.choose(EXPRESS_INTEREST_OTHER_SONG) expression = expression.replace(f"SONG_{WikiEntityInterface.ENTITY_PLACEHOLDER}", song_entity.pref_label) expression = expression.replace(f"MUSICIAN_{WikiEntityInterface.ENTITY_PLACEHOLDER}", musician_entity.pref_label) question = self.choose(QUESTION_OTHER_SONGS) question = question.replace(WikiEntityInterface.ENTITY_PLACEHOLDER, musician_entity.pref_label) rg_result.text = f"{response} {expression} {question}" rg_result.cur_entity = song_entity.wiki_entity rg_result.conditional_state.needs_internal_prompt = False rg_result.conditional_state.next_treelet = self.name rg_result.conditional_state.asked_question = 'QuestionWhichOfTheirSongsDoYouLike' elif state.num_repeats < REPEAT_THRESHOLD: response = self.choose(QUESTION_COULD_YOU_REPEAT) rg_result = self.prepare_rg_result(response, state) rg_result.conditional_state.repeated_question = True rg_result.conditional_state.needs_internal_prompt = False rg_result.conditional_state.next_treelet = self.name rg_result.conditional_state.asked_question = 'QuestionLikedMusicianTemplate' else: response = self.choose(ACKNOWLEDGE_COULDNT_GET_MUSICIAN) rg_result = self.prepare_rg_result(response, state) rg_result.priority = ResponsePriority.WEAK_CONTINUE rg_result.conditional_state.needs_internal_prompt = False return rg_result
def get_musician(song_name): # Try to find the musician from the Wiki overview. musician_name = WikiEntityInterface.extract_musician_name_from_song_overview(song_name) if musician_name: wiki_entity = WikiEntityInterface.link_span(musician_name) if wiki_entity and WikiEntityInterface.is_in_entity_group(wiki_entity, WikiEntityInterface.EntityGroup.MUSICIAN): musician_entity = MusicEntity(pref_label=wiki_entity.common_name, wiki_entity=wiki_entity) return musician_entity # Try to find in Knowledge graph musician_entity = KnowledgeInterface().get_musician_entity_by_song(song_name) return musician_entity
def get_response_trigger_phrase(self, state, trigger_phrase=None): utterance = self.state_manager.current_state.text triggered_templates = self.process_templates(QUESTION_TEMPLATES, utterance) sentiment_answers = self.process_templates(SENTIMENT_TEMPLATES, utterance) triggered_templates = {**triggered_templates, **sentiment_answers} undiscussed_items = [ title for title in EXAMPLE_SONG_WIKI_PAGES if not WikiEntityInterface.is_title_in_entities( title, state.discussed_entities) ] trigger_entity = None if trigger_phrase: trigger_entity = WikiEntityInterface.link_span(trigger_phrase) if trigger_entity and not WikiEntityInterface.is_in_entity_group( trigger_entity, WikiEntityInterface.EntityGroup.SONG): trigger_entity = None response = None if 'QuestionFavoriteSongTemplate' in triggered_templates: response = self._handle_question_favorite(state, triggered_templates) elif trigger_entity: response = self.get_response_trigger_entity(state, trigger_entity) elif undiscussed_items: song_title, song_kid = undiscussed_items[0] cur_entity = WikiEntityInterface.get_by_name(song_title) if cur_entity: question = self.choose(QUESTION_DO_YOU_LIKE_POPULAR) question = question.replace( WikiEntityInterface.ENTITY_PLACEHOLDER, cur_entity.common_name) response = self.prepare_rg_result(question, state, cur_entity=cur_entity) response.conditional_state.song_entity = MusicEntity( pref_label=cur_entity.common_name, wiki_entity=cur_entity, kid=song_kid) response.conditional_state.discussed_entities.append( cur_entity) response.conditional_state.asked_question = 'QuestionWhyDoYouLikeSong' # This is the handler function for the question we are asking. response.conditional_state.next_treelet = self.name response.conditional_state.needs_internal_prompt = False if not response: response = self._handle_expression_chat_song(state, None) return response
def _handle_answer_listening_conditions_question(self, state, triggered_answers): question_name = 'QuestionListeningConditionsTemplate' # Determine which response we should give. is_rare_response = False if question_name in triggered_answers and 'rare_words' in triggered_answers[ question_name]: is_rare_response = True if self.is_no_answer( ) or 'NegativeTemplate' in triggered_answers or 'DontKnowTemplate' in triggered_answers: is_rare_response = True # Construct the response if is_rare_response: response = self.choose(ANSWER_LISTENING_FREQUENCY_RARE) else: surprise_expression = random.choice(SURPRISE_EXPRESSIONS) frequent_response = self.choose( ANSWER_LISTENING_CONDITIONS_FREQUENT) response = "{} {}".format(surprise_expression, frequent_response) # Prepare and return the RG result rg_result = self.prepare_rg_result(response, state) # Set the needs_prompt to True if we are not engaging the user if is_rare_response: rg_result.conditional_state.needs_internal_prompt = False rg_result.needs_prompt = True else: rg_result.cur_entity = WikiEntityInterface.get_by_name( WikiEntityInterface.PageName.MUSIC) return rg_result
def get_prompt(self, state, conditional_state=None, trigger_entity=None): # Instrument treelet only has generic prompts. question_candidates = [ q for q in list(QUESTION_TEMPLATES.keys()) if q not in state.asked_questions ] if question_candidates: question_name = self.choose(question_candidates) question = self.construct_response_from_templates( QUESTION_TEMPLATES, question_name, question=True) transition = random.choice(TRANSITIONS) prompt = self.prepare_prompt_result( " ".join((transition, question)), state, priority=PromptType.GENERIC, cur_entity=WikiEntityInterface.get_by_name( WikiEntityInterface.PageName.INSTRUMENT), conditional_state=conditional_state) prompt.conditional_state.turn_treelet_history.append(self.name) prompt.conditional_state.asked_question = question_name prompt.conditional_state.next_treelet = self.name prompt.conditional_state.needs_internal_prompt = False prompt.expected_type = WikiEntityInterface.EntityGroup.INSTRUMENT return prompt return None
def _handle_answer_feelings_about_music_question(self, state, triggered_answers): question_name = 'QuestionFeelingsAboutMusicTemplate' # Determine which response we should give. is_negative_response = False if question_name in triggered_answers and 'negative_feeling' in triggered_answers[ question_name]: is_negative_response = True if self.is_no_answer( ) or 'NegativeTemplate' in triggered_answers or 'DontKnowTemplate' in triggered_answers: is_negative_response = True # Construct the response if is_negative_response: dry_expression = self.choose(DRY_EXPRESSIONS) positive_response = self.choose(ANSWER_FEELINGS_POSITIVE) response = "{} {}".format(dry_expression, positive_response) else: surprise_expression = random.choice(SURPRISE_EXPRESSIONS) positive_response = self.choose(ANSWER_FEELINGS_POSITIVE) response = "{} {}".format(surprise_expression, positive_response) # Prepare and return the RG result rg_result = self.prepare_rg_result(response, state) # Set the needs_prompt to True if we are not engaging the user if is_negative_response: rg_result.conditional_state.needs_internal_prompt = False rg_result.needs_prompt = True else: rg_result.cur_entity = WikiEntityInterface.get_by_name( WikiEntityInterface.PageName.MUSIC) return rg_result
def _handle_expression_chat_song(self, state, triggered_templates): expression_name = 'ChatSong' response = self.choose(CHAT_SONG_EXPRESSIONS) rg_result = self.prepare_rg_result(response, state) rg_result.cur_entity = WikiEntityInterface.get_by_name( WikiEntityInterface.PageName.SONG) return rg_result
def create_rg_result_ask_another_song_of_musician(self, state, musician_entity, conditional_blacklist=[] ): blacklist = state.discussed_entities + conditional_blacklist song_entity = MusicianTreelet.get_song_of_musician( musician_entity, blacklist) if song_entity and WikiEntityInterface.is_in_entity_group( song_entity.wiki_entity, WikiEntityInterface.EntityGroup.SONG): question = self.choose(QUESTION_OTHER_SONG) musician_placeholder = f'MUSICIAN_{WikiEntityInterface.ENTITY_PLACEHOLDER}' song_placeholder = f'SONG_{WikiEntityInterface.ENTITY_PLACEHOLDER}' question = question.replace(musician_placeholder, musician_entity.pref_label) question = question.replace(song_placeholder, song_entity.pref_label) rg_result = self.prepare_rg_result(question, state) rg_result.conditional_state.discussed_entities = conditional_blacklist + [ song_entity.wiki_entity ] rg_result.conditional_state.needs_internal_prompt = False rg_result.conditional_state.asked_question = 'QuestionAnotherSongOfMusician' rg_result.conditional_state.next_treelet = self.name rg_result.conditional_state.discussed_entities.append( song_entity.wiki_entity) rg_result.cur_entity = song_entity.wiki_entity return rg_result return None
def _get_treelet_name_for_entity(self, entity): entity_treelet_name = None for treelet_name, treelet in self.treelets.items(): for entity_group in treelet.trigger_entity_groups: if WikiEntityInterface.is_in_entity_group( entity, entity_group): if not entity_treelet_name: entity_treelet_name = treelet_name return entity_treelet_name
def _handle_expression_like_music(self, state, triggered_templates): expression_name = 'LikeMusicTemplate' like_reason = self.choose(LIKE_REASONS) surprise_expression = random.choice(SURPRISE_EXPRESSIONS) response = "{} {}".format(surprise_expression, like_reason) rg_result = self.prepare_rg_result(response, state) rg_result.cur_entity = WikiEntityInterface.get_by_name( WikiEntityInterface.PageName.MUSIC) return rg_result
def _handle_expression_chat_music(self, state, triggered_templates): expression_name = 'ChatMusicTemplate' like_reason = self.choose(LIKE_REASONS) chatting_expression = "" # self.choose(CHATTING_EXPRESSIONS) response = "{} {}".format(like_reason, chatting_expression) rg_result = self.prepare_rg_result(response, state) rg_result.cur_entity = WikiEntityInterface.get_by_name( WikiEntityInterface.PageName.MUSIC) return rg_result
def _handle_question_listening_frequency(self, state, triggered_templates): question_name = 'QuestionListeningFrequencyTemplate' # Construct our answer from the example answers response = self.choose(ANSWER_LISTENING_FREQUENCY_FREQUENT) rg_result = self.prepare_rg_result(response, state) rg_result = self._update_remaining_prompts(rg_result, question_name) rg_result.cur_entity = WikiEntityInterface.get_by_name( WikiEntityInterface.PageName.MUSIC) return rg_result
def _handle_question_feelings_about_music(self, state, triggered_templates): question_name = 'QuestionFeelingsAboutMusicTemplate' response = self.choose(ANSWER_FEELINGS_POSITIVE) rg_result = self.prepare_rg_result(response, state) rg_result = self._update_remaining_prompts(rg_result, question_name) rg_result.cur_entity = WikiEntityInterface.get_by_name( WikiEntityInterface.PageName.MUSIC) return rg_result
def _handle_answer_favorite_question(self, state, triggered_answers): question_name = 'QuestionFavoriteInstrumentTemplate' # Check if the user mentioned an instrument. cur_entity = self.state_manager.current_state.entity_tracker.cur_entity instrument_entity = None if cur_entity and WikiEntityInterface.is_in_entity_group( cur_entity, WikiEntityInterface.EntityGroup.INSTRUMENT): instrument_entity = cur_entity elif question_name in triggered_answers and 'answer' in triggered_answers[ question_name]: instrument_name = triggered_answers[question_name]['answer'] instrument_entity = WikiEntityInterface.link_span( instrument_name.capitalize()) # If the user mentioned an instrument, ask a follow up question. if instrument_entity: response = self.choose(ACKNOWLEDGE_FAVORITE_INSTRUMENT) followup = self.choose(FAVORITE_INSTRUMENT_FOLLOWUP_QUESTIONS) response = "{} {}".format(response, followup) response = response.replace(WikiEntityInterface.ENTITY_PLACEHOLDER, instrument_entity.common_name) rg_result = self.prepare_rg_result(response, state) rg_result.cur_entity = instrument_entity rg_result.conditional_state.asked_question = 'QuestionFavoriteInstrumentTemplate Followup 1' rg_result.conditional_state.needs_internal_prompt = False rg_result.conditional_state.next_treelet = self.name # If not, acknowledge the user response and exit the Music RG. elif self.is_no_answer( ) or 'NegativeTemplate' in triggered_answers or 'DontKnowTemplate' in triggered_answers: response = self.choose(ACKNOWLEDGE_FAVORITE_INSTRUMENT_NEGATIVE) rg_result = self.prepare_rg_result(response, state) rg_result.conditional_state.needs_internal_prompt = False rg_result.needs_prompt = True else: response = self.choose(ACKNOWLEDGE_FAVORITE_INSTRUMENT_NEVER_HEARD) rg_result = self.prepare_rg_result(response, state) rg_result.conditional_state.needs_internal_prompt = False rg_result.needs_prompt = True return rg_result
def _handle_answer_liked_songs(self, state, triggered_templates): question_name = 'QuestionWhichOfTheirSongsDoYouLike' cur_entity = self.state_manager.current_state.entity_tracker.cur_entity current_state = self.state_manager.current_state user_initiated = current_state.entity_tracker.cur_entity_initiated_by_user_this_turn(current_state) if cur_entity and user_initiated and WikiEntityInterface.is_in_entity_group(cur_entity, WikiEntityInterface.EntityGroup.SONG): response = self.choose(ACKNOWLEDGE_LIKED_SONGS) rg_result = self.prepare_rg_result(response, state) else: response = self.choose(ACKNOWLEDGE_LIKED_SONGS_NEGATIVE) rg_result = self.prepare_rg_result(response, state) rg_result.conditional_state.needs_internal_prompt = False rg_result.needs_prompt = True return rg_result