[ 
https://issues.apache.org/jira/browse/CAMEL-23967?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18104401#comment-18104401
 ] 

Karol Krawczyk commented on CAMEL-23967:
----------------------------------------

I picked this up and opened a pull request: 
https://github.com/apache/camel/pull/25489

Two things in the proposal did not survive contact with the SDK, so the 
implementation deviates from the description.

h3. {{imageResponseFormat}} cannot be a plain option

The KDoc of {{ImageGenerateParams}} in the pinned SDK says the parameter is not 
supported by the GPT image models, which always return base64. Checking against 
the live API on 13 August 2026 turned out to be stricter still: {{POST 
/v1/images/generations}} answers {{400 Unknown parameter: 'response_format'}} 
for every model, including {{dall-e-2}} and {{dall-e-3}}, and {{/v1/models}} no 
longer lists any DALL-E model at all.

The option is kept, because OpenAI-compatible providers still implement the 
older images API where {{url}} is often the default, but it has no default 
value and is only put on the wire when set explicitly. The body shape follows 
from the response rather than from the option: base64 payloads are decoded into 
{{byte[]}}, URLs stay as {{String}}.

h3. The multipart content type has to be declared

Worth recording, because it is not obvious from the SDK: the images edit 
endpoint validates the upload on the content type of the multipart part, not on 
the file name, and {{MultipartField}} leaves that as {{text/plain}} unless 
{{contentType()}} is called. Without it every edit fails with {{400 Invalid 
file 'image': unsupported mimetype ('text/plain; charset=utf-8')}}. The mock 
cannot catch this, since it does not parse multipart — it took a live call to 
surface it. The producer now resolves the content type from the usual MIME type 
detection, then from the extension of a {{File}} or {{Path}} body, falling back 
to {{image/png}} for anything the API does not accept.

h3. The SDK is now 4.49.0, not 4.41.0

{{parent/pom.xml}} pins {{openai-java}} 4.49.0 on {{main}}. Everything below 
was checked against that artifact rather than against the API reference.

h3. What the pull request adds

Two operations, {{openai:image-generation}} and {{openai:image-edit}}:

* generation takes the prompt from the body, from the new {{imagePrompt}} 
option, or from the {{CamelOpenAIImagePrompt}} header;
* edit takes the image from the body — {{File}}, {{Path}}, {{InputStream}}, 
{{byte[]}}, or a {{List}} of those, since the GPT image models accept up to 16 
reference images — with an optional mask through {{CamelOpenAIImageMask}};
* options {{imageModel}}, {{imageSize}}, {{imageQuality}}, 
{{imageResponseFormat}}, {{imageCount}}, {{imageBackground}}, 
{{imageOutputFormat}}, {{imageOutputCompression}}, {{imageStyle}}, 
{{imageModeration}} and {{imageInputFidelity}}, each overridable per exchange 
by a header;
* a single image becomes the body directly and several images become a 
{{List}}, so the common case does not force routes to unwrap a one-element list;
* {{Content-Type}} is set from the output format reported by the response, 
falling back to the requested one, so the result chains into {{file:}} or 
object storage without further configuration;
* the revised prompt and the token usage are exposed as headers, and 
{{storeFullResponse=true}} keeps the full SDK response in 
{{CamelOpenAIImageResponse}}.

The multipart file name is resolved from {{CamelFileNameOnly}}, then from the 
name of a {{File}} or {{Path}} body, then from the MIME type — the API infers 
the image format from that name, which a raw {{byte[]}} body does not carry.

h3. Testing

{{camel-test-infra-openai-mock}} gained {{whenImageGeneration()}}, 
{{whenImageEdit()}}, {{replyWithImage(byte[])}}, {{replyWithImageUrl(String)}}, 
{{withRevisedPrompt()}}, {{withImageOutputFormat()}}, {{withImageSize()}}, 
{{withImageUsage()}} and {{assertImageRequest()}}, as suggested. Image edit 
requests are multipart, and the mock does not parse multipart — the same 
simplification the transcription handler already makes — so those expectations 
are matched in declaration order and the raw body is exposed to assertions 
instead. That is enough to verify that several images and a mask actually reach 
the wire.

24 unit tests, no model and no GPU involved. Both operations were additionally 
exercised once against the real API, which is what surfaced the two points 
above; the multipart content type is now asserted in the mock tests.

h3. Left out

{{createVariation}} and the streaming variants ({{generateStreaming}}, 
{{editStreaming}}, {{partialImages}}), as suggested in the issue.

_Reported by Claude Code on behalf of Karol Krawczyk_


> camel-openai: add image generation and edit operations
> ------------------------------------------------------
>
>                 Key: CAMEL-23967
>                 URL: https://issues.apache.org/jira/browse/CAMEL-23967
>             Project: Camel
>          Issue Type: New Feature
>          Components: camel-openai
>    Affects Versions: 4.21.0
>            Reporter: Federico Mariani
>            Priority: Minor
>              Labels: ai
>
> The pinned SDK (4.41.0) exposes {{images().generate(...)}}, 
> {{images().edit(...)}} and {{images().createVariation(...)}} (plus streaming 
> variants), none of which are reachable from camel-openai. Image generation is 
> a common integration step (product imagery pipelines, notification 
> enrichment) that chains naturally into Camel's file/storage/messaging 
> components.
> Proposal: new operation {{openai:image-generation}} (and optionally 
> {{image-edit}}):
> * body: prompt String (edit: image file/byte[] with prompt via option/header, 
> reusing the vision-input body handling and {{MimeTypeHelper}});
> * options/headers: {{imageModel}} (e.g. {{gpt-image-1}}), {{imageSize}}, 
> {{imageQuality}}, {{imageResponseFormat}} (b64_json/url), {{imageCount}};
> * output: {{byte[]}} body for a single b64 image, {{List<byte[]>}} or URLs 
> for multiple; response metadata via headers and {{storeFullResponse}}.
> Intended usage:
> {code:java}
> // generate a product image from a description and store it
> 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");
> // edit an existing image coming from S3
> from("aws2-s3:marketing-assets")
>     .setHeader(OpenAIConstants.USER_MESSAGE, 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");
> {code}
> Variations can be a follow-up. Skip suggestion for the same review: 
> {{videos()}} and {{containers()}} services — too niche for now.
> Testing note: unit tests should extend {{camel-test-infra-openai-mock}} with 
> an image-generation expectation (e.g. 
> {{whenImageGeneration()}}/{{replyWithImage(byte[])}} serving a {{b64_json}} 
> payload), like the existing embeddings/transcription mocking — no real model 
> or GPU needed. No mainstream local OpenAI-compatible image backend is 
> CI-suitable today (Ollama's image generation is experimental, macOS-only and 
> has no OpenAI-compatible endpoint; LocalAI works but is heavyweight and 
> amd64-oriented, so an optional IT would need 
> {{skipITs.ppc64le}}/{{skipITs.s390x}}).
> _This issue was drafted by Claude Code on behalf of Federico Mariani_



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to