Sorry to ask what probably is a dumb question, but I’ve been struggling with this for awhile. I’ve even tried to get answers using GPT through the playground, but no luck.
I’ve tried formatting the form many ways (including just passing the form directly as an object instead of passing it as a string), but I just keep getting the same error:
Error: Object for request is wrong. Please confirm formData again.
This is the code. Can anyone tell me what I’m doing wrong? Thanks!
function varyImage() {
//define the endpoint for API call
var endpoint = “https://api.openai.com/v1/images/variations”;
var apiKey = “obscured”;
// get the image from GDrive and convert to a blob
var inputImage = DriveApp.getFileById(‘1YUNB1Jq6k5AQz1Hygqp_0dllhhFMGYV0’);
inputImage.setName = “input.png”;
var fileBlob = inputImage.getAs(“image/png”);
let num = 1;
let size = “512x512”;
try {
// build the form for the multipart/form-data content type
var fileBlobStr = fileBlob.getDataAsString(); // image must be a string
var form = FetchApp.createFormData();
form.append(“n”, num);
form.append(“size”, size);
form.append(“image”, fileBlobStr);
// headers
console.log("form "+JSON.stringify(form));
var myHeaders = {
“Content-Type”: “multipart/form-data”,
“Authorization”: "Bearer " + apiKey,
};
// parameters
var params = {
method: “POST”,
headers: myHeaders,
body: JSON.stringify(form),
}
// API call
var response = FetchApp.fetch(endpoint, params);
var responseJSON = JSON.parse(response);
Logger.log("Image URL: " + responseJSON.data[0][‘url’]);
}
catch (e) {
if (e.response) {
Logger.log(e.response.status);
Logger.log(e.response.data);
}
else {
Logger.log(e.message)
}
}
return;
}
I finally figured out what the problem is. It’s with the FetchApp library and how it converts data to forms. Got it working to create a variation with a single copy and 1024x1024 resolution, so I can figure it out from here… Sorry if anyone was looking at this.
I created my own form in Google Apps Script for the variations endpoint API call and have confirmed it works. It allows you to submit the Image file and the requested size of the resulting image. Though I didn’t include the number of images requested (as it’s optional and defaults to 1) someone could easily modify this to permit that. I successfully modified it for the image edits api.
** edit: I noticed that this input panel actually changes the format of the entry I made. It strips out backslashes which are used to escape the quotes in the form entries for the size and image parameter names in the getRequestBody function!
function varyImage() {
//define the endpoint for API call
var endpoint = “https://api.openai.com/v1/images/variations”;
var apiKey = “obscured”;
// get the image file from GDrive
var inputImage = DriveApp.getFileById(‘1YUNB1Jq6k5AQz1Hygqp_0dllhhFMGYV0’);
//boundary is an arbitrary unique string that’s needed to demarc parts of multipart form,
//and it’s also required when specifying the multipart/form-data content type for the api call
var boundary=“xxxxxxxxxx”
var size = “512x512”
try {
var requestBody = getRequestBody(boundary, inputImage, size);
var headers = {
“Content-Type”: “multipart/form-data; boundary=”+boundary,
“Authorization”: "Bearer " + apiKey,
};
// API call
var outputImage = UrlFetchApp.fetch(endpoint, {
//“muteHttpExceptions”: true,
“method”: “post”,
“headers”: headers,
“payload”: requestBody,
});
var outputImageJSON = JSON.parse(outputImage);
Logger.log("Image URL: " + outputImageJSON.data[0][‘url’]);
}
catch (e) {
if (e.outputImage) {
Logger.log(e.outputImage.status);
Logger.log(e.outputImage.data);
}
else {
Logger.log(e.message)
}
}
return;
}
function getRequestBody(boundary, file, size){
// function to create the RequestBody form
var data = “”;
data += “–” + boundary + “\r\n”;
// start form with first paramter
data += “Content-Disposition: form-data; name="size"; \r\n”;
data += “Content-Type:application/json\r\n\r\n”;
data += size + “\r\n”;
data += “–” + boundary + “\r\n”;
// append file
data += “Content-Disposition: form-data; name="image"; filename="” + file.getName() + “"\r\n”;
//data += “Content-Type:application/octet-stream\r\n\r\n”;
data += “Content-Type:”+file.getMimeType()+“\r\n\r\n”;
var payload = Utilities.newBlob(data).getBytes()
.concat(file.getBlob().getBytes())
.concat(Utilities.newBlob(“\r\n–” + boundary + “–”).getBytes());
return payload;
}