From 5e13f09f2d39e9a550e230e679ef919b3b514572 Mon Sep 17 00:00:00 2001 From: jonghoonpark Date: Fri, 2 May 2025 05:27:22 +0900 Subject: [PATCH] Refactor OpenAI Image API and add support for the new model Signed-off-by: jonghoonpark --- .../ai/openai/OpenAiImageModel.java | 59 +++++++++ .../ai/openai/OpenAiImageOptions.java | 118 ++++++++++++++++-- .../ai/openai/api/OpenAiImageApi.java | 13 +- .../ai/openai/OpenAiTestConfiguration.java | 4 +- .../ai/openai/chat/OpenAiRetryTests.java | 9 +- .../ai/openai/image/OpenAiImageModelIT.java | 54 +++++++- .../image/OpenAiImageModelNoOpApiKeysIT.java | 8 +- .../image/OpenAiImageModelObservationIT.java | 10 +- ...geModelWithImageResponseMetadataTests.java | 4 +- .../ROOT/pages/api/image/openai-image.adoc | 10 +- 10 files changed, 258 insertions(+), 31 deletions(-) diff --git a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiImageModel.java b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiImageModel.java index 68354662548..1bf7f5ae6c5 100644 --- a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiImageModel.java +++ b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiImageModel.java @@ -50,6 +50,7 @@ * @author Christian Tzolov * @author Hyunjoon Choi * @author Thomas Vitale + * @author Jonghoon Park * @since 0.8.0 */ public class OpenAiImageModel implements ImageModel { @@ -88,7 +89,9 @@ public class OpenAiImageModel implements ImageModel { * @param openAiImageApi The OpenAiImageApi instance to be used for interacting with * the OpenAI Image API. * @throws IllegalArgumentException if openAiImageApi is null + * @deprecated use {@link OpenAiImageModel.Builder} instead. */ + @Deprecated(forRemoval = true, since = "1.0.0-M8") public OpenAiImageModel(OpenAiImageApi openAiImageApi) { this(openAiImageApi, OpenAiImageOptions.builder().build(), RetryUtils.DEFAULT_RETRY_TEMPLATE); } @@ -99,7 +102,9 @@ public OpenAiImageModel(OpenAiImageApi openAiImageApi) { * the OpenAI Image API. * @param options The OpenAiImageOptions to configure the image model. * @param retryTemplate The retry template. + * @deprecated use {@link OpenAiImageModel.Builder} instead. */ + @Deprecated(forRemoval = true, since = "1.0.0-M8") public OpenAiImageModel(OpenAiImageApi openAiImageApi, OpenAiImageOptions options, RetryTemplate retryTemplate) { this(openAiImageApi, options, retryTemplate, ObservationRegistry.NOOP); } @@ -111,7 +116,9 @@ public OpenAiImageModel(OpenAiImageApi openAiImageApi, OpenAiImageOptions option * @param options The OpenAiImageOptions to configure the image model. * @param retryTemplate The retry template. * @param observationRegistry The ObservationRegistry used for instrumentation. + * @deprecated use {@link OpenAiImageModel.Builder} instead. */ + @Deprecated(forRemoval = true, since = "1.0.0-M8") public OpenAiImageModel(OpenAiImageApi openAiImageApi, OpenAiImageOptions options, RetryTemplate retryTemplate, ObservationRegistry observationRegistry) { Assert.notNull(openAiImageApi, "OpenAiImageApi must not be null"); @@ -198,6 +205,14 @@ private ImagePrompt buildRequestImagePrompt(ImagePrompt imagePrompt) { .height(ModelOptionsUtils.mergeOption(runtimeOptions.getHeight(), this.defaultOptions.getHeight())) .style(ModelOptionsUtils.mergeOption(runtimeOptions.getStyle(), this.defaultOptions.getStyle())) // Handle OpenAI specific image options + .background( + ModelOptionsUtils.mergeOption(runtimeOptions.getBackground(), this.defaultOptions.getBackground())) + .moderation( + ModelOptionsUtils.mergeOption(runtimeOptions.getModeration(), this.defaultOptions.getModeration())) + .outputCompression(ModelOptionsUtils.mergeOption(runtimeOptions.getOutputCompression(), + this.defaultOptions.getOutputCompression())) + .outputFormat(ModelOptionsUtils.mergeOption(runtimeOptions.getOutputFormat(), + this.defaultOptions.getOutputFormat())) .quality(ModelOptionsUtils.mergeOption(runtimeOptions.getQuality(), this.defaultOptions.getQuality())) .user(ModelOptionsUtils.mergeOption(runtimeOptions.getUser(), this.defaultOptions.getUser())) .build(); @@ -214,4 +229,48 @@ public void setObservationConvention(ImageModelObservationConvention observation this.observationConvention = observationConvention; } + public static OpenAiImageModel.Builder builder() { + return new OpenAiImageModel.Builder(); + } + + public static final class Builder { + + private OpenAiImageApi openAiImageApi; + + private OpenAiImageOptions defaultOptions = OpenAiImageOptions.builder().build(); + + private RetryTemplate retryTemplate = RetryUtils.DEFAULT_RETRY_TEMPLATE; + + private ObservationRegistry observationRegistry = ObservationRegistry.NOOP; + + private Builder() { + } + + public OpenAiImageModel.Builder openAiImageApi(OpenAiImageApi openAiImageApi) { + this.openAiImageApi = openAiImageApi; + return this; + } + + public OpenAiImageModel.Builder defaultOptions(OpenAiImageOptions defaultOptions) { + this.defaultOptions = defaultOptions; + return this; + } + + public OpenAiImageModel.Builder retryTemplate(RetryTemplate retryTemplate) { + this.retryTemplate = retryTemplate; + return this; + } + + public OpenAiImageModel.Builder observationRegistry(ObservationRegistry observationRegistry) { + this.observationRegistry = observationRegistry; + return this; + } + + public OpenAiImageModel build() { + return new OpenAiImageModel(this.openAiImageApi, this.defaultOptions, this.retryTemplate, + this.observationRegistry); + } + + } + } diff --git a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiImageOptions.java b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiImageOptions.java index bb9170a63be..5976ab40d64 100644 --- a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiImageOptions.java +++ b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/OpenAiImageOptions.java @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 the original author or authors. + * Copyright 2023-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -28,6 +28,7 @@ * * @author Mark Pollack * @author Christian Tzolov + * @author Jonghoon Park * @since 0.8.0 */ @JsonInclude(JsonInclude.Include.NON_NULL) @@ -46,6 +47,39 @@ public class OpenAiImageOptions implements ImageOptions { @JsonProperty("model") private String model; + /** + * Allows to set transparency for the background of the generated image(s). This + * parameter is only supported for `gpt-image-1`. Must be one of `transparent`, + * `opaque` or `auto` (default value). When `auto` is used, the model will + * automatically determine the best background for the image. If `transparent`, the + * output format needs to support transparency, so it should be set to either `png` + * (default value) or `webp`. + */ + @JsonProperty("background") + private String background; + + /** + * Control the content-moderation level for images generated by `gpt-image-1`. Must be + * either `low` for less restrictive filtering or `auto` (default value). + */ + @JsonProperty("moderation") + private String moderation; + + /** + * The compression level (0-100%) for the generated images. This parameter is only + * supported for `gpt-image-1` with the `webp` or `jpeg` output formats, and defaults + * to 100. + */ + @JsonProperty("output_compression") + private Integer outputCompression; + + /** + * The format in which the generated images are returned. This parameter is only + * supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. + */ + @JsonProperty("output_format") + private String outputFormat; + /** * The width of the generated images. Must be one of 256, 512, or 1024 for dall-e-2. * This property is interconnected with the 'size' property - setting both width and @@ -75,19 +109,22 @@ public class OpenAiImageOptions implements ImageOptions { private String quality; /** - * The format in which the generated images are returned. Must be one of url or - * b64_json. + * The format in which generated images with `dall-e-2` and `dall-e-3` are returned. + * Must be one of `url` or `b64_json`. URLs are only valid for 60 minutes after the + * image has been generated. This parameter isn't supported for `gpt-image-1` which + * will always return base64-encoded images. */ @JsonProperty("response_format") private String responseFormat; /** - * The size of the generated images. Must be one of 256x256, 512x512, or 1024x1024 for - * dall-e-2. Must be one of 1024x1024, 1792x1024, or 1024x1792 for dall-e-3 models. - * This property is automatically computed when both width and height are set, - * following the format "widthxheight". When setting this property directly, it must - * follow the format "WxH" where W and H are valid integers. Invalid formats will - * result in null width and height values. + * The size of the generated images. Must be one of `1024x1024`, `1536x1024` + * (landscape), `1024x1536` (portrait), or `auto` (default value) for `gpt-image-1`, + * one of `256x256`, `512x512`, or `1024x1024` for `dall-e-2`, and one of `1024x1024`, + * `1792x1024`, or `1024x1792` for `dall-e-3`. This property is automatically computed + * when both width and height are set, following the format "widthxheight". When + * setting this property directly, it must follow the format "WxH" where W and H are + * valid integers. Invalid formats will result in null width and height values. */ @JsonProperty("size") private String size; @@ -130,6 +167,38 @@ public void setModel(String model) { this.model = model; } + public String getBackground() { + return background; + } + + public void setBackground(String background) { + this.background = background; + } + + public String getModeration() { + return moderation; + } + + public void setModeration(String moderation) { + this.moderation = moderation; + } + + public Integer getOutputCompression() { + return outputCompression; + } + + public void setOutputCompression(Integer outputCompression) { + this.outputCompression = outputCompression; + } + + public String getOutputFormat() { + return outputFormat; + } + + public void setOutputFormat(String outputFormat) { + this.outputFormat = outputFormat; + } + public String getQuality() { return this.quality; } @@ -246,14 +315,17 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(this.n, this.model, this.width, this.height, this.quality, this.responseFormat, this.size, - this.style, this.user); + return Objects.hash(this.n, this.model, this.background, this.moderation, this.outputCompression, + this.outputFormat, this.width, this.height, this.quality, this.responseFormat, this.size, this.style, + this.user); } @Override public String toString() { - return "OpenAiImageOptions{" + "n=" + this.n + ", model='" + this.model + '\'' + ", width=" + this.width - + ", height=" + this.height + ", quality='" + this.quality + '\'' + ", responseFormat='" + return "OpenAiImageOptions{" + "n=" + this.n + ", model='" + this.model + '\'' + ", background='" + + this.background + '\'' + ", moderation='" + this.moderation + '\'' + ", outputCompression='" + + this.outputCompression + '\'' + ", outputFormat='" + this.outputFormat + '\'' + ", width=" + + this.width + ", height=" + this.height + ", quality='" + this.quality + '\'' + ", responseFormat='" + this.responseFormat + '\'' + ", size='" + this.size + '\'' + ", style='" + this.style + '\'' + ", user='" + this.user + '\'' + '}'; } @@ -276,6 +348,26 @@ public Builder model(String model) { return this; } + public Builder background(String background) { + this.options.setBackground(background); + return this; + } + + public Builder moderation(String moderation) { + this.options.setModeration(moderation); + return this; + } + + public Builder outputCompression(Integer outputCompression) { + this.options.setOutputCompression(outputCompression); + return this; + } + + public Builder outputFormat(String outputFormat) { + this.options.setOutputFormat(outputFormat); + return this; + } + public Builder quality(String quality) { this.options.setQuality(quality); return this; diff --git a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiImageApi.java b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiImageApi.java index b09507528f8..0684330d409 100644 --- a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiImageApi.java +++ b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiImageApi.java @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 the original author or authors. + * Copyright 2023-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -91,6 +91,11 @@ public static Builder builder() { */ public enum ImageModel { + /** + * The state-of-the-art image generation model released in April 2025. + */ + GPT_IMAGE_1("gpt-image-1"), + /** * The latest DALLĀ·E model released in Nov 2023. */ @@ -120,6 +125,10 @@ public String getValue() { public record OpenAiImageRequest( @JsonProperty("prompt") String prompt, @JsonProperty("model") String model, + @JsonProperty("background") String background, + @JsonProperty("moderation") String moderation, + @JsonProperty("output_compression") Integer outputCompression, + @JsonProperty("output_format") String outputFormat, @JsonProperty("n") Integer n, @JsonProperty("quality") String quality, @JsonProperty("response_format") String responseFormat, @@ -128,7 +137,7 @@ public record OpenAiImageRequest( @JsonProperty("user") String user) { public OpenAiImageRequest(String prompt, String model) { - this(prompt, model, null, null, null, null, null, null); + this(prompt, model, null, null, null, null, null, null,null,null,null,null); } } diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/OpenAiTestConfiguration.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/OpenAiTestConfiguration.java index e7401d9d81b..da5db2e01ae 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/OpenAiTestConfiguration.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/OpenAiTestConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 the original author or authors. + * Copyright 2023-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -79,7 +79,7 @@ public OpenAiAudioSpeechModel openAiAudioSpeechModel(OpenAiAudioApi api) { @Bean public OpenAiImageModel openAiImageModel(OpenAiImageApi imageApi) { - return new OpenAiImageModel(imageApi); + return OpenAiImageModel.builder().openAiImageApi(imageApi).build(); } @Bean diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiRetryTests.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiRetryTests.java index 2ab1a9517e9..7be6866162b 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiRetryTests.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/chat/OpenAiRetryTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 the original author or authors. + * Copyright 2023-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -123,8 +123,11 @@ public void beforeEach() { .responseFormat(TranscriptResponseFormat.JSON) .build(), this.retryTemplate); - this.imageModel = new OpenAiImageModel(this.openAiImageApi, OpenAiImageOptions.builder().build(), - this.retryTemplate); + this.imageModel = OpenAiImageModel.builder() + .openAiImageApi(this.openAiImageApi) + .defaultOptions(OpenAiImageOptions.builder().build()) + .retryTemplate(this.retryTemplate) + .build(); } @Test diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/image/OpenAiImageModelIT.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/image/OpenAiImageModelIT.java index dd77bcd4b6a..013d3cbb07b 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/image/OpenAiImageModelIT.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/image/OpenAiImageModelIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 the original author or authors. + * Copyright 2023-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -25,7 +25,11 @@ import org.springframework.ai.image.ImagePrompt; import org.springframework.ai.image.ImageResponse; import org.springframework.ai.image.ImageResponseMetadata; +import org.springframework.ai.model.SimpleApiKey; +import org.springframework.ai.openai.OpenAiImageModel; +import org.springframework.ai.openai.OpenAiImageOptions; import org.springframework.ai.openai.OpenAiTestConfiguration; +import org.springframework.ai.openai.api.OpenAiImageApi; import org.springframework.ai.openai.metadata.OpenAiImageGenerationMetadata; import org.springframework.ai.openai.testutils.AbstractIT; import org.springframework.boot.test.context.SpringBootTest; @@ -67,4 +71,52 @@ void imageAsUrlTest() { assertThat(openAiImageGenerationMetadata.getRevisedPrompt()).isNotBlank(); } + @Test + void gptImageModelTest() { + var options = ImageOptionsBuilder.builder().height(1024).width(1024).build(); + + var instructions = """ + A light cream colored mini golden doodle with a sign that contains the message "I'm on my way to BARCADE!"."""; + + ImagePrompt imagePrompt = new ImagePrompt(instructions, options); + + OpenAiImageApi imageApi = OpenAiImageApi.builder() + .apiKey(new SimpleApiKey(System.getenv("OPENAI_API_KEY"))) + .build(); + + OpenAiImageOptions imageOptions = OpenAiImageOptions.builder() + .model(OpenAiImageApi.ImageModel.GPT_IMAGE_1.getValue()) + .background("transparent") + .moderation("low") + .outputCompression(80) + .outputFormat("webp") + .quality("low") + .build(); + + OpenAiImageModel openAiImageModel = OpenAiImageModel.builder() + .openAiImageApi(imageApi) + .defaultOptions(imageOptions) + .build(); + + ImageResponse imageResponse = openAiImageModel.call(imagePrompt); + + assertThat(imageResponse.getResults()).hasSize(1); + + ImageResponseMetadata imageResponseMetadata = imageResponse.getMetadata(); + assertThat(imageResponseMetadata.getCreated()).isPositive(); + + var generation = imageResponse.getResult(); + Image image = generation.getOutput(); + assertThat(image.getUrl()).isNull(); + assertThat(image.getB64Json()).isNotNull(); + + var imageGenerationMetadata = generation.getMetadata(); + Assertions.assertThat(imageGenerationMetadata).isInstanceOf(OpenAiImageGenerationMetadata.class); + + OpenAiImageGenerationMetadata openAiImageGenerationMetadata = (OpenAiImageGenerationMetadata) imageGenerationMetadata; + + assertThat(openAiImageGenerationMetadata).isNotNull(); + assertThat(openAiImageGenerationMetadata.getRevisedPrompt()).isNull(); + } + } diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/image/OpenAiImageModelNoOpApiKeysIT.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/image/OpenAiImageModelNoOpApiKeysIT.java index 61160a08a1f..f6b01cf41e0 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/image/OpenAiImageModelNoOpApiKeysIT.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/image/OpenAiImageModelNoOpApiKeysIT.java @@ -69,8 +69,12 @@ public OpenAiImageApi openAiImageApi() { @Bean public OpenAiImageModel openAiImageModel(OpenAiImageApi openAiImageApi) { - return new OpenAiImageModel(openAiImageApi, OpenAiImageOptions.builder().build(), - RetryTemplate.defaultInstance(), TestObservationRegistry.create()); + return OpenAiImageModel.builder() + .openAiImageApi(openAiImageApi) + .defaultOptions(OpenAiImageOptions.builder().build()) + .retryTemplate(RetryTemplate.defaultInstance()) + .observationRegistry(TestObservationRegistry.create()) + .build(); } } diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/image/OpenAiImageModelObservationIT.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/image/OpenAiImageModelObservationIT.java index 37dc7abcdba..6a64819f031 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/image/OpenAiImageModelObservationIT.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/image/OpenAiImageModelObservationIT.java @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 the original author or authors. + * Copyright 2023-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -104,8 +104,12 @@ public OpenAiImageApi openAiImageApi() { @Bean public OpenAiImageModel openAiImageModel(OpenAiImageApi openAiImageApi, TestObservationRegistry observationRegistry) { - return new OpenAiImageModel(openAiImageApi, OpenAiImageOptions.builder().build(), - RetryTemplate.defaultInstance(), observationRegistry); + return OpenAiImageModel.builder() + .openAiImageApi(openAiImageApi) + .defaultOptions(OpenAiImageOptions.builder().build()) + .retryTemplate(RetryTemplate.defaultInstance()) + .observationRegistry(observationRegistry) + .build(); } } diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/image/OpenAiImageModelWithImageResponseMetadataTests.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/image/OpenAiImageModelWithImageResponseMetadataTests.java index 14dda5ccd22..b0ce7fa60a3 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/image/OpenAiImageModelWithImageResponseMetadataTests.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/image/OpenAiImageModelWithImageResponseMetadataTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2023-2024 the original author or authors. + * Copyright 2023-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -139,7 +139,7 @@ public OpenAiImageApi imageGenerationApi(RestClient.Builder builder) { @Bean public OpenAiImageModel openAiImageModel(OpenAiImageApi openAiImageApi) { - return new OpenAiImageModel(openAiImageApi); + return OpenAiImageModel.builder().openAiImageApi(openAiImageApi).build(); } } diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/image/openai-image.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/image/openai-image.adoc index 182b0eaa31a..63170c06aca 100644 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/image/openai-image.adoc +++ b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/image/openai-image.adoc @@ -1,7 +1,7 @@ = OpenAI Image Generation -Spring AI supports DALL-E, the Image generation model from OpenAI. +Spring AI supports Image generation models (DALL-E, GPT Image 1) from OpenAI. == Prerequisites @@ -107,9 +107,13 @@ The prefix `spring.ai.openai.image` is the property prefix that lets you configu | spring.ai.openai.image.project-id | Optionally, you can specify which project is used for an API request. | - | spring.ai.openai.image.options.n | The number of images to generate. Must be between 1 and 10. For dall-e-3, only n=1 is supported. | - | spring.ai.openai.image.options.model | The model to use for image generation. | OpenAiImageApi.DEFAULT_IMAGE_MODEL +| spring.ai.openai.image.options.background | Allows to set transparency for the background of the generated image(s). This parameter is only supported for `gpt-image-1`. Must be one of `transparent`, `opaque` or `auto` (default value). When `auto` is used, the model will automatically determine the best background for the image. If `transparent`, the output format needs to support transparency, so it should be set to either `png` (default value) or `webp`. | - +| spring.ai.openai.image.options.moderation | Control the content-moderation level for images generated by `gpt-image-1`. Must be either `low` for less restrictive filtering or `auto` (default value). | - +| spring.ai.openai.image.options.output_compression | The compression level (0-100%) for the generated images. This parameter is only supported for `gpt-image-1` with the `webp` or `jpeg` output formats, and defaults to 100. | - +| spring.ai.openai.image.options.output_format | The format in which the generated images are returned. This parameter is only supported for `gpt-image-1`. Must be one of `png`, `jpeg`, or `webp`. | - | spring.ai.openai.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. | - -| spring.ai.openai.image.options.response_format | The format in which the generated images are returned. Must be one of URL or b64_json. | - -| `spring.ai.openai.image.options.size` | The size of the generated images. Must be one of 256x256, 512x512, or 1024x1024 for dall-e-2. Must be one of 1024x1024, 1792x1024, or 1024x1792 for dall-e-3 models. | - +| `spring.ai.openai.image.options.response_format` | The format in which the generated images are returned. Must be one of URL or b64_json. This parameter isn't supported for gpt-image-1 which will always return base64-encoded images. | - +| `spring.ai.openai.image.options.size` | The size of the generated images. Must be one of 256x256, 512x512, or 1024x1024 for dall-e-2. Must be one of 1024x1024, 1792x1024, or 1024x1792 for dall-e-3. Must be one of 1024x1024, 1536x1024 (landscape), 1024x1536 (portrait), or auto (default value) for gpt-image-1 | - | `spring.ai.openai.image.options.size_width` | The width of the generated images. Must be one of 256, 512, or 1024 for dall-e-2. | - | `spring.ai.openai.image.options.size_height`| The height of the generated images. Must be one of 256, 512, or 1024 for dall-e-2. | - | `spring.ai.openai.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. | -