Adam
view release on metacpan or search on metacpan
ex/ai-bot.pl view on Meta::CPAN
#
# Environment:
# ENGINE=Groq Engine class (default: Groq)
# MODEL=llama-3.3-70b-versatile Model name
# API_KEY=gsk_... API key (or LANGERTHA_<ENGINE>_API_KEY)
# IRC_SERVER=irc.perl.org IRC server (default: irc.perl.org)
# IRC_NICKNAME=Bert Bot nickname (default: random from a fun list)
# OWNER=Getty Bot owner name for personality (default: $USER)
# IRC_CHANNELS=#ai Channels to join
# DB_FILE=ai-bot.db SQLite database path
# MAX_LINE_LENGTH=400 Max IRC line length (default: 400)
# BUFFER_DELAY=1.5 Seconds to buffer messages before processing (default: 1.5)
# LINE_DELAY=1.5 Delay between outgoing IRC lines (default: 1.5)
# IDLE_PING=1800 Seconds of silence before idle ping (default: 1800)
# SYSTEM_PROMPT=... Additional text appended to the system prompt
use strict;
use warnings;
my @BOT_NAMES = qw(
Botsworth Clanky Sparky Fizz Gizmo Pixel Blip Rusty Ziggy Turbo
ex/ai-bot.pl view on Meta::CPAN
$self->_setup_raider->get;
POE::Kernel->delay( _idle_check => $IDLE_PING );
};
sub _send_to_channel {
my ($self, $channel, $text) = @_;
my @chunks;
for my $line (split(/\n/, $text)) {
$line =~ s/^\s+//;
$line =~ s/\s+$//;
next unless length $line;
while (length($line) > $MAX_LINE) {
my $chunk = substr($line, 0, $MAX_LINE);
if ($chunk =~ /^(.{1,$MAX_LINE})\s/) {
$chunk = $1;
}
push @chunks, $chunk;
$line = substr($line, length($chunk));
$line =~ s/^\s+//;
}
push @chunks, $line if length $line;
}
# Send each line with a delay BEFORE it, simulating typing time
# ~30 chars/sec typing speed, minimum 1.5s delay
my $cumulative = 0;
for my $i (0 .. $#chunks) {
my $delay = length($chunks[$i]) / 30;
$delay = 1.5 if $delay < 1.5;
$delay += 5 if $i > 0 && $chunks[$i - 1] =~ /\.{3}\s*\*?\s*$/;
$cumulative += $delay;
POE::Kernel->delay_add( _send_line => $cumulative, $channel, $chunks[$i] );
}
}
event _send_line => sub {
my ( $self, $channel, $line ) = @_[ OBJECT, ARG0, ARG1 ];
$self->privmsg($channel => $line);
ex/ai-bot.pl view on Meta::CPAN
}
# Clean up AI output
$answer =~ s/^<\s*\@?\s*(\w+)\s*>:?\s*/$1: /mg; # line start <@nick> â Nick:
$answer =~ s/<\s*\@?\s*(\w+)\s*>/$1/g; # mid-text <nick> â Nick
$answer =~ s/<\/?\w+>//g; # strip remaining XML tags
# Strip lines where the AI narrates its tool usage
$answer =~ s/^\*?\s*(save_note|recall_notes|update_note|delete_note|recall_history|stay_silent|set_alarm|whois|send_private_message)\b[^\n]*\n?//mg;
# Check for lines too long
my @lines = grep { length } map { s/^\s+//r =~ s/\s+$//r } split(/\n/, $answer);
my $too_long = grep { length($_) > $MAX_LINE } @lines;
if ($too_long) {
$self->info("Response too long, asking to shorten");
$answer = eval {
my $retry = $self->_raider->raid(
"Your last response had lines over $MAX_LINE characters. "
. "Rewrite it shorter. Every line must be under $MAX_LINE chars."
);
"$retry";
} || $answer;
}
( run in 0.562 second using v1.01-cache-2.11-cpan-140bd7fdf52 )