Пример #1
0
    def check_inquire_intent(self, user_utterance):
        """

        Args:
            utterance: 

        """
        # matching intents to 'list', 'Summarize', 'Subset', 'Compare' and
        # 'Similar'
        tokens = user_utterance.get_tokens()
        utterance = sum(tokens).lemma if tokens else ''
        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
Пример #2
0
    def check_reveal_intent(self, user_utterance, last_agent_dact):
        """This function is only called if the intent of agent is ELicit to see
        if user has answered the query

        Args:
            utterance: 
            raw_utterance: 
            last_agent_dact: 

        """
        user_dacts = []
        for param in last_agent_dact.params:
            dact = DialogueAct(UserIntents.UNK, [])
            slot = param.slot
            params = self.slot_annotator.slot_annotation(slot, user_utterance)
            if params:
                dact.intent = UserIntents.REVEAL
                dact.params.extend(params)
            if dact.intent == UserIntents.UNK and self.is_dontcare(
                    user_utterance):
                dact.intent = UserIntents.REVEAL
                dact.params.append(
                    ItemConstraint(param.slot, Operator.EQ, Values.DONT_CARE))
            if dact.intent != UserIntents.UNK:
                # print(f'All Dacts\n{dact}')
                self._filter_dact(dact, user_utterance.get_text())
                # print(f'Filtered Dacts\n{dact}')
                if len(dact.params) > 0:
                    user_dacts.append(dact)
            else:
                dact.intent = UserIntents.REVEAL
                dact.params.append(
                    ItemConstraint(param.slot, Operator.EQ, Values.NOT_FOUND))
                user_dacts.append(dact)
        return user_dacts
Пример #3
0
    def _user_options_recommend(self):
        """Give use button options when making a recommendation
        
        Returns:
            a list of button options

        """
        options = {
            DialogueAct(UserIntents.REJECT, [
                ItemConstraint('reason', Operator.EQ, 'watched')
            ]): ['I have already watched it.'],
            # [random.choice(['I have already watched it.',
            #                 'I have seen this already.'])],
            DialogueAct(UserIntents.REJECT, [
                ItemConstraint('reason', Operator.EQ, 'dont_like')
            ]): ['Recommend me something else please.'],
            # [random.choice(['I don\'t like this recommendation.',
            #                 'Recommend me something else please.'])],
            DialogueAct(UserIntents.ACCEPT, []):
            ['I like this recommendation.'],
            DialogueAct(UserIntents.INQUIRE, [
                ItemConstraint(Slots.MORE_INFO.value, Operator.EQ, '')
            ]): [
                random.choice(
                    ['Tell me something about it.', 'Tell me more about it.'])
            ]
        }
        options.update({'/restart': ['/restart']})
        return options
Пример #4
0
    def check_reveal_voluntary_intent(self, user_utterance):
        """

        Args:
            utterance: 
            raw_utterance: 

        """
        user_dacts = []
        dact = DialogueAct(UserIntents.UNK, [])
        person_name_checks = False
        for slot in self.ontology.slots_annotation:
            if slot in [x.value for x in [Slots.ACTORS, Slots.DIRECTORS]]:
                if person_name_checks:
                    continue
                else:
                    person_name_checks = True
            # if slot == Slots.TITLE.value and dact.intent!= UserIntents.UNK:
            # continue
            params = self.slot_annotator.slot_annotation(slot, user_utterance)
            if params:
                dact.intent = UserIntents.REVEAL
                dact.params.extend(params)
                # user_dacts.append(dact)
                # return user_dacts
        if dact.intent != UserIntents.UNK:
            # print(f'All Dacts\n{dact}')
            self._filter_dact(dact, user_utterance.get_text())
            # print(f'Filtered Dacts\n{dact}')
            if len(dact.params) > 0:
                user_dacts.append(dact)
        return user_dacts
Пример #5
0
    def _user_options_continue(self, agent_dact):
        """Give user options to continue when needed

        Args:
            agent_dact: 

        """
        if agent_dact.intent == AgentIntents.CONTINUE_RECOMMENDATION:
            options = {
                DialogueAct(UserIntents.CONTINUE_RECOMMENDATION, []):
                ["I would like a similar recommendation."],
                DialogueAct(UserIntents.RESTART, []):
                ['I want to restart for a new movie.'],
                DialogueAct(UserIntents.BYE, []):
                ['I would like to quit now.']
            }
            return options
Пример #6
0
    def check_deny_intent(self, utterance):
        """
        TODO (Ivica Kostric): This is not needed anymore and should be removed.
        Handling of basic intents is merged into a single method
        (check_basic_intent) due to similarities.

        Args:
            utterance:

        """
        user_dacts = []
        dact = DialogueAct(UserIntents.UNK, [])
        for token in utterance.get_tokens():
            for pattern in self.deny_pattern:
                match = re.search(r'\b{0}\b'.format(pattern), token.lemma)
                if match:
                    dact.intent = UserIntents.DENY
        if dact.intent != UserIntents.UNK:
            user_dacts.append(dact)
        return user_dacts
Пример #7
0
    def _user_options_inquire(self, dialogue_state):
        """

        Args:
            dialogue_state: 

        Returns:
            list of user requestables as buttons

        """
        options = {}
        requestables = {
            Slots.GENRES.value: 'genres',
            Slots.PLOT.value: 'movie plot',
            Slots.DIRECTORS.value: 'director name',
            Slots.DURATION.value: 'duration',
            Slots.ACTORS.value: 'list of actors',
            Slots.YEAR.value: 'release year',
            Slots.RATING.value: 'rating'
        }
        for slot in dialogue_state.user_requestable:
            dact = DialogueAct(UserIntents.INQUIRE,
                               [ItemConstraint(slot, Operator.EQ, '')])
            options[dact] = requestables.get(slot, 'Invalid slot')
        options.update({
            DialogueAct(UserIntents.REJECT, [
                ItemConstraint('reason', Operator.EQ, 'dont_like')
            ]): ['I don\'t like this recommendation.'],
            # [random.choice(['I don\'t like this recommendation.',
            #                 'Recommend me something else please.'])],
            DialogueAct(UserIntents.ACCEPT, []): [
                'I like this recommendation.'
            ],
            DialogueAct(UserIntents.CONTINUE_RECOMMENDATION, []): [
                "I would like a similar recommendation."
            ],
            DialogueAct(UserIntents.RESTART, []): [
                'I want to restart for a new movie.'
            ],
        })
        return options
Пример #8
0
    def check_reject_intent(self, user_utterance):
        """

        Args:
            utterance: 

        """
        # checking for intent = 'reject'
        tokens = user_utterance.get_tokens()
        utterance = sum(tokens).lemma if tokens else ''
        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
Пример #9
0
    def check_hi_intent(self, utterance):
        """Checking for a starting message

        TODO (Ivica Kostric): This is not needed anymore and should be removed.
        Handling of basic intents is merged into a single method
        (check_basic_intent) due to similarities.

        Args:
            utterance:

        """
        user_dacts = []
        dact = DialogueAct(UserIntents.UNK, [])
        for token in utterance.get_tokens():
            if any([
                    re.search(r'\b{0}\b'.format(pattern), token.lemma)
                    for pattern in self.hi_pattern
            ]):
                dact.intent = UserIntents.HI
        if dact.intent != UserIntents.UNK:
            user_dacts.append(dact)
        return user_dacts
Пример #10
0
    def check_basic_intent(self, user_utterance, intent):
        """Given intent and list of intent patterns checks if any token in
        user utterance match the pattern.

        Args:
            user_utterance (UserUtterance): class containing raw utterance and
                processed tokens
            intent (UserIntents): Intent for which to compare patterns.

        Returns:
            List[DialogueAct]: If pattern exists returns that intents dialogue
                act
        """
        user_dacts = []
        dact = DialogueAct(UserIntents.UNK, [])
        for token in user_utterance.get_tokens():
            if any([
                    re.search(r'\b{0}\b'.format(pattern), token.lemma)
                    for pattern in self.basic_patterns.get(intent, [])
            ]):
                dact.intent = intent
        if dact.intent != UserIntents.UNK:
            user_dacts.append(dact)
        return user_dacts
Пример #11
0
    def start_dialogue(self, new_user=False):
        """Starts the dialogue by generating a response from the agent
        
        :return: First agent response

        Args:
            new_user:  (Default value = False)

        """
        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]
Пример #12
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.

        Args:
            dialogue_state: current dialogue state
            dialogue_context: context of the dialogue (Default value = None)
            restart:  (Default value = False)

        Returns:
            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
Пример #13
0
    def _user_options_remove_preference_CIN(self, CIN):
        """Generate options for user to select a parameter to remove

        Args:
            CIN: The current information needs

        Returns:
            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
Пример #14
0
    def _user_options_remove_preference(self, dual_params):
        """Generate options for user to select in case of two parameters have same value

        Args:
            dual_params: The current parameters with two slots

        Returns:
            a list of button options

        """
        options = {}
        for value, params in dual_params.items():
            for param in params:
                negative = False
                # TODO (Ivica Kostric): Look into this. Looks like a bug.
                # value is not a string in some (all?) cases. It can be
                # of class Values.
                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
Пример #15
0
    def generate_dact(self,
                      user_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.

        Args:
            user_utterance: UserUtterance class containing user input
            options: a list of options provided to the user to choose from
            dialogue_state: the current dialogue state, if available
                (Default value = None)
            dialogue_context: the current dialogue context, if available
                (Default value = None)

        Returns:
            a list of dialogue acts

        """
        # this is the top priority. The agent must check if user selected
        # any option
        selected_option = self.get_selected_option(
            user_utterance, options, dialogue_state.item_in_focus)
        if selected_option:
            return selected_option

        # Define a list of dialogue acts for this specific utterance
        user_dacts = []

        # process the utterance for necessary
        # utterance = self.intents_checker._lemmatize_value(raw_utterance)
        self.dialogue_state = dialogue_state

        # check if user is ending the conversation
        user_dacts.extend(
            self.intents_checker.check_basic_intent(user_utterance,
                                                    UserIntents.BYE))
        if len(user_dacts) > 0:
            return user_dacts

        # check if it's the start of a conversation
        if not self.dialogue_state.last_agent_dacts:
            user_dacts.extend(
                self.intents_checker.check_reveal_voluntary_intent(
                    user_utterance))
            if len(user_dacts) == 0:
                user_dacts.extend(
                    self.intents_checker.check_basic_intent(
                        user_utterance, UserIntents.HI))
            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(
                        user_utterance))
                if len(user_dacts) == 0:
                    user_dacts.extend(
                        self.intents_checker.check_basic_intent(
                            user_utterance, UserIntents.ACKNOWLEDGE))
                if len(user_dacts) > 0:
                    return user_dacts
            elif last_agent_dact.intent == AgentIntents.ELICIT:
                user_dacts.extend(
                    self.intents_checker.check_reveal_intent(
                        user_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(
                            user_utterance))
                if len(user_dacts) > 0:
                    return user_dacts

        if dialogue_state.agent_made_offer:
            user_dacts.extend(
                self.intents_checker.check_reject_intent(user_utterance))
        if len(user_dacts) == 0:
            user_dacts.extend(
                self.intents_checker.check_inquire_intent(user_utterance))
        if len(user_dacts) == 0:
            user_dacts.extend(
                self.intents_checker.check_reveal_voluntary_intent(
                    user_utterance))
        if len(user_dacts) == 0:
            deny_dact = self.intents_checker.check_basic_intent(
                user_utterance, UserIntents.DENY)
            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