(PHP) File upload for fine tuning not working [Solved, with tutorial]

Ah. I got it.

Sorry, PHP is so messy compared to Python or Ruby just to do some simple API call, it’s easy to miss a detail like that.

Not sure why you needed to post a bunch of working completion code if you are trying to get file upload to work, It’s confusing to busy people trying to help you.

Especially since you did not format you code with indentation, etc before posting, so your code is not easy or enjoyable to read.

:slight_smile:

Here, @pezcri

This code works flawlessly. Maybe you can use it as a working framework to get your PHP code working?

module Files
    def self.get_client
        Ruby::OpenAI.configure do |config|
            config.access_token = ENV.fetch('OPENAI_API_KEY')
        end
        client = OpenAI::Client.new
    end


    def self.upload(filename="#{Rails.root}/app/assets/files/fine-tune.jsonl",purpose='fine-tune')
        client = get_client
        response =client.files.upload(
            parameters: {
                    file: filename,
                    purpose: purpose,
                })
        file_id = JSON.parse(response.body)["id"]
        file_id 
    end
end

Because people will always start asking the most silly questions like “did you turn on your computer first?” so to prevent that I showed that cURL is working just fine on my server, for example, thus avoiding all kind of questions that will not help on the matter.

I posted working perfectly good working Ruby code to help you.

You can use it as a model to get your PHP file uploading to work if you like.

Good luck

:slight_smile:

From what I can see the only different is that its showing the full path to the file, but I did try that, also not working, that is why I ran out of ideas and came here.

Yeah, I understand. I stopped using CURL “forever” ago and ended all development using PHP over 3 years ago after decades of PHP work. Life is too short …

Good luck with PHP. Sorry cannot help more and also for annoying you :slight_smile:

I agree with @PaulBellow, you @pezcri should move to a server where you can run Python, at least :+1:

Hi @pezcri , did you find a solution?
I am facing the same problem.

Actually I just got it right, seems like this was the problem.

$opts = array(‘purpose’ => ‘fine-tune’, ‘file’ => $c_file);
$post_fields = json_encode($opts);

There was no need to json_encode, so the correct was to just:

$post_fields = array(‘purpose’ => ‘fine-tune’, ‘file’ => $c_file);

1 Like

Thanks for coming back to let us know.

I should’ve spotted that in your original post. Apologies.

The error message probably could’ve been a little clearer probably.

Glad you got it sorted!

2 Likes

If I try using it without json_encode I am getting this error

{
    "error": {
        "message": "The browser (or proxy) sent a request that this server could not understand.",
        "type": "server_error",
        "param": null,
        "code": null
    }
}

The training data file is in the same directory the cURL is executed from

$headers  = [
	'Content-Type: multipart/form-data',
	'Authorization: Bearer '.$OPENAI_API_KEY
];

$c_file = "trainingdata.jsonl";
$opts = array('purpose' => 'fine-tune', 'file' => $c_file);

$ch = curl_init();
$curl_info = [
	CURLOPT_URL => "https://api.openai.com/v1/files",
	CURLOPT_RETURNTRANSFER => true,
	CURLOPT_ENCODING => '',
	CURLOPT_MAXREDIRS => 10,
	CURLOPT_TIMEOUT => 30,
	CURLOPT_FOLLOWLOCATION => true,
	CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
	CURLOPT_CUSTOMREQUEST => "POST",
	CURLOPT_POSTFIELDS => $opts,
	CURLOPT_HTTPHEADER => $headers,
];
curl_setopt_array($ch, $curl_info);
$result = curl_exec($ch);

Any idea what might be wrong?

1 Like

Finally, I have managed to do it like this

$headers = array();
$headers[] = "Content-Type: multipart/form-data";
$headers[] = "Authorization: Bearer sk...";

$cf = new CURLFile("trainingdata.jsonl");
$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, "https://api.openai.com/v1/files");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, ["purpose" => "fine-tune" ,"file" => $cf]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

$result = curl_exec($ch);
curl_close($ch);

I hope this helps someone!

3 Likes

:+1:

Excellent and thank you for sharing!

:+1:

2 Likes

Hello T_ray,

Sorry I forgot about the “new CURLFile” part, glad you solved it by yourself.

Anyway, since I did not find this anywhere, I will leave my full code here for: file uploading, retreving fine tune id, fine-tuning and making a completion with your trained model. Hope it helps the few id!ots like me who still need to use PHP for this:

Step 1: Uploading a fine-tune file (given that you already have a formated jsonl file):

$headers = array();
$headers[] = "Content-Type: multipart/form-data";
$headers[] = "Authorization: Bearer **YOUR_KEY**";

$c_file = new CurlFile("file.jsonl", 'application/json', "file.jsonl"); // file must be in the same directory
$post_fields = array('purpose' => 'fine-tune', 'file' => $c_file);

$ch = curl_init();

$curl_info = [ // some of this options are probably not needed
  CURLOPT_URL => "https://api.openai.com/v1/files",
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_ENCODING => '',
  CURLOPT_MAXREDIRS => 10,
  CURLOPT_TIMEOUT => 30,
  CURLOPT_FOLLOWLOCATION => true,
  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
  CURLOPT_CUSTOMREQUEST => "POST",
  CURLOPT_POSTFIELDS => $post_fields,
  CURLOPT_HTTPHEADER => $headers,
];

curl_setopt_array($ch, $curl_info);
$result = curl_exec($ch);
if (curl_errno($ch)) {
    echo 'Error:' . curl_error($ch);
}
curl_close($ch);

echo $result; // you will find the file id here, which should look like this: file-g4mXvDisehjEKLSNKiUSDnBQAy

Step 2: Fine-tune a model with that file

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, "https://api.openai.com/v1/fine-tunes");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
  "model": "davinci", 
  "training_file": "file-g4mXvDisehjEKLSNKiUSDnBQAy"
}');
curl_setopt($ch, CURLOPT_POST, 1);

$headers = array();
$headers[] = "Content-Type: application/json";
$headers[] = "Authorization: Bearer **YOUR_KEY**";
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

$result = curl_exec($ch);
if (curl_errno($ch)) {
    echo 'Error:' . curl_error($ch);
}
curl_close ($ch);

echo $result; // you will find the fine-tune id here, which should look like this: ft-OQeSiun18gzOSKE5sRVtYA7T

Next steps in the following reply…

Step 3: Retrieve the fine-tuned model id (you need to wait until it is uploaded, it could take up to 30 minutes, or maybe more?)

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, "https://api.openai.com/v1/fine-tunes/ft-OQeSiun18gzOSKE5sRVtYA7T");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, 0);

$headers = array();
$headers[] = "Content-Type: application/json";
$headers[] = "Authorization: Bearer **YOUR_KEY**";
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

$result = curl_exec($ch);
if (curl_errno($ch)) {
    echo 'Error:' . curl_error($ch);
}
curl_close ($ch);

echo $result; // you will find the model id here, which should look like this: davinci:ft-personal-2023-02-07-05-20-40

As I said, you need to wait until the fine-tune is uploaded, and you can find out by checking the [events] array in this request. There should be an event which gives you the uploaded model name. If you can’t find it that means you still need to wait. You can check the available events to check the progress.

Step 4: Make a completion with your fine-tuned model

$ch = curl_init();

curl_setopt($ch, CURLOPT_URL, "https://api.openai.com/v1/completions");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, '{
  "model": "davinci:ft-personal-2023-02-07-05-20-40", 
  "prompt": "**YOUR_PROMPT**",
  "max_tokens": 100,
  "temperature": 0,
  "top_p": 1,
  "frequency_penalty": 0,
  "presence_penalty": 0
}');
curl_setopt($ch, CURLOPT_POST, 1);

$headers = array();
$headers[] = "Content-Type: application/json";
$headers[] = "Authorization: Bearer **YOUR_KEY**";
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

$result = curl_exec($ch);
if (curl_errno($ch)) {
    echo 'Error:' . curl_error($ch);
}
curl_close ($ch);

echo $result;

Hope it helps.

3 Likes

Thanks, @pezcri
It is helpful indeed!

@pezcri Thanks for the great example code.

Wondering if you might have an example for a “Step 5” , where you add new data to the already existing, fine-tuned model from steps 1-4 ?

@yabdab
I did not try it, but I think according to the documentation all you have to do is repeat step 2 replacing the model with your trained model name.

So, you have to replace “model”: “davinci” with “model”: “davinci:ft-personal-2023-02-07-05-20-40” which is the model id you get from step 3.

3 Likes

Pezcri, thanks for this - great code!

Hi Pezcri,

I have some problem to upload my fine-tune file.
I’m trying your script but my fine-tune file must is in a different folder than the folder that contains the script.
I tried
$c_file = new CurlFile(“https://my_dominio/complete_path/file.json”, ‘application/json’, “file.jsonl”);
but it doesn’t work.
This is the return:
array(1) { [“error”]=> array(4) { [“message”]=> string(29) “‘file’ is a required property” [“type”]=> string(21) “invalid_request_error” [“param”]=> NULL [“code”]=> NULL } }
Could you help me?

Thank you so much.

Thank you so much for helping me!

Pretty sure the file can be whereever you want. I bet the CURLFile Object stores path and filename separately.