ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Net-Knuddels/eg/markovd
Revision: 1.33
Committed: Sun Jan 30 14:07:27 2005 UTC (21 years, 7 months ago) by root
Branch: MAIN
Changes since 1.32: +8 -6 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 #!/opt/bin/perl
2
3 use strict;
4
5 use Socket;
6 use IO::Socket::INET;
7
8 use YAML;
9 use Encode;
10 use Event;
11 use Net::Knuddels;
12 use Algorithm::MarkovChain;
13 use String::Similarity;
14 use List::Util;
15 use Time::HiRes;
16
17 my @CHANNELS = (
18 'Flirt',
19 'Flirt Private',
20 'Singles 11-14',
21 'Singles 15-17',
22
23 'Singles 11-14 2',
24 'Singles 15-17 2',
25 'Flirt 2',
26 'Flirt Private 2',
27 'Singles 11-14 3',
28 'Singles 15-17 3',
29 'Flirt 3',
30 'Flirt Private 3',
31 'Singles 11-14 4',
32 'Singles 15-17 4',
33 'Flirt 4',
34 'Flirt Private 4',
35 'Singles 11-14 5',
36 'Singles 15-17 5',
37 'Flirt 5',
38 'Flirt Private 5',
39 'Singles 11-14 6',
40 'Singles 15-17 6',
41 'Flirt 6',
42 'Flirt Private 6',
43 'Singles 11-14 7',
44 'Singles 15-17 7',
45 'Flirt 7',
46 'Flirt Private 7',
47 'Singles 11-14 8',
48 'Singles 15-17 8',
49 'Flirt 8',
50 'Flirt Private 8',
51 );
52
53 my $logdir = "logs";
54
55 my $Knick = "ich bin suess";
56 my $Kpass = "qwerty";
57
58 my $client;
59
60 my $seed = Load do { open my $fh, "<", "markovbot.dat"; binmode $fh, ":utf8"; local $/; <$fh> };
61 $seed ||= [];
62
63 my $fwd = new Algorithm::MarkovChain;
64 my $rev = new Algorithm::MarkovChain;
65
66 my %freq;
67 my $word_cnt;
68
69 sub word {
70 $_[0] =~ /(\w+)/ ? lc $1 : ();
71 }
72
73 sub seed_msg {
74 my $msg = $_[0];
75
76 return if $msg =~ /leck|fick|möse|mose|moese|uschi|usci|ushi|fikk|scheide|vagina
77 |bumsen|wichs|wix|popp|popen|fuck|dreck|laber|saugen|pussy|\bsuck\b
78 |\bblas|piss|schluck|fingern|spritz|\bloch|\bsteck|vögel|voegel|vogel
79 |hure|strich|sklave|handschell|slave
80 |stengel|penis|schwanz|pimmel|steifen|ejak|sperma|\btitt|\bass|\bsack|\bsaft\b|\beier\b
81 |\bcs\b|\bts\b|\brs\b|\bicq\b
82 |cam\b|\bmsn\b|\bbot\b|\bchat.*bot\b|tanga|schlafen|sex|\bsau\b
83 |intim|arsch|fotze|dumm|schnauze|klappe|rasiert|fresse|maul\b|\bmaul|rosett?e
84 |zieh.*aus|nackt
85 |sätz|saetz|setze|\bsatz
86 |sc?h?wul|schwuchtel|transe|transv|schlampe|tussi|nutte|mädel
87 |admin|nachgeburt
88 |(?-i:[A-Z]{4,})
89 |\S{20,}
90 /xi;
91
92 my @msg = $msg =~ m/(\S+)/g;
93
94 $freq{word $_}++ for @msg;
95 $word_cnt += @msg;
96
97 $fwd->seed (symbols => \@msg, longest => 14);
98 $rev->seed (symbols => [reverse @msg], longest => 14);
99 }
100
101 for (@$seed) {
102 seed_msg $_;
103 }
104
105 my %grammar_reply = qw(
106 ich du
107 du ich
108 mir dir
109 dir mir
110 mein dein
111 dein mein
112 frau mann
113 mädel junge
114 mädchen junge
115 freund freundin
116 freundin freund
117 girls boys
118 boys girls
119 huhu hi
120 hi hi
121 hallo hi
122 typen mädels
123 bye bye
124 ciao bye
125 );
126
127 sub gen_reply {
128 my ($msg) = @_;
129
130 my @msg = $msg =~ /(\S+)/g;
131
132 @msg = map {
133 my $word = word $_;
134
135 $grammar_reply{$word}
136 or $freq{$word} < $word_cnt * 0.003
137 && $freq{$word} >= 2
138 && 4 < length $word
139 ? $word
140 : ()
141 } @msg;
142
143 my $reply;
144 my $best = 2;
145
146 for (1..15) {
147 shift @msg if @msg > $_;
148 my $len = rand() ** 4 * 20 + 2;
149 my @r = reverse $rev->spew (complete => [reverse @msg], length => $len, stop_at_terminal => 1);
150 @r = $fwd->spew (complete => \@r, length => $len, stop_at_terminal => 1);
151 my $r = join " ", @r;
152 my $b = (List::Util::sum map $freq{word $_} / $word_cnt, @r) / @r;
153 ($reply, $best) = ($r, $b) if $b < $best;
154 }
155
156 $reply;
157 }
158
159 while (0) {
160 my $r = gen_reply scalar <>;
161 print "$r\n\n";
162 }
163
164 Event->signal (signal => "INT", cb => sub { Event::unloop(-1) });
165
166 Event->timer (interval => 60, cb => sub {
167 open my $fh, ">", "markovbot.dat~"
168 or return;
169 binmode $fh;
170 print $fh Encode::encode_utf8 Dump $seed;
171 close $fh;
172 rename "markovbot.dat~", "markovbot.dat";
173 });
174
175 sub logit {
176 my ($msg, $file, $src, $dst, $room) = @_;
177
178 mkdir $logdir;
179 my $fh;
180
181 unless (open $fh, ">>:utf8", Encode::encode_utf8 "$logdir/$file") {
182 warn "Couldn't open for appending $logdir/$src: $!\n";
183 return;
184 }
185
186 print $fh "$room\t$src\t$dst\t$msg\n";
187 }
188
189 ####################################################################################
190 ########################## MAIN START ##############################################
191 ####################################################################################
192
193 $client = new Net::Knuddels::Client
194 PeerAddr => "213.61.5.150:2710",
195 command_wait => sub {
196 my ($client, $wait) = @_;
197 Event->timer (after => $wait, cb => sub { $client->command_cb });
198 };
199
200 Event->io (
201 fd => $client->fh,
202 poll => 'r',
203 cb => sub {
204 $client->ready
205 or $_[0]->w->cancel;
206 });
207
208 $client->login;
209
210 $client->register (dialog => sub {
211 use Dumpvalue;
212 print "---\n";
213 Dumpvalue->new (compactDump => 1, veryCompact => 1, quoteHighBit => 1, tick => '"')->dumpValue ([@_]);
214 });
215
216 $client->register (login => sub {
217 $client->enter_room ($_, $Knick, $Kpass)
218 for @CHANNELS;
219 });
220
221 $client->register (msg_room => sub {
222 my ($room, $user, $msg) = @_;
223 });
224
225 my @queue;
226
227 Event->timer (interval => 1, cb => sub {
228 my $msg = shift @queue
229 or return;
230
231 logit ($msg->[2], $msg->[0], $Knick, $msg->[0], $msg->[1]);
232 $client->send_priv_msg (@$msg);
233 });
234
235 my $some_room;
236
237 $client->register (room_info => sub {
238 print "JOIN ROOM: $_[0]\n";
239 $some_room = $_[0];
240 });
241
242 Event->timer (after => 60, interval => 60, cb => sub {
243 $client->send_priv_msg ("James", $some_room, "/knuschel");
244 });
245
246 my %next_time;
247
248 $client->register (msg_priv_nondup => sub {
249 my ($room, $src, $dst, $msg) = @_;
250
251 my $NOW = Time::HiRes::time;
252
253 $msg =~ s/\260[^\260]*\260//g;
254
255 print "($room) $src >> $msg\n";
256 logit ($msg, $src, $src, $dst, $room);
257
258 return if $next_time{$src} > time; # do not talk unnaturally often
259
260 my $reply = gen_reply $msg;
261
262 push @$seed, $msg;
263 seed_msg $msg;
264
265 my $delay = 30 * (rand) ** 5 + 0.3 * length $reply;
266 $next_time{$src} = time + $delay;
267
268 print "($room) $src << $reply ($delay)\n";
269
270 Event->timer (at => $NOW + $delay, cb => sub {
271 push @queue, [$src, $room, $reply];
272 });
273 });
274
275 Event::loop;
276