ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Net-Knuddels/eg/markovd
Revision: 1.32
Committed: Sun Jan 30 08:01:33 2005 UTC (21 years, 7 months ago) by root
Branch: MAIN
Changes since 1.31: +1 -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
80 |stengel|penis|schwanz|pimmel|steifen|ejak|sperma|\btitt|\bass|\bsack|\bsaft\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 => 10);
98 $rev->seed (symbols => [reverse @msg], longest => 10);
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 );
124
125 sub gen_reply {
126 my ($msg) = @_;
127
128 my @msg = $msg =~ /(\S+)/g;
129
130 @msg = map {
131 my $word = word $_;
132
133 $grammar_reply{$word}
134 or $freq{$word} < $word_cnt * 0.002
135 && $freq{$word} >= 2
136 && 4 < length $word
137 ? $word
138 : ()
139 } @msg;
140
141 my $reply;
142 my $best = 2;
143
144 for (1..10) {
145 shift @msg if @msg > $_;
146 my $len = rand() ** 3 * 15 + 2;
147 my @r = reverse $rev->spew (complete => [reverse @msg], length => $len, stop_at_terminal => 1);
148 @r = $fwd->spew (complete => \@r, length => $len, stop_at_terminal => 1);
149 my $r = join " ", @r;
150 my $b = (List::Util::sum map $freq{word $_} / $word_cnt, @r) / @r;
151 ($reply, $best) = ($r, $b) if $b < $best;
152 }
153
154 $reply;
155 }
156
157 while (0) {
158 my $r = gen_reply scalar <>;
159 print "$r\n\n";
160 }
161
162 Event->signal (signal => "INT", cb => sub { Event::unloop(-1) });
163
164 Event->timer (interval => 60, cb => sub {
165 open my $fh, ">", "markovbot.dat~"
166 or return;
167 binmode $fh;
168 print $fh Encode::encode_utf8 Dump $seed;
169 close $fh;
170 rename "markovbot.dat~", "markovbot.dat";
171 });
172
173 sub logit {
174 my ($msg, $file, $src, $dst, $room) = @_;
175
176 mkdir $logdir;
177 my $fh;
178
179 unless (open $fh, ">>:utf8", Encode::encode_utf8 "$logdir/$file") {
180 warn "Couldn't open for appending $logdir/$src: $!\n";
181 return;
182 }
183
184 print $fh "$room\t$src\t$dst\t$msg\n";
185 }
186
187 ####################################################################################
188 ########################## MAIN START ##############################################
189 ####################################################################################
190
191 $client = new Net::Knuddels::Client
192 PeerAddr => "213.61.5.150:2710",
193 command_wait => sub {
194 my ($client, $wait) = @_;
195 Event->timer (after => $wait, cb => sub { $client->command_cb });
196 };
197
198 Event->io (
199 fd => $client->fh,
200 poll => 'r',
201 cb => sub {
202 $client->ready
203 or $_[0]->w->cancel;
204 });
205
206 $client->login;
207
208 $client->register (dialog => sub {
209 use Dumpvalue;
210 print "---\n";
211 Dumpvalue->new (compactDump => 1, veryCompact => 1, quoteHighBit => 1, tick => '"')->dumpValue ([@_]);
212 });
213
214 $client->register (login => sub {
215 $client->enter_room ($_, $Knick, $Kpass)
216 for @CHANNELS;
217 });
218
219 $client->register (msg_room => sub {
220 my ($room, $user, $msg) = @_;
221 });
222
223 my @queue;
224
225 Event->timer (interval => 1, cb => sub {
226 my $msg = shift @queue
227 or return;
228
229 logit ($msg->[2], $msg->[0], $Knick, $msg->[0], $msg->[1]);
230 $client->send_priv_msg (@$msg);
231 });
232
233 my $some_room;
234
235 $client->register (room_info => sub {
236 print "JOIN ROOM: $_[0]\n";
237 $some_room = $_[0];
238 });
239
240 Event->timer (after => 60, interval => 60, cb => sub {
241 $client->send_priv_msg ("James", $some_room, "/knuschel");
242 });
243
244 my %next_time;
245
246 $client->register (msg_priv_nondup => sub {
247 my ($room, $src, $dst, $msg) = @_;
248
249 my $NOW = Time::HiRes::time;
250
251 $msg =~ s/\260[^\260]*\260//g;
252
253 print "($room) $src >> $msg\n";
254 logit ($msg, $src, $src, $dst, $room);
255
256 return if $next_time{$src} > time; # do not talk unnaturally often
257
258 my $reply = gen_reply $msg;
259
260 push @$seed, $msg;
261 seed_msg $msg;
262
263 my $delay = 30 * (rand) ** 5 + 0.3 * length $reply;
264 $next_time{$src} = time + $delay;
265
266 print "($room) $src << $reply ($delay)\n";
267
268 Event->timer (at => $NOW + $delay, cb => sub {
269 push @queue, [$src, $room, $reply];
270 });
271 });
272
273 Event::loop;
274