ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Net-Knuddels/eg/markovd
Revision: 1.34
Committed: Sun Jan 30 14:23:41 2005 UTC (21 years, 7 months ago) by root
Branch: MAIN
Changes since 1.33: +2 -1 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|perver|befehl|stöhn
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 Event::unloop if grep /falsch.*Passwort/i, @_;
215 });
216
217 $client->register (login => sub {
218 $client->enter_room ($_, $Knick, $Kpass)
219 for @CHANNELS;
220 });
221
222 $client->register (msg_room => sub {
223 my ($room, $user, $msg) = @_;
224 });
225
226 my @queue;
227
228 Event->timer (interval => 1, cb => sub {
229 my $msg = shift @queue
230 or return;
231
232 logit ($msg->[2], $msg->[0], $Knick, $msg->[0], $msg->[1]);
233 $client->send_priv_msg (@$msg);
234 });
235
236 my $some_room;
237
238 $client->register (room_info => sub {
239 print "JOIN ROOM: $_[0]\n";
240 $some_room = $_[0];
241 });
242
243 Event->timer (after => 60, interval => 60, cb => sub {
244 $client->send_priv_msg ("James", $some_room, "/knuschel");
245 });
246
247 my %next_time;
248
249 $client->register (msg_priv_nondup => sub {
250 my ($room, $src, $dst, $msg) = @_;
251
252 my $NOW = Time::HiRes::time;
253
254 $msg =~ s/\260[^\260]*\260//g;
255
256 print "($room) $src >> $msg\n";
257 logit ($msg, $src, $src, $dst, $room);
258
259 return if $next_time{$src} > time; # do not talk unnaturally often
260
261 my $reply = gen_reply $msg;
262
263 push @$seed, $msg;
264 seed_msg $msg;
265
266 my $delay = 30 * (rand) ** 5 + 0.3 * length $reply;
267 $next_time{$src} = time + $delay;
268
269 print "($room) $src << $reply ($delay)\n";
270
271 Event->timer (at => $NOW + $delay, cb => sub {
272 push @queue, [$src, $room, $reply];
273 });
274 });
275
276 Event::loop;
277