示例#1
0
def sys_offer(d_state, new_sys_acts, sys_act, sys_acts, sys_acts_copy):
    # Remove the empty offer
    sys_acts_copy.remove(sys_act)
    if d_state.item_in_focus:
        new_sys_acts.append(
            DialogueAct(
                "offer",
                [
                    DialogueActItem("name", Operator.EQ,
                                    d_state.item_in_focus["name"])
                ],
            ))

        # Only add these slots if no other acts were output
        # by the DM
        if len(sys_acts) == 1:
            for slot in d_state.slots_filled:
                if slot in d_state.item_in_focus:
                    if slot not in ["id", "name"
                                    ] and slot != d_state.requested_slot:
                        new_sys_acts.append(
                            DialogueAct(
                                "inform",
                                [
                                    DialogueActItem(
                                        slot, Operator.EQ,
                                        d_state.item_in_focus[slot])
                                ],
                            ))
                else:
                    new_sys_acts.append(
                        DialogueAct(
                            "inform",
                            [DialogueActItem(slot, Operator.EQ, "no info")]))
示例#2
0
    def remove_from_agenda_push_again_if_false_value(self, item):
        # Remove the inform from the agenda, assuming the
        # value provided is correct. If it is not, the
        # act will be pushed again and will be on top of the
        # agenda (this way we avoid adding / removing
        # twice.
        dact = DialogueAct(
            "inform",
            [
                DialogueActItem(
                    deepcopy(item.slot),
                    deepcopy(self.goal.constraints[item.slot].op),
                    deepcopy(self.goal.constraints[item.slot].value),
                )
            ],
        )
        # Remove and push to make sure the act is on top -
        # if it already exists
        self.agenda.remove(dact)
        if item.value != self.goal.constraints[item.slot].value:
            meets_constraints = False
            # For each violated constraint add an inform
            # TODO: Make this a deny-inform or change
            # operator to NE
            self.agenda.push(dact)
        else:
            meets_constraints = True

        return meets_constraints
示例#3
0
def build_inform(slot, ds: SlotFillingDialogueState):
    if slot in ds.item_in_focus:
        value = ds.item_in_focus[slot]
    else:
        value = "no info"

    return DialogueAct("inform", [DialogueActItem(slot, Operator.EQ, value)])
示例#4
0
    def get_unfilled_slot(d_state):
        for slot in d_state.slots_filled:
            if not d_state.slots_filled[slot]:
                request_unfilled_slot = DialogueAct(
                    "request", [DialogueActItem(slot, Operator.EQ, "")])
                return request_unfilled_slot

        return None
示例#5
0
 def next_action(self, ds: SlotFillingDialogueState):
     if ds.is_terminal_state:
         dacts = [DialogueAct("bye", [DialogueActItem("", Operator.EQ, "")])]
     elif ds.requested_slot != "" and ds.item_in_focus and ds.system_made_offer:
         dacts = build_inform_act(ds)
     else:
         dacts = self.request_slots_or_make_offer(ds)
     return dacts
示例#6
0
def build_inform_act(dialogue_state: SlotFillingDialogueState):
    requested_slot = dialogue_state.requested_slot
    # Reset request as we attempt to address it
    dialogue_state.requested_slot = ""
    value = get_value(dialogue_state.item_in_focus, requested_slot)
    dact = [
        DialogueAct("inform", [DialogueActItem(requested_slot, Operator.EQ, value)])
    ]
    return dact
示例#7
0
def make_offer(ds):
    name = ds.item_in_focus["name"] if "name" in ds.item_in_focus else "unknown"
    dacts = [DialogueAct("offer", [DialogueActItem("name", Operator.EQ, name)])]
    inform_acts = [
        build_inform(slot, ds)
        for slot in ds.slots_filled
        if slot != "requested" and ds.slots_filled[slot] and slot not in ["id", "name"]
    ]
    dacts += inform_acts
    return dacts
示例#8
0
 def _update_goal_request_value_remove_from_agenda(self, item):
     self.goal.requests_made[item.slot].value = item.value
     # Mark the value only if the slot has been
     # requested and is in the requests
     if item.slot in self.goal.requests:
         self.goal.requests[item.slot].value = item.value
     # Remove any requests from the agenda that ask
     # for that slot
     # TODO: Revise this for all operators
     self.agenda.remove(
         DialogueAct("request",
                     [DialogueActItem(item.slot, Operator.EQ, "")]))
示例#9
0
    def decode_action(self, action_enc):

        if action_enc < len(self.dstc2_acts_sys):
            return [DialogueAct(self.dstc2_acts_sys[action_enc], [])]

        if action_enc < len(self.dstc2_acts_sys) + len(
                self.system_requestable_slots):
            return [
                DialogueAct(
                    "request",
                    [
                        DialogueActItem(
                            self.system_requestable_slots[
                                action_enc - len(self.dstc2_acts_sys)],
                            Operator.EQ,
                            "",
                        )
                    ],
                )
            ]

        if action_enc < len(self.dstc2_acts_sys) + len(
                self.system_requestable_slots) + len(self.requestable_slots):
            index = (action_enc - len(self.dstc2_acts_sys) -
                     len(self.system_requestable_slots))
            return [
                DialogueAct(
                    "inform",
                    [
                        DialogueActItem(self.requestable_slots[index],
                                        Operator.EQ, "")
                    ],
                )
            ]

        # Default fall-back action
        print("Reinforce DialoguePolicy ({0}) policy action decoder warning: "
              "Selecting default action (index: {1})!".format(
                  'system', action_enc))
        return [DialogueAct("bye", [])]
示例#10
0
 def build_act_that_requests_random_slot(
         d_state):  # TODO: why would one do such a thing?
     request_random_slot = DialogueAct(
         "request",
         [
             DialogueActItem(
                 random.choice(list(d_state.slots_filled.keys())[:-1]),
                 Operator.EQ,
                 "",
             )
         ],
     )
     return request_random_slot
示例#11
0
def sys_inform(d_state, new_sys_acts, sys_act):
    if sys_act.params:
        slot = sys_act.params[0].slot
    else:
        slot = d_state.requested_slot
    if not slot:
        slot = random.choice(list(d_state.slots_filled.keys()))
    if d_state.item_in_focus:
        if slot not in d_state.item_in_focus or not d_state.item_in_focus[slot]:
            new_sys_acts.append(
                DialogueAct("inform",
                            [DialogueActItem(slot, Operator.EQ, "no info")]))
        else:
            if slot == "name":
                new_sys_acts.append(
                    DialogueAct(
                        "offer",
                        [
                            DialogueActItem(slot, Operator.EQ,
                                            d_state.item_in_focus[slot])
                        ],
                    ))
            else:
                new_sys_acts.append(
                    DialogueAct(
                        "inform",
                        [
                            DialogueActItem(slot, Operator.EQ,
                                            d_state.item_in_focus[slot])
                        ],
                    ))

    else:
        new_sys_acts.append(
            DialogueAct("inform",
                        [DialogueActItem(slot, Operator.EQ, "no info")]))
示例#12
0
def cant_help(d_state, new_sys_acts, sys_act, sys_acts_copy):
    slots = [s for s in d_state.slots_filled if d_state.slots_filled[s]]
    if slots:
        slot = random.choice(slots)

        # Remove the empty canthelp
        sys_acts_copy.remove(sys_act)

        new_sys_acts.append(
            DialogueAct(
                "canthelp",
                [
                    DialogueActItem(slot, Operator.EQ,
                                    d_state.slots_filled[slot])
                ],
            ))
示例#13
0
    def _handle_request(self, items: List[DialogueActItem]):
        # Push appropriate acts into the agenda
        for item in items:
            system_asks_for_slot_in_goal = item.slot in self.goal.constraints

            if system_asks_for_slot_in_goal:
                operation = deepcopy(self.goal.constraints[item.slot].op)
                slot_value = deepcopy(self.goal.constraints[item.slot].value)
            else:
                operation = Operator.EQ
                slot_value = "dontcare"

            slot_name = deepcopy(item.slot)
            self.agenda.push(
                DialogueAct(
                    "inform",
                    [DialogueActItem(slot_name, operation, slot_value)]))
示例#14
0
    def consistency_check(self):
        """
        Perform some basic checks to ensure that items in the agenda are
        consistent - i.e. not duplicate, not
        contradicting with current goal, etc.

        :return: Nothing
        """

        # Remove all requests for slots that are filled in the goal
        if self.goal:
            for slot in self.goal.requests_made:
                if self.goal.requests_made[slot].value:
                    self.remove(
                        DialogueAct("request",
                                    [DialogueActItem(slot, Operator.EQ, "")]))
        else:
            print("Warning! Agenda consistency check called without goal. "
                  "Did you forget to initialize?")
示例#15
0
def make_request(unfilled_slots):
    slot = random.choice(unfilled_slots)
    dacts = [DialogueAct("request", [DialogueActItem(slot, Operator.EQ, "")])]
    return dacts
示例#16
0
    def generate(self):

        if self.goals:
            return random.choice(self.goals)

        # Randomly pick an item from the database
        cursor = self.database.SQL_connection.cursor()

        sql_command = (
            "SELECT * FROM "
            + self.db_table_name
            + " WHERE ROWID == ("
            + str(random.randint(1, self.db_row_count))
            + ");"
        )

        cursor.execute(sql_command)
        db_result = cursor.fetchone()

        attempt = 0
        while attempt < 3 and not db_result:
            print(
                "GoalGenerator: Database {0} appears to be empty!".format(self.database)
            )
            print(f"Trying again (attempt {attempt} out of 3)...")

            sql_command = (
                "SELECT * FROM "
                + self.db_table_name
                + " WHERE ROWID == ("
                + str(random.randint(1, self.db_row_count))
                + ");"
            )

            cursor.execute(sql_command)
            db_result = cursor.fetchone()

            attempt += 1

        if not db_result:
            raise LookupError(
                "GoalGenerator: Database {0} appears to be "
                "empty!".format(self.database)
            )

        result = dict(zip(self.slot_names, db_result))

        # Generate goal
        goal = Goal()

        # TODO: Sample from all available operators, not just '='
        # (where applicable)

        inf_slots = random.sample(
            list(self.ontology.ontology["informable"].keys()),
            random.randint(2, len(self.ontology.ontology["informable"])),
        )

        # Sample requests from requestable slots
        req_slots = random.sample(
            self.ontology.ontology["requestable"],
            random.randint(0, len(self.ontology.ontology["requestable"])),
        )

        # Remove slots for which the user places constraints
        # Note: 'name' may or may not be in inf_slots here, and this is
        # randomness is desirable
        for slot in inf_slots:
            if slot in req_slots:
                req_slots.remove(slot)

        # Never ask for specific name unless it is the only constraint
        # if 'name' in inf_slots and len(inf_slots) > 1:
        if "name" in inf_slots:
            inf_slots.remove("name")

        # Shuffle informable and requestable slots to create some variety
        # when pushing into the agenda.
        random.shuffle(inf_slots)
        random.shuffle(req_slots)

        for slot in inf_slots:
            # Check that the slot has a value in the retrieved item
            if slot in result and result[slot]:
                goal.constraints[slot] = DialogueActItem(
                    slot, Operator.EQ, result[slot]
                )

        for slot in req_slots:
            if slot in result:
                goal.requests[slot] = DialogueActItem(slot, Operator.EQ, [])

        return goal