Add image generation, editing, and variations (#63)
https://beta.openai.com/docs/api-reference/images
This commit is contained in:
parent
3f8f02f104
commit
e68a098b87
|
@ -6,7 +6,7 @@ import lombok.Data;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An object describing an fine-tuned model. Returned by multiple fine-tune requests.
|
* An object describing a fine-tuned model. Returned by multiple fine-tune requests.
|
||||||
*
|
*
|
||||||
* https://beta.openai.com/docs/api-reference/fine-tunes
|
* https://beta.openai.com/docs/api-reference/fine-tunes
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
package com.theokanning.openai.image;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A request for OpenAi to edit an image based on a prompt
|
||||||
|
* All fields except prompt are optional
|
||||||
|
*
|
||||||
|
* https://beta.openai.com/docs/api-reference/images/create-edit
|
||||||
|
*/
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Data
|
||||||
|
public class CreateImageEditRequest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A text description of the desired image(s). The maximum length in 1000 characters.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
String prompt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of images to generate. Must be between 1 and 10. Defaults to 1.
|
||||||
|
*/
|
||||||
|
Integer n;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of the generated images. Must be one of "256x256", "512x512", or "1024x1024". Defaults to "1024x1024".
|
||||||
|
*/
|
||||||
|
String size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The format in which the generated images are returned. Must be one of url or b64_json. Defaults to url.
|
||||||
|
*/
|
||||||
|
String responseFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A unique identifier representing your end-user, which will help OpenAI to monitor and detect abuse.
|
||||||
|
*/
|
||||||
|
String user;
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
package com.theokanning.openai.image;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A request for OpenAi to create an image based on a prompt
|
||||||
|
* All fields except prompt are optional
|
||||||
|
*
|
||||||
|
* https://beta.openai.com/docs/api-reference/images/create
|
||||||
|
*/
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Data
|
||||||
|
public class CreateImageRequest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A text description of the desired image(s). The maximum length in 1000 characters.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
String prompt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of images to generate. Must be between 1 and 10. Defaults to 1.
|
||||||
|
*/
|
||||||
|
Integer n;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of the generated images. Must be one of "256x256", "512x512", or "1024x1024". Defaults to "1024x1024".
|
||||||
|
*/
|
||||||
|
String size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The format in which the generated images are returned. Must be one of url or b64_json. Defaults to url.
|
||||||
|
*/
|
||||||
|
String responseFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A unique identifier representing your end-user, which will help OpenAI to monitor and detect abuse.
|
||||||
|
*/
|
||||||
|
String user;
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package com.theokanning.openai.image;
|
||||||
|
|
||||||
|
import lombok.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A request for OpenAi to create a variation of an image
|
||||||
|
* All fields are optional
|
||||||
|
*
|
||||||
|
* https://beta.openai.com/docs/api-reference/images/create-variation
|
||||||
|
*/
|
||||||
|
@Builder
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Data
|
||||||
|
public class CreateImageVariationRequest {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of images to generate. Must be between 1 and 10. Defaults to 1.
|
||||||
|
*/
|
||||||
|
Integer n;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The size of the generated images. Must be one of "256x256", "512x512", or "1024x1024". Defaults to "1024x1024".
|
||||||
|
*/
|
||||||
|
String size;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The format in which the generated images are returned. Must be one of url or b64_json. Defaults to url.
|
||||||
|
*/
|
||||||
|
String responseFormat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A unique identifier representing your end-user, which will help OpenAI to monitor and detect abuse.
|
||||||
|
*/
|
||||||
|
String user;
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.theokanning.openai.image;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object containing either a URL or a base 64 encoded image.
|
||||||
|
*
|
||||||
|
* https://beta.openai.com/docs/api-reference/images
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class Image {
|
||||||
|
/**
|
||||||
|
* The URL where the image can be accessed.
|
||||||
|
*/
|
||||||
|
String url;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base64 encoded image string.
|
||||||
|
*/
|
||||||
|
@JsonProperty("b64_json")
|
||||||
|
String b64Json;
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package com.theokanning.openai.image;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An object with a list of image results.
|
||||||
|
*
|
||||||
|
* https://beta.openai.com/docs/api-reference/images
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class ImageResult {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The creation time in epoch seconds.
|
||||||
|
*/
|
||||||
|
Long createdAt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of image results.
|
||||||
|
*/
|
||||||
|
List<Image> data;
|
||||||
|
}
|
|
@ -11,6 +11,9 @@ import com.theokanning.openai.file.File;
|
||||||
import com.theokanning.openai.finetune.FineTuneEvent;
|
import com.theokanning.openai.finetune.FineTuneEvent;
|
||||||
import com.theokanning.openai.finetune.FineTuneRequest;
|
import com.theokanning.openai.finetune.FineTuneRequest;
|
||||||
import com.theokanning.openai.finetune.FineTuneResult;
|
import com.theokanning.openai.finetune.FineTuneResult;
|
||||||
|
import com.theokanning.openai.image.CreateImageEditRequest;
|
||||||
|
import com.theokanning.openai.image.CreateImageRequest;
|
||||||
|
import com.theokanning.openai.image.ImageResult;
|
||||||
import com.theokanning.openai.model.Model;
|
import com.theokanning.openai.model.Model;
|
||||||
import com.theokanning.openai.moderation.ModerationRequest;
|
import com.theokanning.openai.moderation.ModerationRequest;
|
||||||
import com.theokanning.openai.moderation.ModerationResult;
|
import com.theokanning.openai.moderation.ModerationResult;
|
||||||
|
@ -82,6 +85,15 @@ public interface OpenAiApi {
|
||||||
@DELETE("/v1/models/{fine_tune_id}")
|
@DELETE("/v1/models/{fine_tune_id}")
|
||||||
Single<DeleteResult> deleteFineTune(@Path("fine_tune_id") String fineTuneId);
|
Single<DeleteResult> deleteFineTune(@Path("fine_tune_id") String fineTuneId);
|
||||||
|
|
||||||
|
@POST("/v1/images/generations")
|
||||||
|
Single<ImageResult> createImage(@Body CreateImageRequest request);
|
||||||
|
|
||||||
|
@POST("/v1/images/edits")
|
||||||
|
Single<ImageResult> createImageEdit(@Body RequestBody requestBody);
|
||||||
|
|
||||||
|
@POST("/v1/images/variations")
|
||||||
|
Single<ImageResult> createImageVariation(@Body RequestBody requestBody);
|
||||||
|
|
||||||
@POST("/v1/moderations")
|
@POST("/v1/moderations")
|
||||||
Single<ModerationResult> createModeration(@Body ModerationRequest request);
|
Single<ModerationResult> createModeration(@Body ModerationRequest request);
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ import com.theokanning.openai.file.File;
|
||||||
import com.theokanning.openai.finetune.FineTuneEvent;
|
import com.theokanning.openai.finetune.FineTuneEvent;
|
||||||
import com.theokanning.openai.finetune.FineTuneRequest;
|
import com.theokanning.openai.finetune.FineTuneRequest;
|
||||||
import com.theokanning.openai.finetune.FineTuneResult;
|
import com.theokanning.openai.finetune.FineTuneResult;
|
||||||
|
import com.theokanning.openai.image.*;
|
||||||
import com.theokanning.openai.model.Model;
|
import com.theokanning.openai.model.Model;
|
||||||
import com.theokanning.openai.moderation.ModerationRequest;
|
import com.theokanning.openai.moderation.ModerationRequest;
|
||||||
import com.theokanning.openai.moderation.ModerationResult;
|
import com.theokanning.openai.moderation.ModerationResult;
|
||||||
|
@ -169,6 +170,62 @@ public class OpenAiService {
|
||||||
return api.deleteFineTune(fineTuneId).blockingGet();
|
return api.deleteFineTune(fineTuneId).blockingGet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ImageResult createImage(CreateImageRequest request) {
|
||||||
|
return api.createImage(request).blockingGet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageResult createImageEdit(CreateImageEditRequest request, String imagePath, String maskPath) {
|
||||||
|
java.io.File image = new java.io.File(imagePath);
|
||||||
|
java.io.File mask = null;
|
||||||
|
if (maskPath != null) {
|
||||||
|
mask = new java.io.File(maskPath);
|
||||||
|
}
|
||||||
|
return createImageEdit(request, image, mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageResult createImageEdit(CreateImageEditRequest request, java.io.File image, java.io.File mask) {
|
||||||
|
RequestBody imageBody = RequestBody.create(MediaType.parse("image"), image);
|
||||||
|
|
||||||
|
MultipartBody.Builder builder = new MultipartBody.Builder()
|
||||||
|
.setType(MediaType.get("multipart/form-data"))
|
||||||
|
.addFormDataPart("prompt", request.getPrompt())
|
||||||
|
.addFormDataPart("size", request.getSize())
|
||||||
|
.addFormDataPart("response_format", request.getResponseFormat())
|
||||||
|
.addFormDataPart("image", "image", imageBody);
|
||||||
|
|
||||||
|
if (request.getN() != null) {
|
||||||
|
builder.addFormDataPart("n", request.getN().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mask != null) {
|
||||||
|
RequestBody maskBody = RequestBody.create(MediaType.parse("image"), mask);
|
||||||
|
builder.addFormDataPart("mask", "mask", maskBody);
|
||||||
|
}
|
||||||
|
|
||||||
|
return api.createImageEdit(builder.build()).blockingGet();
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageResult createImageVariation(CreateImageVariationRequest request, String imagePath) {
|
||||||
|
java.io.File image = new java.io.File(imagePath);
|
||||||
|
return createImageVariation(request, image);
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageResult createImageVariation(CreateImageVariationRequest request, java.io.File image) {
|
||||||
|
RequestBody imageBody = RequestBody.create(MediaType.parse("image"), image);
|
||||||
|
|
||||||
|
MultipartBody.Builder builder = new MultipartBody.Builder()
|
||||||
|
.setType(MediaType.get("multipart/form-data"))
|
||||||
|
.addFormDataPart("size", request.getSize())
|
||||||
|
.addFormDataPart("response_format", request.getResponseFormat())
|
||||||
|
.addFormDataPart("image", "image", imageBody);
|
||||||
|
|
||||||
|
if (request.getN() != null) {
|
||||||
|
builder.addFormDataPart("n", request.getN().toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return api.createImageVariation(builder.build()).blockingGet();
|
||||||
|
}
|
||||||
|
|
||||||
public ModerationResult createModeration(ModerationRequest request) {
|
public ModerationResult createModeration(ModerationRequest request) {
|
||||||
return api.createModeration(request).blockingGet();
|
return api.createModeration(request).blockingGet();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
package com.theokanning.openai;
|
||||||
|
|
||||||
|
import com.theokanning.openai.image.CreateImageEditRequest;
|
||||||
|
import com.theokanning.openai.image.CreateImageRequest;
|
||||||
|
import com.theokanning.openai.image.CreateImageVariationRequest;
|
||||||
|
import com.theokanning.openai.image.Image;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
|
||||||
|
|
||||||
|
public class ImageTest {
|
||||||
|
|
||||||
|
static String filePath = "src/test/resources/penguin.png";
|
||||||
|
static String fileWithAlphaPath = "src/test/resources/penguin_with_alpha.png";
|
||||||
|
static String maskPath = "src/test/resources/mask.png";
|
||||||
|
|
||||||
|
String token = System.getenv("OPENAI_TOKEN");
|
||||||
|
OpenAiService service = new OpenAiService(token, 30);
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createImageUrl() {
|
||||||
|
CreateImageRequest createImageRequest = CreateImageRequest.builder()
|
||||||
|
.prompt("penguin")
|
||||||
|
.n(3)
|
||||||
|
.size("256x256")
|
||||||
|
.user("testing")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
List<Image> images = service.createImage(createImageRequest).getData();
|
||||||
|
assertEquals(3, images.size());
|
||||||
|
assertNotNull(images.get(0).getUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createImageBase64() {
|
||||||
|
CreateImageRequest createImageRequest = CreateImageRequest.builder()
|
||||||
|
.prompt("penguin")
|
||||||
|
.responseFormat("b64_json")
|
||||||
|
.user("testing")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
List<Image> images = service.createImage(createImageRequest).getData();
|
||||||
|
assertEquals(1, images.size());
|
||||||
|
assertNotNull(images.get(0).getB64Json());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createImageEdit() {
|
||||||
|
CreateImageEditRequest createImageRequest = CreateImageEditRequest.builder()
|
||||||
|
.prompt("a penguin with a red background")
|
||||||
|
.responseFormat("url")
|
||||||
|
.size("256x256")
|
||||||
|
.user("testing")
|
||||||
|
.n(2)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
List<Image> images = service.createImageEdit(createImageRequest, fileWithAlphaPath, null).getData();
|
||||||
|
assertEquals(2, images.size());
|
||||||
|
assertNotNull(images.get(0).getUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createImageEditWithMask() {
|
||||||
|
CreateImageEditRequest createImageRequest = CreateImageEditRequest.builder()
|
||||||
|
.prompt("a penguin with a red hat")
|
||||||
|
.responseFormat("url")
|
||||||
|
.size("256x256")
|
||||||
|
.user("testing")
|
||||||
|
.n(2)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
List<Image> images = service.createImageEdit(createImageRequest, filePath, maskPath).getData();
|
||||||
|
assertEquals(2, images.size());
|
||||||
|
assertNotNull(images.get(0).getUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createImageVariation() {
|
||||||
|
CreateImageVariationRequest createImageVariationRequest = CreateImageVariationRequest.builder()
|
||||||
|
.responseFormat("url")
|
||||||
|
.size("256x256")
|
||||||
|
.user("testing")
|
||||||
|
.n(2)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
List<Image> images = service.createImageVariation(createImageVariationRequest, filePath).getData();
|
||||||
|
assertEquals(2, images.size());
|
||||||
|
assertNotNull(images.get(0).getUrl());
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
Binary file not shown.
After Width: | Height: | Size: 66 KiB |
Binary file not shown.
After Width: | Height: | Size: 58 KiB |
Loading…
Reference in New Issue