def __init__(self, args): """ Initializes the internal structures of the Agenda-Based Usr Simulator :param args: a dictionary containing an ontology, a database, and other necessary arguments """ super(AgendaBasedUS, self).__init__() if 'ontology' not in args: raise AttributeError('AgendaBasedUS: Please provide ontology!') if 'database' not in args: raise AttributeError('AgendaBasedUS: Please provide database!') ontology = args['ontology'] database = args['database'] um = None if 'um' in args: um = args['um'] self.nlu = None self.nlg = None self.dialogue_turn = 0 self.us_has_initiative = False self.policy = None self.goals_path = None if um is not None: self.user_model = um self.ontology = None if isinstance(ontology, Ontology): self.ontology = ontology elif isinstance(ontology, str): self.ontology = Ontology(ontology) else: raise ValueError('Unacceptable ontology type %s ' % ontology) self.database = None if isinstance(database, DataBase): self.database = database elif isinstance(database, str): if database[-3:] == '.db': self.database = SQLDataBase(database) elif database[-5:] == '.json': self.database = JSONDataBase(database) else: raise ValueError('Unacceptable database type %s ' % database) else: raise ValueError('Unacceptable database type %s ' % database) self.patience = 3 # Initialize probabilities if 'patience' in args: self.patience = args['patience'] if 'pop_distribution' in args: self.pop_distribution = args['pop_distribution'] if 'slot_confuse_prob' in args: self.slot_confuse_prob = args['slot_confuse_prob'] if 'op_confuse_prob' in args: self.op_confuse_prob = args['op_confuse_prob'] if 'value_confuse_prob' in args: self.value_confuse_prob = args['value_confuse_prob'] self.goal_slot_selection_weights = None if 'goal_slot_selection_weights' in args: self.goal_slot_selection_weights = \ args['goal_slot_selection_weights'] if 'nlu' in args: nlu_args = \ dict(zip(['ontology', 'database'], [self.ontology, self.database])) if args['nlu'] == 'CamRest': self.nlu = CamRestNLU(nlu_args) elif args['nlu'] == 'dummy': self.nlu = DummyNLU(nlu_args) if 'nlg' in args: if args['nlg'] == 'CamRest': if args['nlg_model_path'] and args['nlg_metadata_path']: self.nlg = \ CamRestNLG({'model_path': args['nlg_model_path']}) else: raise ValueError('ABUS: Cannot initialize CamRest NLG ' 'without a model path AND a metadata ' 'path.') elif args['nlg'] == 'dummy': self.nlg = DummyNLG() if 'goals_path' in args: self.goals_path = args['goals_path'] if 'policy_file' in args: self.load(args['policy_file']) if 'us_has_initiative' in args: self.us_has_initiative = args['us_has_initiative'] self.curr_patience = self.patience # Default values for probabilities self.pop_distribution = [1.0] self.slot_confuse_prob = 0.0 self.op_confuse_prob = 0.0 self.value_confuse_prob = 0.0 self.agenda = Agenda.Agenda() self.error_model = ErrorModel.ErrorModel(self.ontology, self.database, self.slot_confuse_prob, self.op_confuse_prob, self.value_confuse_prob) self.goal_generator = Goal.GoalGenerator(self.ontology, self.database, self.goals_path) self.goal = None self.offer_made = False self.prev_offer_name = None # Store previous system actions to keep track of patience self.prev_system_acts = None
def __init__(self, configuration, agent_id): """ Initialize the internal structures of this agent. :param configuration: a dictionary representing the configuration file :param agent_id: an integer, this agent's id """ super(ConversationalMultiAgent, self).__init__() self.agent_id = agent_id # Flag to alternate training between roles self.train_system = True # Dialogue statistics self.dialogue_episode = 1 # Note that since this is a multi-agent setting, dialogue_turn refers # to this agent's turns only self.dialogue_turn = 0 self.num_successful_dialogues = 0 self.num_task_success = 0 self.cumulative_rewards = 0 self.total_dialogue_turns = 0 self.minibatch_length = 200 self.train_interval = 50 self.train_epochs = 3 # Alternate training between the agents self.train_alternate_training = True self.train_switch_trainable_agents_every = self.train_interval self.configuration = configuration # True values here would imply some default modules self.USE_USR_SIMULATOR = False self.USER_SIMULATOR_NLG = False self.USE_NLU = False self.USE_NLG = False self.USE_SPEECH = False self.USER_HAS_INITIATIVE = True self.SAVE_LOG = True # The dialogue will terminate after MAX_TURNS (this agent will issue # a bye() dialogue act. self.MAX_TURNS = 10 self.ontology = None self.database = None self.domain = None self.dialogue_manager = None self.user_model = None self.nlu = None self.nlg = None self.agent_role = None self.agent_goal = None self.goal_generator = None self.goals_path = None self.prev_state = None self.curr_state = None self.prev_usr_utterance = None self.prev_sys_utterance = None self.prev_action = None self.prev_reward = None self.prev_success = None self.prev_task_success = None self.user_model = UserModel() # The size of the experience pool is a hyperparameter. # Do not have an experience window larger than the current batch, # as past experience may not be relevant since both agents learn. self.recorder = DialogueEpisodeRecorder(size=self.minibatch_length) # TODO: Get reward type from the config self.reward_func = SlotFillingReward() # self.reward_func = SlotFillingGoalAdvancementReward() if self.configuration: agent_id_str = 'AGENT_' + str(self.agent_id) # Error checks for options the config must have if not self.configuration['GENERAL']: raise ValueError('Cannot run Plato without GENERAL settings!') elif not self.configuration['GENERAL']['interaction_mode']: raise ValueError('Cannot run Plato without an interaction ' 'mode!') elif not self.configuration['DIALOGUE']: raise ValueError('Cannot run Plato without DIALOGUE settings!') elif not self.configuration[agent_id_str]: raise ValueError('Cannot run Plato without at least ' 'one agent!') # Dialogue domain self.settings if 'DIALOGUE' in self.configuration and \ self.configuration['DIALOGUE']: if 'initiative' in self.configuration['DIALOGUE']: self.USER_HAS_INITIATIVE = bool( self.configuration['DIALOGUE']['initiative'] == 'user') if self.configuration['DIALOGUE']['domain']: self.domain = self.configuration['DIALOGUE']['domain'] if self.configuration['DIALOGUE']['ontology_path']: if os.path.isfile( self.configuration['DIALOGUE']['ontology_path']): self.ontology = \ Ontology.Ontology( self.configuration['DIALOGUE']['ontology_path'] ) else: raise FileNotFoundError( 'Domain file %s not ' 'found' % self.configuration['DIALOGUE']['ontology_path']) if self.configuration['DIALOGUE']['db_path']: if os.path.isfile( self.configuration['DIALOGUE']['db_path']): if 'db_type' in self.configuration['DIALOGUE']: if self.configuration['DIALOGUE']['db_type'] == \ 'sql': self.database = DataBase.SQLDataBase( self.configuration['DIALOGUE']['db_path']) else: self.database = DataBase.DataBase( self.configuration['DIALOGUE']['db_path']) else: # Default to SQL self.database = DataBase.SQLDataBase( self.configuration['DIALOGUE']['db_path']) else: raise FileNotFoundError( 'Database file %s not ' 'found' % self.configuration['DIALOGUE']['db_path']) if 'goals_path' in self.configuration['DIALOGUE']: if os.path.isfile( self.configuration['DIALOGUE']['goals_path']): self.goals_path = \ self.configuration['DIALOGUE']['goals_path'] else: raise FileNotFoundError( 'Goals file %s not ' 'found' % self.configuration['DIALOGUE']['goals_path']) # General settings if 'GENERAL' in self.configuration and \ self.configuration['GENERAL']: if 'experience_logs' in self.configuration['GENERAL']: dialogues_path = None if 'path' in \ self.configuration['GENERAL']['experience_logs']: dialogues_path = \ self.configuration['GENERAL'][ 'experience_logs']['path'] if 'load' in \ self.configuration['GENERAL'][ 'experience_logs'] and \ bool( self.configuration[ 'GENERAL' ]['experience_logs']['load'] ): if dialogues_path and os.path.isfile(dialogues_path): self.recorder.load(dialogues_path) else: raise FileNotFoundError( 'Dialogue Log file %s not found (did you ' 'provide one?)' % dialogues_path) if 'save' in \ self.configuration['GENERAL']['experience_logs']: self.recorder.set_path(dialogues_path) self.SAVE_LOG = bool(self.configuration['GENERAL'] ['experience_logs']['save']) if self.configuration['GENERAL']['interaction_mode'] == \ 'simulation': self.USE_USR_SIMULATOR = True # NLU Settings if 'NLU' in self.configuration[agent_id_str] and \ self.configuration[agent_id_str]['NLU'] and \ self.configuration[agent_id_str]['NLU']['nlu']: nlu_args = dict( zip(['ontology', 'database'], [self.ontology, self.database])) if self.configuration[agent_id_str]['NLU']['nlu'] == 'dummy': self.nlu = DummyNLU(nlu_args) self.USE_NLU = True elif self.configuration[agent_id_str]['NLU']['nlu'] == \ 'CamRest': if self.configuration[agent_id_str]['NLU']['model_path']: nlu_args['model_path'] = \ self.configuration[ agent_id_str ]['NLU']['model_path'] self.nlu = CamRestNLU(nlu_args) self.USE_NLU = True else: raise ValueError( 'Cannot find model_path in the config.') # NLG Settings if 'NLG' in self.configuration[agent_id_str] and \ self.configuration[agent_id_str]['NLG'] and \ self.configuration[agent_id_str]['NLG']['nlg']: if self.configuration[agent_id_str]['NLG']['nlg'] == 'dummy': self.nlg = DummyNLG() elif self.configuration[agent_id_str]['NLG']['nlg'] == \ 'CamRest': if self.configuration[agent_id_str]['NLG']['model_path']: self.nlg = CamRestNLG({ 'model_path': self.configuration[agent_id_str]['NLG'] ['model_path'] }) else: raise ValueError( 'Cannot find model_path in the config.') if self.nlg: self.USE_NLG = True # Retrieve agent role if 'role' in self.configuration[agent_id_str]: self.agent_role = self.configuration[agent_id_str]['role'] else: raise ValueError('ConversationalMultiAgent: No role assigned ' 'for agent {0} in ' 'config!'.format(self.agent_id)) if self.agent_role == 'user': if self.ontology and self.database: self.goal_generator = GoalGenerator( ontology=self.ontology, database=self.database, goals_file=self.goals_path) else: raise ValueError('Conversational Multi Agent (user): ' 'Cannot generate goal without ontology ' 'and database.') dm_args = dict( zip([ 'settings', 'ontology', 'database', 'domain', 'agent_id', 'agent_role' ], [ self.configuration, self.ontology, self.database, self.domain, self.agent_id, self.agent_role ])) dm_args.update(self.configuration['AGENT_' + str(agent_id)]['DM']) self.dialogue_manager = DialogueManager.DialogueManager(dm_args)
class AgendaBasedUS(UserSimulator.UserSimulator): """ Implementation of the Agenda Based Usr Simulator. """ def __init__(self, args): """ Initializes the internal structures of the Agenda-Based Usr Simulator :param args: a dictionary containing an ontology, a database, and other necessary arguments """ super(AgendaBasedUS, self).__init__() if 'ontology' not in args: raise AttributeError('AgendaBasedUS: Please provide ontology!') if 'database' not in args: raise AttributeError('AgendaBasedUS: Please provide database!') ontology = args['ontology'] database = args['database'] um = None if 'um' in args: um = args['um'] self.nlu = None self.nlg = None self.dialogue_turn = 0 self.us_has_initiative = False self.policy = None self.goals_path = None if um is not None: self.user_model = um self.ontology = None if isinstance(ontology, Ontology): self.ontology = ontology elif isinstance(ontology, str): self.ontology = Ontology(ontology) else: raise ValueError('Unacceptable ontology type %s ' % ontology) self.database = None if isinstance(database, DataBase): self.database = database elif isinstance(database, str): if database[-3:] == '.db': self.database = SQLDataBase(database) elif database[-5:] == '.json': self.database = JSONDataBase(database) else: raise ValueError('Unacceptable database type %s ' % database) else: raise ValueError('Unacceptable database type %s ' % database) self.patience = 3 # Initialize probabilities if 'patience' in args: self.patience = args['patience'] if 'pop_distribution' in args: self.pop_distribution = args['pop_distribution'] if 'slot_confuse_prob' in args: self.slot_confuse_prob = args['slot_confuse_prob'] if 'op_confuse_prob' in args: self.op_confuse_prob = args['op_confuse_prob'] if 'value_confuse_prob' in args: self.value_confuse_prob = args['value_confuse_prob'] self.goal_slot_selection_weights = None if 'goal_slot_selection_weights' in args: self.goal_slot_selection_weights = \ args['goal_slot_selection_weights'] if 'nlu' in args: nlu_args = \ dict(zip(['ontology', 'database'], [self.ontology, self.database])) if args['nlu'] == 'CamRest': self.nlu = CamRestNLU(nlu_args) elif args['nlu'] == 'dummy': self.nlu = DummyNLU(nlu_args) if 'nlg' in args: if args['nlg'] == 'CamRest': if args['nlg_model_path'] and args['nlg_metadata_path']: self.nlg = \ CamRestNLG({'model_path': args['nlg_model_path']}) else: raise ValueError('ABUS: Cannot initialize CamRest NLG ' 'without a model path AND a metadata ' 'path.') elif args['nlg'] == 'dummy': self.nlg = DummyNLG() if 'goals_path' in args: self.goals_path = args['goals_path'] if 'policy_file' in args: self.load(args['policy_file']) if 'us_has_initiative' in args: self.us_has_initiative = args['us_has_initiative'] self.curr_patience = self.patience # Default values for probabilities self.pop_distribution = [1.0] self.slot_confuse_prob = 0.0 self.op_confuse_prob = 0.0 self.value_confuse_prob = 0.0 self.agenda = Agenda.Agenda() self.error_model = ErrorModel.ErrorModel(self.ontology, self.database, self.slot_confuse_prob, self.op_confuse_prob, self.value_confuse_prob) self.goal_generator = Goal.GoalGenerator(self.ontology, self.database, self.goals_path) self.goal = None self.offer_made = False self.prev_offer_name = None # Store previous system actions to keep track of patience self.prev_system_acts = None def initialize(self, args): """ Initializes the user simulator, e.g. before each dialogue episode. :return: Nothing """ if 'goal' not in args: # Sample Goal goal_slot_selection_weights = None if 'goal_slot_selection_weights' in args: goal_slot_selection_weights = \ args['goal_slot_selection_weights'] self.goal = \ self.goal_generator.generate( goal_slot_selection_weights=goal_slot_selection_weights) else: self.goal = deepcopy(args['goal']) # Initialize agenda and user state self.agenda.initialize(deepcopy(self.goal)) if self.nlu: self.nlu.initialize({}) if self.nlg: self.nlg.initialize({}) self.prev_system_acts = None self.curr_patience = self.patience self.dialogue_turn = 0 self.offer_made = False self.prev_offer_name = None def receive_input(self, inpt, goal=None): """ Receives and processes the input (i.e. the system's response) and updates the simulator's internal state. :param inpt: list of dialogue acts representing input from the system :param goal: the simulated user's goal :return: Nothing """ if self.nlu and isinstance(inpt, str): system_acts = self.nlu.process_input(inpt) else: system_acts = inpt if goal: self.goal = goal self.dialogue_turn += 1 # TODO: AVOID RE-CHECKING THIS IN THE HANDCRAFTED POLICY # Update user goal (in ABUS the state is factored into the goal and # the agenda) for system_act in system_acts: if system_act.intent == 'offer': self.offer_made = True # Reset past requests if self.prev_offer_name and \ system_act.params and \ system_act.params[0].slot and \ system_act.params[0].slot == 'name' and \ system_act.params[0].value and \ self.prev_offer_name != system_act.params[0].value: self.prev_offer_name = system_act.params[0].value self.goal.actual_requests = {} for item in self.goal.requests: item.value = '' if self.policy: self.receive_input_policy(system_acts) else: self.receive_input_handcrafted(system_acts) self.agenda.consistency_check() def receive_input_policy(self, system_acts): """ Handle the input according to a policy :param system_acts: a list with the system's dialogue acts :return: Nothing """ if self.prev_system_acts and self.prev_system_acts == system_acts: self.curr_patience -= 1 else: self.curr_patience = self.patience self.prev_system_acts = deepcopy(system_acts) for system_act in system_acts: # 'bye' doesn't seem to appear in the CamRest data if system_act.intent == 'bye' or self.curr_patience == 0 or \ self.dialogue_turn > 15: self.agenda.push(DialogueAct('bye', [])) return sys_act_slot = 'inform' if system_act.intent == 'offer' else \ system_act.intent if system_act.params and system_act.params[0].slot: sys_act_slot += '_' + system_act.params[0].slot # Attempt to recover if sys_act_slot not in self.policy: if sys_act_slot == 'inform_name': sys_act_slot = 'offer_name' if sys_act_slot not in self.policy: if system_act.intent == 'inform' and system_act.params and \ system_act.params[0].slot in self.goal.constraints: user_act_slots = ['inform_' + system_act.params[0].slot] else: print('Warning! ABUS policy does not know what to do for' ' %s' % sys_act_slot) return else: dacts = list(self.policy[sys_act_slot]['dacts'].keys()) probs = [self.policy[sys_act_slot]['dacts'][i] for i in dacts] user_act_slots = random.choices(dacts, weights=probs) for user_act_slot in user_act_slots: intent, slot = user_act_slot.split('_') if slot == 'this' and system_act.params and \ system_act.params[0].slot: slot = system_act.params[0].slot value = '' if intent == 'inform': if slot in self.goal.constraints: value = self.goal.constraints[slot].value else: value = 'dontcare' dact = \ DialogueAct(intent, [DialogueActItem(slot, Operator.EQ, value)]) self.agenda.remove(dact) self.agenda.push(dact) def receive_input_handcrafted(self, system_acts): """ Handle the input according to probabilistic rules :param system_acts: a list with the system's dialogue acts :return: Nothing """ # TODO: Revise these rules wrt other operators (i.e. not only EQ) if self.prev_system_acts and self.prev_system_acts == system_acts: self.curr_patience -= 1 else: self.curr_patience = self.patience self.prev_system_acts = deepcopy(system_acts) for system_act in system_acts: # Update user goal (in ABUS the state is factored into the goal # and the agenda) if system_act.intent == 'bye' or self.dialogue_turn > 15: self.agenda.clear() self.agenda.push(DialogueAct('bye', [])) elif system_act.intent in ['inform', 'offer']: # Check that the venue provided meets the constraints meets_constraints = True for item in system_act.params: if item.slot in self.goal.constraints and \ self.goal.constraints[item.slot].value != \ 'dontcare': # Remove the inform from the agenda, assuming the # value provided is correct. If it is not, the # act will be pushed again and will be on top of the # agenda (this way we avoid adding / removing # twice. dact = \ DialogueAct( 'inform', [DialogueActItem( deepcopy(item.slot), deepcopy( self.goal.constraints[item.slot].op), deepcopy( self.goal.constraints[ item.slot].value))]) # Remove and push to make sure the act is on top - # if it already exists self.agenda.remove(dact) if item.value != \ self.goal.constraints[item.slot].value: meets_constraints = False # For each violated constraint add an inform # TODO: Make this a deny-inform or change # operator to NE self.agenda.push(dact) # If it meets the constraints, update the requests if meets_constraints: for item in system_act.params: if item.slot in self.goal.actual_requests: self.goal.actual_requests[item.slot].value = \ item.value # Mark the value only if the slot has been # requested and is in the requests if item.slot in self.goal.requests: self.goal.requests[item.slot].value = \ item.value # Remove any requests from the agenda that ask # for that slot # TODO: Revise this for all operators self.agenda.remove( DialogueAct('request', [ DialogueActItem(item.slot, Operator.EQ, '') ])) # When the system makes a new offer, replace all requests in # the agenda if system_act.intent == 'offer': for r in self.goal.requests: req = deepcopy(self.goal.requests[r]) req_dact = DialogueAct('request', [req]) # The agenda will replace the old act first self.agenda.push(req_dact) # Push appropriate acts into the agenda elif system_act.intent == 'request': if system_act.params: for item in system_act.params: if item.slot in self.goal.constraints: self.agenda.push( DialogueAct('inform', [ DialogueActItem( deepcopy(item.slot), deepcopy(self.goal.constraints[ item.slot].op), deepcopy(self.goal.constraints[ item.slot].value)) ])) else: self.agenda.push( DialogueAct('inform', [ DialogueActItem(deepcopy(item.slot), Operator.EQ, 'dontcare') ])) # TODO Relax goals if system returns no info for name def respond(self): """ Creates the response of the simulated user. :return: List of DialogueActs as a response """ if self.curr_patience == 0: if self.nlg: return self.nlg.generate_output({ 'dacts': [DialogueAct('bye', [])], 'system': False }) else: return [DialogueAct('bye', [])] # Sample the number of acts to pop. acts = [] pops = min( random.choices(range(1, len(self.pop_distribution) + 1), weights=self.pop_distribution)[0], self.agenda.size()) for pop in range(pops): act = self.error_model.semantic_noise(self.agenda.pop()) # Keep track of actual requests made. These are used in reward and # success calculation if act.intent == 'request' and act.params: self.goal.actual_requests[act.params[0].slot] = act.params[0] acts.append(act) if self.nlg: acts = self.nlg.generate_output({'dacts': acts, 'system': False}) return acts def train(self, data): """ Placeholder for training models :param data: dialogue experience :return: nothing """ pass def save(self, path=None): """ Placeholder for saving trained models :param path: path to save the models :return: nothing """ pass def load(self, path): """ Load an Agenda-Based Simulated Usr policy :param path: path to the policy file :return: nothing """ if isinstance(path, str): if os.path.isfile(path): with open(path, 'rb') as file: obj = pickle.load(file) if 'policy' in obj: self.policy = obj['policy'] print('ABUS policy loaded.') else: raise FileNotFoundError('ABUS policy file %s not found' % path) else: raise ValueError('Unacceptable ABUS policy file name: %s ' % path) def at_terminal_state(self): """ Check if the Agenda-Based Simulated Usr is at a terminal state :return: True or False """ return not self.agenda.agenda
def __init__(self, configuration): """ Initialize the internal structures of this agent. :param configuration: a dictionary representing the configuration file :param agent_id: an integer, this agent's id """ super(ConversationalSingleAgent, self).__init__() self.configuration = configuration # There is only one agent in this setting self.agent_id = 0 # Dialogue statistics self.dialogue_episode = 0 self.dialogue_turn = 0 self.num_successful_dialogues = 0 self.num_task_success = 0 self.cumulative_rewards = 0 self.total_dialogue_turns = 0 self.minibatch_length = 500 self.train_interval = 50 self.train_epochs = 10 # True values here would imply some default modules self.USE_USR_SIMULATOR = False self.USER_SIMULATOR_NLU = False self.USER_SIMULATOR_NLG = False self.USE_NLG = False self.USE_SPEECH = False self.USER_HAS_INITIATIVE = True self.SAVE_LOG = True # The dialogue will terminate after MAX_TURNS (this agent will issue # a bye() dialogue act. self.MAX_TURNS = 15 self.dialogue_turn = -1 self.ontology = None self.database = None self.domain = None self.dialogue_manager = None self.user_model = None self.user_simulator = None self.user_simulator_args = {} self.nlu = None self.nlg = None self.agent_role = None self.agent_goal = None self.goal_generator = None self.curr_state = None self.prev_state = None self.curr_state = None self.prev_usr_utterance = None self.prev_sys_utterance = None self.prev_action = None self.prev_reward = None self.prev_success = None self.prev_task_success = None self.user_model = UserModel() self.recorder = DialogueEpisodeRecorder() # TODO: Handle this properly - get reward function type from config self.reward_func = SlotFillingReward() # self.reward_func = SlotFillingGoalAdvancementReward() if self.configuration: # Error checks for options the config must have if not self.configuration['GENERAL']: raise ValueError('Cannot run Plato without GENERAL settings!') elif not self.configuration['GENERAL']['interaction_mode']: raise ValueError('Cannot run Plato without an ' 'interaction mode!') elif not self.configuration['DIALOGUE']: raise ValueError('Cannot run Plato without DIALOGUE settings!') elif not self.configuration['AGENT_0']: raise ValueError('Cannot run Plato without at least ' 'one agent!') # Dialogue domain self.settings if 'DIALOGUE' in self.configuration and \ self.configuration['DIALOGUE']: if 'initiative' in self.configuration['DIALOGUE']: self.USER_HAS_INITIATIVE = bool( self.configuration['DIALOGUE']['initiative'] == 'user') self.user_simulator_args['us_has_initiative'] = \ self.USER_HAS_INITIATIVE if self.configuration['DIALOGUE']['domain']: self.domain = self.configuration['DIALOGUE']['domain'] if self.configuration['DIALOGUE']['ontology_path']: if os.path.isfile( self.configuration['DIALOGUE']['ontology_path']): self.ontology = Ontology.Ontology( self.configuration['DIALOGUE']['ontology_path']) else: raise FileNotFoundError( 'Domain file %s not found' % self.configuration['DIALOGUE']['ontology_path']) if self.configuration['DIALOGUE']['db_path']: if os.path.isfile( self.configuration['DIALOGUE']['db_path']): if 'db_type' in self.configuration['DIALOGUE']: if self.configuration['DIALOGUE']['db_type'] == \ 'sql': self.database = DataBase.SQLDataBase( self.configuration['DIALOGUE']['db_path']) else: self.database = DataBase.DataBase( self.configuration['DIALOGUE']['db_path']) else: # Default to SQL self.database = DataBase.SQLDataBase( self.configuration['DIALOGUE']['db_path']) else: raise FileNotFoundError( 'Database file %s not found' % self.configuration['DIALOGUE']['db_path']) if 'goals_path' in self.configuration['DIALOGUE']: if os.path.isfile( self.configuration['DIALOGUE']['goals_path']): self.goals_path = \ self.configuration['DIALOGUE']['goals_path'] else: raise FileNotFoundError( 'Goals file %s not found' % self.configuration['DIALOGUE']['goals_path']) # General settings if 'GENERAL' in self.configuration and \ self.configuration['GENERAL']: if 'experience_logs' in self.configuration['GENERAL']: dialogues_path = None if 'path' in \ self.configuration['GENERAL']['experience_logs']: dialogues_path = \ self.configuration['GENERAL'][ 'experience_logs']['path'] if 'load' in \ self.configuration['GENERAL']['experience_logs'] \ and bool( self.configuration['GENERAL'][ 'experience_logs']['load'] ): if dialogues_path and os.path.isfile(dialogues_path): self.recorder.load(dialogues_path) else: raise FileNotFoundError( 'Dialogue Log file %s not found (did you ' 'provide one?)' % dialogues_path) if 'save' in \ self.configuration['GENERAL']['experience_logs']: self.recorder.set_path(dialogues_path) self.SAVE_LOG = bool(self.configuration['GENERAL'] ['experience_logs']['save']) if self.configuration['GENERAL']['interaction_mode'] == \ 'simulation': self.USE_USR_SIMULATOR = True elif self.configuration['GENERAL']['interaction_mode'] == \ 'speech': self.USE_SPEECH = True self.asr = speech_rec.Recognizer() # Agent Settings # Usr Simulator # Check for specific simulator self.settings, otherwise # default to agenda if 'USER_SIMULATOR' in self.configuration['AGENT_0']: # Agent 0 simulator configuration a0_sim_config = self.configuration['AGENT_0']['USER_SIMULATOR'] if a0_sim_config and a0_sim_config['simulator']: # Default settings self.user_simulator_args['ontology'] = self.ontology self.user_simulator_args['database'] = self.database self.user_simulator_args['um'] = self.user_model self.user_simulator_args['patience'] = 5 if a0_sim_config['simulator'] == 'agenda': if 'patience' in a0_sim_config: self.user_simulator_args['patience'] = \ int(a0_sim_config['patience']) if 'pop_distribution' in a0_sim_config: if isinstance(a0_sim_config['pop_distribution'], list): self.user_simulator_args['pop_distribution'] =\ a0_sim_config['pop_distribution'] else: self.user_simulator_args['pop_distribution'] =\ eval(a0_sim_config['pop_distribution']) if 'slot_confuse_prob' in a0_sim_config: self.user_simulator_args['slot_confuse_prob'] = \ float(a0_sim_config['slot_confuse_prob']) if 'op_confuse_prob' in a0_sim_config: self.user_simulator_args['op_confuse_prob'] = \ float(a0_sim_config['op_confuse_prob']) if 'value_confuse_prob' in a0_sim_config: self.user_simulator_args['value_confuse_prob'] = \ float(a0_sim_config['value_confuse_prob']) if 'goal_slot_selection_weights' in a0_sim_config: self.user_simulator_args[ 'goal_slot_selection_weights'] = a0_sim_config[ 'goal_slot_selection_weights'] if 'nlu' in a0_sim_config: self.user_simulator_args['nlu'] = \ a0_sim_config['nlu'] if self.user_simulator_args['nlu'] == 'dummy': self.user_simulator_args['database'] = \ self.database self.USER_SIMULATOR_NLU = True if 'nlg' in a0_sim_config: self.user_simulator_args['nlg'] = \ a0_sim_config['nlg'] if self.user_simulator_args['nlg'] == 'CamRest': if a0_sim_config: self.user_simulator_args[ 'nlg_model_path'] = a0_sim_config[ 'nlg_model_path'] self.USER_SIMULATOR_NLG = True else: raise ValueError( 'Usr Simulator NLG: Cannot find ' 'model_path in the config.') elif self.user_simulator_args['nlg'] == 'dummy': self.USER_SIMULATOR_NLG = True if 'goals_file' in a0_sim_config: self.user_simulator_args['goals_file'] = \ a0_sim_config['goals_file'] if 'policy_file' in a0_sim_config: self.user_simulator_args['policy_file'] = \ a0_sim_config['policy_file'] self.user_simulator = AgendaBasedUS( self.user_simulator_args) elif a0_sim_config['simulator'] == 'dtl': if 'policy_file' in a0_sim_config: self.user_simulator_args['policy_file'] = \ a0_sim_config['policy_file'] self.user_simulator = DTLUserSimulator( self.user_simulator_args) else: raise ValueError( 'Error! Cannot start DAct-to-Language ' 'simulator without a policy file!') else: # Fallback to agenda based simulator with default settings self.user_simulator = AgendaBasedUS( self.user_simulator_args) # NLU Settings if 'NLU' in self.configuration['AGENT_0'] and \ self.configuration['AGENT_0']['NLU'] and \ self.configuration['AGENT_0']['NLU']['nlu']: nlu_args = dict( zip(['ontology', 'database'], [self.ontology, self.database])) if self.configuration['AGENT_0']['NLU']['nlu'] == 'dummy': self.nlu = DummyNLU(nlu_args) elif self.configuration['AGENT_0']['NLU']['nlu'] == 'CamRest': if self.configuration['AGENT_0']['NLU']['model_path']: nlu_args['model_path'] = \ self.configuration['AGENT_0']['NLU']['model_path'] self.nlu = CamRestNLU(nlu_args) else: raise ValueError( 'Cannot find model_path in the config.') # NLG Settings if 'NLG' in self.configuration['AGENT_0'] and \ self.configuration['AGENT_0']['NLG'] and \ self.configuration['AGENT_0']['NLG']['nlg']: if self.configuration['AGENT_0']['NLG']['nlg'] == 'dummy': self.nlg = DummyNLG() elif self.configuration['AGENT_0']['NLG']['nlg'] == 'CamRest': if self.configuration['AGENT_0']['NLG']['model_path']: self.nlg = CamRestNLG({ 'model_path': self.configuration['AGENT_0']['NLG']['model_path'] }) else: raise ValueError( 'Cannot find model_path in the config.') if self.nlg: self.USE_NLG = True # Retrieve agent role if 'role' in self.configuration['AGENT_0']: self.agent_role = self.configuration['AGENT_0']['role'] else: raise ValueError( 'ConversationalAgent: No role assigned for agent {0} in ' 'config!'.format(self.agent_id)) if self.agent_role == 'user': if self.ontology and self.database: self.goal_generator = GoalGenerator(ontology=self.ontology, database=self.database) else: raise ValueError( 'Conversational Multi Agent (user): Cannot generate ' 'goal without ontology and database.') dm_args = dict( zip([ 'settings', 'ontology', 'database', 'domain', 'agent_id', 'agent_role' ], [ self.configuration, self.ontology, self.database, self.domain, self.agent_id, self.agent_role ])) dm_args.update(self.configuration['AGENT_0']['DM']) self.dialogue_manager = DialogueManager.DialogueManager(dm_args)