From 03d0d6bc2d5816727669da34df98fda37c57763d Mon Sep 17 00:00:00 2001 From: "Brian S. Stephan" Date: Sun, 1 May 2011 10:31:20 -0500 Subject: [PATCH] Markov: shut up if we've been too chatty in too short a period of time. track all lines seen and all lines said by Markov. every 30 seconds, if there have been more than 20 such lines, and Markov is responsible for roughly half of them, then shut up for 30 seconds, because the bot probably got stuck talking to another bot. this should mean that such a reply infinite loop can't happen for more than a minute. i'm not entirely sure on the 30 sec/20 lines ratio. this may need tuning. --- modules/Markov.py | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/modules/Markov.py b/modules/Markov.py index a4f1621..9e0b6f7 100644 --- a/modules/Markov.py +++ b/modules/Markov.py @@ -17,12 +17,15 @@ along with this program. If not, see . """ import cPickle +from datetime import datetime import os import random import re import sqlite3 import sys +from dateutil.parser import * +from dateutil.relativedelta import * from extlib import irclib from Module import Module @@ -62,6 +65,7 @@ class Markov(Module): self.replyre = re.compile(replypattern) self.shut_up = False + self.lines_seen = [] Module.__init__(self, irc, config, server) @@ -180,6 +184,10 @@ class Markov(Module): my_nick = connection.get_nickname() what = re.sub('^' + my_nick + '[:,]\s+', '', what) target = event.target() + nick = irclib.nm_to_n(event.source()) + + self.lines_seen.append((nick, datetime.now())) + self.connection = connection # don't learn from commands if self.trainre.search(what) or self.learnre.search(what) or self.replyre.search(what): @@ -204,9 +212,11 @@ class Markov(Module): addressed_re = re.compile(addressed_pattern) if addressed_re.match(what): # i was addressed directly, so respond, addressing the speaker + self.lines_seen.append(('.self.said.', datetime.now())) return self.reply(connection, event, '{0:s}: {1:s}'.format(nick, self._generate_line(line=addressed_re.match(what).group(1)))) else: # i wasn't addressed directly, so just respond + self.lines_seen.append(('.self.said.', datetime.now())) return self.reply(connection, event, '{0:s}'.format(self._generate_line(line=what))) def markov_train(self, connection, event, nick, userhost, what, admin_unlocked): @@ -251,17 +261,36 @@ class Markov(Module): if match.group(5) != '': line = match.group(6) + self.lines_seen.append(('.self.said.', datetime.now())) return self._generate_line(line=line, min_size=min_size, max_size=max_size) else: + self.lines_seen.append(('.self.said.', datetime.now())) return self._generate_line(min_size=min_size, max_size=max_size) def timer_do(self): - """Do various things. + """Do various things.""" - * Check to see if we've been talking too much, and shut up if so. - """ + self._do_shut_up_checks() - self.shut_up = True + def _do_shut_up_checks(self): + """Check to see if we've been talking too much, and shut up if so.""" + + self.shut_up = False + + last_30_sec_lines = [] + + for (nick,then) in self.lines_seen: + rdelta = relativedelta(datetime.now(), then) + if rdelta.years == 0 and rdelta.months == 0 and rdelta.days == 0 and rdelta.hours == 0 and rdelta.minutes == 0 and rdelta.seconds <= 29: + last_30_sec_lines.append((nick,then)) + + if len(last_30_sec_lines) >= 20: + lines_i_said = len(filter(lambda (a,b): a == '.self.said.', last_30_sec_lines)) + if lines_i_said * 100 / len(last_30_sec_lines) >= 45: + self.shut_up = True + targets = self._get_chatter_targets() + for t in targets: + self.sendmsg(self.connection, t, 'shutting up for 30 seconds due to last 30 seconds of activity') def _learn_line(self, line, target=None): """Create Markov chains from the provided line."""