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, 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, and text-to-speech 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 @@ -47,6 +47,7 @@ See xref:others:openai-responses.adoc[Responses API operation] for usage (`previ
* `audio-transcription` - Transcribe audio files to text using speech-to-text models (e.g., Whisper, GPT-4o Transcribe)
* `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

// component options: START
include::partial$component-configure-options.adoc[]
Expand Down Expand Up @@ -1254,17 +1255,20 @@ 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 and Audio Operations] - Text embeddings, vector database integration, and audio transcription
* xref:others:openai-operations.adoc[Embeddings, Moderation and Audio Operations] - Text embeddings, vector database integration, content moderation, and audio transcription

== Error Handling

The component may throw the following exceptions:

* `IllegalArgumentException`:
** When an invalid operation is specified (supported: `chat-completion`, `embeddings`, `tool-execution`, `audio-transcription`, `audio-translation`, `audio-speech`)
** When an invalid operation is specified (supported: `chat-completion`, `responses`, `embeddings`, `tool-execution`, `audio-transcription`, `audio-translation`, `audio-speech`, `moderation`)
** 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)
* `CamelExchangeException`:
** When moderation returns a number of results that does not match the number of inputs (moderation)
* 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 and Audio Operations
= OpenAI - Embeddings, Moderation and Audio Operations
:tabs-sync-option:

xref:ROOT:openai-component.adoc[Back to OpenAI Component]
Expand Down Expand Up @@ -168,6 +168,112 @@ The following headers are set after an embeddings request:
| `CamelOpenAISimilarityScore` | Double | Cosine similarity (if reference embedding provided)
|===

== Moderation Operation

The `moderation` operation checks text against the OpenAI usage policies. It is the canonical pre-filter for untrusted
input on a public-facing route: rejecting policy-violating content before spending chat tokens or triggering tool calls.

The message body is passed through unchanged and the verdict is exposed as headers, so the result can be used for
content-based routing while the original content stays available to the rest of the route.

=== Guarding a Route

[tabs]
====
Java::
+
[source,java]
----
from("platform-http:/chat")
.to("openai:moderation?moderationModel=omni-moderation-latest")
.choice()
.when(header(OpenAIConstants.MODERATION_FLAGGED).isEqualTo(true))
.setBody(constant("Your message violates our usage policy."))
.otherwise()
.to("openai:chat-completion?model=gpt-5")
.end();
----

YAML::
+
[source,yaml]
----
- from:
uri: platform-http:/chat
steps:
- to: openai:moderation?moderationModel=omni-moderation-latest
- choice:
when:
- simple: "${header.CamelOpenAIModerationFlagged} == true"
steps:
- setBody:
constant: "Your message violates our usage policy."
otherwise:
steps:
- to: openai:chat-completion?model=gpt-5
----
====

=== Batch Moderation

A `List` body moderates every element in a single API call. `CamelOpenAIModerationFlagged` is then `true` when at least
one element was flagged, while the category headers hold one entry per input, in the order of the input list.

The header shape follows the body shape: a `String` body yields `Map` headers and a `List` body yields `List` headers,
including a list with a single element. That way a route processing batches does not have to special-case a batch that
happens to hold one item:

[source,java]
----
from("direct:moderate-batch")
.to("openai:moderation")
.process(exchange -> {
List<Map<String, Boolean>> categories
= exchange.getMessage().getHeader(OpenAIConstants.MODERATION_CATEGORIES, List.class);
// categories.get(0) belongs to the first input, and so on
});
----

=== Moderation Parameters

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

| `moderationModel` | String | `omni-moderation-latest` | The moderation model to use
| `storeFullResponse` | boolean | `false` | Store the full SDK response in the `CamelOpenAIModerationResponse` exchange property
|===

=== Failure Modes

The operation is meant to gate untrusted content, so it fails the exchange rather than letting a message through
without a verdict:

* the API returning a number of results that does not match the number of inputs raises a `CamelExchangeException`,
instead of leaving `CamelOpenAIModerationFlagged` as `false`;
* a missing body, an empty list, or a list containing `null` elements raises an `IllegalArgumentException`.

=== Moderation Output Headers

The following headers are set after a moderation request:

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

| `CamelOpenAIModerationFlagged` | Boolean | Whether the input violates the usage policies. For a batch, `true` when at least one input was flagged
| `CamelOpenAIModerationCategories` | Map/List | Category name to violation flag. A `Map` for a single input, a `List` of maps for a batch
| `CamelOpenAIModerationCategoryScores` | Map/List | Category name to confidence score. A `Map` for a single input, a `List` of maps for a batch
| `CamelOpenAIModerationResponseModel` | String | The model used for moderation
|===

The category names are the ones returned by the API, for example `hate`, `hate/threatening`, `self-harm/intent`,
`sexual/minors` and `violence/graphic`.

NOTE: The `illicit` and `illicit/violent` categories are optional in the API model. OpenAI returns them, but an
xref:others:openai-providers.adoc[OpenAI-compatible provider] may not, in which case they are absent from the
category map. The score map always contains every category.

== Audio Transcription Operation

The `audio-transcription` operation transcribes audio files to text using OpenAI's speech-to-text models (Whisper, GPT-4o Transcribe).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ public boolean configure(CamelContext camelContext, Object obj, String name, Obj
case "mcptoolrefresh":
case "mcpToolRefresh": target.getConfiguration().setMcpToolRefresh(property(camelContext, boolean.class, value)); return true;
case "model": target.getConfiguration().setModel(property(camelContext, java.lang.String.class, value)); return true;
case "moderationmodel":
case "moderationModel": target.getConfiguration().setModerationModel(property(camelContext, java.lang.String.class, value)); return true;
case "oauthprofile":
case "oauthProfile": target.getConfiguration().setOauthProfile(property(camelContext, java.lang.String.class, value)); return true;
case "outputclass":
Expand Down Expand Up @@ -230,6 +232,8 @@ public Class<?> getOptionType(String name, boolean ignoreCase) {
case "mcptoolrefresh":
case "mcpToolRefresh": return boolean.class;
case "model": return java.lang.String.class;
case "moderationmodel":
case "moderationModel": return java.lang.String.class;
case "oauthprofile":
case "oauthProfile": return java.lang.String.class;
case "outputclass":
Expand Down Expand Up @@ -368,6 +372,8 @@ public Object getOptionValue(Object obj, String name, boolean ignoreCase) {
case "mcptoolrefresh":
case "mcpToolRefresh": return target.getConfiguration().isMcpToolRefresh();
case "model": return target.getConfiguration().getModel();
case "moderationmodel":
case "moderationModel": return target.getConfiguration().getModerationModel();
case "oauthprofile":
case "oauthProfile": return target.getConfiguration().getOauthProfile();
case "outputclass":
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<>(68);
Set<String> props = new HashSet<>(69);
props.add("additionalBodyProperty");
props.add("additionalHeader");
props.add("additionalResponseHeader");
Expand Down Expand Up @@ -61,6 +61,7 @@ public class OpenAIEndpointUriFactory extends org.apache.camel.support.component
props.add("mcpTimeout");
props.add("mcpToolRefresh");
props.add("model");
props.add("moderationModel");
props.add("oauthProfile");
props.add("operation");
props.add("outputClass");
Expand Down
Loading