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
This commit is contained in:
Brian S. Stephan 2012-03-19 00:12:29 -05:00
parent ce93480e9b
commit 7d41564d02
1 changed files with 54 additions and 26 deletions

View File

@ -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))