class BotBrain: def __init__(self): self.memory = Memory() self.OPERATORS = {":=" : self.opDefine, "<<" : self.opDefineKeyword, "++" : self.opIncrement, "+=" : self.opIncrement, "--" : self.opDecrement, "-=" : self.opDecrement, "@all@" : self.opPublicReminder, "@@" : self.opReminder } self.COMMANDS = {"remember" : self.comRemember, "recall" : self.comFindQuote, "evaluate" : self.comEvaluate, "count" : self.comCount, "findfactoid" : self.comFactoidSearch, "findquote" : self.comQuoteSearch, "findkeyword" : self.comKeywordSearch, "delete" : self.comDeleteFactoid, "deletekeyword" : self.comDeleteKeyword, "vardump" : self.comVardump} self.PROCESSCOMMANDS = {"remember" : False, "recall" : False, "evaluate" : True, "count" : False, "findfactoid" : False, "findquote" : False, "findkeyword" : False, "delete" : False, "deletekeyword" : False, 'vardump' : False } def keepConnection(self): self.memory.keepConnection() def opPublicReminder(self, message, sender, STATE, private=False): logging.info("opPublicReminder- Message: %s Sender: %s" % (message, sender)) # No matter what is passed in, this is now a public reminder # (private = False) return self.opReminder(message, sender, STATE, False) def opReminder(self, message, sender, STATE, private=False): """ Set a reminder in the form of {message} @@ {timestamp} """ logging.info("opReminder- Message: %s Sender: %s" % (message, sender)) if ("@all@" in message): message = message.split("@all@") else: message = message.split("@@") if(len(message) == 2): reminder = message[0].rstrip().lstrip() timestamp = message[1].lower().rstrip().lstrip() # allow private reminders target = None if private: logging.info("Private reminder to %s" % (sender)) target = sender # Attempt to parse timestamp text cal = parsedatetime.Calendar() when, ret = cal.parse(timestamp) # 0 means we can't parse if ret > 0: isotimestamp = time.strftime('%Y-%m-%dT%H:%M:%SZ', when) self.memory.addReminder("[ " + sender + "] " + reminder, isotimestamp, target) return "Ok %s, reminder set for %s" % (sender, isotimestamp) else: return "I can't make a reminder for %s" % (timestamp) def opDefineKeyword(self, message, sender, STATE, private=False): logging.info("opDefineKeyword- Message: %s Sender: %s" % (message, sender)) message = message.split("<<") if(len(message) >= 2): keyword = message[0].lower().rstrip().lstrip() replacement = message[1].rstrip().lstrip() self.memory.addKeyword(sender, keyword, replacement) return "Ok %s, remembering %s is a %s" % (sender, replacement, keyword) def opDefine(self, message, sender, STATE, private=False): logging.info("opDefine- Message: %s Sender: %s" % (message, sender)) message = message.split(":=") if(len(message) >= 2): trigger = message[0].lower().rstrip().lstrip() factoid = message[1].rstrip().lstrip() self.memory.addFactoid(sender, trigger, factoid) return "Ok %s, remembering %s -> %s" % (sender, trigger, factoid) def comVardump(self, message, sender, STATE): logging.info("comVardump- Message: %s Sender: %s" % (message, sender)) # Look for a target parameter message = message.split() if(len(message) == 2): logging.info("Looking for %s in counter keys" % message[1]) if (message[1] in STATE['counters'].keys()): logging.info("Found %s in counter keys" % message[1]) return "%s" % STATE['counters'][message[1]] else: return "I can't find any counters for %s" % message[1] else: # If nothing else, return the sender's state return "%s" % STATE['counters'][sender] def opIncrement(self, message, sender, STATE, private=False): logging.info("opIncrement- Message: %s Sender: %s" % (message, sender)) if ("++" in message): delim = "++" else: delim = "+=" logging.info("delim - %s" % (delim)) if(delim == "++" and len(message.split("++")[1]) > 0): return if (delim == "+="): inc = int(message.split(delim)[1].strip()) message = message.split(delim)[0].strip() else: inc = 1 message = message.split(delim)[0].strip() # Allow 'targeting' counters with dot notation if ("." in message): sender = message.split(".")[0] message = message.split(".")[1] if(message in STATE['counters'][sender].keys()): STATE['counters'][sender][message] += inc else: STATE['counters'][sender][message] = inc return "%s has a %s count of %i" % (sender, message, STATE['counters'][sender][message]) def opDecrement(self, message, sender, STATE, private=False): logging.info("opDecrement- Message: %s Sender: %s" % (message, sender)) if ("--" in message): delim = "--" else: delim = "-=" logging.info("delim - %s" % (delim)) if(delim == '--' and len(message.split("--")[1]) > 0): return if (delim == "-="): dec = int(message.split(delim)[1].strip()) message = message.split(delim)[0].strip() else: dec = 1 message = message.split(delim)[0].strip() # Allow 'targeting' counters with dot notation if ("." in message): sender = message.split(".")[0] message = message.split(".")[1] if(message in STATE['counters'][sender].keys()): STATE['counters'][sender][message] -= dec if(STATE['counters'][sender][message] <= 0): # Remove from list if we go to 0 del STATE['counters'][sender][message] else: return "I can't find that counter." if(message in STATE['counters'][sender].keys()): return "%s has a %s count of %i" % (sender, message, STATE['counters'][sender][message]) else: return "Counter removed." def comDeleteKeyword(self, message, sender, STATE): logging.info("comDeleteKeyword- Message: %s Sender: %s" % (message, sender)) # strip out command message = message[len('deletekeyword')+1:].lstrip() return self.memory.deleteKeyword(sender, message, STATE['allow_delete']) def comDeleteFactoid(self, message, sender, STATE): logging.info("comDeleteFactoid- Message: %s Sender: %s" % (message, sender)) # strip out command message = message[len('delete')+1:].lstrip() return self.memory.deleteFactoid(sender, message, STATE['allow_delete']) def comRemember(self, message, sender, STATE): logging.info("comRemember- Message: %s Sender: %s" % (message, sender)) # Should be in format 'remember user quote' # First strip the 'remember' out message = message[len('remember')+1:].lstrip() # We might need to build a multiline quote: quote = "" # Split it by spaces, we're looking for user / word pairs message = message.split() # we'll just say the first one we look up is the 'sender' user = message[0] # remove the 'remember' command so we don't match buff = None if(len(STATE['buffer']) > 1): buff = STATE['buffer'] buff.popleft() primaryuser = message[0] while(len(message) > 1): # allow for "remember user word user word user word" # extract the username we're looking for targetuser = message.pop(0) # and the word targettext = message.pop(0) # search the buffer for a matching line for user, text in buff: if(user == targetuser and targettext in text): # If there's already something there, make it multiline if (len(quote) > 0): quote += '\n' + '<' + targetuser + '> ' + text else: quote = text break # break for if (len(quote) > 0): # we found something, let's save it self.memory.addQuote(sender, primaryuser, quote) return "Ok %s, remembering that %s said '%s'" % (sender, primaryuser, quote) else: return "Sorry %s, I couldn't find %s in my logs" % (sender, targettext) def comEvaluate(self, message, sender, STATE): logging.info("comEvaluate- Message: %s Sender: %s" % (message, sender)) message = message.rstrip().lstrip()[:255] if(len(message.split(" ")) >= 2): return ' '.join(message.split(" ")[1:]) # if no keyword is passed, just return the latest factoid return self.memory.getLatestFactoid() def comFactoidSearch(self, message, sender, STATE): logging.info("comFactoidSearch- Message: %s Sender: %s" % (message, sender)) trigger = message[len("findfactoid")+1:] query = trigger.rstrip().lstrip() if (len(query) > 0): return self.memory.findFactoid(query) def comKeywordSearch(self, message, sender, STATE): logging.info("comKeywordSearch- Message: %s Sender: %s" % (message, sender)) trigger = message[len("findkeyword")+1:] query = trigger.rstrip().lstrip() if (len(query) > 0): return self.memory.findKeyword(query) def comQuoteSearch(self, message, sender, STATE): logging.info("comQuoteSearch- Message: %s Sender: %s" % (message, sender)) trigger = message[len("findquote")+1:] query = trigger.rstrip().lstrip() if (len(query) > 0): return self.memory.findQuote(query) def comFindQuote(self, message, sender, STATE): logging.info("comFindQuote- Message: %s Sender: %s" % (message, sender)) trigger = message[len("recall")+1:] query = trigger.rstrip().lstrip() if (len(query) > 0): return self.memory.getQuote(query) else: return self.memory.getRandomQuote() def comCount(self, message, sender, STATE): logging.info("comCount- Message: %s Sender: %s" % (message, sender)) trigger = message[len("count")+1:] query = trigger.rstrip().lstrip() if (len(query) > 0): if(query[0] == '$'): return self.memory.countKeyword(query[1:]) else: return self.memory.countFactoid(query) def stripChars(self, string): return ''.join([l for l in string if l.isalnum() or l in ' ']) def findFactoid(self, trigger): logging.info("findFactoid- trigger: %s" % (trigger)) ret = self.memory.getFactoid(trigger) if (ret is not None): return ret else: # if the factoid is not found, strip out punctuation etc and try again return self.memory.getFactoid(self.stripChars(trigger)) def findKeyword(self, keyword): logging.info("findKeyword- keyword: %s" % (keyword)) return self.memory.getKeyword(keyword) def getMessages(self): return self.memory.getMessages()
import sys import time from memory import Memory memory = Memory() for line in sys.stdin: memory.addReminder(line.rstrip().lstrip(), time.strftime("%Y-%m-%d"))