ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Net-Knuddels/eg/markovd
Revision: 1.37
Committed: Sun Jan 30 20:33:16 2005 UTC (21 years, 7 months ago) by root
Branch: MAIN
Changes since 1.36: +12 -4 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 <<<<<<< markovd
77 return if $msg =~ /leck|fick|möse|mose|moese|uschi|usci|ushi|fikkn
78 |bumsen|wichs|wix|popp|popen|fuck|dreck|laber|saugen|pussy|\bsuck\b
79 |\bblas|piss|schluck|fingern|spritz|\bloch
80 |hure|strich|sklave|handschell
81 |stengel|penis|schwanz|pimmel|steifen|ejak|sperma|\btitt|\bass|\bsack|\bsaft\b
82 =======
83 return if $msg =~ /leck|fick|möse|mose|moese|uschi|usci|ushi|fikk|scheide|vagina
84 |bumsen|wichs|wix|popp|popen|fuck|dreck|laber|saugen|pussy|\bsuck\b
85 |\bblas|piss|schluck|fingern|spritz|\bloch|\bsteck|vögel|voegel|vogel
86 |hure|strich|sklave|handschell|slave|perver|befehl|stöhn|dildo
87 |stengel|penis|schwanz|pimmel|steifen|ejak|sperma|\btitt|\bass|\bsack|\bsaft\b|\beier\b
88 >>>>>>> 1.35
89 |\bcs\b|\bts\b|\brs\b|\bicq\b
90 |cam\b|\bmsn\b|\bbot\b|\bchat.*bot\b|tanga|schlafen|sex|\bsau\b
91 |intim|arsch|fotze|dumm|schnauze|klappe|rasiert|fresse|maul\b|\bmaul|rosett?e
92 |zieh.*aus|nackt
93 |sätz|saetz|setze|\bsatz
94 |sc?h?wul|schwuchtel|transe|transv|schlampe|tussi|nutte|mädel
95 |admin|nachgeburt
96 |(?-i:[A-Z]{4,})
97 |\S{20,}
98 /xi;
99
100 my @msg = $msg =~ m/(\S+)/g;
101
102 $freq{word $_}++ for @msg;
103 $word_cnt += @msg;
104
105 $fwd->seed (symbols => \@msg, longest => 10);
106 $rev->seed (symbols => [reverse @msg], longest => 10);
107 }
108
109 for (@$seed) {
110 seed_msg $_;
111 }
112
113 my %grammar_reply = qw(
114 ich du
115 du ich
116 mir dir
117 dir mir
118 mein dein
119 dein mein
120 frau mann
121 mädel junge
122 mädchen junge
123 freund freundin
124 freundin freund
125 girls boys
126 boys girls
127 huhu hi
128 hi hi
129 hallo hi
130 typen mädels
131 bye bye
132 ciao bye
133 );
134
135 sub gen_reply {
136 my ($msg) = @_;
137
138 my @msg = $msg =~ /(\S+)/g;
139
140 @msg = map {
141 my $word = word $_;
142
143 $grammar_reply{$word}
144 or $freq{$word} < $word_cnt * 0.003
145 && $freq{$word} >= 2
146 && 4 < length $word
147 ? $word
148 : ()
149 } @msg;
150
151 my $reply;
152 my $best = 2;
153
154 for (1..10) {
155 shift @msg if @msg > $_;
156 my $len = rand() ** 3 * 15 + 2;
157 my @r = reverse $rev->spew (complete => [reverse @msg], length => $len, stop_at_terminal => 1);
158 @r = $fwd->spew (complete => \@r, length => $len, stop_at_terminal => 1);
159 my $r = join " ", @r;
160 my $b = (List::Util::sum map $freq{word $_} / $word_cnt, @r) / @r;
161 ($reply, $best) = ($r, $b) if $b < $best;
162 }
163
164 $reply;
165 }
166
167 while (0) {
168 my $r = gen_reply scalar <>;
169 print "$r\n\n";
170 }
171
172 Event->signal (signal => "INT", cb => sub { Event::unloop(-1) });
173
174 Event->timer (interval => 60, cb => sub {
175 open my $fh, ">", "markovbot.dat~"
176 or return;
177 binmode $fh;
178 print $fh Encode::encode_utf8 Dump $seed;
179 close $fh;
180 rename "markovbot.dat~", "markovbot.dat";
181 });
182
183 sub logit {
184 my ($msg, $file, $src, $dst, $room) = @_;
185
186 mkdir $logdir;
187 my $fh;
188
189 unless (open $fh, ">>:utf8", Encode::encode_utf8 "$logdir/$file") {
190 warn "Couldn't open for appending $logdir/$src: $!\n";
191 return;
192 }
193
194 print $fh "$room\t$src\t$dst\t$msg\n";
195 }
196
197 ####################################################################################
198 ########################## MAIN START ##############################################
199 ####################################################################################
200
201 $client = new Net::Knuddels::Client
202 PeerAddr => "213.61.5.150:2710",
203 command_wait => sub {
204 my ($client, $wait) = @_;
205 Event->timer (after => $wait, cb => sub { $client->command_cb });
206 };
207
208 Event->io (
209 fd => $client->fh,
210 poll => 'r',
211 cb => sub {
212 $client->ready
213 or $_[0]->w->cancel;
214 });
215
216 $client->login;
217
218 $client->register (dialog => sub {
219 use Dumpvalue;
220 print "---\n";
221 Dumpvalue->new (compactDump => 1, veryCompact => 1, quoteHighBit => 1, tick => '"')->dumpValue ([@_]);
222 Event::unloop(-1) if grep /Falsches.*Passwort/i, @_;
223 });
224
225 $client->register (login => sub {
226 $client->enter_room ($_, $Knick, $Kpass)
227 for @CHANNELS;
228 });
229
230 $client->register (msg_room => sub {
231 my ($room, $user, $msg) = @_;
232 });
233
234 my @queue;
235
236 Event->timer (interval => 1, cb => sub {
237 my $msg = shift @queue
238 or return;
239
240 logit ($msg->[2], $msg->[0], $Knick, $msg->[0], $msg->[1]);
241 $client->send_priv_msg (@$msg);
242 });
243
244 my $some_room;
245
246 $client->register (room_info => sub {
247 print "JOIN ROOM: $_[0]\n";
248 $some_room = $_[0];
249 });
250
251 Event->timer (after => 60, interval => 60, cb => sub {
252 $client->send_priv_msg ("James", $some_room, "/knuschel");
253 });
254
255 my %next_time;
256
257 $client->register (msg_priv_nondup => sub {
258 my ($room, $src, $dst, $msg) = @_;
259
260 my $NOW = Time::HiRes::time;
261
262 $msg =~ s/\260[^\260]*\260//g;
263
264 print "($room) $src >> $msg\n";
265 logit ($msg, $src, $src, $dst, $room);
266
267 return if $next_time{$src} > time; # do not talk unnaturally often
268
269 my $reply = gen_reply $msg;
270
271 push @$seed, $msg;
272 seed_msg $msg;
273
274 my $delay = 30 * (rand) ** 5 + 0.3 * length $reply;
275 $next_time{$src} = time + $delay;
276
277 print "($room) $src << $reply ($delay)\n";
278
279 Event->timer (at => $NOW + $delay, cb => sub {
280 push @queue, [$src, $room, $reply];
281 });
282 });
283
284 Event::loop;
285