add markov module and irc plugin
just listens to servers right now, doesn't speak up (yet)
This commit is contained in:
		
							parent
							
								
									7ec643afda
								
							
						
					
					
						commit
						51edb54ed7
					
				@ -40,6 +40,7 @@ INSTALLED_APPS = [
 | 
			
		||||
    'bot',
 | 
			
		||||
    'dice',
 | 
			
		||||
    'logger',
 | 
			
		||||
    'markov',
 | 
			
		||||
    'weather',
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										0
									
								
								markov/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								markov/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										7
									
								
								markov/admin.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								markov/admin.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,7 @@
 | 
			
		||||
"""Display Markov data elements in the Django admin."""
 | 
			
		||||
from django.contrib import admin
 | 
			
		||||
 | 
			
		||||
from markov.models import MarkovContext, MarkovState
 | 
			
		||||
 | 
			
		||||
admin.site.register(MarkovContext)
 | 
			
		||||
admin.site.register(MarkovState)
 | 
			
		||||
							
								
								
									
										6
									
								
								markov/apps.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								markov/apps.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,6 @@
 | 
			
		||||
"""App config for the markov module."""
 | 
			
		||||
from django.apps import AppConfig
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MarkovConfig(AppConfig):
 | 
			
		||||
    name = 'markov'
 | 
			
		||||
							
								
								
									
										33
									
								
								markov/bot.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								markov/bot.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
			
		||||
"""Observe Markov chains from Discord."""
 | 
			
		||||
import logging
 | 
			
		||||
 | 
			
		||||
from bot import hitomi
 | 
			
		||||
from markov import lib
 | 
			
		||||
 | 
			
		||||
logger = logging.getLogger(__name__)
 | 
			
		||||
logger.info("loading markov plugin")
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def on_message(message):
 | 
			
		||||
    """Keep the observed Markov chains."""
 | 
			
		||||
    # ignore self
 | 
			
		||||
    if message.author == hitomi.user:
 | 
			
		||||
        logger.debug("markov ignoring message authored by self")
 | 
			
		||||
        return
 | 
			
		||||
 | 
			
		||||
    if message.channel.is_private:
 | 
			
		||||
        # DMs have a context of the author
 | 
			
		||||
        context_name = message.author
 | 
			
		||||
    else:
 | 
			
		||||
        # channels have a context of the server, but we should ignore channels that override @everyone's read ability
 | 
			
		||||
        for changed_role in message.channel.changed_roles:
 | 
			
		||||
            if changed_role.is_everyone:
 | 
			
		||||
                if not changed_role.permissions.read_messages:
 | 
			
		||||
                    logger.debug("markov ignoring channel that @everyone can't read")
 | 
			
		||||
                    return
 | 
			
		||||
        context_name = message.server.id
 | 
			
		||||
 | 
			
		||||
    lib.learn_line(message.content, context_name)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
hitomi.on_message_handlers.append(on_message)
 | 
			
		||||
							
								
								
									
										30
									
								
								markov/lib.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								markov/lib.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,30 @@
 | 
			
		||||
"""Shared methods for the Markov module."""
 | 
			
		||||
import logging
 | 
			
		||||
 | 
			
		||||
from markov.models import MarkovContext, MarkovState
 | 
			
		||||
 | 
			
		||||
logger = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
def learn_line(line, context_name):
 | 
			
		||||
    """Create a bunch of MarkovStates for a given line of text."""
 | 
			
		||||
    logger.debug("learning %s...", line[:40])
 | 
			
		||||
 | 
			
		||||
    context, created = MarkovContext.objects.get_or_create(name=context_name)
 | 
			
		||||
 | 
			
		||||
    words = line.split()
 | 
			
		||||
    words = [MarkovState.start1, MarkovState.start2] + words + [MarkovState.stop]
 | 
			
		||||
 | 
			
		||||
    for word in words:
 | 
			
		||||
        if len(word) > MarkovState._meta.get_field('k1').max_length:
 | 
			
		||||
            return
 | 
			
		||||
 | 
			
		||||
    for i, word in enumerate(words):
 | 
			
		||||
        logger.debug("'{0:s}','{1:s}' -> '{2:s}'".format(words[i], words[i + 1], words[i + 2]))
 | 
			
		||||
        state, created = MarkovState.objects.get_or_create(context=context, k1=words[i], k2=words[i + 1],
 | 
			
		||||
                                                           v=words[i + 2])
 | 
			
		||||
        state.count += 1
 | 
			
		||||
        state.save()
 | 
			
		||||
 | 
			
		||||
        if i > len(words) - 4:
 | 
			
		||||
            break
 | 
			
		||||
							
								
								
									
										41
									
								
								markov/migrations/0001_initial.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								markov/migrations/0001_initial.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,41 @@
 | 
			
		||||
# Generated by Django 2.0.1 on 2018-01-09 19:57
 | 
			
		||||
 | 
			
		||||
from django.db import migrations, models
 | 
			
		||||
import django.db.models.deletion
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Migration(migrations.Migration):
 | 
			
		||||
 | 
			
		||||
    initial = True
 | 
			
		||||
 | 
			
		||||
    dependencies = [
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    operations = [
 | 
			
		||||
        migrations.CreateModel(
 | 
			
		||||
            name='MarkovContext',
 | 
			
		||||
            fields=[
 | 
			
		||||
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
 | 
			
		||||
                ('name', models.CharField(max_length=200, unique=True)),
 | 
			
		||||
            ],
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.CreateModel(
 | 
			
		||||
            name='MarkovState',
 | 
			
		||||
            fields=[
 | 
			
		||||
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
 | 
			
		||||
                ('k1', models.CharField(max_length=256)),
 | 
			
		||||
                ('k2', models.CharField(max_length=256)),
 | 
			
		||||
                ('v', models.CharField(max_length=256)),
 | 
			
		||||
                ('count', models.IntegerField(default=0)),
 | 
			
		||||
                ('context', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='markov.MarkovContext')),
 | 
			
		||||
            ],
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AlterUniqueTogether(
 | 
			
		||||
            name='markovstate',
 | 
			
		||||
            unique_together={('context', 'k1', 'k2', 'v')},
 | 
			
		||||
        ),
 | 
			
		||||
        migrations.AlterIndexTogether(
 | 
			
		||||
            name='markovstate',
 | 
			
		||||
            index_together={('context', 'k1', 'k2'), ('context', 'v')},
 | 
			
		||||
        ),
 | 
			
		||||
    ]
 | 
			
		||||
							
								
								
									
										0
									
								
								markov/migrations/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								markov/migrations/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										43
									
								
								markov/models.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								markov/models.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,43 @@
 | 
			
		||||
"""Database objects for storing Markov chains."""
 | 
			
		||||
 | 
			
		||||
import logging
 | 
			
		||||
 | 
			
		||||
from django.db import models
 | 
			
		||||
 | 
			
		||||
log = logging.getLogger(__name__)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MarkovContext(models.Model):
 | 
			
		||||
    """Define contexts for Markov chains."""
 | 
			
		||||
 | 
			
		||||
    name = models.CharField(max_length=200, unique=True)
 | 
			
		||||
 | 
			
		||||
    def __str__(self):
 | 
			
		||||
        """String representation."""
 | 
			
		||||
        return "{0:s}".format(self.name)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class MarkovState(models.Model):
 | 
			
		||||
    """One element in a Markov chain, some text or something."""
 | 
			
		||||
 | 
			
		||||
    start1 = '__start1'
 | 
			
		||||
    start2 = '__start2'
 | 
			
		||||
    stop = '__stop'
 | 
			
		||||
 | 
			
		||||
    k1 = models.CharField(max_length=256)
 | 
			
		||||
    k2 = models.CharField(max_length=256)
 | 
			
		||||
    v = models.CharField(max_length=256)
 | 
			
		||||
 | 
			
		||||
    count = models.IntegerField(default=0)
 | 
			
		||||
    context = models.ForeignKey(MarkovContext, on_delete=models.CASCADE)
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        index_together = [
 | 
			
		||||
            ['context', 'k1', 'k2'],
 | 
			
		||||
            ['context', 'v'],
 | 
			
		||||
        ]
 | 
			
		||||
        unique_together = ('context', 'k1', 'k2', 'v')
 | 
			
		||||
 | 
			
		||||
    def __str__(self):
 | 
			
		||||
        """String representation."""
 | 
			
		||||
        return "{0:s},{1:s} -> {2:s} (count: {3:d})".format(self.k1, self.k2, self.v, self.count)
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user