import logging import re import irc.client from ircbot.lib import Plugin, reply_destination_for_event from ircbot.models import IrcChannel import markov.lib as markovlib log = logging.getLogger('markov.ircplugin') class Markov(Plugin): """Build Markov chains and reply with them.""" def start(self): """Set up the handlers.""" self.connection.add_global_handler('pubmsg', self.handle_chatter, -20) self.connection.add_global_handler('privmsg', self.handle_chatter, -20) self.connection.reactor.add_global_regex_handler(['pubmsg', 'privmsg'], r'^!markov\s+reply(\s+min=(\d+))?(\s+max=(\d+))?(\s+(.*)$|$)', self.handle_reply, -20) super(Markov, self).start() def stop(self): """Tear down handlers.""" self.connection.remove_global_handler('pubmsg', self.handle_chatter) self.connection.remove_global_handler('privmsg', self.handle_chatter) self.connection.reactor.remove_global_regex_handler(['pubmsg', 'privmsg'], self.handle_reply) super(Markov, self).stop() def handle_reply(self, connection, event, match): """Generate a reply to one line, without learning it.""" target = reply_destination_for_event(event) min_size = 15 max_size = 30 context = markovlib.get_or_create_target_context(target) if match.group(2): min_size = int(match.group(2)) if match.group(4): max_size = int(match.group(4)) if match.group(5) != '': line = match.group(6) topics = [x for x in line.split(' ') if len(x) >= 3] return self.bot.reply(event, u" ".join(markovlib.generate_line(context, topics=topics, min_words=min_size, max_words=max_size, max_sentences=1))) else: return self.bot.reply(event, u" ".join(markovlib.generate_line(context, min_words=min_size, max_words=max_size, max_sentences=1))) def handle_chatter(self, connection, event): """Learn from IRC chatter.""" what = event.arguments[0] my_nick = connection.get_nickname() trimmed_what = re.sub(r'^{0:s}[:,]\s+'.format(my_nick), '', what) nick = irc.client.NickMask(event.source).nick target = reply_destination_for_event(event) # check to see whether or not we should learn from this channel channel = None if irc.client.is_channel(target): channel, c = IrcChannel.objects.get_or_create(name=target) if channel and not channel.markov_learn_from_channel: log.debug("not learning from %s as i've been told to ignore it", channel) else: # learn the line recursing = getattr(event, '_recursing', False) if not recursing: log.debug(u"learning %s", trimmed_what) context = markovlib.get_or_create_target_context(target) markovlib.learn_line(trimmed_what, context) log.debug(u"searching '%s' for '%s'", what, my_nick) if re.search(my_nick, what, re.IGNORECASE) is not None: context = markovlib.get_or_create_target_context(target) addressed_pattern = r'^{0:s}[:,]\s+(.*)'.format(my_nick) addressed_re = re.compile(addressed_pattern) if addressed_re.match(what): # i was addressed directly, so respond, addressing # the speaker topics = [x for x in addressed_re.match(what).group(1).split(' ') if len(x) >= 3] return self.bot.reply(event, u"{0:s}: {1:s}" u"".format(nick, u" ".join(markovlib.generate_line(context, topics=topics, max_sentences=1)))) else: # i wasn't addressed directly, so just respond topics = [x for x in what.split(' ') if len(x) >= 3] return self.bot.reply(event, u"{0:s}" u"".format(u" ".join(markovlib.generate_line(context, topics=topics, max_sentences=1)))) plugin = Markov