Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

*{component-header}*

The OpenAI component provides integration with OpenAI and OpenAI-compatible APIs for chat completion, text embeddings, content moderation, audio transcription, audio translation, and text-to-speech using the official openai-java SDK.
The OpenAI component provides integration with OpenAI and OpenAI-compatible APIs for chat completion, text embeddings, content moderation, audio transcription, audio translation, text-to-speech, and image generation and editing using the official openai-java SDK.

Maven users will need to add the following dependency to their `pom.xml` for this component:

Expand Down Expand Up @@ -48,6 +48,8 @@ See xref:others:openai-responses.adoc[Responses API operation] for usage (`previ
* `audio-translation` - Transcribe and translate audio files into English text (e.g., Whisper)
* `audio-speech` - Synthesize spoken audio from text using text-to-speech models (e.g., gpt-4o-mini-tts, tts-1)
* `moderation` - Check text against the OpenAI usage policies before it reaches a model
* `image-generation` - Generate images from a text prompt (e.g., gpt-image-1, gpt-image-1-mini)
* `image-edit` - Edit an existing image, optionally through a mask, from a text prompt

// component options: START
include::partial$component-configure-options.adoc[]
Expand Down Expand Up @@ -1255,20 +1257,24 @@ For more details on specific features, see:
* xref:others:openai-responses.adoc[Responses API operation] - OpenAI Responses API, hosted tools, and server-side conversation state
* xref:others:openai-mcp.adoc[MCP Tool Calling] - Model Context Protocol server configuration, agentic loop, streaming, and connection recovery
* xref:others:openai-providers.adoc[OpenAI-Compatible Providers] - Using Ollama, LM Studio, vLLM, and OpenRouter as alternative backends
* xref:others:openai-operations.adoc[Embeddings, Moderation and Audio Operations] - Text embeddings, vector database integration, content moderation, and audio transcription
* xref:others:openai-operations.adoc[Embeddings, Moderation, Audio and Image Operations] - Text embeddings, vector database integration, content moderation, audio transcription, and image generation

== Error Handling

The component may throw the following exceptions:

* `IllegalArgumentException`:
** When an invalid operation is specified (supported: `chat-completion`, `responses`, `embeddings`, `tool-execution`, `audio-transcription`, `audio-translation`, `audio-speech`, `moderation`)
** When an invalid operation is specified (supported: `chat-completion`, `responses`, `embeddings`, `tool-execution`, `audio-transcription`, `audio-translation`, `audio-speech`, `moderation`, `image-generation`, `image-edit`)
** When message body or user message is missing
** When the audio model is missing (audio-transcription, audio-translation) or the speech model is missing (audio-speech)
** When image file is provided without userMessage (chat-completion)
** When unsupported file type is provided (only text and image files are supported)
** When invalid JSON schema string is provided
** When the moderation input list is empty or contains null elements (moderation)
** When the image model is missing (image-generation, image-edit)
** When the prompt is missing (image-generation, image-edit) or the image list is empty (image-edit)
** When an unsupported image or mask body type is provided (image-edit)
* `CamelExchangeException`:
** When moderation returns a number of results that does not match the number of inputs (moderation)
** When the image response contains no images, or an image with neither `b64_json` nor `url` (image-generation, image-edit)
* API-specific exceptions from the OpenAI SDK for network errors, authentication failures, rate limiting, etc.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
= OpenAI - Embeddings, Moderation and Audio Operations
= OpenAI - Embeddings, Moderation, Audio and Image Operations
:tabs-sync-option:

xref:ROOT:openai-component.adoc[Back to OpenAI Component]
Expand Down Expand Up @@ -581,3 +581,147 @@ The message body is the generated audio as a `byte[]`. The `Content-Type` header
====
The generated audio is fully buffered into a `byte[]` in memory. This is fine for typical short text-to-speech responses, but be mindful of heap usage when synthesizing very large inputs (e.g., book-length narration).
====

== Image Generation and Edit Operations

The `image-generation` operation creates images from a text prompt using OpenAI's `POST /v1/images/generations` endpoint. The message body is the prompt, and the produced body is the generated image as a `byte[]` together with a `Content-Type` header, so the result chains straight into `file:`, object storage, or messaging endpoints.

=== Basic Image Generation

[tabs]
====
Java::
+
[source,java]
----
from("direct:product-image")
.setBody(simple("Studio photo of ${header.productName} on a white background"))
.to("openai:image-generation?imageModel=gpt-image-1&imageSize=1024x1024")
.to("file:target/images?fileName=${header.productName}.png");
----

XML::
+
[source,xml]
----
<route>
<from uri="direct:product-image"/>
<to uri="openai:image-generation?imageModel=gpt-image-1&amp;imageSize=1024x1024"/>
<to uri="file:target/images?fileName=${header.productName}.png"/>
</route>
----

YAML::
+
[source,yaml]
----
- route:
from:
uri: direct:product-image
steps:
- to:
uri: openai:image-generation
parameters:
imageModel: gpt-image-1
imageSize: 1024x1024
- to:
uri: file:target/images?fileName=${header.productName}.png
----
====

The prompt can also come from the `imagePrompt` endpoint option or the `CamelOpenAIImagePrompt` header, which take precedence over the message body. That is useful when the body is already carrying something else, or when the prompt is a fixed part of the route.

=== Image Generation Parameters

[cols="1,1,3"]
|===
| Parameter | Type | Description

| `imageModel` | String | The model to use (e.g., `gpt-image-1`, `gpt-image-1-mini`, `gpt-image-1.5`, `gpt-image-2`). Required. The DALL-E models are no longer offered by OpenAI, but remain valid values for compatible providers.
| `imagePrompt` | String | The prompt, when it does not come from the message body.
| `imageSize` | String | Image size such as `1024x1024`, `1536x1024`, `1024x1536` or `auto`. The accepted values depend on the model.
| `imageQuality` | String | `auto`, `high`, `medium`, `low` for the GPT image models; `hd` and `standard` are DALL-E values kept for compatible providers.
| `imageResponseFormat` | String | `url` or `b64_json`. Rejected by the OpenAI images endpoint, see the note below.
| `imageCount` | Integer | Number of images to generate, from 1 to 10. `dall-e-3` only supports 1.
| `imageBackground` | String | `transparent`, `opaque` or `auto`. GPT image models only, and `transparent` requires the `png` or `webp` output format.
| `imageOutputFormat` | String | `png`, `jpeg` or `webp`. GPT image models only, which default to `png`.
| `imageOutputCompression` | Integer | Compression from 0 to 100 for the `webp` and `jpeg` output formats. GPT image models only.
| `imageStyle` | String | `vivid` or `natural`. A `dall-e-3` option, so only useful with compatible providers.
| `imageModeration` | String | `low` or `auto`. GPT image models only.
|===

[IMPORTANT]
====
Leave `imageResponseFormat` unset against OpenAI. The GPT image models always return base64 and reject the parameter, and as of August 2026 the OpenAI images endpoint rejects it for every model with `Unknown parameter: 'response_format'` — the DALL-E models that used to accept it are no longer offered. The option is only sent when you set it explicitly, so routes are unaffected by default; it remains available for OpenAI-compatible providers that still implement the older images API, where `url` is often the default.
====

=== Image Edit

The `image-edit` operation edits an existing image using OpenAI's `POST /v1/images/edits` endpoint. The message body carries the image, so the prompt must come from the `imagePrompt` endpoint option or the `CamelOpenAIImagePrompt` header.

[source,java]
----
from("aws2-s3:marketing-assets")
.setHeader(OpenAIConstants.IMAGE_PROMPT, constant("Add a red SALE banner in the top-right corner"))
.to("openai:image-edit?imageModel=gpt-image-1")
.to("aws2-s3:marketing-assets-processed");
----

The body may be a `File`, `Path`, `InputStream`, `byte[]`, or a `List` of those. A list is sent as several reference images, which the GPT image models accept up to 16 of, each under 50 MB.

An optional mask can be supplied through the `CamelOpenAIImageMask` header, using the same body types. The fully transparent areas of the mask mark where the image should be edited:

[source,java]
----
from("direct:edit")
.setHeader(OpenAIConstants.IMAGE_MASK, constant(maskBytes))
.setHeader(OpenAIConstants.IMAGE_PROMPT, constant("Replace the masked area with a blue sky"))
.to("openai:image-edit?imageModel=gpt-image-1&imageInputFidelity=high");
----

The image-edit operation accepts the same parameters as image-generation, except for `imageStyle` and `imageModeration`, and adds one of its own:

[cols="1,1,3"]
|===
| Parameter | Type | Description

| `imageInputFidelity` | String | `high` or `low`, controlling how closely the edit preserves the style and features of the input image. Supported by `gpt-image-1` and `gpt-image-1.5`.
|===

=== Image Input Handling

The API validates the upload on the content type of the multipart part and accepts only `image/png`, `image/jpeg` and `image/webp`. That content type is resolved in this order:

1. the MIME type detected as described in xref:ROOT:openai-component.adoc[the component MIME type detection] — the `CamelOpenAIMediaType` header, then the content type headers set by the object storage components, then `Content-Type`, then `CamelFileContentType`, then the file name;
2. the extension of the body, when the body is a `File` or `Path`;
3. `image/png`.

Anything that resolves to a type the API does not accept, such as the `text/plain` that a bare `byte[]` body would otherwise be sent as, falls back to `image/png` rather than being passed through.

The multipart file name is kept consistent with that content type: the `CamelFileNameOnly` header when it has an extension, otherwise the name of a `File` or `Path` body, otherwise `image.<ext>`.

That means an image arriving from `file:` or from an object storage component needs no extra configuration. A `byte[]` body of a JPEG or WebP image needs either `CamelFileNameOnly`, `Content-Type` or the `CamelOpenAIMediaType` header, or it will be uploaded as PNG.

=== Image Output

A single image becomes the message body directly, and several images become a `List`, so the common case does not force routes to unwrap a one-element list. Images returned as base64 are decoded into `byte[]`, and images returned as URLs stay as `String`.

[cols="1,1,3"]
|===
| Header | Type | Description

| `CamelOpenAIImageResultCount` | Integer | The number of images returned.
| `CamelOpenAIImageRevisedPrompt` | String | The prompt as revised by the model, when a single image is returned (`dall-e-3`).
| `CamelOpenAIImageRevisedPrompts` | List<String> | The revised prompts, one entry per returned image.
| `CamelOpenAIImageInputTokens` | Long | Input tokens billed. GPT image models only.
| `CamelOpenAIImageOutputTokens` | Long | Output tokens billed. GPT image models only.
| `CamelOpenAIImageTotalTokens` | Long | Total tokens billed. GPT image models only.
| `Content-Type` | String | Set only when the body is binary, from the output format reported by the response, falling back to the requested `imageOutputFormat` and then to `image/png`.
|===

Set `storeFullResponse=true` to keep the complete SDK response in the `CamelOpenAIImageResponse` exchange property.

[NOTE]
====
Generated images are fully buffered into memory as `byte[]`. Requesting several large, high-quality images in a single exchange multiplies that cost, so prefer the `url` response format on `dall-e-2` and `dall-e-3` when the route only needs to pass a reference along.
====
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,30 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj
case "hallucinatedToolNameStrategy": target.getConfiguration().setHallucinatedToolNameStrategy(property(camelContext, org.apache.camel.component.openai.HallucinatedToolNameStrategy.class, value)); return true;
case "hostedmcptools":
case "hostedMcpTools": target.getConfiguration().setHostedMcpTools(property(camelContext, java.lang.String.class, value)); return true;
case "imagebackground":
case "imageBackground": target.getConfiguration().setImageBackground(property(camelContext, java.lang.String.class, value)); return true;
case "imagecount":
case "imageCount": target.getConfiguration().setImageCount(property(camelContext, java.lang.Integer.class, value)); return true;
case "imageinputfidelity":
case "imageInputFidelity": target.getConfiguration().setImageInputFidelity(property(camelContext, java.lang.String.class, value)); return true;
case "imagemodel":
case "imageModel": target.getConfiguration().setImageModel(property(camelContext, java.lang.String.class, value)); return true;
case "imagemoderation":
case "imageModeration": target.getConfiguration().setImageModeration(property(camelContext, java.lang.String.class, value)); return true;
case "imageoutputcompression":
case "imageOutputCompression": target.getConfiguration().setImageOutputCompression(property(camelContext, java.lang.Integer.class, value)); return true;
case "imageoutputformat":
case "imageOutputFormat": target.getConfiguration().setImageOutputFormat(property(camelContext, java.lang.String.class, value)); return true;
case "imageprompt":
case "imagePrompt": target.getConfiguration().setImagePrompt(property(camelContext, java.lang.String.class, value)); return true;
case "imagequality":
case "imageQuality": target.getConfiguration().setImageQuality(property(camelContext, java.lang.String.class, value)); return true;
case "imageresponseformat":
case "imageResponseFormat": target.getConfiguration().setImageResponseFormat(property(camelContext, java.lang.String.class, value)); return true;
case "imagesize":
case "imageSize": target.getConfiguration().setImageSize(property(camelContext, java.lang.String.class, value)); return true;
case "imagestyle":
case "imageStyle": target.getConfiguration().setImageStyle(property(camelContext, java.lang.String.class, value)); return true;
case "jsonschema":
case "jsonSchema": target.getConfiguration().setJsonSchema(property(camelContext, java.lang.String.class, value)); return true;
case "lazystartproducer":
Expand Down Expand Up @@ -205,6 +229,30 @@ public Class<?> getOptionType(String name, boolean ignoreCase) {
case "hallucinatedToolNameStrategy": return org.apache.camel.component.openai.HallucinatedToolNameStrategy.class;
case "hostedmcptools":
case "hostedMcpTools": return java.lang.String.class;
case "imagebackground":
case "imageBackground": return java.lang.String.class;
case "imagecount":
case "imageCount": return java.lang.Integer.class;
case "imageinputfidelity":
case "imageInputFidelity": return java.lang.String.class;
case "imagemodel":
case "imageModel": return java.lang.String.class;
case "imagemoderation":
case "imageModeration": return java.lang.String.class;
case "imageoutputcompression":
case "imageOutputCompression": return java.lang.Integer.class;
case "imageoutputformat":
case "imageOutputFormat": return java.lang.String.class;
case "imageprompt":
case "imagePrompt": return java.lang.String.class;
case "imagequality":
case "imageQuality": return java.lang.String.class;
case "imageresponseformat":
case "imageResponseFormat": return java.lang.String.class;
case "imagesize":
case "imageSize": return java.lang.String.class;
case "imagestyle":
case "imageStyle": return java.lang.String.class;
case "jsonschema":
case "jsonSchema": return java.lang.String.class;
case "lazystartproducer":
Expand Down Expand Up @@ -345,6 +393,30 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
case "hallucinatedToolNameStrategy": return target.getConfiguration().getHallucinatedToolNameStrategy();
case "hostedmcptools":
case "hostedMcpTools": return target.getConfiguration().getHostedMcpTools();
case "imagebackground":
case "imageBackground": return target.getConfiguration().getImageBackground();
case "imagecount":
case "imageCount": return target.getConfiguration().getImageCount();
case "imageinputfidelity":
case "imageInputFidelity": return target.getConfiguration().getImageInputFidelity();
case "imagemodel":
case "imageModel": return target.getConfiguration().getImageModel();
case "imagemoderation":
case "imageModeration": return target.getConfiguration().getImageModeration();
case "imageoutputcompression":
case "imageOutputCompression": return target.getConfiguration().getImageOutputCompression();
case "imageoutputformat":
case "imageOutputFormat": return target.getConfiguration().getImageOutputFormat();
case "imageprompt":
case "imagePrompt": return target.getConfiguration().getImagePrompt();
case "imagequality":
case "imageQuality": return target.getConfiguration().getImageQuality();
case "imageresponseformat":
case "imageResponseFormat": return target.getConfiguration().getImageResponseFormat();
case "imagesize":
case "imageSize": return target.getConfiguration().getImageSize();
case "imagestyle":
case "imageStyle": return target.getConfiguration().getImageStyle();
case "jsonschema":
case "jsonSchema": return target.getConfiguration().getJsonSchema();
case "lazystartproducer":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class OpenAIEndpointUriFactory extends org.apache.camel.support.component
private static final Set<String> ENDPOINT_IDENTITY_PROPERTY_NAMES;
private static final Map<String, String> MULTI_VALUE_PREFIXES;
static {
Set<String> props = new HashSet<>(69);
Set<String> props = new HashSet<>(81);
props.add("additionalBodyProperty");
props.add("additionalHeader");
props.add("additionalResponseHeader");
Expand All @@ -47,6 +47,18 @@ public class OpenAIEndpointUriFactory extends org.apache.camel.support.component
props.add("fileSearchVectorStoreIds");
props.add("hallucinatedToolNameStrategy");
props.add("hostedMcpTools");
props.add("imageBackground");
props.add("imageCount");
props.add("imageInputFidelity");
props.add("imageModel");
props.add("imageModeration");
props.add("imageOutputCompression");
props.add("imageOutputFormat");
props.add("imagePrompt");
props.add("imageQuality");
props.add("imageResponseFormat");
props.add("imageSize");
props.add("imageStyle");
props.add("jsonSchema");
props.add("lazyStartProducer");
props.add("maxAgenticTokens");
Expand Down
Loading