AI-Anthropic

 view release on metacpan or  search on metacpan

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

    my $response = $self->{_http}->post(
        $self->{api_base} . '/v1/messages',
        {
            headers      => $self->_headers,
            content      => $self->{_json}->encode($body),
            data_callback => sub {
                my ($chunk, $res) = @_;
                
                # Parse SSE events
                for my $line (split /\n/, $chunk) {
                    next unless $line =~ /^data: (.+)/;
                    my $data = $1;
                    next if $data eq '[DONE]';
                    
                    eval {
                        my $event = $self->{_json}->decode($data);
                        
                        if ($event->{type} eq 'content_block_delta') {
                            my $text = $event->{delta}{text} // '';
                            $full_text .= $text;
                            $callback->($text) if $callback;
                        } elsif ($event->{type} eq 'message_stop') {
                            $response_data = $event;
                        }
                    };
                }
            },
        }
    );
    
    unless ($response->{success}) {
        return $self->_handle_response($response);
    }
    
    # Return a response object with the full text
    return AI::Anthropic::Response->new(
        text         => $full_text,
        raw_response => $response_data,
    );
}

sub _headers {
    my ($self) = @_;
    
    return {
        'Content-Type'      => 'application/json',
        'x-api-key'         => $self->{api_key},
        'anthropic-version' => API_VERSION,
    };
}

sub _handle_response {
    my ($self, $response) = @_;
    
    my $data;
    eval {
        $data = $self->{_json}->decode($response->{content});
    };
    
    unless ($response->{success}) {
        my $error_msg = $data->{error}{message} // $response->{content} // 'Unknown error';
        croak "Anthropic API error: $error_msg (status: $response->{status})";
    }
    
    return AI::Anthropic::Response->new(
        text          => $data->{content}[0]{text} // '',
        role          => $data->{role},
        model         => $data->{model},
        stop_reason   => $data->{stop_reason},
        usage         => $data->{usage},
        raw_response  => $data,
    );
}

# ============================================
# Response class
# ============================================

package AI::Anthropic::Response;

use strict;
use warnings;
use overload '""' => \&text, fallback => 1;

sub new {
    my ($class, %args) = @_;
    return bless \%args, $class;
}

sub text         { shift->{text}         }
sub role         { shift->{role}         }
sub model        { shift->{model}        }
sub stop_reason  { shift->{stop_reason}  }
sub usage        { shift->{usage}        }
sub raw_response { shift->{raw_response} }

sub input_tokens  { shift->{usage}{input_tokens}  // 0 }
sub output_tokens { shift->{usage}{output_tokens} // 0 }
sub total_tokens  { 
    my $self = shift;
    return $self->input_tokens + $self->output_tokens;
}

1;

__END__

=head1 EXAMPLES

=head2 Basic usage

    use AI::Anthropic;
    
    my $claude = AI::Anthropic->new;
    print $claude->message("Hello, Claude!");

=head2 With image (vision)

    my $response = $claude->chat(
        messages => [
            {
                role    => 'user',



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