Skip to content

Commit 79a929a

Browse files
committed
Support edit images
1 parent 01d91b2 commit 79a929a

File tree

8 files changed

+90
-1
lines changed

8 files changed

+90
-1
lines changed

src/main/java/org/devlive/sdk/openai/DefaultApi.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package org.devlive.sdk.openai;
22

33
import io.reactivex.Single;
4+
import okhttp3.MultipartBody;
5+
import okhttp3.RequestBody;
46
import org.devlive.sdk.openai.entity.CompletionChatEntity;
57
import org.devlive.sdk.openai.entity.CompletionEntity;
68
import org.devlive.sdk.openai.entity.ImageEntity;
@@ -13,10 +15,15 @@
1315
import org.devlive.sdk.openai.response.UserKeyResponse;
1416
import retrofit2.http.Body;
1517
import retrofit2.http.GET;
18+
import retrofit2.http.Multipart;
1619
import retrofit2.http.POST;
20+
import retrofit2.http.Part;
21+
import retrofit2.http.PartMap;
1722
import retrofit2.http.Path;
1823
import retrofit2.http.Url;
1924

25+
import java.util.Map;
26+
2027
public interface DefaultApi
2128
{
2229
/**
@@ -64,4 +71,14 @@ Single<CompleteChatResponse> fetchChatCompletions(@Url String url,
6471
*/
6572
@POST
6673
Single<ImageResponse> fetchImagesGenerations(@Url String url, @Body ImageEntity configure);
74+
75+
/**
76+
* Creates an edited or extended image given an original image and a prompt.
77+
*/
78+
@POST
79+
@Multipart
80+
Single<ImageResponse> fetchImagesEdits(@Url String url,
81+
@Part() MultipartBody.Part image,
82+
@Part() MultipartBody.Part mask,
83+
@PartMap Map<String, RequestBody> configure);
6784
}

src/main/java/org/devlive/sdk/openai/DefaultClient.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
package org.devlive.sdk.openai;
22

3+
import com.google.common.collect.Maps;
34
import lombok.extern.slf4j.Slf4j;
5+
import okhttp3.MultipartBody;
46
import okhttp3.OkHttpClient;
7+
import okhttp3.RequestBody;
58
import org.apache.commons.lang3.ObjectUtils;
9+
import org.apache.commons.lang3.StringUtils;
610
import org.devlive.sdk.openai.entity.CompletionChatEntity;
711
import org.devlive.sdk.openai.entity.CompletionEntity;
812
import org.devlive.sdk.openai.entity.ImageEntity;
@@ -15,8 +19,12 @@
1519
import org.devlive.sdk.openai.response.ImageResponse;
1620
import org.devlive.sdk.openai.response.ModelResponse;
1721
import org.devlive.sdk.openai.response.UserKeyResponse;
22+
import org.devlive.sdk.openai.utils.MultipartBodyUtils;
1823
import org.devlive.sdk.openai.utils.ProviderUtils;
1924

25+
import java.io.File;
26+
import java.util.Map;
27+
2028
@Slf4j
2129
public abstract class DefaultClient implements AutoCloseable
2230
{
@@ -66,6 +74,30 @@ public ImageResponse createImages(ImageEntity configure)
6674
.blockingGet();
6775
}
6876

77+
public ImageResponse editImages(File image, File mask, ImageEntity configure)
78+
{
79+
MultipartBody.Part imageBody = MultipartBodyUtils.getPart(image, "image");
80+
MultipartBody.Part maskBody = null;
81+
if (ObjectUtils.isNotEmpty(mask)) {
82+
maskBody = MultipartBodyUtils.getPart(mask, "mask");
83+
}
84+
85+
Map<String, RequestBody> map = Maps.newConcurrentMap();
86+
map.put("prompt", RequestBody.create(MultipartBodyUtils.TYPE, configure.getPrompt()));
87+
map.put("n", RequestBody.create(MultipartBodyUtils.TYPE, configure.getCount().toString()));
88+
map.put("size", RequestBody.create(MultipartBodyUtils.TYPE, configure.getSize()));
89+
map.put("response_format", RequestBody.create(MultipartBodyUtils.TYPE, configure.getFormat()));
90+
if (StringUtils.isNotEmpty(configure.getUser())) {
91+
map.put("user", RequestBody.create(MultipartBodyUtils.TYPE, configure.getUser()));
92+
}
93+
94+
return this.api.fetchImagesEdits(ProviderUtils.getUrl(provider, UrlModel.FETCH_EDITS_GENERATIONS),
95+
imageBody,
96+
maskBody,
97+
map)
98+
.blockingGet();
99+
}
100+
69101
public void close()
70102
{
71103
if (ObjectUtils.isNotEmpty(this.client)) {

src/main/java/org/devlive/sdk/openai/model/UrlModel.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ public enum UrlModel
88
FETCH_CHAT_COMPLETIONS,
99
FETCH_USER_API_KEYS,
1010
FETCH_CREATE_USER_API_KEY,
11-
FETCH_IMAGES_GENERATIONS
11+
FETCH_IMAGES_GENERATIONS,
12+
FETCH_EDITS_GENERATIONS
1213
}

src/main/java/org/devlive/sdk/openai/response/ImageResponse.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.devlive.sdk.openai.response;
22

3+
import com.fasterxml.jackson.annotation.JsonFormat;
34
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
45
import com.fasterxml.jackson.annotation.JsonProperty;
56
import lombok.Data;
@@ -11,6 +12,10 @@
1112
@JsonIgnoreProperties(ignoreUnknown = true)
1213
public class ImageResponse
1314
{
15+
@JsonProperty(value = "created")
16+
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
17+
private String createTime;
18+
1419
@JsonProperty(value = "data")
1520
private List<ImageEntity> images;
1621
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package org.devlive.sdk.openai.utils;
2+
3+
import okhttp3.MediaType;
4+
import okhttp3.MultipartBody;
5+
import okhttp3.RequestBody;
6+
7+
import java.io.File;
8+
9+
public class MultipartBodyUtils
10+
{
11+
public final static MediaType TYPE = MediaType.parse("multipart/form-data");
12+
13+
private MultipartBodyUtils()
14+
{
15+
}
16+
17+
public static MultipartBody.Part getPart(File image, String name)
18+
{
19+
RequestBody body = RequestBody.create(TYPE, image);
20+
return MultipartBody.Part.createFormData(name, image.getName(), body);
21+
}
22+
}

src/main/java/org/devlive/sdk/openai/utils/ProviderUtils.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public class ProviderUtils
2121
DEFAULT_PROVIDER.put(UrlModel.FETCH_CHAT_COMPLETIONS, "v1/chat/completions");
2222
AZURE_PROVIDER.put(UrlModel.FETCH_CHAT_COMPLETIONS, "chat/completions");
2323
DEFAULT_PROVIDER.put(UrlModel.FETCH_IMAGES_GENERATIONS, "v1/images/generations");
24+
DEFAULT_PROVIDER.put(UrlModel.FETCH_EDITS_GENERATIONS, "v1/images/edits");
2425
}
2526

2627
private ProviderUtils()

src/test/java/org/devlive/sdk/openai/OpenAiClientTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import org.junit.Before;
1515
import org.junit.Test;
1616

17+
import java.io.File;
1718
import java.util.List;
1819
import java.util.concurrent.TimeUnit;
1920
import java.util.stream.Collectors;
@@ -140,4 +141,14 @@ public void testCreateImages()
140141
.build();
141142
Assert.assertTrue(client.createImages(configure).getImages().size() > 0);
142143
}
144+
145+
@Test
146+
public void testEditImages()
147+
{
148+
ImageEntity configure = ImageEntity.builder()
149+
.prompt("Add hello to image")
150+
.build();
151+
String file = this.getClass().getResource("/logo.png").getFile();
152+
Assert.assertTrue(client.editImages(new File(file), null, configure).getImages().size() > 0);
153+
}
143154
}

src/test/resources/logo.png

24.5 KB
Loading

0 commit comments

Comments
 (0)