def run(config):
    """
    This script will create a data-specific parser, and run it.
    """

    if not config:
        raise AttributeError('Please provide a path to the data. For'
                             'example: <PATH...>/DSTC2/dstc2_traindev/data/')

    if config[-5:] == '.yaml':
        config = check_file_path(config)

        with open(config, 'r') as file:
            args = yaml.load(file, Loader=yaml.Loader)

    else:
        raise ValueError('Unacceptable config file type for data parser.')

    if 'package' not in args:
        raise AttributeError('Please provide a "package" argument for '
                             'data parser!')

    if 'class' not in args:
        raise AttributeError('Please provide a "class" argument for '
                             'data parser!')

    if 'arguments' not in args:
        print(f'Warning! Data Parser {args["package"]}.'
              f'{args["class"]} called without arguments!')

        args['arguments'] = {}

    parser = ConversationalGenericAgent.load_module(args['package'],
                                                    args['class'],
                                                    args['arguments'])

    parser.initialize(**args['arguments'])

    print('Parsing...')

    parser.parse_data()

    print('Parsing complete.')

    # Save plato experience logs
    parser.save(f'logs/')

    print('Logs saved.')
Пример #2
0
    def __init__(self, configuration):
        """
        Initialize the internal structures of this agent.

        :param configuration: a dictionary representing the configuration file
        """

        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

        # Default meta-parameter values
        self.minibatch_length = 500
        self.train_interval = 50
        self.train_epochs = 3

        # 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
        self.SAVE_INTERVAL = 10000

        # 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.global_args = {}
        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 'ontology_path' in self.configuration['DIALOGUE']:
                    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'])

                # Alternatively, look at global_arguments for ontology path
                elif 'global_arguments' in self.configuration['GENERAL'] \
                        and 'ontology' in \
                        self.configuration['GENERAL']['global_arguments']:
                    if os.path.isfile(
                            self.configuration['GENERAL'][
                                'global_arguments']['ontology']
                    ):
                        self.ontology = ontology.Ontology(
                            self.configuration['GENERAL'][
                                'global_arguments']['ontology']
                        )
                    else:
                        raise FileNotFoundError(
                            'domain file %s not found' %
                            self.configuration['GENERAL'][
                                'global_arguments']['ontology'])

                if 'db_path' in self.configuration['DIALOGUE']:
                    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']
                        )

                # Alternatively, look at global arguments for db path
                elif 'global_arguments' in self.configuration['GENERAL'] \
                        and 'database' in \
                        self.configuration['GENERAL']['global_arguments']:
                    if os.path.isfile(
                            self.configuration['GENERAL'][
                                'global_arguments']['database']
                    ):
                        self.database = database.DataBase(
                            self.configuration['GENERAL'][
                                'global_arguments']['database']
                        )
                    else:
                        raise FileNotFoundError(
                            'domain file %s not found' %
                            self.configuration['GENERAL'][
                                'global_arguments']['ontology'])

                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 'global_arguments' in self.configuration['GENERAL']:
                    self.global_args = \
                        self.configuration['GENERAL']['global_arguments']
                    
                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

            # Retrieve agent role
            if 'role' in self.configuration['AGENT_0']:
                self.agent_role = self.configuration['AGENT_0']['role']
            else:
                raise ValueError(
                    'agent: 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 Single Agent (user): Cannot generate '
                        'goal without ontology and database.'
                    )
                
            # Retrieve agent parameters
            if 'max_turns' in self.configuration['AGENT_0']:
                self.MAX_TURNS = self.configuration['AGENT_0']['max_turns']
                
            if 'train_interval' in self.configuration['AGENT_0']:
                self.train_interval = \
                    self.configuration['AGENT_0']['train_interval']
                
            if 'train_minibatch' in self.configuration['AGENT_0']:
                self.minibatch_length = \
                    self.configuration['AGENT_0']['train_minibatch']
                
            if 'train_epochs' in self.configuration['AGENT_0']:
                self.train_epochs = \
                    self.configuration['AGENT_0']['train_epochs']

            if 'save_interval' in self.configuration['AGENT_0']:
                self.SAVE_INTERVAL = \
                    self.configuration['AGENT_0']['save_interval']
            
            # usr Simulator
            # Check for specific simulator self.settings, otherwise
            # default to agenda
            if 'USER_SIMULATOR' in self.configuration['AGENT_0']:
                # Agent 0 simulator configuration
                if 'package' in \
                    self.configuration['AGENT_0']['USER_SIMULATOR'] and \
                        'class' in \
                        self.configuration['AGENT_0']['USER_SIMULATOR']:
                    if 'arguments' in \
                            self.configuration['AGENT_0']['USER_SIMULATOR']:
                        self.user_simulator_args =\
                            self.configuration[
                                'AGENT_0']['USER_SIMULATOR']['arguments']

                    self.user_simulator_args.update(self.global_args)
                    
                    self.user_simulator = \
                        ConversationalGenericAgent.load_module(
                            self.configuration['AGENT_0']['USER_SIMULATOR'][
                                'package'],
                            self.configuration['AGENT_0']['USER_SIMULATOR'][
                                'class'],
                            self.user_simulator_args
                        )

                    if hasattr(self.user_simulator, 'nlu'):
                        self.USER_SIMULATOR_NLU = self.user_simulator.nlu
                    if hasattr(self.user_simulator, 'nlg'):
                        self.USER_SIMULATOR_NLG = self.user_simulator.nlg
                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']:
                nlu_args = {}
                if 'package' in self.configuration['AGENT_0']['NLU'] and \
                        'class' in self.configuration['AGENT_0']['NLU']:
                    if 'arguments' in \
                            self.configuration['AGENT_0']['NLU']:
                        nlu_args = \
                            self.configuration['AGENT_0']['NLU']['arguments']

                    nlu_args.update(self.global_args)

                    self.nlu = \
                        ConversationalGenericAgent.load_module(
                            self.configuration['AGENT_0']['NLU'][
                                'package'],
                            self.configuration['AGENT_0']['NLU'][
                                'class'],
                            nlu_args
                        )
                    
            # DM Settings
            if 'DM' in self.configuration['AGENT_0']:
                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
                         ]
                    )
                )

                if 'package' in self.configuration['AGENT_0']['DM'] and \
                        'class' in self.configuration['AGENT_0']['DM']:
                    if 'arguments' in \
                            self.configuration['AGENT_0']['DM']:
                        dm_args.update(
                            self.configuration['AGENT_0']['DM']['arguments']
                        )

                    dm_args.update(self.global_args)

                    self.dialogue_manager = \
                        ConversationalGenericAgent.load_module(
                            self.configuration['AGENT_0']['DM'][
                                'package'],
                            self.configuration['AGENT_0']['DM'][
                                'class'],
                            dm_args
                        )

            # NLG Settings
            if 'NLG' in self.configuration['AGENT_0']:
                nlg_args = {}
                if 'package' in self.configuration['AGENT_0']['NLG'] and \
                        'class' in self.configuration['AGENT_0']['NLG']:
                    if 'arguments' in \
                            self.configuration['AGENT_0']['NLG']:
                        nlg_args = \
                            self.configuration['AGENT_0']['NLG']['arguments']

                    nlg_args.update(self.global_args)

                    self.nlg = \
                        ConversationalGenericAgent.load_module(
                            self.configuration['AGENT_0']['NLG'][
                                'package'],
                            self.configuration['AGENT_0']['NLG'][
                                'class'],
                            nlg_args
                        )

                if self.nlg:
                    self.USE_NLG = True

        # True if at least one module is training
        self.IS_TRAINING = self.nlu and self.nlu.training or \
            self.dialogue_manager and self.dialogue_manager.training or \
            self.nlg and self.nlg.training
    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
        self.global_args = {}

        # 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_NLU = False
        self.USE_NLG = False
        self.USE_SPEECH = False
        self.USER_HAS_INITIATIVE = True
        self.SAVE_LOG = True
        self.SAVE_INTERVAL = 10000

        # 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=20000)

        # TODO: Get reward type from the config
        self.reward_func = SlotFillingReward()

        if self.configuration:
            ag_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[ag_id_str]:
                raise ValueError('Cannot run Plato without at least '
                                 'one agent!')

            # General settings
            if 'GENERAL' in self.configuration and \
                    self.configuration['GENERAL']:
                if 'global_arguments' in self.configuration['GENERAL']:
                    self.global_args = \
                        self.configuration['GENERAL']['global_arguments']

                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']
                        )

                        # Retrieve agent role
                        if 'role' in self.configuration[ag_id_str]:
                            self.agent_role = self.configuration[ag_id_str][
                                'role']
                        else:
                            raise ValueError(
                                'agent: No role assigned for '
                                'agent {0} in '
                                'config!'.format(self.agent_id)
                            )

            # Dialogue 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 'domain' in self.configuration['DIALOGUE']:
                    self.domain = self.configuration['DIALOGUE']['domain']
                elif 'domain' in self.global_args:
                    self.domain = self.global_args['domain']

                ontology_path = None
                if 'ontology_path' in self.configuration['DIALOGUE']:
                    ontology_path = \
                        self.configuration['DIALOGUE']['ontology_path']
                elif 'ontology' in self.global_args:
                    ontology_path = self.global_args['ontology']

                if ontology_path and os.path.isfile(ontology_path):
                    self.ontology = ontology.Ontology(ontology_path)
                else:
                    raise FileNotFoundError(
                        'domain file %s not found' % ontology_path
                    )

                db_path = None
                if 'db_path' in self.configuration['DIALOGUE']:
                    db_path = self.configuration['DIALOGUE']['db_path']
                elif 'database' in self.global_args:
                    db_path = self.global_args['database']

                if db_path and os.path.isfile(db_path):
                    if db_path[-3:] == '.db':
                        self.database = database.SQLDataBase(db_path)
                    else:
                        self.database = database.DataBase(db_path)
                else:
                    raise FileNotFoundError(
                        'Database file %s not found' % 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']
                        )

            # Agent Settings

            # Retrieve agent role
            if 'role' in self.configuration[ag_id_str]:
                self.agent_role = self.configuration[ag_id_str][
                    'role']
            else:
                raise ValueError(
                    'agent: 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.'
                    )

            # Retrieve agent parameters
            if 'max_turns' in self.configuration[ag_id_str]:
                self.MAX_TURNS = self.configuration[ag_id_str][
                    'max_turns']

            if 'train_interval' in self.configuration[ag_id_str]:
                self.train_interval = \
                    self.configuration[ag_id_str]['train_interval']

            if 'train_minibatch' in self.configuration[ag_id_str]:
                self.minibatch_length = \
                    self.configuration[ag_id_str]['train_minibatch']

            if 'train_epochs' in self.configuration[ag_id_str]:
                self.train_epochs = \
                    self.configuration[ag_id_str]['train_epochs']

            if 'save_interval' in self.configuration[ag_id_str]:
                self.SAVE_INTERVAL = \
                    self.configuration[ag_id_str]['save_interval']
                
            # NLU Settings
            if 'NLU' in self.configuration[ag_id_str]:
                nlu_args = {}
                if 'package' in self.configuration[ag_id_str]['NLU'] and \
                        'class' in self.configuration[ag_id_str]['NLU']:
                    if 'arguments' in \
                            self.configuration[ag_id_str]['NLU']:
                        nlu_args = \
                            self.configuration[ag_id_str]['NLU'][
                                'arguments']

                    nlu_args.update(self.global_args)

                    self.nlu = \
                        ConversationalGenericAgent.load_module(
                            self.configuration[ag_id_str]['NLU'][
                                'package'],
                            self.configuration[ag_id_str]['NLU'][
                                'class'],
                            nlu_args
                        )

            # DM Settings
            if 'DM' in self.configuration[ag_id_str]:
                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
                         ]
                    )
                )

                if 'package' in self.configuration[ag_id_str]['DM'] and \
                        'class' in self.configuration[ag_id_str]['DM']:
                    if 'arguments' in \
                            self.configuration[ag_id_str]['DM']:
                        dm_args.update(
                            self.configuration[ag_id_str]['DM'][
                                'arguments']
                        )

                    dm_args.update(self.global_args)

                    self.dialogue_manager = \
                        ConversationalGenericAgent.load_module(
                            self.configuration[ag_id_str]['DM'][
                                'package'],
                            self.configuration[ag_id_str]['DM'][
                                'class'],
                            dm_args
                        )

            # NLG Settings
            if 'NLG' in self.configuration[ag_id_str]:
                nlg_args = {}
                if 'package' in self.configuration[ag_id_str]['NLG'] and \
                        'class' in self.configuration[ag_id_str]['NLG']:
                    if 'arguments' in \
                            self.configuration[ag_id_str]['NLG']:
                        nlg_args = \
                            self.configuration[ag_id_str]['NLG'][
                                'arguments']

                    nlg_args.update(self.global_args)

                    self.nlg = \
                        ConversationalGenericAgent.load_module(
                            self.configuration[ag_id_str]['NLG'][
                                'package'],
                            self.configuration[ag_id_str]['NLG'][
                                'class'],
                            nlg_args
                        )

                if self.nlg:
                    self.USE_NLG = True

        # True if at least one module is training
        self.IS_TRAINING = self.nlu and self.nlu.training or \
            self.dialogue_manager and self.dialogue_manager.training or \
            self.nlg and self.nlg.training
    def __init__(self, args):
        """
        Parses the arguments in the dictionary and initializes the appropriate
        models for dialogue State Tracking and dialogue Policy.

        :param args: the configuration file parsed into a dictionary
        """

        super(DialogueManagerGeneric, self).__init__()

        if 'settings' not in args:
            raise AttributeError(
                'DialogueManagerGeneric: Please provide settings (config)!')
        if 'ontology' not in args:
            raise AttributeError(
                'DialogueManagerGeneric: Please provide ontology!')
        if 'database' not in args:
            raise AttributeError(
                'DialogueManagerGeneric: Please provide database!')
        if 'domain' not in args:
            raise AttributeError(
                'DialogueManagerGeneric: Please provide domain!')

        settings = args['settings']
        ontology = args['ontology']
        database = args['database']
        domain = args['domain']

        agent_id = 0
        if 'agent_id' in args:
            agent_id = int(args['agent_id'])

        agent_role = 'system'
        if 'agent_role' in args:
            agent_role = args['agent_role']

        self.settings = settings

        self.TRAIN_DST = False
        self.TRAIN_POLICY = False

        self.MAX_DB_RESULTS = 10

        self.DSTracker = None
        self.DSTracker_info = {}

        self.policy = None
        self.policy_info = {}

        self.policy_path = None
        self.ontology = None
        self.database = None
        self.domain = None

        self.agent_id = agent_id
        self.agent_role = agent_role

        self.dialogue_counter = 0
        self.CALCULATE_SLOT_ENTROPIES = True

        if isinstance(ontology, Ontology):
            self.ontology = ontology
        elif isinstance(ontology, str):
            self.ontology = Ontology(ontology)
        else:
            raise ValueError('Unacceptable ontology type %s ' % ontology)

        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)
                
        if args and args['policy']:
            if 'domain' in self.settings['DIALOGUE']:
                self.domain = self.settings['DIALOGUE']['domain']
            else:
                raise ValueError(
                    'domain is not specified in DIALOGUE at config.')

            if 'calculate_slot_entropies' in args:
                self.CALCULATE_SLOT_ENTROPIES = \
                    bool(args['calculate_slot_entropies'])

            if 'package' in args['policy'] and 'class' in args['policy']:
                self.policy_info = args['policy']

                if 'global_arguments' in args['settings']['GENERAL']:
                    if 'arguments' not in self.policy_info:
                        self.policy_info['arguments'] = {}

                    self.policy_info['arguments'].update(
                        args['settings']['GENERAL']['global_arguments']
                    )

                if 'train' in self.policy_info['arguments']:
                    self.TRAIN_POLICY = \
                        bool(self.policy_info['arguments']['train'])

                if 'policy_path' in self.policy_info['arguments']:
                    self.policy_path = \
                        self.policy_info['arguments']['policy_path']

                self.policy_info['arguments']['agent_role'] = self.agent_role

                # Replace ontology and database strings with the actual
                # objects to avoid repetitions (these won't change).
                if 'ontology' in self.policy_info['arguments']:
                    self.policy_info['arguments']['ontology'] = self.ontology

                if 'database' in self.policy_info['arguments']:
                    self.policy_info['arguments']['database'] = self.database

                self.policy = ConversationalGenericAgent.load_module(
                    self.policy_info['package'],
                    self.policy_info['class'],
                    self.policy_info['arguments']
                )

            else:
                raise ValueError('DialogueManagerGeneric: Cannot instantiate'
                                 'dialogue policy!')

        # DST Settings
        if 'DST' in args and args:
            if 'package' in args['DST'] and 'class' in args['DST']:
                self.DSTracker_info['package'] = args['DST']['package']
                self.DSTracker_info['class'] = args['DST']['class']

                self.DSTracker_info['args'] = {}

                if 'global_arguments' in args['settings']['GENERAL']:
                    self.DSTracker_info['args'] = \
                        args['settings']['GENERAL']['global_arguments']

                if 'arguments' in args['DST']:
                    self.DSTracker_info['args']. \
                        update(args['DST']['arguments'])

                self.DSTracker = ConversationalGenericAgent.load_module(
                    self.DSTracker_info['package'],
                    self.DSTracker_info['class'],
                    self.DSTracker_info['args']
                )

            else:
                raise ValueError('DialogueManagerGeneric: Cannot instantiate'
                                 'dialogue state tracker!')

        # Default to dummy DST, if no information is provided
        else:
            dst_args = dict(
                zip(
                    ['ontology', 'database', 'domain'],
                    [self.ontology, self.database, domain]))
            self.DSTracker = SlotFillingDST(dst_args)

        self.training = self.TRAIN_DST or self.TRAIN_POLICY

        self.load('')
    def run_single_agent(self, settings, human_role='user'):

        print('PATH:')
        print(os.system('pwd'))

        # Initialize automatic speech recognizer, if necessary
        if self.INTERACTION_MODE == 'speech':
            self.asr = speech_rec.Recognizer()

        ConvSysAgent = None
        ConvUserAgent = None

        # Verify that we have an AGENT section
        ag_id = 'AGENT_0'

        if ag_id in settings:
            if 'role' in settings[ag_id]:
                if settings[ag_id]['role'] == 'system':
                    ConvSysAgent = ConversationalGenericAgent(settings, 0)
                    ConvSysAgent.initialize()

                elif settings[ag_id]['role'] == 'user':
                    ConvUserAgent = ConversationalGenericAgent(settings, 0)
                    ConvUserAgent.initialize()

                else:
                    print('WARNING: Unknown agent role: {0}!'.format(
                        settings[ag_id]['role']))
            else:
                raise ValueError(
                    'Role for agent {0} not defined in config.'.format(0))

        # Lookup dictionary that maps button to function to call
        func_dict = {'Start Call': self.run_speech}

        # Layout the design of the GUI
        layout = [[sg.Image(r'plato/resources/PlatoRDSLogo_small.gif')],
                  [
                      sg.Text('User: '******'left',
                              font=("Helvetica", 50)),
                      sg.Text('System: ',
                              size=(27, 1),
                              justification='left',
                              font=("Helvetica", 50)),
                  ],
                  [
                      sg.Text('',
                              size=(60, 15),
                              justification='left',
                              font=("Helvetica", 20),
                              key='_USER_'),
                      sg.Text('',
                              size=(60, 15),
                              justification='left',
                              font=("Helvetica", 20),
                              key='_SYS_')
                  ],
                  [
                      sg.Button('Start Call'),
                      sg.Quit(),
                      sg.Text('',
                              size=(25, 1),
                              auto_size_text=True,
                              font=("Helvetica", 15),
                              key='_ASR_')
                  ]]

        # Show the Window to the user
        self.window = sg.Window('Plato Conversational Agent', layout)

        # Event loop. Read buttons, make callbacks
        while True:
            # Read the Window
            event, value = self.window.Read()

            if event in ('Quit', None):
                break

            # Lookup event in function dictionary
            try:
                func_to_call = func_dict[event]
                func_to_call(ConvSysAgent)

            except:
                pass

        self.window.Close()
Пример #6
0
    def run_single_agent(config, num_dialogues):
        """
        This function will create an agent and orchestrate the conversation.

        :param config: a dictionary containing settings
        :param num_dialogues: how many dialogues to run for
        :return: some statistics
        """
        if 'GENERAL' in config and 'generic' in config['GENERAL'] \
                and config['GENERAL']['generic']:
            ca = ConversationalGenericAgent(config, 0)
        else:
            ca = ConversationalSingleAgent(config)

        ca.initialize()

        for dialogue in range(num_dialogues):
            print('\n=====================================================\n\n'
                  'Dialogue %d (out of %d)\n' % (dialogue + 1, num_dialogues))

            ca.start_dialogue()

            while not ca.terminated():
                ca.continue_dialogue()

            ca.end_dialogue()

        # Collect statistics
        statistics = {'AGENT_0': {}}

        statistics['AGENT_0']['dialogue_success_percentage'] = \
            100 * float(ca.num_successful_dialogues / num_dialogues)
        statistics['AGENT_0']['avg_cumulative_rewards'] = \
            float(ca.cumulative_rewards / num_dialogues)
        statistics['AGENT_0']['avg_turns'] = \
            float(ca.total_dialogue_turns / num_dialogues)
        statistics['AGENT_0']['objective_task_completion_percentage'] = \
            100 * float(ca.num_task_success / num_dialogues)

        print('\n\ndialogue Success Rate: {0}\nAverage Cumulative Reward: {1}'
              '\nAverage Turns: {2}'.format(
                  statistics['AGENT_0']['dialogue_success_percentage'],
                  statistics['AGENT_0']['avg_cumulative_rewards'],
                  statistics['AGENT_0']['avg_turns']))

        return statistics
Пример #7
0
    def run_multi_agent(config, num_dialogues, num_agents):
        """
        This function will create multiple conversational agents and
        orchestrate the conversation among them.

        Note: In Plato v. 0.1 this function will create two agents.

        :param config: a dictionary containing settings
        :param num_dialogues: how many dialogues to run for
        :param num_agents: how many agents to spawn
        :return: some statistics
        """

        conv_sys_agents = []
        conv_user_agents = []
        objective_success = 0

        generic_agents = False
        if 'GENERAL' in config and 'generic' in config['GENERAL'] \
                and config['GENERAL']['generic']:
            generic_agents = bool(config['GENERAL']['generic'])

        # Verify that we have a DM section for each agent in the config and
        # initialize agents
        for a in range(num_agents):
            ag_id_str = 'AGENT_' + str(a)
            if 'role' in config[ag_id_str]:
                if config[ag_id_str]['role'] == 'system':
                    if generic_agents:
                        conv_sys_agents.append(
                            ConversationalGenericAgent(config, a))
                    else:
                        conv_sys_agents.append(
                            ConversationalMultiAgent(config, a))

                elif config[ag_id_str]['role'] == 'user':
                    if generic_agents:
                        conv_user_agents.append(
                            ConversationalGenericAgent(config, a))
                    else:
                        conv_user_agents.append(
                            ConversationalMultiAgent(config, a))

                else:
                    print('WARNING: Unknown agent role: {0}!'.format(
                        config[ag_id_str]['role']))
            else:
                raise ValueError(
                    'Role for agent {0} not defined in config.'.format(a))

        # TODO: WARNING: FOR NOW ASSUMING WE HAVE ONE SYSTEM AND ONE USER AGENT
        conv_user_agents[0].initialize()

        conv_sys_agents[0].initialize()

        for dialogue in range(num_dialogues):
            print('\n=====================================================\n\n'
                  'Dialogue %d (out of %d)\n' % (dialogue + 1, num_dialogues))

            # WARNING: FOR NOW ASSUMING WE HAVE ONE SYSTEM AGENT.
            user_output = conv_user_agents[0].start_dialogue()
            sys_output = conv_sys_agents[0].start_dialogue(
                {'goal': user_output['goal']})

            while not all(ca.terminated() for ca in conv_sys_agents) \
                    and not all(ca.terminated() for ca in conv_user_agents):
                # WARNING: FOR NOW ASSUMING WE HAVE ONE USER AGENT.
                user_output = conv_user_agents[0].continue_dialogue({
                    'other_input_raw':
                    sys_output['output_raw'],
                    'other_input_dacts':
                    sys_output['output_dacts'],
                    'goal':
                    sys_output['goal']
                })

                # Need to check for termination condition again, for the case
                # where the system says 'bye' and then the user says bye too.
                if all(ca.terminated() for ca in conv_sys_agents) \
                        or all(ca.terminated() for ca in conv_user_agents):
                    break

                # WARNING: FOR NOW ASSUMING WE HAVE ONE SYSTEM AGENT.
                sys_output = conv_sys_agents[0].continue_dialogue({
                    'other_input_raw':
                    user_output['output_raw'],
                    'other_input_dacts':
                    user_output['output_dacts'],
                    'goal':
                    user_output['goal']
                })

                # Sync goals (user has ground truth)
                conv_sys_agents[0].set_goal(conv_user_agents[0].get_goal())

            # Check if there is a goal. For example, if the agents are generic
            # there may not be a tracked goal.
            if not conv_sys_agents[0].agent_goal:
                continue

            # Consolidate goals to track objective success (each agent tracks
            # different things)

            # From the sys we keep everything except the status of actual
            # requests (filled or not)
            goal = conv_sys_agents[0].agent_goal
            goal.actual_requests = \
                conv_user_agents[0].agent_goal.actual_requests

            _, _, obj_succ = conv_sys_agents[0].reward_func.calculate(
                conv_sys_agents[0].get_state(), [],
                goal=goal,
                agent_role="system")

            objective_success += 1 if obj_succ else 0

            print(f'OBJECTIVE TASK COMPLETION: {obj_succ}')

            for ca in conv_sys_agents:
                ca.end_dialogue()

            for ca in conv_user_agents:
                ca.end_dialogue()

        # Collect statistics
        statistics = {}

        for i in range(num_agents):
            ag_id_str = 'AGENT_' + str(i)
            statistics[ag_id_str] = {'role': config[ag_id_str]['role']}

        statistics['AGENT_0']['dialogue_success_percentage'] = \
            100 * \
            float(conv_sys_agents[0].num_successful_dialogues / num_dialogues)
        statistics['AGENT_0']['avg_cumulative_rewards'] = \
            float(conv_sys_agents[0].cumulative_rewards / num_dialogues)
        statistics['AGENT_0']['avg_turns'] = \
            float(conv_sys_agents[0].total_dialogue_turns / num_dialogues)
        statistics['AGENT_0']['objective_task_completion_percentage'] = \
            100 * float(objective_success / num_dialogues)

        statistics['AGENT_1']['dialogue_success_percentage'] = \
            100 * \
            float(conv_user_agents[0].num_successful_dialogues / num_dialogues)
        statistics['AGENT_1']['avg_cumulative_rewards'] = \
            float(conv_user_agents[0].cumulative_rewards / num_dialogues)
        statistics['AGENT_1']['avg_turns'] = \
            float(conv_user_agents[0].total_dialogue_turns / num_dialogues)
        statistics['AGENT_1']['objective_task_completion_percentage'] = \
            100 * float(objective_success / num_dialogues)

        print('\n\nSYSTEM dialogue Success Rate: {0}\n'
              'Average Cumulative Reward: {1}\n'
              'Average Turns: {2}'.format(
                  100 * float(conv_sys_agents[0].num_successful_dialogues /
                              num_dialogues),
                  float(conv_sys_agents[0].cumulative_rewards / num_dialogues),
                  float(conv_sys_agents[0].total_dialogue_turns /
                        num_dialogues)))

        print('\n\nUSER dialogue Success Rate: {0}\n'
              'Average Cumulative Reward: {1}\n'
              'Average Turns: {2}'.format(
                  100 * float(conv_user_agents[0].num_successful_dialogues /
                              num_dialogues),
                  float(conv_user_agents[0].cumulative_rewards /
                        num_dialogues),
                  float(conv_user_agents[0].total_dialogue_turns /
                        num_dialogues)))

        avg_rew = 0.5 * (
            float(conv_sys_agents[0].cumulative_rewards / num_dialogues) +
            float(conv_user_agents[0].cumulative_rewards / num_dialogues))
        print(f'\n\nAVERAGE rewards: {avg_rew}')

        print('\n\nObjective Task Success Rate: {0}'.format(
            100 * float(objective_success / num_dialogues)))

        return statistics