diff --git a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/openai.json b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/openai.json index 1858c1a803cd9..fb7741eb5c594 100644 --- a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/openai.json +++ b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/openai.json @@ -68,7 +68,7 @@ "developerMessage": { "index": 6, "kind": "parameter", "displayName": "Developer Message", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Developer message to prepend before user messages" }, "dimensions": { "index": 7, "kind": "parameter", "displayName": "Dimensions", "group": "producer", "label": "", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Number of dimensions for the embedding output. Only supported by text-embedding-3 models. Reducing dimensions can lower costs and improve performance without significant quality loss." }, "embeddingModel": { "index": 8, "kind": "parameter", "displayName": "Embedding Model", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "The model to use for embeddings" }, - "encodingFormat": { "index": 9, "kind": "parameter", "displayName": "Encoding Format", "group": "producer", "label": "", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "float", "base64" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "float", "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "The format for embedding output: 'float' for list of floats, 'base64' for compressed format" }, + "encodingFormat": { "index": 9, "kind": "parameter", "displayName": "Encoding Format", "group": "producer", "label": "", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "float", "base64" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "base64", "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "The format for embedding output: 'float' for list of floats, 'base64' for compressed format" }, "jsonSchema": { "index": 10, "kind": "parameter", "displayName": "Json Schema", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "supportFileReference": true, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "JSON schema for structured output validation" }, "maxTokens": { "index": 11, "kind": "parameter", "displayName": "Max Tokens", "group": "producer", "label": "", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Maximum number of tokens to generate" }, "model": { "index": 12, "kind": "parameter", "displayName": "Model", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "The model to use for chat completion" }, diff --git a/components/camel-ai/camel-openai/src/generated/resources/META-INF/org/apache/camel/component/openai/openai.json b/components/camel-ai/camel-openai/src/generated/resources/META-INF/org/apache/camel/component/openai/openai.json index 1858c1a803cd9..fb7741eb5c594 100644 --- a/components/camel-ai/camel-openai/src/generated/resources/META-INF/org/apache/camel/component/openai/openai.json +++ b/components/camel-ai/camel-openai/src/generated/resources/META-INF/org/apache/camel/component/openai/openai.json @@ -68,7 +68,7 @@ "developerMessage": { "index": 6, "kind": "parameter", "displayName": "Developer Message", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Developer message to prepend before user messages" }, "dimensions": { "index": 7, "kind": "parameter", "displayName": "Dimensions", "group": "producer", "label": "", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Number of dimensions for the embedding output. Only supported by text-embedding-3 models. Reducing dimensions can lower costs and improve performance without significant quality loss." }, "embeddingModel": { "index": 8, "kind": "parameter", "displayName": "Embedding Model", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "The model to use for embeddings" }, - "encodingFormat": { "index": 9, "kind": "parameter", "displayName": "Encoding Format", "group": "producer", "label": "", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "float", "base64" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "float", "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "The format for embedding output: 'float' for list of floats, 'base64' for compressed format" }, + "encodingFormat": { "index": 9, "kind": "parameter", "displayName": "Encoding Format", "group": "producer", "label": "", "required": false, "type": "enum", "javaType": "java.lang.String", "enum": [ "float", "base64" ], "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "defaultValue": "base64", "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "The format for embedding output: 'float' for list of floats, 'base64' for compressed format" }, "jsonSchema": { "index": 10, "kind": "parameter", "displayName": "Json Schema", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "supportFileReference": true, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "JSON schema for structured output validation" }, "maxTokens": { "index": 11, "kind": "parameter", "displayName": "Max Tokens", "group": "producer", "label": "", "required": false, "type": "integer", "javaType": "java.lang.Integer", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "Maximum number of tokens to generate" }, "model": { "index": 12, "kind": "parameter", "displayName": "Model", "group": "producer", "label": "", "required": false, "type": "string", "javaType": "java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": false, "secret": false, "configurationClass": "org.apache.camel.component.openai.OpenAIConfiguration", "configurationField": "configuration", "description": "The model to use for chat completion" }, diff --git a/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIConfiguration.java b/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIConfiguration.java index 32b9907c7beb7..6d588fb12d0e6 100644 --- a/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIConfiguration.java +++ b/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIConfiguration.java @@ -107,9 +107,9 @@ public class OpenAIConfiguration implements Cloneable { "Reducing dimensions can lower costs and improve performance without significant quality loss.") private Integer dimensions; - @UriParam(enums = "float,base64", defaultValue = "float") + @UriParam(enums = "float,base64", defaultValue = "base64") @Metadata(description = "The format for embedding output: 'float' for list of floats, 'base64' for compressed format") - private String encodingFormat = "float"; + private String encodingFormat = "base64"; public String getApiKey() { return apiKey; diff --git a/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIEmbeddingsProducer.java b/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIEmbeddingsProducer.java index 65bbe3809565a..26488e697f068 100644 --- a/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIEmbeddingsProducer.java +++ b/components/camel-ai/camel-openai/src/main/java/org/apache/camel/component/openai/OpenAIEmbeddingsProducer.java @@ -25,6 +25,7 @@ import com.openai.models.embeddings.CreateEmbeddingResponse; import com.openai.models.embeddings.Embedding; import com.openai.models.embeddings.EmbeddingCreateParams; +import com.openai.models.embeddings.EmbeddingCreateParams.EncodingFormat; import org.apache.camel.AsyncCallback; import org.apache.camel.Exchange; import org.apache.camel.Message; @@ -92,6 +93,10 @@ private void processInternal(Exchange exchange) throws Exception { paramsBuilder.dimensions(dimensions.longValue()); } + if (ObjectHelper.isNotEmpty(config.getEncodingFormat())) { + paramsBuilder.encodingFormat(EncodingFormat.of(config.getEncodingFormat())); + } + EmbeddingCreateParams params = paramsBuilder.build(); // Execute request diff --git a/components/camel-ai/camel-openai/src/test/java/org/apache/camel/component/openai/integration/OpenAIEmbeddingsIT.java b/components/camel-ai/camel-openai/src/test/java/org/apache/camel/component/openai/integration/OpenAIEmbeddingsIT.java index 2f7a84847db2a..45cf8ec8a28b7 100644 --- a/components/camel-ai/camel-openai/src/test/java/org/apache/camel/component/openai/integration/OpenAIEmbeddingsIT.java +++ b/components/camel-ai/camel-openai/src/test/java/org/apache/camel/component/openai/integration/OpenAIEmbeddingsIT.java @@ -85,6 +85,10 @@ public void configure() { from("direct:embedding") .to("openai:embeddings") .to("mock:response"); + + from("direct:embeddingWithEncodingFormatFloat") + .to("openai:embeddings?encodingFormat=float") + .to("mock:responseEncodingFormatFloat"); } }; } @@ -116,6 +120,33 @@ public void testSingleTextEmbedding() throws Exception { .isEqualTo("Apache Camel is an integration framework"); } + @Test + public void testSingleTextEmbeddingWithFloatEncodingFormat() throws Exception { + MockEndpoint mockResponse = getMockEndpoint("mock:responseEncodingFormatFloat"); + mockResponse.expectedMessageCount(1); + + Exchange result = template.request("direct:embeddingWithEncodingFormatFloat", + e -> e.getIn().setBody("Apache Camel is an integration framework")); + + mockResponse.assertIsSatisfied(); + + assertThat(result).isNotNull(); + Object body = result.getMessage().getBody(); + assertThat(body).isNotNull(); + assertThat(body).isInstanceOf(List.class); + + @SuppressWarnings("unchecked") + List embedding = (List) body; + assertThat(embedding).isNotEmpty(); + + // Verify headers + assertThat(result.getMessage().getHeader(OpenAIConstants.EMBEDDING_COUNT)).isEqualTo(1); + assertThat(result.getMessage().getHeader(OpenAIConstants.EMBEDDING_VECTOR_SIZE, Integer.class)) + .isGreaterThan(0); + assertThat(result.getMessage().getHeader(OpenAIConstants.ORIGINAL_TEXT)) + .isEqualTo("Apache Camel is an integration framework"); + } + @Test public void testBatchTextEmbeddings() throws Exception { MockEndpoint mockResponse = getMockEndpoint("mock:response"); diff --git a/components/camel-ai/camel-openai/src/test/resources/log4j2.properties b/components/camel-ai/camel-openai/src/test/resources/log4j2.properties new file mode 100644 index 0000000000000..8f3be64cbf154 --- /dev/null +++ b/components/camel-ai/camel-openai/src/test/resources/log4j2.properties @@ -0,0 +1,30 @@ +## --------------------------------------------------------------------------- +## Licensed to the Apache Software Foundation (ASF) under one or more +## contributor license agreements. See the NOTICE file distributed with +## this work for additional information regarding copyright ownership. +## The ASF licenses this file to You under the Apache License, Version 2.0 +## (the "License"); you may not use this file except in compliance with +## the License. You may obtain a copy of the License at +## +## http://www.apache.org/licenses/LICENSE-2.0 +## +## Unless required by applicable law or agreed to in writing, software +## distributed under the License is distributed on an "AS IS" BASIS, +## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +## See the License for the specific language governing permissions and +## limitations under the License. +## --------------------------------------------------------------------------- + +appender.file.type = File +appender.file.name = file +appender.file.fileName = target/camel-openai-tests.log +appender.file.layout.type = PatternLayout +appender.file.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n + +appender.out.type = Console +appender.out.name = out +appender.out.layout.type = PatternLayout +appender.out.layout.pattern = [%30.30t] %-30.30c{1} %-5p %m%n + +rootLogger.level = INFO +rootLogger.appenderRef.file.ref = file diff --git a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/OpenAIEndpointBuilderFactory.java b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/OpenAIEndpointBuilderFactory.java index 6164c32a9fb0a..e2f733d788a06 100644 --- a/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/OpenAIEndpointBuilderFactory.java +++ b/dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/OpenAIEndpointBuilderFactory.java @@ -228,7 +228,7 @@ default OpenAIEndpointBuilder embeddingModel(String embeddingModel) { * * The option is a: java.lang.String type. * - * Default: float + * Default: base64 * Group: producer * * @param encodingFormat the value to set