AI-Chat

 view release on metacpan or  search on metacpan

lib/AI/Chat.pm  view on Meta::CPAN

package AI::Chat;

use strict;
use warnings;

use Carp;
use HTTP::Tiny;
use JSON::PP;

our $VERSION = '0.6';
$VERSION = eval $VERSION;

my $http = HTTP::Tiny->new;

# Create Chat object
sub new {
    my $class = shift;
    my %attr  = @_;

    $attr{'error'}      = '';

    $attr{'api'}        = 'OpenAI' unless $attr{'api'};
    $attr{'error'}      = 'Invalid API' unless $attr{'api'} eq 'OpenAI';
    $attr{'error'}      = 'API Key missing' unless $attr{'key'};

    $attr{'model'}      = 'gpt-4o-mini' unless $attr{'model'};

    return bless \%attr, $class;
}

# Define endpoints for APIs
my %url    = (
    'OpenAI' => 'https://api.openai.com/v1/chat/completions',
);

# Define HTTP Headers for APIs
my %header = (
    'OpenAI' => &_get_header_openai,
);

# Returns true if last operation was success
sub success {
    my $self = shift;
    return !$self->{'error'};
}

# Returns error if last operation failed
sub error {
    my $self = shift;
    return $self->{'error'};
}

# Header for calling OpenAI
sub _get_header_openai {
    my $self = shift;
    $self->{'key'} = '' unless defined $self->{'key'};
    return {
         'Authorization' => 'Bearer ' . $self->{'key'},
         'Content-type'  => 'application/json'
     };
 }
 
 # Get a reply from a single prompt
 sub prompt {
     my ($self, $prompt, $temperature) = @_;
     
     $self->{'error'} = '';
     unless ($prompt) {
         $self->{'error'} = "Missing prompt calling 'prompt' method";
         return undef;
     }

    $temperature = 1.0 unless $temperature;

    my @messages;
    push @messages, {
        role    => 'system',
        content => $self->{'role'},
    } if $self->{'role'};
    push @messages, {
        role    => 'user',
        content => $prompt,
    };
    
    return $self->chat(\@messages, $temperature);
}

# Get a reply from a full chat
sub chat {
    my ($self, $chat, $temperature) = @_;
    
    if (ref($chat) ne 'ARRAY') {
        $self->{'error'} = 'chat method requires an arrayref';
        return undef;
    }

    $temperature = 1.0 unless $temperature;

    my $response = $http->post($url{$self->{'api'}}, {
         'headers' => {
             'Authorization' => 'Bearer ' . $self->{'key'},
             'Content-type'  => 'application/json'
         },
         content => encode_json {
             model          => $self->{'model'},
             messages       => [ @$chat ],
             temperature    => $temperature,
         }
     });
     if ($response->{'content'} =~ 'invalid_api_key') {
         croak 'Incorrect API Key - check your API Key is correct';
     }
     
     if ($self->{'debug'} and !$response->{'success'}) {
         croak $response if $self->{'debug'} eq 'verbose';
         croak $response->{'content'};
     }

     my $reply = decode_json($response->{'content'});
     
     return $reply->{'choices'}[0]->{'message'}->{'content'};
}


__END__

=head1 NAME

AI::Chat - Interact with AI Chat APIs

=head1 VERSION

Version 0.6 

=head1 SYNOPSIS

  use AI::Chat;

  my $chat  = AI::Chat->new(
      key   => 'your-api-key',
      api   => 'OpenAI',
      model => 'gpt-4o-mini',
  );

  my $reply = $chat->prompt("What is the meaning of life?");
  print $reply;

=head1 DESCRIPTION



( run in 0.771 second using v1.01-cache-2.11-cpan-39bf76dae61 )