Beispiel #1
0
    def _response_INFORM_TYPE(self, usr_act):
        queryable = ((len(self.state['informed']['pricerange']) > 0) and (len(self.state['informed']['area']) > 0) and (len(self.state['informed']['food']) > 0)) \
                    or (len(self.state['informed']['name']) > 0)
        if not queryable:
            # the only optio.n is to ask_type until all the entities are collected
            possible_actions = [SystemAct.ASK_TYPE]
            selected_action = self.sample(possible_actions)

            if selected_action == SystemAct.ASK_TYPE:
                params = self._generate_params(selected_action)
            else:
                raise ValueError("disallowed sys_Act {}".format(selected_action))

            return Action(selected_action, params)
        else:
            # if queryable, need to present result
            if len(self.state['informed']['name']) > 0:
                # specific restaurant
                cur_info = {'name': self.state['informed']['name'][-1]}
            else:
                cur_info = {entity: self.state['informed'][entity][-1] for entity in ['pricerange', 'area', 'food'] \
                            if self.state['informed'][entity][-1] != dialog_config.I_DO_NOT_CARE}
            match_result = self.query_in_DB(cur_info, skip=self.state['results'])
            if len(match_result) > 0:
                present_result = match_result[0]
                #self.state['results'].append(present_result)
                #self.state['match_presented'] += 1
                params = present_result#{present_result[entity] for entity in dialog_config.informable_slots}
                return Action(SystemAct.PRESENT_RESULT, params)
            else:
                return Action(SystemAct.NOMATCH_RESULT, None)
Beispiel #2
0
    def _response_MAKE_RESERVATION(self, usr_act):

        params = {entity: None for entity, value in self.state['reservation_informed'].items() if len(value) == 0}
        if len(params) == 0:
            # all asked
            if self.sample([True, False], p=[0.8, 0.2]):
                params = {'reference': "ABC"}
                return Action(SystemAct.BOOKING_SUCCESS, params)
            else:
                return Action(SystemAct.BOOKING_FAIL, None)
        else:
            return Action(SystemAct.ASK_RESERVATION_INFO, params)
Beispiel #3
0
    def _response_ANYTHING_ELSE(self):
        if len(self.state['informed']['name']) > 0:
            # specific restaurant
            cur_info = {'name': self.state['informed']['name'][-1]}
        else:
            cur_info = {entity: self.state['informed'][entity][-1] for entity in ['pricerange', 'area', 'food'] \
                        if len(self.state['informed'][entity]) and self.state['informed'][entity][-1] != dialog_config.I_DO_NOT_CARE}

        match_result = self.query_in_DB(cur_info, skip=self.state['results'])
        if len(match_result) > 0: #self.state['match_presented']:
            present_result = match_result[0]#match_result[self.state['match_presented']]
            params = present_result
            return Action(SystemAct.PRESENT_RESULT, params)
        else:
            return Action(SystemAct.NO_OTHER, None)
Beispiel #4
0
 def query_and_decide_present_mode(self, usr_act):
     if len(self.state['informed']['name']) > 0:
         # specific restaurant
         cur_info = {'name': self.state['informed']['name'][-1]}
     else:
         cur_info = {entity: self.state['informed'][entity][-1] for entity in ['pricerange', 'area', 'food'] \
                     if self.state['informed'][entity][-1] != dialog_config.I_DO_NOT_CARE}
     match_result = self.query_in_DB(cur_info, skip=self.state['results'])
     if len(match_result) > 0:
         present_result = match_result[0]
         params = present_result  # {present_result[entity] for entity in dialog_config.informable_slots}
         return Action(SystemAct.PRESENT_RESULT, params)
     else:
         if usr_act.act == UserAct.ANYTHING_ELSE and len(match_result) == 0:
             return Action(SystemAct.NO_OTHER, None)
         else:
             return Action(SystemAct.NOMATCH_RESULT, None)
Beispiel #5
0
    def _response_INFORM_TYPE_CHANGE(self, usr_act):
        # print(usr_act)
        # print(self.state['informed'])
        if len(self.state['informed']['name']) > 0:
            # specific restaurant
            cur_info = {'name': self.state['informed']['name'][-1]}
        else:
            cur_info = {entity: self.state['informed'][entity][-1] for entity in ['pricerange', 'area', 'food'] \
                        if len(self.state['informed'][entity]) and self.state['informed'][entity][-1] != dialog_config.I_DO_NOT_CARE}

        match_result = self.query_in_DB(cur_info, skip=self.state['results'])
        if len(match_result) > 0:
            present_result = match_result[0]
            #self.state['results'].append(present_result)
            #self.state['match_presented'] += 1
            params = present_result#{present_result[entity] for entity in dialog_config.informable_slots}
            return Action(SystemAct.PRESENT_RESULT, params)
        else:
            return Action(SystemAct.NOMATCH_RESULT, None)
    def step_user(self, mode, mturk_res=None):
        import pdb
        # pdb.set_trace()
        # first user sentence
        if self.config.INTERACTIVE:
            if mturk_res is None:
                self.last_usr_sent = input('Please respond: ')
            else:
                self.last_usr_sent = mturk_res
            self.last_usr_act_true = None
        else:
            self.last_usr_act_true, self.last_usr_sent = self.user.respond(sys_act=self.last_sys_act, prev_sys=self.last_sys_sent)

        if self.last_usr_act_true is None:
            # self.last_usr_act_true is None only when using SL-based simulator
            self.last_usr_act_pred = self.system.nlu(usr_sent=self.last_usr_sent, usr_act=self.last_usr_act_true, mode=dialog_config.RL_TRAINING)
        else:
            self.last_usr_act_pred = self.system.nlu(usr_sent=self.last_usr_sent, usr_act=self.last_usr_act_true, mode=mode)

        self.update_state(act=self.last_usr_act_pred, who='usr')

        if self.verbose and (not self.config.INTERACTIVE):
            print("{} Usr: {}".format(self.step_i, self.last_usr_sent))
            # print("True user act: ", self.last_usr_act_true)

        # if not self.config.use_sequicity_for_rl_model:
        #     next_state = self.system.prepare_state_representation()
        # else:
        #     next_state = None
        next_state = None

        if self.first_step:
            self.first_step = False
            return next_state

        if not self.config.INTERACTIVE:
            # next_state = self.system.prepare_state_representation()
            # if self.config.use_new_reward:
            #     reward = self.evaluate_cur_move_new()
            # else:
            reward = self.evaluate_cur_move()
            # reward = 0
            return next_state, reward, self.done
        else:
            # next_state = self.system.prepare_state_representation()
            reward = 0

            if self.last_usr_act_pred.act == UserAct.GOODBYE:
                self.done = True
                self.last_sys_act, self.last_sys_sent = Action(SystemAct.GOODBYE,
                                                               None), "Thanks for using the system! Have a good day!"
                if self.verbose:
                    print("{} Sys: {}".format(self.step_i, self.last_sys_sent))

            return next_state, reward, self.done
Beispiel #7
0
    def _index_to_action(self, sys_act_idx, usr_act=None):
        assert isinstance(sys_act_idx, (int, np.integer))
        if sys_act_idx == 1:
            # present result
            queryable = ((len(self.state['informed']['pricerange']) > 0) and (
                        len(self.state['informed']['area']) > 0) and (len(self.state['informed']['food']) > 0)) \
                        or (len(self.state['informed']['name']) > 0)
            if self.with_bit:
                assert queryable
            else:
                if not queryable:
                    print("cannot make a query now! missing slots")
                    self.dialog_status = dialog_config.FAILED_DIALOG
                    return None
                else:
                    return self.query_and_decide_present_mode(usr_act)

        elif sys_act_idx == 3:
            # book success/failure
            reservable = [len(value) for entity, value in self.state['reservation_informed'].items()]
            reservable = np.all(reservable)

            if self.with_bit:
                assert reservable
            else:
                if not reservable:
                    print("cannot make a reservation now! missing slots")
                    self.dialog_status = dialog_config.FAILED_DIALOG
                    return None
                else:
                    reservation_available = self.sample([True, False], p=[0.8, 0.2])
                    if reservation_available:
                        params = self._generate_params(SystemAct.BOOKING_SUCCESS)
                        return Action(SystemAct.BOOKING_SUCCESS, params)
                    else:
                        return Action(SystemAct.BOOKING_FAIL, None)
        else:
            sys_act_str = dialog_config.index_to_action_dict[sys_act_idx]
            params = self._generate_params(sys_act_str=sys_act_str, usr_act=usr_act)

            return Action(sys_act_str, params)
Beispiel #8
0
    def respond(self, sys_act, prev_sys=None):
        mode = 'test'
        turn_states = {}
        turn_num = self.turn_batch['turn_num'][0]
        act_list = ['inform_type', \
                    'inform_type_change', \
                    'ask_info', \
                    'make_reservation', \
                    'make_reservation_change_time', \
                    'anything_else', \
                    'goodbye']

        if turn_num != 0:
            self.update_states_from_sys(sys_act)

        if prev_sys is None:
            prev_sys = 'Hello! What can I help you?'.lower()
        else:
            prev_sys = prev_sys.lower()

        # # format input
        utt_tokenized = word_tokenize(prev_sys) + ['EOS_U']
        utt_encoded = self.m.reader.vocab.sentence_encode(utt_tokenized)

        if self.turn_batch['turn_num'] == [0]:
            self.turn_batch['user'] = [utt_encoded]
        else:
            self.turn_batch['user'] = [self.m.reader.vocab.sentence_encode(word_tokenize(self.prev_act)) + \
                                 [self.m.reader.vocab.encode('EOS_M')] + \
                                 utt_encoded]

        self.turn_batch['u_len'] = [len(i) for i in self.turn_batch['user']]
        self.turn_batch['m_len'] = [
            len(i) for i in self.turn_batch['response']
        ]

        u_input, u_input_np, z_input, m_input, m_input_np, u_len, \
            m_len, degree_input, kw_ret \
                = self.m._convert_batch(self.turn_batch, self.prev_z)

        # # execute tsd-net
        m_idx, z_idx, turn_states = self.m.m(
            mode=mode,
            u_input=u_input,
            u_len=u_len,
            z_input=z_input,
            m_input=m_input,
            degree_input=degree_input,
            u_input_np=u_input_np,
            m_input_np=m_input_np,
            m_len=m_len,
            turn_states=turn_states,
            dial_id=self.turn_batch['dial_id'],
            **kw_ret)

        self.act = act_list[m_idx[0, 0, 0]]
        if turn_num == 0:
            self.act = 'inform_type'

        # # generating slots
        slot_dict = self.generate_dial_act_slots(sys_act, prev_sys)

        # # generating sentence with templats
        usr_act = Action(self.act, slot_dict)
        # pdb.set_trace()
        # print(usr_act)

        if self.act == 'inform_type' and slot_dict == {} and sys_act.act == SystemAct.ASK_TYPE:
            usr_response_sent = 'i do not care.'
        else:
            if self.nlg_sample:
                assert self.nlg_templates
                assert self.generator
                # usr_response_sent, lexicalized_usr_act = self.nlg.generate_sent(usr_act, templates=self.nlg_templates, generator=1)
                print('supervised nlg_sample')
                if prev_sys is None:
                    prev_sys = "<start>"

                usr_response_sent, lexicalized_usr_act = self.nlg.generate_sent(
                    usr_act,
                    templates=self.nlg_templates,
                    generator=self.generator,
                    context=prev_sys,
                    seq2seq=None)
            else:
                # print('')
                if self.seq2seq is None:
                    print("supervised templates")
                    assert self.nlg_template
                    assert not self.nlg_sample
                    assert self.generator is None
                    usr_response_sent, lexicalized_usr_act = self.nlg.generate_sent(
                        usr_act,
                        turn_num=(len(self.state['usr_act_sequence']) - 1),
                        generator=None,
                        seq2seq=None)
                else:
                    print(" supervised seq2seq")
                    assert not self.nlg_sample
                    assert not self.nlg_template
                    assert self.seq2seq
                    usr_response_sent, lexicalized_usr_act = self.nlg.generate_sent(
                        usr_act, generator=None, seq2seq=self.seq2seq)
                    usr_response_sent = usr_response_sent.replace("<eos>", "")
                usr_response_sent = usr_response_sent.lower()

                # usr_response_sent, lexicalized_usr_act = self.nlg.generate_sent(usr_act, turn_num=turn_num)

        # # check success of last turn
        if turn_num != 0:
            self.success_or_not(self.prev_usr, prev_sys, usr_response_sent,
                                sys_act)

        # # update states
        self.update_states_from_user(slot_dict)

        self.prev_z = z_idx
        self.prev_act = self.act
        self.prev_usr = usr_response_sent
        turn_num += 1
        self.turn_batch['turn_num'] = [turn_num]
        # self.turn_batch['bspan'] = self.prev_z

        return None, usr_response_sent
Beispiel #9
0
 def _response_GOODBYE(self):
     return Action(SystemAct.GOODBYE, None)
Beispiel #10
0
 def _response_MAKE_RESERVATION_CHANGE_TIME(self, usr_act):
     if self.sample([True, False], p=[0.8, 0.2]):
         params = {'reference': "ABC"}
         return Action(SystemAct.BOOKING_SUCCESS, params)
     else:
         return Action(SystemAct.BOOKING_FAIL, None)
Beispiel #11
0
 def _response_ASK_INFO(self, usr_act):
     params = self._generate_params(SystemAct.PROVIDE_INFO, usr_act=usr_act)
     return Action(SystemAct.PROVIDE_INFO, params)
Beispiel #12
0
    def nlu(self, usr_sent, usr_act=None, mode=None):

        if (mode == dialog_config.RANDOM_ACT) or (mode == dialog_config.RL_WARM_START):
            # return the true usr_act
            delex_sent, kv_dic = delexicalize.delexicalize_one_sent(usr_sent)
            self.last_usr_sent = delex_sent
            return usr_act
        elif mode == dialog_config.RL_TRAINING or mode == dialog_config.INTERACTIVE:
            # return usr_act
            # print("Warning: temporarily use the real user_act")
            delex_sent, kv_dic = delexicalize.delexicalize_one_sent(usr_sent)

            params = {}
            for k, v in kv_dic.items():
                if ('value_area') in k or ('value_place') in k:
                    params['area'] = v
                elif 'value_food' in k:
                    params['food'] = v
                elif 'value_pricerange' in k:
                    params['pricerange'] = v
                elif 'restaurant_name' in k:
                    params['name'] = v

                elif 'value_day' in k:
                    params['day'] = v
                elif 'value_time' in k:
                    params['time'] = v
                elif 'value_count' in k:
                    params['people'] = v
                else:
                    continue

            usr_act_str = single_pred(self.nlu_model, delex_sent)[0].lower()

            # import pdb
            # pdb.set_trace()
            if len(self.state['results']) == 0:
                if self.config.use_sl_simulator:
                    usr_act_str = UserAct.INFORM_TYPE
                else:
                    usr_act_str = UserAct.INFORM_TYPE
                # pass
            if usr_act_str == UserAct.INFORM_TYPE:
                pass
            elif usr_act_str == UserAct.INFORM_TYPE_CHANGE:
                pass
            elif usr_act_str == UserAct.ASK_INFO:
                if "phone" in usr_sent:
                    params.update({"phone": None})
                if "address" in usr_sent:
                    params.update({'address': None})
                if "postcode" in usr_sent or "post code" in usr_sent:
                    params.update({'postcode': None})
                # params.update({'phone': None})
                # if "price" in usr_sent:
                #     params.update({'price': None})
                # if "area" in usr_sent:
                #     params.update({'area': None})
                # if "food" in usr_sent or "cuisine" in usr_sent or "type" in usr_sent:
                #     params.update({'food': None})
            elif usr_act_str == UserAct.ANYTHING_ELSE:
                pass
            elif usr_act_str == UserAct.MAKE_RESERVATION:
                pass
            elif usr_act_str == UserAct.MAKE_RESERVATION_CHANGE_TIME:
                pass
            elif usr_act_str == UserAct.GOODBYE:
                pass
            else:
                usr_act_str = UserAct.INFORM_TYPE


            usr_act = Action(usr_act_str, params)
            self.last_usr_sent = delex_sent
            print(usr_act)
            return usr_act