Langertha
view release on metacpan or search on metacpan
lib/Langertha/Role/OpenAICompatible.pm view on Meta::CPAN
package Langertha::Role::OpenAICompatible;
# ABSTRACT: Role for OpenAI-compatible API format
our $VERSION = '0.502';
use Moose::Role;
use File::ShareDir::ProjectDistDir qw( :all );
use Carp qw( croak );
use JSON::MaybeXS;
use Langertha::ToolChoice;
use Langertha::Response;
use Langertha::ToolCall;
has api_key => (
is => 'ro',
lazy_build => 1,
);
sub _build_api_key { undef }
sub update_request {
my ( $self, $request ) = @_;
my $key = $self->api_key;
$request->header('Authorization', 'Bearer '.$key) if defined $key;
}
sub openapi_file { yaml => dist_file('Langertha','openai.yaml') };
sub default_embedding_model { 'text-embedding-3-large' }
sub default_transcription_model { 'whisper-1' }
sub default_image_model { 'gpt-image-1' }
# Dynamic model listing
sub list_models_path { '/models' }
sub list_models_request {
my ($self, %params) = @_;
my $url = $self->url.$self->list_models_path;
if ($params{after}) {
$url .= '?after='.$params{after};
}
return $self->generate_http_request(
GET => $url,
sub { $self->list_models_response(shift) },
);
}
sub list_models_response {
my ($self, $response) = @_;
my $data = $self->parse_response($response);
return $data;
}
sub list_models {
my ($self, %opts) = @_;
# Guard: if supported_operations excludes listModels, fall back to current model
unless ($self->can_operation('listModels')) {
return [$self->model];
}
# Check cache unless force_refresh requested
unless ($opts{force_refresh}) {
my $cache = $self->_models_cache;
if ($cache->{timestamp} && time - $cache->{timestamp} < $self->models_cache_ttl) {
return $opts{full} ? $cache->{models} : $cache->{model_ids};
}
}
# Fetch all pages
my @all_models;
my $after;
for my $page (1..100) {
my $request = $self->list_models_request($after ? (after => $after) : ());
my $response = $self->user_agent->request($request);
( run in 1.025 second using v1.01-cache-2.11-cpan-7fcb06a456a )