예제 #1
0
 def check_bye_intent(self, utterance):
     # checking for intent = "bye"
     user_dacts = []
     dact = DialogueAct(UserIntents.UNK, [])
     if any([
             re.search(r'\b{0}\b'.format(pattern), utterance)
             for pattern in self.bye_pattern
     ]):
         dact.intent = UserIntents.BYE
     if dact.intent != UserIntents.UNK:
         user_dacts.append(dact)
     return user_dacts
예제 #2
0
 def check_inquire_intent(self, utterance):
     # matching intents to "list", "Summarize", "Subset", "Compare" and "Similar"
     user_dacts = []
     dact = DialogueAct(UserIntents.UNK, [])
     for slot, values in self.tag_words_user_inquire.items():
         if any([value for value in values if value in utterance]):
             dact.intent = UserIntents.INQUIRE
             dact.params.append(ItemConstraint(slot, Operator.EQ, ""))
     if dact.intent == UserIntents.UNK:  # and self._is_question(raw_utterance):
         for slot, values in self.tag_words_user_reveal_inquire.items():
             if any([value for value in values if value in utterance]):
                 dact.intent = UserIntents.INQUIRE
                 dact.params.append(ItemConstraint(slot, Operator.EQ, ""))
     if dact.intent != UserIntents.UNK:
         user_dacts.append(dact)
     return user_dacts
예제 #3
0
    def start_dialogue(self, new_user=False):
        """Starts the dialogue by generating a response from the agent

        :return: First agent response
        """
        self.dialogue_state_tracker.dialogue_state.initialize()
        self.dialogue_state_tracker.dialogue_context.initialize()
        agent_dact = DialogueAct(AgentIntents.WELCOME, [
            ItemConstraint('new_user', Operator.EQ, new_user),
            ItemConstraint('is_bot', Operator.EQ, self.isBot)
        ])
        self.dialogue_state_tracker.update_state_agent([agent_dact])
        return [agent_dact]
예제 #4
0
 def check_reject_intent(self, utterance):
     # checking for intent = "reject"
     user_dacts = []
     dact = DialogueAct(UserIntents.UNK, [])
     if any([
             re.search(r'\b{0}\b'.format(pattern), utterance)
             for pattern in self.dontlike_movie_pattern
     ]):
         dact.intent = UserIntents.REJECT
         dact.params = [ItemConstraint('reason', Operator.EQ, 'dont_like')]
     elif any([
             re.search(r'\b{0}\b'.format(pattern), utterance)
             for pattern in self.watched_pattern
     ]):
         dact.intent = UserIntents.REJECT
         dact.params = [ItemConstraint('reason', Operator.EQ, 'watched')]
     if dact.intent != UserIntents.UNK:
         user_dacts.append(dact)
     return user_dacts
예제 #5
0
    def _user_options_remove_preference_CIN(self, CIN):
        """Generate options for user to select a parameter to remove

        :type CIN: dict
        :param CIN: The current information needs
        :return: a list of button options
        """
        options = {}
        params = []
        for slot, values in CIN.items():
            if not values: continue
            if isinstance(values, list):
                params.extend([
                    ItemConstraint(slot, Operator.EQ, value)
                    for value in set(values)
                    if value not in Values.__dict__.values()
                    and not value.startswith('.NOT.')
                ])
            else:
                if values not in Values.__dict__.values(
                ) and not values.startswith('.NOT.'):
                    params.append(ItemConstraint(slot, Operator.EQ, values))

        for param in params:
            value = deepcopy(param.value)
            negative = False
            if value.startswith('.NOT.'):
                negative = True  # TODO. Add changes here
                value = value.replace('.NOT.', '')
            _a_an = 'an' if value[0] in ['a', 'e', 'i', 'o', 'u'] else 'a'
            param_key = DialogueAct(UserIntents.REMOVE_PREFERENCE, [param])
            if param.slot == Slots.GENRES.value:
                if negative:
                    options[param_key] = [
                        random.choice([
                            f'I want {_a_an} "{value}" movie.',
                            f'I would prefer {_a_an} "{value}" '
                            f'film.'
                        ])
                    ]
                else:
                    options[param_key] = [
                        random.choice([
                            f'Don\'t want {_a_an} "{value}" '
                            f'movie.', f'Won\'t prefer {_a_an} "{value}" film.'
                        ])
                    ]
            elif param.slot == Slots.TITLE.value:
                if negative:
                    options[param_key] = [
                        f'I want movies named like "{value}".'
                    ]
                else:
                    options[param_key] = [f'No movies named like "{value}".']
            elif param.slot == Slots.KEYWORDS.value:
                if negative:
                    options[param_key] = [f'I need movies based on "{value}".']
                else:
                    options[param_key] = [
                        random.choice([
                            f'Don\'t need movies based on '
                            f'"{value}".',
                            f'No need of {_a_an} "{value}" film.'
                        ])
                    ]
            elif param.slot == Slots.DIRECTORS.value:
                if negative:
                    options[param_key] = [
                        random.choice([
                            f'I want the director "{value.title()}".',
                            f'Should be directed by "{value.title()}".'
                        ])
                    ]
                else:
                    options[param_key] = [
                        random.choice([
                            f'Don\'t want the director "{value.title()}".',
                            f'Shouldn\'t be directed by "{value.title()}".'
                        ])
                    ]
            elif param.slot == Slots.ACTORS.value:
                if negative:
                    options[param_key] = [
                        f'I want the actor "{value.title()}".'
                    ]
                else:
                    options[param_key] = [
                        random.choice([
                            f'Don\'t consider actor "{value.title()}".',
                            f'Remove "{value.title()}" from the list of actors.'
                        ])
                    ]
            elif param.slot == Slots.YEAR.value:
                if negative:
                    options[param_key] = [
                        random.choice([
                            f'Release year should be the "'
                            f'{self._summarize_title_year(value)}".',
                            f'Need a movie from the "'
                            f'{self._summarize_title_year(value)}".'
                        ])
                    ]
                else:
                    options[param_key] = [
                        random.choice([
                            f'Release year shouldn\'t be the "'
                            f'{self._summarize_title_year(value)}".',
                            f'Don\'t need a movie from the "'
                            f'{self._summarize_title_year(value)}".'
                        ])
                    ]
            options.update({'/restart': ['/restart']})
        return options
예제 #6
0
    def _user_options_remove_preference(self, dual_params):
        """Generate options for user to select in case of two parameters have same value

        :param dual_params: The current parameters with two slots
        :return: a list of button options
        """
        options = {}
        for value, params in dual_params.items():
            for param in params:
                negative = False
                if value.startswith('.NOT.'):
                    negative = True  # TODO. Add changes here
                    value = value.replace('.NOT.', '')
                _a_an = 'an' if value[0] in ['a', 'e', 'i', 'o', 'u'] else 'a'
                param_key = DialogueAct(UserIntents.REMOVE_PREFERENCE, [param])
                if param == Slots.GENRES.value:
                    if negative:
                        options[param_key] = [
                            random.choice([
                                f'I want {_a_an} "{value}" '
                                f'genre movie.',
                                f'I would prefer {_a_an} "{value}" '
                                f'genre film.'
                            ])
                        ]
                    else:
                        options[param_key] = [
                            random.choice([
                                f'Don\'t want {_a_an} "{value}" genre'
                                f'movie.', f'Won\'t prefer {_a_an} "{value}" '
                                f'genre film.'
                            ])
                        ]
                elif param == Slots.TITLE.value:
                    if negative:
                        options[param_key] = [
                            f'I want movies named like "{value}".'
                        ]
                    else:
                        options[param_key] = [
                            f'No movies named like "{value}".'
                        ]
                elif param == Slots.KEYWORDS.value:
                    if negative:
                        options[param_key] = [
                            f'I need movies based on "{value}".'
                        ]
                    else:
                        options[param_key] = [
                            random.choice([
                                f'Don\'t need movies based on '
                                f'"{value}".',
                                f'No need of {_a_an} "{value}" film.'
                            ])
                        ]
                elif param == Slots.DIRECTORS.value:
                    if negative:
                        options[param_key] = [
                            random.choice([
                                f'I want the director "{value.title()}".',
                                f'Should be directed by "{value.title()}".'
                            ])
                        ]
                    else:
                        options[param_key] = [
                            random.choice([
                                f'Don\'t want the director "{value.title()}".',
                                f'Shouldn\'t be directed by "{value.title()}".'
                            ])
                        ]
                elif param == Slots.ACTORS.value:
                    if negative:
                        options[param_key] = [
                            f'I want the actor "{value.title()}".'
                        ]
                    else:
                        options[param_key] = [
                            random.choice([
                                f'Don\'t consider actor "{value.title()}".',
                                f'Remove "{value.title()}" from the list of actors.'
                            ])
                        ]
                elif param == Slots.YEAR.value:
                    if negative:
                        options[param_key] = [
                            random.choice([
                                f'Release year should be the "'
                                f'{self._summarize_title_year(value)}".',
                                f'Need a movie from the "'
                                f'{self._summarize_title_year(value)}".'
                            ])
                        ]
                    else:
                        options[param_key] = [
                            random.choice([
                                f'Release year shouldn\'t be the "'
                                f'{self._summarize_title_year(value)}".',
                                f'Don\'t need a movie from the "'
                                f'{self._summarize_title_year(value)}".'
                            ])
                        ]
                options.update({'/restart': ['/restart']})
        return options
예제 #7
0
    def generate_dact(self, raw_utterance, options, dialogue_state=None, dialogue_context=None):
        """Processes the utterance according to dialogue state and context and generate a user
        dialogue act for Agent to understand.

        :type dialogue_state: DialogueState
        :type last_agent_dact: DialogueAct
        :type options: dict
        :param utterance: a string containing user input
        :param options: a list of options provided to the user to choose from
        :param dialogue_state: the current dialogue state, if available
        :param dialogue_context: the current dialogue context, if available
        :return: a list of dialogue acts
        """
        # this is the top priority. The agent must check if user selected any option
        if options:
            for dact, value in options.items():
                if (isinstance(value, list) and value[0] == raw_utterance) or value == \
                        raw_utterance:
                    if dact.intent == UserIntents.CONTINUE_RECOMMENDATION:
                        dact.params = self.intents_checker.generate_params_continue_recommendation(
                            dialogue_state.item_in_focus)
                    return [dact]

        user_dacts = []  # Define a list of dialogue acts for this specific utterance
        utterance = self.intents_checker._lemmatize_value(
            raw_utterance)  # process the utterance for necessary
        self.dialogue_state = dialogue_state

        user_dacts.extend(self.intents_checker.check_bye_intent(utterance))
        if len(user_dacts) > 0:
            return user_dacts

        if not self.dialogue_state.last_agent_dacts:
            user_dacts.extend(self.intents_checker.check_reveal_voluntary_intent(utterance,
                                                                                 raw_utterance))
            if len(user_dacts) == 0:
                user_dacts.extend(self.intents_checker.check_hi_intent(utterance))
            if len(user_dacts) > 0:
                return user_dacts
            else:
                return None

        for last_agent_dact in self.dialogue_state.last_agent_dacts:
            if last_agent_dact.intent == AgentIntents.WELCOME:
                user_dacts.extend(self.intents_checker.check_reveal_voluntary_intent(utterance,
                                                                                     raw_utterance))
                if len(user_dacts) == 0:
                    user_dacts.extend(self.intents_checker.check_acknowledge_intent(utterance))
                if len(user_dacts) > 0:
                    return user_dacts
            elif last_agent_dact.intent == AgentIntents.ELICIT:
                user_dacts.extend(self.intents_checker.check_reveal_intent(utterance, raw_utterance,
                                                                           last_agent_dact))
                if len(user_dacts) == 0 or any([param.value in Values.__dict__.values() for dact
                                                in user_dacts for param in dact.params]):
                    user_dacts.extend(self.intents_checker.check_reveal_voluntary_intent(utterance,
                                                                                         raw_utterance))
                if len(user_dacts) > 0:
                    return user_dacts

        if dialogue_state.agent_made_offer:
            user_dacts.extend(self.intents_checker.check_reject_intent(utterance))
        if len(user_dacts) == 0:
            user_dacts.extend(self.intents_checker.check_inquire_intent(utterance))
        if len(user_dacts) == 0:
            user_dacts.extend(self.intents_checker.check_reveal_voluntary_intent(utterance,
                                                                                 raw_utterance))
        if len(user_dacts) == 0:
            deny_dact = self.intents_checker.check_deny_intent(utterance)
            if len(deny_dact) > 0:
                deny_dact[0].intent = UserIntents.INQUIRE
                user_dacts.extend(deny_dact)
        if len(user_dacts) > 0:
            return user_dacts

        if len(user_dacts) == 0:
            user_dacts.append(DialogueAct(UserIntents.UNK, []))
        return user_dacts
예제 #8
0
    def next_action(self,
                    dialogue_state,
                    dialogue_context=None,
                    restart=False):
        """Decides the next action to be taken by the agent based on the current state and context.

        :type dialogue_state: DialogueState
        :param dialogue_state: current dialogue state
        :param dialogue_context: context of the dialogue
        :return: a list of Dialogue Acts
        """
        agent_dacts = []
        slots = deepcopy(dialogue_state.agent_requestable)
        if not dialogue_state.last_user_dacts and not restart:
            agent_dacts.append(
                DialogueAct(AgentIntents.WELCOME, [
                    ItemConstraint('new_user', Operator.EQ, self.new_user),
                    ItemConstraint('is_bot', Operator.EQ, self.isBot)
                ]))
            return agent_dacts

        if not dialogue_state.last_agent_dacts and not restart:
            if not dialogue_state.last_agent_dacts:
                agent_dacts.append(
                    DialogueAct(AgentIntents.WELCOME, [
                        ItemConstraint('new_user', Operator.EQ, self.new_user),
                        ItemConstraint('is_bot', Operator.EQ, self.isBot)
                    ]))

        if (not dialogue_state.last_user_dacts and restart) or \
                (dialogue_state.last_user_dacts and UserIntents.RESTART in
                 [dact.intent for dact in dialogue_state.last_user_dacts]):
            agent_dacts.append(DialogueAct(AgentIntents.RESTART, []))
            agent_dacts.append(
                DialogueAct(AgentIntents.ELICIT,
                            [ItemConstraint(slots[0], Operator.EQ, '')]))
            return agent_dacts

        for user_dact in dialogue_state.last_user_dacts:
            agent_dact = DialogueAct(AgentIntents.UNK, [])
            # generating intent = "bye"
            if user_dact.intent == UserIntents.BYE:
                agent_dact.intent = AgentIntents.BYE
                agent_dacts.append(deepcopy(agent_dact))
                return agent_dacts

            # generating intent = "elicit"
            if user_dact.intent == UserIntents.ACKNOWLEDGE or user_dact.intent == \
                    UserIntents.UNK:
                if AgentIntents.WELCOME in [
                        dact.intent for dact in dialogue_state.last_agent_dacts
                ]:
                    agent_dact.intent = AgentIntents.ELICIT
                    agent_dact.params.append(
                        ItemConstraint(slots[0], Operator.EQ, ''))
                    agent_dacts.append(deepcopy(agent_dact))
                    return agent_dacts

            # deciding between intent "elicit" or "recommend"
            if dialogue_state.agent_made_partial_offer:  # agent will inform about number of
                CIN_slots = [
                    key for key in dialogue_state.frame_CIN.keys()
                    if not dialogue_state.frame_CIN[key]
                    and key != Slots.TITLE.value
                ]
                if len(
                        CIN_slots
                ) >= dialogue_state.slot_left_unasked:  # if there is a scope of
                    # further questioning
                    # results and will ask next question
                    agent_dact.intent = AgentIntents.COUNT_RESULTS
                    agent_dact.params.append(
                        ItemConstraint('count', Operator.EQ,
                                       len(dialogue_state.database_result)))
                    agent_dacts.append(deepcopy(agent_dact))
                    # adding another dialogue act of ELICIT
                    if dialogue_state.agent_req_filled:
                        random.shuffle(CIN_slots)
                        agent_dact = DialogueAct(AgentIntents.ELICIT, [])
                        agent_dact.params.append(
                            ItemConstraint(CIN_slots[0], Operator.EQ, ""))
                        agent_dacts.append(deepcopy(agent_dact))
                    else:
                        agent_dact = DialogueAct(AgentIntents.ELICIT, [])
                        random.shuffle(slots)
                        for slot in slots:
                            if not dialogue_state.frame_CIN[slot]:
                                agent_dact.params.append(
                                    ItemConstraint(slot, Operator.EQ, ''))
                                break
                        agent_dacts.append(deepcopy(agent_dact))

                else:
                    agent_dact = DialogueAct(AgentIntents.RECOMMEND, [])
                    item_in_focus = dialogue_state.database_result[0]
                    agent_dact.params.append(
                        ItemConstraint(Slots.TITLE.value, Operator.EQ,
                                       item_in_focus[Slots.TITLE.value]))
            elif dialogue_state.agent_should_make_offer:
                agent_dact.intent = AgentIntents.RECOMMEND
                agent_dact.params.append(
                    ItemConstraint(
                        Slots.TITLE.value, Operator.EQ,
                        dialogue_state.item_in_focus[Slots.TITLE.value]))
                agent_dacts.append(deepcopy(agent_dact))
            elif dialogue_state.agent_offer_no_results:
                agent_dact.intent = AgentIntents.NO_RESULTS
                agent_dacts.append(deepcopy(agent_dact))
            elif dialogue_state.agent_made_offer:
                if user_dact.intent == UserIntents.INQUIRE:
                    agent_dact.intent = AgentIntents.INFORM
                    for param in user_dact.params:
                        if param.slot != Slots.MORE_INFO.value:
                            agent_dact.params.append(
                                ItemConstraint(
                                    param.slot, Operator.EQ,
                                    dialogue_state.item_in_focus[param.slot]))
                        else:
                            agent_dact.params.append(
                                ItemConstraint(
                                    param.slot, Operator.EQ,
                                    dialogue_state.item_in_focus[
                                        Slots.TITLE.value]))
                    if len(agent_dact.params) == 0:
                        agent_dact.params.append(
                            ItemConstraint(
                                'deny', Operator.EQ,
                                dialogue_state.item_in_focus[
                                    Slots.TITLE.value]))
                    agent_dacts.append(deepcopy(agent_dact))
                # elif user_dact.intent == UserIntents.REVEAL and Slots.TITLE.value in [param.slot for
                #                                                                      param in
                #                                                                      user_dact.params]:
                #     agent_dact.intent = AgentIntents.INFORM
                #     agent_dact.params.append(ItemConstraint(Slots.MORE_INFO.value, Operator.EQ,
                #                                             dialogue_state.item_in_focus[
                #                                                 Slots.TITLE.value]))
                #     agent_dacts.append(deepcopy(agent_dact))
                elif user_dact.intent == UserIntents.ACCEPT:
                    agent_dact.intent = AgentIntents.CONTINUE_RECOMMENDATION
                    agent_dact.params.append(
                        ItemConstraint(
                            Slots.TITLE.value, Operator.EQ,
                            dialogue_state.item_in_focus[Slots.TITLE.value]))
                    agent_dacts.append(deepcopy(agent_dact))

            if agent_dact.intent == AgentIntents.UNK:
                if not dialogue_state.agent_req_filled and user_dact.intent != UserIntents.HI:
                    agent_dact.intent = AgentIntents.ELICIT
                    # random.shuffle(slots)
                    for slot in slots:
                        if not dialogue_state.frame_CIN[slot]:
                            agent_dact.params.append(
                                ItemConstraint(slot, Operator.EQ, ''))
                            break
                elif user_dact.intent == UserIntents.UNK:
                    agent_dact.intent = AgentIntents.CANT_HELP
                if agent_dact.intent != AgentIntents.UNK:
                    agent_dacts.append(deepcopy(agent_dact))

        if len(agent_dacts) == 0:
            agent_dacts.append(DialogueAct(AgentIntents.CANT_HELP, []))
        # Adding example:
        for agent_dact in agent_dacts:
            if agent_dact.intent == AgentIntents.ELICIT and \
                    agent_dact.params[0].slot not in [Slots.YEAR.value]:
                if dialogue_state.database_result:
                    agent_dact.params[0].value = self._generate_examples(
                        dialogue_state.database_result,
                        agent_dact.params[0].slot)
        return agent_dacts