#!/usr/bin/env python # -*- coding: utf-8 -*- from module_manager import ModuleManager from module_list import module_list_data if __name__ == '__main__': mm = ModuleManager() for i in module_list_data: mm.create_class_instance(i[0], i[1], i[2], i[3] ) # init all instances mm.init_all_instance() # start server mm.get_class_instance('nfc_server').start()
if args.test_mode: print('Starting evaluation: {}'.format( datetime.now().strftime("%m/%d/%Y %H:%M:%S"))) model = load_model(args.model_path, args.task == 'detect') evaluate(args.task, model, test_examples, args.model_name, args.rerank) print('Terminating evaluation: {}'.format( datetime.now().strftime("%m/%d/%Y %H:%M:%S"))) else: print('Starting training: {}'.format( datetime.now().strftime("%m/%d/%Y %H:%M:%S"))) manager = ModuleManager(args.attend_code_sequence_states, args.attend_code_graph_states, args.features, args.posthoc, args.task, args.pickle) manager.initialize(train_examples) model = build_model(args.task, args.model_path, manager) # bacthes = manager.get_batches(train_examples, device=torch.device('cuda'), shuffle=True) # # print('BATCHES:') # for b in bacthes: # print(b) # break # # exit(0)
def __init__(self, **kwargs): ## Make sure there's a Discord token before doing anything else self.token = CONFIG_OPTIONS.get("discord_token") if (not self.token): raise RuntimeError("Unable to get Discord token!") self.version = kwargs.get(self.VERSION_KEY, self.VERSION) self.activation_str = kwargs.get(self.ACTIVATION_STR_KEY, self.ACTIVATION_STR) self.description = kwargs.get(self.DESCRIPTION_KEY, self.DESCRIPTION) self.invalid_command_minimum_similarity = float( kwargs.get(self.INVALID_COMMAND_MINIMUM_SIMILARITY, 0.66)) self.dynamo_db = dynamo_helper.DynamoHelper() ## Init the bot and module manager self.bot = commands.Bot(command_prefix=commands.when_mentioned_or( self.activation_str), description=self.description) self.module_manager = ModuleManager(self, self.bot) ## Apply customized HelpCommand self.bot.help_command = help_command.HawkingHelpCommand() ## Register the modules (Order of registration is important, make sure dependancies are loaded first) self.module_manager.register(message_parser.MessageParser, False) self.module_manager.register(admin.Admin, True, self, self.bot) self.module_manager.register(speech.Speech, True, self) self.module_manager.register( audio_player.AudioPlayer, True, self.bot, self.get_speech_cog().play_random_channel_timeout_message) ## Load any dynamic modules inside the /modules folder self.module_manager.discover() ## Give some feedback for when the bot is ready to go, and provide some help text via the 'playing' status @self.bot.event async def on_ready(): ## todo: Activity instead of Game? Potentially remove "Playing" text below bot bot_status = discord.Game(type=0, name="Use {}help".format( self.activation_str)) await self.bot.change_presence(activity=bot_status) logger.info("Logged in as '{}' (version: {}), (id: {})".format( self.bot.user.name, self.version, self.bot.user.id)) ## Give some feedback to users when their command doesn't execute. @self.bot.event async def on_command_error(ctx, exception): '''Handles command errors. Attempts to find a similar command and suggests it, otherwise directs the user to the help prompt.''' self.dynamo_db.put( dynamo_helper.DynamoItem(ctx, ctx.message.content, inspect.currentframe().f_code.co_name, False, str(exception))) ## Attempt to find a command that's similar to the one they wanted. Otherwise just direct them to the help page most_similar_command = self.find_most_similar_command( ctx.message.content) if (most_similar_command[0] == ctx.invoked_with): logger.exception( "Unable to complete command, with content: {}, for author: {}, in channel {}, in server: {}" .format(ctx.message.content, ctx.message.author.name, ctx.guild.name), exc_info=exception) ## Handle issues where the command is valid, but couldn't be completed for whatever reason. await ctx.send( "I'm sorry <@{}>, I'm afraid I can't do that.\nSomething went wrong, and I couldn't complete the command." .format(ctx.message.author.id)) else: logger.exception( "Received invalid command: '{0}{1}', suggested: '{0}{2}', for author: {3}, in server: {4}" .format(self.activation_str, ctx.invoked_with, most_similar_command[0], ctx.message.author.name, ctx.guild.name), exc_info=exception) help_text_chunks = [ "Sorry <@{}>, **{}{}** isn't a valid command.".format( ctx.message.author.id, ctx.prefix, ctx.invoked_with) ] if (most_similar_command[1] > self.invalid_command_minimum_similarity): help_text_chunks.append("Did you mean **{}{}**?".format( self.activation_str, most_similar_command[0])) else: help_text_chunks.append("Try the **{}help** page.".format( self.activation_str)) ## Dump output to user await ctx.send(" ".join(help_text_chunks)) return
class Hawking: ## Keys and Defaults ## Basically, any given class can be configured by changing the respective value for the ## desired key in config.json (see the Keys section at the top of each class for a list of ## keys). However, if you want to use Hawking as a part of something else, you may want to ## dynamically configure objects as necessary. Thus, you can also instantiate classes with ## keyworded arguments, which will then override any existing defaults, or config.json data. ## The existing defaults in each class are sort of like a fallback, in case the config.json is ## broken in some way. ## Keys VERSION_KEY = "version" ACTIVATION_STR_KEY = "activation_str" DESCRIPTION_KEY = "description" INVALID_COMMAND_MINIMUM_SIMILARITY = "invalid_command_minimum_similarity" ## Defaults VERSION = CONFIG_OPTIONS.get(VERSION_KEY, "Invalid version") ACTIVATION_STR = CONFIG_OPTIONS.get(ACTIVATION_STR_KEY, "\\") DESCRIPTION = CONFIG_OPTIONS.get( DESCRIPTION_KEY, "A retro TTS bot for Discord\n Visit https://github.com/naschorr/hawking" ) ## Initialize the bot, and add base cogs def __init__(self, **kwargs): ## Make sure there's a Discord token before doing anything else self.token = CONFIG_OPTIONS.get("discord_token") if (not self.token): raise RuntimeError("Unable to get Discord token!") self.version = kwargs.get(self.VERSION_KEY, self.VERSION) self.activation_str = kwargs.get(self.ACTIVATION_STR_KEY, self.ACTIVATION_STR) self.description = kwargs.get(self.DESCRIPTION_KEY, self.DESCRIPTION) self.invalid_command_minimum_similarity = float( kwargs.get(self.INVALID_COMMAND_MINIMUM_SIMILARITY, 0.66)) self.dynamo_db = dynamo_helper.DynamoHelper() ## Init the bot and module manager self.bot = commands.Bot(command_prefix=commands.when_mentioned_or( self.activation_str), description=self.description) self.module_manager = ModuleManager(self, self.bot) ## Apply customized HelpCommand self.bot.help_command = help_command.HawkingHelpCommand() ## Register the modules (Order of registration is important, make sure dependancies are loaded first) self.module_manager.register(message_parser.MessageParser, False) self.module_manager.register(admin.Admin, True, self, self.bot) self.module_manager.register(speech.Speech, True, self) self.module_manager.register( audio_player.AudioPlayer, True, self.bot, self.get_speech_cog().play_random_channel_timeout_message) ## Load any dynamic modules inside the /modules folder self.module_manager.discover() ## Give some feedback for when the bot is ready to go, and provide some help text via the 'playing' status @self.bot.event async def on_ready(): ## todo: Activity instead of Game? Potentially remove "Playing" text below bot bot_status = discord.Game(type=0, name="Use {}help".format( self.activation_str)) await self.bot.change_presence(activity=bot_status) logger.info("Logged in as '{}' (version: {}), (id: {})".format( self.bot.user.name, self.version, self.bot.user.id)) ## Give some feedback to users when their command doesn't execute. @self.bot.event async def on_command_error(ctx, exception): '''Handles command errors. Attempts to find a similar command and suggests it, otherwise directs the user to the help prompt.''' self.dynamo_db.put( dynamo_helper.DynamoItem(ctx, ctx.message.content, inspect.currentframe().f_code.co_name, False, str(exception))) ## Attempt to find a command that's similar to the one they wanted. Otherwise just direct them to the help page most_similar_command = self.find_most_similar_command( ctx.message.content) if (most_similar_command[0] == ctx.invoked_with): logger.exception( "Unable to complete command, with content: {}, for author: {}, in channel {}, in server: {}" .format(ctx.message.content, ctx.message.author.name, ctx.guild.name), exc_info=exception) ## Handle issues where the command is valid, but couldn't be completed for whatever reason. await ctx.send( "I'm sorry <@{}>, I'm afraid I can't do that.\nSomething went wrong, and I couldn't complete the command." .format(ctx.message.author.id)) else: logger.exception( "Received invalid command: '{0}{1}', suggested: '{0}{2}', for author: {3}, in server: {4}" .format(self.activation_str, ctx.invoked_with, most_similar_command[0], ctx.message.author.name, ctx.guild.name), exc_info=exception) help_text_chunks = [ "Sorry <@{}>, **{}{}** isn't a valid command.".format( ctx.message.author.id, ctx.prefix, ctx.invoked_with) ] if (most_similar_command[1] > self.invalid_command_minimum_similarity): help_text_chunks.append("Did you mean **{}{}**?".format( self.activation_str, most_similar_command[0])) else: help_text_chunks.append("Try the **{}help** page.".format( self.activation_str)) ## Dump output to user await ctx.send(" ".join(help_text_chunks)) return ## Methods ## Add an arbitary cog to the bot def add_cog(self, cls): self.bot.add_cog(cls) ## Returns a cog with a given name def get_cog(self, cls_name): return self.bot.get_cog(cls_name) ## Returns the bot's audio player cog def get_audio_player_cog(self): return self.bot.get_cog("AudioPlayer") ## Returns the bot's audio player cog def get_speech_cog(self): return self.bot.get_cog("Speech") ## Returns the bot's phrases cog def get_phrases_cog(self): return self.bot.get_cog("Phrases") ## Returns the bot's music cog def get_music_cog(self): return self.bot.get_cog("Music") ## Register an arbitrary module with hawking (easy wrapper for self.module_manager.register) def register_module(self, cls, is_cog, *init_args, **init_kwargs): self.module_manager.register(cls, is_cog, *init_args, **init_kwargs) ## Finds the most similar command to the supplied one def find_most_similar_command(self, command): ## Build a message string that we can compare with. try: message = command[len(self.activation_str):] except TypeError: message = command ## Get a list of all visible commands commands = [cmd.name for cmd in self.bot.commands if not cmd.hidden] ## Find the most similar command most_similar_command = (None, 0) for key in commands: distance = StringSimilarity.similarity(key, message) if (distance > most_similar_command[1]): most_similar_command = (key, distance) return most_similar_command ## Run the bot def run(self): '''Starts the bot up''' ## So ideally there would be some flavor of atexit.register or signal.signal command to gracefully shut the bot ## down upon SIGTERM or SIGINT. However that doesn't seem to be possible at the moment. Discord.py's got most of ## the functionality built into the base close() method that fires on SIGINT and SIGTERM, but the bot never ends ## up getting properly disconnected from the voice channels that it's connected to. I end up having to wait for ## a time out. Otherwise the bot will be in a weird state upon starting back up, and attempting to speak in one ## of the channels that it was previously in. Fortunately this bad state will self-recover in a minute or so, ## but it's still unpleasant. A temporary fix is to bump up the RestartSec= property in the service config to be ## long enough to allow for the bot to be forcefully disconnected logger.info('Starting up the bot.') self.bot.run(self.token)
def __init__(self, **kwargs): self.activation_str = kwargs.get(self.ACTIVATION_STR_KEY, self.ACTIVATION_STR) self.description = kwargs.get(self.DESCRIPTION_KEY, self.DESCRIPTION) self.token_file_path = kwargs.get(self.TOKEN_FILE_PATH_KEY, self.TOKEN_FILE_PATH) self.invalid_command_minimum_similarity = float(kwargs.get(self.INVALID_COMMAND_MINIMUM_SIMILARITY, 0.66)) self.dynamo_db = dynamo_helper.DynamoHelper() ## Todo: pass kwargs to the their modules ## Init the bot and module manager self.bot = commands.Bot( command_prefix=commands.when_mentioned_or(self.activation_str), formatter=help_formatter.HawkingHelpFormatter(), description=self.description ) self.module_manager = ModuleManager(self, self.bot) ## Register the modules (Order of registration is important, make sure dependancies are loaded first) self.module_manager.register(message_parser.MessageParser, False) self.module_manager.register(speech.Speech, True, self.bot) self.module_manager.register(admin.Admin, True, self, self.bot) ## Load any dynamic modules inside the /modules folder self.module_manager.discover() ## Give some feedback for when the bot is ready to go, and provide some help text via the 'playing' status @self.bot.event async def on_ready(): bot_status = discord.Game(type=0, name="Use {}help".format(self.activation_str)) await self.bot.change_presence(game=bot_status) print("Logged in as '{}' (version: {}), (id: {})".format(self.bot.user.name, self.VERSION, self.bot.user.id)) ## Give some feedback to users when their command doesn't execute. @self.bot.event async def on_command_error(exception, ctx): # discord.py uses reflection to set the destination chat channel for whatever reason (sans command ctx) _internal_channel = ctx.message.channel utilities.debug_print(exception, debug_level=2) self.dynamo_db.put(dynamo_helper.DynamoItem( ctx, ctx.message.content, inspect.currentframe().f_code.co_name, False, str(exception))) ## Handy for debugging # import traceback # print('Ignoring exception in command {}:'.format(ctx.command), file=sys.stderr) # traceback.print_exception(type(exception), exception, exception.__traceback__, file=sys.stderr) ## Permissions error? if (isinstance(exception, CommandInvokeError) and isinstance(exception.original, TimeoutError)): await self.bot.say("Sorry <@{}>, I'm not able to join the voice channel right now. Discord might be having issues, or I might not have permission to join." .format(ctx.message.author.id)) return ## Poorly handled (for now, until I can get more concrete examples in my database) error messages for users if ("code =" in str(exception)): await self.bot.say("Sorry <@{}>, Discord is having some issues that won't let me speak right now." .format(ctx.message.author.id)) return ## Attempt to find a command that's similar to the one they wanted. Otherwise just direct them to the help page else: most_similar_command = self.find_most_similar_command(ctx.message.content) if (most_similar_command[0] == ctx.invoked_with): ## Handle issues where the command is valid, but couldn't be completed for whatever reason. await self.bot.say("Sorry <@{}>, I can't talk right now. Try again in a little bit.".format(ctx.message.author.id)) else: ## Otherwise, handle other issues involving invalid commands help_text_chunks = [ "Sorry <@{}>, **{}{}** isn't a valid command.".format(ctx.message.author.id, ctx.prefix, ctx.invoked_with) ] ## Build the output to give to the user if (most_similar_command[1] > self.invalid_command_minimum_similarity): help_text_chunks.append("Did you mean **{}{}**?".format(self.activation_str, most_similar_command[0])) else: help_text_chunks.append("Try the **{}help** page.".format(self.activation_str)) await self.bot.say(" ".join(help_text_chunks))
class Hawking: ## Keys and Defaults ## Basically, any given class can be configured by changing the respective value for the ## desired key in config.json (see the Keys section at the top of each class for a list of ## keys). However, if you want to use Hawking as a part of something else, you may want to ## dynamically configure objects as necessary. Thus, you can also instantiate classes with ## keyworded arguments, which will then override any existing defaults, or config.json data. ## The existing defaults in each class are sort of like a fallback, in case the config.json is ## broken in some way. ## Keys VERSION_KEY = "version" ACTIVATION_STR_KEY = "activation_str" DESCRIPTION_KEY = "description" TOKEN_KEY = "token" TOKEN_FILE_KEY = "token_file" TOKEN_FILE_PATH_KEY = "token_file_path" INVALID_COMMAND_MINIMUM_SIMILARITY = "invalid_command_minimum_similarity" ## Defaults VERSION = CONFIG_OPTIONS.get(VERSION_KEY, "Invalid version") ACTIVATION_STR = CONFIG_OPTIONS.get(ACTIVATION_STR_KEY, "\\") DESCRIPTION = CONFIG_OPTIONS.get(DESCRIPTION_KEY, "A retro TTS bot for Discord (Alpha)\n Visit https://github.com/naschorr/hawking") TOKEN_FILE = CONFIG_OPTIONS.get(TOKEN_FILE_KEY, "token.json") TOKEN_FILE_PATH = CONFIG_OPTIONS.get(TOKEN_FILE_PATH_KEY, os.sep.join([utilities.get_root_path(), TOKEN_FILE])) ## Initialize the bot, and add base cogs def __init__(self, **kwargs): self.activation_str = kwargs.get(self.ACTIVATION_STR_KEY, self.ACTIVATION_STR) self.description = kwargs.get(self.DESCRIPTION_KEY, self.DESCRIPTION) self.token_file_path = kwargs.get(self.TOKEN_FILE_PATH_KEY, self.TOKEN_FILE_PATH) self.invalid_command_minimum_similarity = float(kwargs.get(self.INVALID_COMMAND_MINIMUM_SIMILARITY, 0.66)) self.dynamo_db = dynamo_helper.DynamoHelper() ## Todo: pass kwargs to the their modules ## Init the bot and module manager self.bot = commands.Bot( command_prefix=commands.when_mentioned_or(self.activation_str), formatter=help_formatter.HawkingHelpFormatter(), description=self.description ) self.module_manager = ModuleManager(self, self.bot) ## Register the modules (Order of registration is important, make sure dependancies are loaded first) self.module_manager.register(message_parser.MessageParser, False) self.module_manager.register(speech.Speech, True, self.bot) self.module_manager.register(admin.Admin, True, self, self.bot) ## Load any dynamic modules inside the /modules folder self.module_manager.discover() ## Give some feedback for when the bot is ready to go, and provide some help text via the 'playing' status @self.bot.event async def on_ready(): bot_status = discord.Game(type=0, name="Use {}help".format(self.activation_str)) await self.bot.change_presence(game=bot_status) print("Logged in as '{}' (version: {}), (id: {})".format(self.bot.user.name, self.VERSION, self.bot.user.id)) ## Give some feedback to users when their command doesn't execute. @self.bot.event async def on_command_error(exception, ctx): # discord.py uses reflection to set the destination chat channel for whatever reason (sans command ctx) _internal_channel = ctx.message.channel utilities.debug_print(exception, debug_level=2) self.dynamo_db.put(dynamo_helper.DynamoItem( ctx, ctx.message.content, inspect.currentframe().f_code.co_name, False, str(exception))) ## Handy for debugging # import traceback # print('Ignoring exception in command {}:'.format(ctx.command), file=sys.stderr) # traceback.print_exception(type(exception), exception, exception.__traceback__, file=sys.stderr) ## Permissions error? if (isinstance(exception, CommandInvokeError) and isinstance(exception.original, TimeoutError)): await self.bot.say("Sorry <@{}>, I'm not able to join the voice channel right now. Discord might be having issues, or I might not have permission to join." .format(ctx.message.author.id)) return ## Poorly handled (for now, until I can get more concrete examples in my database) error messages for users if ("code =" in str(exception)): await self.bot.say("Sorry <@{}>, Discord is having some issues that won't let me speak right now." .format(ctx.message.author.id)) return ## Attempt to find a command that's similar to the one they wanted. Otherwise just direct them to the help page else: most_similar_command = self.find_most_similar_command(ctx.message.content) if (most_similar_command[0] == ctx.invoked_with): ## Handle issues where the command is valid, but couldn't be completed for whatever reason. await self.bot.say("Sorry <@{}>, I can't talk right now. Try again in a little bit.".format(ctx.message.author.id)) else: ## Otherwise, handle other issues involving invalid commands help_text_chunks = [ "Sorry <@{}>, **{}{}** isn't a valid command.".format(ctx.message.author.id, ctx.prefix, ctx.invoked_with) ] ## Build the output to give to the user if (most_similar_command[1] > self.invalid_command_minimum_similarity): help_text_chunks.append("Did you mean **{}{}**?".format(self.activation_str, most_similar_command[0])) else: help_text_chunks.append("Try the **{}help** page.".format(self.activation_str)) await self.bot.say(" ".join(help_text_chunks)) ## Methods ## Add an arbitary cog to the bot def add_cog(self, cls): self.bot.add_cog(cls) ## Returns a cog with a given name def get_cog(self, cls_name): return self.bot.get_cog(cls_name) ## Returns the bot's speech cog def get_speech_cog(self): return self.bot.get_cog("Speech") ## Returns the bot's phrases cog def get_phrases_cog(self): return self.bot.get_cog("Phrases") ## Returns the bot's music cog def get_music_cog(self): return self.bot.get_cog("Music") ## Register an arbitrary module with hawking (easy wrapper for self.module_manager.register) def register_module(self, cls, is_cog, *init_args, **init_kwargs): self.module_manager.register(cls, is_cog, *init_args, **init_kwargs) ## Finds the most similar command to the supplied one def find_most_similar_command(self, command): ## Build a message string that we can compare with. try: message = command[len(self.activation_str):].lower() except TypeError: message = command.lower() ## Get a list of all visible commands commands = [name for name, cmd in self.bot.commands.items() if not cmd.hidden] ## Find the most similar command most_similar_command = (None, 0) for key in commands: distance = StringSimilarity.similarity(key.lower(), message) if (distance > most_similar_command[1]): most_similar_command = (key, distance) return most_similar_command ## Run the bot def run(self): ## Keep bot going despite any misc service errors try: self.bot.run(utilities.load_json(self.token_file_path)[self.TOKEN_KEY]) except RuntimeError as e: utilities.debug_print("Critical Runtime Error when running bot:", e, debug_level=0) except Exception as e: utilities.debug_print("Critical exception when running bot:", e, debug_level=0) time.sleep(1) self.run()
raise ValueError('Please specify attention states for detection') if args.posthoc and (args.task != 'detect' or args.features): # Features and update rely on code changes raise ValueError('Posthoc setting not supported for given arguments') if args.test_mode: print('Starting evaluation: {}'.format( datetime.now().strftime("%m/%d/%Y %H:%M:%S"))) model = load_model(args.model_path, args.task == 'detect') evaluate(args.task, model, test_examples, args.model_name, args.rerank) print('Terminating evaluation: {}'.format( datetime.now().strftime("%m/%d/%Y %H:%M:%S"))) else: print('Starting training: {}'.format( datetime.now().strftime("%m/%d/%Y %H:%M:%S"))) manager = ModuleManager(args.attend_code_sequence_states, args.attend_code_graph_states, args.features, args.posthoc, args.task) manager.initialize(train_examples) model = build_model(args.task, args.model_path, manager) print('Model path: {}'.format(args.model_path)) sys.stdout.flush() train(model, train_examples, valid_examples) print('Terminating training: {}'.format( datetime.now().strftime("%m/%d/%Y %H:%M:%S")))