-
Notifications
You must be signed in to change notification settings - Fork 0
/
jimlad.py
129 lines (97 loc) · 4.15 KB
/
jimlad.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
#!/usr/bin/python
import random
import re
import redis
#import irc
#import irc.bot
from irc import IRCBot, run_bot
class MarkovBot(IRCBot):
"""
http://code.activestate.com/recipes/194364-the-markov-chain-algorithm/
http://github.com/ericflo/yourmomdotcom
"""
chain_length = 2 #2
chattiness = 0.1 #0.01
max_words = 40 #30
messages_to_generate = 5
prefix = 'irc'
separator = '\x01'
stop_word = '\x02'
def __init__(self, *args, **kwargs):
super(MarkovBot, self).__init__(*args, **kwargs)
#self.redis_conn = redis.Redis(host = '192.168.1.130', port = 6379, db = 0)
self.redis_conn = redis.Redis()
def make_key(self, k):
return '-'.join((self.prefix, k))
def sanitize_message(self, message):
return re.sub('[\"\']', '', message.lower())
def split_message(self, message):
# split the incoming message into words, i.e. ['what', 'up', 'bro']
words = message.split()
# if the message is any shorter, it won't lead anywhere
if len(words) > self.chain_length:
# add some stop words onto the message
# ['what', 'up', 'bro', '\x02']
words.append(self.stop_word)
# len(words) == 4, so range(4-2) == range(2) == 0, 1, meaning
# we return the following slices: [0:3], [1:4]
# or ['what', 'up', 'bro'], ['up', 'bro', '\x02']
for i in range(len(words) - self.chain_length):
yield words[i:i + self.chain_length + 1]
def generate_message(self, seed):
key = seed
# keep a list of words we've seen
gen_words = []
# only follow the chain so far, up to <max words>
for i in xrange(self.max_words):
# split the key on the separator to extract the words -- the key
# might look like "this\x01is" and split out into ['this', 'is']
words = key.split(self.separator)
# add the word to the list of words in our generated message
gen_words.append(words[0])
# get a new word that lives at this key -- if none are present we've
# reached the end of the chain and can bail
next_word = self.redis_conn.srandmember(self.make_key(key))
if not next_word:
break
# create a new key combining the end of the old one and the next_word
key = self.separator.join(words[1:] + [next_word])
return ' '.join(gen_words)
def log(self, sender, message, channel):
# speak only when spoken to, or when the spirit moves me
say_something = self.is_ping(message) or (
sender != self.conn.nick and random.random() < self.chattiness
)
messages = []
# use a convenience method to strip out the "ping" portion of a message
if self.is_ping(message):
message = self.fix_ping(message)
if message.startswith('/'):
return
# split up the incoming message into chunks that are 1 word longer than
# the size of the chain, e.g. ['what', 'up', 'bro'], ['up', 'bro', '\x02']
for words in self.split_message(self.sanitize_message(message)):
# grab everything but the last word
key = self.separator.join(words[:-1])
# add the last word to the set
self.redis_conn.sadd(self.make_key(key), words[-1])
# if we should say something, generate some messages based on what
# was just said and select the longest, then add it to the list
if say_something:
best_message = ''
for i in range(self.messages_to_generate):
generated = self.generate_message(seed=key)
if len(generated) > len(best_message):
best_message = generated
if best_message:
messages.append(best_message)
if len(messages):
return random.choice(messages)
def command_patterns(self):
return (
('.*', self.log),
)
host = 'irc.hypersigil.org'
port = 6667
nick = 'cake'
run_bot(MarkovBot, host, port, nick, ['#botdev'])