Ejemplo n.º 1
0
    def _convert_inform_by_primkey(self, q_results: iter, sys_act: SysAct,
                                   belief_state: BeliefState):
        """
            Helper function that adds the values for slots to a SysAct object when the system
            is answering a request for information about an entity from the user

            Args:
                q_results (iterable): list of query results from the database
                sys_act (SysAct): current raw sys_act to be filled in
                belief_state (BeliefState)

        """
        sys_act.type = SysActionType.InformByName
        if q_results:
            result = q_results[0]  # currently return just the first result
            keys = list(result.keys()
                        )  # should represent all user specified constraints

            # add slots + values (where available) to the sys_act
            for k in keys:
                res = result[k] if result[k] else 'not available'
                sys_act.add_value(k, res)
            # Name might not be a constraint in request queries, so add it
            if self.domain_key not in keys:
                name = self._get_name(belief_state)
                sys_act.add_value(self.domain_key, name)
            # Add default Inform slots
            for slot in self.domain.get_default_inform_slots():
                if slot not in sys_act.slot_values:
                    sys_act.add_value(slot, result[slot])
        else:
            sys_act.add_value(self.domain_key, 'none')
Ejemplo n.º 2
0
    def _convert_inform_by_constraints(self, q_results: iter, sys_act: SysAct,
                                       belief_state: BeliefState):
        """
            Helper function for filling in slots and values of a raw inform act when the system is
            ready to make the user an offer

            Args:
                q_results (iter): the results from the databse query
                sys_act (SysAct): the raw infor act to be filled in
                belief_state (BeliefState): the current system beliefs

        """
        # altered to add all results to the SysAct
        if list(q_results):
            self.current_suggestions = []
            self.s_index = 0
            for result in q_results:
                sys_act.add_value(self.domain_key, result[self.domain_key])

        else:
            sys_act.add_value(self.domain_key, 'none')

        sys_act.type = SysActionType.InformByName
        constraints, dontcare = self._get_constraints(belief_state)
        for c in constraints:
            # Using constraints here rather than results to deal with empty
            # results sets (eg. user requests something impossible) --LV
            sys_act.add_value(c, constraints[c])

        # altered to the changes above
        if list(q_results):
            for slot in belief_state['requests']:
                if slot not in sys_act.slot_values:
                    for result in q_results:
                        sys_act.add_value(slot, result[slot])
Ejemplo n.º 3
0
 def _receive_confirmrequest(self, sys_act):
     """Processes a confirmrequest action from the system."""
     # first slot is confirm, second slot is request
     for slot, value in sys_act.slot_values.items():
         if value is None:
             # system's request action
             self._receive_request(
                 SysAct(act_type=SysActionType.Request,
                        slot_values={slot: None}))
         else:
             # system's confirm action
             self._receive_confirm(
                 SysAct(act_type=SysActionType.Confirm,
                        slot_values={slot: [value]}))
Ejemplo n.º 4
0
def test_convert_inform_by_alternatives_adds_constraints(
        policy, beliefstate, entryA, constraintA, constraintB):
    """
    Tests whether converting the inform system action by a request for alternatives adds the
    constraints as slot-value pairs to the system action.

    Args:
        policy: Policy Object (given in conftest.py)
        beliefstate: BeliefState object (given in conftest.py)
        entryA (dict): slot-value pairs for a complete entry in the domain (given in
        conftest_<domain>.py)
        constraintA (dict): an existing slot-value pair in the domain (given in
        conftest_<domain>.py)
        constraintB (dict): another existing slot-value pair in the domain (given in
        conftest_<domain>.py)
    """
    beliefstate['informs'] = {
        constraintA['slot']: {
            constraintA['value']: 0.5
        },
        constraintB['slot']: {
            constraintB['value']: 0.3
        }
    }
    sys_act = SysAct()
    policy._convert_inform_by_alternatives(sys_act, [entryA], beliefstate)
    assert any(slot == constraintA['slot'] and constraintA['value'] in values
               for slot, values in sys_act.slot_values.items())
    assert any(slot == constraintB['slot'] and constraintB['value'] in values
               for slot, values in sys_act.slot_values.items())
Ejemplo n.º 5
0
    def _convert_inform_by_constraints(self, q_results: iter, sys_act: SysAct,
                                       belief_state: BeliefState):
        """
            Helper function for filling in slots and values of a raw inform act when the system is
            ready to make the user an offer

            Args:
                q_results (iter): the results from the databse query
                sys_act (SysAct): the raw infor act to be filled in
                belief_state (BeliefState): the current system beliefs

        """
        # TODO: Do we want some way to allow users to scroll through
        # result set other than to type 'alternatives'? --LV
        if q_results:
            self.current_suggestions = []
            self.s_index = 0
            for result in q_results:
                self.current_suggestions.append(result)
            result = self.current_suggestions[0]
            sys_act.add_value(self.domain_key, result[self.domain_key])
        else:
            sys_act.add_value(self.domain_key, 'none')

        sys_act.type = SysActionType.InformByName
        constraints, dontcare = self._get_constraints(belief_state)
        for c in constraints:
            # Using constraints here rather than results to deal with empty
            # results sets (eg. user requests something impossible) --LV
            sys_act.add_value(c, constraints[c])
Ejemplo n.º 6
0
    def _convert_inform_by_alternatives(self, sys_act: SysAct, q_res: iter,
                                        belief_state: BeliefState):
        """
            Helper Function, scrolls through the list of alternative entities which match the
            user's specified constraints and uses the next item in the list to fill in the raw
            inform act.

            When the end of the list is reached, currently continues to give last item in the list
            as a suggestion

            Args:
                sys_act (SysAct): the raw inform to be filled in
                belief_state (BeliefState): current system belief state ()

        """
        if q_res and not self.current_suggestions:
            self.current_suggestions = []
            self.s_index = -1
            for result in q_res:
                self.current_suggestions.append(result)

        self.s_index += 1
        # here we should scroll through possible offers presenting one each turn the user asks
        # for alternatives
        if self.s_index <= len(self.current_suggestions) - 1:
            # the first time we inform, we should inform by name, so we use the right template
            if self.s_index == 0:
                sys_act.type = SysActionType.InformByName
            else:
                sys_act.type = SysActionType.InformByAlternatives
            result = self.current_suggestions[self.s_index]
            # Inform by alternatives according to our current templates is
            # just a normal inform apparently --LV
            sys_act.add_value(self.domain_key, result[self.domain_key])
        else:
            sys_act.type = SysActionType.InformByAlternatives
            # default to last suggestion in the list
            self.s_index = len(self.current_suggestions) - 1
            sys_act.add_value(self.domain.get_primary_key(), 'none')

        # in addition to the name, add the constraints the user has specified, so they know the
        # offer is relevant to them
        constraints, dontcare = self._get_constraints(belief_state)
        for c in constraints:
            sys_act.add_value(c, constraints[c])
Ejemplo n.º 7
0
    def _raw_action(self, q_res: iter, beliefstate: BeliefState) -> SysAct:
        """Based on the output of the db query and the method, choose
           whether next action should be request or inform

        Args:
            q_res (list): rows (list of dicts) returned by the issued sqlite3
            query
            method (str): the type of user action
                     ('byprimarykey', 'byconstraints', 'byalternatives')

        Returns:
            (SysAct): SysAct object of appropriate type

        --LV
        """
        sys_act = SysAct()
        # if there is more than one result
        if len(q_res) > 1:
            constraints, dontcare = self._get_constraints(beliefstate)
            # Gather all the results for each column
            temp = {key: [] for key in q_res[0].keys()}
            # If any column has multiple values, ask for clarification
            for result in q_res:
                for key in result.keys():
                    if key != self.domain_key:
                        temp[key].append(result[key])
            next_req = self._gen_next_request(temp, beliefstate)
            if next_req:
                sys_act.type = SysActionType.Request
                sys_act.add_value(next_req)
                return sys_act

        # Otherwise action type will be inform, so return an empty inform (to be filled in later)
        sys_act.type = SysActionType.InformByName
        return sys_act
Ejemplo n.º 8
0
def test_convert_inform_by_constraints_without_results(policy, beliefstate):
    """
    Tests whether the system converts the inform system action to an inform by name action with
    no specific entity name if querying the database returned no results.

    Args:
        policy: Policy Object (given in conftest.py)
        beliefstate: BeliefState object (given in conftest.py)
    """
    primkey = policy.domain.get_primary_key()
    sys_act = SysAct()
    policy._convert_inform_by_constraints([], sys_act, beliefstate)
    assert sys_act.type == SysActionType.InformByName
    assert 'none' in sys_act.slot_values[primkey]
Ejemplo n.º 9
0
def test_convert_inform_with_given_constraints(policy, beliefstate, entryA):
    """
    Tests whether the system selects an inform by name action if the inform is converted with
    other constraints than the primary key or a request for alternatives.

    Args:
        policy: Policy Object (given in conftest.py)
        beliefstate: BeliefState object (given in conftest.py)
        entryA (dict): slot-value pairs for a complete entry in the domain (given in
        conftest_<domain>.py)
    """
    beliefstate['user_acts'] = []
    beliefstate['requests'] = []
    sys_act = SysAct()
    policy._convert_inform([entryA], sys_act, beliefstate)
    assert sys_act.type == SysActionType.InformByName
    assert sys_act.slot_values != {}
Ejemplo n.º 10
0
def test_convert_inform_by_primkey_with_results(policy, beliefstate, entryA):
    """
    Tests whether the system converts the inform system action to an inform by name action with
    a specified name if querying the database returned results.

    Args:
        policy: Policy Object (given in conftest.py)
        beliefstate: BeliefState object (given in conftest.py)
        entryA (dict): slot-value pairs for a complete entry in the domain (given in
        conftest_<domain>.py)
    """
    primkey = policy.domain.get_primary_key()
    beliefstate['informs'] = {primkey: {entryA[primkey]: 0.5}}
    sys_act = SysAct()
    policy._convert_inform_by_primkey([entryA], sys_act, beliefstate)
    assert sys_act.type == SysActionType.InformByName
    assert primkey in sys_act.slot_values
    assert entryA[primkey] in sys_act.slot_values[primkey]
Ejemplo n.º 11
0
def test_convert_inform_for_request_alternatives(policy, beliefstate, entryA):
    """
    Tests whether the system selects either an inform by name action or an inform by alternatives
    action if the inform is converted with a given request for alternatives by the user.

    Args:
        policy: Policy Object (given in conftest.py)
        beliefstate: BeliefState object (given in conftest.py)
        entryA (dict): slot-value pairs for a complete entry in the domain (given in
        conftest_<domain>.py)
    """
    beliefstate['user_acts'] = [UserActionType.RequestAlternatives]
    beliefstate['requests'] = []
    sys_act = SysAct()
    policy._convert_inform([entryA], sys_act, beliefstate)
    assert sys_act.type in (SysActionType.InformByName,
                            SysActionType.InformByAlternatives)
    assert sys_act.slot_values != {}
Ejemplo n.º 12
0
 def parse_action(self, intent, slot, value):
     try:
         if not self.user:
             return SysAct(act_type=SysActionType(intent),
                           slot_values={slot: [value] if value else []}
                           if slot else None)
         else:
             return UserAct(act_type=UserActionType(intent),
                            slot=slot,
                            value=value)
     except ValueError:
         # intent is probably not a valid SysActionType
         if not self.user:
             print("Intent must be one of {}".format(
                 list(map(lambda x: x.value, SysActionType))))
         else:
             print("Intent must be one of {}".format(
                 list(map(lambda x: x.value, UserActionType))))
Ejemplo n.º 13
0
def test_convert_inform_by_alternatives_without_suggestions(
        policy, beliefstate, entryA):
    """
    Tests whether the system converts the inform system action to an inform by name action if it
    is the first inform of the dialog (i.e. the list of current suggestions is empty).

    Args:
        policy: Policy Object (given in conftest.py)
        beliefstate: BeliefState object (given in conftest.py)
        entryA (dict): slot-value pairs for a complete entry in the domain (given in
        conftest_<domain>.py)
    """
    policy.current_suggestions = []
    policy.s_index = 0
    sys_act = SysAct()
    policy._convert_inform_by_alternatives(sys_act, [entryA], beliefstate)
    assert sys_act.type == SysActionType.InformByName
    assert policy.current_suggestions != []
    assert policy.s_index == 0
    assert sys_act.slot_values != {}
Ejemplo n.º 14
0
def test_convert_inform_with_primary_key(policy, beliefstate,
                                         primkey_constraint, entryA):
    """
    Tests whether the system selects an inform by name action if the inform is converted with a
    given primary key.

    Args:
        policy: Policy Object (given in conftest.py)
        beliefstate: BeliefState object (given in conftest.py)
        primkey_constraint (dict): slot-value pair for a primary key constraint (given in
        conftest_<domain>.py)
        entryA (dict): slot-value pairs for a complete entry in the domain (given in
        conftest_<domain>.py)
    """
    beliefstate['informs'] = {
        primkey_constraint['slot']: {
            primkey_constraint['value']: 0.5
        }
    }
    sys_act = SysAct()
    policy._convert_inform([entryA], sys_act, beliefstate)
    assert sys_act.type == SysActionType.InformByName
    assert sys_act.slot_values != {}
Ejemplo n.º 15
0
def test_convert_inform_by_constraints_with_results(policy, beliefstate,
                                                    entryA, entryB):
    """
    Tests whether the system converts the inform system action to an inform by name action with
    specific entity name if querying the database returned results.

    Args:
        policy: Policy Object (given in conftest.py)
        beliefstate: BeliefState object (given in conftest.py)
        entryA (dict): slot-value pairs for a complete entry in the domain (given in
        conftest_<domain>.py)
        entryB (dict): slot-value pairs for another complete entry in the domain (given in
        conftest_<domain>.py)
    """
    primkey = policy.domain.get_primary_key()
    policy.current_suggestions = [entryA]
    policy.s_index = 1
    sys_act = SysAct()
    policy._convert_inform_by_constraints([entryB], sys_act, beliefstate)
    assert sys_act.type == SysActionType.InformByName
    assert policy.current_suggestions == [entryB]
    assert policy.s_index == 0
    assert entryB[primkey] in sys_act.slot_values[primkey]
Ejemplo n.º 16
0
def test_convert_inform_by_alternatives_with_suggestions(
        policy, beliefstate, entryA, entryB):
    """
    Tests whether the system converts the inform system action to an inform by alternatives action
    if it is not the first inform of the dialog (i.e. the list of current suggestions is not empty).

    Args:
        policy: Policy Object (given in conftest.py)
        beliefstate: BeliefState object (given in conftest.py)
        entryA (dict): slot-value pairs for a complete entry in the domain (given in
        conftest_<domain>.py)
        entryB (dict): slot-value pairs for another complete entry in the domain (given in
        conftest_<domain>.py)
    """
    primkey = policy.domain.get_primary_key()
    policy.current_suggestions = [entryA, entryB]
    policy.s_index = 0
    sys_act = SysAct()
    policy._convert_inform_by_alternatives(sys_act, [], beliefstate)
    assert sys_act.type == SysActionType.InformByAlternatives
    assert policy.s_index == 1
    assert sys_act.slot_values != {}
    assert entryB[primkey] in sys_act.slot_values[primkey]
Ejemplo n.º 17
0
def test_convert_inform_by_alternatives_with_invalid_index(
        policy, beliefstate, entryA, entryB):
    """
    Tests whether the system converts the inform system action to an inform by name action
    without a specific entity name if the index for the current suggestion list is not valid
    (e.g. the index is higher than the number of current suggestions).

    Args:
        policy: Policy Object (given in conftest.py)
        beliefstate: BeliefState object (given in conftest.py)
        entryA (dict): slot-value pairs for a complete entry in the domain (given in
        conftest_<domain>.py)
        entryB (dict): slot-value pairs for another complete entry in the domain (given in
        conftest_<domain>.py)
    """
    primkey = policy.domain.get_primary_key()
    policy.current_suggestions = [entryA]
    policy.s_index = 1
    sys_act = SysAct()
    policy._convert_inform_by_alternatives(sys_act, [entryB], beliefstate)
    assert sys_act.type == SysActionType.InformByAlternatives
    assert policy.s_index == 0
    assert sys_act.slot_values != {}
    assert 'none' in sys_act.slot_values[primkey]
Ejemplo n.º 18
0
    def generate_sys_acts(self, user_acts: List[UserAct] = None) -> dict(sys_acts=List[SysAct]):
        """Generates system acts by looking up answers to the given user question.

        Args:
            user_acts: The list of user acts containing information about the predicted relation,
                topic entities and relation direction

        Returns:
            dict with 'sys_acts' as key and list of system acts as value
        """
        if user_acts is None:
            return { 'sys_acts': [SysAct(SysActionType.Welcome)]}
        elif any([user_act.type == UserActionType.Bye for user_act in user_acts]):
            return { 'sys_acts': [SysAct(SysActionType.Bye)] }
        elif not user_acts:
            return { 'sys_acts': [SysAct(SysActionType.Bad)] }
        
        user_acts = [user_act for user_act in user_acts if user_act.type != UserActionType.SelectDomain]
        if len(user_acts) == 0:
           return { 'sys_acts': [SysAct(SysActionType.Welcome)]} 

        relation = [user_act.value for user_act in user_acts \
            if user_act.type == UserActionType.Inform and user_act.slot == 'relation'][0]
        topics = [user_act.value for user_act in user_acts \
            if user_act.type == UserActionType.Inform and user_act.slot == 'topic']
        direction = [user_act.value for user_act in user_acts \
            if user_act.type == UserActionType.Inform and user_act.slot == 'direction'][0]

        if not topics:
            return { 'sys_acts': [SysAct(SysActionType.Bad)] }

        # currently, short answers are used for world knowledge
        answers = self._get_short_answers(relation, topics, direction)

        sys_acts = [SysAct(SysActionType.InformByName, slot_values=answer) for answer in answers]

        self.debug_logger.dialog_turn("System Action: " + '; '.join(
            [str(sys_act) for sys_act in sys_acts]))
        return {'sys_acts': sys_acts}
Ejemplo n.º 19
0
    def forward(self,
                dialog_graph,
                beliefstate: BeliefState = None,
                user_acts: List[u.UserAct] = None,
                sys_act: SysAct = None,
                **kwargs) -> dict(sys_act=SysAct):
        """
            Responsible for walking the policy through a single turn. Uses the current user
            action and system belief state to determine what the next system action should be.

            To implement an alternate policy, this method may need to be overwritten

            Args:
                dialog_graph (DialogSystem): the graph to which the policy belongs
                belief_state (BeliefState): a BeliefState obejct representing current system
                                           knowledge
                user_acts (list): a list of UserAct objects mapped from the user's last utterance
                sys_act (SysAct): this should be None

            Returns:
                (dict): a dictionary with the key "sys_act" and the value that of the systems next
                        action

        """
        belief_state = beliefstate
        # variables for general (non-domain specific) actions
        self.turn = dialog_graph.num_turns
        self.prev_sys_act = sys_act
        self._check_for_gen_actions(user_acts)

        # do nothing on the first turn --LV
        if user_acts is None and self.turn == 0:
            sys_act = SysAct()
            sys_act.type = SysActionType.Welcome
            return sys_act
        # if there is no user act, and it's not the first turn, this is bad
        elif not self.act_types_lst and self.turn > 0:
            # if not self.is_user_act and self.turn > 0:
            sys_act = SysAct()
            sys_act.type = SysActionType.Bad
        # if the user has not said anything which can be parsed
        elif u.UserActionType.Bad in self.act_types_lst:
            sys_act = SysAct()
            sys_act.type = SysActionType.Bad
        # if the action is 'bye' tell system to end dialog
        elif u.UserActionType.Bye in self.act_types_lst:
            sys_act = SysAct()
            sys_act.type = SysActionType.Bye
        # if user only says thanks, ask if they want anything else
        elif u.UserActionType.Thanks in self.act_types_lst:
            sys_act = SysAct()
            sys_act.type = SysActionType.RequestMore
        # If user only says hello, request a random slot to move dialog along
        elif u.UserActionType.Hello in self.act_types_lst:
            sys_act = SysAct()
            sys_act.type = SysActionType.Request
            sys_act.add_value(self._get_open_slot(belief_state))
        # handle domain specific actions
        else:
            sys_act = self._next_action(belief_state)

        self.logger.dialog_turn("System Action: " + str(sys_act))
        return {'sys_act': sys_act}
Ejemplo n.º 20
0
    def choose_sys_act(self, beliefstate: BeliefState = None, sys_act: SysAct = None)\
            -> dict(sys_act=SysAct):
        """
            Responsible for walking the policy through a single turn. Uses the current user
            action and system belief state to determine what the next system action should be.

            To implement an alternate policy, this method may need to be overwritten

            Args:
                belief_state (BeliefState): a BeliefState object representing current system
                                           knowledge
                user_acts (list): a list of UserAct objects mapped from the user's last utterance
                sys_act (SysAct): this should be None

            Returns:
                (dict): a dictionary with the key "sys_act" and the value that of the systems next
                        action

        """
        # variables for general (non-domain specific) actions
        # self.turn = dialog_graph.num_turns
        self.prev_sys_act = sys_act
        self._remove_gen_actions(beliefstate)
        sys_state = {}

        # do nothing on the first turn --LV
        if self.first_turn and not beliefstate['user_acts']:
            self.first_turn = False
            sys_act = SysAct()
            sys_act.type = SysActionType.Welcome
            return {'sys_act': sys_act}
        elif UserActionType.Bad in beliefstate["user_acts"]:
            sys_act = SysAct()
            sys_act.type = SysActionType.Bad
        # if the action is 'bye' tell system to end dialog
        elif UserActionType.Bye in beliefstate["user_acts"]:
            sys_act = SysAct()
            sys_act.type = SysActionType.Bye
        # if user only says thanks, ask if they want anything else
        elif UserActionType.Thanks in beliefstate["user_acts"]:
            sys_act = SysAct()
            sys_act.type = SysActionType.RequestMore
        # If user only says hello, request a random slot to move dialog along
        elif UserActionType.Hello in beliefstate[
                "user_acts"] or UserActionType.SelectDomain in beliefstate[
                    "user_acts"]:
            sys_act = SysAct()
            sys_act.type = SysActionType.Request
            slot = self._get_open_slot(beliefstate)
            sys_act.add_value(slot)
            # prepare sys_state info
            sys_state['lastRequestSlot'] = slot

            # If we switch to the domain, start a new dialog
            if UserActionType.SelectDomain in beliefstate["user_acts"]:
                self.dialog_start()
            self.first_turn = False

        # handle domain specific actions
        else:
            sys_act, sys_state = self._next_action(beliefstate)

        self.logger.dialog_turn("System Action: " + str(sys_act))
        if 'last_act' not in sys_state:
            sys_state['last_act'] = sys_act
        return {'sys_act': sys_act, 'sys_state': sys_state}
Ejemplo n.º 21
0
    def choose_sys_act(self, beliefstate: BeliefState = None) \
            -> dict(sys_act=SysAct):
        """
            Responsible for walking the policy through a single turn. Uses the current user
            action and system belief state to determine what the next system action should be.

            To implement an alternate policy, this method may need to be overwritten

            Args:
                belief_state (BeliefState): a BeliefState obejct representing current system
                                           knowledge

            Returns:
                (dict): a dictionary with the key "sys_act" and the value that of the systems next
                        action

        """
        self.turns += 1
        # do nothing on the first turn --LV
        sys_state = {}
        if self.first_turn and not beliefstate['user_acts']:
            self.first_turn = False
            sys_act = SysAct()
            sys_act.type = SysActionType.Welcome
            sys_state["last_act"] = sys_act
            return {'sys_act': sys_act, "sys_state": sys_state}

        if self.turns >= self.max_turns:
            sys_act = SysAct()
            sys_act.type = SysActionType.Bye
            sys_state["last_act"] = sys_act
            return {'sys_act': sys_act, "sys_state": sys_state}

        # removes hello and thanks if there are also domain specific actions
        self._remove_gen_actions(beliefstate)

        if UserActionType.Bad in beliefstate["user_acts"]:
            sys_act = SysAct()
            sys_act.type = SysActionType.Bad
        # if the action is 'bye' tell system to end dialog
        elif UserActionType.Bye in beliefstate["user_acts"]:
            sys_act = SysAct()
            sys_act.type = SysActionType.Bye
        # if user only says thanks, ask if they want anything else
        elif UserActionType.Thanks in beliefstate["user_acts"]:
            sys_act = SysAct()
            sys_act.type = SysActionType.RequestMore
        # If user only says hello, request a random slot to move dialog along
        elif UserActionType.Hello in beliefstate[
                "user_acts"] or UserActionType.SelectDomain in beliefstate[
                    "user_acts"]:
            sys_act = SysAct()
            sys_act.type = SysActionType.Request
            slot = self._get_open_slot(beliefstate)
            sys_act.add_value(slot)

            # If we switch to the domain, start a new dialog
            if UserActionType.SelectDomain in beliefstate["user_acts"]:
                self.dialog_start()
            self.first_turn = False
        # handle domain specific actions
        else:
            sys_act, sys_state = self._next_action(beliefstate)
        if self.logger:
            self.logger.dialog_turn("System Action: " + str(sys_act))
        if "last_act" not in sys_state:
            sys_state["last_act"] = sys_act
        return {'sys_act': sys_act, "sys_state": sys_state}
Ejemplo n.º 22
0
    def _next_action(self, beliefstate: BeliefState):
        """Determines the next system action based on the current belief state and
           previous action.

           When implementing a new type of policy, this method MUST be rewritten

        Args:
            belief_state (HandCraftedBeliefState): system values on liklihood
            of each possible state

        Return:
            (SysAct): the next system action

        --LV
        """
        sys_state = {}
        # Assuming this happens only because domain is not actually active --LV
        """if UserActionType.Bad in beliefstate['user_acts'] or beliefstate['requests'] \
                and not self._get_name(beliefstate):
            sys_act = SysAct()
            sys_act.type = SysActionType.Bad
            return sys_act, {'last_action': sys_act}"""

        if not self._mandatory_requests_fulfilled(beliefstate):
            sys_act = SysAct()
            sys_act.type = SysActionType.Request
            sys_act.slot_values = {
                self._get_open_mandatory_slot(beliefstate): None
            }
            return sys_act, {'last_action': sys_act}

        elif UserActionType.RequestAlternatives in beliefstate['user_acts'] \
                and not self._get_constraints(beliefstate)[0]:
            sys_act = SysAct()
            sys_act.type = SysActionType.Bad
            return sys_act, {'last_action': sys_act}

        elif self.domain.get_primary_key() in beliefstate['informs'] \
                and not beliefstate['requests']:
            sys_act = SysAct()
            sys_act.type = SysActionType.InformByName
            sys_act.add_value(self.domain.get_primary_key(),
                              self._get_name(beliefstate))
            return sys_act, {'last_action': sys_act}

        # Otherwise we need to query the db to determine next action
        results = self._query_db(beliefstate)
        sys_act = self._raw_action(results, beliefstate)

        # requests are fairly easy, if it's a request, return it directly
        if sys_act.type == SysActionType.Request:
            if len(list(sys_act.slot_values.keys())) > 0:
                # update the belief state to reflec the slot we just asked about
                sys_state['lastRequestSlot'] = list(
                    sys_act.slot_values.keys())[0]
                # belief_state['system']['lastRequestSlot'] = list(sys_act.slot_values.keys())[0]

        # otherwise we need to convert a raw inform into a one with proper slots and values
        elif sys_act.type == SysActionType.InformByName:
            self._convert_inform(results, sys_act, beliefstate)
            # update belief state to reflect the offer we just made
            values = sys_act.get_values(self.domain.get_primary_key())
            if values:
                # belief_state['system']['lastInformedPrimKeyVal'] = values[0]
                sys_state['lastInformedPrimKeyVal'] = values[0]
            else:
                sys_act.add_value(self.domain.get_primary_key(), 'none')

        sys_state['last_act'] = sys_act
        return (sys_act, sys_state)