2019-09-20 15:56:00 +00:00
|
|
|
import random
|
|
|
|
from src import ModuleManager, utils
|
|
|
|
|
2019-09-23 09:03:32 +00:00
|
|
|
NO_MARKOV = "Markov chains not enabled in this channel"
|
|
|
|
|
2019-09-20 15:56:00 +00:00
|
|
|
class Module(ModuleManager.BaseModule):
|
2019-09-20 16:15:21 +00:00
|
|
|
def on_load(self):
|
2019-09-20 15:57:17 +00:00
|
|
|
if not self.bot.database.has_table("markov"):
|
|
|
|
self.bot.database.execute("""CREATE TABLE markov
|
2019-09-20 15:56:00 +00:00
|
|
|
(channel_id INTEGER, first_word TEXT, second_word TEXT,
|
|
|
|
third_word TEXT, frequency INT,
|
|
|
|
FOREIGN KEY (channel_id) REFERENCES channels(channel_id),
|
2019-09-20 15:58:42 +00:00
|
|
|
PRIMARY KEY (channel_id, first_word, second_word))""")
|
2019-09-20 15:56:00 +00:00
|
|
|
|
|
|
|
@utils.hook("received.message.channel")
|
|
|
|
def channel_message(self, event):
|
2019-09-23 09:03:32 +00:00
|
|
|
if event["channel"].get_setting("markov", False):
|
|
|
|
self._create(event["channel"].id, event["message_split"])
|
|
|
|
|
|
|
|
@utils.hook("received.command.markovlog")
|
|
|
|
@utils.kwarg("min_args", 1)
|
|
|
|
@utils.kwarg("permission", "markovlog")
|
|
|
|
@utils.kwarg("help", "Load a message-only newline-delimited log in to this "
|
|
|
|
"channel's markov chain")
|
|
|
|
def load_log(self, event):
|
|
|
|
if not event["target"].get_setting("markov", False):
|
|
|
|
raise utils.EventError(NO_MARKOV)
|
|
|
|
|
|
|
|
page = utils.http.request(event["args_split"][0])
|
|
|
|
if page.code == 200:
|
|
|
|
for line in page.data.split("\n"):
|
|
|
|
self._create(event["target"].id, line.strip("\r").split(" "))
|
|
|
|
else:
|
|
|
|
event["stdout"].write("Failed to load log (%d)" % page.code)
|
|
|
|
|
|
|
|
def _create(self, channel_id, words):
|
|
|
|
words = list(filter(None, words))
|
|
|
|
words = [word.lower() for word in words]
|
2019-09-20 15:56:00 +00:00
|
|
|
words_n = len(words)
|
|
|
|
|
2019-09-23 09:03:32 +00:00
|
|
|
if not words_n > 2:
|
|
|
|
return
|
|
|
|
|
|
|
|
inserts = []
|
|
|
|
inserts.append([None, None, words[0]])
|
|
|
|
inserts.append([None, words[0], words[1]])
|
2019-09-20 15:56:00 +00:00
|
|
|
|
2019-09-23 09:03:32 +00:00
|
|
|
for i in range(words_n-2):
|
|
|
|
inserts.append(words[i:i+3])
|
2019-09-20 15:56:00 +00:00
|
|
|
|
2019-09-23 09:03:32 +00:00
|
|
|
inserts.append([words[-2], words[-1], None])
|
2019-09-20 15:56:00 +00:00
|
|
|
|
2019-09-23 09:03:32 +00:00
|
|
|
for insert in inserts:
|
|
|
|
frequency = self.bot.database.execute_fetchone("""SELECT
|
|
|
|
frequency FROM markov WHERE channel_id=? AND first_word=?
|
|
|
|
AND second_word=? AND third_word=?""",
|
|
|
|
[channel_id]+insert)
|
|
|
|
frequency = (frequency or [0])[0]+1
|
2019-09-20 15:56:00 +00:00
|
|
|
|
2019-09-23 09:03:32 +00:00
|
|
|
self.bot.database.execute(
|
|
|
|
"INSERT OR REPLACE INTO markov VALUES (?, ?, ?, ?, ?)",
|
|
|
|
[channel_id]+insert+[frequency])
|
2019-09-20 15:56:00 +00:00
|
|
|
|
|
|
|
def _choose(self, words):
|
|
|
|
words, frequencies = list(zip(*words))
|
|
|
|
return random.choices(words, weights=frequencies, k=1)[0]
|
|
|
|
|
2019-09-20 16:18:39 +00:00
|
|
|
@utils.hook("received.command.markov")
|
|
|
|
@utils.kwarg("channel_only", True)
|
2019-09-20 17:08:22 +00:00
|
|
|
@utils.kwarg("help", "Generate a markov chain for the current channel")
|
|
|
|
def markov(self, event):
|
|
|
|
self._markov_for(event["target"], event["stdout"], event["stderr"])
|
|
|
|
|
2019-09-20 17:09:26 +00:00
|
|
|
@utils.hook("received.command.markovfor")
|
2019-09-20 17:08:22 +00:00
|
|
|
@utils.kwarg("min_args", 1)
|
|
|
|
@utils.kwarg("permission", "markovfor")
|
|
|
|
@utils.kwarg("help", "Generate a markov chain for a given channel")
|
|
|
|
@utils.kwarg("usage", "<channel>")
|
|
|
|
def markov_for(self, event):
|
|
|
|
if event["args_split"][0] in event["server"].channels:
|
|
|
|
channel = event["server"].channels.get(event["args_split"][0])
|
|
|
|
self._markov_for(channel, event["stdout"], event["stderr"])
|
|
|
|
else:
|
|
|
|
event["stderr"].write("Unknown channel")
|
|
|
|
|
|
|
|
def _markov_for(self, channel, stdout, stderr):
|
|
|
|
if not channel.get_setting("markov", False):
|
2019-09-23 09:03:32 +00:00
|
|
|
stderr.write(NO_MARKOV)
|
2019-09-20 16:18:39 +00:00
|
|
|
else:
|
2019-09-20 17:08:22 +00:00
|
|
|
out = self._generate(channel.id)
|
|
|
|
if not out == None:
|
|
|
|
stdout.write(out)
|
|
|
|
else:
|
|
|
|
stderr.write("Failed to generate markov chain")
|
2019-09-20 16:18:39 +00:00
|
|
|
|
|
|
|
def _generate(self, channel_id):
|
2019-09-20 16:12:17 +00:00
|
|
|
first_words = self.bot.database.execute_fetchall("""SELECT third_word,
|
|
|
|
frequency FROM markov WHERE channel_id=? AND first_word IS NULL AND
|
|
|
|
second_word IS NULL AND third_word NOT NULL""", [channel_id])
|
2019-09-20 15:56:00 +00:00
|
|
|
if not first_words:
|
|
|
|
return None
|
|
|
|
first_word = self._choose(first_words)
|
|
|
|
|
2019-09-20 16:12:17 +00:00
|
|
|
second_words = self.bot.database.execute_fetchall("""SELECT third_word,
|
|
|
|
frequency FROM markov WHERE channel_id=? AND first_word IS NULL AND
|
|
|
|
second_word=? AND third_word NOT NULL""", [channel_id, first_word])
|
2019-09-20 15:56:00 +00:00
|
|
|
if not second_words:
|
|
|
|
return None
|
|
|
|
second_word = self._choose(second_words)
|
|
|
|
|
|
|
|
words = [first_word, second_word]
|
|
|
|
for i in range(30):
|
|
|
|
two_words = words[-2:]
|
2019-09-20 16:12:17 +00:00
|
|
|
third_words = self.bot.database.execute_fetchall("""SELECT
|
|
|
|
third_word, frequency FROM markov WHERE channel_id=? AND
|
|
|
|
first_word=? AND second_word=?""", [channel_id]+two_words)
|
2019-09-20 15:56:00 +00:00
|
|
|
|
|
|
|
third_word = self._choose(third_words)
|
|
|
|
if third_word == None:
|
|
|
|
break
|
|
|
|
words.append(third_word)
|
|
|
|
|
|
|
|
return " ".join(words)
|