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)
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)
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)
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)
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
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)
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
def _response_GOODBYE(self): return Action(SystemAct.GOODBYE, None)
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)
def _response_ASK_INFO(self, usr_act): params = self._generate_params(SystemAct.PROVIDE_INFO, usr_act=usr_act) return Action(SystemAct.PROVIDE_INFO, params)
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