Skip to content

Commit 6e7d513

Browse files
committed
Add outputFormat and outputCompression to OpenAiSdkImageOptions
Add support for outputFormat and outputCompression parameters in image generation using the OpenAI SDK. These options allow users to specify the output format (png, jpeg, webp) and compression level for generated images, which is supported by the gpt-image-1 model. Changes: * Add outputFormat and outputCompression fields to OpenAiSdkImageOptions * Add getters, setters, and builder methods for the new fields * Update equals, hashCode, and toString methods * Update toOpenAiImageGenerateParams to include the new parameters * Update Builder.from() and Builder.merge() to handle new fields * Add test coverage for the new properties * Update documentation with new properties and gpt-image-1 example Signed-off-by: Igor Bari <[email protected]>
1 parent bf5ebce commit 6e7d513

File tree

3 files changed

+91
-5
lines changed

3 files changed

+91
-5
lines changed

auto-configurations/models/spring-ai-autoconfigure-model-openai-sdk/src/test/java/org/springframework/ai/model/openaisdk/autoconfigure/OpenAiSdkImagePropertiesTests.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,9 @@ public void imageOptionsTest() {
102102
"spring.ai.openai-sdk.image.options.responseFormat=url",
103103
"spring.ai.openai-sdk.image.options.size=1024x1792",
104104
"spring.ai.openai-sdk.image.options.style=vivid",
105-
"spring.ai.openai-sdk.image.options.user=userXYZ"
105+
"spring.ai.openai-sdk.image.options.user=userXYZ",
106+
"spring.ai.openai-sdk.image.options.outputFormat=jpeg",
107+
"spring.ai.openai-sdk.image.options.outputCompression=75"
106108
)
107109
// @formatter:on
108110
.withConfiguration(SpringAiTestAutoConfigurations.of(OpenAiSdkImageAutoConfiguration.class))
@@ -122,6 +124,8 @@ public void imageOptionsTest() {
122124
assertThat(imageProperties.getOptions().getSize()).isEqualTo("1024x1792");
123125
assertThat(imageProperties.getOptions().getStyle()).isEqualTo("vivid");
124126
assertThat(imageProperties.getOptions().getUser()).isEqualTo("userXYZ");
127+
assertThat(imageProperties.getOptions().getOutputFormat()).isEqualTo("jpeg");
128+
assertThat(imageProperties.getOptions().getOutputCompression()).isEqualTo(75);
125129
});
126130
}
127131

models/spring-ai-openai-sdk/src/main/java/org/springframework/ai/openaisdk/OpenAiSdkImageOptions.java

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,17 @@ public class OpenAiSdkImageOptions extends AbstractOpenAiSdkOptions implements I
8282
*/
8383
private String user;
8484

85+
/**
86+
* The output format of the generated images. Must be one of png, jpeg, or webp.
87+
*/
88+
private String outputFormat;
89+
90+
/**
91+
* The compression level (0-100) for lossy formats like jpeg and webp. Only applies
92+
* when outputFormat is jpeg or webp.
93+
*/
94+
private Integer outputCompression;
95+
8596
public static Builder builder() {
8697
return new Builder();
8798
}
@@ -160,6 +171,22 @@ public void setStyle(String style) {
160171
this.style = style;
161172
}
162173

174+
public String getOutputFormat() {
175+
return this.outputFormat;
176+
}
177+
178+
public void setOutputFormat(String outputFormat) {
179+
this.outputFormat = outputFormat;
180+
}
181+
182+
public Integer getOutputCompression() {
183+
return this.outputCompression;
184+
}
185+
186+
public void setOutputCompression(Integer outputCompression) {
187+
this.outputCompression = outputCompression;
188+
}
189+
163190
@Override
164191
public boolean equals(Object o) {
165192
if (o == null || getClass() != o.getClass()) {
@@ -169,20 +196,23 @@ public boolean equals(Object o) {
169196
return Objects.equals(this.n, that.n) && Objects.equals(this.width, that.width)
170197
&& Objects.equals(this.height, that.height) && Objects.equals(this.quality, that.quality)
171198
&& Objects.equals(this.responseFormat, that.responseFormat) && Objects.equals(this.size, that.size)
172-
&& Objects.equals(this.style, that.style) && Objects.equals(this.user, that.user);
199+
&& Objects.equals(this.style, that.style) && Objects.equals(this.user, that.user)
200+
&& Objects.equals(this.outputFormat, that.outputFormat)
201+
&& Objects.equals(this.outputCompression, that.outputCompression);
173202
}
174203

175204
@Override
176205
public int hashCode() {
177206
return Objects.hash(this.n, this.width, this.height, this.quality, this.responseFormat, this.size, this.style,
178-
this.user);
207+
this.user, this.outputFormat, this.outputCompression);
179208
}
180209

181210
@Override
182211
public String toString() {
183212
return "OpenAiSdkImageOptions{" + "n=" + this.n + ", width=" + this.width + ", height=" + this.height
184213
+ ", quality='" + this.quality + '\'' + ", responseFormat='" + this.responseFormat + '\'' + ", size='"
185-
+ this.size + '\'' + ", style='" + this.style + '\'' + ", user='" + this.user + '\'' + '}';
214+
+ this.size + '\'' + ", style='" + this.style + '\'' + ", user='" + this.user + '\''
215+
+ ", outputFormat='" + this.outputFormat + '\'' + ", outputCompression=" + this.outputCompression + '}';
186216
}
187217

188218
public ImageGenerateParams toOpenAiImageGenerateParams(ImagePrompt imagePrompt) {
@@ -220,6 +250,12 @@ else if (this.getModel() != null) {
220250
if (this.getUser() != null) {
221251
builder.user(this.getUser());
222252
}
253+
if (this.getOutputFormat() != null) {
254+
builder.outputFormat(ImageGenerateParams.OutputFormat.of(this.getOutputFormat().toLowerCase()));
255+
}
256+
if (this.getOutputCompression() != null) {
257+
builder.outputCompression(this.getOutputCompression().longValue());
258+
}
223259

224260
return builder.build();
225261
}
@@ -256,6 +292,8 @@ public Builder from(OpenAiSdkImageOptions fromOptions) {
256292
this.options.setSize(fromOptions.getSize());
257293
this.options.setStyle(fromOptions.getStyle());
258294
this.options.setUser(fromOptions.getUser());
295+
this.options.setOutputFormat(fromOptions.getOutputFormat());
296+
this.options.setOutputCompression(fromOptions.getOutputCompression());
259297
return this;
260298
}
261299

@@ -322,6 +360,12 @@ public Builder merge(ImageOptions from) {
322360
if (castFrom.getUser() != null) {
323361
this.options.setUser(castFrom.getUser());
324362
}
363+
if (castFrom.getOutputFormat() != null) {
364+
this.options.setOutputFormat(castFrom.getOutputFormat());
365+
}
366+
if (castFrom.getOutputCompression() != null) {
367+
this.options.setOutputCompression(castFrom.getOutputCompression());
368+
}
325369
}
326370
return this;
327371
}
@@ -421,6 +465,16 @@ public Builder style(String style) {
421465
return this;
422466
}
423467

468+
public Builder outputFormat(String outputFormat) {
469+
this.options.setOutputFormat(outputFormat);
470+
return this;
471+
}
472+
473+
public Builder outputCompression(Integer outputCompression) {
474+
this.options.setOutputCompression(outputCompression);
475+
return this;
476+
}
477+
424478
public OpenAiSdkImageOptions build() {
425479
return this.options;
426480
}

spring-ai-docs/src/main/antora/modules/ROOT/pages/api/image/openai-sdk-image.adoc

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ The prefix `spring.ai.openai-sdk.image` is the property prefix for configuring t
191191
|====
192192
| Property | Description | Default
193193

194-
| spring.ai.openai-sdk.image.options.model | The model to use for image generation. Available models: `dall-e-2`, `dall-e-3`. See the https://platform.openai.com/docs/models[models] page for more information. | `dall-e-3`
194+
| spring.ai.openai-sdk.image.options.model | The model to use for image generation. Available models: `dall-e-2`, `dall-e-3`, `gpt-image-1`. See the https://platform.openai.com/docs/models[models] page for more information. | `dall-e-3`
195195
| spring.ai.openai-sdk.image.options.n | The number of images to generate. Must be between 1 and 10. For `dall-e-3`, only n=1 is supported. | -
196196
| spring.ai.openai-sdk.image.options.quality | The quality of the image that will be generated. `hd` creates images with finer details and greater consistency across the image. This parameter is only supported for `dall-e-3`. Available values: `standard`, `hd`. | -
197197
| spring.ai.openai-sdk.image.options.response-format | The format in which the generated images are returned. Must be one of `url` or `b64_json`. | -
@@ -200,6 +200,8 @@ The prefix `spring.ai.openai-sdk.image` is the property prefix for configuring t
200200
| spring.ai.openai-sdk.image.options.height | The height of the generated images. Must be one of 256, 512, or 1024 for `dall-e-2`. | -
201201
| spring.ai.openai-sdk.image.options.style | The style of the generated images. Must be one of `vivid` or `natural`. Vivid causes the model to lean towards generating hyper-real and dramatic images. Natural causes the model to produce more natural, less hyper-real looking images. This parameter is only supported for `dall-e-3`. | -
202202
| spring.ai.openai-sdk.image.options.user | A unique identifier representing your end-user, which can help OpenAI to monitor and detect abuse. | -
203+
| spring.ai.openai-sdk.image.options.output-format | The output format of the generated images. Must be one of `png`, `jpeg`, or `webp`. This parameter is supported for `gpt-image-1`. | -
204+
| spring.ai.openai-sdk.image.options.output-compression | The compression level (0-100) for lossy formats like `jpeg` and `webp`. Lower values mean higher compression. This parameter is supported for `gpt-image-1`. | -
203205
|====
204206

205207
TIP: All properties prefixed with `spring.ai.openai-sdk.image.options` can be overridden at runtime by adding request-specific <<image-options>> to the `ImagePrompt` call.
@@ -229,6 +231,32 @@ ImageResponse response = imageModel.call(
229231
.build()));
230232
----
231233

234+
=== Using GPT Image 1 with Output Format Options
235+
236+
The `gpt-image-1` model supports additional options for controlling the output format and compression level. This is useful when you need to generate images in specific formats like JPEG with controlled file sizes:
237+
238+
[source,java]
239+
----
240+
ImageResponse response = imageModel.call(
241+
new ImagePrompt("A photorealistic landscape of mountains at sunset",
242+
OpenAiSdkImageOptions.builder()
243+
.model("gpt-image-1")
244+
.N(1)
245+
.width(1024)
246+
.height(1024)
247+
.outputFormat("jpeg")
248+
.outputCompression(75)
249+
.build()));
250+
----
251+
252+
The `outputFormat` option accepts:
253+
254+
* `png` - Lossless format, larger file size (default)
255+
* `jpeg` - Lossy format, smaller file size with configurable compression
256+
* `webp` - Modern format with good compression and quality balance
257+
258+
The `outputCompression` option (0-100) controls the compression level for lossy formats (`jpeg` and `webp`). Lower values result in higher compression (smaller files, lower quality), while higher values preserve more quality (larger files).
259+
232260
TIP: In addition to the model specific https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-openai-sdk/src/main/java/org/springframework/ai/openaisdk/OpenAiSdkImageOptions.java[OpenAiSdkImageOptions] you can use a portable link:https://github.com/spring-projects/spring-ai/blob/main/spring-ai-model/src/main/java/org/springframework/ai/image/ImageOptions.java[ImageOptions] instance, created with the link:https://github.com/spring-projects/spring-ai/blob/main/spring-ai-model/src/main/java/org/springframework/ai/image/ImageOptionsBuilder.java[ImageOptionsBuilder#builder()].
233261

234262
== Sample Controller

0 commit comments

Comments
 (0)