Processing POST request of an audio file

803 views Asked by At

What is the equivalent POST request using:

for this curl shell command:

curl --request POST \
  --url https://api.someservice.com/v1/ \
  --header 'Authorization: Bearer TOKEN' \
  --header 'Content-Type: multipart/form-data' \
  --form file=@/path/to/file/audio.mp3 \
  --form transformer=trans-2 \
  --form format=text

I tried following the examples in "Cro::HTTP::Client" without success...

(See the example starting with my $resp = await Cro::HTTP::Client.post: 'we.love.pand.as/pandas',)


Update

Here is a working example using the answer of @jja that requires to:

  • Have an OpenAI (account and) authorization key

  • Download one of the MP3 files from here

    • Or use another MP3 file with speech recording.
use HTTP::Tiny;


my $fileName = $*HOME ~ '/Downloads/HelloRaccoonsEN.mp3';


say .<content>.decode given HTTP::Tiny.post: 'https://api.openai.com/v1/audio/transcriptions',
        headers => { authorization => "Bearer {%*ENV<OPENAI_API_KEY>}" },
        content => {
            file        => $fileName.IO,
            model       => 'whisper-1',
            format      => 'text'
        };

Here is the expected result:

# {"text":"Raku practitioners around the world, eat more onions!"}
3

There are 3 answers

4
jja On BEST ANSWER

This is how that would look with HTTP::Tiny:

say .<content>.decode given HTTP::Tiny.post: 'https://httpbin.org/anything',
    headers => { authorization => 'Bearer TOKEN' },
    content => {
        file        => 'path/to/your/file'.IO,
        transformer => 'trans-2',
        format      => 'text'
    }

If you set the content to a hash it will default to use a multipart form encoding, and if any of the values supports a slurp method (in this case, the IO::Path you get by calling IO on your path) that will be used to get the value before sending.

And the output so you can inspect what was sent:

{
  "args": {}, 
  "data": "", 
  "files": {
    "file": "data:application/octet-stream;base64,...."
  }, 
  "form": {
    "format": "text", 
    "transformer": "trans-2"
  }, 
  "headers": {
    "Authorization": "Bearer TOKEN", 
    "Content-Length": "...", 
    "Content-Type": "multipart/form-data; boundary=\"VfaSnFoNawbxJQnMbtJr\"", 
    "Host": "httpbin.org", 
    "User-Agent": "HTTP::Tiny/0.2.5 Raku", 
    "X-Amzn-Trace-Id": "Root=1-deadbeef-deadbeefdeadbeefdeadbeef"
  }, 
  "json": null, 
  "method": "POST", 
  "origin": "123.45.67.89", 
  "url": "https://httpbin.org/anything"
}
5
jubilatious1 On

Using Raku's HTTP::Tinyish module

I've had very good luck downloading bioinformatic data from the European Bioinformatics Institute (EBI/Ensembl) using HTTP::Tinyish. Maybe the POST code below will work for you?

use HTTP::Tinyish;

my $http = HTTP::Tinyish.new(agent => "Mozilla/4.0");

my $server = 'https://rest.ensembl.org';
my $ext = '/archive/id';
my %response = $http.post: $server ~ $ext, 
  headers => { 
    'Content-type' => 'application/json',
    'Accept' => 'application/json'
  },
  content => '{ "id" : ["ENSG00000157764", "ENSG00000248378"] }';

die "Failed: " ~ %response<status> ~ "\n" ~ %response<content> ~ "\n" unless %response<success>; 


"\n1.________\n\n".put; #json output
use JSON::Fast <immutable>;
# .put for to-json(from-json(%response<content>));


"\n2.________\n\n".put; #below provides sorted output:
use PrettyDump;
for ( %response<content> ) {
  my $pretty = PrettyDump.new;
  put $pretty.dump: from-json(%response<content>);
};


"\n3.________\n\n".put; #below provides very compact `.raku` output:
# .say for from-json(%response<content>).raku;

Sample Output (version 2, PrettyDump only):

2.________


List=(
    Map=(
            :assembly("GRCh38"),
            :id("ENSG00000157764"),
            :is_current("1"),
            :latest("ENSG00000157764.14"),
            :peptide(Any),
            :possible_replacement(List=()),
            :release("109"),
            :type("Gene"),
            :version(14)
    ),
    Map=(
            :assembly("GRCh38"),
            :id("ENSG00000248378"),
            :is_current("1"),
            :latest("ENSG00000248378.1"),
            :peptide(Any),
            :possible_replacement(List=()),
            :release("109"),
            :type("Gene"),
            :version(1)
    )
)

Comment-out/un-comment the various returns (above), until you find one that suits your needs.

12
Jonathan Worthington On

It would have been helpful to know what you attempted in order to work out how to correct it. Anyway, I'd expect the example request to look something like this in Cro:

my $resp = await Cro::HTTP::Client.post: 'https://api.someservice.com/v1/',
    headers => [ Authorization => 'Bearer TOKEN' ],
    content-type => 'multipart/form-data',
    body => [
        transformer => 'trans-2',
        format => 'text',
        Cro::HTTP::Body::MultiPartFormData::Part.new(
            headers => [Cro::HTTP::Header.new(
                name => 'Content-type',
                value => 'audio/mpeg'
            )],
            name => 'file',
            filename => 'audio.mp3',
            body-blob => slurp('/path/to/file/audio.mp3', :bin)
        )
    ];

I'm not sure exactly what mime type curl goes with, so it may slightly differ from what curl does in that regard.