when creating a markov target, tie it to ircbot models

This commit is contained in:
Brian S. Stephan 2023-02-19 17:38:25 -06:00
parent 76a052e091
commit 0227b74eee
Signed by: bss
GPG Key ID: 3DE06D3180895FCB
7 changed files with 111 additions and 31 deletions

View File

@ -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<addressed_msg>.*)'.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

View File

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

View File

@ -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'),
),
]

View File

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

View File

@ -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'),
),
]

View File

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

View File

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