def _get_random_goal(self): '''Sample a final goal of user. Returns: A dict represent slots and their values sampled. ''' self.goal_id = sample_from_dict(self._goal_dist) goal_des = self.metadata['goals'][self.goal_id] goal = {} self.goal = goal sampled_slots = [] for s, v in goal_des['fixed_slots']:#fixed slots goal[s] = v sampled_slots.append(s) for key in goal_des['same_table_slot_keys']:#same table slots NOTE same_table_slot was coded without testing since data hadn't faked yet slots_values = self._get_random_same_table_slots_values(key) for slot in slots_values.keys(): if slot in goal_des['changeable_slots']: sampled_slots.append(slot) goal[slot] = slots_values[slot] for one_set in goal_des['one_of_slot_set']:#get value for one slot set and ignore other slots slot_set = sample_from_dict(one_set) for slot in slot_set: goal[slot] = self._get_random_slot_value(slot) for key in one_set.keys(): sampled_slots.extend(key) sampled_slots.extend(goal_des['sys_unaskable_slots']) remain_slots = matlab.subtract(goal_des['changeable_slots'], sampled_slots) for slot in remain_slots:#changeable slots goal[slot] = self._get_random_slot_value(slot) '''Don't fill default slots, only return when system ask for slot, value in goal_des['default_slots_values']:#fill the default slot which was not being filled if slot not in goal.keys(): goal[slot] = value ''' fun = get_dict_value(goal_des,'goal_post_process_fun') if fun is not None: #goal = fun(self, goal) goal = fun(goal) #for debug: #self.goal_id = 0 #goal = {'to_city': u'Allerton', 'task': 'find_connection', 'from_city': u'North Massapequa',} return goal
def _get_random_row(self, table): '''Get a random row for the given table.''' if table in self.metadata['data_observation_probability'].keys(): data_dist = self._get_data_distribution(table) return sample_from_dict(data_dist) else: return self.db.get_random_row(table)
def simulate_one_da_item(self, da_item): #TODO: The current way of sample prob is not really fit with action and slot confusion, just for value confusion print '--Simulate da_item:', da_item original_da_type = da_item.dat original_slot = da_item.name original_value = da_item.value #get the da_types/acts will be confused da_types, da_types_probs = self._get_confused_acts(original_da_type) print zip(da_types, da_types_probs) #print '------FInish test, da confused: ' #print da_types, '|||', da_types_probs #pdb.set_trace() #Confusing things da_items = []#all item confused for this da_item da_items_probs = [] #Each confused action have a prob of 1 for its all confused elements and will be combined/recalculate later for index, da_type in enumerate(da_types):#for every dalougue act (type) which will be considerd or confused, such as inform, affirm #get the act_out definitions and check is this actionneed slot #print 'build ', da_type act_out_des = self.domain['dialogue_act_definitions'][da_type] if 'act_without_slot' in act_out_des.keys() and act_out_des['act_without_slot']: da_item = DialogueActItem(da_type) da_items.append(da_item) da_items_probs.append(self.prob_combine_fun(1.0, da_types_probs[index])) continue #get slots will be confused slot_confusion = self.config['slot_confusion'] slots = original_slot if original_slot in slot_confusion.keys(): slots = sample_from_dict(slot_confusion[original_slot]) if not isinstance(slots, list):#only one slot slots = [slots] #print 'check confused slots' #pdb.set_trace() for slot in slots:#for every slot if act_out_des['value_included']==False: da_items.append(DialogueActItem(da_type, slot)) da_items_probs.append(self.prob_combine_fun(1.0,da_types_probs[index])) continue confusion_des = self._get_confusion_description(slot, da_type) items, probs = self._get_confused_slot_values(confusion_des, slot, original_value) for item, prob in zip(items, probs): da_items.append(DialogueActItem(da_type, slot, item)) da_items_probs.append(self.prob_combine_fun(prob,da_types_probs[index])) #print 'Get final resul for a dialogue_item:', da_items print '***sampled dialogue acts:' for dai, prob in zip(da_items, da_items_probs): print dai, '\t', prob return da_items, da_items_probs
def _sample_element_from_list_dict(self, lst_dict):#should be static or class function, but this way potential for future speeup with caching '''Sample an element in a list based on its active probability. Args: lst_dict: A list of dict, in which each dict contains the key, active_prob, presenting the observation probably. Returns: A dict from the given list. ''' dist = self._get_dict_distribution(lst_dict) index = sample_from_dict(dist) return lst_dict[index]
def new_dialogue(self): '''Start a new dialogue. Sample a new user goal and reset everything for simulating a new dialogue. ''' self.goal = self._get_random_goal() self.slot_level = self._build_slot_level() #self.dialog_turns = [] make the full history in somewhere else, not the task of user simulator self.unprocessed_da_queue = [] self.act_used_slots = {} self.slot_level_used = 0 self.turns = [] self.patience_history= {} self.system_logger.info("SimpleUserSimulator: GOAL: %s"%self.goal) #Sample patience level, since different user will have a different level if 'patience_levels' in self.config.keys(): self.patience_level = sample_from_dict(self.config['patience_levels']) print '---Patience - level: ', self.patience_level self.last_user_da = None
def _build_one_answer(self, da_metadata, answer, follow_order=False): '''Build a full answer to a system act. Args: da_metadata: a dict contains only description of system act such as slots-values. answer: a dic full description of answer act. follow_order: a boolean specifying the first return act need to be satisfied or cancel completely the answer. Returns: A list of DialogueActItem object. ''' #print answer da_items = [] new_items = [] first_act = True for act_out in answer['return_acts']:#for reply without ordered answer #New for repeat if act_out == 'repeat': da_items.extend(self.last_user_da)#add previous act, may add more if we use inform in return_acts continue answer_types = get_dict_value(answer, act_out + '_answer_types') answer_type = None if answer_types is not None: answer_type = sample_from_dict(answer_types) overridden_properties = get_dict_value(answer, act_out + '_overridden_properties') #da_items.extend(self._build_dialogue_act_items(da_metadata, act_out, answer_type, overridden_properties)) new_items = self._build_dialogue_act_items(da_metadata, act_out, answer_type, overridden_properties) da_items.extend(new_items) if follow_order and 'all_act_valid' in answer.keys() and answer['all_act_valid']==True:#this case of this answer requires all acts must appliabl if len(new_items)==0: da_items = []#cancel all other da item already build, that will move to next case of anser break if first_act and follow_order:#if the first action in a return actions which follows the order not successful, that case not satisfy, give up first_act=False if len(da_items)==0: break return da_items
def _sample_confusion_type(self, confusion_des): '''Sample confusion type.''' return sample_from_dict(confusion_des['confusion_types'])
def simulate_one_da_item(self, da_item): # TODO: The current way of sample prob is not really fit with action and slot confusion, just for value confusion print "--Simulate da_item:", da_item original_da_type = da_item.dat original_slot = da_item.name original_value = da_item.value # get the da_types/acts will be confused act_confusion = self.config["act_confusion"] da_types = original_da_type if original_da_type in act_confusion.keys(): da_types = sample_from_dict(act_confusion[original_da_type]) if isinstance(da_types, str): # only one datype will be generate da_types = [da_types] # Confusing things da_items = [] # all item confused for this da_item da_items_probs = [] # Each confused action have a prob of 1 for its all confused elements and will be combined/recalculate later for ( da_type ) in da_types: # for every dalougue act (type) which will be considerd or confused, such as inform, affirm # get the act_out definitions and check is this actionneed slot act_out_des = self.domain["dialogue_act_definitions"][da_type] if "act_without_slot" in act_out_des.keys() and act_out_des["act_without_slot"]: da_item = DialogueActItem(da_type) da_items.append(da_item) da_items_probs.append(1.0) continue # get slots will be confused slot_confusion = self.config["slot_confusion"] slots = original_slot if original_slot in slot_confusion.keys(): slots = sample_from_dict(slot_confusion[original_slot]) if isinstance(slots, str): # only one slot slots = [slots] for slot in slots: # for every slot confusion_des = self._get_confusion_description(slot, da_type) confusion_type = self._sample_confusion_type(confusion_des["confusion_types"]) correct_position = 0 print "---", da_type, slot, confusion_type if confusion_type == "silence": # can be never used since it is similar to the act confusion da_item = DialogueActItem("silence") da_items.append(da_item) else: length = confusion_des["max_length"] length = random.randint(1, length) correct_position = 0 # this postion for the confusion type = correct if confusion_type == "correct": correct_position = 0 elif confusion_type == "offlist": correct_position = -1 elif confusion_type == "onlist": correct_position = self._sample_onlist_position(confusion_des, length) # sample else: raise NotImplementedError("confusion_type=%s was not implemented." % confusion_type) # print da_type, slot, confusion_type, correct_position items, probs = self._sample_nbest_list_hypotheses( da_type, slot, original_value, correct_position, length, confusion_des, confusion_type ) da_items.extend(items) da_items_probs.extend(probs) # print 'Get final resul for a dialogue_item:', da_items return da_items, da_items_probs
def _sample_confusion_type(self, confusion_des): return sample_from_dict(confusion_des)