Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit e68a098

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

File tree

Expand file treeCollapse file tree

12 files changed

+333
-1
lines changed
Filter options
Expand file treeCollapse file tree

12 files changed

+333
-1
lines changed

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

Copy file name to clipboardExpand all lines: api/src/main/java/com/theokanning/openai/finetune/FineTuneResult.java
+1-1Lines 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
*/
+42Lines 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+
}
+42Lines 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+
}
+36Lines 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+
}
+24Lines 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+
}
+24Lines 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

Copy file name to clipboardExpand all lines: client/src/main/java/com/theokanning/openai/OpenAiApi.java
+12Lines 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

Copy file name to clipboardExpand all lines: client/src/main/java/com/theokanning/openai/OpenAiService.java
+57Lines 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
}
+95Lines 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

Copy file name to clipboard
12.3 KB
Loading

‎client/src/test/resources/penguin.png

Copy file name to clipboard
65.8 KB
Loading
57.9 KB
Loading

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.