From 0227b74eee0761b94693ef62b6ebacc8ea9bd3eb Mon Sep 17 00:00:00 2001 From: "Brian S. Stephan" Date: Sun, 19 Feb 2023 17:38:25 -0600 Subject: [PATCH] when creating a markov target, tie it to ircbot models --- markov/ircplugin.py | 33 +++++++++++++++++-- markov/lib.py | 28 +--------------- .../migrations/0005_markovtarget_channel.py | 20 +++++++++++ .../0006_link_markovtarget_to_ircchannel.py | 24 ++++++++++++++ .../0007_alter_markovtarget_channel.py | 20 +++++++++++ markov/models.py | 3 ++ tests/test_markov_ircplugin.py | 14 +++++++- 7 files changed, 111 insertions(+), 31 deletions(-) create mode 100644 markov/migrations/0005_markovtarget_channel.py create mode 100644 markov/migrations/0006_link_markovtarget_to_ircchannel.py create mode 100644 markov/migrations/0007_alter_markovtarget_channel.py diff --git a/markov/ircplugin.py b/markov/ircplugin.py index 733740b..4abb58c 100644 --- a/markov/ircplugin.py +++ b/markov/ircplugin.py @@ -7,6 +7,7 @@ import irc.client import markov.lib as markovlib from ircbot.lib import Plugin, reply_destination_for_event from ircbot.models import IrcChannel +from markov.models import MarkovContext, MarkovTarget log = logging.getLogger('markov.ircplugin') @@ -40,7 +41,7 @@ class Markov(Plugin): min_size = 15 max_size = 30 - context = markovlib.get_or_create_target_context(target) + context = self.get_or_create_target_context(target) if match.group(2): min_size = int(match.group(2)) @@ -90,12 +91,12 @@ class Markov(Plugin): recursing = getattr(event, 'recursing', False) if not recursing: log.debug("learning %s", learning_what) - context = markovlib.get_or_create_target_context(target) + context = self.get_or_create_target_context(target) markovlib.learn_line(learning_what, context) log.debug("searching '%s' for '%s'", what, all_nicks) if re.search(all_nicks, what, re.IGNORECASE) is not None: - context = markovlib.get_or_create_target_context(target) + context = self.get_or_create_target_context(target) addressed_pattern = r'^(({nicks})[:,]|@({nicks}))\s+(?P.*)'.format(nicks=all_nicks) match = re.match(addressed_pattern, what, re.IGNORECASE) @@ -113,5 +114,31 @@ class Markov(Plugin): return self.bot.reply(event, "{0:s}" "".format(" ".join(markovlib.generate_line(context, topics=topics)))) + def get_or_create_target_context(self, target_name): + """Return the context for a provided nick/channel, creating missing ones.""" + target_name = target_name.lower() + + # find the stuff, or create it + try: + target = MarkovTarget.objects.get(name=target_name) + except MarkovTarget.DoesNotExist: + # we need to create a context and a target, and we have to make the context first + # make a context --- lacking a good idea, just create one with this target name until configured otherwise + channel, c = IrcChannel.objects.get_or_create(name=target_name, server=self.connection.server_config) + context, c = MarkovContext.objects.get_or_create(name=target_name) + target, c = MarkovTarget.objects.get_or_create(name=target_name, context=context, channel=channel) + + return target.context + + try: + return target.context + except MarkovContext.DoesNotExist: + # make a context --- lacking a good idea, just create one with this target name until configured otherwise + context, c = MarkovContext.objects.get_or_create(name=target_name) + target.context = context + target.save() + + return target.context + plugin = Markov diff --git a/markov/lib.py b/markov/lib.py index 172d65f..517cb6c 100644 --- a/markov/lib.py +++ b/markov/lib.py @@ -4,7 +4,7 @@ import random from django.db.models import Sum -from markov.models import MarkovContext, MarkovState, MarkovTarget +from markov.models import MarkovState log = logging.getLogger(__name__) @@ -124,32 +124,6 @@ def generate_sentence(context, topics=None, min_words=15, max_words=30): return words -def get_or_create_target_context(target_name): - """Return the context for a provided nick/channel, creating missing ones.""" - target_name = target_name.lower() - - # find the stuff, or create it - try: - target = MarkovTarget.objects.get(name=target_name) - except MarkovTarget.DoesNotExist: - # we need to create a context and a target, and we have to make the context first - # make a context --- lacking a good idea, just create one with this target name until configured otherwise - context, c = MarkovContext.objects.get_or_create(name=target_name) - target, c = MarkovTarget.objects.get_or_create(name=target_name, context=context) - - return target.context - - try: - return target.context - except MarkovContext.DoesNotExist: - # make a context --- lacking a good idea, just create one with this target name until configured otherwise - context, c = MarkovContext.objects.get_or_create(name=target_name) - target.context = context - target.save() - - return target.context - - def get_word_out_of_states(states, backwards=False): """Pick one random word out of the given states.""" # work around possible broken data, where a k1,k2 should have a value but doesn't diff --git a/markov/migrations/0005_markovtarget_channel.py b/markov/migrations/0005_markovtarget_channel.py new file mode 100644 index 0000000..898b4a1 --- /dev/null +++ b/markov/migrations/0005_markovtarget_channel.py @@ -0,0 +1,20 @@ +# Generated by Django 3.2.18 on 2023-02-20 00:09 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('ircbot', '0019_ircchannel_discord_bridge'), + ('markov', '0004_alter_markovstate_context'), + ] + + operations = [ + migrations.AddField( + model_name='markovtarget', + name='channel', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE, to='ircbot.ircchannel'), + ), + ] diff --git a/markov/migrations/0006_link_markovtarget_to_ircchannel.py b/markov/migrations/0006_link_markovtarget_to_ircchannel.py new file mode 100644 index 0000000..115616b --- /dev/null +++ b/markov/migrations/0006_link_markovtarget_to_ircchannel.py @@ -0,0 +1,24 @@ +"""Generated by Django 3.2.18 on 2023-02-19 23:15.""" +from django.db import migrations + + +def link_markovcontext_to_ircchannel(apps, schema_editor): + """Link the markov targets to a hopefully matching channel, by name.""" + IrcChannel = apps.get_model('ircbot', 'IrcChannel') + MarkovTarget = apps.get_model('markov', 'MarkovTarget') + for target in MarkovTarget.objects.all(): + channel = IrcChannel.objects.get(name=target.name) + target.channel = channel + target.save() + + +class Migration(migrations.Migration): + """Populate the markov target to IRC channel link.""" + + dependencies = [ + ('markov', '0005_markovtarget_channel'), + ] + + operations = [ + migrations.RunPython(link_markovcontext_to_ircchannel) + ] diff --git a/markov/migrations/0007_alter_markovtarget_channel.py b/markov/migrations/0007_alter_markovtarget_channel.py new file mode 100644 index 0000000..cdc90fa --- /dev/null +++ b/markov/migrations/0007_alter_markovtarget_channel.py @@ -0,0 +1,20 @@ +# Generated by Django 3.2.18 on 2023-02-20 00:11 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('ircbot', '0019_ircchannel_discord_bridge'), + ('markov', '0006_link_markovtarget_to_ircchannel'), + ] + + operations = [ + migrations.AlterField( + model_name='markovtarget', + name='channel', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='ircbot.ircchannel'), + ), + ] diff --git a/markov/models.py b/markov/models.py index 8ebe2ac..56b91bd 100644 --- a/markov/models.py +++ b/markov/models.py @@ -3,6 +3,8 @@ import logging from django.db import models +from ircbot.models import IrcChannel + log = logging.getLogger(__name__) @@ -21,6 +23,7 @@ class MarkovTarget(models.Model): name = models.CharField(max_length=200, unique=True) context = models.ForeignKey(MarkovContext, on_delete=models.CASCADE) + channel = models.ForeignKey(IrcChannel, on_delete=models.CASCADE) chatter_chance = models.IntegerField(default=0) diff --git a/tests/test_markov_ircplugin.py b/tests/test_markov_ircplugin.py index c2a6f82..d40daba 100644 --- a/tests/test_markov_ircplugin.py +++ b/tests/test_markov_ircplugin.py @@ -3,7 +3,7 @@ from unittest import mock from django.test import TestCase -from ircbot.models import IrcServer +from ircbot.models import IrcChannel, IrcServer from markov.ircplugin import Markov @@ -100,3 +100,15 @@ class MarkovTestCase(TestCase): 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_autocreate_ircchannel(self): + """Test that we create the necessary config objects when seeing a target for the first time.""" + self.assertEqual(IrcChannel.objects.filter(name='#fakechannel').count(), 0) + context = self.plugin.get_or_create_target_context('#fakechannel') + + self.assertEqual(IrcChannel.objects.filter(name='#fakechannel').count(), 1) + self.assertIsNotNone(context) + self.assertIsNotNone(context.markovtarget_set) + self.assertIsNotNone(context.markovtarget_set.all()[0].channel) + self.assertEqual(context.markovtarget_set.all()[0].channel.name, '#fakechannel') + self.assertEqual(context.markovtarget_set.all()[0].name, '#fakechannel')