Compare commits
8 Commits
419994ee32
...
cf648cd555
Author | SHA1 | Date | |
---|---|---|---|
cf648cd555 | |||
c67b56ee5e | |||
b9c2a96231 | |||
ff5e95a53e | |||
3468622aa5 | |||
e05d0a1a1c | |||
dfda9d8c71 | |||
4c89989b8e |
@ -60,15 +60,10 @@ class Markov(Plugin):
|
|||||||
def handle_chatter(self, connection, event):
|
def handle_chatter(self, connection, event):
|
||||||
"""Learn from IRC chatter."""
|
"""Learn from IRC chatter."""
|
||||||
what = event.arguments[0]
|
what = event.arguments[0]
|
||||||
if connection.server_config.additional_addressed_nicks:
|
who = irc.client.NickMask(event.source).nick
|
||||||
all_nicks = '|'.join(connection.server_config.additional_addressed_nicks.split('\n') +
|
|
||||||
[connection.get_nickname()])
|
|
||||||
else:
|
|
||||||
all_nicks = connection.get_nickname()
|
|
||||||
trimmed_what = re.sub(r'^(({nicks})[:,]|@({nicks}))\s+'.format(nicks=all_nicks), '', what)
|
|
||||||
nick = irc.client.NickMask(event.source).nick
|
|
||||||
target = reply_destination_for_event(event)
|
target = reply_destination_for_event(event)
|
||||||
|
|
||||||
|
log.debug("what: '%s', who: '%s', target: '%s'", what, who, target)
|
||||||
# check to see whether or not we should learn from this channel
|
# check to see whether or not we should learn from this channel
|
||||||
channel = None
|
channel = None
|
||||||
if irc.client.is_channel(target):
|
if irc.client.is_channel(target):
|
||||||
@ -78,11 +73,23 @@ class Markov(Plugin):
|
|||||||
log.debug("not learning from %s as i've been told to ignore it", channel)
|
log.debug("not learning from %s as i've been told to ignore it", channel)
|
||||||
else:
|
else:
|
||||||
# learn the line
|
# learn the line
|
||||||
|
# remove our own nick and aliases from what we learn
|
||||||
|
if connection.server_config.additional_addressed_nicks:
|
||||||
|
all_nicks = '|'.join(connection.server_config.additional_addressed_nicks.split('\n') +
|
||||||
|
[connection.get_nickname()])
|
||||||
|
else:
|
||||||
|
all_nicks = connection.get_nickname()
|
||||||
|
what = re.sub(r'^(({nicks})[:,]|@({nicks}))\s+'.format(nicks=all_nicks), '', what)
|
||||||
|
|
||||||
|
# don't learn the speaker's nick if this came over a bridge
|
||||||
|
if channel and who == channel.discord_bridge:
|
||||||
|
what = ' '.join(what.split(' ')[1:])
|
||||||
|
|
||||||
recursing = getattr(event, 'recursing', False)
|
recursing = getattr(event, 'recursing', False)
|
||||||
if not recursing:
|
if not recursing:
|
||||||
log.debug("learning %s", trimmed_what)
|
log.debug("learning %s", what)
|
||||||
context = markovlib.get_or_create_target_context(target)
|
context = markovlib.get_or_create_target_context(target)
|
||||||
markovlib.learn_line(trimmed_what, context)
|
markovlib.learn_line(what, context)
|
||||||
|
|
||||||
log.debug("searching '%s' for '%s'", what, all_nicks)
|
log.debug("searching '%s' for '%s'", what, all_nicks)
|
||||||
if re.search(all_nicks, what, re.IGNORECASE) is not None:
|
if re.search(all_nicks, what, re.IGNORECASE) is not None:
|
||||||
@ -96,7 +103,7 @@ class Markov(Plugin):
|
|||||||
topics = [x for x in match.group('addressed_msg').split(' ') if len(x) >= 3]
|
topics = [x for x in match.group('addressed_msg').split(' ') if len(x) >= 3]
|
||||||
|
|
||||||
return self.bot.reply(event, "{0:s}: {1:s}"
|
return self.bot.reply(event, "{0:s}: {1:s}"
|
||||||
"".format(nick, " ".join(markovlib.generate_line(context, topics=topics))))
|
"".format(who, " ".join(markovlib.generate_line(context, topics=topics))))
|
||||||
else:
|
else:
|
||||||
# i wasn't addressed directly, so just respond
|
# i wasn't addressed directly, so just respond
|
||||||
topics = [x for x in what.split(' ') if len(x) >= 3]
|
topics = [x for x in what.split(' ') if len(x) >= 3]
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"""Provide methods for manipulating markov chain processing."""
|
"""Provide methods for manipulating markov chain processing."""
|
||||||
import logging
|
import logging
|
||||||
from random import SystemRandom as sysrand
|
import random
|
||||||
|
|
||||||
from django.db.models import Sum
|
from django.db.models import Sum
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ def generate_line(context, topics=None, min_words=15, max_words=30, sentence_bia
|
|||||||
else:
|
else:
|
||||||
if len(line) > 0:
|
if len(line) > 0:
|
||||||
if line[-1][-1] not in [',', '.', '!', '?', ':']:
|
if line[-1][-1] not in [',', '.', '!', '?', ':']:
|
||||||
line[-1] += sysrand.choice(['?', '.', '!'])
|
line[-1] += random.SystemRandom().choice(['?', '.', '!'])
|
||||||
|
|
||||||
tries += 1
|
tries += 1
|
||||||
|
|
||||||
@ -53,7 +53,7 @@ def generate_sentence(context, topics=None, min_words=15, max_words=30):
|
|||||||
words = []
|
words = []
|
||||||
# if we have topics, try to work from it and work backwards
|
# if we have topics, try to work from it and work backwards
|
||||||
if topics:
|
if topics:
|
||||||
topic_word = sysrand.choice(topics)
|
topic_word = random.SystemRandom().choice(topics)
|
||||||
topics.remove(topic_word)
|
topics.remove(topic_word)
|
||||||
log.debug("looking for topic '%s'", topic_word)
|
log.debug("looking for topic '%s'", topic_word)
|
||||||
new_states = MarkovState.objects.filter(context=context, v=topic_word)
|
new_states = MarkovState.objects.filter(context=context, v=topic_word)
|
||||||
@ -100,7 +100,7 @@ def generate_sentence(context, topics=None, min_words=15, max_words=30):
|
|||||||
words.append(MarkovState._stop)
|
words.append(MarkovState._stop)
|
||||||
elif len(target_hits) > 0:
|
elif len(target_hits) > 0:
|
||||||
# if there's a target word in the states, pick it
|
# if there's a target word in the states, pick it
|
||||||
target_hit = sysrand.choice(target_hits)
|
target_hit = random.SystemRandom().choice(target_hits)
|
||||||
log.debug("found a topic hit %s, using it", target_hit)
|
log.debug("found a topic hit %s, using it", target_hit)
|
||||||
topics.remove(target_hit)
|
topics.remove(target_hit)
|
||||||
words.append(target_hit)
|
words.append(target_hit)
|
||||||
|
72
tests/test_markov_ircplugin.py
Normal file
72
tests/test_markov_ircplugin.py
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
"""Test IRC behavior of the markov plugin."""
|
||||||
|
from unittest import mock
|
||||||
|
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
from ircbot.models import IrcServer
|
||||||
|
from markov.ircplugin import Markov
|
||||||
|
|
||||||
|
|
||||||
|
class MarkovTestCase(TestCase):
|
||||||
|
"""Test the markov plugin."""
|
||||||
|
|
||||||
|
fixtures = ['tests/fixtures/irc_server_fixture.json']
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
"""Create common objects."""
|
||||||
|
self.mock_bot = mock.MagicMock()
|
||||||
|
self.mock_connection = mock.MagicMock()
|
||||||
|
|
||||||
|
self.mock_connection.get_nickname.return_value = 'test_bot'
|
||||||
|
self.mock_connection.server_config = IrcServer.objects.get(pk=1)
|
||||||
|
|
||||||
|
self.plugin = Markov(self.mock_bot, self.mock_connection, mock.MagicMock())
|
||||||
|
|
||||||
|
def test_learn(self):
|
||||||
|
"""Test that an IRC event triggers learning as expected."""
|
||||||
|
mock_event = mock.MagicMock()
|
||||||
|
mock_event.arguments = ['hello this is a test message']
|
||||||
|
mock_event.target = '#test'
|
||||||
|
mock_event.recursing = False
|
||||||
|
|
||||||
|
with mock.patch('markov.lib.learn_line') as mock_learn_line:
|
||||||
|
self.plugin.handle_chatter(self.mock_connection, mock_event)
|
||||||
|
|
||||||
|
self.assertEqual(mock_learn_line.call_args.args[0], 'hello this is a test message')
|
||||||
|
|
||||||
|
def test_learn_self_edit(self):
|
||||||
|
"""Test that we don't learn our own name when learning something addressed to us."""
|
||||||
|
mock_event = mock.MagicMock()
|
||||||
|
mock_event.arguments = ['test_bot: hello this is a test message']
|
||||||
|
mock_event.target = '#test'
|
||||||
|
mock_event.recursing = False
|
||||||
|
|
||||||
|
with mock.patch('markov.lib.learn_line') as mock_learn_line:
|
||||||
|
self.plugin.handle_chatter(self.mock_connection, mock_event)
|
||||||
|
|
||||||
|
self.assertEqual(mock_learn_line.call_args.args[0], 'hello this is a test message')
|
||||||
|
|
||||||
|
def test_learn_variant_self_edit(self):
|
||||||
|
"""Test that we don't learn our own name when learning something addressed to us, discord style."""
|
||||||
|
mock_event = mock.MagicMock()
|
||||||
|
mock_event.arguments = ['@test_bot hello this is a test message']
|
||||||
|
mock_event.target = '#test'
|
||||||
|
mock_event.recursing = False
|
||||||
|
|
||||||
|
with mock.patch('markov.lib.learn_line') as mock_learn_line:
|
||||||
|
self.plugin.handle_chatter(self.mock_connection, mock_event)
|
||||||
|
|
||||||
|
self.assertEqual(mock_learn_line.call_args.args[0], 'hello this is a test message')
|
||||||
|
|
||||||
|
def test_learn_bridge_edit(self):
|
||||||
|
"""Test that we don't learn the speaker's nick when learning a message from the bridge."""
|
||||||
|
mock_event = mock.MagicMock()
|
||||||
|
mock_event.arguments = ['<tester> hello this is a test message']
|
||||||
|
mock_event.target = '#test'
|
||||||
|
mock_event.recursing = False
|
||||||
|
mock_event.source = 'bridge!bridge@localhost'
|
||||||
|
|
||||||
|
with mock.patch('markov.lib.learn_line') as mock_learn_line:
|
||||||
|
self.plugin.handle_chatter(self.mock_connection, mock_event)
|
||||||
|
|
||||||
|
self.assertEqual(mock_learn_line.call_args.args[0], 'hello this is a test message')
|
Loading…
x
Reference in New Issue
Block a user