Apps script issue with new image variation endpoint

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’m using apps script to call the new image variation endpoint. I’m not using node, curl or python and so there’s not a library I can rely on the form the api calls. Through trial and error I guessed that the expected content type is multipart/form-data (is that correct?) so because apps script does not directly support formatting the form, I am using the FetchApp library (GitHub - tanaikech/FetchApp: This is a GAS library for creating and requesting the type of multipart/form-data using Google Apps Script. This library enhances Class UelFetchApp of Google Apps Script.).

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.

1 Like

Thanks for coming back to let us know.

Hopefully this thread helps someone in the future.

1 Like

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;
}

2 Likes