├── .gitignore └── yourmomdotcom.py /.gitignore: -------------------------------------------------------------------------------- 1 | training_text.txt 2 | -------------------------------------------------------------------------------- /yourmomdotcom.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import random 4 | import re 5 | 6 | from collections import defaultdict 7 | 8 | from twisted.words.protocols import irc 9 | from twisted.internet import reactor, protocol 10 | 11 | markov = defaultdict(list) 12 | STOP_WORD = "\n" 13 | 14 | def add_to_brain(msg, chain_length, write_to_file=False): 15 | if write_to_file: 16 | f = open('training_text.txt', 'a') 17 | f.write(msg + '\n') 18 | f.close() 19 | buf = [STOP_WORD] * chain_length 20 | for word in msg.split(): 21 | markov[tuple(buf)].append(word) 22 | del buf[0] 23 | buf.append(word) 24 | markov[tuple(buf)].append(STOP_WORD) 25 | 26 | def generate_sentence(msg, chain_length, max_words=10000): 27 | buf = msg.split()[:chain_length] 28 | if len(msg.split()) > chain_length: 29 | message = buf[:] 30 | else: 31 | message = [] 32 | for i in xrange(chain_length): 33 | message.append(random.choice(markov[random.choice(markov.keys())])) 34 | for i in xrange(max_words): 35 | try: 36 | next_word = random.choice(markov[tuple(buf)]) 37 | except IndexError: 38 | continue 39 | if next_word == STOP_WORD: 40 | break 41 | message.append(next_word) 42 | del buf[0] 43 | buf.append(next_word) 44 | return ' '.join(message) 45 | 46 | class MomBot(irc.IRCClient): 47 | def _get_nickname(self): 48 | return self.factory.nickname 49 | nickname = property(_get_nickname) 50 | 51 | def signedOn(self): 52 | self.join(self.factory.channel) 53 | print "Signed on as %s." % (self.nickname,) 54 | 55 | def joined(self, channel): 56 | print "Joined %s." % (channel,) 57 | 58 | def privmsg(self, user, channel, msg): 59 | if not user: 60 | return 61 | if self.nickname in msg: 62 | msg = re.compile(self.nickname + "[:,]* ?", re.I).sub('', msg) 63 | prefix = "%s: " % (user.split('!', 1)[0], ) 64 | else: 65 | prefix = '' 66 | add_to_brain(msg, self.factory.chain_length, write_to_file=True) 67 | if prefix or random.random() <= self.factory.chattiness: 68 | sentence = generate_sentence(msg, self.factory.chain_length, 69 | self.factory.max_words) 70 | if sentence: 71 | self.msg(self.factory.channel, prefix + sentence) 72 | 73 | class MomBotFactory(protocol.ClientFactory): 74 | protocol = MomBot 75 | 76 | def __init__(self, channel, nickname='YourMomDotCom', chain_length=3, 77 | chattiness=1.0, max_words=10000): 78 | self.channel = channel 79 | self.nickname = nickname 80 | self.chain_length = chain_length 81 | self.chattiness = chattiness 82 | self.max_words = max_words 83 | 84 | def clientConnectionLost(self, connector, reason): 85 | print "Lost connection (%s), reconnecting." % (reason,) 86 | connector.connect() 87 | 88 | def clientConnectionFailed(self, connector, reason): 89 | print "Could not connect: %s" % (reason,) 90 | 91 | if __name__ == "__main__": 92 | try: 93 | chan = sys.argv[1] 94 | except IndexError: 95 | print "Please specify a channel name." 96 | print "Example:" 97 | print " python yourmomdotcom.py django-hotclub" 98 | chain_length = 2 99 | if os.path.exists('training_text.txt'): 100 | f = open('training_text.txt', 'r') 101 | for line in f: 102 | add_to_brain(line, chain_length) 103 | print 'Brain Reloaded' 104 | f.close() 105 | reactor.connectTCP('irc.freenode.net', 6667, MomBotFactory('#' + chan, 'YourMomDotCom', chain_length, chattiness=0.05)) 106 | reactor.run() --------------------------------------------------------------------------------