AI-Ollama-Client

 view release on metacpan or  search on metacpan

lib/AI/Ollama/Client/Impl.pm  view on Meta::CPAN

        my $resp = $tx->res;
        $self->emit(response => $resp);
        # Should we validate using OpenAPI::Modern here?!
        if( $resp->code == 200 ) {
            # Blob exists on the server
            $res->done($resp);
        } elsif( $resp->code == 404 ) {
            # Blob was not found
            $res->done($resp);
        } else {
            # An unknown/unhandled response, likely an error
            $res->fail( sprintf( "unknown_unhandled code %d: %s", $resp->code, $resp->body ), $resp);
        }
    })->retain;

    # Start our transaction
    $self->emit(request => $tx);
    $tx = $self->ua->start_p($tx)->then(sub($tx) {
        $r1->resolve( $tx );
        undef $r1;
    })->catch(sub($err) {
        $self->emit(response => $tx, $err);
        $r1->fail( $err => $tx );
        undef $r1;
    });

    return $res
}

=head2 C<< build_createBlob_request >>

Build an HTTP request as L<Mojo::Request> object. For the parameters see below.

lib/AI/Ollama/Client/Impl.pm  view on Meta::CPAN


    my $r1 = Future::Mojo->new();
    $r1->then( sub( $tx ) {
        my $resp = $tx->res;
        $self->emit(response => $resp);
        # Should we validate using OpenAPI::Modern here?!
        if( $resp->code == 201 ) {
            # Blob was successfully created
            $res->done($resp);
        } else {
            # An unknown/unhandled response, likely an error
            $res->fail( sprintf( "unknown_unhandled code %d: %s", $resp->code, $resp->body ), $resp);
        }
    })->retain;

    # Start our transaction
    $self->emit(request => $tx);
    $tx = $self->ua->start_p($tx)->then(sub($tx) {
        $r1->resolve( $tx );
        undef $r1;
    })->catch(sub($err) {
        $self->emit(response => $tx, $err);
        $r1->fail( $err => $tx );
        undef $r1;
    });

    return $res
}

=head2 C<< build_generateChatCompletion_request >>

Build an HTTP request as L<Mojo::Request> object. For the parameters see below.

lib/AI/Ollama/Client/Impl.pm  view on Meta::CPAN

                    };
                    if( $msg->{state} eq 'finished' ) {
                        $queue->finish();
                    }
                });
            } else {
                # Unknown/unhandled content type
                $res->fail( sprintf("unknown_unhandled content type '%s'", $resp->content_type), $resp );
            }
        } else {
            # An unknown/unhandled response, likely an error
            $res->fail( sprintf( "unknown_unhandled code %d", $resp->code ), $resp);
        }
    });

    my $_tx;
    $tx->res->once( progress => sub($msg, @) {
        $r1->resolve( $tx );
        undef $_tx;
        undef $r1;
    });

lib/AI/Ollama/Client/Impl.pm  view on Meta::CPAN


    my $r1 = Future::Mojo->new();
    $r1->then( sub( $tx ) {
        my $resp = $tx->res;
        $self->emit(response => $resp);
        # Should we validate using OpenAPI::Modern here?!
        if( $resp->code == 200 ) {
            # Successful operation.
            $res->done($resp);
        } else {
            # An unknown/unhandled response, likely an error
            $res->fail( sprintf( "unknown_unhandled code %d: %s", $resp->code, $resp->body ), $resp);
        }
    })->retain;

    # Start our transaction
    $self->emit(request => $tx);
    $tx = $self->ua->start_p($tx)->then(sub($tx) {
        $r1->resolve( $tx );
        undef $r1;
    })->catch(sub($err) {
        $self->emit(response => $tx, $err);
        $r1->fail( $err => $tx );
        undef $r1;
    });

    return $res
}

=head2 C<< build_createModel_request >>

Build an HTTP request as L<Mojo::Request> object. For the parameters see below.

lib/AI/Ollama/Client/Impl.pm  view on Meta::CPAN

                    };
                    if( $msg->{state} eq 'finished' ) {
                        $queue->finish();
                    }
                });
            } else {
                # Unknown/unhandled content type
                $res->fail( sprintf("unknown_unhandled content type '%s'", $resp->content_type), $resp );
            }
        } else {
            # An unknown/unhandled response, likely an error
            $res->fail( sprintf( "unknown_unhandled code %d", $resp->code ), $resp);
        }
    });

    my $_tx;
    $tx->res->once( progress => sub($msg, @) {
        $r1->resolve( $tx );
        undef $_tx;
        undef $r1;
    });

lib/AI/Ollama/Client/Impl.pm  view on Meta::CPAN


    my $r1 = Future::Mojo->new();
    $r1->then( sub( $tx ) {
        my $resp = $tx->res;
        $self->emit(response => $resp);
        # Should we validate using OpenAPI::Modern here?!
        if( $resp->code == 200 ) {
            # Successful operation.
            $res->done($resp);
        } else {
            # An unknown/unhandled response, likely an error
            $res->fail( sprintf( "unknown_unhandled code %d: %s", $resp->code, $resp->body ), $resp);
        }
    })->retain;

    # Start our transaction
    $self->emit(request => $tx);
    $tx = $self->ua->start_p($tx)->then(sub($tx) {
        $r1->resolve( $tx );
        undef $r1;
    })->catch(sub($err) {
        $self->emit(response => $tx, $err);
        $r1->fail( $err => $tx );
        undef $r1;
    });

    return $res
}

=head2 C<< build_generateEmbedding_request >>

Build an HTTP request as L<Mojo::Request> object. For the parameters see below.

lib/AI/Ollama/Client/Impl.pm  view on Meta::CPAN

                $self->validate_response( $payload, $tx );
                $res->done(
                    AI::Ollama::GenerateEmbeddingResponse->new($payload),

                );
            } else {
                # Unknown/unhandled content type
                $res->fail( sprintf("unknown_unhandled content type '%s'", $resp->content_type), $resp );
            }
        } else {
            # An unknown/unhandled response, likely an error
            $res->fail( sprintf( "unknown_unhandled code %d: %s", $resp->code, $resp->body ), $resp);
        }
    })->retain;

    # Start our transaction
    $self->emit(request => $tx);
    $tx = $self->ua->start_p($tx)->then(sub($tx) {
        $r1->resolve( $tx );
        undef $r1;
    })->catch(sub($err) {
        $self->emit(response => $tx, $err);
        $r1->fail( $err => $tx );
        undef $r1;
    });

    return $res
}

=head2 C<< build_generateCompletion_request >>

Build an HTTP request as L<Mojo::Request> object. For the parameters see below.

lib/AI/Ollama/Client/Impl.pm  view on Meta::CPAN

If C<true> no formatting will be applied to the prompt and no context will be returned.

You may choose to use the C<raw> parameter if you are specifying a full templated prompt in your request to the API, and are managing history yourself.

=item C<< stream >>

If C<false> the response will be returned as a single response object, otherwise the response will be streamed as a series of objects.

=item C<< system >>

The system prompt to (overrides what is defined in the Modelfile).

=item C<< template >>

The full prompt or prompt template (overrides what is defined in the Modelfile).

=back

Returns a L<< AI::Ollama::GenerateCompletionResponse >> on success.

=cut

sub build_generateCompletion_request( $self, %options ) {
    my $method = 'POST';
    my $path = '/generate';

lib/AI/Ollama/Client/Impl.pm  view on Meta::CPAN

                    };
                    if( $msg->{state} eq 'finished' ) {
                        $queue->finish();
                    }
                });
            } else {
                # Unknown/unhandled content type
                $res->fail( sprintf("unknown_unhandled content type '%s'", $resp->content_type), $resp );
            }
        } else {
            # An unknown/unhandled response, likely an error
            $res->fail( sprintf( "unknown_unhandled code %d", $resp->code ), $resp);
        }
    });

    my $_tx;
    $tx->res->once( progress => sub($msg, @) {
        $r1->resolve( $tx );
        undef $_tx;
        undef $r1;
    });

lib/AI/Ollama/Client/Impl.pm  view on Meta::CPAN

                    };
                    if( $msg->{state} eq 'finished' ) {
                        $queue->finish();
                    }
                });
            } else {
                # Unknown/unhandled content type
                $res->fail( sprintf("unknown_unhandled content type '%s'", $resp->content_type), $resp );
            }
        } else {
            # An unknown/unhandled response, likely an error
            $res->fail( sprintf( "unknown_unhandled code %d", $resp->code ), $resp);
        }
    });

    my $_tx;
    $tx->res->once( progress => sub($msg, @) {
        $r1->resolve( $tx );
        undef $_tx;
        undef $r1;
    });

lib/AI/Ollama/Client/Impl.pm  view on Meta::CPAN

                $self->validate_response( $payload, $tx );
                $res->done(
                    AI::Ollama::PushModelResponse->new($payload),

                );
            } else {
                # Unknown/unhandled content type
                $res->fail( sprintf("unknown_unhandled content type '%s'", $resp->content_type), $resp );
            }
        } else {
            # An unknown/unhandled response, likely an error
            $res->fail( sprintf( "unknown_unhandled code %d: %s", $resp->code, $resp->body ), $resp);
        }
    })->retain;

    # Start our transaction
    $self->emit(request => $tx);
    $tx = $self->ua->start_p($tx)->then(sub($tx) {
        $r1->resolve( $tx );
        undef $r1;
    })->catch(sub($err) {
        $self->emit(response => $tx, $err);
        $r1->fail( $err => $tx );
        undef $r1;
    });

    return $res
}

=head2 C<< build_showModelInfo_request >>

Build an HTTP request as L<Mojo::Request> object. For the parameters see below.

lib/AI/Ollama/Client/Impl.pm  view on Meta::CPAN

                $self->validate_response( $payload, $tx );
                $res->done(
                    AI::Ollama::ModelInfo->new($payload),

                );
            } else {
                # Unknown/unhandled content type
                $res->fail( sprintf("unknown_unhandled content type '%s'", $resp->content_type), $resp );
            }
        } else {
            # An unknown/unhandled response, likely an error
            $res->fail( sprintf( "unknown_unhandled code %d: %s", $resp->code, $resp->body ), $resp);
        }
    })->retain;

    # Start our transaction
    $self->emit(request => $tx);
    $tx = $self->ua->start_p($tx)->then(sub($tx) {
        $r1->resolve( $tx );
        undef $r1;
    })->catch(sub($err) {
        $self->emit(response => $tx, $err);
        $r1->fail( $err => $tx );
        undef $r1;
    });

    return $res
}

=head2 C<< build_listModels_request >>

Build an HTTP request as L<Mojo::Request> object. For the parameters see below.

lib/AI/Ollama/Client/Impl.pm  view on Meta::CPAN

                $self->validate_response( $payload, $tx );
                $res->done(
                    AI::Ollama::ModelsResponse->new($payload),

                );
            } else {
                # Unknown/unhandled content type
                $res->fail( sprintf("unknown_unhandled content type '%s'", $resp->content_type), $resp );
            }
        } else {
            # An unknown/unhandled response, likely an error
            $res->fail( sprintf( "unknown_unhandled code %d: %s", $resp->code, $resp->body ), $resp);
        }
    })->retain;

    # Start our transaction
    $self->emit(request => $tx);
    $tx = $self->ua->start_p($tx)->then(sub($tx) {
        $r1->resolve( $tx );
        undef $r1;
    })->catch(sub($err) {
        $self->emit(response => $tx, $err);
        $r1->fail( $err => $tx );
        undef $r1;
    });

    return $res
}


sub validate_response( $self, $payload, $tx ) {
    if(     $self->validate_responses
        and my $openapi = $self->openapi ) {
        my $results = $openapi->validate_response($payload, { request => $tx->req });
        if( $results->{error}) {
            say $results;
            say $tx->res->to_string;
        };
    };
}

sub validate_request( $self, $tx ) {
    if(        $self->validate_requests
        and my $openapi = $self->openapi ) {
        my $results = $openapi->validate_request($tx->req);
        if( $results->{error}) {
            say $results;
            say $tx->req->to_string;
        };
    };
}

1;

lib/AI/Ollama/GenerateCompletionRequest.pm  view on Meta::CPAN

If `false` the response will be returned as a single response object, otherwise the response will be streamed as a series of objects.

=cut

has 'stream' => (
    is       => 'ro',
);

=head2 C<< system >>

The system prompt to (overrides what is defined in the Modelfile).

=cut

has 'system' => (
    is       => 'ro',
    isa      => Str,
);

=head2 C<< template >>

The full prompt or prompt template (overrides what is defined in the Modelfile).

=cut

has 'template' => (
    is       => 'ro',
    isa      => Str,
);


1;

lib/AI/Ollama/PullModelResponse.pm  view on Meta::CPAN

=cut

sub as_hash( $self ) {
    return { $self->%* }
}

=head1 PROPERTIES

=head2 C<< completed >>

Total bytes transferred.

=cut

has 'completed' => (
    is       => 'ro',
    isa      => Int,
);

=head2 C<< digest >>

ollama/ollama-curated.json  view on Meta::CPAN

{"openapi":"3.0.3","components":{"schemas":{"PushModelResponse":{"properties":{"total":{"type":"integer","description":"total size of the model","example":"2142590208"},"status":{"$ref":"#/components/schemas/PushModelStatus"},"digest":{"example":"sha...

ollama/ollama-curated.yaml  view on Meta::CPAN

        images:
          type: array
          description: (optional) a list of Base64-encoded images to include in the message (for multimodal models such as llava)
          items:
            type: string
            contentEncoding: base64
            description: Base64-encoded image (for multimodal models such as llava)
            example: iVBORw0KGgoAAAANSUhEUgAAAAkAAAANCAIAAAD0YtNRAAAABnRSTlMA/AD+APzoM1ogAAAAWklEQVR4AWP48+8PLkR7uUdzcMvtU8EhdykHKAciEXL3pvw5FQIURaBDJkARoDhY3zEXiCgCHbNBmAlUiyaBkENoxZSDWnOtBmoAQu7TnT+3WuDOA7KBIkAGAGwiNeqjusp/AAAAAElFTkSuQmCC
        system:
          type: string
          description: The system prompt to (overrides what is defined in the Modelfile).
        template:
          type: string
          description: The full prompt or prompt template (overrides what is defined in the Modelfile).
        context:
          type: array
          description: The context parameter returned from a previous request to [generateCompletion], this can be used to keep a short conversational memory.
          items:
            type: integer
        options:
          $ref: '#/components/schemas/RequestOptions'
        format:
          $ref: '#/components/schemas/ResponseFormat'
        raw:

ollama/ollama-curated.yaml  view on Meta::CPAN

        digest:
          type: string
          description: The model's digest.
          example: 'sha256:bc07c81de745696fdf5afca05e065818a8149fb0c77266fb584d9b2cba3711a'
        total:
          type: integer
          description: Total size of the model.
          example: 2142590208
        completed:
          type: integer
          description: Total bytes transferred.
          example: 2142590208
    PullModelStatus:
      type: string
      description: Status pulling the model.
      enum:
        - pulling manifest
        - downloading digestname
        - verifying sha256 digest
        - writing manifest
        - removing any unused layers

openapi/petstore-expanded.yaml  view on Meta::CPAN

    url: https://www.apache.org/licenses/LICENSE-2.0.html
servers:
  - url: https://petstore.swagger.io/v2
paths:
  /pets:
    get:
      description: |
        Returns all pets from the system that the user has access to
        Nam sed condimentum est. Maecenas tempor sagittis sapien, nec rhoncus sem sagittis sit amet. Aenean at gravida augue, ac iaculis sem. Curabitur odio lorem, ornare eget elementum nec, cursus id lectus. Duis mi turpis, pulvinar ac eros ac, tinc...

        Sed tempus felis lobortis leo pulvinar rutrum. Nam mattis velit nisl, eu condimentum ligula luctus nec. Phasellus semper velit eget aliquet faucibus. In a mattis elit. Phasellus vel urna viverra, condimentum lorem id, rhoncus nibh. Ut pellent...
      operationId: findPets
      parameters:
        - name: tags
          in: query
          description: tags to filter by
          required: false
          style: form
          schema:
            type: array
            items:

openapi/petstore-expanded.yaml  view on Meta::CPAN

      responses:
        '200':
          description: pet response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Pet'
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    post:
      description: Creates a new pet in the store. Duplicates are allowed
      operationId: addPet
      requestBody:
        description: Pet to add to the store
        required: true

openapi/petstore-expanded.yaml  view on Meta::CPAN

            schema:
              $ref: '#/components/schemas/NewPet'
      responses:
        '200':
          description: pet response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pet'
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /pets/{id}:
    get:
      description: Returns a user based on a single ID, if the user does not have access to the pet
      operationId: find pet by id
      parameters:
        - name: id

openapi/petstore-expanded.yaml  view on Meta::CPAN

            type: integer
            format: int64
      responses:
        '200':
          description: pet response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Pet'
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    delete:
      description: deletes a single pet based on the ID supplied
      operationId: deletePet
      parameters:
        - name: id
          in: path
          description: ID of pet to delete
          required: true
          schema:
            type: integer
            format: int64
      responses:
        '204':
          description: pet deleted
        default:
          description: unexpected error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
components:
  schemas:
    Pet:
      allOf:
        - $ref: '#/components/schemas/NewPet'
        - type: object

scripts/describe-image.pl  view on Meta::CPAN


my $ol = AI::Ollama::Client->new(
    server => 'http://192.168.1.97:11434/api',
);

$ol->on('request' => sub( $ol, $tx ) {
    use Data::Dumper;
    warn Dumper $tx->req;
});

$ol->on('response' => sub( $ol, $tx, $err='' ) {
    if( $err ) {
        warn $err if $err;
    } else {
        #use Data::Dumper;
        warn $tx->code;
    }
});

my $tx = $ol->pullModel(
    name => 'llava:latest',
)->catch(sub {
    use Data::Dumper; warn Dumper \@_;

xt/99-compile.t  view on Meta::CPAN


require './Makefile.PL';
# Loaded from Makefile.PL
our %module = get_module_info();

my $last_version = undef;

sub check {
    #return if (! m{(\.pm|\.pl) \z}xmsi);

    my ($stdout, $stderr, $exit) = capture(sub {
        system( $^X, '-Mblib', '-c', $_ );
    });

    s!\s*\z!!
        for ($stdout, $stderr);

    if( $exit ) {
        diag $stderr;
        diag "Exit code: ", $exit;
        fail($_);
    } elsif( $stderr ne "$_ syntax OK") {
        diag $stderr;
        fail($_);
    } else {
        pass($_);
    };
}

my @files;
find({wanted => \&wanted, no_chdir => 1},
    grep { -d $_ }
         'blib/lib', 'examples', 'lib'

xt/99-test-prerequisites.t  view on Meta::CPAN

        require CPAN::Meta::Prereqs;
        require Parse::CPAN::Meta;
        require Perl::PrereqScanner::Lite;
        require Module::CoreList;
        require Test::Without::Module;
        require Capture::Tiny;
        Capture::Tiny->import('capture');
        require Path::Class;
        Path::Class->import('dir');
    };
    if (my $err = $@) {
        warn "# $err";
        plan skip_all => "Prerequisite needed for testing is missing";
        exit 0;
    };
};

my @tests;
if( @ARGV ) {
    @tests = @ARGV;
} else {
    open my $manifest, '<', 'MANIFEST'

xt/99-test-prerequisites.t  view on Meta::CPAN

    # If we have no apparent missing prerequisites, we're good
    my @missing = sort keys %missing;

    # Rerun the test without these modules and see whether it crashes
    my @failed;
    for my $candidate (@missing) {
        diag "Checking that $candidate is not essential";
        my @cmd = ($^X, "-MTest::Without::Module=$candidate", "-Mblib", '-w', $test_file);
        my $cmd = join " ", @cmd;

        my ($stdout, $stderr, $exit) = capture {
            system( @cmd );
        };
        if( $exit != 0 ) {
            push @failed, [ $candidate, [@cmd]];
        } elsif( $? != 0 ) {
            push @failed, [ $candidate, [@cmd]];
        };
    };
    is 0+@failed, 0, $test_file
        or diag Dumper \@failed;

xt/meta-lint.t  view on Meta::CPAN

require "$file.pm";

my $version = sprintf '%0.2f', $module->VERSION;

for my $meta_file ('META.yml', 'META.json') {
    my $meta = Parse::CPAN::Meta->load_file($meta_file);

    my $cmv = CPAN::Meta::Validator->new( $meta );

    if(! ok $cmv->is_valid, "$meta_file is valid" ) {
        diag $_ for $cmv->errors;
    };

    # Also check that the declared version matches the version in META.*
    is $meta->{version}, $version, "$meta_file version matches module version ($version)";
};



( run in 1.655 second using v1.01-cache-2.11-cpan-49f99fa48dc )