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