Exemplo n.º 1
0
 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']]
Exemplo n.º 2
0
    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
Exemplo n.º 3
0
    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 
Exemplo n.º 4
0
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
Exemplo n.º 5
0
    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
Exemplo n.º 6
0
    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
Exemplo n.º 7
0
    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
Exemplo n.º 8
0
    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
Exemplo n.º 9
0
    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]])
Exemplo n.º 10
0
    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)