Markov: consolidate _reply_to_line and _reply into _generate_line

This commit is contained in:
Brian S. Stephan 2011-04-30 15:37:16 -05:00
parent aa6ea083fd
commit 42d414a0a4
1 changed files with 13 additions and 55 deletions

View File

@ -182,10 +182,10 @@ class Markov(Module):
addressed_re = re.compile(addressed_pattern) addressed_re = re.compile(addressed_pattern)
if addressed_re.match(what): if addressed_re.match(what):
# i was addressed directly, so respond, addressing the speaker # i was addressed directly, so respond, addressing the speaker
return self.reply(connection, event, '{0:s}: {1:s}'.format(nick, self._reply_to_line(addressed_re.match(what).group(1)))) return self.reply(connection, event, '{0:s}: {1:s}'.format(nick, self._generate_line(line=addressed_re.match(what).group(1))))
else: else:
# i wasn't addressed directly, so just respond # i wasn't addressed directly, so just respond
return self.reply(connection, event, '{0:s}'.format(self._reply_to_line(what))) return self.reply(connection, event, '{0:s}'.format(self._generate_line(line=what)))
def markov_train(self, connection, event, nick, userhost, what, admin_unlocked): def markov_train(self, connection, event, nick, userhost, what, admin_unlocked):
"""Learn lines from a file. Good for initializing a brain.""" """Learn lines from a file. Good for initializing a brain."""
@ -229,9 +229,9 @@ class Markov(Module):
if match.group(5) != '': if match.group(5) != '':
line = match.group(6) line = match.group(6)
return self._reply_to_line(line, min_size=min_size, max_size=max_size) return self._generate_line(line=line, min_size=min_size, max_size=max_size)
else: else:
return self._reply(min_size=min_size, max_size=max_size) return self._generate_line(min_size=min_size, max_size=max_size)
def _learn_line(self, line, target=None): def _learn_line(self, line, target=None):
"""Create Markov chains from the provided line.""" """Create Markov chains from the provided line."""
@ -273,54 +273,7 @@ class Markov(Module):
print("sqlite error: " + str(e)) print("sqlite error: " + str(e))
raise raise
def _reply(self, min_size=15, max_size=100): def _generate_line(self, line='', min_size=15, max_size=100):
"""Generate a totally random string from the chains, of specified limit of words."""
# if the limit is too low, there's nothing to do
if (max_size <= 3):
raise Exception("max_size is too small: %d" % max_size)
# if the min is too large, abort
if (min_size > 20):
raise Exception("min_size is too large: %d" % min_size)
# start with an empty chain, and work from there
gen_words = [self.start1, self.start2]
# set up the number of times we've tried to hit the specified minimum
min_search_tries = 0
# walk a chain, randomly, building the list of words
while len(gen_words) < max_size + 2 and gen_words[-1] != self.stop:
key_hits = self._retrieve_chains_for_key(gen_words[-2], gen_words[-1])
if len(gen_words) < min_size and len(filter(lambda a: a != self.stop, key_hits)) > 0:
# we aren't at min size yet and we have at least one chain path
# that isn't (yet) the end. take one of those.
gen_words.append(random.choice(filter(lambda a: a != self.stop, key_hits)))
min_search_tries = 0
elif len(gen_words) < min_size and min_search_tries <= 10:
# we aren't at min size yet and the only path we currently have is
# a end, but we haven't retried much yet, so chop off our current
# chain and try again.
gen_words = gen_words[0:len(gen_words)-2]
min_search_tries = min_search_tries + 1
else:
# either we have hit our min size requirement, or we haven't but
# we also exhausted min_search_tries. either way, just pick a word
# at random, knowing it may be the end of the chain
gen_words.append(random.choice(key_hits))
min_search_tries = 0
# chop off the seed data at the start
gen_words = gen_words[2:]
# chop off the end text, if it was the keyword indicating an end of chain
if gen_words[-1] == self.stop:
gen_words = gen_words[:-1]
return ' '.join(gen_words).encode('utf-8', 'ignore')
def _reply_to_line(self, line, min_size=15, max_size=100):
"""Reply to a line, using some text in the line as a point in the chain.""" """Reply to a line, using some text in the line as a point in the chain."""
# if the limit is too low, there's nothing to do # if the limit is too low, there's nothing to do
@ -331,9 +284,13 @@ class Markov(Module):
if (min_size > 20): if (min_size > 20):
raise Exception("min_size is too large: %d" % min_size) raise Exception("min_size is too large: %d" % min_size)
words = []
target_word = ''
# get a random word from the input # get a random word from the input
words = line.split() if line != '':
target_word = words[random.randint(0, len(words)-1)] words = line.split()
target_word = words[random.randint(0, len(words)-1)]
print('target word ' + target_word)
# start with an empty chain, and work from there # start with an empty chain, and work from there
gen_words = [self.start1, self.start2] gen_words = [self.start1, self.start2]
@ -341,8 +298,9 @@ class Markov(Module):
# walk a chain, randomly, building the list of words # walk a chain, randomly, building the list of words
while len(gen_words) < max_size + 2 and gen_words[-1] != self.stop: while len(gen_words) < max_size + 2 and gen_words[-1] != self.stop:
key_hits = self._retrieve_chains_for_key(gen_words[-2], gen_words[-1]) key_hits = self._retrieve_chains_for_key(gen_words[-2], gen_words[-1])
print(key_hits)
# use the chain that includes the target word, if it is found # use the chain that includes the target word, if it is found
if target_word in key_hits: if target_word != '' and target_word in key_hits:
gen_words.append(target_word) gen_words.append(target_word)
# generate new word # generate new word
target_word = words[random.randint(0, len(words)-1)] target_word = words[random.randint(0, len(words)-1)]