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',
 | 
					    'bot',
 | 
				
			||||||
    'dice',
 | 
					    'dice',
 | 
				
			||||||
    'logger',
 | 
					    'logger',
 | 
				
			||||||
 | 
					    'markov',
 | 
				
			||||||
    'weather',
 | 
					    '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