diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000000000000000000000000000000000000..5bc422ac0eb174e5ecf6fa19527919ace751fdde
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,53 @@
+FROM nvidia/cuda:10.1-cudnn7-runtime-ubuntu18.04
+ENV DEBIAN_FRONTEND noninteractive
+RUN apt-get update
+RUN apt-get install -y --no-install-recommends  software-properties-common
+RUN add-apt-repository ppa:deadsnakes/ppa
+RUN apt-get update
+RUN apt-get install -y --no-install-recommends python3.7 python3-pip build-essential libssl-dev libffi-dev python3.7-dev
+
+RUN python3.7 -m pip install --upgrade pip
+RUN python3.7 -m pip install setuptools wheel
+
+RUN which python3.7
+RUN which pip3
+
+RUN ln -f -s /usr/bin/python3.7 /usr/bin/python
+RUN ln -f -s /usr/bin/pip3 /usr/bin/pip
+RUN python --version
+
+RUN pip install nltk==3.4
+RUN pip install tqdm==4.30
+RUN pip install checksumdir==1.1
+RUN pip install dataclasses
+RUN pip install visdom
+RUN pip install Pillow
+RUN pip install future
+RUN pip install torch
+RUN pip install numpy==1.15.0
+RUN pip install scipy
+RUN pip install scikit-learn==0.20.3
+RUN pip install pytorch-pretrained-bert==0.6.1
+RUN pip install transformers==2.3.0
+RUN pip install tensorflow==1.14
+RUN pip install tensorboard==1.14.0
+RUN pip install tensorboardX==1.7
+RUN pip install tokenizers==0.8.0
+RUN pip install allennlp==0.9.0
+RUN pip install requests
+RUN pip install simplejson
+RUN pip install spacy
+RUN pip install unidecode
+RUN pip install jieba
+RUN pip install embeddings
+RUN pip install quadprog
+RUN pip install pyyaml
+RUN pip install fuzzywuzzy
+RUN pip install python-Levenshtein
+
+
+RUN [ "python", "-c", "import nltk; nltk.download('stopwords')" ]
+
+WORKDIR /root
+
+CMD ["/bin/bash"]
diff --git a/README.md b/README.md
index 5433d94db5996b48368df4354bcd795ee9461c24..252a121c39c87e00598ae7fbff313c22af7b6f6e 100755
--- a/README.md
+++ b/README.md
@@ -208,9 +208,9 @@ evaluation of our pre-trained models are: (joint acc.)
 
 | type  | CrossWOZ-en | MultiWOZ-zh |
 | ----- | ----------- | ----------- |
-| val   | 12.2%       | 44.8%       |
-| test  | 12.4%       | 42.3%       |
-| human_val | 10.9%       | 48.2%       |
+| val   | 12.4%       | 45.1%       |
+| test  | 12.4%       | 43.5%       |
+| human_val | 10.6%       | 49.4%       |
 
 `human_val` option will make the model evaluate on the validation set translated by human. 
 
diff --git a/convlab2/__init__.py b/convlab2/__init__.py
index e28e3a1879d84c5ed920912e58b6915dcb13d0e8..87a7442310d0d5bad9dbeae9b1b29041d4490067 100755
--- a/convlab2/__init__.py
+++ b/convlab2/__init__.py
@@ -1,3 +1,5 @@
+import os
+
 from convlab2.nlu import NLU
 from convlab2.dst import DST
 from convlab2.policy import Policy
@@ -11,6 +13,5 @@ from os.path import abspath, dirname
 def get_root_path():
     return dirname(dirname(abspath(__file__)))
 
-import os
 
-DATA_ROOT = os.path.join(get_root_path(), 'data')
\ No newline at end of file
+DATA_ROOT = os.path.join(get_root_path(), 'data')
diff --git a/convlab2/dialog_agent/agent.py b/convlab2/dialog_agent/agent.py
index f2d9ee6875511c3f41f5303178a32e153ea33230..adb9d33ea575b091ff7f94a4a4460dc346e68a34 100755
--- a/convlab2/dialog_agent/agent.py
+++ b/convlab2/dialog_agent/agent.py
@@ -32,7 +32,7 @@ class Agent(ABC):
         pass
 
     @abstractmethod
-    def init_session(self):
+    def init_session(self, **kwargs):
         """Reset the class variables to prepare for a new session."""
         pass
 
@@ -140,7 +140,7 @@ class PipelineAgent(Agent):
             return self.policy.get_reward()
         return None
 
-    def init_session(self):
+    def init_session(self, **kwargs):
         """Init the attributes of DST and Policy module."""
         if self.nlu is not None:
             self.nlu.init_session()
@@ -149,7 +149,7 @@ class PipelineAgent(Agent):
             if self.name == 'sys':
                 self.dst.state['history'].append([self.name, 'null'])
         if self.policy is not None:
-            self.policy.init_session()
+            self.policy.init_session(**kwargs)
         if self.nlg is not None:
             self.nlg.init_session()
         self.history = []
diff --git a/convlab2/dialog_agent/session.py b/convlab2/dialog_agent/session.py
index f96bab6bb42febe24cc770ce9b5c1e698f89be2b..ffe70de297fcf9c8aa11c47ce1e880fe50db5da9 100755
--- a/convlab2/dialog_agent/session.py
+++ b/convlab2/dialog_agent/session.py
@@ -139,11 +139,13 @@ class BiSession(Session):
         """
         self.sys_agent.policy.train()
 
-    def init_session(self):
+    def init_session(self, **kwargs):
         self.sys_agent.init_session()
-        self.user_agent.init_session()
+        self.user_agent.init_session(**kwargs)
         if self.evaluator:
             self.evaluator.add_goal(self.user_agent.policy.get_goal())
+        self.dialog_history = []
+        self.__turn_indicator = 0
 
 
 class DealornotSession(Session):
@@ -198,3 +200,5 @@ class DealornotSession(Session):
         self.__turn_indicator = random.choice([0, 1])
         self.alice.init_session()
         self.bob.init_session()
+        self.current_agent = None
+        self.dialog_history = []
diff --git a/convlab2/dst/evaluate.py b/convlab2/dst/evaluate.py
index 053140f0108205c4148327bdb2fdba9ee9144b36..842dde702c2402470eee14ad2bbe8d672b10127f 100755
--- a/convlab2/dst/evaluate.py
+++ b/convlab2/dst/evaluate.py
@@ -11,17 +11,40 @@ from tqdm import tqdm
 import copy
 import jieba
 
-multiwoz_slot_list = ['attraction-area', 'attraction-name', 'attraction-type', 'hotel-day', 'hotel-people', 'hotel-stay', 'hotel-area', 'hotel-internet', 'hotel-name', 'hotel-parking', 'hotel-pricerange', 'hotel-stars', 'hotel-type', 'restaurant-day', 'restaurant-people', 'restaurant-time', 'restaurant-area', 'restaurant-food', 'restaurant-name', 'restaurant-pricerange', 'taxi-arriveby', 'taxi-departure', 'taxi-destination', 'taxi-leaveat', 'train-people', 'train-arriveby', 'train-day', 'train-departure', 'train-destination', 'train-leaveat']
-crosswoz_slot_list = ["景点-门票", "景点-评分", "餐馆-名称", "酒店-价格", "酒店-评分", "景点-名称", "景点-地址", "景点-游玩时间", "餐馆-营业时间", "餐馆-评分", "酒店-名称", "酒店-周边景点", "酒店-酒店设施-叫醒服务", "酒店-酒店类型", "餐馆-人均消费", "餐馆-推荐菜", "酒店-酒店设施", "酒店-电话", "景点-电话", "餐馆-周边餐馆", "餐馆-电话", "餐馆-none", "餐馆-地址", "酒店-酒店设施-无烟房", "酒店-地址", "景点-周边景点", "景点-周边酒店", "出租-出发地", "出租-目的地", "地铁-出发地", "地铁-目的地", "景点-周边餐馆", "酒店-周边餐馆", "出租-车型", "餐馆-周边景点", "餐馆-周边酒店", "地铁-出发地附近地铁站", "地铁-目的地附近地铁站", "景点-none", "酒店-酒店设施-商务中心", "餐馆-源领域", "酒店-酒店设施-中式餐厅", "酒店-酒店设施-接站服务", "酒店-酒店设施-国际长途电话", "酒店-酒店设施-吹风机", "酒店-酒店设施-会议室", "酒店-源领域", "酒店-none", "酒店-酒店设施-宽带上网", "酒店-酒店设施-看护小孩服务", "酒店-酒店设施-酒店各处提供wifi", "酒店-酒店设施-暖气", "酒店-酒店设施-spa", "出租-车牌", "景点-源领域", "酒店-酒店设施-行李寄存", "酒店-酒店设施-西式餐厅", "酒店-酒店设施-酒吧", "酒店-酒店设施-早餐服务", "酒店-酒店设施-健身房", "酒店-酒店设施-残疾人设施", "酒店-酒店设施-免费市内电话", "酒店-酒店设施-接待外宾", "酒店-酒店设施-部分房间提供wifi", "酒店-酒店设施-洗衣服务", "酒店-酒店设施-租车", "酒店-酒店设施-公共区域和部分房间提供wifi", "酒店-酒店设施-24小时热水", "酒店-酒店设施-温泉", "酒店-酒店设施-桑拿", "酒店-酒店设施-收费停车位", "酒店-周边酒店", "酒店-酒店设施-接机服务", "酒店-酒店设施-所有房间提供wifi", "酒店-酒店设施-棋牌室", "酒店-酒店设施-免费国内长途电话", "酒店-酒店设施-室内游泳池", "酒店-酒店设施-早餐服务免费", "酒店-酒店设施-公共区域提供wifi", "酒店-酒店设施-室外游泳池"]
+multiwoz_slot_list = [
+    'attraction-area', 'attraction-name', 'attraction-type', 'hotel-day', 'hotel-people',
+    'hotel-stay', 'hotel-area', 'hotel-internet', 'hotel-name', 'hotel-parking', 'hotel-pricerange',
+    'hotel-stars', 'hotel-type', 'restaurant-day', 'restaurant-people', 'restaurant-time',
+    'restaurant-area', 'restaurant-food', 'restaurant-name', 'restaurant-pricerange', 'taxi-arriveby',
+    'taxi-departure', 'taxi-destination', 'taxi-leaveat', 'train-people', 'train-arriveby',
+    'train-day', 'train-departure', 'train-destination', 'train-leaveat'
+]
+crosswoz_slot_list = [
+    "景点-门票", "景点-评分", "餐馆-名称", "酒店-价格", "酒店-评分", "景点-名称", "景点-地址", "景点-游玩时间", "餐馆-营业时间", "餐馆-评分",
+    "酒店-名称", "酒店-周边景点", "酒店-酒店设施-叫醒服务", "酒店-酒店类型", "餐馆-人均消费", "餐馆-推荐菜", "酒店-酒店设施", "酒店-电话", "景点-电话",
+    "餐馆-周边餐馆", "餐馆-电话", "餐馆-none", "餐馆-地址", "酒店-酒店设施-无烟房", "酒店-地址", "景点-周边景点", "景点-周边酒店", "出租-出发地",
+    "出租-目的地", "地铁-出发地", "地铁-目的地", "景点-周边餐馆", "酒店-周边餐馆", "出租-车型", "餐馆-周边景点", "餐馆-周边酒店", "地铁-出发地附近地铁站",
+    "地铁-目的地附近地铁站", "景点-none", "酒店-酒店设施-商务中心", "餐馆-源领域", "酒店-酒店设施-中式餐厅", "酒店-酒店设施-接站服务",
+    "酒店-酒店设施-国际长途电话", "酒店-酒店设施-吹风机", "酒店-酒店设施-会议室", "酒店-源领域", "酒店-none", "酒店-酒店设施-宽带上网",
+    "酒店-酒店设施-看护小孩服务", "酒店-酒店设施-酒店各处提供wifi", "酒店-酒店设施-暖气", "酒店-酒店设施-spa", "出租-车牌", "景点-源领域",
+    "酒店-酒店设施-行李寄存", "酒店-酒店设施-西式餐厅", "酒店-酒店设施-酒吧", "酒店-酒店设施-早餐服务", "酒店-酒店设施-健身房", "酒店-酒店设施-残疾人设施",
+    "酒店-酒店设施-免费市内电话", "酒店-酒店设施-接待外宾", "酒店-酒店设施-部分房间提供wifi", "酒店-酒店设施-洗衣服务", "酒店-酒店设施-租车",
+    "酒店-酒店设施-公共区域和部分房间提供wifi", "酒店-酒店设施-24小时热水", "酒店-酒店设施-温泉", "酒店-酒店设施-桑拿", "酒店-酒店设施-收费停车位",
+    "酒店-周边酒店", "酒店-酒店设施-接机服务", "酒店-酒店设施-所有房间提供wifi", "酒店-酒店设施-棋牌室", "酒店-酒店设施-免费国内长途电话",
+    "酒店-酒店设施-室内游泳池", "酒店-酒店设施-早餐服务免费", "酒店-酒店设施-公共区域提供wifi", "酒店-酒店设施-室外游泳池"
+]
+
 from convlab2.dst.sumbt.multiwoz_zh.sumbt import multiwoz_zh_slot_list
 from convlab2.dst.sumbt.crosswoz_en.sumbt import crosswoz_en_slot_list
 
+
 def format_history(context):
     history = []
     for i in range(len(context)):
-        history.append(['sys' if i%2==1 else 'usr', context[i]])
+        history.append(['sys' if i % 2 == 1 else 'usr', context[i]])
     return history
 
+
 def sentseg(sent):
     sent = sent.replace('\t', ' ')
     sent = ' '.join(sent.split())
@@ -215,6 +238,8 @@ if __name__ == '__main__':
             if model_name == 'sumbt':
                 from convlab2.dst.sumbt.crosswoz_en.sumbt import SUMBTTracker
                 model = SUMBTTracker()
+            else:
+                raise Exception("Available models: sumbt")
         else:
             if model_name == 'TRADE':
                 from convlab2.dst.trade.crosswoz.trade import CrossWOZTRADE
@@ -228,7 +253,7 @@ if __name__ == '__main__':
             else:
                 raise Exception("Available models: TRADE")
 
-        ## load data
+        # load data
         from convlab2.util.dataloader.module_dataloader import CrossWOZAgentDSTDataloader
         from convlab2.util.dataloader.dataset_dataloader import CrossWOZDataloader
 
diff --git a/convlab2/dst/sumbt/BeliefTrackerSlotQueryMultiSlot.py b/convlab2/dst/sumbt/BeliefTrackerSlotQueryMultiSlot.py
index bd3dc57052afb186627ccacc73c6fa679dc99b2d..c33ee6891b31fdf02947e5f298b4fce015401560 100755
--- a/convlab2/dst/sumbt/BeliefTrackerSlotQueryMultiSlot.py
+++ b/convlab2/dst/sumbt/BeliefTrackerSlotQueryMultiSlot.py
@@ -150,6 +150,9 @@ class BeliefTracker(nn.Module):
         ### Etc.
         self.dropout = nn.Dropout(self.hidden_dropout_prob)
 
+        # default evaluation mode
+        self.eval()
+
     def initialize_slot_value_lookup(self, label_ids, slot_ids):
 
         self.sv_encoder.eval()
diff --git a/convlab2/dst/sumbt/README.md b/convlab2/dst/sumbt/README.md
index 68f4f5968eff65a400ef9ea26645cd9f7b176534..9d8f6b250afa0fae6d3bb131ba0b473a7cbaec2d 100755
--- a/convlab2/dst/sumbt/README.md
+++ b/convlab2/dst/sumbt/README.md
@@ -36,8 +36,6 @@ We use the multiwoz data.
 
 ## Performance on Multiwoz
 
-`mode` determines the data we use: if mode=`usr`, use user utterances to train; if mode=`sys`, use system utterances to train.
-
 We evaluate the Joint accuracy and Slot accuracy on Multiwoz 2.0 validation and test set. 
 The accuracy on validation set are slightly higher than the results reported in the paper,
 because in the evaluation code all undefined values in ontology are set `none` but predictions 
diff --git a/convlab2/dst/sumbt/multiwoz/sumbt.py b/convlab2/dst/sumbt/multiwoz/sumbt.py
index 9176e54b7f7be2746a3b79e0dce580fbc02bb9d4..d9eb9d3ef0097d15d7b4b8bcdfeee4eb6f5a46ef 100755
--- a/convlab2/dst/sumbt/multiwoz/sumbt.py
+++ b/convlab2/dst/sumbt/multiwoz/sumbt.py
@@ -145,7 +145,7 @@ class SUMBTTracker(DST):
         self.dev_examples = processor.get_dev_examples(os.path.join(SUMBT_PATH, args.tmp_data_dir), accumulation=False)
         self.test_examples = processor.get_test_examples(os.path.join(SUMBT_PATH, args.tmp_data_dir), accumulation=False)
         self.eval_slots = eval_slots
-        # self.download_model()
+        self.download_model()
 
     def download_model(self):
         if not os.path.isdir(DOWNLOAD_DIRECTORY):
diff --git a/convlab2/evaluator/evaluator.py b/convlab2/evaluator/evaluator.py
index 9dfaee0a2f4dbfd5d4413a8f8d4e73e0b43058a5..89a37b35bc77973e8ab381b066b4d7a77d4615f4 100755
--- a/convlab2/evaluator/evaluator.py
+++ b/convlab2/evaluator/evaluator.py
@@ -51,3 +51,7 @@ class Evaluator(object):
         judge if the domain (subtask) is successfully completed
         """
         raise NotImplementedError
+
+    def final_goal_analyze(self):
+        """judge whether the final goal satisfies the database constraints"""
+        raise NotImplementedError
diff --git a/convlab2/evaluator/multiwoz_eval.py b/convlab2/evaluator/multiwoz_eval.py
index 877f6e0f18354334eb50f3d242d92233990cd70c..e7303c56d204eed52bf9deb3d55a5a258f9a1ff1 100755
--- a/convlab2/evaluator/multiwoz_eval.py
+++ b/convlab2/evaluator/multiwoz_eval.py
@@ -30,9 +30,10 @@ mapping = {'restaurant': {'addr': 'address', 'area': 'area', 'food': 'food', 'na
            'hospital': {'post': 'postcode', 'phone': 'phone', 'addr': 'address', 'department': 'department'},
            'police': {'post': 'postcode', 'phone': 'phone', 'addr': 'address'}}
 
-time_re = re.compile(r'^(([01]\d|2[0-3]):([0-5]\d)|24:00)$')
+time_re = re.compile(r'^(([01]\d|2[0-4]):([0-5]\d)|24:00)$')
 NUL_VALUE = ["", "dont care", 'not mentioned', "don't care", "dontcare", "do n't care"]
 
+
 class MultiWozEvaluator(Evaluator):
     def __init__(self):
         self.sys_da_array = []
@@ -40,7 +41,8 @@ class MultiWozEvaluator(Evaluator):
         self.goal = {}
         self.cur_domain = ''
         self.booked = {}
-        self.dbs = Database().dbs
+        self.database = Database()
+        self.dbs = self.database.dbs
 
     def _init_dict(self):
         dic = {}
@@ -100,10 +102,12 @@ class MultiWozEvaluator(Evaluator):
             if da == 'booking-book-ref' and self.cur_domain in ['hotel', 'restaurant', 'train']:
                 if not self.booked[self.cur_domain] and re.match(r'^\d{8}$', value) and \
                         len(self.dbs[self.cur_domain]) > int(value):
-                    self.booked[self.cur_domain] = self.dbs[self.cur_domain][int(value)]
+                    self.booked[self.cur_domain] = self.dbs[self.cur_domain][int(value)].copy()
+                    self.booked[self.cur_domain]['Ref'] = value
             elif da == 'train-offerbooked-ref' or da == 'train-inform-ref':
                 if not self.booked['train'] and re.match(r'^\d{8}$', value) and len(self.dbs['train']) > int(value):
-                    self.booked['train'] = self.dbs['train'][int(value)]
+                    self.booked['train'] = self.dbs['train'][int(value)].copy()
+                    self.booked['train']['Ref'] = value
             elif da == 'taxi-inform-car':
                 if not self.booked['taxi']:
                     self.booked['taxi'] = 'booked'
@@ -181,7 +185,7 @@ class MultiWozEvaluator(Evaluator):
         for domain in domains:
             inform_slot[domain] = set()
         TP, FP, FN = 0, 0, 0
-        
+
         inform_not_reqt = set()
         reqt_not_inform = set()
         bad_inform = set()
@@ -197,7 +201,7 @@ class MultiWozEvaluator(Evaluator):
                 else:
                     bad_inform.add((intent, domain, key))
                     FP += 1
-        
+
         for domain in domains:
             for k in goal[domain]['reqt']:
                 if k in inform_slot[domain]:
@@ -224,11 +228,11 @@ class MultiWozEvaluator(Evaluator):
             return time_re.match(value)
         elif key == "day":
             return value.lower() in ["monday", "tuesday", "wednesday", "thursday", "friday",
-                              "saturday", "sunday"]
+                                     "saturday", "sunday"]
         elif key == "duration":
             return 'minute' in value
         elif key == "internet" or key == "parking":
-            return value in ["yes", "no"]
+            return value in ["yes", "no", "none"]
         elif key == "phone":
             return re.match(r'^\d{11}$', value) or domain == "restaurant"
         elif key == "price":
@@ -294,10 +298,12 @@ class MultiWozEvaluator(Evaluator):
         """
         book_sess = self.book_rate(ref2goal)
         inform_sess = self.inform_F1(ref2goal)
+        goal_sess = self.final_goal_analyze()
         # book rate == 1 & inform recall == 1
-        if (book_sess == 1 and inform_sess[1] == 1) \
-                or (book_sess == 1 and inform_sess[1] is None) \
-                or (book_sess is None and inform_sess[1] == 1):
+        if ((book_sess == 1 and inform_sess[1] == 1) \
+            or (book_sess == 1 and inform_sess[1] is None) \
+            or (book_sess is None and inform_sess[1] == 1)) \
+                and goal_sess == 1:
             return 1
         else:
             return 0
@@ -325,7 +331,6 @@ class MultiWozEvaluator(Evaluator):
 
         inform = self._inform_F1_goal(goal, self.sys_da_array, [domain])
         return inform
-        
 
     def domain_success(self, domain, ref2goal=True):
         """
@@ -366,3 +371,45 @@ class MultiWozEvaluator(Evaluator):
             return 1
         else:
             return 0
+
+    def _final_goal_analyze(self):
+        """whether the final goal satisfies constraints"""
+        match = mismatch = 0
+        for domain, dom_goal_dict in self.goal.items():
+            constraints = []
+            if 'reqt' in dom_goal_dict:
+                reqt_constraints = list(dom_goal_dict['reqt'].items())
+                constraints += reqt_constraints
+            else:
+                reqt_constraints = []
+            if 'info' in dom_goal_dict:
+                info_constraints = list(dom_goal_dict['info'].items())
+                constraints += info_constraints
+            else:
+                info_constraints = []
+            query_result = self.database.query(domain, info_constraints, soft_contraints=reqt_constraints)
+            if not query_result:
+                mismatch += 1
+                continue
+
+            booked = self.booked[domain]
+            if not self.goal[domain].get('book'):
+                match += 1
+            elif isinstance(booked, dict):
+                ref = booked['Ref']
+                if any(found['Ref'] == ref for found in query_result):
+                    match += 1
+                else:
+                    mismatch += 1
+            else:
+                match += 1
+        return match, mismatch
+
+    def final_goal_analyze(self):
+        """percentage of domains, in which the final goal satisfies the database constraints.
+        If there is no dialog action, returns 1."""
+        match, mismatch = self._final_goal_analyze()
+        if match == mismatch == 0:
+            return 1
+        else:
+            return match / (match + mismatch)
diff --git a/convlab2/nlg/template/multiwoz/manual_user_template_nlg.json b/convlab2/nlg/template/multiwoz/manual_user_template_nlg.json
index 27e02ada323918dc1c1f69f9d3c629700d91f4fa..7f56b3cacbf307dae59e2d65aaea32cc7754836e 100755
--- a/convlab2/nlg/template/multiwoz/manual_user_template_nlg.json
+++ b/convlab2/nlg/template/multiwoz/manual_user_template_nlg.json
@@ -5,7 +5,7 @@
             "Hi , I am planning a trip and need some help with a particular attraction .",
             "Yeah , I ' m looking for an entertaining tourist attraction , can point me in the direction of some places to check out ?",
             "Something fun . It needs to be an attraction . Can you make a suggestion ?",
-            "I ca n't wait to get there and see some of the local attractions . I am looking for a place to stay . Can you help me ?",
+            "I ca n't wait to get there and see some of the local attractions . Can you help me ?",
             "I am looking for tourist attractions .",
             "I am looking for a particular attraction .",
             "Can you help me plan a trip to see a particular attraction ?",
@@ -16,8 +16,7 @@
             "I would like to visit on in town #ATTRACTION-INFORM-AREA# please .",
             "Are there anything fun to do in city #ATTRACTION-INFORM-AREA# ?",
             "I ' m looking for some attractions in the #ATTRACTION-INFORM-AREA# .",
-            "I am also looking for suggestions on places to go in the #ATTRACTION-INFORM-AREA# of town . Can you help me with that ?",
-            "I 'd like a sports place in the #ATTRACTION-INFORM-AREA# please .",
+            "I am also looking for suggestions on places to go in the #ATTRACTION-INFORM-AREA# . Can you help me with that ?",
             "I am also looking for places to go in town . Maybe something in the #ATTRACTION-INFORM-AREA# .",
             "I also need a place to go in the #ATTRACTION-INFORM-AREA# .",
             "Can you recommend some fun entertainment in the #ATTRACTION-INFORM-AREA# ?"
@@ -53,7 +52,7 @@
             "Can I get the address ?",
             "Just the address please",
             "That sounds great ! May I have the address ?",
-            "Is there an exact address , like a street number ? Thanks !",
+            "Is there an exact address , like a street number ?",
             "What is the address ?",
             "Can I get the address please ?",
             "Can I get the precise address please ?"
@@ -61,23 +60,23 @@
         "Post": [
             "Oh , and what is their postcode , please ?",
             "what is their postcode ?",
-            "Can I please have the postcode ?",
-            "Thank you very much . Can you give me the postcode ?",
+            "Can I please have the postcode of the attraction ?",
+            "Can you give me the postcode of the attraction ?",
             "Can you tell me their postcode ?",
             "Yes , that will work great . Can I get their postcode please ?",
             "What is the postcode for this place ?",
             "Can you let me have their postcode ?",
-            "I 'll need the postcode ."
+            "I 'll need the postcode of the attraction ."
         ],
         "Phone": [
             "can I get the phone number of one ?",
             "Yes can I get the phone number of one you 'd recommend ?",
             "Can you give me their phone number please ?",
-            "What is the phone number ?",
-            "I need the phone number as well .",
+            "What is the phone number of the attraction ?",
+            "I need the phone number of the attraction as well .",
             "Please get me their phone number",
-            "Sounds good . Could I get the phone number ?",
-            "Can you give me the phone number ?",
+            "Sounds good . Could I get the phone number of the attraction ?",
+            "Can you give me the phone number of the attraction ?",
             "I 'd like their phone number if you have it available , please ."
         ],
         "Fee": [
@@ -93,7 +92,7 @@
         ],
         "Area": [
             "Can you tell me what area it is located in ?",
-            "Thank you . What 's the area ?",
+            "What 's the area ?",
             "What area is it located ?",
             "What area of town is that in ?",
             "Just need to know what area it 's in .",
@@ -105,7 +104,7 @@
             "yes I 'll need the attraction type please .",
             "What type of attraction is this ?",
             "Can you tell me what type of attraction that is considered ?",
-            "Thank you . What type of attraction is this ?",
+            "What type of attraction is this ?",
             "What type of attraction is that college ?"
         ]
     },
@@ -137,10 +136,10 @@
     },
     "Hospital-Request": {
         "Phone": [
-            "I just need the general phone number , please .",
-            "Can you provide the phone number for me ?",
-            "No but I need the phone number",
-            "What is the phone number ?",
+            "I just need the phone number of the hospital , please .",
+            "Can you provide the phone number of the hospital for me ?",
+            "No but I need the phone number of the hospital ",
+            "What is the phone number of the hospital ?",
             "Could you send their phone number please ?",
             "May I also have the phone number please ?",
             "I am looking for the Hospital , can you please give me their phone number ?",
@@ -150,25 +149,25 @@
         "Post": [
             "Can I get the postcode as well ?",
             "but do you have the postal code by any chance ?",
-            "Thanks , can I also get the postcode ?",
+            "Can I also get the postcode of the hospital ?",
             "I just need the postcode , please .",
-            "Thank you . Can I have the postcode ?",
+            "Can I have the postcode of the hospital ?",
             "What is the postcode ?",
-            "I need the postcode , thanks .",
+            "I need the postcode of the hospital .",
             "Could you also give me the postcode ?",
             "can you also give me their postcode ?"
         ],
         "Addr": [
-            "Can I also get the address ? Thanks !",
+            "Can I also get the address ?",
             "Does the address not have a street number ?",
             "Can I get the address please ?",
             "What is the address so I can find the hospital ?",
             "What is their address ?",
-            "Thanks . Can I get an address as well ?",
+            "Can I get an address as well ?",
             "Can I please have the full address of the hospital ?",
             "may I please have the address ?",
             "What is the exact address ?",
-            "Thank you . Could you please get me the address for the hospital ?"
+            "Could you please get me the address for the hospital ?"
         ]
     },
     "Hotel-Inform": {
@@ -177,8 +176,8 @@
             "I do n't want to have to pay for parking .",
             "It must have free parking .",
             "Hello , I ' m looking for a place to stay that offers free parking .",
-            "Hello , I would like to find a hotel that includes free parking .",
-            "I ' m looking for a place to stay . I need a hotel that includes free parking",
+            "Hello , I would like to find a place to stay that includes free parking .",
+            "I ' m looking for a place to stay that includes free parking",
             "I 'd like to book one that offers parking please ."
         ],
         "Stay": [
@@ -202,9 +201,9 @@
         ],
         "Price": [
             "I would like to keep it in the #HOTEL-INFORM-PRICE# range , please .",
-            "Could you also find me a hotel with a #HOTEL-INFORM-PRICE# price ?",
+            "Could you also find me a place to stay with a #HOTEL-INFORM-PRICE# price ?",
             "I would prefer something that is in the #HOTEL-INFORM-PRICE# price range .",
-            "How about a hotel in the #HOTEL-INFORM-PRICE# price range ?",
+            "How about in the #HOTEL-INFORM-PRICE# price range ?",
             "it needs to be in the #HOTEL-INFORM-PRICE# price range .",
             "I ' m looking for some #HOTEL-INFORM-PRICE# priced accommodations for my visit . Can you help me with that ?",
             "I would like to keep the price #HOTEL-INFORM-PRICE# .",
@@ -222,24 +221,18 @@
         ],
         "Area": [
             "I need a place to stay in the #HOTEL-INFORM-AREA# please .",
-            "I would prefer the hotel be in the #HOTEL-INFORM-AREA# part of town .",
+            "I would prefer the hotel be in the #HOTEL-INFORM-AREA# .",
             "I ' m also looking for a place to stay . In the #HOTEL-INFORM-AREA# preferably .",
-            "Would you be able to help me find a place to stay in the #HOTEL-INFORM-AREA# side of town ?",
-            "I ' m looking for a place to stay in the #HOTEL-INFORM-AREA# part of town .",
-            "I ' m looking for a hotel in the #HOTEL-INFORM-AREA# .",
+            "Would you be able to help me find a place to stay in the #HOTEL-INFORM-AREA# ?",
+            "I ' m looking for a place to stay in the #HOTEL-INFORM-AREA# .",
             "I need it in the #HOTEL-INFORM-AREA# , please ."
         ],
         "People": [
-            "I need reservations for #HOTEL-INFORM-PEOPLE# .",
-            "Yes , could you book the hotel room for me for #HOTEL-INFORM-PEOPLE# people ?",
-            "There are #HOTEL-INFORM-PEOPLE# of us .",
+            "Yes , could you book the reservation for me for #HOTEL-INFORM-PEOPLE# people ?",
             "That will work . Can you make a reservation for #HOTEL-INFORM-PEOPLE# people , please ?",
-            "There is going to be #HOTEL-INFORM-PEOPLE# of us",
             "Actually , I 'd like to book it for #HOTEL-INFORM-PEOPLE# people . Can you help with that ?",
             "There will be #HOTEL-INFORM-PEOPLE# people .",
-            "There will be #HOTEL-INFORM-PEOPLE# of us .",
-            "Yes , could you book the hotel room for me for #HOTEL-INFORM-PEOPLE# people ?",
-            "I would like to book it for #HOTEL-INFORM-PEOPLE# people . Thanks ."
+            "I would like to book it for #HOTEL-INFORM-PEOPLE# people ."
         ],
         "Stars": [
             "I would like it to be a #HOTEL-INFORM-STARS# star hotel .",
@@ -262,7 +255,7 @@
             "I ' m looking for information on a hotel called #HOTEL-INFORM-NAME# .",
             "Can you also help me find a hotel called the #HOTEL-INFORM-NAME# ?",
             "I am looking for a hotel by the name of #HOTEL-INFORM-NAME# .",
-            "Thank you and I am also looking for the #HOTEL-INFORM-NAME# ."
+            "I am also looking for the #HOTEL-INFORM-NAME# ."
         ],
         "none": [
             "I need a hotel as well .",
@@ -284,7 +277,7 @@
             "could I get their address ?",
             "Could you give me the address , please ?",
             "may I have the address for that hotel ?",
-            "I do n't need it booked but what s the address ?"
+            "what s the address ?"
         ],
         "Ref": [
             "Please book it and provide the reference number .",
@@ -294,29 +287,29 @@
             "can I get the reference number once you make that reservation ?",
             "That 's great . Can you book the room and give me the reference number ?",
             "I 'd like the reference number as well .",
-            "Thank you . I will also need the booking reference number .",
+            "I will also need the booking reference number .",
             "Okay , just let me get a reference number when you book it .",
             "I need the reference number too ."
         ],
         "Post": [
-            "Can I get the postcode for both of them ?",
-            "That sounds fine , I just need the postcode though .",
+            "Can I get the postcode ?",
+            "That sounds fine , I just need the postcode of the hotel though .",
             "Can I please have the post code ?",
             "I just need the postcode .",
-            "What is the postcode ?",
+            "What is the postcode of the hotel ?",
             "Actually , can you give me the postcode for that ?",
             "could you provide me with their postcode ?",
-            "And I need a postcode .",
+            "And I need a postcode of the hotel .",
             "I would like to get the postcode , please .",
             "Can I get their postcode please ?"
         ],
         "Phone": [
             "Do you have their phone numbers ?",
-            "i need the phone number",
-            "Could I get the phone number ?",
-            "What 's the phone number ?",
+            "i need the phone number of the hotel ",
+            "Could I get the phone number of the hotel ?",
+            "What 's the phone number of the hotel ?",
             "can you get me their phone number ?",
-            "Can you give me the phone number , please ?",
+            "Can you give me the phone number of the hotel , please ?",
             "Just get me their phone number .",
             "What is their phone number ?"
         ],
@@ -351,7 +344,6 @@
             "What 's the area at first ?"
         ],
         "Type": [
-            "Thanks , what type of hotel is it ?",
             "what type of hotel is it ?",
             "what type of hotels are they ?",
             "What type of hotel is it ?",
@@ -377,7 +369,7 @@
             "How many stars is it ?",
             "how many stars ?",
             "How many stars does the hotel have ?",
-            "Thanks , how many stars is it rated ?"
+            "how many stars is it rated ?"
         ]
     },
     "Police-Inform": {
@@ -393,22 +385,22 @@
     },
     "Police-Request": {
         "Post": [
-            "Can I please have the postcode as well ?",
+            "Can I please have the postcode of the police station as well ?",
             "I will also need the postcode please .",
             "Can I get the postcode ?",
             "what is its postcode ?",
             "What is the postcode for that station ?",
             "may I also please have the postcode ?",
             "Can you help me with locating the postcode ?",
-            "the postcode please",
-            "What is the postcode ?"
+            "the postcode of the police station please",
+            "What is the postcode of the police station ?"
         ],
         "Addr": [
             "Was Parkside the address of the police station ? If not , can I have the address please ?",
             "Also , can you give me the exact address to the station ?",
             "Could I also get the address of the police station ?",
             "Can you give me their address , please ?",
-            "Yes and the address , as well . Thanks .",
+            "Yes and the address , as well .",
             "What is the address ?",
             "Can you give me the exact address for the police ?",
             "Yes , I will need their address also please .",
@@ -416,14 +408,14 @@
             "Do you have their address ?"
         ],
         "Phone": [
-            "Do you have the phone number there ?",
+            "Do you have the phone number of the police station there ?",
             "What is the police phone number , please ?",
             "Can you give me the phone number please ?",
-            "May I get the phone number ?",
-            "Thank you , what is their phone number ?",
+            "May I get the phone number of the police station ?",
+            "What is their phone number ?",
             "Yes , I 'll also need their phone number .",
             "Could you tell me where to find the nearest police station and give the telephone number ?",
-            "I only needed the phone number . Thank you !",
+            "I only needed the phone number of the police station .",
             "I do n't know I am new to this area , please just give me the phone number to the police station .",
             "I need to call them actually right now - do you have their phone number ?"
         ]
@@ -442,14 +434,14 @@
             "I ' m looking for a restaurant named #RESTAURANT-INFORM-NAME# ."
         ],
         "Area": [
-            "I ' m so hungry - can you find me a place to eat in the city #RESTAURANT-INFORM-AREA# ?",
+            "I ' m so hungry - can you find me a place to eat in the #RESTAURANT-INFORM-AREA# ?",
             "Can you help me find a restaurant ? I want to find a place in the #RESTAURANT-INFORM-AREA# .",
-            "I would prefer it in the #RESTAURANT-INFORM-AREA# area .",
-            "I am also in the market for a new restaurant . Is there something in the #RESTAURANT-INFORM-AREA# of town ?",
+            "I would prefer it in the #RESTAURANT-INFORM-AREA# .",
+            "I am also in the market for a new restaurant . Is there something in the #RESTAURANT-INFORM-AREA# ?",
             "Is that located in the #RESTAURANT-INFORM-AREA# ?",
             "I 'd like to be in the #RESTAURANT-INFORM-AREA# please .",
             "What restaurants are located in the #RESTAURANT-INFORM-AREA# ?",
-            "I also would like information on a place to eat in the #RESTAURANT-INFORM-AREA# of town ."
+            "I also would like information on a place to eat in the #RESTAURANT-INFORM-AREA# ."
         ],
         "Price": [
             "it just needs to be #RESTAURANT-INFORM-PRICE# .",
@@ -457,18 +449,18 @@
             "I want to find a #RESTAURANT-INFORM-PRICE# priced restaurant .",
             "I ' m looking for an #RESTAURANT-INFORM-PRICE# restaurant .",
             "I am looking for a #RESTAURANT-INFORM-PRICE# restaurant .",
-            "Actually I need a #RESTAURANT-INFORM-PRICE#ly priced restaurant . Are there any fitting that description ?",
+            "Actually I need a #RESTAURANT-INFORM-PRICE# priced restaurant . Are there any fitting that description ?",
             "Oh , I really need something #RESTAURANT-INFORM-PRICE# .",
             "I also need a place to dine that is #RESTAURANT-INFORM-PRICE# priced ."
         ],
         "Food": [
-            "How about #RESTAURANT-INFORM-FOOD# .",
+            "How about #RESTAURANT-INFORM-FOOD# food .",
             "are there any #RESTAURANT-INFORM-FOOD# restaurants ?",
-            "Hmm , I 'll try #RESTAURANT-INFORM-FOOD# .",
+            "Hmm , I 'll try #RESTAURANT-INFORM-FOOD# food .",
             "I 'd like to find a #RESTAURANT-INFORM-FOOD# restaurant , if possible .",
             "Do you have #RESTAURANT-INFORM-FOOD# food ?",
             "Yes . This restaurant should serve #RESTAURANT-INFORM-FOOD# food too .",
-            "I ' m visiting Cambridge and would like some suggestions for an restaurant which serves #RESTAURANT-INFORM-FOOD# .",
+            "I ' m visiting Cambridge and would like some suggestions for an restaurant which serves #RESTAURANT-INFORM-FOOD# food .",
             "how about a #RESTAURANT-INFORM-FOOD# restaurant ?",
             "I would prefer #RESTAURANT-INFORM-FOOD# food please ."
         ],
@@ -495,16 +487,14 @@
             "I need a reservation for #RESTAURANT-INFORM-PEOPLE# people .",
             "I need a table for #RESTAURANT-INFORM-PEOPLE# people .",
             "We will have #RESTAURANT-INFORM-PEOPLE# people in the party .",
-            "Book a table for #RESTAURANT-INFORM-PEOPLE# person please .",
-            "Can you book me a table for #RESTAURANT-INFORM-PEOPLE# ?",
-            "It will be for #RESTAURANT-INFORM-PEOPLE# people .",
-            "There will be #RESTAURANT-INFORM-PEOPLE# of us ."
+            "Book a table for #RESTAURANT-INFORM-PEOPLE# people please .",
+            "Can you book me a table for #RESTAURANT-INFORM-PEOPLE# people?",
+            "It will be for #RESTAURANT-INFORM-PEOPLE# people ."
         ],
         "Day": [
             "i am also looking for a restaurant to book for #RESTAURANT-INFORM-DAY#",
             "I 'll be needing a table for #RESTAURANT-INFORM-DAY# .",
             "book a table on #RESTAURANT-INFORM-DAY# .",
-            "We will be there #RESTAURANT-INFORM-DAY# night .",
             "Please make a reservation for #RESTAURANT-INFORM-DAY# .",
             "I do need a booking for #RESTAURANT-INFORM-DAY# .",
             "Please reserve a table on #RESTAURANT-INFORM-DAY# .",
@@ -513,7 +503,7 @@
     },
     "Restaurant-Request": {
         "Addr": [
-            "Thank you . May I have the address ?",
+            "May I have the address ?",
             "may I have the address ?",
             "please give me their address .",
             "What is the address ?",
@@ -524,24 +514,24 @@
         ],
         "Post": [
             "I just need the post code .",
-            "I will need the postcode though .",
+            "I will need the postcode of the restaurant though .",
             "Can I get the postcode for it please ?",
-            "What is the postal code ?",
-            "No thank you I just need the postcode .",
+            "What is the postal code of the restaurant ?",
+            "I just need the postcode .",
             "What is their postcode ?",
             "can I get the postcode for the restaurant ?",
             "Can I get the postcode ?",
-            "I would like to know the postcode , if possible ?",
+            "I would like to know the postcode of the restaurant , if possible ?",
             "can I have their postcode , please ?"
         ],
         "Phone": [
             "May I have their telephone number please ?",
             "I would like their phone number .",
-            "Please provide the phone number .",
-            "Please provide their phone number , thank you .",
-            "That place sounds great . Can I get the phone number please ?",
-            "What is the phone number ?",
-            "Can I just get the phone number ?"
+            "Please provide the phone number of the restaurant .",
+            "Please provide their phone number .",
+            "That place sounds great . Can I get the phone number of the restaurant please ?",
+            "What is the phone number of the restaurant ?",
+            "Can I just get the phone number of the restaurant ?"
         ],
         "Price": [
             "What is the price range ?",
@@ -589,7 +579,7 @@
     "Taxi-Inform": {
         "Leave": [
             "I want to leave after #TAXI-INFORM-LEAVE# .",
-            "thanks . i want to leave by #TAXI-INFORM-LEAVE# .",
+            "I want to leave by #TAXI-INFORM-LEAVE# .",
             "Okay I also need a taxi that will leave by #TAXI-INFORM-LEAVE# .",
             "#TAXI-INFORM-LEAVE# , please .",
             "still need a cab by my booked time , #TAXI-INFORM-LEAVE# please",
@@ -599,13 +589,13 @@
         "none": [
             "I 'll need a ride there . Can you arrange a taxi for me ?",
             "Now I need a taxi .",
-            "Alright book a taxi for me as well . I 'll need to get to the two places and I ' m not familiar with the town . Thanks .",
+            "Alright book a taxi for me as well . I 'll need to get to the two places and I ' m not familiar with the town .",
             "I also want to book a taxi to commute between the two places .",
             "Yes please . I need a taxi to commute .",
             "Yes I would also like a taxi to commute between the two places .",
             "i 'll need a taxi",
             "Can you schedule me a taxi to take me there ?",
-            "Thank you .        Would you also give me the contact number for the taxi ?",
+            "Would you also give me the contact number for the taxi ?",
             "One more thing , I would like to book a taxi to commute between the two places ."
         ],
         "Arrive": [
@@ -620,7 +610,7 @@
         ],
         "Dest": [
             "I need a taxi to take me in time for my reservation to #TAXI-INFORM-DEST# today",
-            "I want to visit the #TAXI-INFORM-DEST# and need a taxi to take me",
+            "I want to visit #TAXI-INFORM-DEST# and need a taxi to take me",
             "I 'll be heading to #TAXI-INFORM-DEST# .",
             "Hi , i need to book a taxi to go to #TAXI-INFORM-DEST# .",
             "I need a tax to #TAXI-INFORM-DEST# .",
@@ -654,12 +644,12 @@
             "Can you give me the car type ?"
         ],
         "Phone": [
-            "Can I get the phone number ?",
-            "Could you please send me the phone number .",
+            "Can I get the phone number of the taxi ?",
+            "Could you please send me the phone number of the taxi ?",
             "Do you have their phone number ?",
             "Can I get the phone also please ?",
             "Can you get me the contact phone number please ?",
-            "please provide the phone number ."
+            "please provide the phone number of the taxi ."
         ]
     },
     "Train-Inform": {
@@ -675,10 +665,9 @@
         ],
         "Depart": [
             "I am departing from #TRAIN-INFORM-DEPART# .",
-            "Is it going to #TRAIN-INFORM-DEPART# ?",
             "I need it to depart from #TRAIN-INFORM-DEPART# .",
             "I will departing from #TRAIN-INFORM-DEPART# .",
-            "Thanks ! I also need a train departing from #TRAIN-INFORM-DEPART# .",
+            "I also need a train departing from #TRAIN-INFORM-DEPART# .",
             "I would like to depart from #TRAIN-INFORM-DEPART# .",
             "I ' m also looking for a train from #TRAIN-INFORM-DEPART# .",
             "Great I also need a train departs from #TRAIN-INFORM-DEPART# .",
@@ -728,7 +717,7 @@
             "Yes I would like to go to #TRAIN-INFORM-DEST# please .",
             "I need to book a train to #TRAIN-INFORM-DEST# .",
             "I need some information on a train going to #TRAIN-INFORM-DEST# .",
-            "Ok , great thanks . Can you also help me find a train going to #TRAIN-INFORM-DEST# ?"
+            "Can you also help me find a train going to #TRAIN-INFORM-DEST# ?"
         ],
         "Leave": [
             "Leaving anytime after #TRAIN-INFORM-LEAVE# please .",
diff --git a/convlab2/nlg/template/multiwoz/nlg.py b/convlab2/nlg/template/multiwoz/nlg.py
index dc164f621b085c560519eccdea6c52d3e337763a..1329275cebd7c28a51f59b405cff281c5b1f1eeb 100755
--- a/convlab2/nlg/template/multiwoz/nlg.py
+++ b/convlab2/nlg/template/multiwoz/nlg.py
@@ -6,13 +6,21 @@ import collections
 from convlab2.nlg import NLG
 
 
+def lower_keys(x):
+    if isinstance(x, list):
+        return [lower_keys(v) for v in x]
+    elif isinstance(x, dict):
+        return {k.lower(): lower_keys(v) for k, v in x.items()}
+    else:
+        return x
+
 def read_json(filename):
     with open(filename, 'r') as f:
-        return json.load(f)
+        return lower_keys(json.load(f))
 
 
 # supported slot
-slot2word = {
+Slot2word = {
     'Fee': 'fee',
     'Addr': 'address',
     'Area': 'area',
@@ -43,6 +51,7 @@ slot2word = {
     # 'TrainID': 'TrainID'
 }
 
+slot2word = dict((k.lower(), v.lower()) for k,v in Slot2word.items())
 
 class TemplateNLG(NLG):
     def __init__(self, is_user, mode="manual"):
@@ -105,9 +114,9 @@ class TemplateNLG(NLG):
         dialog_acts = self.sorted_dialog_act(dialog_acts)
         action = collections.OrderedDict()
         for intent, domain, slot, value in dialog_acts:
-            k = '-'.join([domain, intent])
+            k = '-'.join([domain.lower(), intent.lower()])
             action.setdefault(k, [])
-            action[k].append([slot, value])
+            action[k].append([slot.lower(), value])
         dialog_acts = action
         mode = self.mode
         try:
@@ -160,7 +169,7 @@ class TemplateNLG(NLG):
         sentences = ''
         for dialog_act, slot_value_pairs in dialog_acts.items():
             intent = dialog_act.split('-')
-            if 'Select' == intent[1]:
+            if 'select' == intent[1]:
                 slot2values = {}
                 for slot, value in slot_value_pairs:
                     slot2values.setdefault(slot, [])
@@ -176,7 +185,7 @@ class TemplateNLG(NLG):
                             sentence += ' , ' + value
                     sentence += ' {} ? '.format(slot2word[slot])
                     sentences += sentence
-            elif 'Request' == intent[1]:
+            elif 'request' == intent[1]:
                 for slot, value in slot_value_pairs:
                     if dialog_act not in template or slot not in template[dialog_act]:
                         sentence = 'What is the {} of {} ? '.format(slot.lower(), dialog_act.split('-')[0].lower())
@@ -191,19 +200,32 @@ class TemplateNLG(NLG):
                 sentences += sentence
             else:
                 for slot, value in slot_value_pairs:
+                    value_lower = value.lower()
                     if value in ["do nt care", "do n't care", "dontcare"]:
-                        sentence = 'I don\'t care about the {} of the {}'.format(slot.lower(), dialog_act.split('-')[0].lower())
-                    elif self.is_user and dialog_act.split('-')[1] == 'Inform' and slot == 'Choice' and value == 'any':
+                        sentence = 'I don\'t care about the {} of the {}'.format(slot, dialog_act.split('-')[0])
+                    elif self.is_user and dialog_act.split('-')[1] == 'inform' and slot == 'choice' and value_lower == 'any':
                         # user have no preference, any choice is ok
                         sentence = random.choice([
                             "Please pick one for me. ",
                             "Anyone would be ok. ",
                             "Just select one for me. "
                         ])
+                    elif slot == 'price' and 'same price range' in value_lower:
+                        sentence = random.choice([
+                            "it just needs to be {} .".format(value),
+                            "Oh , I really need something {} .".format(value),
+                            "I would prefer something that is {} .".format(value),
+                            "it needs to be {} .".format(value)
+                        ])
+                    elif slot in ['internet', 'parking'] and value_lower == 'no':
+                        sentence = random.choice([
+                            "It does n't need to have {} .".format(slot),
+                            "I do n't need free {} .".format(slot),
+                        ])
                     elif dialog_act in template and slot in template[dialog_act]:
                         sentence = random.choice(template[dialog_act][slot])
                         sentence = sentence.replace('#{}-{}#'.format(dialog_act.upper(), slot.upper()), str(value))
-                    elif slot == 'NotBook':
+                    elif slot == 'notbook':
                         sentence = random.choice([
                             "I do not need to book. ",
                             "I 'm not looking to make a booking at the moment."
@@ -225,7 +247,7 @@ class TemplateNLG(NLG):
                 key += s + ';'
             if dialog_act in template and key in template[dialog_act]:
                 sentence = random.choice(template[dialog_act][key])
-                if 'Request' in dialog_act or 'general' in dialog_act:
+                if 'request' in dialog_act or 'general' in dialog_act:
                     sentence = self._postprocess(sentence)
                     sentences += sentence
                 else:
@@ -241,7 +263,8 @@ class TemplateNLG(NLG):
 
 def example():
     # dialog act
-    dialog_acts = [['Inform', 'Hotel', 'Area', 'east'],['Inform', 'Hotel', 'Name', 'fds'], ['welcome', 'general', 'none', 'none']]
+    dialog_acts = [['Inform', 'Hotel', 'Area', 'east'],['Inform', 'Hotel', 'Internet', 'no'], ['welcome', 'general', 'none', 'none']]
+    #dialog_acts = [['Inform', 'Restaurant', 'NotBook', 'none']]
     print(dialog_acts)
 
     # system model for manual, auto, auto_manual
diff --git a/convlab2/policy/evaluate.py b/convlab2/policy/evaluate.py
index 87c7b02bc783e139703c5259cceeed244fd1bb0c..8085bf40d140bca2dcaf6af9a15b49ebdcee21ff 100755
--- a/convlab2/policy/evaluate.py
+++ b/convlab2/policy/evaluate.py
@@ -213,6 +213,7 @@ def evaluate(dataset_name, model_name, load_path, calculate_reward=True):
                     logging.info(f'task success: {task_succ}')
                     logging.info(f'book rate: {sess.evaluator.book_rate()}')
                     logging.info(f'inform precision/recall/f1: {sess.evaluator.inform_F1()}')
+                    logging.info(f"percentage of domains that satisfies the database constraints: {sess.evaluator.final_goal_analyze()}")
                     logging.info('-'*50)
                     break
             else: 
diff --git a/convlab2/policy/rule/multiwoz/policy_agenda_multiwoz.py b/convlab2/policy/rule/multiwoz/policy_agenda_multiwoz.py
index 74e8ca177edcae73821a6fee376fa0e57f535df0..3e717ffe733992869187580274166e0cd71e56ae 100755
--- a/convlab2/policy/rule/multiwoz/policy_agenda_multiwoz.py
+++ b/convlab2/policy/rule/multiwoz/policy_agenda_multiwoz.py
@@ -67,10 +67,13 @@ class UserPolicyAgendaMultiWoz(Policy):
     def reset_turn(self):
         self.__turn = 0
 
-    def init_session(self):
+    def init_session(self, ini_goal=None):
         """ Build new Goal and Agenda for next session """
         self.reset_turn()
-        self.goal = Goal(self.goal_generator)
+        if not ini_goal:
+            self.goal = Goal(self.goal_generator)
+        else:
+            self.goal = ini_goal
         self.domain_goals = self.goal.domain_goals
         self.agenda = Agenda(self.goal)
 
@@ -108,7 +111,7 @@ class UserPolicyAgendaMultiWoz(Policy):
                 self.agenda.close_session()
 
         # A -> A' + user_action
-        # action = self.agenda.get_action(random.randint(1, self.max_initiative))
+        # action = self.agenda.get_action(random.randint(2, self.max_initiative))
         action = self.agenda.get_action(self.max_initiative)
 
         # transform to DA
@@ -310,7 +313,7 @@ class Goal(object):
         """
         create new Goal by random
         Args:
-            goal_generator (GoalGenerator): Goal Gernerator.
+            goal_generator (GoalGenerator): Goal Generator.
         """
         self.domain_goals = goal_generator.get_user_goal()
 
@@ -324,6 +327,25 @@ class Goal(object):
             if 'book' in self.domain_goals[domain].keys():
                 self.domain_goals[domain]['booked'] = DEF_VAL_UNK
 
+    def set_user_goal(self, user_goal):
+        """
+        set new Goal given user goal generated by goal_generator.get_user_goal()
+        Args:
+            user_goal : user goal generated by GoalGenerator.
+        """
+        self.domain_goals = user_goal
+
+        self.domains = list(self.domain_goals['domain_ordering'])
+        del self.domain_goals['domain_ordering']
+
+        for domain in self.domains:
+            if 'reqt' in self.domain_goals[domain].keys():
+                self.domain_goals[domain]['reqt'] = {slot: DEF_VAL_UNK for slot in self.domain_goals[domain]['reqt']}
+
+            if 'book' in self.domain_goals[domain].keys():
+                self.domain_goals[domain]['booked'] = DEF_VAL_UNK
+
+
     def task_complete(self):
         """
         Check that all requests have been met
@@ -391,6 +413,7 @@ class Agenda(object):
             domain = goal.domains[idx]
 
             # inform
+            # first ask fail_info which return no result then ask info
             if 'fail_info' in goal.domain_goals[domain]:
                 for slot in random_sample(goal.domain_goals[domain]['fail_info'].keys(),
                                           len(goal.domain_goals[domain]['fail_info'])):
@@ -538,6 +561,7 @@ class Agenda(object):
     def close_session(self):
         """ Clear up all actions """
         self.__stack = []
+        self.__cur_push_num = 0
         self.__push(self.CLOSE_ACT)
 
     def get_action(self, initiative=1):
@@ -624,7 +648,7 @@ class Agenda(object):
             # booked ok
             if 'booked' in goal.domain_goals[domain]:
                 goal.domain_goals[domain]['booked'] = DEF_VAL_BOOKED
-            self._push_item('general-thank')
+            # self._push_item('general-thank')
 
         return False
 
@@ -654,24 +678,28 @@ class Agenda(object):
 
                 if domain == 'taxi' and (slot == 'destination' or slot == 'departure'):
                     places = [dom for dom in goal.domains[: goal.domains.index('taxi')] if
-                              'address' in goal.domain_goals[dom].get('reqt',[])]
-
-                    if len(places) >= 1 and slot == 'destination' and \
-                            goal.domain_goals[places[-1]]['reqt']['address'] not in NOT_SURE_VALS:
-                        self._push_item(domain + '-inform', slot, goal.domain_goals[places[-1]]['reqt']['address'])
-
-                    elif len(places) >= 2 and slot == 'departure' and \
-                            goal.domain_goals[places[-2]]['reqt']['address'] not in NOT_SURE_VALS:
-                        self._push_item(domain + '-inform', slot, goal.domain_goals[places[-2]]['reqt']['address'])
-
-                    # elif random.random() < 0.5:
-                    #     self._push_item(domain + '-inform', slot, DEF_VAL_DNC)
+                              dom in ['attraction', 'hotel', 'restaurant', 'police', 'hospital']] # name will not appear in reqt
+                    if len(places) >= 1 and slot == 'destination':
+                        place_idx = -1
+                    elif len(places) >= 2 and slot == 'departure':
+                        place_idx = -2
+                    else:
+                        place_idx = None
+                    if place_idx:
+                        if goal.domain_goals[places[place_idx]]['info'].get('name', DEF_VAL_NUL) not in NOT_SURE_VALS:
+                            place = goal.domain_goals[places[place_idx]]['info']['name']
+                        # elif goal.domain_goals[places[place_idx]]['reqt'].get('address', DEF_VAL_NUL) not in NOT_SURE_VALS:
+                        #     place = goal.domain_goals[places[place_idx]]['reqt']['address']
+                        else:
+                            place = "the " + places[place_idx]
+                        self._push_item(domain + '-inform', slot, place)
+                    else:
+                        self._push_item(domain + '-inform', slot, DEF_VAL_DNC)
 
-                # elif random.random() < 0.5:
-                #     self._push_item(domain + '-inform', slot, DEF_VAL_DNC)
+                else:
+                    # for those sys requests that are not in user goal
+                    self._push_item(domain + '-inform', slot, DEF_VAL_DNC)
 
-                # for those sys requests that are not in user goal
-                self._push_item(domain + '-inform', slot, DEF_VAL_DNC)
         return False
 
     def _handle_nooffer(self, domain, intent, slot_vals, goal: Goal):
@@ -803,6 +831,17 @@ class Agenda(object):
         return None
 
     def __push(self, diaact, slot=DEF_VAL_NUL, value=DEF_VAL_NUL):
+        if slot in ['people', 'day', 'area', 'pricerange']:
+            for item in self.__stack:
+                if item['slot'] == slot and item['value'] == value and random.random() < 0.3:
+                    if slot == 'people':
+                        item['value'] = 'the same'
+                    elif slot == 'day':
+                        item['value'] = 'the same day'
+                    elif slot == 'pricerange':
+                        item['value'] = 'in the same price range as the {}'.format(diaact.split('-')[0])
+                    elif slot == 'area':
+                        item['value'] = 'same area as the {}'.format(diaact.split('-')[0])
         self.__stack.append({'diaact': diaact, 'slot': slot, 'value': value})
 
     def __pop(self, initiative=1):
@@ -829,7 +868,13 @@ class Agenda(object):
                 except Exception as e:
                     break
         else:
-            for _ in range(initiative if self.__cur_push_num == 0 else self.__cur_push_num):
+            if self.__cur_push_num == 0 or (all([self.__stack[-i-1]['value'] == DEF_VAL_DNC for i in
+                                                 range(0, min(len(self.__stack), self.__cur_push_num))])):
+                # pop more when only dontcare
+                num2pop = initiative
+            else:
+                num2pop = self.__cur_push_num
+            for _ in range(num2pop):
                 try:
                     item = self.__stack.pop(-1)
                     diaacts.append(item['diaact'])
@@ -861,79 +906,248 @@ class Agenda(object):
 if __name__ == '__main__':
     import numpy as np
     import torch
-    np.random.seed(42)
-    random.seed(42)
-    torch.manual_seed(42)
-
-    user_policy = UserPolicyAgendaMultiWoz()
-    from convlab2.policy.rule.multiwoz.rule_based_multiwoz_bot import RuleBasedMultiwozBot
-    sys_policy = RuleBasedMultiwozBot()
+    from pprint import pprint
+    from convlab2.dialog_agent import PipelineAgent, BiSession
+    from convlab2.evaluator.multiwoz_eval import MultiWozEvaluator
+    from convlab2.policy.rule.multiwoz import RulePolicy
     from convlab2.nlg.template.multiwoz.nlg import TemplateNLG
-    user_nlg = TemplateNLG(is_user=True, mode='manual')
-    sys_nlg = TemplateNLG(is_user=False, mode='manual')
-    from convlab2.util.multiwoz.state import default_state
-
-    user_policy.init_session()
-    sys_policy.init_session()
-
-    print(user_policy.goal)
-
-    print(user_policy.agenda)
-    user_act = user_policy.predict([])
-    print(user_act)
-    user_utt = user_nlg.generate(user_act)
-    print(user_utt)
-    state = default_state()
-    state['user_action'] = user_act
-    sys_act = sys_policy.predict(state)
-    sys_act.append(["Request", "Restaurant", "Price", "?"])
-    sys_act = [['Inform', 'Hotel', 'Choice', '0']]
-    print(sys_act)
-
-
-    user_act = user_policy.predict(sys_act)
-    print(user_act)
-    user_utt = user_nlg.generate(user_act)
-    print(user_utt)
-    sys_act = sys_policy.predict(state)
-    print(sys_act)
-
-    user_act = user_policy.predict(sys_act)
-    print(user_act)
-    user_utt = user_nlg.generate(user_act)
+    from convlab2.dst.rule.multiwoz.dst import RuleDST
+    from convlab2.nlu.jointBERT.multiwoz.nlu import BERTNLU
+
+    seed = 50
+    np.random.seed(seed)
+    random.seed(seed)
+    torch.manual_seed(seed)
+
+    sys_nlu = BERTNLU()
+    sys_dst = RuleDST()
+    sys_policy = RulePolicy()
+    sys_nlg = TemplateNLG(is_user=False)
+    sys_agent = PipelineAgent(sys_nlu, sys_dst, sys_policy, sys_nlg, name='sys')
+
+    user_nlu = BERTNLU(mode='sys', config_file='multiwoz_sys_context.json',
+                       model_file='https://convlab.blob.core.windows.net/convlab-2/bert_multiwoz_sys_context.zip')
+    user_dst = None
+    user_policy = RulePolicy(character='usr')
+    user_nlg = TemplateNLG(is_user=True)
+    user_agent = PipelineAgent(user_nlu, user_dst, user_policy, user_nlg, name='user')
+
+    # evaluator = MultiWozEvaluator()
+    # sess = BiSession(sys_agent=sys_agent, user_agent=user_agent, kb_query=None, evaluator=evaluator)
+
+
+
+
+    # user_policy = UserPolicyAgendaMultiWoz()
+    #
+    # sys_policy = RuleBasedMultiwozBot()
+    #
+    # user_nlg = TemplateNLG(is_user=True, mode='manual')
+    # sys_nlg = TemplateNLG(is_user=False, mode='manual')
+    #
+    # dst = RuleDST()
+    #
+    # user_nlu = BERTNLU(mode='sys', config_file='multiwoz_sys_context.json',
+    #                    model_file='https://convlab.blob.core.windows.net/convlab-2/bert_multiwoz_sys_context.zip')
+    #
+    goal_generator = GoalGenerator()
+    # while True:
+    #     goal = goal_generator.get_user_goal()
+    #     if 'restaurant' in goal['domain_ordering'] and 'hotel' in goal['domain_ordering']:
+    #         break
+    # # pprint(goal)
+    user_goal = {'domain_ordering': ('restaurant', 'hotel', 'taxi'),
+                 'hotel': {'book': {'day': 'sunday', 'people': '6', 'stay': '4'},
+                           'info': {'internet': 'no',
+                                    'parking': 'no',
+                                    'pricerange': 'moderate',
+                                    'area': 'centre'}},
+                 'restaurant': {'info': {'area': 'centre',
+                                         'food': 'portuguese',
+                                         'pricerange': 'cheap'},
+                                'fail_info': {'area': 'centre',
+                                         'food': 'portuguese',
+                                         'pricerange': 'expensive'},
+                                'reqt': ['postcode']},
+                 'taxi': {'info': {'arriveBy': '13:00'}, 'reqt': ['car type', 'phone']}}
+    # # user_goal = goal
+    goal = Goal(goal_generator)
+    goal.set_user_goal(user_goal)
+    #
+    # user_policy.init_session(ini_goal=goal)
+    # sys_policy.init_session()
+    #
+    # goal = user_policy.get_goal()
+    #
+    # pprint(goal)
+
+    sys_response = ''
+    # sess.init_session(ini_goal=goal)
+    user_policy.init_session(ini_goal=goal)
+    print('init goal:')
+    # pprint(user_policy.get_goal())
+    pprint(user_agent.policy.get_goal())
+    # pprint(sess.evaluator.goal)
+    # print('-' * 50)
+    # for i in range(20):
+    #     sys_response, user_response, session_over, reward = sess.next_turn(sys_response)
+    #     print('user:', user_response)
+    #     print('sys:', sys_response)
+    #     print()
+    #     if session_over is True:
+    #         break
+    # print('task success:', sess.evaluator.task_success())
+    # print('book rate:', sess.evaluator.book_rate())
+    # print('inform precision/recall/f1:', sess.evaluator.inform_F1())
+    # print('-' * 50)
+    # print('final goal:')
+    # pprint(sess.evaluator.goal)
+    # print('=' * 100)
+
+    history = []
+    user_utt = user_agent.response('')
     print(user_utt)
-    sys_act = sys_policy.predict(state)
-    sys_act = [["Book", "Booking", "Ref", "7GAWK763"]]
-    print(sys_act)
-
-    user_act = user_policy.predict(sys_act)
-    print(user_act)
-    user_utt = user_nlg.generate(user_act)
+    user_utt = 'I need a restaurant . It just needs to be expensive . I am also in the market for a new restaurant . Is there something in the centre of town ? Do you have portuguese food ?'
+    # history.append(['user', user_utt])
+    sys_agent.dst.state['belief_state']['restaurant']['semi']['food'] = 'portuguese'
+    sys_utt = sys_agent.response(user_utt)
+    pprint(sys_agent.dst.state)
+    print(sys_utt)
+    sys_utt = "I have n't found any in the centre. I am unable to find any portuguese restaurants in town ."
+    # history.append(['user', user_utt])
+
+    user_utt = user_agent.response(sys_utt)
     print(user_utt)
-    sys_act = sys_policy.predict(state)
-    sys_act = [["Reqmore", "General", "none", "none"]]
-    print(sys_act)
+    user_utt = "It just needs to be cheap ."
+    sys_utt = sys_agent.response(user_utt)
+    print(sys_utt)
+    sys_utt = "It is in the centre area . They serve portuguese . Would you like to try nandos city centre ? They are in the cheap price range . I will book it for you and get a reference number ?"
 
-    user_act = user_policy.predict(sys_act)
-    print(user_act)
-    user_utt = user_nlg.generate(user_act)
+    user_utt = user_agent.response(sys_utt)
     print(user_utt)
-    sys_act = sys_policy.predict(state)
-    sys_act = [["Inform", "Hotel", "Parking", "none"]]
-    print(sys_act)
+    sys_utt = sys_agent.response(user_utt)
+    print(sys_utt)
 
-    user_act = user_policy.predict(sys_act)
-    print(user_act)
-    user_utt = user_nlg.generate(user_act)
+    user_utt = user_agent.response(sys_utt)
     print(user_utt)
-    sys_act = sys_policy.predict(state)
-    sys_act = [["Request", "Booking", "people", "?"]]
-    print(sys_act)
+    sys_utt = sys_agent.response(user_utt)
+    print(sys_utt)
 
-    user_act = user_policy.predict(sys_act)
-    print(user_act)
-    user_utt = user_nlg.generate(user_act)
+    user_utt = user_agent.response(sys_utt)
     print(user_utt)
-    sys_act = sys_policy.predict(state)
-    sys_act = [["Inform", "Hotel", "Post", "233"], ["Book", "Booking", "none", "none"]]
-    print(sys_act)
+    sys_utt = sys_agent.response(user_utt)
+    print(sys_utt)
+
+    #
+    # print(user_policy.agenda)
+    # user_act = user_policy.predict([])
+    # print(user_act)
+    # user_utt = user_nlg.generate(user_act)
+    # print(user_utt)
+    # state = dst.state
+    # state['user_action'] = user_act
+    # dst.update(user_act)
+    # # pprint(state)
+    # sys_act = sys_policy.predict(state)
+    # sys_utt = sys_nlg.generate(sys_act)
+    # # sys_act.append(["Request", "Restaurant", "Price", "?"])
+    # # sys_act = [['Request', 'Hotel', 'Area', '?'], ['Request', 'Hotel', 'Stars', '?']]
+    # print(sys_act)
+    # print(sys_utt)
+    #
+    # user_act = user_policy.predict(sys_act)
+    # print(user_act)
+    # user_utt = user_nlg.generate(user_act)
+    # print(user_utt)
+    # state = dst.state
+    # state['user_action'] = user_act
+    # dst.update(user_act)
+    # # pprint(state)
+    # sys_act = sys_policy.predict(state)
+    # # sys_act = [['Inform', 'Hotel', 'Choice', '3']]
+    # print(sys_act)
+    #
+    #
+    # user_act = user_policy.predict(sys_act)
+    # print(user_act)
+    # user_utt = user_nlg.generate(user_act)
+    # print(user_utt)
+    # state = dst.state
+    # state['user_action'] = user_act
+    # dst.update(user_act)
+    # # pprint(state)
+    # sys_act = sys_policy.predict(state)
+    # # sys_act = [["Book", "Booking", "Ref", "7GAWK763"]]
+    # print(sys_act)
+    # #
+    # user_act = user_policy.predict(sys_act)
+    # print(user_act)
+    # user_utt = user_nlg.generate(user_act)
+    # print(user_utt)
+    # state = dst.state
+    # state['user_action'] = user_act
+    # dst.update(user_act)
+    # # pprint(state)
+    # sys_act = sys_policy.predict(state)
+    # # sys_act = [["Reqmore", "General", "none", "none"]]
+    # print(sys_act)
+    # #
+    # user_act = user_policy.predict(sys_act)
+    # print(user_act)
+    # user_utt = user_nlg.generate(user_act)
+    # print(user_utt)
+    # state = dst.state
+    # state['user_action'] = user_act
+    # dst.update(user_act)
+    # # pprint(state)
+    # sys_act = sys_policy.predict(state)
+    # # sys_act = [["Inform", "Hotel", "Parking", "none"]]
+    # print(sys_act)
+    #
+    # user_act = user_policy.predict(sys_act)
+    # print(user_act)
+    # user_utt = user_nlg.generate(user_act)
+    # print(user_utt)
+    # state = dst.state
+    # state['user_action'] = user_act
+    # dst.update(user_act)
+    # # pprint(state)
+    # sys_act = sys_policy.predict(state)
+    # # sys_act = [["Request", "Booking", "people", "?"]]
+    # print(sys_act)
+    #
+    # user_act = user_policy.predict(sys_act)
+    # print(user_act)
+    # user_utt = user_nlg.generate(user_act)
+    # print(user_utt)
+    # state = dst.state
+    # state['user_action'] = user_act
+    # dst.update(user_act)
+    # # pprint(state)
+    # sys_act = sys_policy.predict(state)
+    # # sys_act = [["Inform", "Hotel", "Post", "233"], ["Book", "Booking", "none", "none"]]
+    # print(sys_act)
+    #
+    # user_act = user_policy.predict(sys_act)
+    # print(user_act)
+    # user_utt = user_nlg.generate(user_act)
+    # print(user_utt)
+    # state = dst.state
+    # state['user_action'] = user_act
+    # dst.update(user_act)
+    # # pprint(state)
+    # sys_act = sys_policy.predict(state)
+    # sys_act = [["Request", "Taxi", "Dest", "?"], ["Request", "Taxi", "Depart", "?"]]
+    # print(sys_act)
+    #
+    # user_act = user_policy.predict(sys_act)
+    # print(user_act)
+    # user_utt = user_nlg.generate(user_act)
+    # print(user_utt)
+    # state = dst.state
+    # state['user_action'] = user_act
+    # dst.update(user_act)
+    # # pprint(state)
+    # sys_act = sys_policy.predict(state)
+    # # sys_act = [["Request", "Taxi", "Destination", "?"], ["Request", "Taxi", "Departure", "?"]]
+    # print(sys_act)
diff --git a/convlab2/policy/rule/multiwoz/rule.py b/convlab2/policy/rule/multiwoz/rule.py
index fb0c46329f29302390686cce826d1a11c25d7879..9fdc3a30a00ade9b84239e589fcd048ca90f06a8 100755
--- a/convlab2/policy/rule/multiwoz/rule.py
+++ b/convlab2/policy/rule/multiwoz/rule.py
@@ -30,11 +30,11 @@ class RulePolicy(Policy):
         """
         return self.policy.predict(state)
 
-    def init_session(self):
+    def init_session(self, **kwargs):
         """
         Restore after one session
         """
-        self.policy.init_session()
+        self.policy.init_session(**kwargs)
 
     def is_terminated(self):
         if self.character == 'sys':
diff --git a/convlab2/policy/rule/multiwoz/rule_based_multiwoz_bot.py b/convlab2/policy/rule/multiwoz/rule_based_multiwoz_bot.py
index e17ba98d5b894ef7e30ddcaf46f5940338e6f582..768393658697fa9e239f81f49c17258f76a73c43 100755
--- a/convlab2/policy/rule/multiwoz/rule_based_multiwoz_bot.py
+++ b/convlab2/policy/rule/multiwoz/rule_based_multiwoz_bot.py
@@ -225,16 +225,16 @@ class RuleBasedMultiwozBot(Policy):
                         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, "?"])
+                # 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:
diff --git a/convlab2/task/multiwoz/generate_goals.py b/convlab2/task/multiwoz/generate_goals.py
index 05384497ce795783559601753422670e2796d898..d32b90b6d20c1eccdcf3db349b9c879310439435 100644
--- a/convlab2/task/multiwoz/generate_goals.py
+++ b/convlab2/task/multiwoz/generate_goals.py
@@ -3,6 +3,7 @@ generate user goal for collecting new multiwoz data
 """
 
 from convlab2.task.multiwoz.goal_generator import GoalGenerator
+from convlab2.util.file_util import read_zipped_json
 import random
 import numpy as np
 import json
@@ -10,6 +11,78 @@ import datetime
 from pprint import pprint
 
 
+def extract_slot_combination_from_goal(goal):
+    domains = ['attraction', 'hotel', 'restaurant', 'police', 'hospital', 'taxi', 'train']
+    serialized_goal = []
+    for domain in goal:
+        if domain in domains:
+            for scope, content in goal[domain].items():
+                if content:
+                    # if isinstance(content, dict):
+                    #     for slot, value in content.items():
+                    #         serialized_goal.append("{}-{}-{}-{}".format(domain, scope, slot, value))
+                    # else:
+                    #     for slot in content:
+                    #         serialized_goal.append("{}-{}-{}".format(domain, scope, slot))
+                    for slot in content:
+                        serialized_goal.append("{}-{}-{}".format(domain, scope, slot))
+    return sorted(serialized_goal)
+
+
+def test_generate_overlap(total_num=1000, seed=42, output_file='goal.json'):
+    train_data = read_zipped_json('../../../data/multiwoz/train.json.zip', 'train.json')
+    train_serialized_goals = []
+    for d in train_data:
+        train_serialized_goals.append(extract_slot_combination_from_goal(train_data[d]['goal']))
+
+    test_data = read_zipped_json('../../../data/multiwoz/test.json.zip', 'test.json')
+    test_serialized_goals = []
+    for d in test_data:
+        test_serialized_goals.append(extract_slot_combination_from_goal(test_data[d]['goal']))
+
+    overlap = 0
+    for serialized_goal in test_serialized_goals:
+        if serialized_goal in train_serialized_goals:
+            overlap += 1
+    print(len(train_serialized_goals), len(test_serialized_goals), overlap) # 8434 1000 430
+
+    random.seed(seed)
+    np.random.seed(seed)
+    goal_generator = GoalGenerator()
+    goals = []
+    avg_domains = []
+    serialized_goals = []
+    while len(goals) < total_num:
+        goal = goal_generator.get_user_goal()
+        # pprint(goal)
+        if 'police' in goal['domain_ordering']:
+            no_police = list(goal['domain_ordering'])
+            no_police.remove('police')
+            goal['domain_ordering'] = tuple(no_police)
+            del goal['police']
+        try:
+            message = goal_generator.build_message(goal)[1]
+        except:
+            continue
+        # print(message)
+        avg_domains.append(len(goal['domain_ordering']))
+        goals.append({
+            "goals": [],
+            "ori_goals": goal,
+            "description": message,
+            "timestamp": str(datetime.datetime.now()),
+            "ID": len(goals)
+        })
+        serialized_goals.append(extract_slot_combination_from_goal(goal))
+        if len(serialized_goals) == 1:
+            print(serialized_goals)
+    overlap = 0
+    for serialized_goal in serialized_goals:
+        if serialized_goal in train_serialized_goals:
+            overlap += 1
+    print(len(train_serialized_goals), len(serialized_goals), overlap) # 8434 1000 199
+
+
 def generate(total_num=1000, seed=42, output_file='goal.json'):
     random.seed(seed)
     np.random.seed(seed)
@@ -43,4 +116,3 @@ def generate(total_num=1000, seed=42, output_file='goal.json'):
 
 if __name__ == '__main__':
     generate(output_file='goal20200629.json')
-    
\ No newline at end of file
diff --git a/convlab2/task/multiwoz/goal_generator.py b/convlab2/task/multiwoz/goal_generator.py
index fc9d9b33bec05aa3aa59a711b90b824b834e9c19..cdf378bd4c2f340860ffcb166838f95490687d6b 100755
--- a/convlab2/task/multiwoz/goal_generator.py
+++ b/convlab2/task/multiwoz/goal_generator.py
@@ -142,7 +142,7 @@ class GoalGenerator:
                  sample_reqt_from_trainset=False):
         """
         Args:
-            goal_model_path: path to a goal model 
+            goal_model_path: path to a goal model
             corpus_path: path to a dialog corpus to build a goal model
             boldify: highlight some information in the goal message
             sample_info_from_trainset: if True, sample info slots combination from train set, else sample each slot independently
@@ -422,27 +422,27 @@ class GoalGenerator:
                 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_book: not use any more since 2020.8.18
+            # 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(self.db.query(domain, domain_goal['info'].items())) == 0:
@@ -453,6 +453,7 @@ class GoalGenerator:
                         if domain == 'train':
                             domain_goal['info'] = adjusted_info
                         else:
+                            # first ask fail_info which return no result then ask info
                             domain_goal['fail_info'] = domain_goal['info']
                             domain_goal['info'] = adjusted_info
 
@@ -479,13 +480,14 @@ class GoalGenerator:
 
         # 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()]
+            places = [dom for dom in domain_ordering[: domain_ordering.index('taxi')] if
+                      dom in ['attraction', 'hotel', 'restaurant', 'police', 'hospital']]
             if len(places) >= 1:
                 del user_goal['taxi']['info']['destination']
-                if 'reqt' not in user_goal[places[-1]]:
-                    user_goal[places[-1]]['reqt'] = []
-                if 'address' not in user_goal[places[-1]]['reqt']:
-                    user_goal[places[-1]]['reqt'].append('address')
+                # if 'reqt' not in user_goal[places[-1]]:
+                #     user_goal[places[-1]]['reqt'] = []
+                # if 'address' not in user_goal[places[-1]]['reqt']:
+                #     user_goal[places[-1]]['reqt'].append('address')
                 # the line below introduce randomness by `union`
                 # 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']:
@@ -494,10 +496,10 @@ class GoalGenerator:
                         del user_goal['taxi']['info']['leaveAt']
             if len(places) >= 2:
                 del user_goal['taxi']['info']['departure']
-                if 'reqt' not in user_goal[places[-2]]:
-                    user_goal[places[-2]]['reqt'] = []
-                if 'address' not in user_goal[places[-2]]['reqt']:
-                    user_goal[places[-2]]['reqt'].append('address')
+                # if 'reqt' not in user_goal[places[-2]]:
+                #     user_goal[places[-2]]['reqt'] = []
+                # if 'address' not in user_goal[places[-2]]['reqt']:
+                #     user_goal[places[-2]]['reqt'].append('address')
                 # the line below introduce randomness by `union`
                 # user_goal[places[-2]]['reqt'] = list(set(user_goal[places[-2]].get('reqt', [])).union({'address'}))
 
diff --git a/convlab2/util/analysis_tool/analyzer.py b/convlab2/util/analysis_tool/analyzer.py
index fb25a31ee590f9fa091e2703c7ced6534f581451..de16c18d8b72206545931fb20eea55a8e0ed4c4d 100755
--- a/convlab2/util/analysis_tool/analyzer.py
+++ b/convlab2/util/analysis_tool/analyzer.py
@@ -50,6 +50,7 @@ class Analyzer:
         print('task success:', sess.evaluator.task_success())
         print('book rate:', sess.evaluator.book_rate())
         print('inform precision/recall/f1:', sess.evaluator.inform_F1())
+        print(f"percentage of domains that satisfies the database constraints: {sess.evaluator.final_goal_analyze()}")
         print('-' * 50)
         print('final goal:')
         pprint(sess.evaluator.goal)
@@ -67,6 +68,9 @@ class Analyzer:
         complete_num = 0
         turn_num = 0
         turn_suc_num = 0
+        num_domains = 0
+        num_domains_satisfying_constraints = 0
+        num_dialogs_satisfying_constraints = 0
 
         reporter = Reporter(model_name)
         logger = logging.getLogger(__name__)
@@ -81,6 +85,7 @@ class Analyzer:
         if not os.path.exists(output_dir):
             os.mkdir(output_dir)
         f = open(os.path.join(output_dir, 'res.txt'), 'w')
+        flog = open(os.path.join(output_dir, 'log.txt'), 'w')
 
         for j in tqdm(range(total_dialog), desc="dialogue"):
             sys_response = '' if self.user_agent.nlu else []
@@ -106,13 +111,13 @@ class Analyzer:
             for i in range(40):
                 sys_response, user_response, session_over, reward = sess.next_turn(
                     sys_response)
-                # print('user in', sess.user_agent.get_in_da(),file=f)
-                # print('user out', sess.user_agent.get_out_da(),file=f)
+                print('user in', sess.user_agent.get_in_da(),file=flog)
+                print('user out', sess.user_agent.get_out_da(),file=flog)
                 #
-                # print('sys in', sess.sys_agent.get_in_da(),file=f)
-                # print('sys out', sess.sys_agent.get_out_da(),file=f)
-                # print('user:', user_response,file=f)
-                # print('sys:', sys_response,file=f)
+                # print('sys in', sess.sys_agent.get_in_da(),file=flog)
+                # print('sys out', sess.sys_agent.get_out_da(),file=flog)
+                print('user:', user_response,file=flog)
+                print('sys:', sys_response,file=flog)
 
                 step += 2
 
@@ -141,6 +146,7 @@ class Analyzer:
             task_complete = sess.user_agent.policy.policy.goal.task_complete()
             book_rate = sess.evaluator.book_rate()
             stats = sess.evaluator.inform_F1()
+            percentage = sess.evaluator.final_goal_analyze()
             if task_success:
                 suc_num += 1
                 turn_suc_num += step
@@ -152,6 +158,10 @@ class Analyzer:
                 f1.append(stats[2])
             if book_rate is not None:
                 match.append(book_rate)
+            if len(sess.evaluator.goal) > 0:
+                num_domains += len(sess.evaluator.goal)
+                num_domains_satisfying_constraints += len(sess.evaluator.goal) * percentage
+            num_dialogs_satisfying_constraints += (percentage == 1)
             if (j+1) % 100 == 0:
                 logger.info("model name %s", model_name)
                 logger.info("dialogue %d", j+1)
@@ -160,6 +170,9 @@ class Analyzer:
                 logger.info('task success: %.3f', suc_num/(j+1))
                 logger.info('book rate: %.3f', np.mean(match))
                 logger.info('inform precision/recall/f1: %.3f %.3f %.3f', np.mean(precision), np.mean(recall), np.mean(f1))
+                logging.info("percentage of domains that satisfy the database constraints: %.3f" % \
+                             (1 if num_domains == 0 else (num_domains_satisfying_constraints / num_domains)))
+                logging.info("percentage of dialogs that satisfy the database constraints: %.3f" % (num_dialogs_satisfying_constraints / (j + 1)))
             domain_set = []
             for da in sess.evaluator.usr_da_array:
                 if da.split('-')[0] != 'general' and da.split('-')[0] not in domain_set:
@@ -194,6 +207,9 @@ class Analyzer:
         print('average book rate:', np.mean(match))
         print("average turn (succ):", tmp)
         print("average turn (all):", turn_num / total_dialog)
+        print("percentage of domains that satisfy the database constraints: %.3f" % \
+              (1 if num_domains == 0 else (num_domains_satisfying_constraints / num_domains)))
+        print("percentage of dialogs that satisfy the database constraints: %.3f" % (num_dialogs_satisfying_constraints / total_dialog))
         print("=" * 100)
         print("complete number of dialogs/tot:", complete_num / total_dialog, file=f)
         print("success number of dialogs/tot:", suc_num / total_dialog, file=f)
@@ -203,6 +219,9 @@ class Analyzer:
         print('average book rate:', np.mean(match), file=f)
         print("average turn (succ):", tmp, file=f)
         print("average turn (all):", turn_num / total_dialog, file=f)
+        print("percentage of domains that satisfy the database constraints: %.3f" % \
+              (1 if num_domains == 0 else (num_domains_satisfying_constraints / num_domains)), file=f)
+        print("percentage of dialogs that satisfy the database constraints: %.3f" % (num_dialogs_satisfying_constraints / total_dialog), file=f)
         f.close()
 
         reporter.report(complete_num/total_dialog, suc_num/total_dialog, np.mean(precision), np.mean(recall), np.mean(f1), tmp, turn_num / total_dialog)
diff --git a/convlab2/util/multiwoz/dbquery.py b/convlab2/util/multiwoz/dbquery.py
index c3a5c2f7e1cb78feedd04f1d538a42a979df2c2c..4a2879f84f8cf62fc7ba02ba1cd309688b6086d7 100755
--- a/convlab2/util/multiwoz/dbquery.py
+++ b/convlab2/util/multiwoz/dbquery.py
@@ -3,6 +3,9 @@
 import json
 import os
 import random
+from fuzzywuzzy import fuzz
+from itertools import chain
+from copy import deepcopy
 
 
 class Database(object):
@@ -17,7 +20,7 @@ class Database(object):
                     'data/multiwoz/db/{}_db.json'.format(domain))) as f:
                 self.dbs[domain] = json.load(f)
 
-    def query(self, domain, constraints, ignore_open=False):
+    def query(self, domain, constraints, ignore_open=False, soft_contraints=(), fuzzy_match_ratio=60):
         """Returns the list of entities for a given domain
         based on the annotation of the belief state"""
         # query the db
@@ -26,16 +29,23 @@ class Database(object):
             'taxi_types': random.choice(self.dbs[domain]['taxi_types']),
             'taxi_phone': ''.join([str(random.randint(1, 9)) for _ in range(11)])}]
         if domain == 'police':
-            return self.dbs['police']
+            return deepcopy(self.dbs['police'])
         if domain == 'hospital':
-            return self.dbs['hospital']
-        for ele in constraints:
-            if ele[0] == 'area' and ele[1] == 'center':
-                ele[1] = 'centre'
+            department = None
+            for key, val in constraints:
+                if key == 'department':
+                    department = val
+            if not department:
+                return deepcopy(self.dbs['hospital'])
+            else:
+                return [deepcopy(x) for x in self.dbs['hospital'] if x['department'].lower() == department.strip().lower()]
+        constraints = list(map(lambda ele: ele if not(ele[0] == 'area' and ele[1] == 'center') else ('area', 'centre'), constraints))
 
         found = []
         for i, record in enumerate(self.dbs[domain]):
-            for key, val in constraints:
+            constraints_iterator = zip(constraints, [False] * len(constraints))
+            soft_contraints_iterator = zip(soft_contraints, [True] * len(soft_contraints))
+            for (key, val), fuzzy_match in chain(constraints_iterator, soft_contraints_iterator):
                 if val == "" or val == "dont care" or val == 'not mentioned' or val == "don't care" or val == "dontcare" or val == "do n't care":
                     pass
                 else:
@@ -56,16 +66,26 @@ class Database(object):
                         # elif ignore_open and key in ['destination', 'departure', 'name']:
                         elif ignore_open and key in ['destination', 'departure']:
                             continue
+                        elif record[key].strip() == '?':
+                            # '?' matches any constraint
+                            continue
                         else:
-                            if val.strip().lower() != record[key].strip().lower():
-                                break
+                            if not fuzzy_match:
+                                if val.strip().lower() != record[key].strip().lower():
+                                    break
+                            else:
+                                if fuzz.partial_ratio(val.strip().lower(), record[key].strip().lower()) < fuzzy_match_ratio:
+                                    break
                     except:
                         continue
             else:
-                record['Ref'] = '{0:08d}'.format(i)
-                found.append(record)
+                res = deepcopy(record)
+                res['Ref'] = '{0:08d}'.format(i)
+                found.append(res)
 
         return found
+
+
 if __name__ == '__main__':
     db = Database()
     print(db.query("train", [['departure', 'cambridge'], ['destination','peterborough'], ['day', 'tuesday'], ['arriveBy', '11:15']]))
diff --git a/data/crosswoz/extract_all_ontology.py b/data/crosswoz/extract_all_ontology.py
new file mode 100644
index 0000000000000000000000000000000000000000..4ca4deaee5ae01b850793667b4e6bee8d17064e4
--- /dev/null
+++ b/data/crosswoz/extract_all_ontology.py
@@ -0,0 +1,203 @@
+"""
+extract all value appear in dialog act and state, for translation.
+"""
+import json
+import zipfile
+import re
+from pprint import pprint
+
+def read_zipped_json(filepath, filename):
+    archive = zipfile.ZipFile(filepath, 'r')
+    return json.load(archive.open(filename))
+
+
+zh_pattern = re.compile(u'[\u4e00-\u9fa5]+')
+multi_name = set()
+
+def extract_ontology(data):
+    intent_set = set()
+    domain_set = set()
+    slot_set = set()
+    value_set = {}
+    for _, sess in data.items():
+        for i, turn in enumerate(sess['messages']):
+            for intent, domain, slot, value in turn['dialog_act']:
+                intent_set.add(intent)
+                domain_set.add(domain)
+                slot_set.add(slot)
+                if not domain in value_set:
+                    value_set[domain] = {}
+                elif slot not in value_set[domain]:
+                    value_set[domain][slot] = set()
+                elif slot in ['推荐菜', '名称', '酒店设施']:
+                    if slot == '名称' and len(value.split()) > 1:
+                        multi_name.add((domain, slot, value))
+                    elif slot == '推荐菜' and '-' in value:
+                        print((domain, slot, value))
+                    for dish in value.split():
+                        value_set[domain][slot].add(dish)
+                elif slot == 'selectedResults' and domain in ['地铁', '出租']:
+                    if domain == '地铁':
+                        value = value[5:]
+                        value_set[domain][slot].add(value.strip())
+                    if domain == '出租':
+                        value = value[4:-1]
+                        for v in value.split(' - '):
+                            value_set[domain][slot].add(v.strip())
+                else:
+                    value_set[domain][slot].add(value)
+            if turn['role'] == 'usr':
+                for _, domain, slot, value, __ in turn['user_state']:
+                    domain_set.add(domain)
+                    slot_set.add(slot)
+                    if isinstance(value, list):
+                        for v in value:
+                            if not domain in value_set:
+                                value_set[domain] = {}
+                            elif slot not in value_set[domain]:
+                                value_set[domain][slot] = set()
+                            elif slot in ['推荐菜', '名称', '酒店设施']:
+                                if slot == '名称' and len(value.split()) > 1:
+                                    multi_name.add((domain, slot, value))
+                                elif slot == '推荐菜' and '-' in value:
+                                    print((domain, slot, value))
+                                for dish in v.split():
+                                    value_set[domain][slot].add(dish)
+                            elif slot == 'selectedResults' and domain in ['地铁', '出租']:
+                                if domain == '地铁':
+                                    v = v[5:]
+                                    value_set[domain][slot].add(v.strip())
+                                if domain == '出租':
+                                    v = v[4:-1]
+                                    for item in v.split(' - '):
+                                        value_set[domain][slot].add(item.strip())
+                            else:
+                                value_set[domain][slot].add(v)
+                    else:
+                        assert isinstance(value, str)
+                        if not domain in value_set:
+                            value_set[domain] = {}
+                        elif slot not in value_set[domain]:
+                            value_set[domain][slot] = set()
+                        elif slot in ['推荐菜', '名称', '酒店设施']:
+                            if slot == '名称' and len(value.split()) > 1:
+                                multi_name.add((domain, slot, value))
+                            elif slot == '推荐菜' and '-' in value:
+                                print((domain, slot, value))
+                            for dish in value.split():
+                                value_set[domain][slot].add(dish)
+                        elif slot == 'selectedResults' and domain in ['地铁', '出租']:
+                            if domain == '地铁':
+                                value = value[5:]
+                                value_set[domain][slot].add(value.strip())
+                            if domain == '出租':
+                                value = value[4:-1]
+                                for v in value.split(' - '):
+                                    value_set[domain][slot].add(v.strip())
+                        else:
+                            value_set[domain][slot].add(value)
+            else:
+                for state_key in ['sys_state', 'sys_state_init']:
+                    for domain, svd in turn[state_key].items():
+                        domain_set.add(domain)
+                        for slot, value in svd.items():
+                            slot_set.add(slot)
+                            if isinstance(value, list):
+                                for v in value:
+                                    if not domain in value_set:
+                                        value_set[domain] = {}
+                                    elif slot not in value_set[domain]:
+                                        value_set[domain][slot] = set()
+                                    elif slot in ['推荐菜', '名称', '酒店设施']:
+                                        if slot == '名称' and len(value.split()) > 1:
+                                            multi_name.add((domain, slot, value))
+                                        elif slot == '推荐菜' and '-' in value:
+                                            print((domain, slot, value))
+                                        for dish in v.split():
+                                            value_set[domain][slot].add(dish)
+                                    elif slot == 'selectedResults' and domain in ['地铁', '出租']:
+                                        if domain == '地铁':
+                                            v = v[5:]
+                                            value_set[domain][slot].add(v.strip())
+                                        if domain == '出租':
+                                            v = v[4:-1]
+                                            for item in v.split(' - '):
+                                                value_set[domain][slot].add(item.strip())
+                                    else:
+                                        value_set[domain][slot].add(v)
+                            else:
+                                assert isinstance(value, str)
+                                if not domain in value_set:
+                                    value_set[domain] = {}
+                                elif slot not in value_set[domain]:
+                                    value_set[domain][slot] = set()
+                                elif slot in ['推荐菜', '名称', '酒店设施']:
+                                    if slot == '名称' and len(value.split()) > 1:
+                                        multi_name.add((domain, slot, value))
+                                    elif slot == '推荐菜' and '-' in value:
+                                        print((domain, slot, value))
+                                    for dish in value.split():
+                                        value_set[domain][slot].add(dish)
+                                elif slot == 'selectedResults' and domain in ['地铁', '出租']:
+                                    if domain == '地铁':
+                                        value = value[5:]
+                                        value_set[domain][slot].add(value.strip())
+                                    if domain == '出租':
+                                        value = value[4:-1]
+                                        for v in value.split(' - '):
+                                            value_set[domain][slot].add(v.strip())
+                                else:
+                                    value_set[domain][slot].add(value)
+    return intent_set, domain_set, slot_set, value_set
+
+
+if __name__ == '__main__':
+    intent_set = set()
+    domain_set = set()
+    slot_set = set()
+    value_set = {}
+
+    for s in ['train', 'val', 'test', 'dstc9_data']:
+        print(f'Proceeding {s} set...')
+        data = read_zipped_json(s+'.json.zip', s+'.json')
+        output = extract_ontology(data)
+        intent_set |= output[0]
+        domain_set |= output[1]
+        slot_set |= output[2]
+        for domain in output[3]:
+            if domain in value_set:
+                for slot in output[3][domain]:
+                    if slot in value_set[domain]:
+                        value_set[domain][slot] |= output[3][domain][slot]
+                    else:
+                        value_set[domain][slot] = output[3][domain][slot]
+            else:
+                value_set[domain] = output[3][domain]
+
+        print(len(domain_set))
+        print(len(intent_set))
+        print(len(slot_set))
+        print(len(value_set))
+
+    intent_set = list(set([s.lower() for s in intent_set]))
+    domain_set = list(set([s.lower() for s in domain_set]))
+    slot_set = list(set([s.lower() for s in slot_set]))
+    for domain in value_set:
+        for slot in value_set[domain]:
+            value_set[domain][slot] = list(set([s.lower() for s in value_set[domain][slot]]))
+    # json.dump({
+    #     'intent_set': intent_set,
+    #     'domain_set': domain_set,
+    #     'slot_set': slot_set,
+    #     'value_set': value_set,
+    # }, open('all_value_train_val_test.json', 'w'), indent=2, ensure_ascii=False)
+    print(len(domain_set))
+    print(len(intent_set))
+    print(len(slot_set))
+    print(len(value_set))
+    print(len(multi_name))
+    pprint(multi_name)
+
+    # 统计一下每个domain-slot对应的value数
+    # value_count = {x: len(value_set[x]) for x in value_set.keys()}
+    # pprint(value_count)
diff --git a/data/crosswoz/extract_all_value.py b/data/crosswoz/extract_all_value.py
index 9d9db1b8d1b1676122e08e6f91566a9407499bb6..31de3cbadc5e00e15251337636974317a293ed33 100755
--- a/data/crosswoz/extract_all_value.py
+++ b/data/crosswoz/extract_all_value.py
@@ -33,7 +33,7 @@ def extract_ontology(data):
                         assert isinstance(value, str)
                         value_set.add(value)
             else:
-                for domain, svd in turn['sys_state'].items():
+                for domain, svd in turn['sys_state_init'].items():
                     domain_set.add(domain)
                     for slot, value in svd.items():
                         slot_set.add(slot)
diff --git a/data/crosswoz/gen_ontology.py b/data/crosswoz/gen_ontology.py
new file mode 100644
index 0000000000000000000000000000000000000000..f0aa7ad002951c8d12d61500b8c3b545ae2a2013
--- /dev/null
+++ b/data/crosswoz/gen_ontology.py
@@ -0,0 +1,86 @@
+import json
+from zipfile import ZipFile
+
+import re
+
+ontology = {
+    "景点": {
+        "名称": set(),
+        "门票": set(),
+        "游玩时间": set(),
+        "评分": set(),
+        "周边景点": set(),
+        "周边餐馆": set(),
+        "周边酒店": set(),
+    },
+    "餐馆": {
+        "名称": set(),
+        "推荐菜": set(),
+        "人均消费": set(),
+        "评分": set(),
+        "周边景点": set(),
+        "周边餐馆": set(),
+        "周边酒店": set(),
+    },
+    "酒店": {
+        "名称": set(),
+        "酒店类型": set(),
+        "酒店设施": set(),
+        "价格": set(),
+        "评分": set(),
+        "周边景点": set(),
+        "周边餐馆": set(),
+        "周边酒店": set(),
+    },
+    "地铁": {
+        "出发地": set(),
+        "目的地": set(),
+    },
+    "出租": {
+        "出发地": set(),
+        "目的地": set(),
+    }
+}
+
+if __name__ == '__main__':
+    pattern = re.compile('. .+')
+    for split in ['train', 'val', 'test', 'dstc9_data']:
+        print(split)
+        with ZipFile(f'{split}.json.zip', 'r') as zipfile:
+            with zipfile.open(f'{split}.json', 'r') as f:
+                data = json.load(f)
+
+        for dialog in data.values():
+            for turn in dialog['messages']:
+                if turn['role'] == 'sys':
+                    state = turn['sys_state_init']
+                    for domain_name, domain in state.items():
+                        for slot_name, value in domain.items():
+
+                            if slot_name == 'selectedResults':
+                                continue
+                            else:
+                                value = value.replace('\t', ' ').strip()
+                                if not value:
+                                    continue
+                                values = ontology[domain_name][slot_name]
+                                if slot_name in ['酒店设施', '推荐菜']:
+                                    # deal with values contain bothering space like "早 餐 服 务   无 烟 房"
+                                    if pattern.match(value):
+                                        print(value)
+                                        value = value.replace('   ', ';').replace(' ', '').replace(';', ' ')
+                                        print(value)
+                                    for v in value.split(' '):
+                                        if v:
+                                            values.add(v)
+                                elif value and value not in values:
+                                    # if ',' in value or ',' in value or ' ' in value:
+                                        # print(value, slot_name)
+                                    values.add(value)
+
+    for domain in ontology.values():
+        for slot_name, values in domain.items():
+            domain[slot_name] = list(values)
+
+    with open('ontology.json', 'w') as f:
+        json.dump(ontology, f, indent=4, ensure_ascii=False)
diff --git a/data/crosswoz/train.json.zip b/data/crosswoz/train.json.zip
index 09d303cdf5525be1ee2c20b98046857622e62972..25b9a5957021db8217b6ea6e7b67f468f04a1b16 100755
Binary files a/data/crosswoz/train.json.zip and b/data/crosswoz/train.json.zip differ
diff --git a/data/crosswoz/val.json.zip b/data/crosswoz/val.json.zip
index 6c38c8d75e41d632d36e4e239e0dd9dbbadfdad8..3f5d5ba5713d16755dd96c3f9e5779f973d58eef 100755
Binary files a/data/crosswoz/val.json.zip and b/data/crosswoz/val.json.zip differ
diff --git a/data/crosswoz_en/.gitignore b/data/crosswoz_en/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..c249259bc672859adde39d83d57df40beddab6f9
--- /dev/null
+++ b/data/crosswoz_en/.gitignore
@@ -0,0 +1 @@
+CrossWOZ_translate
\ No newline at end of file
diff --git a/data/crosswoz_en/dstc9_testset_example.json b/data/crosswoz_en/dstc9_testset_example.json
new file mode 100644
index 0000000000000000000000000000000000000000..7598cea194412902a5a18714d2e01f3863844fa2
--- /dev/null
+++ b/data/crosswoz_en/dstc9_testset_example.json
@@ -0,0 +1,110 @@
+{
+    "397": {
+        "messages": [
+            {
+                "content": "Hello, can you recommend an attraction with a playing time of 1 hour-2 hours and a rating of 4.5 points or above?",
+                "role": "usr"
+            },
+            {
+                "content": "No problem! You can pay a visit to Peking University.",
+                "role": "sys"
+            },
+            {
+                "content": "OK, are there any good restaurants around it?",
+                "role": "usr"
+            },
+            {
+                "content": "There are many restaurants around it, including Baijia Dayuan and Quanjude Toast Duck Restaurant (Qinghuayuan).",
+                "role": "sys"
+            },
+            {
+                "content": "That's great! I'm just looking for a nearby restaurant with a per-person cost of 150-500 yuan serving Mashed potato in chicken soup. Which restaurant is suitable for me?",
+                "role": "usr"
+            },
+            {
+                "content": "Sorry, there is no one that fully meets your needs. I recommend you to try Baijia Dayuan. Its recommended dishes are Excellent selection of delicious food. And its other conditions meet your needs. Does it work for you?",
+                "role": "sys"
+            },
+            {
+                "content": "Okay, what are the opening hours of it?",
+                "role": "usr"
+            },
+            {
+                "content": "The opening hours are Monday to Sunday 11:00-22:00.",
+                "role": "sys"
+            },
+            {
+                "content": "OK, I am free at that time. Does it have a high rating?",
+                "role": "usr"
+            },
+            {
+                "content": "Not bad. The rating is 4.5 points.",
+                "role": "sys"
+            },
+            {
+                "content": "That's good. Can you find a restaurant with a per-person cost of 100-150 yuan serving Boiled fish in soup, Taro rolls and Roast duck? I'm going to change a place to enjoy tomorrow.",
+                "role": "usr"
+            },
+            {
+                "content": "Sorry, but we haven't found any restaurants that fully meet your needs. I recommend Youth Restaurant (Wuzi University) and you can have a try. The per-person cost of it is only 75 yuan and you can eat what you want.",
+                "role": "sys"
+            },
+            {
+                "content": "OK, it's much cheaper. I'm so satisfied. Where is it?",
+                "role": "usr"
+            },
+            {
+                "content": "It is at No.6, material College Road, Chaoyang North Road.",
+                "role": "sys"
+            },
+            {
+                "content": "Well, I got it. I need to find a place for my accommodation after dinner. Could you recommend a hotel with a rating of 5 points?",
+                "role": "usr"
+            },
+            {
+                "content": "No problem! Golden Phoenix Hotel is a very good one.",
+                "role": "sys"
+            },
+            {
+                "content": "Really? What are the nearby attractions around this hotel?",
+                "role": "usr"
+            },
+            {
+                "content": "Sorry, there is no attraction around it.",
+                "role": "sys"
+            },
+            {
+                "content": "I'm sorry to hear that. I want to find a free attraction with a rating of 4.5 points or above around it. What should I do?",
+                "role": "usr"
+            },
+            {
+                "content": "I'm so sorry, but there is no attraction around the hotel. I'd like to recommend another for you. GUI Street Snacks meets your needs. How do you like it?",
+                "role": "sys"
+            },
+            {
+                "content": "Well, it is fine. I decide to go there. Do you have its telephone number?",
+                "role": "usr"
+            },
+            {
+                "content": "Yes, their number 15210801573.",
+                "role": "sys"
+            },
+            {
+                "content": "Ok, I get it. Are there any other attractions around it?",
+                "role": "usr"
+            },
+            {
+                "content": "Well, there are a lot of them, including Prince Kung's Mansion and The Forbidden City. They are very famous.",
+                "role": "sys"
+            },
+            {
+                "content": "That sounds great. Thank you so much. Goodbye.",
+                "role": "usr"
+            },
+            {
+                "content": "You're welcome. Goodbye.",
+                "role": "sys"
+            }
+        ]
+    }
+}
\ No newline at end of file
diff --git a/data/multiwoz/db/hospital_db.json b/data/multiwoz/db/hospital_db.json
index 82fe62e887d95d78b05c9de5bff3208c55bff8b3..f8873e34de42b857c746266e1ff10dc52b872b29 100755
--- a/data/multiwoz/db/hospital_db.json
+++ b/data/multiwoz/db/hospital_db.json
@@ -2,331 +2,463 @@
     {
         "department": "neurosciences critical care unit",
         "id": 0,
-        "phone": "01223216297"
+        "phone": "01223216297",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "trauma high dependency unit",
         "id": 1,
-        "phone": "01223216305"
+        "phone": "01223216305",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "neurology neurosurgery",
         "id": 2,
-        "phone": "01223217216"
+        "phone": "01223217216",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "oncology neurosurgery",
         "id": 3,
-        "phone": "01223216314"
+        "phone": "01223216314",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "children's oncology and haematology",
         "id": 4,
-        "phone": "01223217231"
+        "phone": "01223217231",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "children's surgical and medicine",
         "id": 5,
-        "phone": "01223217450"
+        "phone": "01223217450",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "acute medicine for the elderly",
         "id": 6,
-        "phone": "01223217261"
+        "phone": "01223217261",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "general medicine and nephrology",
         "id": 7,
-        "phone": "01223217195"
+        "phone": "01223217195",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "medicine for the elderly",
         "id": 8,
-        "phone": "01223216988"
+        "phone": "01223216988",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "hepatobillary and gastrointestinal surgery regional referral centre",
         "id": 9,
-        "phone": "01223217300"
+        "phone": "01223217300",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "trauma and orthopaedics",
         "id": 10,
-        "phone": "01223217279"
+        "phone": "01223217279",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "teenage cancer trust unit",
         "id": 11,
-        "phone": "01223274222"
+        "phone": "01223274222",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "haematology and haematological oncology",
         "id": 12,
-        "phone": "01223217312"
+        "phone": "01223217312",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "children's surgical and medicine",
         "id": 13,
-        "phone": "01223217250"
+        "phone": "01223217250",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "intermediate dependancy area",
         "id": 14,
-        "phone": "01223348144"
+        "phone": "01223348144",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "hepatology",
         "id": 15,
-        "phone": "01223217712"
+        "phone": "01223217712",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "haematology",
         "id": 16,
-        "phone": "01223274679"
+        "phone": "01223274679",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "neurology",
         "id": 17,
-        "phone": "01223274680"
+        "phone": "01223274680",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "surgery",
         "id": 18,
-        "phone": "01223217303"
+        "phone": "01223217303",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "trauma and orthopaedics",
         "id": 19,
-        "phone": "01223217282"
+        "phone": "01223217282",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "oncology",
         "id": 20,
-        "phone": "01223217708"
+        "phone": "01223217708",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "infectious diseases",
         "id": 21,
-        "phone": "01223217314"
+        "phone": "01223217314",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "haematology day unit",
         "id": 22,
-        "phone": "01223348169"
+        "phone": "01223348169",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "clinical decisions unit",
         "id": 23,
-        "phone": "01223596203"
+        "phone": "01223596203",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "acute medical assessment unit",
         "id": 24,
-        "phone": "01223348314"
+        "phone": "01223348314",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "medical short stay unit",
         "id": 25,
-        "phone": "01223348336"
+        "phone": "01223348336",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "inpatient occupational therapy",
         "id": 26,
-        "phone": "01223216881"
+        "phone": "01223216881",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "paediatric day unit",
         "id": 27,
-        "phone": "01223217567"
+        "phone": "01223217567",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "paediatric clinic",
         "id": 28,
-        "phone": "01223348313"
+        "phone": "01223348313",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "medicine for the elderly",
         "id": 29,
-        "phone": "01223274744"
+        "phone": "01223274744",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "transplant high dependency unit",
         "id": 30,
-        "phone": "01223216811"
+        "phone": "01223216811",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "diabetes and endocrinology",
         "id": 31,
-        "phone": "01223217323"
+        "phone": "01223217323",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "infusion services",
         "id": 32,
-        "phone": "01223586967"
+        "phone": "01223586967",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "medicine for the elderly",
         "id": 33,
-        "phone": "01223217484"
+        "phone": "01223217484",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "medicine for the elderly",
         "id": 34,
-        "phone": "01223217498"
+        "phone": "01223217498",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "transplant unit",
         "id": 35,
-        "phone": "01223217711"
+        "phone": "01223217711",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "medicine for the elderly",
         "id": 36,
-        "phone": "01223217428"
+        "phone": "01223217428",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "theatre admissions unit",
         "id": 37,
-        "phone": "01223256583"
+        "phone": "01223256583",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "cardiology",
         "id": 38,
-        "phone": "01223256233"
+        "phone": "01223256233",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "major trauma unit",
         "id": 39,
-        "phone": "01223349881"
+        "phone": "01223349881",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "cardiology and coronary care unit",
         "id": 40,
-        "phone": "01223256459"
+        "phone": "01223256459",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "colorectal surgery",
         "id": 41,
-        "phone": "01223348545"
+        "phone": "01223348545",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "plastic and vascular surgery plastics",
         "id": 42,
-        "phone": "01223274280"
+        "phone": "01223274280",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "gastroenterology",
         "id": 43,
-        "phone": "01223274284"
+        "phone": "01223274284",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "oral and maxillofacial surgery and ent",
         "id": 44,
-        "phone": "01223348527"
+        "phone": "01223348527",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "urology",
         "id": 45,
-        "phone": "01223256650"
+        "phone": "01223256650",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "respiratory medicine",
         "id": 46,
-        "phone": "01223256645"
+        "phone": "01223256645",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "lewin stroke and rehabilitation unit",
         "id": 47,
-        "phone": "01223274750"
+        "phone": "01223274750",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "neurosciences",
         "id": 48,
-        "phone": "01223216348"
+        "phone": "01223216348",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "psychiatry",
         "id": 49,
-        "phone": "01223596201"
+        "phone": "01223596201",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "emergency department",
         "id": 50,
-        "phone": "01223217118"
+        "phone": "01223217118",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "cambridge eye unit",
         "id": 51,
-        "phone": "01223257168"
+        "phone": "01223257168",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "clinical investigation ward",
         "id": 52,
-        "phone": "01223586706"
+        "phone": "01223586706",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "clinical research facility",
         "id": 53,
-        "phone": "01223596055"
+        "phone": "01223596055",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "coronary care unit",
         "id": 54,
-        "phone": "01223217297"
+        "phone": "01223217297",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "intermediate dependency area",
         "id": 55,
-        "phone": "01223217873"
+        "phone": "01223217873",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "medical decisions unit",
         "id": 56,
-        "phone": "01223596066"
+        "phone": "01223596066",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "paediatric intensive care unit",
         "id": 57,
-        "phone": "01223217715"
+        "phone": "01223217715",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "paediatric day unit",
         "id": 58,
-        "phone": "01223257157"
+        "phone": "01223257157",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "john farman intensive care unit",
         "id": 59,
-        "phone": "01223256166"
+        "phone": "01223256166",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "delivery unit",
         "id": 60,
-        "phone": "01223217217"
+        "phone": "01223217217",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "postnatal",
         "id": 61,
-        "phone": "01223217667"
+        "phone": "01223217667",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "neonatal unit",
         "id": 62,
-        "phone": "01223217678"
+        "phone": "01223217678",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "antenatal",
         "id": 63,
-        "phone": "01223217671"
+        "phone": "01223217671",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "transitional care",
         "id": 64,
-        "phone": "01223254668"
+        "phone": "01223254668",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     },
     {
         "department": "gynaecology",
         "id": 65,
-        "phone": "01223257206"
+        "phone": "01223257206",
+        "address": "hills rd , cambridge",
+        "postcode": "cb20qq"
     }
 ]
diff --git a/data/multiwoz/db/police_db.json b/data/multiwoz/db/police_db.json
index dbe208f09942f74c89cdabc8510dae457a0d905f..e040cec446bbd98d1a145d4a0a49d487c7623fdf 100755
--- a/data/multiwoz/db/police_db.json
+++ b/data/multiwoz/db/police_db.json
@@ -3,6 +3,7 @@
         "name": "Parkside Police Station",
         "address": "Parkside, Cambridge",
         "id": 0,
-        "phone": "01223358966"
+        "phone": "01223358966",
+        "postcode": "cb11jg"
     }
 ]
diff --git a/data/multiwoz/goal/new_goal_model.pkl b/data/multiwoz/goal/new_goal_model.pkl
index dd9cfc652d3315b1b3d6b1950c32fc1a82b552ec..c1bfa6bf2243797f5c7a8b3fc64ede6516322480 100644
Binary files a/data/multiwoz/goal/new_goal_model.pkl and b/data/multiwoz/goal/new_goal_model.pkl differ
diff --git a/data/multiwoz/goal/new_goal_model_no_police_hospital.pkl b/data/multiwoz/goal/new_goal_model_no_police_hospital.pkl
new file mode 100644
index 0000000000000000000000000000000000000000..be2b3d6771f2eb024f3f924e248187176135b200
Binary files /dev/null and b/data/multiwoz/goal/new_goal_model_no_police_hospital.pkl differ
diff --git a/data/multiwoz_zh/dstc9_testset_example.json b/data/multiwoz_zh/dstc9_testset_example.json
new file mode 100644
index 0000000000000000000000000000000000000000..90d1f3cf798e97f0e58be526fd9042ed4a171705
--- /dev/null
+++ b/data/multiwoz_zh/dstc9_testset_example.json
@@ -0,0 +1,42 @@
+{
+    "144": {
+        "log": [
+            {
+                "text": "您好,我想参观本地市中心的大学。你能帮我推荐一个吗?"
+            },
+            {
+                "text": "市中心有很多大学,基督学院可以吗?"
+            },
+            {
+                "text": "我很感兴趣,请告诉我邮编。"
+            },
+            {
+                "text": "好的,邮编是cb23bu。"
+            },
+            {
+                "text": "我还需要一个住处,可以免费停车的四星级酒店,有推荐吗?"
+            },
+            {
+                "text": "我查到这里有很多酒店,您还有其他要求吗?"
+            },
+            {
+                "text": "您能帮我找个便宜的吗?"
+            },
+            {
+                "text": "好的,这里有很多便宜的酒店,我可以推荐您一个。艾伦拜尔很不错,4星级的。"
+            },
+            {
+                "text": "是什么样的酒店?你能告诉我电话吗?"
+            },
+            {
+                "text": "这是一家宾馆,您可以打01223210353了解一下。"
+            },
+            {
+                "text": "先这样,谢谢,再见!"
+            },
+            {
+                "text": "不客气,再见!"
+            }
+        ]
+    }
+}
\ No newline at end of file
diff --git a/setup.py b/setup.py
index b2ca3519160fecc781b96617b454a2b650e87bb2..b9c62d789db703180f5fa6b25adc68a79366dce3 100755
--- a/setup.py
+++ b/setup.py
@@ -34,6 +34,7 @@ setup(
         'nltk>=3.4',
         'tqdm>=4.30',
         'checksumdir>=1.1',
+        'dataclasses',
         'visdom',
         'Pillow',
         'future',
@@ -46,6 +47,7 @@ setup(
         'tensorflow==1.14',
         'tensorboard>=1.14.0',
         'tensorboardX==1.7',
+        'tokenizers>=0.8.0',
         'allennlp==0.9.0',
         'requests',
         'simplejson',
@@ -54,7 +56,9 @@ setup(
         'jieba',
         'embeddings',
         'quadprog',
-        'pyyaml'
+        'pyyaml',
+        'fuzzywuzzy',
+        'python-Levenshtein'
     ],
     extras_require={
         'develop': [
diff --git a/tests/test_BERTNLU-RuleDST-RulePolicy-SCLSTM.py b/tests/test_BERTNLU-RuleDST-RulePolicy-SCLSTM.py
index 0588dd75b1158df8704c95480143d43834e6433e..521fea7912ee20137aee7f1c163428fe1821d808 100755
--- a/tests/test_BERTNLU-RuleDST-RulePolicy-SCLSTM.py
+++ b/tests/test_BERTNLU-RuleDST-RulePolicy-SCLSTM.py
@@ -67,7 +67,7 @@ def test_end2end():
     analyzer = Analyzer(user_agent=user_agent, dataset='multiwoz')
 
     set_seed(20200202)
-    analyzer.comprehensive_analyze(sys_agent=sys_agent, model_name='BERTNLU-RuleDST-RulePolicy-TemplateNLG', total_dialog=1000)
+    analyzer.comprehensive_analyze(sys_agent=sys_agent, model_name='BERTNLU-RuleDST-RulePolicy-SCLSTM', total_dialog=1000)
 
 if __name__ == '__main__':
     test_end2end()
\ No newline at end of file
diff --git a/tests/test_end2end.py b/tests/test_end2end.py
index c07b2865fc013fb46b1dc2ca4d1ba95240df969e..2aef3217af17ac2726b501d03d15cecda8ae92c3 100755
--- a/tests/test_end2end.py
+++ b/tests/test_end2end.py
@@ -67,7 +67,7 @@ def test_end2end():
     analyzer = Analyzer(user_agent=user_agent, dataset='multiwoz')
 
     set_seed(20200202)
-    analyzer.comprehensive_analyze(sys_agent=sys_agent, model_name='BERTNLU-RuleDST-RulePolicy-TemplateNLG', total_dialog=1000)
+    analyzer.comprehensive_analyze(sys_agent=sys_agent, model_name='end2end', total_dialog=100)
 
 if __name__ == '__main__':
     test_end2end()