k-krawczyk opened a new pull request, #25489: URL: https://github.com/apache/camel/pull/25489
# Description Adds the `image-generation` and `image-edit` operations to `camel-openai`, closing [CAMEL-23967](https://issues.apache.org/jira/browse/CAMEL-23967). ```java // generate a product image 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 image coming from object storage 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"); ``` ## Two deviations from the issue **`imageResponseFormat` has no default and is only sent when set.** 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, and `/v1/models` no longer lists any DALL-E model. The option is kept because OpenAI-compatible providers still implement the older images API, where `url` is often the default — but a default value here would break every route against OpenAI, so there is none. **The body shape follows the response, not the option.** Base64 payloads are decoded into `byte[]`, URLs stay as `String`. 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. ## What it adds - `imageModel`, `imagePrompt`, `imageSize`, `imageQuality`, `imageResponseFormat`, `imageCount`, `imageBackground`, `imageOutputFormat`, `imageOutputCompression`, `imageStyle`, `imageModeration`, `imageInputFidelity` — each overridable per exchange by a header. - `image-edit` takes the image from the body as `File`, `Path`, `InputStream`, `byte[]`, or a `List` of those, since the GPT image models accept up to 16 reference images. An optional mask goes through `CamelOpenAIImageMask`. - `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 unchanged. - The multipart parts of an edit declare their content type. The API validates the upload on that content type rather than on the file name, and the SDK leaves it as `text/plain` unless it is set, so an edit is rejected without this. It is resolved from the usual MIME type detection, then from the extension of a `File`/`Path` body, and falls back to `image/png` for anything the API does not accept. - Revised prompt and token usage as headers; `storeFullResponse=true` keeps the full SDK response in `CamelOpenAIImageResponse`. Left out, as the issue suggests: `createVariation` and the streaming variants. ## Testing `camel-test-infra-openai-mock` gained `whenImageGeneration()`, `whenImageEdit()`, `replyWithImage(byte[])`, `replyWithImageUrl(String)`, `withRevisedPrompt()`, `withImageOutputFormat()`, `withImageSize()`, `withImageUsage()` and `assertImageRequest()`. 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, which is enough to verify that several images and a mask reach the wire. 24 unit tests, no model and no GPU involved. Beyond the mock, both operations were also exercised against the real OpenAI API once, which is what surfaced the multipart content type and the state of `response_format`. That smoke test is not part of the contribution — there is no CI-suitable local image backend, as the issue notes — but the multipart content type is now asserted in the mock tests. _Reported by Claude Code on behalf of Karol Krawczyk_ -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
