From ccafe0deae57db51d62fe532977864b8247b3122 Mon Sep 17 00:00:00 2001 From: Ryan Voots Date: Mon, 1 Jan 2024 10:56:45 -0500 Subject: [PATCH] More image work here --- .vstags | 2 +- lib/OpenAIAsync/Server/API/v1/Audio.pm | 2 +- lib/OpenAIAsync/Server/API/v1/Image.pm | 41 ++++++++++++++++++++++++++ lib/OpenAIAsync/Types/Requests.pm | 39 +++++++++++++++++++++++- lib/OpenAIAsync/Types/Results.pm | 12 +++++++- 5 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 lib/OpenAIAsync/Server/API/v1/Image.pm diff --git a/.vstags b/.vstags index 5ca06d5..d8b7b50 100644 --- a/.vstags +++ b/.vstags @@ -9862,7 +9862,6 @@ OpenAIAsync::Server .build/S3aTKnbkmA/lib/OpenAIAsync/Server.pm 1;" p OpenAIAsync::Server .build/kBWSNkpY90/blib/lib/OpenAIAsync/Server.pm 1;" p OpenAIAsync::Server .build/kBWSNkpY90/lib/OpenAIAsync/Server.pm 1;" p OpenAIAsync::Server lib/OpenAIAsync/Server.pm 1;" p -OpenAIAsync::Server::API::v1::Audio lib/OpenAIAsync/Server/API/v1/Audio.pm 1;" p OpenAIAsync::Server::API::v1::ChatCompletion .build/S3aTKnbkmA/blib/lib/OpenAIAsync/Server/API/v1/ChatCompletion.pm 1;" p OpenAIAsync::Server::API::v1::ChatCompletion .build/S3aTKnbkmA/lib/OpenAIAsync/Server/API/v1/ChatCompletion.pm 1;" p OpenAIAsync::Server::API::v1::ChatCompletion .build/kBWSNkpY90/blib/lib/OpenAIAsync/Server/API/v1/ChatCompletion.pm 1;" p @@ -9883,6 +9882,7 @@ OpenAIAsync::Server::API::v1::File .build/S3aTKnbkmA/lib/OpenAIAsync/Server/API/ OpenAIAsync::Server::API::v1::File .build/kBWSNkpY90/blib/lib/OpenAIAsync/Server/API/v1/File.pm 1;" p OpenAIAsync::Server::API::v1::File .build/kBWSNkpY90/lib/OpenAIAsync/Server/API/v1/File.pm 1;" p OpenAIAsync::Server::API::v1::File lib/OpenAIAsync/Server/API/v1/File.pm 1;" p +OpenAIAsync::Server::API::v1::Image lib/OpenAIAsync/Server/API/v1/Image.pm 1;" p OpenAIAsync::Server::API::v1::ModelList .build/S3aTKnbkmA/blib/lib/OpenAIAsync/Server/API/v1/ModelList.pm 1;" p OpenAIAsync::Server::API::v1::ModelList .build/S3aTKnbkmA/lib/OpenAIAsync/Server/API/v1/ModelList.pm 1;" p OpenAIAsync::Server::API::v1::ModelList .build/kBWSNkpY90/blib/lib/OpenAIAsync/Server/API/v1/ModelList.pm 1;" p diff --git a/lib/OpenAIAsync/Server/API/v1/Audio.pm b/lib/OpenAIAsync/Server/API/v1/Audio.pm index 1780115..7650a9a 100644 --- a/lib/OpenAIAsync/Server/API/v1/Audio.pm +++ b/lib/OpenAIAsync/Server/API/v1/Audio.pm @@ -1,4 +1,4 @@ -package OpenAIAsync::Server::API::v1::Audio; +cpackage OpenAIAsync::Server::API::v1::Audio; use v5.36.0; use Object::Pad; diff --git a/lib/OpenAIAsync/Server/API/v1/Image.pm b/lib/OpenAIAsync/Server/API/v1/Image.pm new file mode 100644 index 0000000..9d72b40 --- /dev/null +++ b/lib/OpenAIAsync/Server/API/v1/Image.pm @@ -0,0 +1,41 @@ +package OpenAIAsync::Server::API::v1::Image; + +use v5.36.0; +use Object::Pad; +use IO::Async::SSL; # We're not directly using it but I want to enforce that we pull it in when detecting dependencies, since openai itself is always https +use Future::AsyncAwait; +use IO::Async; + +use OpenAIAsync::Types::Results; +use OpenAIAsync::Types::Requests; + +our $VERSION = '0.02'; + +# ABSTRACT: Async server for OpenAI style REST API for various AI systems (LLMs, Images, Video, etc.) + +=pod + +=head1 NAME + +OpenAIAsync::Server::API::Image - Basic image role, consumed to implement the OpenAI image api. Does not provide an implementation, you are expected to override them in your class + +=head1 SYNOPSIS + +... + +=cut + +role OpenAIAsync::Server::API::v1::Image :strict(params) { + ADJUST { + $self->register_url( + method => 'GET', + url => qr{^/v1/files$}, + handle => async sub($req, $ctx, $obj, $params) {await $self->create_image($obj, $req, $ctx)}, + request_class => "OpenAIAsync::Type::Requests::", + result_class => "OpenAIAsync::Type::Results::FileList", + decoder => 'optional_json', # this API input is OPTIONAL, if it's not present then we create a blank object to use. + ); + } + + async method create_image($http_req, $ctx) {...} +} \ No newline at end of file diff --git a/lib/OpenAIAsync/Types/Requests.pm b/lib/OpenAIAsync/Types/Requests.pm index 2d85448..b423318 100644 --- a/lib/OpenAIAsync/Types/Requests.pm +++ b/lib/OpenAIAsync/Types/Requests.pm @@ -284,4 +284,41 @@ class OpenAIAsync::Types::Requests::Moderations :does(OpenAIAsync::Types::Reques field $model :JSONStr = undef; } -1; \ No newline at end of file +class OpenAIAsync::Types::Requests::GenerateImage :does(OpenAIAsync::Types::Requests::Base) :Struct { + method _endpoint() {"/images/generations"} + + field $prompt :JSONStr; + field $model :JSONStr = undef; + field $n :JSONNum = undef; # how many to generate + field $quality :JSONStr = undef; # defaults to "standard", can also be "hd" + field $response_format :JSONStr = undef; # url, or b64_json + field $size :JSONStr = undef; # defaults to 1024x1024 + field $style :JSONStr = undef; # vivid or natural, defaults to vivid + field $user :JSONStr = undef; +} + +class OpenAIAsync::Types::Requests::CreateImageEdit :does(OpenAIAsync::Types::Requests::BaseFormEncoding) :Struct { + method _endpoint() {"/images/edits"} + + field $image; # Image file data, TODO document? + field $mask = undef; # Image file data for mask, TODO document + field $prompt :JSONStr; + field $model :JSONStr = undef; + field $n :JSONNum = undef; # how many to generate + field $response_format :JSONStr = undef; # url, or b64_json + field $size :JSONStr = undef; # defaults to 1024x1024 + field $user :JSONStr = undef; +} + +class OpenAIAsync::Types::Requests::CreateImageVariation :does(OpenAIAsync::Types::Requests::BaseFormEncoding) :Struct { + method _endpoint() {"/images/variations"} + + field $image; # Image file data, TODO document? + field $model :JSONStr = undef; + field $n :JSONNum = undef; # how many to generate + field $response_format :JSONStr = undef; # url, or b64_json + field $size :JSONStr = undef; # defaults to 1024x1024 + field $user :JSONStr = undef; +} + +1; \ No newline at end of file diff --git a/lib/OpenAIAsync/Types/Results.pm b/lib/OpenAIAsync/Types/Results.pm index 39cb008..3603b87 100644 --- a/lib/OpenAIAsync/Types/Results.pm +++ b/lib/OpenAIAsync/Types/Results.pm @@ -159,4 +159,14 @@ class OpenAIAsync::Types::Results::ModerationResultsCategoryScores :does(OpenAIA field $sexual_minors :JSONNum :JSONKey(sexual/minors); field $violence :JSONNum; field $violence_graphic :JSONNum :JSONKey(violence/graphic); -} \ No newline at end of file +} + +class OpenAIAsync::Types::Results::Image :does(OpenAIAsync::Types::Base) :Struct { + field $b64_json :JSONStr = undef; + field $url :JSONStr = undef; + field $revised_prompt :JSONStr = undef; + + ADJUST { + die "Missing required value one of b64_json or url" unless ($b64_json or $url); + } +}