def domain_fill(self, delex_action, state, action, act): domain, act_type = act.split('-') constraints = [] for slot in state['belief_state'][domain.lower()]['semi']: if state['belief_state'][domain.lower()]['semi'][slot] != "": constraints.append([ slot, state['belief_state'][domain.lower()]['semi'][slot] ]) if act_type in ['NoOffer', 'OfferBook']: # NoOffer['none'], OfferBook['none'] action[act] = [] for slot in constraints: action[act].append( [REF_USR_DA[domain].get(slot[0], slot[0]), slot[1]]) elif act_type in ['Inform', 'Recommend', 'OfferBooked' ]: # Inform[Slot,...], Recommend[Slot, ...] kb_result = query(domain.lower(), constraints) # print("Policy Util") # print(constraints) # print(len(kb_result)) if len(kb_result) == 0: action[act] = [['none', 'none']] else: action[act] = [] for slot in delex_action[act]: if slot == 'Choice': action[act].append([slot, len(kb_result)]) elif slot == 'Ref': if "Ref" in kb_result[0]: action[act].append(["Ref", kb_result[0]["Ref"]]) else: action[act].append(["Ref", "N/A"]) else: try: action[act].append([ slot, kb_result[0][REF_SYS_DA[domain].get( slot, slot)] ]) except: action[act].append([slot, "N/A"]) if len(action[act]) == 0: action[act] = [['none', 'none']] elif act_type in ['Select']: # Select[Slot] kb_result = query(domain.lower(), constraints) if len(kb_result) < 2: action[act] = [['none', 'none']] else: slot = delex_action[act][0] action[act] = [] action[act].append( [slot, kb_result[0][REF_SYS_DA[domain].get(slot, slot)]]) action[act].append( [slot, kb_result[1][REF_SYS_DA[domain].get(slot, slot)]]) else: print('Cannot decode:', str(delex_action)) action[act] = [['none', 'none']]
def decode(self, action_index, state): domains = ['Attraction', 'Hospital', 'Hotel', 'Restaurant', 'Taxi', 'Train', 'Police'] delex_action = self.action_vocab.get_action(action_index) action = {} for act in delex_action: domain, act_type = act.split('-') if domain in domains: self.current_domain = domain if act_type == 'Request': action[act] = [] for slot in delex_action[act]: action[act].append([slot, '?']) elif act == 'Booking-Book': constraints = [] for slot in state['belief_state'][self.current_domain.lower()]['semi']: if state['belief_state'][self.current_domain.lower()]['semi'][slot] != "": constraints.append([slot, state['belief_state'][self.current_domain.lower()]['semi'][slot]]) kb_result = query(self.current_domain.lower(), constraints) if len(kb_result) == 0: action[act] = [['none', 'none']] else: if "Ref" in kb_result[0]: action[act] = [["Ref", kb_result[0]["Ref"]]] else: action[act] = [["Ref", "N/A"]] elif domain not in domains: action[act] = [['none', 'none']] else: if act == 'Taxi-Inform': for info_slot in ['leaveAt', 'arriveBy']: if info_slot in state['belief_state']['taxi']['semi'] and \ state['belief_state']['taxi']['semi'][info_slot] != "": car = generate_car() phone_num = generate_phone_num(11) action[act] = [] action[act].append(['Car', car]) action[act].append(['Phone', phone_num]) break else: action[act] = [['none', 'none']] elif act in ['Train-Inform', 'Train-NoOffer', 'Train-OfferBook']: for info_slot in ['departure', 'destination']: if info_slot not in state['belief_state']['train']['semi'] or \ state['belief_state']['train']['semi'][info_slot] == "": action[act] = [['none', 'none']] break else: for info_slot in ['leaveAt', 'arriveBy']: if info_slot in state['belief_state']['train']['semi'] and \ state['belief_state']['train']['semi'][info_slot] != "": self.domain_fill(delex_action, state, action, act) break else: action[act] = [['none', 'none']] elif domain in domains: self.domain_fill(delex_action, state, action, act) return action
def get_db_state(self, belief_state): domains = ['restaurant', 'hotel', 'attraction', 'train'] db_vector = np.zeros(6 * len(domains)) num_entities = {} for domain in domains: entities = query(domain, belief_state[domain]['semi'].items()) db_vector = self.one_hot(len(entities), domain, domains, db_vector) return db_vector
def addDBPointer(state): """Create database pointer for all related domains.""" domains = ['restaurant', 'hotel', 'attraction', 'train'] pointer_vector = np.zeros(6 * len(domains)) db_results = {} num_entities = {} for domain in domains: # entities = dbPointer.queryResultVenues(domain, {'metadata': state}) entities = dbquery.query(domain, state[domain]['semi'].items()) num_entities[domain] = len(entities) if len(entities) > 0: # fields = dbPointer.table_schema(domain) # db_results[domain] = dict(zip(fields, entities[0])) db_results[domain] = entities[0] # pointer_vector = dbPointer.oneHotVector(len(entities), domain, pointer_vector) pointer_vector = oneHotVector(len(entities), domain, pointer_vector) return list(pointer_vector), db_results, num_entities
def gen_example(self, state): file = '' turn = 0 guid = 'infer' act = state['user_action'] for w in act: d, f = w.split('-') if Constants.domains.index(d.lower()) < 8: self.domain = d.lower() hierarchical_act_vecs = [0 for _ in range(44)] # fake target meta = state['belief_state'] constraints = [] if self.domain != 'bus': for slot in meta[self.domain]['semi']: if meta[self.domain]['semi'][slot] != "": constraints.append([slot, meta[self.domain]['semi'][slot]]) query_result = query(self.domain, constraints) if not query_result: kb = {'count': '0'} src = "no information" else: kb = query_result[0] kb['count'] = str(len(query_result)) src = [] for k, v in kb.items(): k = examine(self.domain, k.lower()) if k != 'illegal' and isinstance(v, str): src.extend([k, 'is', v]) src = " ".join(src) usr = state['history'][-1][-1] sys = state['history'][-1][-2] if len( state['history'][-1]) > 1 else None example = InputExample(file, turn, guid, src, usr, sys, hierarchical_act_vecs) kb['domain'] = self.domain return example, kb
def sample_sequence_v4(self, history, current_output=None): special_tokens_id = self.tokenizer.convert_tokens_to_ids( self.SPECIAL_TOKENS) dptok = [special_tokens_id[5]] sys = [special_tokens_id[3]] eos = [special_tokens_id[1]] if current_output is None: current_output = [] cs_dict = {} kb_results = {} i = 0 dp_count = 0 cs_count = 0 dp = [] cs = [] cs_done = 0 dp_done = 0 constraints = [] whole_kb = None while i < self.max_length: instance, sequence = build_input_from_segments_v1(history, current_output, self.tokenizer, dp=dp, cs=cs, with_eos=False, mode='infer') input_ids = torch.tensor(instance["input_ids"], device=self.device).unsqueeze(0) token_type_ids = torch.tensor(instance["token_type_ids"], device=self.device).unsqueeze(0) logits, attentions = self.model(input_ids, token_type_ids=token_type_ids) if "gpt2" in self.model_name: logits = logits[0] logits = logits[0, -1, :] / self.temperature logits = self.top_filtering(logits) probs = F.softmax(logits, dim=-1) if not dp_done: prev = torch.topk(probs, 1)[1] else: prev = torch.topk( probs, 1)[1] if self.no_sample else torch.multinomial( probs, 1) if i < self.min_length and prev.item() in eos: b = 0 while prev.item() in eos: if b == 3: break prev = torch.multinomial(probs, num_samples=1) b += 1 if prev.item() in eos: X = [self.tokenizer.decode([x]) for x in dp] Y = [self.tokenizer.decode([x]) for x in current_output] attentions_cpu = copy.deepcopy(attentions) for j in range(len(attentions_cpu)): for i, attn in enumerate(attentions_cpu[j][0].cpu()): visualize(X, Y, attn, 'res_{}_{}'.format(j, i)) break if prev.item() in dptok: X = ['<bos>'] + ['<usr>'] + [ self.tokenizer.decode([x]) for x in history[0] ] Y = ['<cs>'] + [self.tokenizer.decode([x]) for x in cs] attentions_cpu = copy.deepcopy(attentions) for j in range(len(attentions_cpu)): for i, attn in enumerate(attentions_cpu[j][0].cpu()): pass #visualize(X, Y, attn, 'cs_{}_{}'.format(j,i)) if cs_count == 0: cs_text = self.decode(cs).strip() if self.cur_dom != cs_text.split( ' ')[0][1:-1] and cs_text.split( ' ')[0][1:-1] in self.domains: self.cur_dom = cs_text.split(' ')[0][1:-1] keys = self.cs_mapping[ self.cur_dom] if self.cur_dom else [] if keys != []: prev_key = (0, '') cs_tok = cs_text.split(' ') for j, tok in enumerate(cs_tok): if tok[1:-1] in keys: if prev_key[1] != '': cs_dict[prev_key[1]] = ' '.join( cs_tok[prev_key[0] + 1:j]) prev_key = (j, tok[1:-1]) if j == len(cs_tok) - 1: cs_dict[prev_key[1]] = ' '.join( cs_tok[prev_key[0] + 1:]) constraints = [] cs_key = [] for k in cs_dict: if k in self.prev_cs and self.prev_dom == self.cur_dom: if cs_dict[k] in [ '<nm>', '', '<nm> ' ] and cs_dict[k] != self.prev_cs[k]: if cs_dict[k] in ['<dc>', '<dc> ']: constraints.append([k, 'dontcare']) else: constraints.append([k, self.prev_cs[k]]) else: if not cs_dict[k] in ['<nm>', '', '<nm> ']: if cs_dict[k] in ['<dc>', '<dc> ']: constraints.append([k, 'dontcare']) else: constraints.append([k, cs_dict[k]]) cs_key.append(k) kb_results = query(self.cur_dom, constraints) if self.cur_dom else None if self.cur_dom == 'train': if 'leaveAt' in cs_key: kb_results = sorted(kb_results, key=lambda k: k['leaveAt']) else: kb_results = sorted(kb_results, key=lambda k: k['arriveBy'], reverse=True) whole_kb = kb_results kb_results = self.convert_kb( kb_results[0]) if kb_results else None cs_count += 1 cs_done += 1 i = 0 if prev.item() in sys: X = ['<ds>'] + [self.tokenizer.decode([x]) for x in cs] Y = [self.tokenizer.decode([x]) for x in dp][:4] attentions_cpu = copy.deepcopy(attentions) for j in range(len(attentions_cpu)): for i, attn in enumerate(attentions_cpu[j][0].cpu()): pass #visualize(X, Y, attn, 'dp_{}_{}'.format(j,i)) if dp_count == 0: dialog_act = dp[1:] da_text = self.decode(dialog_act).strip() da_tok = da_text.split(' ') toks = [] for i, t in enumerate(da_tok): if t in act_name: toks.extend(t[1:-1].split('-')) elif t in slot_name: toks.append(t[1:-1]) else: toks.append(t) da_dict = self.convert_da(' '.join(toks), self.dia_act_dict) da_dict = self.convert_value(da_dict, constraints, None, whole_kb) bs = [] for d in da_dict: bs.append('<' + d.lower() + '>') for slot, value in da_dict[d]: bs.append('<' + slot.lower() + '>') if isinstance(value, dict): for k in value.keys(): bs.append(k) bs.append(value[k]) else: bs.append(value.lower()) dp = self.tokenizer.encode('<dp> ' + ' '.join(bs)) i = 0 dp_count += 1 dp_done += 1 if not cs_done: cs.append(prev.item()) elif not dp_done: dp.append(prev.item()) else: current_output.append(prev.item()) i += 1 self.prev_cs = constraints self.prev_dom = self.cur_dom return current_output[1:], dp[1:], cs_dict, kb_results, whole_kb
def get_user_goal(self, seed=None): if seed is not None: random.seed(seed) np.random.seed(seed) domain_ordering = () while len(domain_ordering) <= 0: domain_ordering = nomial_sample(self.domain_ordering_dist) # domain_ordering = ('restaurant',) user_goal = { dom: self._get_domain_goal(dom) for dom in domain_ordering } assert len(user_goal.keys()) > 0 # using taxi to communte between places, removing destination and departure. if 'taxi' in domain_ordering: places = [ dom for dom in domain_ordering[:domain_ordering.index('taxi')] if 'address' in self.ind_slot_dist[dom]['reqt'].keys() ] if len(places) >= 1: del user_goal['taxi']['info']['destination'] user_goal[places[-1]]['reqt'] = list( set(user_goal[places[-1]].get('reqt', [])).union({'address'})) if places[-1] == 'restaurant' and 'book' in user_goal[ 'restaurant']: user_goal['taxi']['info']['arriveBy'] = user_goal[ 'restaurant']['book']['time'] if 'leaveAt' in user_goal['taxi']['info']: del user_goal['taxi']['info']['leaveAt'] if len(places) >= 2: del user_goal['taxi']['info']['departure'] user_goal[places[-2]]['reqt'] = list( set(user_goal[places[-2]].get('reqt', [])).union({'address'})) # match area of attraction and restaurant if 'restaurant' in domain_ordering and \ 'attraction' in domain_ordering and \ 'fail_info' not in user_goal['restaurant'] and \ domain_ordering.index('restaurant') > domain_ordering.index('attraction') and \ 'area' in user_goal['restaurant']['info'] and 'area' in user_goal['attraction']['info']: adjusted_restaurant_goal = deepcopy( user_goal['restaurant']['info']) adjusted_restaurant_goal['area'] = user_goal['attraction']['info'][ 'area'] if len( dbquery.query('restaurant', adjusted_restaurant_goal.items( ))) > 0 and random.random() < 0.5: user_goal['restaurant']['info']['area'] = user_goal[ 'attraction']['info']['area'] # match day and people of restaurant and hotel if 'restaurant' in domain_ordering and 'hotel' in domain_ordering and \ 'book' in user_goal['restaurant'] and 'book' in user_goal['hotel']: if random.random() < 0.5: user_goal['restaurant']['book']['people'] = user_goal['hotel'][ 'book']['people'] if 'fail_book' in user_goal['restaurant']: user_goal['restaurant']['fail_book']['people'] = user_goal[ 'hotel']['book']['people'] if random.random() < 1.0: user_goal['restaurant']['book']['day'] = user_goal['hotel'][ 'book']['day'] if 'fail_book' in user_goal['restaurant']: user_goal['restaurant']['fail_book']['day'] = user_goal[ 'hotel']['book']['day'] if user_goal['restaurant']['book']['day'] == user_goal['restaurant']['fail_book']['day'] and \ user_goal['restaurant']['book']['time'] == user_goal['restaurant']['fail_book']['time'] and \ user_goal['restaurant']['book']['people'] == user_goal['restaurant']['fail_book']['people']: del user_goal['restaurant']['fail_book'] # match day and people of hotel and train if 'hotel' in domain_ordering and 'train' in domain_ordering and \ 'book' in user_goal['hotel'] and 'info' in user_goal['train']: if user_goal['train']['info']['destination'] == 'cambridge' and \ 'day' in user_goal['hotel']['book']: user_goal['train']['info']['day'] = user_goal['hotel']['book'][ 'day'] elif user_goal['train']['info']['departure'] == 'cambridge' and \ 'day' in user_goal['hotel']['book'] and 'stay' in user_goal['hotel']['book']: user_goal['train']['info']['day'] = days[ (days.index(user_goal['hotel']['book']['day']) + int(user_goal['hotel']['book']['stay'])) % 7] # In case, we have no query results with adjusted train goal, we simply drop the train goal. if len(dbquery.query('train', user_goal['train']['info'].items())) == 0: del user_goal['train'] domain_ordering = tuple(list(domain_ordering).remove('train')) user_goal['domain_ordering'] = domain_ordering return user_goal
def _get_domain_goal(self, domain): cnt_slot = self.ind_slot_dist[domain] cnt_slot_value = self.ind_slot_value_dist[domain] pro_book = self.book_dist[domain] while True: # domain_goal = defaultdict(lambda: {}) # domain_goal = {'info': {}, 'fail_info': {}, 'reqt': {}, 'book': {}, 'fail_book': {}} domain_goal = {'info': {}} # inform if 'info' in cnt_slot: for slot in cnt_slot['info']: if random.random( ) < cnt_slot['info'][slot] + pro_correction['info']: domain_goal['info'][slot] = nomial_sample( cnt_slot_value['info'][slot]) if domain in ['hotel', 'restaurant', 'attraction' ] and 'name' in domain_goal['info'] and len( domain_goal['info']) > 1: if random.random() < cnt_slot['info']['name']: domain_goal['info'] = { 'name': domain_goal['info']['name'] } else: del domain_goal['info']['name'] if domain in ['taxi', 'train'] and 'arriveBy' in domain_goal[ 'info'] and 'leaveAt' in domain_goal['info']: if random.random() < (cnt_slot['info']['leaveAt'] / (cnt_slot['info']['arriveBy'] + cnt_slot['info']['leaveAt'])): del domain_goal['info']['arriveBy'] else: del domain_goal['info']['leaveAt'] if domain in ['taxi', 'train'] and 'arriveBy' not in domain_goal['info'] and 'leaveAt' not in \ domain_goal['info']: if random.random() < (cnt_slot['info']['arriveBy'] / (cnt_slot['info']['arriveBy'] + cnt_slot['info']['leaveAt'])): domain_goal['info']['arriveBy'] = nomial_sample( cnt_slot_value['info']['arriveBy']) else: domain_goal['info']['leaveAt'] = nomial_sample( cnt_slot_value['info']['leaveAt']) if domain in ['taxi', 'train' ] and 'departure' not in domain_goal['info']: domain_goal['info']['departure'] = nomial_sample( cnt_slot_value['info']['departure']) if domain in ['taxi', 'train' ] and 'destination' not in domain_goal['info']: domain_goal['info']['destination'] = nomial_sample( cnt_slot_value['info']['destination']) if domain in ['taxi', 'train'] and \ 'departure' in domain_goal['info'] and \ 'destination' in domain_goal['info'] and \ domain_goal['info']['departure'] == domain_goal['info']['destination']: if random.random() < (cnt_slot['info']['departure'] / (cnt_slot['info']['departure'] + cnt_slot['info']['destination'])): domain_goal['info']['departure'] = nomial_sample( cnt_slot_value['info']['departure']) else: domain_goal['info']['destination'] = nomial_sample( cnt_slot_value['info']['destination']) if domain_goal['info'] == {}: continue # request if 'reqt' in cnt_slot: reqt = [ slot for slot in cnt_slot['reqt'] if random.random() < cnt_slot['reqt'][slot] + pro_correction['reqt'] and slot not in domain_goal['info'] ] if len(reqt) > 0: domain_goal['reqt'] = reqt # book if 'book' in cnt_slot and random.random( ) < pro_book + pro_correction['book']: if 'book' not in domain_goal: domain_goal['book'] = {} for slot in cnt_slot['book']: if random.random( ) < cnt_slot['book'][slot] + pro_correction['book']: domain_goal['book'][slot] = nomial_sample( cnt_slot_value['book'][slot]) # makes sure that there are all necessary slots for booking if domain == 'restaurant' and 'time' not in domain_goal['book']: domain_goal['book']['time'] = nomial_sample( cnt_slot_value['book']['time']) if domain == 'hotel' and 'stay' not in domain_goal['book']: domain_goal['book']['stay'] = nomial_sample( cnt_slot_value['book']['stay']) if domain in ['hotel', 'restaurant' ] and 'day' not in domain_goal['book']: domain_goal['book']['day'] = nomial_sample( cnt_slot_value['book']['day']) if domain in ['hotel', 'restaurant' ] and 'people' not in domain_goal['book']: domain_goal['book']['people'] = nomial_sample( cnt_slot_value['book']['people']) if domain == 'train' and len(domain_goal['book']) <= 0: domain_goal['book']['people'] = nomial_sample( cnt_slot_value['book']['people']) # fail_book if 'book' in domain_goal and random.random() < 0.5: if domain == 'hotel': domain_goal['fail_book'] = deepcopy(domain_goal['book']) if 'stay' in domain_goal['book'] and random.random() < 0.5: # increase hotel-stay domain_goal['fail_book']['stay'] = str( int(domain_goal['book']['stay']) + 1) elif 'day' in domain_goal['book']: # push back hotel-day by a day domain_goal['fail_book']['day'] = days[ (days.index(domain_goal['book']['day']) - 1) % 7] elif domain == 'restaurant': domain_goal['fail_book'] = deepcopy(domain_goal['book']) if 'time' in domain_goal['book'] and random.random() < 0.5: hour, minute = domain_goal['book']['time'].split(':') domain_goal['fail_book']['time'] = str( (int(hour) + 1) % 24) + ':' + minute elif 'day' in domain_goal['book']: if random.random() < 0.5: domain_goal['fail_book']['day'] = days[ (days.index(domain_goal['book']['day']) - 1) % 7] else: domain_goal['fail_book']['day'] = days[ (days.index(domain_goal['book']['day']) + 1) % 7] # fail_info if 'info' in domain_goal and len( dbquery.query(domain, domain_goal['info'].items())) == 0: num_trial = 0 while num_trial < 100: adjusted_info = self._adjust_info(domain, domain_goal['info']) if len(dbquery.query(domain, adjusted_info.items())) > 0: if domain == 'train': domain_goal['info'] = adjusted_info else: domain_goal['fail_info'] = domain_goal['info'] domain_goal['info'] = adjusted_info break num_trial += 1 if num_trial >= 100: continue # at least there is one request and book if 'reqt' in domain_goal or 'book' in domain_goal: break return domain_goal
def _update_train(self, user_act, user_action, state, DA): trans = { 'day': 'Day', 'destination': 'Destination', 'departure': 'Departure' } constraints = [] for time in ['leaveAt', 'arriveBy']: if state['belief_state']['train']['semi'][time] != "": constraints.append( [time, state['belief_state']['train']['semi'][time]]) if len(constraints) == 0: p = random.random() if 'Train-Request' not in DA: DA['Train-Request'] = [] if p < 0.33: DA['Train-Request'].append(['Leave', '?']) elif p < 0.66: DA['Train-Request'].append(['Arrive', '?']) else: DA['Train-Request'].append(['Leave', '?']) DA['Train-Request'].append(['Arrive', '?']) if 'Train-Request' not in DA: DA['Train-Request'] = [] for prop in ['day', 'destination', 'departure']: if state['belief_state']['train']['semi'][prop] == "": slot = REF_USR_DA['Train'].get(prop, prop) DA["Train-Request"].append([slot, '?']) else: constraints.append( [prop, state['belief_state']['train']['semi'][prop]]) kb_result = query('train', constraints) self.kb_result['Train'] = deepcopy(kb_result) # print(constraints) # print(len(kb_result)) if user_act == 'Train-Request': del (DA['Train-Request']) if 'Train-Inform' not in DA: DA['Train-Inform'] = [] for slot in user_action[user_act]: # Train_DA_MAP = {'Duration': "Time", 'Price': 'Ticket', 'TrainID': 'Id'} # slot[0] = Train_DA_MAP.get(slot[0], slot[0]) slot_name = REF_SYS_DA['Train'].get(slot[0], slot[0]) try: DA['Train-Inform'].append( [slot[0], kb_result[0][slot_name]]) except: pass return if len(kb_result) == 0: if 'Train-NoOffer' not in DA: DA['Train-NoOffer'] = [] for prop in constraints: DA['Train-NoOffer'].append( [REF_USR_DA['Train'].get(prop[0], prop[0]), prop[1]]) if 'Train-Request' in DA: del DA['Train-Request'] elif len(kb_result) >= 1: if len(constraints) < 4: return if 'Train-Request' in DA: del DA['Train-Request'] if 'Train-OfferBook' not in DA: DA['Train-OfferBook'] = [] for prop in constraints: DA['Train-OfferBook'].append( [REF_USR_DA['Train'].get(prop[0], prop[0]), prop[1]])
def _update_DA(self, user_act, user_action, state, DA): """ Answer user's utterance about any domain other than taxi or train. """ domain, intent_type = user_act.split('-') constraints = [] for slot in state['belief_state'][domain.lower()]['semi']: if state['belief_state'][domain.lower()]['semi'][slot] != "": constraints.append([ slot, state['belief_state'][domain.lower()]['semi'][slot] ]) kb_result = query(domain.lower(), constraints) self.kb_result[domain] = deepcopy(kb_result) # print("\tConstraint: " + "{}".format(constraints)) # print("\tCandidate Count: " + "{}".format(len(kb_result))) # if len(kb_result) > 0: # print("Candidate: " + "{}".format(kb_result[0])) # print(state['user_action']) # Respond to user's request if intent_type == 'Request': if self.recommend_flag > 1: self.recommend_flag = -1 self.choice = "" elif self.recommend_flag == 1: self.recommend_flag == 0 if (domain + "-Inform") not in DA: DA[domain + "-Inform"] = [] for slot in user_action[user_act]: if len(kb_result) > 0: kb_slot_name = REF_SYS_DA[domain].get(slot[0], slot[0]) if kb_slot_name in kb_result[0]: DA[domain + "-Inform"].append( [slot[0], kb_result[0][kb_slot_name]]) else: DA[domain + "-Inform"].append([slot[0], "unknown"]) # DA[domain + "-Inform"].append([slot_name, state['kb_results_dict'][0][slot[0].lower()]]) else: # There's no result matching user's constraint # if len(state['kb_results_dict']) == 0: if len(kb_result) == 0: if (domain + "-NoOffer") not in DA: DA[domain + "-NoOffer"] = [] for slot in state['belief_state'][domain.lower()]['semi']: if state['belief_state'][domain.lower()]['semi'][slot] != "" and \ state['belief_state'][domain.lower()]['semi'][slot] != "do n't care": slot_name = REF_USR_DA[domain].get(slot, slot) DA[domain + "-NoOffer"].append([ slot_name, state['belief_state'][domain.lower()]['semi'][slot] ]) p = random.random() # Ask user if he wants to change constraint if p < 0.3: req_num = min( random.randint(0, 999999) % len(DA[domain + "-NoOffer"]) + 1, 3) if domain + "-Request" not in DA: DA[domain + "-Request"] = [] for i in range(req_num): slot_name = REF_USR_DA[domain].get( DA[domain + "-NoOffer"][i][0], DA[domain + "-NoOffer"][i][0]) DA[domain + "-Request"].append([slot_name, "?"]) # There's exactly one result matching user's constraint # elif len(state['kb_results_dict']) == 1: elif len(kb_result) == 1: # Inform user about this result if (domain + "-Inform") not in DA: DA[domain + "-Inform"] = [] props = [] for prop in state['belief_state'][domain.lower()]['semi']: props.append(prop) property_num = len(props) if property_num > 0: info_num = random.randint(0, 999999) % property_num + 1 random.shuffle(props) for i in range(info_num): slot_name = REF_USR_DA[domain].get(props[i], props[i]) # DA[domain + "-Inform"].append([slot_name, state['kb_results_dict'][0][props[i]]]) DA[domain + "-Inform"].append( [slot_name, kb_result[0][props[i]]]) # There are multiple resultes matching user's constraint else: p = random.random() # Recommend a choice from kb_list if True: #p < 0.3: if (domain + "-Inform") not in DA: DA[domain + "-Inform"] = [] if (domain + "-Recommend") not in DA: DA[domain + "-Recommend"] = [] DA[domain + "-Inform"].append( ["Choice", str(len(kb_result))]) idx = random.randint(0, 999999) % len(kb_result) # idx = 0 choice = kb_result[idx] if domain in [ "Hotel", "Attraction", "Police", "Restaurant" ]: DA[domain + "-Recommend"].append( ['Name', choice['name']]) self.recommend_flag = 0 self.candidate = choice props = [] for prop in choice: props.append([prop, choice[prop]]) prop_num = min(random.randint(0, 999999) % 3, len(props)) # prop_num = min(2, len(props)) random.shuffle(props) for i in range(prop_num): slot = props[i][0] string = REF_USR_DA[domain].get(slot, slot) if string in INFORMABLE_SLOTS: DA[domain + "-Recommend"].append( [string, str(props[i][1])]) # Ask user to choose a candidate. elif p < 0.5: prop_values = [] props = [] # for prop in state['kb_results_dict'][0]: for prop in kb_result[0]: # for candidate in state['kb_results_dict']: for candidate in kb_result: if prop not in candidate: continue if candidate[prop] not in prop_values: prop_values.append(candidate[prop]) if len(prop_values) > 1: props.append([prop, prop_values]) prop_values = [] random.shuffle(props) idx = 0 while idx < len(props): if props[idx][0] not in SELECTABLE_SLOTS[domain]: props.pop(idx) idx -= 1 idx += 1 if domain + "-Select" not in DA: DA[domain + "-Select"] = [] for i in range(min(len(props[0][1]), 5)): prop_value = REF_USR_DA[domain].get( props[0][0], props[0][0]) DA[domain + "-Select"].append( [prop_value, props[0][1][i]]) # Ask user for more constraint else: reqs = [] for prop in state['belief_state'][domain.lower()]['semi']: if state['belief_state'][ domain.lower()]['semi'][prop] == "": prop_value = REF_USR_DA[domain].get(prop, prop) reqs.append([prop_value, "?"]) i = 0 while i < len(reqs): if reqs[i][0] not in REQUESTABLE_SLOTS: reqs.pop(i) i -= 1 i += 1 random.shuffle(reqs) if len(reqs) == 0: return req_num = min(random.randint(0, 999999) % len(reqs) + 1, 2) if (domain + "-Request") not in DA: DA[domain + "-Request"] = [] for i in range(req_num): req = reqs[i] req[0] = REF_USR_DA[domain].get(req[0], req[0]) DA[domain + "-Request"].append(req)