class YamlConf: """Wrapper class to pYaml - useful for more complex configurations""" def __init__(self, filename): self.log = Log() self.log.info("Opening YAML config file '{}'".format(filename)) try: with open(filename) as f: self.data = yaml.load(f.read()) except yaml.YAMLError as e: self.log.error("File '{}' cannot be parsed!".format(filename)) self.log.error("{}".format(e)) self.log.info("{} YAML parsed succesfully".format(filename)) def getValue(self, *keys): """Search through our data and find the specified key or subkey""" data = self.data ##Iterate through the key heirarchy for i in keys: try: data = data.get(i) except KeyError: self.log.error("Key {} not found".format( self._formatKey(keys))) return None return data def _formatKey(self, keys): """Pretty print a key heirarchy""" form = "" for key in keys: form += "{} -> ".format(key) return form[:-3]
def __init__(self, board): self.log = Log() self.log.info("Getting /{}/...".format(board)) try: self.board = chan.Board(board) self.log.info("/{}/ was fetched successfully".format(board)) except Exception as e: self.log.error("Failed to fetch /{}/ -- {}".format(board, e))
def __init__(self, filename, sep=":"): self.log = Log() self.filename = filename self.log.info("Reading {}".format(filename)) self.config = {} self.sep = sep self._readFile() self._extractConfig() self.log.info("Succesfully parsed {}".format(filename))
def __init__(self, filename): self.log = Log() self.log.info("Opening YAML config file '{}'".format(filename)) try: with open(filename) as f: self.data = yaml.load(f.read()) except yaml.YAMLError as e: self.log.error("File '{}' cannot be parsed!".format(filename)) self.log.error("{}".format(e)) self.log.info("{} YAML parsed succesfully".format(filename))
def __init__(self, corpus, n, debug=False, model=None): self.log = Log() if debug: self.log.setLevel(self.log.DEBUG) self.n = n self.log.info("Initialising {}-Gram model...".format(n)) if model: self.model = model else: if type(corpus) == type([]): self.buildModel(corpus) else: self.buildModel([corpus]) self.log.info("{}-Gram model ready for use".format(self.n))
def __init__(self, f_name, f_obj, help, module="Builtin"): self.log = Log() self.log.newline() self.log.info("Creating command {}".format(f_name)) self.log.line("-") self.name = f_name self.func = f_obj self.help = self.func.__doc__ or "" self.module = module self.admin_required = "admin" in self.func.__code__.co_varnames self.nargs = self.func.__code__.co_argcount self.defaults = self.func.__defaults__ self.argdefault = {} if (self.defaults): self.noptargs = len(self.defaults) else: self.noptargs = 0 self.args = self.func.__code__.co_varnames[:self.nargs - self.noptargs] self.optargs = self.func.__code__.co_varnames[self.nargs - self. noptargs:self.noptargs + 1] self.hints = typing.get_type_hints(self.func) if "self" in self.args: self.nargs -= 1 self.args = tuple([x for x in self.args if x != "self"]) for i in range(self.noptargs): self.argdefault[self.optargs[i]] = self.defaults[i] if self.nargs > 0: self.log.info("ARGS: " + ", ".join(self.args)) self.log.info("OPTARGS: " + ", ".join(self.optargs)) self.log.info("DEFAULTS: " + ", ".join([ "{}={}".format(i, self.argdefault[i]) for i in self.argdefault ])) else: self.log.info("No arguments") self.delim = "," self.NOSPLIT = "NOSPLIT" in self.func.__code__.co_varnames self.success = True self.log.line("-") self.log.info(self)
def __init__(self): self.log = Log() __builtins__["chat"] = self self.log.newline() self.log.info("SKYPE BOT INIT") self.log.line("+",40) self.log.incIndent() self.log.newline() self.log.info("SKYPE4PY STARTUP") self.log.line() self.log.incIndent() self.s = skype.Skype() ##Connect to the API self.s.Attach() self.log.decIndent() self.log.line() self.log.info("SKYPE4PY STARTED") self.log.newline() ##Set initial variables self.lastMessage = None ##Create a processor for all possible commands self.cmdProc = commandprocessor.CommandProcessor() ##Try to connect to the chat try: self.chat = self.s.ActiveChats[0] except Exception as e: print("Cloud chat not supported! {}".format(e)) sys.exit(1) ##Allow for some twiddling self.lastMessage = self.chat.Messages[0] ##Alert users to the bot presence self.log.line("+", 40) self.log.info("FINISHED SKYPE BOT INIT") self.log.newline()
def __init__(self, f_name, f_obj, help, module = "Builtin"): self.log = Log() self.log.newline() self.log.info("Creating command {}".format(f_name)) self.log.line("-") self.name = f_name self.func = f_obj self.help = self.func.__doc__ or "" self.module = module self.admin_required = "admin" in self.func.__code__.co_varnames self.nargs = self.func.__code__.co_argcount self.defaults = self.func.__defaults__ self.argdefault = {} if (self.defaults): self.noptargs = len(self.defaults) else: self.noptargs = 0 self.args = self.func.__code__.co_varnames[:self.nargs - self.noptargs] self.optargs = self.func.__code__.co_varnames[self.nargs-self.noptargs: self.noptargs+1] self.hints = typing.get_type_hints(self.func) if "self" in self.args: self.nargs -= 1 self.args = tuple([x for x in self.args if x != "self"]) for i in range(self.noptargs): self.argdefault[self.optargs[i]] = self.defaults[i] if self.nargs > 0: self.log.info("ARGS: " + ", ".join(self.args)) self.log.info("OPTARGS: " + ", ".join(self.optargs)) self.log.info("DEFAULTS: " + ", ".join( ["{}={}".format( i, self.argdefault[i]) for i in self.argdefault])) else: self.log.info("No arguments") self.delim = "," self.NOSPLIT = "NOSPLIT" in self.func.__code__.co_varnames self.success = True self.log.line("-") self.log.info(self)
class FourChan: """Wrapper class to py4chan - 4chan API""" def __init__(self, board): self.log = Log() self.log.info("Getting /{}/...".format(board)) try: self.board = chan.Board(board) self.log.info("/{}/ was fetched successfully".format(board)) except Exception as e: self.log.error("Failed to fetch /{}/ -- {}".format(board, e)) def getPosts(self,limit=10): self.log.info("Getting posts - limit of {}".format(limit)) return self.board.get_all_thread_ids()[:limit+1] def getTitles(self): self.log.info("Getting thread titles...") q = [] for x in self.getPosts(): b = self.board.get_thread(x).posts q += [self._scrub(y.comment) for y in b] self.log.info("Got titles of threads successfully") return [x for x in q if x != ''] def _scrub(self, post): """Clean up the posts, remove all HTML and formatting""" scrubs = ["<span class=\"quote\">", "<br>", "</span>","</s>"] for i in scrubs: post = post.replace(i, " ") post = post.replace(">", ">").replace("'", "'").replace(""", "\"") post = post.replace("<", "<") q = re.compile("<\/?[A-Za-z0-9\/\=\#\"\': ]*>") for w in q.findall(post): post = post.replace(w, "") postnums = re.compile(">?[0-9]{4,}") for w in postnums.findall(post): post = post.replace(w, "") return post.replace(">\n","").replace("\n", "")
def __init__(self, configfile="command-proc.conf"): super(CommandProcessor, self).__init__() #Open a logger for superior feedback(tm) self.log = Log() #Alert the user that we're starting the processor self.log.info("Command Processor Created") self.log.newline() self.log.info("CMDPROC INIT") self.log.line() self.log.incIndent() #Set up some initial variables self.triggers = [] self.services = [] self.pipes = [] self.commands = {} self.loadedModules = ["Builtin"] #Read in the config self.log.info("Reading config...") self.config = YamlConf(configfile) self.log.info("Setting config...") #Load in the config #The getValue() or "Value" means that we have a default #So if we can't get something from the config, it defaults to something self.bot_name = self.config.getValue("bot", "name") or "Bot" self.bot_version = self.config.getValue("bot", "version") or "0.01" self.msg_prefix = self.config.getValue("bot", "msg_prefix") or "BOT: " self.command_prefix = self.config.getValue("bot", "cmd_prefix") or "!" debug = self.config.getValue("bot", "debug_logging") or False module_path = self.config.getValue("modules", "path") or "." #This means python will be able to find modules #When python looks for things, it goes down a so-called PYTHONPATH #We give it some new directories to look in self.module_path = module_path sys.path.insert(0, module_path) initial_modules = self.config.getValue("modules", "load") or [] inital_triggers = self.config.getValue("triggers") or [] self.admins = self.config.getValue("admins") self.log.info("Read config.") #callback means that we run a function once we're done #processing something, so like we can go # output = process("!hello") # callback(output) #By default it's just print, so we print the output self.callback = print #Set up the input and output queues self.log.info("Initilising command queue...") self.cmdQ = queue.Queue() self.log.info("Initilising output queue...") self.outputQ = queue.Queue() #Set up some stuff so we can tell the commandprocessor to stop #when we want to exit, we turn the Event on self.log.info("Initilising requests...") self.stopReq = threading.Event() self.stopNOW = threading.Event() #We have a few "initial modules", things to load on startup self.log.info("Setting up modules...") for i in initial_modules: self.loadModule(i) #Same goes for triggers self.log.info("Setting up triggers...") for i in inital_triggers: self.addTrigger(i, inital_triggers[i]) #If the user wants more information than usual, they can set debug to True self.log.info("Setting verbosity...") if debug: self.log.setLevel(self.log.DEBUG) #For reference: an underscore before the function name means that it only has INTERNAL use, #i.e nobody outside this class should call _addUtilityCommands() self._addUtilityCommands() #Tell the user that we've finished setting everything up self.log.line() self.log.info("FINISHED CMDPROC INIT") self.log.newline()
#!/usr/bin/env python3 from floatingutils.log import Log log = Log() log.info("API Module Ready.")
#!/usr/bin/env python3 from floatingutils.log import Log log = Log() log.info("Artificial Intelligence Module Ready.")
def __init__(self, useragent="FloatingGhost's python utility"): self.log = Log() self.log.info("Connecting to reddit...") self.api = praw.Reddit(user_agent=useragent) self.log.info("Connected.")
class Reddit: def __init__(self, useragent="FloatingGhost's python utility"): self.log = Log() self.log.info("Connecting to reddit...") self.api = praw.Reddit(user_agent=useragent) self.log.info("Connected.") def getSub(self, subname, limit=100): """Get a subreddit""" self.log.info("Retrieving r/{}".format(subname)) return self.api.get_subreddit(subname).get_hot(limit=limit) def getOPs(self, subname, limit=20): """Get the self text of the OPs in a subreddit""" self.log.info("Getting the OP self text in {} (limit {})".format(subname,limit)) x = self.getSub(subname, limit) return [y.selftext for y in x if y.selftext != ''] def getSubTitles(self, subname, limit=500): """Get the titles of a subreddit's posts""" self.log.info("Getting the titles in r/{}".format(subname)) return [str(x).split("::")[-1][1:] for x in self.getSub(subname, limit)] def getComments(self, subname, limit=500): """Get the comments of a subreddit""" self.log.info("Getting the comments of r/{}".format(subname)) x = self.api.get_subreddit(subname).get_comments(limit=limit) return [y.body for y in x]
class NGram: """Class for an N-Gram model of a natural language corpus""" def __init__(self, corpus, n, debug=False, model=None): self.log = Log() if debug: self.log.setLevel(self.log.DEBUG) self.n = n self.log.info("Initialising {}-Gram model...".format(n)) if model: self.model = model else: if type(corpus) == type([]): self.buildModel(corpus) else: self.buildModel([corpus]) self.log.info("{}-Gram model ready for use".format(self.n)) def buildModel(self, list_corpus): """Build a model from a list of strings""" #Pad out the message corpus = "" self.log.info("Creating N-Gram model from {} string{}".format( len(list_corpus), "s" if len(list_corpus) > 1 else "")) for i in list_corpus: #Remove punctuation i = i.replace(",", " ").replace(".", " ") corpus += " <s> " * (self.n - 1) + i + " <s> " * (self.n - 2) + " <end>" corpus = corpus.strip().lower() nlen = [] self.log.info("Splitting corpus into {} length strings".format(self.n)) corpus = [x for x in corpus.split(" ") if x != ''] for i in range(len(corpus) - 1): nlen.append(corpus[i:i + self.n]) if len(nlen) > 6000: nlen = nlen[:6000] qqq = len(nlen) self.log.info("Processing {} {}-length strings".format( len(nlen), self.n)) self.model = [] endWords = [] givenWords = [] for i in nlen: word = i[-1] given = i[:-1] if word not in endWords: endWords.append(word) if given not in givenWords: givenWords.append(given) self.log.info("Calculating probabilities...") #calculate probs percentages = range(10, 101, 10) for w in givenWords: p = givenWords.index(w) / qqq p = 100 * p if p > percentages[0]: self.log.info("{}% done...".format(p)) percentages = percentages[1:] occurances = [x for x in nlen if x[:-1] == w] for x in occurances: y = x[-1] ##endword endswith = [z for z in occurances if z[-1] == y] ##Count number of occurrences try: modelAdd = [ x[-1], w, 1.0 / (1 + len(occurances) - len(endswith)) ] except ZeroDivisionError: ##Prob must be 1 modelAdd = [x[-1], w, 1.0] self.model.append(modelAdd) self.log.info("{}-Gram model built!".format(self.n)) def generate(self): """Generate a possible message from the model""" self.log.info("Generating a possible string...") try: m = "<s>" while m.split(" ")[-1] != "<end>": m += " " + random.choice( self.getAllFromGiven(m.split(" ")[-self.n + 1:])) self.log.info("Generated!") return m.replace("<s>", "").replace("<end>", "") except IndexError: return "Could not generate... not enough data!" def getAllFromGiven(self, given): """Get all instances of x, where (given, x) is a member of the model""" j = [] for i in self.model: if i[1] == given: j.append(i[0]) return j def getProb(self, word, given): """Get P(word|given)""" ##Find P(word | given) for i in self.model: g = listtostr_(i[1]) if i[0] == word and given == g: return i[2] return 0
class CommandProcessor(threading.Thread): """Thread-based module for processing commands. Takes in commands from a queue, processes them asyncronously, outputs to another queue. ARGS: configfile -- The file to load in all of our configuration from """ def __init__(self, configfile="command-proc.conf"): super(CommandProcessor, self).__init__() #Open a logger for superior feedback(tm) self.log = Log() #Alert the user that we're starting the processor self.log.info("Command Processor Created") self.log.newline() self.log.info("CMDPROC INIT") self.log.line() self.log.incIndent() #Set up some initial variables self.triggers = [] self.services = [] self.pipes = [] self.commands = {} self.loadedModules = ["Builtin"] #Read in the config self.log.info("Reading config...") self.config = YamlConf(configfile) self.log.info("Setting config...") #Load in the config #The getValue() or "Value" means that we have a default #So if we can't get something from the config, it defaults to something self.bot_name = self.config.getValue("bot", "name") or "Bot" self.bot_version = self.config.getValue("bot", "version") or "0.01" self.msg_prefix = self.config.getValue("bot", "msg_prefix") or "BOT: " self.command_prefix = self.config.getValue("bot", "cmd_prefix") or "!" debug = self.config.getValue("bot", "debug_logging") or False module_path = self.config.getValue("modules", "path") or "." #This means python will be able to find modules #When python looks for things, it goes down a so-called PYTHONPATH #We give it some new directories to look in self.module_path = module_path sys.path.insert(0, module_path) initial_modules = self.config.getValue("modules", "load") or [] inital_triggers = self.config.getValue("triggers") or [] self.admins = self.config.getValue("admins") self.log.info("Read config.") #callback means that we run a function once we're done #processing something, so like we can go # output = process("!hello") # callback(output) #By default it's just print, so we print the output self.callback = print #Set up the input and output queues self.log.info("Initilising command queue...") self.cmdQ = queue.Queue() self.log.info("Initilising output queue...") self.outputQ = queue.Queue() #Set up some stuff so we can tell the commandprocessor to stop #when we want to exit, we turn the Event on self.log.info("Initilising requests...") self.stopReq = threading.Event() self.stopNOW = threading.Event() #We have a few "initial modules", things to load on startup self.log.info("Setting up modules...") for i in initial_modules: self.loadModule(i) #Same goes for triggers self.log.info("Setting up triggers...") for i in inital_triggers: self.addTrigger(i, inital_triggers[i]) #If the user wants more information than usual, they can set debug to True self.log.info("Setting verbosity...") if debug: self.log.setLevel(self.log.DEBUG) #For reference: an underscore before the function name means that it only has INTERNAL use, #i.e nobody outside this class should call _addUtilityCommands() self._addUtilityCommands() #Tell the user that we've finished setting everything up self.log.line() self.log.info("FINISHED CMDPROC INIT") self.log.newline() def join(self, timeout=None): """When the owner of CommandProcessor wants us to exit, we alert the user that we've recieved the quit request, and shut everythig down """ self.log.info("QUITTING") self.log.line("Q") #Tell the processing function to stop self.stopReq.set() #Join the thread to the main process, #wait for `timeout` seconds before forcing it to. super(Thread, self).join(timeout) def addCommand(self, function_name, function_object, help=None, module="Builtin"): """Add a command to the processor ARGS: function_name: The name you wish to call the function by, i.e "func" function_object: The actual object to run when you call the command """ self.log.info("Adding command {}".format(function_name)) #Check if we've already got a command by name `function_name` if function_name in self.commands: self.log.info("Command {} already registered. Overwriting") #Make a nice little command object, for keeping track of it com = Command(function_name, function_object, help=help, module=module) #Make sure it actually worked yo if com.success: self.commands[function_name] = com else: self.log.info("Failed to add command") def removeCommand(self, function_name): """WHAT THE FEK DO YOU THINK IT DOES? MAKE CAKE? NO. IT REMOVES A COMMAND!""" #Check that we've actually got a command by that name if function_name in self.commands: #If we do, delete it! del self.commands[function_name] self.log.info("Succesfully removed {}".format(function_name)) else: #Otherwise, we can't. Because you can't delete something that doesn't exist, dummy self.log.info("Could not remove non-existent function {}".format( function_name)) def addTrigger(self, trigger_text, replacement_text): """Add a text-based trigger - will send replacement_text when trigger_text is in a given message""" #Check if we've got a trigger about that already, because we might for trigger in self.triggers: if trigger.trigger == trigger_text: #If we do, modifify it to the new trigger trigger.send_text = replacement_text return ("Modified trigger to {}".format(trigger)) #If we haven't got a trigger about `trigger_text`, #make a new one self.triggers.append(Trigger(trigger_text, replacement_text)) self.log.info("Added {}".format(self.triggers[-1])) return ("Added -- {}".format(self.triggers[-1])) def writeConfig(self): """Save the config, all currently loaded modules will be saved to init_modules""" self.log.info("Writing config...") #Add all of our triggers to a nice little dictionary, #So we can write it to a file trigs = {} for i in self.triggers: trigs[i.trigger] = i.send_text settings = { "bot": { "name": self.bot_name, "version": self.bot_version, "msg_prefix": self.msg_prefix, "cmd_prefix": self.command_prefix, "debug_logging": False }, "modules": { "path": self.module_path, "load": self.loadedModules }, "triggers": trigs, "ai": { "model_directory": "models" }, "admins": self.admins } self.log.info(settings) #Write the config in YAML format with open("command-proc.conf", "w") as f: f.write(pyaml.dump(settings)) self.log.info("Written") def removeTrigger(self, txt): """Remove the trigger with `trigger_text` == `txt`""" for trigger in self.triggers: if trigger.trigger == txt: self.triggers.remove(trigger) return ("Removed {}".format(trigger)) def setCallback(self, function): """Set the function to run on function complete ARGS: function (python function)""" self.callback = function def _process(self, command): """Internal process command - parse the command and execute""" self.log.info("Processing request {}...".format(command[0])) #Remove trailing and preceeding spaces #isinstance checks if command is a string or list #e.g isinstance("hello", str) is True #isinstance("hello", list) is False if isinstance(command, str): command = [command, None] if isinstance(command[0], list): command = command[0] command[0] = command[0].strip() try: #Check if it's a command or not if command[0][0] == self.command_prefix: #It's a command self._checkAgainstCommands(command) else: #We'll check it against the triggers self._checkAgainstTriggers(command) except Exception: pass def _checkAgainstCommands(self, command): command, channel = command command = command[1:] command_name, sep, args = command.partition(" ") if command_name in self.commands: #Now we've verified, go ahead and run it try: cmd = self.commands[command_name].run(args) if type(cmd) == types.GeneratorType: for i in cmd: self.output([i, channel]) else: self.output([cmd, channel]) except ArgumentFormatError: self.output("Error running {} -- Argument format error".format( command_name)) except TypeError: pass else: self.log.info( "No command of name {} detected".format(command_name)) self.output( "Error running {} -- Command not found".format(command_name)) def output(self, val): self.outputQ.put(val) if self.callback: self.callback(*val) def _checkAgainstTriggers(self, command): for i in self.triggers: if i.match(command[0]): self.output([i.send_text, command[1]]) def getOutput(self): try: x = self.outputQ.get(False) except queue.Empty: return None return x def run(self): """Start the thread off""" self.log.info("Command processor thread starting...") while (not self.stopReq.isSet()) or self.cmdQ.qsize() != 0: if self.stopNOW.isSet(): break try: toProcess = self.cmdQ.get(True, 0.5) self._process(toProcess) except queue.Empty: continue except Exception as e: self.log.error(e) traceback.format_exc(e) self.log.info("Stopping with qsize: {}".format(self.cmdQ.qsize())) self.log.info("Stopreq state: {}".format(self.stopReq.isSet())) self.log.info("Thread closed.") def push(self, commandstring, assoc_info=None): """Add a command to the command queue - to be processed commands ARGS: commandstring (str) - the command to process assoc_info (Any) - Things to be returned with the processed cmd""" self.log.info("Pushing command {}".format(commandstring)) self.cmdQ.put([commandstring, assoc_info]) for pipe in self.pipes: pipe.put([commandstring, assoc_info]) def exit(self, now=False): """Quit the thread, cleanly exit""" admin = 1 yield "Closing..." self.log.info("Exit request acknowledged, will exit.") self.stopReq.set() if (now): self.stopNOW.set() ##Module loading/unloading def loadModule(self, name): self.log.newline() self.log.info("LOADING MODULE {}".format(name.upper())) self.log.line() self.log.incIndent() try: ##Try loading the module as i yield ("Importing {}...".format(name)) i = importlib.import_module(name) ##In case it's changed and was imported before, reload it self.log.debug("Reloading...") i = importlib.reload(i) ##Get a list of all the functions defined in the module self.log.debug("Getting functions...") funcs = dir(i) ##Don't import python's internal functions, like __name__ and __init__ x = re.compile("__[a-z]*__") z = ([("i.{}".format(y)) for y in funcs if not (x.match(y) or y[-1] == "_")]) self.log.debug("Loaded, adding functions...") self.log.incIndent() self.funcs = "Loaded functions:\n" ##Load the functions in for j in z: if type(eval(j)) == types.FunctionType: if "onimport" in j: self.log.info("Running import function...") eval(j)() elif "onexit" in j: atexit.register(eval(j)) else: self.addCommand(j.split(".")[1], eval(j), module=name) self.funcs += "!{}, ".format(j.split(".")[1]) if name not in self.loadedModules: self.loadedModules.append(name) yield (self.funcs) except ImportError as ie: self.log.error("Could not find module {}".format(name)) self.log.error(ie) except Exception as e: self.log.error("Unknown exception: {}".format(e)) def unloadModule(self, module_name): yield "Unloading module {}".format(module_name) funcs = "( " for i in self.commands: if self.commands[i].module == module_name: self.removeCommand(i) funcs += i + ", " self.loadedModules.remove(module_name) self.log.info("Unloaded {} {} )".format(module_name, funcs)) def lsmod(self): """List all currently loaded modules""" x = "Loaded modules: \n" x += "\n".join(self.loadedModules) return (x + "\n") def getHelp(self, cmd=None): if cmd: if cmd in self.commands: return (self.commands[cmd].getHelp()) else: return ("Command {} does not exist".format(cmd)) else: #Return list of commands return "Available Commands: " + ", ".join(self.commands) def listTriggers(self): return "\n".join([str(x) for x in self.triggers]) def loadService(self, srvname): self.services.append( Service(name=srvname, function=function, autostart=True)) def startService(self, srvname): for i in self.services: if i.name == srvname: i.start() return "Started" return "Service not found" def killService(self, srvname): for i in self.services: if i.name == srvname: i.stop() self.services.remove(i) return "Killed" return "Service not found" def lsService(self): x = [i.name for i in self.services] return "\n".join(x) def _addUtilityCommands(self): self.addCommand("lsmod", self.lsmod) self.addCommand("import", self.loadModule) self.addCommand("quit", self.exit) self.addCommand("help", self.getHelp) self.addCommand("mktrig", self.addTrigger) self.addCommand("rmtrig", self.removeTrigger) self.addCommand("lstrig", self.listTriggers) self.addCommand("writeconf", self.writeConfig) self.addCommand("loadSrv", self.loadService) self.addCommand("startSrv", self.startService) self.addCommand("killSrv", self.killService) self.addCommand("lsSrv", self.lsService)
#!/usr/bin/env python3 from floatingutils.log import Log import requests import sys log = Log() class Client: def __init__(self, IP: str, PORT: int, protocol: str = "http"): self.ip = IP self.port = PORT self.socket = "{}://{}:{}".format(protocol, IP, PORT) log.info("Connecting to server {}".format(self.socket)) def post(self, path, data: dict = {}): try: data["SESSION_KEY"] = self.session except AttributeError: pass try: r = requests.post("{}/{}".format(self.socket, path), data=data) except requests.exceptions.ConnectionError: log.error("Server did not respond.") sys.exit(1) return self._processResponse(r.text) def getServerPub(self):
#!/usr/bin/env python3 from floatingutils.log import Log Log().info("Utils ready.")
class FourChan: """Wrapper class to py4chan - 4chan API""" def __init__(self, board): self.log = Log() self.log.info("Getting /{}/...".format(board)) try: self.board = chan.Board(board) self.log.info("/{}/ was fetched successfully".format(board)) except Exception as e: self.log.error("Failed to fetch /{}/ -- {}".format(board, e)) def getPosts(self, limit=10): self.log.info("Getting posts - limit of {}".format(limit)) return self.board.get_all_thread_ids()[:limit + 1] def getTitles(self): self.log.info("Getting thread titles...") q = [] for x in self.getPosts(): b = self.board.get_thread(x).posts q += [self._scrub(y.comment) for y in b] self.log.info("Got titles of threads successfully") return [x for x in q if x != ''] def _scrub(self, post): """Clean up the posts, remove all HTML and formatting""" scrubs = ["<span class=\"quote\">", "<br>", "</span>", "</s>"] for i in scrubs: post = post.replace(i, " ") post = post.replace(">", ">").replace("'", "'").replace(""", "\"") post = post.replace("<", "<") q = re.compile("<\/?[A-Za-z0-9\/\=\#\"\': ]*>") for w in q.findall(post): post = post.replace(w, "") postnums = re.compile(">?[0-9]{4,}") for w in postnums.findall(post): post = post.replace(w, "") return post.replace(">\n", "").replace("\n", "")
class Chat: """Represents a chat class in a skype client""" def __init__(self): self.log = Log() __builtins__["chat"] = self self.log.newline() self.log.info("SKYPE BOT INIT") self.log.line("+",40) self.log.incIndent() self.log.newline() self.log.info("SKYPE4PY STARTUP") self.log.line() self.log.incIndent() self.s = skype.Skype() ##Connect to the API self.s.Attach() self.log.decIndent() self.log.line() self.log.info("SKYPE4PY STARTED") self.log.newline() ##Set initial variables self.lastMessage = None ##Create a processor for all possible commands self.cmdProc = commandprocessor.CommandProcessor() ##Try to connect to the chat try: self.chat = self.s.ActiveChats[0] except Exception as e: print("Cloud chat not supported! {}".format(e)) sys.exit(1) ##Allow for some twiddling self.lastMessage = self.chat.Messages[0] ##Alert users to the bot presence self.log.line("+", 40) self.log.info("FINISHED SKYPE BOT INIT") self.log.newline() def send(self, msg): """Send a message to the chat""" if msg != None and msg != "" and type(msg) != type(True): self.chat.SendMessage(">>>"+msg) def processMessage(self): """Figure out what to do with the last received message""" if ">>>" not in self.lastMessage.Body: self.log.info("Processing {}".format(self.lastMessage.Body)) self.cmdProc.push([self.lastMessage.Body, None]) def mainloop(self): self.log.info("Starting mainloop...") self.cmdProc.start() threading.Thread(target=self.getOutput).start() self.log.info("Started thread.") while 1: try: newmsg = self.chat.Messages[0] if self.lastMessage != newmsg: self.lastMessage = newmsg self.processMessage() except KeyboardInterrupt: sys.exit() def addCommand(self, cmdName, func): self.cmdProc.addCommand(cmdName, func) def getAllBy(self, handle): return [i.Body for i in self.chat.Messages if str(i.FromHandle).lower() == handle] def getOutput(self): self.log.info("Starting output thread...") while True: x = (self.cmdProc.getOutput()) if type(x) == list: self.send(x[0]) else: self.send(x)
class Reddit: def __init__(self, useragent="FloatingGhost's python utility"): self.log = Log() self.log.info("Connecting to reddit...") self.api = praw.Reddit(user_agent=useragent) self.log.info("Connected.") def getSub(self, subname, limit=100): """Get a subreddit""" self.log.info("Retrieving r/{}".format(subname)) return self.api.get_subreddit(subname).get_hot(limit=limit) def getOPs(self, subname, limit=20): """Get the self text of the OPs in a subreddit""" self.log.info("Getting the OP self text in {} (limit {})".format( subname, limit)) x = self.getSub(subname, limit) return [y.selftext for y in x if y.selftext != ''] def getSubTitles(self, subname, limit=500): """Get the titles of a subreddit's posts""" self.log.info("Getting the titles in r/{}".format(subname)) return [ str(x).split("::")[-1][1:] for x in self.getSub(subname, limit) ] def getComments(self, subname, limit=500): """Get the comments of a subreddit""" self.log.info("Getting the comments of r/{}".format(subname)) x = self.api.get_subreddit(subname).get_comments(limit=limit) return [y.body for y in x]
class Conf: """Class for parsing simple (key sep value) format files""" def __init__(self, filename, sep=":"): self.log = Log() self.filename = filename self.log.info("Reading {}".format(filename)) self.config = {} self.sep = sep self._readFile() self._extractConfig() self.log.info("Succesfully parsed {}".format(filename)) def _readFile(self): """Read in the configuration file""" self.log.debug("Opening file {}".format(self.filename)) ##Open the config file try: f = open(self.filename, "r") except FileNotFoundError: self.log.error("File '{}' not found!".format(self.filename)) ##Read in each line, ignoring empty lines self.text = [x[:-1] for x in f.readlines() if x[:-1] != ""] self.log.debug("File read succesfully") ##Close the file f.close() self.log.debug("{} closed".format(self.filename)) def writeFile(self, alternateFile=None): """Write the changed configuration back to a file""" self.log.info("Writing config back to file") filename = self.filename ##Just in case the user wants to change location if alternateFile: filename = alternateFile self.log.info("Writing to {}".format(filename)) try: with open(filename, "w") as f: for i in sorted(self.config): f.write("{}:{}\n".format(i, self.config[i])) except Exception as e: self.log.warning("An error occurred -- {}".format(e)) return 1 self.log.debug("{} Written succesfully".format(filename)) return 0 def _extractConfig(self): """Get all the key value pairs from the config file""" ##Keep track of line of debug purposes lineno = 1 for i in self.text: ##Split the line by the seperator setting, sep, value = i.partition(self.sep) if setting in self.config: ##If we've already seen that key before self.log.warning("Duplicate setting '{}' (Line {})".format( setting, lineno)) else: ##Check for empty setting name if setting == "": self.log.warning( "Empty setting name (Line {})".format(lineno)) else: ##Check for empty value if value == "": self.log.warning( "Empty setting value '{}'(Line {})".format( setting, lineno)) else: ##It all looks good self.config[setting] = value lineno += 1 def getValue(self, key): """Get the value associated with a key""" if key in self.config: return self.config[key] else: ##If we can't find the key self.log.error("Setting '{}' not found!".format(key)) return 0 def getData(self, key): """Get the parsed value of a key - for lists and dicts""" x = self.getValue(key) return eval(x) def setValue(self, key, value): """Change the value of a setting""" if key == "": self.log.warning( "Non-empty keys only please! (value thrown: {})".format(value)) return False else: self.config[key] = value return True
#!/usr/bin/env python3 from floatingutils.log import Log log = Log() log.info("Networking submodule ready.")
class Command: def __init__(self, f_name, f_obj, help, module="Builtin"): self.log = Log() self.log.newline() self.log.info("Creating command {}".format(f_name)) self.log.line("-") self.name = f_name self.func = f_obj self.help = self.func.__doc__ or "" self.module = module self.admin_required = "admin" in self.func.__code__.co_varnames self.nargs = self.func.__code__.co_argcount self.defaults = self.func.__defaults__ self.argdefault = {} if (self.defaults): self.noptargs = len(self.defaults) else: self.noptargs = 0 self.args = self.func.__code__.co_varnames[:self.nargs - self.noptargs] self.optargs = self.func.__code__.co_varnames[self.nargs - self. noptargs:self.noptargs + 1] self.hints = typing.get_type_hints(self.func) if "self" in self.args: self.nargs -= 1 self.args = tuple([x for x in self.args if x != "self"]) for i in range(self.noptargs): self.argdefault[self.optargs[i]] = self.defaults[i] if self.nargs > 0: self.log.info("ARGS: " + ", ".join(self.args)) self.log.info("OPTARGS: " + ", ".join(self.optargs)) self.log.info("DEFAULTS: " + ", ".join([ "{}={}".format(i, self.argdefault[i]) for i in self.argdefault ])) else: self.log.info("No arguments") self.delim = "," self.NOSPLIT = "NOSPLIT" in self.func.__code__.co_varnames self.success = True self.log.line("-") self.log.info(self) def getHelp(self): h = self.name + ":\n" + self.help if self.nargs > 0: h += "\nARGS: " + ", ".join(self.args) + "\n" if self.noptargs > 0: h += "\nOPTARGS: " + " , ".join(self.optargs) if "\n" not in h: h += " (No Arguments)" return h def run(self, args, user_is_admin=False): if self.admin_required and not user_is_admin: self.log.warning("{} requires administrative permissions".format( self.name)) self.log.newline() self.log.newline() self.log.line("+") if not self.NOSPLIT: args = self._formatArgs(args.split(self.delim)) else: args = self._formatArgs([args]) self.log.info("Running {} with args {}".format(self.name, args)) output = self.func(**args) self.log.line("+") self.log.newline() self.log.newline() return output def _formatArgs(self, args): args = [x.strip() for x in args if x != ''] processedArgs = {} allargs = self.args + self.optargs for i in range(self.nargs): arg = "" argn = allargs[i] if i >= len(args): arg = self.argdefault[argn] else: arg = args[i] if allargs[i] in self.hints: try: arg = self.hints[argn](arg) except ValueError as ex: raise ArgumentFormatError(ex) processedArgs[argn] = arg return processedArgs def __repr__(self): x = "\n\nCOMMAND DEFINITION ::- \n" return x + "\nCommand (\n Name: {}.{},\n Args: {},\n OptArgs: {}\n Admin: {}\n)\n".format( self.module, self.name, self.args, self.optargs, self.admin_required)
class CommandProcessor(threading.Thread): """Thread-based module for processing commands. Takes in commands from a queue, processes them asyncronously, outputs to another queue. ARGS: configfile -- The file to load in all of our configuration from """ def __init__(self, configfile = "command-proc.conf"): super(CommandProcessor, self).__init__() #Open a logger for superior feedback(tm) self.log = Log() #Alert the user that we're starting the processor self.log.info("Command Processor Created") self.log.newline() self.log.info("CMDPROC INIT") self.log.line() self.log.incIndent() #Set up some initial variables self.triggers = [] self.services = [] self.pipes = [] self.commands = {} self.loadedModules = ["Builtin"] #Read in the config self.log.info("Reading config...") self.config = YamlConf(configfile) self.log.info("Setting config...") #Load in the config #The getValue() or "Value" means that we have a default #So if we can't get something from the config, it defaults to something self.bot_name = self.config.getValue("bot", "name") or "Bot" self.bot_version = self.config.getValue("bot", "version") or "0.01" self.msg_prefix = self.config.getValue("bot", "msg_prefix") or "BOT: " self.command_prefix = self.config.getValue("bot", "cmd_prefix") or "!" debug = self.config.getValue("bot", "debug_logging") or False module_path = self.config.getValue("modules", "path") or "." #This means python will be able to find modules #When python looks for things, it goes down a so-called PYTHONPATH #We give it some new directories to look in self.module_path = module_path sys.path.insert(0, module_path) initial_modules = self.config.getValue("modules", "load") or [] inital_triggers = self.config.getValue("triggers") or [] self.admins = self.config.getValue("admins") self.log.info("Read config.") #callback means that we run a function once we're done #processing something, so like we can go # output = process("!hello") # callback(output) #By default it's just print, so we print the output self.callback = print #Set up the input and output queues self.log.info("Initilising command queue...") self.cmdQ = queue.Queue() self.log.info("Initilising output queue...") self.outputQ = queue.Queue() #Set up some stuff so we can tell the commandprocessor to stop #when we want to exit, we turn the Event on self.log.info("Initilising requests...") self.stopReq = threading.Event() self.stopNOW = threading.Event() #We have a few "initial modules", things to load on startup self.log.info("Setting up modules...") for i in initial_modules: self.loadModule(i) #Same goes for triggers self.log.info("Setting up triggers...") for i in inital_triggers: self.addTrigger(i, inital_triggers[i]) #If the user wants more information than usual, they can set debug to True self.log.info("Setting verbosity...") if debug: self.log.setLevel(self.log.DEBUG) #For reference: an underscore before the function name means that it only has INTERNAL use, #i.e nobody outside this class should call _addUtilityCommands() self._addUtilityCommands() #Tell the user that we've finished setting everything up self.log.line() self.log.info("FINISHED CMDPROC INIT") self.log.newline() def join(self, timeout=None): """When the owner of CommandProcessor wants us to exit, we alert the user that we've recieved the quit request, and shut everythig down """ self.log.info("QUITTING") self.log.line("Q") #Tell the processing function to stop self.stopReq.set() #Join the thread to the main process, #wait for `timeout` seconds before forcing it to. super(Thread, self).join(timeout) def addCommand(self, function_name, function_object, help=None, module="Builtin"): """Add a command to the processor ARGS: function_name: The name you wish to call the function by, i.e "func" function_object: The actual object to run when you call the command """ self.log.info("Adding command {}".format(function_name)) #Check if we've already got a command by name `function_name` if function_name in self.commands: self.log.info("Command {} already registered. Overwriting") #Make a nice little command object, for keeping track of it com = Command(function_name, function_object, help=help, module=module) #Make sure it actually worked yo if com.success: self.commands[function_name] = com else: self.log.info("Failed to add command") def removeCommand(self, function_name): """WHAT THE FEK DO YOU THINK IT DOES? MAKE CAKE? NO. IT REMOVES A COMMAND!""" #Check that we've actually got a command by that name if function_name in self.commands: #If we do, delete it! del self.commands[function_name] self.log.info("Succesfully removed {}".format(function_name)) else: #Otherwise, we can't. Because you can't delete something that doesn't exist, dummy self.log.info("Could not remove non-existent function {}".format(function_name)) def addTrigger(self, trigger_text, replacement_text): """Add a text-based trigger - will send replacement_text when trigger_text is in a given message""" #Check if we've got a trigger about that already, because we might for trigger in self.triggers: if trigger.trigger == trigger_text: #If we do, modifify it to the new trigger trigger.send_text = replacement_text return ("Modified trigger to {}".format(trigger)) #If we haven't got a trigger about `trigger_text`, #make a new one self.triggers.append(Trigger(trigger_text, replacement_text)) self.log.info("Added {}".format(self.triggers[-1])) return ("Added -- {}".format(self.triggers[-1])) def writeConfig(self): """Save the config, all currently loaded modules will be saved to init_modules""" self.log.info("Writing config...") #Add all of our triggers to a nice little dictionary, #So we can write it to a file trigs = {} for i in self.triggers: trigs[i.trigger] = i.send_text settings = { "bot" : { "name": self.bot_name, "version": self.bot_version, "msg_prefix": self.msg_prefix, "cmd_prefix": self.command_prefix, "debug_logging": False }, "modules" : { "path": self.module_path, "load": self.loadedModules }, "triggers": trigs, "ai": { "model_directory": "models" }, "admins": self.admins } self.log.info(settings) #Write the config in YAML format with open("command-proc.conf", "w") as f: f.write(pyaml.dump(settings)) self.log.info("Written") def removeTrigger(self, txt): """Remove the trigger with `trigger_text` == `txt`""" for trigger in self.triggers: if trigger.trigger == txt: self.triggers.remove(trigger) return ("Removed {}".format(trigger)) def setCallback(self, function): """Set the function to run on function complete ARGS: function (python function)""" self.callback = function def _process(self, command): """Internal process command - parse the command and execute""" self.log.info("Processing request {}...".format(command[0])) #Remove trailing and preceeding spaces #isinstance checks if command is a string or list #e.g isinstance("hello", str) is True #isinstance("hello", list) is False if isinstance(command, str): command = [command, None] if isinstance(command[0], list): command = command[0] command[0] = command[0].strip() try: #Check if it's a command or not if command[0][0] == self.command_prefix: #It's a command self._checkAgainstCommands(command) else: #We'll check it against the triggers self._checkAgainstTriggers(command) except Exception: pass def _checkAgainstCommands(self, command): command,channel = command command = command[1:] command_name,sep,args = command.partition(" ") if command_name in self.commands: #Now we've verified, go ahead and run it try: cmd = self.commands[command_name].run(args) if type(cmd) == types.GeneratorType: for i in cmd: self.output([i, channel]) else: self.output([cmd, channel]) except ArgumentFormatError: self.output("Error running {} -- Argument format error".format(command_name)) except TypeError: pass else: self.log.info("No command of name {} detected".format(command_name)) self.output("Error running {} -- Command not found".format(command_name)) def output(self, val): self.outputQ.put(val) if self.callback: self.callback(*val) def _checkAgainstTriggers(self, command): for i in self.triggers: if i.match(command[0]): self.output([i.send_text, command[1]]) def getOutput(self): try: x = self.outputQ.get(False) except queue.Empty: return None return x def run(self): """Start the thread off""" self.log.info("Command processor thread starting...") while (not self.stopReq.isSet()) or self.cmdQ.qsize() != 0: if self.stopNOW.isSet(): break try: toProcess = self.cmdQ.get(True, 0.5) self._process(toProcess) except queue.Empty: continue except Exception as e: self.log.error(e) traceback.format_exc(e) self.log.info("Stopping with qsize: {}".format(self.cmdQ.qsize())) self.log.info("Stopreq state: {}".format(self.stopReq.isSet())) self.log.info("Thread closed.") def push(self, commandstring, assoc_info = None): """Add a command to the command queue - to be processed commands ARGS: commandstring (str) - the command to process assoc_info (Any) - Things to be returned with the processed cmd""" self.log.info("Pushing command {}".format(commandstring)) self.cmdQ.put([commandstring, assoc_info]) for pipe in self.pipes: pipe.put([commandstring, assoc_info]) def exit(self, now=False): """Quit the thread, cleanly exit""" admin = 1 yield "Closing..." self.log.info("Exit request acknowledged, will exit.") self.stopReq.set() if (now): self.stopNOW.set() ##Module loading/unloading def loadModule(self, name): self.log.newline() self.log.info("LOADING MODULE {}".format(name.upper())) self.log.line() self.log.incIndent() try: ##Try loading the module as i yield("Importing {}...".format(name)) i = importlib.import_module(name) ##In case it's changed and was imported before, reload it self.log.debug("Reloading...") i = importlib.reload(i) ##Get a list of all the functions defined in the module self.log.debug("Getting functions...") funcs = dir(i) ##Don't import python's internal functions, like __name__ and __init__ x = re.compile("__[a-z]*__") z = ([("i.{}".format(y)) for y in funcs if not (x.match(y) or y[-1]=="_")]) self.log.debug("Loaded, adding functions...") self.log.incIndent() self.funcs = "Loaded functions:\n" ##Load the functions in for j in z: if type(eval(j)) == types.FunctionType: if "onimport" in j: self.log.info("Running import function...") eval(j)() elif "onexit" in j: atexit.register(eval(j)) else: self.addCommand(j.split(".")[1], eval(j), module=name) self.funcs += "!{}, ".format(j.split(".")[1]) if name not in self.loadedModules: self.loadedModules.append(name) yield(self.funcs) except ImportError as ie: self.log.error("Could not find module {}".format(name)) self.log.error(ie) except Exception as e: self.log.error("Unknown exception: {}".format(e)) def unloadModule(self, module_name): yield "Unloading module {}".format(module_name) funcs = "( " for i in self.commands: if self.commands[i].module == module_name: self.removeCommand(i) funcs += i + ", " self.loadedModules.remove(module_name) self.log.info("Unloaded {} {} )".format(module_name, funcs)) def lsmod(self): """List all currently loaded modules""" x = "Loaded modules: \n" x += "\n".join(self.loadedModules) return( x + "\n" ) def getHelp(self, cmd=None): if cmd: if cmd in self.commands: return(self.commands[cmd].getHelp()) else: return("Command {} does not exist".format(cmd)) else: #Return list of commands return "Available Commands: "+", ".join(self.commands) def listTriggers(self): return "\n".join([str(x) for x in self.triggers]) def loadService(self, srvname): self.services.append( Service( name = srvname, function = function, autostart = True ) ) def startService(self, srvname): for i in self.services: if i.name == srvname: i.start() return "Started" return "Service not found" def killService(self, srvname): for i in self.services: if i.name == srvname: i.stop() self.services.remove(i) return "Killed" return "Service not found" def lsService(self): x = [i.name for i in self.services] return "\n".join(x) def _addUtilityCommands(self): self.addCommand("lsmod", self.lsmod) self.addCommand("import", self.loadModule) self.addCommand("quit", self.exit) self.addCommand("help", self.getHelp) self.addCommand("mktrig", self.addTrigger) self.addCommand("rmtrig", self.removeTrigger) self.addCommand("lstrig", self.listTriggers) self.addCommand("writeconf", self.writeConfig) self.addCommand("loadSrv", self.loadService) self.addCommand("startSrv", self.startService) self.addCommand("killSrv", self.killService) self.addCommand("lsSrv", self.lsService)
def __init__(self, configfile = "command-proc.conf"): super(CommandProcessor, self).__init__() #Open a logger for superior feedback(tm) self.log = Log() #Alert the user that we're starting the processor self.log.info("Command Processor Created") self.log.newline() self.log.info("CMDPROC INIT") self.log.line() self.log.incIndent() #Set up some initial variables self.triggers = [] self.services = [] self.pipes = [] self.commands = {} self.loadedModules = ["Builtin"] #Read in the config self.log.info("Reading config...") self.config = YamlConf(configfile) self.log.info("Setting config...") #Load in the config #The getValue() or "Value" means that we have a default #So if we can't get something from the config, it defaults to something self.bot_name = self.config.getValue("bot", "name") or "Bot" self.bot_version = self.config.getValue("bot", "version") or "0.01" self.msg_prefix = self.config.getValue("bot", "msg_prefix") or "BOT: " self.command_prefix = self.config.getValue("bot", "cmd_prefix") or "!" debug = self.config.getValue("bot", "debug_logging") or False module_path = self.config.getValue("modules", "path") or "." #This means python will be able to find modules #When python looks for things, it goes down a so-called PYTHONPATH #We give it some new directories to look in self.module_path = module_path sys.path.insert(0, module_path) initial_modules = self.config.getValue("modules", "load") or [] inital_triggers = self.config.getValue("triggers") or [] self.admins = self.config.getValue("admins") self.log.info("Read config.") #callback means that we run a function once we're done #processing something, so like we can go # output = process("!hello") # callback(output) #By default it's just print, so we print the output self.callback = print #Set up the input and output queues self.log.info("Initilising command queue...") self.cmdQ = queue.Queue() self.log.info("Initilising output queue...") self.outputQ = queue.Queue() #Set up some stuff so we can tell the commandprocessor to stop #when we want to exit, we turn the Event on self.log.info("Initilising requests...") self.stopReq = threading.Event() self.stopNOW = threading.Event() #We have a few "initial modules", things to load on startup self.log.info("Setting up modules...") for i in initial_modules: self.loadModule(i) #Same goes for triggers self.log.info("Setting up triggers...") for i in inital_triggers: self.addTrigger(i, inital_triggers[i]) #If the user wants more information than usual, they can set debug to True self.log.info("Setting verbosity...") if debug: self.log.setLevel(self.log.DEBUG) #For reference: an underscore before the function name means that it only has INTERNAL use, #i.e nobody outside this class should call _addUtilityCommands() self._addUtilityCommands() #Tell the user that we've finished setting everything up self.log.line() self.log.info("FINISHED CMDPROC INIT") self.log.newline()
class NGram: """Class for an N-Gram model of a natural language corpus""" def __init__(self, corpus, n, debug=False, model=None): self.log = Log() if debug: self.log.setLevel(self.log.DEBUG) self.n = n self.log.info("Initialising {}-Gram model...".format(n)) if model: self.model = model else: if type(corpus) == type([]): self.buildModel(corpus) else: self.buildModel([corpus]) self.log.info("{}-Gram model ready for use".format(self.n)) def buildModel(self, list_corpus): """Build a model from a list of strings""" #Pad out the message corpus = "" self.log.info("Creating N-Gram model from {} string{}".format(len(list_corpus), "s" if len(list_corpus)>1 else "")) for i in list_corpus: #Remove punctuation i = i.replace(","," ").replace("."," ") corpus += " <s> "*(self.n-1) + i + " <s> "*(self.n-2)+" <end>" corpus = corpus.strip().lower() nlen = [] self.log.info("Splitting corpus into {} length strings".format(self.n)) corpus = [x for x in corpus.split(" ") if x != ''] for i in range(len(corpus)-1): nlen.append(corpus[i:i+self.n]) if len(nlen) > 6000: nlen = nlen[:6000] qqq = len(nlen) self.log.info("Processing {} {}-length strings".format(len(nlen), self.n)) self.model = [] endWords = [] givenWords = [] for i in nlen: word = i[-1] given = i[:-1] if word not in endWords: endWords.append(word) if given not in givenWords: givenWords.append(given) self.log.info("Calculating probabilities...") #calculate probs percentages = range(10, 101, 10) for w in givenWords: p = givenWords.index(w) / qqq p = 100*p if p > percentages[0]: self.log.info("{}% done...".format(p)) percentages = percentages[1:] occurances = [x for x in nlen if x[:-1] == w] for x in occurances: y = x[-1] ##endword endswith = [z for z in occurances if z[-1] == y] ##Count number of occurrences try: modelAdd = [x[-1], w, 1.0 / (1+len(occurances)-len(endswith))] except ZeroDivisionError: ##Prob must be 1 modelAdd = [x[-1],w,1.0] self.model.append(modelAdd) self.log.info("{}-Gram model built!".format(self.n)) def generate(self): """Generate a possible message from the model""" self.log.info("Generating a possible string...") try: m = "<s>" while m.split(" ")[-1] != "<end>": m += " " + random.choice(self.getAllFromGiven(m.split(" ")[-self.n+1:])) self.log.info("Generated!") return m.replace("<s>","").replace("<end>","") except IndexError: return "Could not generate... not enough data!" def getAllFromGiven(self, given): """Get all instances of x, where (given, x) is a member of the model""" j = [] for i in self.model: if i[1] == given: j.append(i[0]) return j def getProb(self, word, given): """Get P(word|given)""" ##Find P(word | given) for i in self.model: g = listtostr_(i[1]) if i[0] == word and given == g: return i[2] return 0
class Command: def __init__(self, f_name, f_obj, help, module = "Builtin"): self.log = Log() self.log.newline() self.log.info("Creating command {}".format(f_name)) self.log.line("-") self.name = f_name self.func = f_obj self.help = self.func.__doc__ or "" self.module = module self.admin_required = "admin" in self.func.__code__.co_varnames self.nargs = self.func.__code__.co_argcount self.defaults = self.func.__defaults__ self.argdefault = {} if (self.defaults): self.noptargs = len(self.defaults) else: self.noptargs = 0 self.args = self.func.__code__.co_varnames[:self.nargs - self.noptargs] self.optargs = self.func.__code__.co_varnames[self.nargs-self.noptargs: self.noptargs+1] self.hints = typing.get_type_hints(self.func) if "self" in self.args: self.nargs -= 1 self.args = tuple([x for x in self.args if x != "self"]) for i in range(self.noptargs): self.argdefault[self.optargs[i]] = self.defaults[i] if self.nargs > 0: self.log.info("ARGS: " + ", ".join(self.args)) self.log.info("OPTARGS: " + ", ".join(self.optargs)) self.log.info("DEFAULTS: " + ", ".join( ["{}={}".format( i, self.argdefault[i]) for i in self.argdefault])) else: self.log.info("No arguments") self.delim = "," self.NOSPLIT = "NOSPLIT" in self.func.__code__.co_varnames self.success = True self.log.line("-") self.log.info(self) def getHelp(self): h = self.name + ":\n" + self.help if self.nargs > 0: h += "\nARGS: " + ", ".join(self.args) + "\n" if self.noptargs > 0: h += "\nOPTARGS: " + " , ".join(self.optargs) if "\n" not in h: h += " (No Arguments)" return h def run(self, args, user_is_admin=False): if self.admin_required and not user_is_admin: self.log.warning("{} requires administrative permissions".format(self.name)) self.log.newline() self.log.newline() self.log.line("+") if not self.NOSPLIT: args = self._formatArgs(args.split(self.delim)) else: args = self._formatArgs([args]) self.log.info("Running {} with args {}".format(self.name, args)) output = self.func(**args) self.log.line("+") self.log.newline() self.log.newline() return output def _formatArgs(self, args): args = [x.strip() for x in args if x != ''] processedArgs = {} allargs = self.args + self.optargs for i in range(self.nargs): arg = "" argn = allargs[i] if i >= len(args): arg = self.argdefault[argn] else: arg = args[i] if allargs[i] in self.hints: try: arg = self.hints[argn](arg) except ValueError as ex: raise ArgumentFormatError(ex) processedArgs[argn] = arg return processedArgs def __repr__(self): x = "\n\nCOMMAND DEFINITION ::- \n" return x+"\nCommand (\n Name: {}.{},\n Args: {},\n OptArgs: {}\n Admin: {}\n)\n".format( self.module, self.name, self.args, self.optargs, self.admin_required)
__author__ = "Hannah Ward" ############## #games.ai # #Parser for # #Phaser.io AI# ############## import json import argparse import re from floatingutils.log import Log log = Log() log.debug("Initialising Parser...") parser = argparse.ArgumentParser(description='Parse a .ai file into JSON') parser.add_argument("filename", help="The .ai file to process") parser.add_argument('--game', default="game", help='The name of your \'game\' instance - usually just game') parser.add_argument('--obj', help="The game of your game object that the AI will apply to") parser.add_argument("--varname", help="The variable name to be output", default="ai") parser.add_argument("--out", default="ai.out", help="The output filename") log.debug("Parser ready") args = parser.parse_args() log.info("Processing {}".format(args.filename))
#!/usr/bin/env python3 from floatingutils.reddit import Reddit from floatingutils.conf import YamlConf from floatingutils.log import Log import webbrowser import pickle import time l = Log() r = Reddit() l.info("Logging in...") config = YamlConf("reddit.login") username = config.getValue("reddit", "username") cli_id = "CzlpOR3KW0oNBg" headless = config.getValue("headless") api_key = config.getValue("reddit", "api") l.info("Using {}".format(username)) r.api.set_oauth_app_info(client_id = cli_id, client_secret = api_key, redirect_uri="http://localhost/reddit_auth") url = r.api.get_authorize_url("uniqueKey", "identity submit read", True)