def _pair_with_human(cursor, my_id, my_index, partner_id, scenario, chat_id): controller, my_session, partner_session = _init_controller(my_index, HumanSystem.name(), scenario, chat_id) self.controller_map[my_id] = controller self.controller_map[partner_id] = controller self.sessions[my_id] = my_session self.sessions[partner_id] = partner_session # ensures that partner is actually in waiting state self._get_user_info(cursor, partner_id, assumed_status=Status.Waiting) # Update partner self._update_user(cursor, partner_id, status=Status.Chat, partner_id=my_id, partner_type=HumanSystem.name(), scenario_id=scenario.uuid, agent_index=1 - my_index, message="", chat_id=chat_id) # Update me self._update_user(cursor, my_id, status=Status.Chat, partner_id=partner_id, partner_type=HumanSystem.name(), scenario_id=scenario_id, agent_index=my_index, message="", chat_id=chat_id) return True
def _init_controller(my_index, partner_type, scenario, chat_id): my_session = self.systems[HumanSystem.name()].new_session(my_index, scenario.get_kb(my_index)) partner_session = self.systems[partner_type].new_session(1 - my_index, scenario.get_kb(1 - my_index)) controller = Controller(scenario, [my_session, partner_session], chat_id=chat_id) return controller, my_session, partner_session
def add_systems(args, config_dict, schema, debug=False): """ Params: config_dict: A dictionary that maps the bot name to a dictionary containing configs for the bot. The dictionary should contain the bot type (key 'type') and. for bots that use an underlying model for generation, the path to the directory containing the parameters, vocab, etc. for the model. Returns: agents: A dict mapping from the bot name to the System object for that bot. pairing_probabilities: A dict mapping from the bot name to the probability that a user is paired with that bot. Also includes the pairing probability for humans (backend.Partner.Human) """ total_probs = 0.0 # systems = {HumanSystem.name(): HumanSystem()} ### changed parts from original craigslistbargain code # get_system: in craigslistbargain/systems/__init__.py systems = {HumanSystem.name(): HumanSystem(), RulebasedSystem.name(): get_system("rulebased", args)} ### pairing_probabilities = {} timed = False if debug else True for (sys_name, info) in config_dict.iteritems(): if "active" not in info.keys(): warnings.warn("active status not specified for bot %s - assuming that bot is inactive." % sys_name) if info["active"]: name = info["type"] try: model = get_system(name, args, schema=schema, timed=timed, model_path=info.get('checkpoint')) except ValueError: warnings.warn( 'Unrecognized model type in {} for configuration ' '{}. Ignoring configuration.'.format(info, sys_name)) continue systems[sys_name] = model if 'prob' in info.keys(): prob = float(info['prob']) pairing_probabilities[sys_name] = prob total_probs += prob print '{} systems loaded'.format(len(systems)) for name in systems: print name # TODO: clean up pairing probabilities (obsolete) if total_probs > 1.0: raise ValueError("Probabilities for active bots can't exceed 1.0.") if len(pairing_probabilities.keys()) != 0 and len(pairing_probabilities.keys()) != len(systems.keys()): remaining_prob = (1.0-total_probs)/(len(systems.keys()) - len(pairing_probabilities.keys())) else: remaining_prob = 1.0 / len(systems.keys()) inactive_bots = set() for system_name in systems.keys(): if system_name not in pairing_probabilities.keys(): if remaining_prob == 0.0: inactive_bots.add(system_name) else: pairing_probabilities[system_name] = remaining_prob for sys_name in inactive_bots: systems.pop(sys_name, None) return systems, pairing_probabilities
def add_systems(args, config_dict, schema): """ Args: config_dict: A dictionary that maps the bot name to a dictionary containing configs for the bot. The dictionary should contain the bot type (key 'type') and. for bots that use an underlying model for generation, the path to the directory containing the parameters, vocab, etc. for the model. Returns: systems: A dict mapping from the bot name to the System object for that bot. """ total_probs = 0.0 systems = {HumanSystem.name(): HumanSystem()} timed = False if params['debug'] else True for (sys_name, info) in config_dict.iteritems(): if "active" not in info.keys(): warnings.warn( "active status not specified for bot %s - assuming that bot is inactive." % sys_name) if info["active"]: name = info["type"] try: model = get_system(name, args, schema=schema, timed=timed, model_path=args.checkpoint) except ValueError: warnings.warn( 'Unrecognized model type in {} for configuration ' '{}. Ignoring configuration.'.format(info, sys_name)) continue systems[sys_name] = model return systems
def add_systems(args, config_dict, schema, debug=False): """ Params: config_dict: A dictionary that maps the bot name to a dictionary containing configs for the bot. The dictionary should contain the bot type (key 'type') and. for bots that use an underlying model for generation, the path to the directory containing the parameters, vocab, etc. for the model. Returns: agents: A dict mapping from the bot name to the System object for that bot. pairing_probabilities: A dict mapping from the bot name to the probability that a user is paired with that bot. Also includes the pairing probability for humans (backend.Partner.Human) """ total_probs = 0.0 systems = {HumanSystem.name(): HumanSystem()} pairing_probabilities = {} timed = False if debug else True print 'timed:', timed for (sys_name, info) in config_dict.iteritems(): if "active" not in info.keys(): warnings.warn( "active status not specified for bot %s - assuming that bot is inactive." % sys_name) if info["active"]: name = info["type"] try: # TODO: model related arguments should be in config_dict (read from params.json), instead of in command line args, currently we are assuming there is only one model that needs `checkpoint` model = get_system(name, args, schema=schema, timed=timed, model_path=args.checkpoint) except ValueError: warnings.warn( 'Unrecognized model type in {} for configuration ' '{}. Ignoring configuration.'.format(info, sys_name)) continue systems[sys_name] = model if 'prob' in info.keys(): prob = float(info['prob']) pairing_probabilities[sys_name] = prob total_probs += prob # TODO: clean up pairing probabilities (obsolete) if total_probs > 1.0: raise ValueError("Probabilities for active bots can't exceed 1.0.") if len(pairing_probabilities.keys()) != 0 and len( pairing_probabilities.keys()) != len(systems.keys()): remaining_prob = (1.0 - total_probs) / ( len(systems.keys()) - len(pairing_probabilities.keys())) else: remaining_prob = 1.0 / len(systems.keys()) inactive_bots = set() for system_name in systems.keys(): if system_name not in pairing_probabilities.keys(): if remaining_prob == 0.0: inactive_bots.add(system_name) else: pairing_probabilities[system_name] = remaining_prob for sys_name in inactive_bots: systems.pop(sys_name, None) return systems, pairing_probabilities
def is_user_partner_bot(self, cursor, userid): u = self._get_user_info_unchecked(cursor, userid) return len(u.partner_type) > 0 and u.partner_type != HumanSystem.name()
def attempt_join_chat(self, userid): def _init_controller(my_index, partner_type, scenario, chat_id): my_session = self.systems[HumanSystem.name()].new_session(my_index, scenario.get_kb(my_index)) partner_session = self.systems[partner_type].new_session(1 - my_index, scenario.get_kb(1 - my_index)) controller = Controller(scenario, [my_session, partner_session], chat_id=chat_id) return controller, my_session, partner_session def _pair_with_human(cursor, my_id, my_index, partner_id, scenario, chat_id): controller, my_session, partner_session = _init_controller(my_index, HumanSystem.name(), scenario, chat_id) self.controller_map[my_id] = controller self.controller_map[partner_id] = controller self.sessions[my_id] = my_session self.sessions[partner_id] = partner_session # ensures that partner is actually in waiting state self._get_user_info(cursor, partner_id, assumed_status=Status.Waiting) # Update partner self._update_user(cursor, partner_id, status=Status.Chat, partner_id=my_id, partner_type=HumanSystem.name(), scenario_id=scenario.uuid, agent_index=1 - my_index, message="", chat_id=chat_id) # Update me self._update_user(cursor, my_id, status=Status.Chat, partner_id=partner_id, partner_type=HumanSystem.name(), scenario_id=scenario_id, agent_index=my_index, message="", chat_id=chat_id) return True def _pair_with_bot(cursor, userid, my_index, bot_type, scenario, chat_id): controller, my_session, bot_session = _init_controller(my_index, bot_type, scenario, chat_id) config = bot_session.config if config is not None: cursor.execute('INSERT INTO bot VALUES (?,?,?)', (chat_id, bot_type, json.dumps(list(config)))) self.controller_map[userid] = controller self.sessions[userid] = my_session self._update_user(cursor, userid, status=Status.Chat, partner_id=0, partner_type=bot_type, scenario_id=scenario_id, agent_index=my_index, message="", chat_id=chat_id) return True def _get_other_waiting_users(cursor, userid): cursor.execute("SELECT name FROM active_user WHERE name!=? AND status=? AND connected_status=1", (userid, Status.Waiting)) userids = [r[0] for r in cursor.fetchall()] return userids def _choose_scenario_and_partner_type(cursor): # for each scenario, get number of complete dialogues per agent type all_partners = self.systems.keys() if not self.active_system else [self.active_system] if self.active_scenario is not None: return self.scenario_db.scenarios_list[self.active_scenario], np.random.choice(all_partners) cursor.execute('''SELECT * FROM scenario''') db_scenarios = cursor.fetchall() scenario_dialogues = defaultdict(lambda: defaultdict(int)) for (scenario_id, partner_type, complete, active) in db_scenarios: complete = set(json.loads(complete)) active = set(json.loads(active)) # map from scenario ID -> partner type -> # of completed dialogues with that partner if scenario_id not in scenario_dialogues: scenario_dialogues[scenario_id] = {} scenario_dialogues[scenario_id][partner_type] = len(complete) + len(active) # find "active" scenarios (scenarios for which at least one agent type has no completed or active dialogues) active_scenarios = defaultdict(list) for sid in scenario_dialogues.keys(): for partner_type in all_partners: if scenario_dialogues[sid][partner_type] < self.num_chats_per_scenario[partner_type]: active_scenarios[sid].append(partner_type) # if all scenarios have at least one dialogue per agent type (i.e. no active scenarios), # just select a random scenario and agent type if len(active_scenarios.keys()) == 0: sid = np.random.choice(scenario_dialogues.keys()) p = np.random.choice(all_partners) return self.scenario_db.get(sid), p # otherwise, select a random active scenario and an agent type that it's missing sid = np.random.choice(active_scenarios.keys()) p = np.random.choice(active_scenarios[sid]) return self.scenario_db.get(sid), p def _update_used_scenarios(scenario_id, partner_type, chat_id): cursor.execute( '''SELECT active FROM scenario WHERE scenario_id=? AND partner_type=?''', (scenario_id, partner_type)) active_set = set(json.loads(cursor.fetchone()[0])) active_set.add(chat_id) cursor.execute('''UPDATE scenario SET active=? WHERE scenario_id=? AND partner_type=?''', (json.dumps(list(active_set)), scenario_id, partner_type)) try: with self.conn: cursor = self.conn.cursor() others = _get_other_waiting_users(cursor, userid) scenario, partner_type = _choose_scenario_and_partner_type(cursor) scenario_id = scenario.uuid #my_index = np.random.choice([0, 1]) # TODO: hack for buyer/seller my_index = 0 if self.scenario_int_id[scenario_id] % 2 == 0 else 1 chat_id = self._generate_chat_id() if partner_type == HumanSystem.name(): if len(others) == 0: return None partner_id = np.random.choice(others) try: _pair_with_human(cursor, userid, my_index, partner_id, scenario, chat_id) except UnexpectedStatusException: self.logger.warn("Attempt to pair user {:s} with {:s} failed. User {:s} not in waiting " "status".format(userid, partner_id, partner_id)) return False except ConnectionTimeoutException: self.logger.warn("Attempt to pair user {:s} with {:s} failed. User {:s} had connection " "timeout".format(userid, partner_id, partner_id)) return False _update_used_scenarios(scenario_id, HumanSystem.name(), chat_id) if my_index == 0: self.add_chat_to_db(chat_id, scenario_id, userid, partner_id, HumanSystem.name(), HumanSystem.name()) else: self.add_chat_to_db(chat_id, scenario_id, partner_id, userid, HumanSystem.name(), HumanSystem.name()) self.logger.debug("Paired users {:s} and {:s} in chat with ID {:s} and scenario {:s}".format( userid, partner_id, chat_id, scenario_id )) return True else: _update_used_scenarios(scenario_id, partner_type, chat_id) if my_index == 0: self.add_chat_to_db(chat_id, scenario_id, userid, 0, HumanSystem.name(), partner_type) else: self.add_chat_to_db(chat_id, scenario_id, 0, userid, partner_type, HumanSystem.name()) self.logger.debug("Paired user {:s} with bot of type {:s} in chat with ID {:s} and scenario " "{:s}".format(userid, partner_type, chat_id, scenario_id)) return _pair_with_bot(cursor, userid, my_index, partner_type, scenario, chat_id) except sqlite3.IntegrityError: print("WARNING: Rolled back transaction")