From 7d41564d022e9c2802cc019e7758fd8a01f854ff Mon Sep 17 00:00:00 2001 From: "Brian S. Stephan" Date: Mon, 19 Mar 2012 00:12:29 -0500 Subject: [PATCH] Markov: allow for auto-context insertion this should result in no chains having a null context --- if no pre-existing context is created, one is created for the channel/nick and used. this makes, for example, arbitrary queries "private" to that nick (again unless that has been overridden). shouldn't affect much of anything, but adding this made the context-less learning code obsolete, which is fine since it was never used anyway --- modules/Markov.py | 80 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 26 deletions(-) diff --git a/modules/Markov.py b/modules/Markov.py index 51287ff..d4a826d 100644 --- a/modules/Markov.py +++ b/modules/Markov.py @@ -54,11 +54,9 @@ class Markov(Module): self.stop = '__stop' # set up regexes, for replying to specific stuff - trainpattern = '^!markov\s+train\s+(.*)$' learnpattern = '^!markov\s+learn\s+(.*)$' replypattern = '^!markov\s+reply(\s+min=(\d+))?(\s+max=(\d+))?(\s+(.*)$|$)' - self.trainre = re.compile(trainpattern) self.learnre = re.compile(learnpattern) self.replyre = re.compile(replypattern) @@ -163,11 +161,14 @@ class Markov(Module): target = event.target() nick = irclib.nm_to_n(event.source()) + if not irclib.is_channel(target): + target = nick + 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): + if self.learnre.search(what) or self.replyre.search(what): return self._learn_line(what, target) @@ -177,10 +178,7 @@ class Markov(Module): target = event.target() - if self.trainre.search(what): - return self.reply(connection, event, self.markov_train(connection, event, nick, - userhost, what, admin_unlocked)) - elif self.learnre.search(what): + if self.learnre.search(what): return self.reply(connection, event, self.markov_learn(connection, event, nick, userhost, what, admin_unlocked)) elif self.replyre.search(what) and not self.shut_up: @@ -202,21 +200,6 @@ class Markov(Module): self.lines_seen.append(('.self.said.', datetime.now())) return self.reply(connection, event, '{0:s}'.format(self._generate_line(target, line=what))) - def markov_train(self, connection, event, nick, userhost, what, admin_unlocked): - """Learn lines from a file. Good for initializing a brain.""" - - match = self.trainre.search(what) - if match and admin_unlocked: - filename = match.group(1) - - try: - for line in open(filename, 'r'): - self._learn_line(line) - - return 'Learned from \'{0:s}\'.'.format(filename) - except IOError: - return 'No such file \'{0:s}\'.'.format(filename) - def markov_learn(self, connection, event, nick, userhost, what, admin_unlocked): """Learn one line, as provided to the command.""" @@ -431,10 +414,10 @@ class Markov(Module): max_id = self._get_max_chain_id() rand_id = random.randint(1,max_id) query = ('SELECT v FROM markov_chain WHERE k1 = ? AND k2 = ? AND ' - '(context_id = ? OR context_id IS NULL) AND id >= {0:d} LIMIT 1'.format(rand_id)) + '(context_id = ?) AND id >= {0:d} LIMIT 1'.format(rand_id)) else: query = ('SELECT v FROM markov_chain WHERE k1 = ? AND k2 = ? AND ' - '(context_id = ? OR context_id IS NULL)') + '(context_id = ?)') cursor = db.execute(query, (k1,k2,context_id)) results = cursor.fetchall() @@ -454,7 +437,7 @@ class Markov(Module): values = [] try: db = self.get_db() - query = 'SELECT k2 FROM markov_chain WHERE v = ? AND (context_id = ? OR context_id IS NULL)' + query = 'SELECT k2 FROM markov_chain WHERE v = ? AND (context_id = ?)' cursor = db.execute(query, (v,context_id)) results = cursor.fetchall() @@ -529,7 +512,52 @@ class Markov(Module): if result: return result['id'] else: - return None + # auto-generate a context to keep things private + self._add_context_for_target(target) + return self._get_context_id_for_target(target) + except sqlite3.Error as e: + db.close() + print('sqlite error in Markov._get_context_id_for_target: ' + str(e)) + raise + + def _add_context_for_target(self, target): + + """Create a new context for the desired/input target.""" + + try: + db = self.get_db() + cur = db.cursor() + statement = 'INSERT INTO markov_context (context) VALUES (?)' + cur.execute(statement, (target,)) + statement = ''' + INSERT INTO markov_target_to_context_map (target, context_id) + VALUES (?, (SELECT id FROM markov_context WHERE context = ?)) + ''' + cur.execute(statement, (target,target)) + db.commit() + db.close() + except sqlite3.Error as e: + db.rollback() + db.close() + print("sqlite error in Markov._add_context_for_target: " + str(e)) + raise + try: + db = self.get_db() + query = ''' + SELECT mc.id FROM markov_context mc + INNER JOIN markov_target_to_context_map mt + ON mt.context_id = mc.id + WHERE mt.target = ? + ''' + cursor = db.execute(query, (target,)) + result = cursor.fetchone() + db.close() + if result: + return result['id'] + else: + # auto-generate a context to keep things private + self._add_context_for_target(target) + return self._get_context_id_for_target(target) except sqlite3.Error as e: db.close() print('sqlite error in Markov._get_context_id_for_target: ' + str(e))