From 565123071251344d0f03eb059b4607c5c4c74adb Mon Sep 17 00:00:00 2001 From: Ryan Voots Date: Sun, 11 Feb 2024 13:36:20 -0500 Subject: [PATCH] Proper serialization happening now --- .vstags | 12 ++++----- lib/OpenAIAsync/Server.pm | 24 +++++++++++++---- lib/OpenAIAsync/Types/Requests.pm | 4 ++- lib/OpenAIAsync/Types/Results.pm | 43 ++++++++++++++++++++++++++++++- t/03-create-server.t | 6 +++-- 5 files changed, 74 insertions(+), 15 deletions(-) diff --git a/.vstags b/.vstags index 514950e..22c99c5 100644 --- a/.vstags +++ b/.vstags @@ -10617,7 +10617,7 @@ OpenAIAsync::Types::Requests::ChatCompletion::Messages::Union .build/so1aP3GqCj/ OpenAIAsync::Types::Requests::ChatCompletion::Messages::Union .build/so1aP3GqCj/lib/OpenAIAsync/Types/Requests.pm 211;" p OpenAIAsync::Types::Requests::ChatCompletion::Messages::Union .build/uNYKA_hGAv/blib/lib/OpenAIAsync/Types/Requests.pm 211;" p OpenAIAsync::Types::Requests::ChatCompletion::Messages::Union .build/uNYKA_hGAv/lib/OpenAIAsync/Types/Requests.pm 211;" p -OpenAIAsync::Types::Requests::ChatCompletion::Messages::Union lib/OpenAIAsync/Types/Requests.pm 211;" p +OpenAIAsync::Types::Requests::ChatCompletion::Messages::Union lib/OpenAIAsync/Types/Requests.pm 213;" p OpenAIAsync::Types::Requests::ChatCompletion::Messages::User::ContentUnion .build/3IqZsCXCBI/blib/lib/OpenAIAsync/Types/Requests.pm 129;" p OpenAIAsync::Types::Requests::ChatCompletion::Messages::User::ContentUnion .build/3IqZsCXCBI/lib/OpenAIAsync/Types/Requests.pm 129;" p OpenAIAsync::Types::Requests::ChatCompletion::Messages::User::ContentUnion .build/3XJnl1bWS2/blib/lib/OpenAIAsync/Types/Requests.pm 129;" p @@ -10666,7 +10666,7 @@ OpenAIAsync::Types::Requests::ChatCompletion::Messages::User::ContentUnion .buil OpenAIAsync::Types::Requests::ChatCompletion::Messages::User::ContentUnion .build/so1aP3GqCj/lib/OpenAIAsync/Types/Requests.pm 129;" p OpenAIAsync::Types::Requests::ChatCompletion::Messages::User::ContentUnion .build/uNYKA_hGAv/blib/lib/OpenAIAsync/Types/Requests.pm 129;" p OpenAIAsync::Types::Requests::ChatCompletion::Messages::User::ContentUnion .build/uNYKA_hGAv/lib/OpenAIAsync/Types/Requests.pm 129;" p -OpenAIAsync::Types::Requests::ChatCompletion::Messages::User::ContentUnion lib/OpenAIAsync/Types/Requests.pm 129;" p +OpenAIAsync::Types::Requests::ChatCompletion::Messages::User::ContentUnion lib/OpenAIAsync/Types/Requests.pm 131;" p OpenAIAsync::Types::Results .build/3IqZsCXCBI/blib/lib/OpenAIAsync/Types/Results.pm 1;" p OpenAIAsync::Types::Results .build/3IqZsCXCBI/lib/OpenAIAsync/Types/Results.pm 1;" p OpenAIAsync::Types::Results .build/3XJnl1bWS2/blib/lib/OpenAIAsync/Types/Results.pm 1;" p @@ -28901,8 +28901,8 @@ new .build/uNYKA_hGAv/blib/lib/OpenAIAsync/Types/Requests.pm 132;" s new .build/uNYKA_hGAv/blib/lib/OpenAIAsync/Types/Requests.pm 214;" s new .build/uNYKA_hGAv/lib/OpenAIAsync/Types/Requests.pm 132;" s new .build/uNYKA_hGAv/lib/OpenAIAsync/Types/Requests.pm 214;" s -new lib/OpenAIAsync/Types/Requests.pm 132;" s -new lib/OpenAIAsync/Types/Requests.pm 214;" s +new lib/OpenAIAsync/Types/Requests.pm 134;" s +new lib/OpenAIAsync/Types/Requests.pm 216;" s new local/bin/lwp-request 231;" s new local/lib/perl5/Algorithm/Diff.pm 580;" s new local/lib/perl5/App/Cmd.pm 163;" s @@ -29739,7 +29739,7 @@ ontent::new .build/so1aP3GqCj/blib/lib/OpenAIAsync/Types/Requests.pm 214;" s ontent::new .build/so1aP3GqCj/lib/OpenAIAsync/Types/Requests.pm 214;" s ontent::new .build/uNYKA_hGAv/blib/lib/OpenAIAsync/Types/Requests.pm 214;" s ontent::new .build/uNYKA_hGAv/lib/OpenAIAsync/Types/Requests.pm 214;" s -ontent::new lib/OpenAIAsync/Types/Requests.pm 214;" s +ontent::new lib/OpenAIAsync/Types/Requests.pm 216;" s oo local/lib/perl5/oo.pm 1;" p oo::import local/lib/perl5/oo.pm 22;" s oo::moo local/lib/perl5/oo.pm 7;" s @@ -32425,7 +32425,7 @@ y::new .build/so1aP3GqCj/blib/lib/OpenAIAsync/Types/Requests.pm 132;" s y::new .build/so1aP3GqCj/lib/OpenAIAsync/Types/Requests.pm 132;" s y::new .build/uNYKA_hGAv/blib/lib/OpenAIAsync/Types/Requests.pm 132;" s y::new .build/uNYKA_hGAv/lib/OpenAIAsync/Types/Requests.pm 132;" s -y::new lib/OpenAIAsync/Types/Requests.pm 132;" s +y::new lib/OpenAIAsync/Types/Requests.pm 134;" s y_n local/lib/perl5/Module/Build/Base.pm 602;" s year local/lib/perl5/Software/License.pm 57;" s year local/lib/perl5/x86_64-linux/DateTime.pm 767;" s diff --git a/lib/OpenAIAsync/Server.pm b/lib/OpenAIAsync/Server.pm index e6b35c2..224eb2b 100644 --- a/lib/OpenAIAsync/Server.pm +++ b/lib/OpenAIAsync/Server.pm @@ -221,6 +221,7 @@ class OpenAIAsync::Server :repr(HASH) :strict(params) { use Hash::Merge; use HTTP::Response; use HTTP::Request; + use Scalar::Util qw/blessed/; use OpenAIAsync::Types::Requests; use OpenAIAsync::Types::Results; @@ -272,10 +273,23 @@ class OpenAIAsync::Server :repr(HASH) :strict(params) { method _resp_custom($req, $code, $str, $json = 0) { my $response = HTTP::Response->new( $code ); - $response->content_type('text/plain') unless $json; # TODO this needs to be more flexible due to audio outputs - $response->content_type('application/json') if $json; - $response->add_content($str); - $response->content_length(length $str); + + if (blessed($str)) { + my $new_str = $str->_serialize(); + my $ct = $str->_content_type(); + + $response->content_type($ct); + + $response->add_content($new_str); + $response->content_length(length $new_str); + } else { + $response->content_type('text/plain') unless $json; # TODO this needs to be more flexible due to audio outputs + $response->content_type('application/json') if $json; + + $response->add_content($str); + $response->content_length(length $str); + } + $req->respond($response); } @@ -297,7 +311,7 @@ class OpenAIAsync::Server :repr(HASH) :strict(params) { my $found_route = false; my $f; for my $route ($routes->@*) { - printf " Checking %s %s\n", $route->{url}, $route->{method}; +# printf " Checking %s %s\n", $route->{url}, $route->{method}; if ($path =~ $route->{url} && $route->{method} eq $method) { my $params = +{%+, _ => [@+]}; # make a copy of named parameters, and digited ones to pass into the handler $found_route = true; diff --git a/lib/OpenAIAsync/Types/Requests.pm b/lib/OpenAIAsync/Types/Requests.pm index 7086b47..9fcb069 100644 --- a/lib/OpenAIAsync/Types/Requests.pm +++ b/lib/OpenAIAsync/Types/Requests.pm @@ -11,13 +11,15 @@ use OpenAIAsync::Types::Shared; role OpenAIAsync::Types::Requests::Base :Struct { apply OpenAIAsync::Types::Base; method _endpoint(); # How the client finds where to send the request - method decoder() {"json"}; + method decoder() {"json"} + method encoder() {"json"} } role OpenAIAsync::Types::Requests::BaseFormEncoding :Struct { apply OpenAIAsync::Types::BaseFormEncoding; method _endpoint(); # How the client finds where to send the request method decoder() {"www-form-urlencoded"} + method encoder() {"www-form-urlencoded"} } #### Base Request Types diff --git a/lib/OpenAIAsync/Types/Results.pm b/lib/OpenAIAsync/Types/Results.pm index 4b0e27e..4201d37 100644 --- a/lib/OpenAIAsync/Types/Results.pm +++ b/lib/OpenAIAsync/Types/Results.pm @@ -7,6 +7,47 @@ use Object::PadX::Role::AutoMarshal; use Object::PadX::Role::AutoJSON; use Object::Pad::ClassAttr::Struct; +role OpenAIAsync::Types::Results::Encoder::JSON { + apply OpenAIAsync::Types::Base; + apply Object::PadX::Role::AutoJSON; + apply Object::PadX::Role::AutoMarshal; + + use JSON::MaybeXS; + my $_json = JSON::MaybeXS->new(utf8 => 1, convert_blessed => 1, canonical => 1); + + method _serialize() { + my $json = $_json->encode($self); + + return $json; + } + + method _content_type() {"application/json"} +} + +role OpenAIAsync::Types::Results::Encoder::Raw { + apply OpenAIAsync::Types::Base; + apply Object::PadX::Role::AutoJSON; + apply Object::PadX::Role::AutoMarshal; + + use JSON::MaybeXS; + + method serialize() { + ... # TODO this needs to give out bytes, how to decide that? meta programming? + } +} + +role OpenAIAsync::Types::Results::Encoder::WWWForm { + apply OpenAIAsync::Types::Base; + apply Object::PadX::Role::AutoJSON; + apply Object::PadX::Role::AutoMarshal; + + use JSON::MaybeXS; + + method serialize() { + ... + } +} + class OpenAIAsync::Types::Results::ToolCall :Struct { apply OpenAIAsync::Types::Base; @@ -40,7 +81,7 @@ class OpenAIAsync::Types::Results::ChatCompletionChoices :Struct { } class OpenAIAsync::Types::Results::ChatCompletion :Struct { - apply OpenAIAsync::Types::Base; + apply OpenAIAsync::Types::Results::Encoder::JSON field $id :JSONStr; field $choices :MarshalTo([OpenAIAsync::Types::Results::ChatCompletionChoices]); diff --git a/t/03-create-server.t b/t/03-create-server.t index c9636f1..501955e 100644 --- a/t/03-create-server.t +++ b/t/03-create-server.t @@ -54,8 +54,10 @@ sub mk_req($uri, $content) { my $res = await mk_req("/chat/completions", $chat_completion_input); -use Data::Dumper; -print Dumper($res); +my $content = $res->content; +is($content, '{"choices":[],"created":"0","id":"24601","model":"GumbyBrain-llm","object":"text_completion","system_fingerprint":"SHODAN node 12 of 16 tertiary adjunct of unimatrix 42","usage":{"completion_tokens":9,"prompt_tokens":6,"total_tokens":42}}', "check marshalling of data directly"); #$loop->delay_future(after => 120)->get(); + + done_testing();