Bug in request function of http-client package
There is a bug with the request function of http-client when working with multipart/form-data in subroutine create_transcription.
The issue arises when there are no spaces before the "name" attribute in the form variable for the second and following pairs. Here's an example:
response = request(url=this%url, method=HTTP_POST , header=req_header, form=form_data, file=file_data)
And here's the problematic form definition:
form_data = [&
pair_type('model', trim(this%model)),&
pair_type(' language', trim(this%language)),&
pair_type(' response_format', trim(this%response_format)),&
pair_type(' prompt', trim(this%prompt)),&
pair_type(' temperature', trim(tempereture_str))&
]
Hello @gha3mi, I've tested the code with my own data, and it appears to be functioning correctly. Could you please specify if you are encountering any errors or receiving unexpected output? Additionally, sharing your code and the output you're experiencing would be helpful. I've personally tested this example, and it's functioning as expected.
program main
use http, only: response_type, request, HTTP_POST, pair_type
implicit none
type(response_type) :: response
type(pair_type), allocatable :: form_data(:), req_header(:)
type(pair_type) :: file_data
character(:), allocatable :: str1, str2, str3
! Storing form data in a array of pair_type object, each pair_type object
! represent a single form field
file_data = pair_type('file.txt', './data/file.txt')
str1 = ' value1 '
str2 = ' value2 '
str3 = ' value3 '
req_header = [pair_type('content-type', 'multipart/form-data')]
form_data = [pair_type('param1', trim(str1)), pair_type('param2', trim(str2)), pair_type('param3', trim(str3))]
response = request(url='https://httpbin.org/post', method=HTTP_POST, file=file_data, form=form_data, header=req_header)
if(.not. response%ok) then
print *,'Error message : ', response%err_msg
else
print *, 'Response Code : ', response%status_code
print *, 'Response Length : ', response%content_length
print *, 'Response Method : ', response%method
print *, 'Response Content : ', response%content
end if
end program main
Thanks, @rajkumardongre. I've tested your program, and it functions correctly.
However, in this case, it requires a space:
form_data = [&
pair_type('model', trim(this%model)),&
pair_type(' language', trim(this%language)),&
pair_type(' response_format', trim(this%response_format)),&
pair_type(' prompt', trim(this%prompt)),&
pair_type(' temperature', trim(tempereture_str))&
]
The test code can be found in test/test3.f90 and utilizes the create_transcription subroutine from the foropenai_Transcription module. create_transcription subroutine is available here: https://github.com/gha3mi/foropenai/blob/a80f469ff4588b13229f2f7f89a2a5fd388e1727/src/foropenai_Transcription.f90#L366C1-L418C84
The result of test3 is as follows: text: FORTRAN stands for Formula Translation.
Note: An OpenAI API key is required to use this program. If your account has credit, you can obtain an API key from this link and make sure to set it in the foropenai.json config file.
@rajkumardongre
This is the equivalent curl command that functions correctly:
curl https://api.openai.com/v1/audio/transcriptions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: multipart/form-data" \
-F file="@test/audio.mp3" \
-F model="whisper-1" \
-F language="en" \
-F response_format="json" \
-F prompt=""\
-F temperature="0.0"
When using http-client:
program test_transcription
use http, only: response_type, request, HTTP_POST, pair_type
type(pair_type), allocatable :: req_header(:), form_data(:), file_data
character(len=:), allocatable :: api_key
type(response_type) :: response
api_key = 'OPENAI_API_KEY'
req_header = [&
pair_type('Authorization', 'Bearer '//trim(api_key)),&
pair_type('Content-Type', 'multipart/form-data')&
]
! This format doesn't work:
form_data = [&
pair_type('model' , "whisper-1"),&
pair_type('language' , "en"),&
pair_type('response_format', "json"),&
pair_type('prompt' , ""),&
pair_type('temperature' , "0.0")&
]
! This format functions correctly:
! form_data = [&
! pair_type('model', 'whisper-1'),&
! pair_type(' language', 'en'),&
! pair_type(' response_format', 'json'),&
! pair_type(' prompt', ''),&
! pair_type(' temperature', '0.0')&
! ]
! This format functions correctly:
! form_data = [&
! pair_type('model', 'whisper-1'),&
! pair_type('Language', 'en'),& ! Language instead of language
! pair_type('response_format', 'json'),&
! pair_type('prompt', ''),&
! pair_type('Temperature', '0.0')& ! Temperature instead of temperature
! ]
file_data = pair_type('file', 'test/audio.mp3')
response = request(&
url = "https://api.openai.com/v1/audio/transcriptions",&
method = HTTP_POST,&
header = req_header,&
form = form_data,&
file = file_data)
print*, response%content
end program test_transcription
Edit: Updated test program.
@rajkumardongre, here's another issue with multipart/form-data when using the http-client, whereas the curl command functions correctly. Issue #33.