Skip to content
This repository was archived by the owner on Jun 6, 2024. It is now read-only.

Commit e68a098

Browse files
authored
Add image generation, editing, and variations (#63)
https://beta.openai.com/docs/api-reference/images
1 parent 3f8f02f commit e68a098

File tree

12 files changed

+333
-1
lines changed

12 files changed

+333
-1
lines changed

api/src/main/java/com/theokanning/openai/finetune/FineTuneResult.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import java.util.List;
77

88
/**
9-
* An object describing an fine-tuned model. Returned by multiple fine-tune requests.
9+
* An object describing a fine-tuned model. Returned by multiple fine-tune requests.
1010
*
1111
* https://beta.openai.com/docs/api-reference/fine-tunes
1212
*/
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.theokanning.openai.image;
2+
3+
import lombok.*;
4+
5+
/**
6+
* A request for OpenAi to edit an image based on a prompt
7+
* All fields except prompt are optional
8+
*
9+
* https://beta.openai.com/docs/api-reference/images/create-edit
10+
*/
11+
@Builder
12+
@NoArgsConstructor
13+
@AllArgsConstructor
14+
@Data
15+
public class CreateImageEditRequest {
16+
17+
/**
18+
* A text description of the desired image(s). The maximum length in 1000 characters.
19+
*/
20+
@NonNull
21+
String prompt;
22+
23+
/**
24+
* The number of images to generate. Must be between 1 and 10. Defaults to 1.
25+
*/
26+
Integer n;
27+
28+
/**
29+
* The size of the generated images. Must be one of "256x256", "512x512", or "1024x1024". Defaults to "1024x1024".
30+
*/
31+
String size;
32+
33+
/**
34+
* The format in which the generated images are returned. Must be one of url or b64_json. Defaults to url.
35+
*/
36+
String responseFormat;
37+
38+
/**
39+
* A unique identifier representing your end-user, which will help OpenAI to monitor and detect abuse.
40+
*/
41+
String user;
42+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.theokanning.openai.image;
2+
3+
import lombok.*;
4+
5+
/**
6+
* A request for OpenAi to create an image based on a prompt
7+
* All fields except prompt are optional
8+
*
9+
* https://beta.openai.com/docs/api-reference/images/create
10+
*/
11+
@Builder
12+
@NoArgsConstructor
13+
@AllArgsConstructor
14+
@Data
15+
public class CreateImageRequest {
16+
17+
/**
18+
* A text description of the desired image(s). The maximum length in 1000 characters.
19+
*/
20+
@NonNull
21+
String prompt;
22+
23+
/**
24+
* The number of images to generate. Must be between 1 and 10. Defaults to 1.
25+
*/
26+
Integer n;
27+
28+
/**
29+
* The size of the generated images. Must be one of "256x256", "512x512", or "1024x1024". Defaults to "1024x1024".
30+
*/
31+
String size;
32+
33+
/**
34+
* The format in which the generated images are returned. Must be one of url or b64_json. Defaults to url.
35+
*/
36+
String responseFormat;
37+
38+
/**
39+
* A unique identifier representing your end-user, which will help OpenAI to monitor and detect abuse.
40+
*/
41+
String user;
42+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.theokanning.openai.image;
2+
3+
import lombok.*;
4+
5+
/**
6+
* A request for OpenAi to create a variation of an image
7+
* All fields are optional
8+
*
9+
* https://beta.openai.com/docs/api-reference/images/create-variation
10+
*/
11+
@Builder
12+
@NoArgsConstructor
13+
@AllArgsConstructor
14+
@Data
15+
public class CreateImageVariationRequest {
16+
17+
/**
18+
* The number of images to generate. Must be between 1 and 10. Defaults to 1.
19+
*/
20+
Integer n;
21+
22+
/**
23+
* The size of the generated images. Must be one of "256x256", "512x512", or "1024x1024". Defaults to "1024x1024".
24+
*/
25+
String size;
26+
27+
/**
28+
* The format in which the generated images are returned. Must be one of url or b64_json. Defaults to url.
29+
*/
30+
String responseFormat;
31+
32+
/**
33+
* A unique identifier representing your end-user, which will help OpenAI to monitor and detect abuse.
34+
*/
35+
String user;
36+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.theokanning.openai.image;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import lombok.Data;
5+
6+
/**
7+
* An object containing either a URL or a base 64 encoded image.
8+
*
9+
* https://beta.openai.com/docs/api-reference/images
10+
*/
11+
@Data
12+
public class Image {
13+
/**
14+
* The URL where the image can be accessed.
15+
*/
16+
String url;
17+
18+
19+
/**
20+
* Base64 encoded image string.
21+
*/
22+
@JsonProperty("b64_json")
23+
String b64Json;
24+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.theokanning.openai.image;
2+
3+
import lombok.Data;
4+
5+
import java.util.List;
6+
7+
/**
8+
* An object with a list of image results.
9+
*
10+
* https://beta.openai.com/docs/api-reference/images
11+
*/
12+
@Data
13+
public class ImageResult {
14+
15+
/**
16+
* The creation time in epoch seconds.
17+
*/
18+
Long createdAt;
19+
20+
/**
21+
* List of image results.
22+
*/
23+
List<Image> data;
24+
}

client/src/main/java/com/theokanning/openai/OpenAiApi.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
import com.theokanning.openai.finetune.FineTuneEvent;
1212
import com.theokanning.openai.finetune.FineTuneRequest;
1313
import com.theokanning.openai.finetune.FineTuneResult;
14+
import com.theokanning.openai.image.CreateImageEditRequest;
15+
import com.theokanning.openai.image.CreateImageRequest;
16+
import com.theokanning.openai.image.ImageResult;
1417
import com.theokanning.openai.model.Model;
1518
import com.theokanning.openai.moderation.ModerationRequest;
1619
import com.theokanning.openai.moderation.ModerationResult;
@@ -82,6 +85,15 @@ public interface OpenAiApi {
8285
@DELETE("/v1/models/{fine_tune_id}")
8386
Single<DeleteResult> deleteFineTune(@Path("fine_tune_id") String fineTuneId);
8487

88+
@POST("/v1/images/generations")
89+
Single<ImageResult> createImage(@Body CreateImageRequest request);
90+
91+
@POST("/v1/images/edits")
92+
Single<ImageResult> createImageEdit(@Body RequestBody requestBody);
93+
94+
@POST("/v1/images/variations")
95+
Single<ImageResult> createImageVariation(@Body RequestBody requestBody);
96+
8597
@POST("/v1/moderations")
8698
Single<ModerationResult> createModeration(@Body ModerationRequest request);
8799

client/src/main/java/com/theokanning/openai/OpenAiService.java

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import com.theokanning.openai.finetune.FineTuneEvent;
1616
import com.theokanning.openai.finetune.FineTuneRequest;
1717
import com.theokanning.openai.finetune.FineTuneResult;
18+
import com.theokanning.openai.image.*;
1819
import com.theokanning.openai.model.Model;
1920
import com.theokanning.openai.moderation.ModerationRequest;
2021
import com.theokanning.openai.moderation.ModerationResult;
@@ -169,6 +170,62 @@ public DeleteResult deleteFineTune(String fineTuneId) {
169170
return api.deleteFineTune(fineTuneId).blockingGet();
170171
}
171172

173+
public ImageResult createImage(CreateImageRequest request) {
174+
return api.createImage(request).blockingGet();
175+
}
176+
177+
public ImageResult createImageEdit(CreateImageEditRequest request, String imagePath, String maskPath) {
178+
java.io.File image = new java.io.File(imagePath);
179+
java.io.File mask = null;
180+
if (maskPath != null) {
181+
mask = new java.io.File(maskPath);
182+
}
183+
return createImageEdit(request, image, mask);
184+
}
185+
186+
public ImageResult createImageEdit(CreateImageEditRequest request, java.io.File image, java.io.File mask) {
187+
RequestBody imageBody = RequestBody.create(MediaType.parse("image"), image);
188+
189+
MultipartBody.Builder builder = new MultipartBody.Builder()
190+
.setType(MediaType.get("multipart/form-data"))
191+
.addFormDataPart("prompt", request.getPrompt())
192+
.addFormDataPart("size", request.getSize())
193+
.addFormDataPart("response_format", request.getResponseFormat())
194+
.addFormDataPart("image", "image", imageBody);
195+
196+
if (request.getN() != null) {
197+
builder.addFormDataPart("n", request.getN().toString());
198+
}
199+
200+
if (mask != null) {
201+
RequestBody maskBody = RequestBody.create(MediaType.parse("image"), mask);
202+
builder.addFormDataPart("mask", "mask", maskBody);
203+
}
204+
205+
return api.createImageEdit(builder.build()).blockingGet();
206+
}
207+
208+
public ImageResult createImageVariation(CreateImageVariationRequest request, String imagePath) {
209+
java.io.File image = new java.io.File(imagePath);
210+
return createImageVariation(request, image);
211+
}
212+
213+
public ImageResult createImageVariation(CreateImageVariationRequest request, java.io.File image) {
214+
RequestBody imageBody = RequestBody.create(MediaType.parse("image"), image);
215+
216+
MultipartBody.Builder builder = new MultipartBody.Builder()
217+
.setType(MediaType.get("multipart/form-data"))
218+
.addFormDataPart("size", request.getSize())
219+
.addFormDataPart("response_format", request.getResponseFormat())
220+
.addFormDataPart("image", "image", imageBody);
221+
222+
if (request.getN() != null) {
223+
builder.addFormDataPart("n", request.getN().toString());
224+
}
225+
226+
return api.createImageVariation(builder.build()).blockingGet();
227+
}
228+
172229
public ModerationResult createModeration(ModerationRequest request) {
173230
return api.createModeration(request).blockingGet();
174231
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package com.theokanning.openai;
2+
3+
import com.theokanning.openai.image.CreateImageEditRequest;
4+
import com.theokanning.openai.image.CreateImageRequest;
5+
import com.theokanning.openai.image.CreateImageVariationRequest;
6+
import com.theokanning.openai.image.Image;
7+
import org.junit.jupiter.api.Test;
8+
9+
import java.util.List;
10+
11+
import static org.junit.jupiter.api.Assertions.assertEquals;
12+
import static org.junit.jupiter.api.Assertions.assertNotNull;
13+
14+
15+
public class ImageTest {
16+
17+
static String filePath = "src/test/resources/penguin.png";
18+
static String fileWithAlphaPath = "src/test/resources/penguin_with_alpha.png";
19+
static String maskPath = "src/test/resources/mask.png";
20+
21+
String token = System.getenv("OPENAI_TOKEN");
22+
OpenAiService service = new OpenAiService(token, 30);
23+
24+
25+
@Test
26+
void createImageUrl() {
27+
CreateImageRequest createImageRequest = CreateImageRequest.builder()
28+
.prompt("penguin")
29+
.n(3)
30+
.size("256x256")
31+
.user("testing")
32+
.build();
33+
34+
List<Image> images = service.createImage(createImageRequest).getData();
35+
assertEquals(3, images.size());
36+
assertNotNull(images.get(0).getUrl());
37+
}
38+
39+
@Test
40+
void createImageBase64() {
41+
CreateImageRequest createImageRequest = CreateImageRequest.builder()
42+
.prompt("penguin")
43+
.responseFormat("b64_json")
44+
.user("testing")
45+
.build();
46+
47+
List<Image> images = service.createImage(createImageRequest).getData();
48+
assertEquals(1, images.size());
49+
assertNotNull(images.get(0).getB64Json());
50+
}
51+
52+
@Test
53+
void createImageEdit() {
54+
CreateImageEditRequest createImageRequest = CreateImageEditRequest.builder()
55+
.prompt("a penguin with a red background")
56+
.responseFormat("url")
57+
.size("256x256")
58+
.user("testing")
59+
.n(2)
60+
.build();
61+
62+
List<Image> images = service.createImageEdit(createImageRequest, fileWithAlphaPath, null).getData();
63+
assertEquals(2, images.size());
64+
assertNotNull(images.get(0).getUrl());
65+
}
66+
67+
@Test
68+
void createImageEditWithMask() {
69+
CreateImageEditRequest createImageRequest = CreateImageEditRequest.builder()
70+
.prompt("a penguin with a red hat")
71+
.responseFormat("url")
72+
.size("256x256")
73+
.user("testing")
74+
.n(2)
75+
.build();
76+
77+
List<Image> images = service.createImageEdit(createImageRequest, filePath, maskPath).getData();
78+
assertEquals(2, images.size());
79+
assertNotNull(images.get(0).getUrl());
80+
}
81+
82+
@Test
83+
void createImageVariation() {
84+
CreateImageVariationRequest createImageVariationRequest = CreateImageVariationRequest.builder()
85+
.responseFormat("url")
86+
.size("256x256")
87+
.user("testing")
88+
.n(2)
89+
.build();
90+
91+
List<Image> images = service.createImageVariation(createImageVariationRequest, filePath).getData();
92+
assertEquals(2, images.size());
93+
assertNotNull(images.get(0).getUrl());
94+
}
95+
}

client/src/test/resources/mask.png

12.3 KB
Loading

0 commit comments

Comments
 (0)