Skip to content

Commit f49327d

Browse files
Add OpenAI extension
Fixes #8203
1 parent e515f4d commit f49327d

37 files changed

+1809
-0
lines changed

catalog/pom.xml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3113,6 +3113,19 @@
31133113
</exclusion>
31143114
</exclusions>
31153115
</dependency>
3116+
<dependency>
3117+
<groupId>org.apache.camel.quarkus</groupId>
3118+
<artifactId>camel-quarkus-openai</artifactId>
3119+
<version>${project.version}</version>
3120+
<type>pom</type>
3121+
<scope>test</scope>
3122+
<exclusions>
3123+
<exclusion>
3124+
<groupId>*</groupId>
3125+
<artifactId>*</artifactId>
3126+
</exclusion>
3127+
</exclusions>
3128+
</dependency>
31163129
<dependency>
31173130
<groupId>org.apache.camel.quarkus</groupId>
31183131
<artifactId>camel-quarkus-openapi-java</artifactId>
@@ -4862,6 +4875,10 @@
48624875
<skipArtifactIdBase>support-.*</skipArtifactIdBase>
48634876
<skipArtifactIdBase>integration-tests?-support-.*</skipArtifactIdBase>
48644877
</skipArtifactIdBases>
4878+
<!-- TODO: Remove this with Camel >= 4.18.0 -->
4879+
<additionalExtensions>
4880+
<additionalExtension>openai</additionalExtension>
4881+
</additionalExtensions>
48654882
</configuration>
48664883
</execution>
48674884
</executions>
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Do not edit directly!
2+
# This file was generated by camel-quarkus-maven-plugin:update-extension-doc-page
3+
cqArtifactId: camel-quarkus-openai
4+
cqArtifactIdBase: openai
5+
cqNativeSupported: true
6+
cqStatus: Stable
7+
cqDeprecated: false
8+
cqJvmSince: 3.32.0
9+
cqNativeSince: 3.32.0
10+
cqCamelPartName: openai
11+
cqCamelPartTitle: OpenAI
12+
cqCamelPartDescription: OpenAI endpoint for chat completion.
13+
cqExtensionPageTitle: OpenAI

docs/modules/ROOT/nav.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@
251251
*** xref:reference/extensions/observability-services.adoc[Observability Services]
252252
*** xref:reference/extensions/olingo4.adoc[Olingo4]
253253
*** xref:reference/extensions/once.adoc[Once]
254+
*** xref:reference/extensions/openai.adoc[OpenAI]
254255
*** xref:reference/extensions/openapi-java.adoc[OpenAPI Java]
255256
*** xref:reference/extensions/opensearch.adoc[OpenSearch]
256257
*** xref:reference/extensions/openstack.adoc[OpenStack]
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// Do not edit directly!
2+
// This file was generated by camel-quarkus-maven-plugin:update-extension-doc-page
3+
[id="extensions-openai"]
4+
= OpenAI
5+
:linkattrs:
6+
:cq-artifact-id: camel-quarkus-openai
7+
:cq-native-supported: true
8+
:cq-status: Stable
9+
:cq-status-deprecation: Stable
10+
:cq-description: OpenAI endpoint for chat completion.
11+
:cq-deprecated: false
12+
:cq-jvm-since: 3.32.0
13+
:cq-native-since: 3.32.0
14+
15+
ifeval::[{doc-show-badges} == true]
16+
[.badges]
17+
[.badge-key]##JVM since##[.badge-supported]##3.32.0## [.badge-key]##Native since##[.badge-supported]##3.32.0##
18+
endif::[]
19+
20+
OpenAI endpoint for chat completion.
21+
22+
[id="extensions-openai-maven-coordinates"]
23+
== Maven coordinates
24+
25+
https://{link-quarkus-code-generator}/?extension-search=camel-quarkus-openai[Create a new project with this extension on {link-quarkus-code-generator}, window="_blank"]
26+
27+
Or add the coordinates to your existing project:
28+
29+
[source,xml]
30+
----
31+
<dependency>
32+
<groupId>org.apache.camel.quarkus</groupId>
33+
<artifactId>camel-quarkus-openai</artifactId>
34+
</dependency>
35+
----
36+
ifeval::[{doc-show-user-guide-link} == true]
37+
Check the xref:user-guide/index.adoc[User guide] for more information about writing Camel Quarkus applications.
38+
endif::[]
39+
40+
[id="extensions-openai-usage"]
41+
== Usage
42+
[id="extensions-openai-usage-structured-output-with-output-class-in-native-mode"]
43+
=== Structured output with output class in native mode
44+
45+
When using structured output with the `outputClass` option in native mode, you must ensure that the target class is registered for reflection.
46+
47+
This can be done with the `@RegisterForReflection` annotation or configuration property `quarkus.camel.native.reflection.include-patterns`. For example:
48+
49+
[source,java]
50+
----
51+
@RegisterForReflection
52+
public class MyStructuredOutputClass {
53+
...
54+
}
55+
----
56+
57+
[source,java]
58+
----
59+
public class Routes extends RouteBuilder {
60+
@Override
61+
public void configure() {
62+
from("direct:chat")
63+
.to("openai:chat-completion?outputClass=" + MyStructuredOutputClass.class.getName());
64+
}
65+
}
66+
----
67+
68+
[id="extensions-openai-usage-structured-output-with-json-schema-from-classpath-resource-in-native-mode"]
69+
=== Structured output with JSON schema from classpath resource in native mode
70+
71+
When loading JSON schema classpath resources in native mode, you must ensure the resource is included in the native application.
72+
73+
For example, given a route like the following.
74+
75+
[source,java]
76+
----
77+
public class Routes extends RouteBuilder {
78+
@Override
79+
public void configure() {
80+
from("direct:chat")
81+
.to("openai:chat-completion?jsonSchema=resource:classpath:schemas/mySchema.json");
82+
}
83+
}
84+
----
85+
86+
Add the following to `application.properties`.
87+
88+
[source,properties]
89+
----
90+
quarkus.native.resources.includes=schemas/mySchema.json
91+
----
92+
93+
Refer to the xref:user-guide/native-mode.adoc#reflection[Native mode] user guide for more information.
94+
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
4+
Licensed to the Apache Software Foundation (ASF) under one or more
5+
contributor license agreements. See the NOTICE file distributed with
6+
this work for additional information regarding copyright ownership.
7+
The ASF licenses this file to You under the Apache License, Version 2.0
8+
(the "License"); you may not use this file except in compliance with
9+
the License. You may obtain a copy of the License at
10+
11+
http://www.apache.org/licenses/LICENSE-2.0
12+
13+
Unless required by applicable law or agreed to in writing, software
14+
distributed under the License is distributed on an "AS IS" BASIS,
15+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
See the License for the specific language governing permissions and
17+
limitations under the License.
18+
19+
-->
20+
<project xmlns="http://maven.apache.org/POM/4.0.0"
21+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
22+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
23+
<modelVersion>4.0.0</modelVersion>
24+
<parent>
25+
<groupId>org.apache.camel.quarkus</groupId>
26+
<artifactId>camel-quarkus-openai-parent</artifactId>
27+
<version>3.32.0-SNAPSHOT</version>
28+
<relativePath>../pom.xml</relativePath>
29+
</parent>
30+
31+
<artifactId>camel-quarkus-openai-deployment</artifactId>
32+
<name>Camel Quarkus :: OpenAI :: Deployment</name>
33+
34+
<dependencies>
35+
<dependency>
36+
<groupId>org.apache.camel.quarkus</groupId>
37+
<artifactId>camel-quarkus-core-deployment</artifactId>
38+
</dependency>
39+
<dependency>
40+
<groupId>org.apache.camel.quarkus</groupId>
41+
<artifactId>camel-quarkus-support-swagger-deployment</artifactId>
42+
</dependency>
43+
<dependency>
44+
<groupId>io.quarkus</groupId>
45+
<artifactId>quarkus-jackson-deployment</artifactId>
46+
</dependency>
47+
<dependency>
48+
<groupId>org.apache.camel.quarkus</groupId>
49+
<artifactId>camel-quarkus-openai</artifactId>
50+
</dependency>
51+
</dependencies>
52+
53+
<build>
54+
<plugins>
55+
<plugin>
56+
<groupId>org.apache.maven.plugins</groupId>
57+
<artifactId>maven-compiler-plugin</artifactId>
58+
<configuration>
59+
<annotationProcessorPaths>
60+
<path>
61+
<groupId>io.quarkus</groupId>
62+
<artifactId>quarkus-extension-processor</artifactId>
63+
<version>${quarkus.version}</version>
64+
</path>
65+
</annotationProcessorPaths>
66+
</configuration>
67+
</plugin>
68+
</plugins>
69+
</build>
70+
71+
</project>
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.camel.quarkus.component.openai.deployment;
18+
19+
import java.util.Set;
20+
import java.util.stream.Collectors;
21+
import java.util.stream.Stream;
22+
23+
import com.openai.core.JsonField;
24+
import com.openai.core.JsonValue;
25+
import com.openai.models.chat.completions.ChatCompletion;
26+
import com.openai.models.chat.completions.ChatCompletionChunk;
27+
import io.quarkus.deployment.Capabilities;
28+
import io.quarkus.deployment.Capability;
29+
import io.quarkus.deployment.annotations.BuildProducer;
30+
import io.quarkus.deployment.annotations.BuildStep;
31+
import io.quarkus.deployment.builditem.CombinedIndexBuildItem;
32+
import io.quarkus.deployment.builditem.FeatureBuildItem;
33+
import io.quarkus.deployment.builditem.IndexDependencyBuildItem;
34+
import io.quarkus.deployment.builditem.RemovedResourceBuildItem;
35+
import io.quarkus.deployment.builditem.nativeimage.NativeImageResourcePatternsBuildItem;
36+
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
37+
import io.quarkus.deployment.builditem.nativeimage.ReflectiveHierarchyBuildItem;
38+
import io.quarkus.deployment.pkg.steps.NativeOrNativeSourcesBuild;
39+
import io.quarkus.jackson.deployment.IgnoreJsonDeserializeClassBuildItem;
40+
import io.quarkus.maven.dependency.ArtifactKey;
41+
import org.jboss.jandex.ClassInfo;
42+
import org.jboss.jandex.DotName;
43+
import org.jboss.jandex.Type;
44+
45+
class OpenaiProcessor {
46+
private static final String FEATURE = "camel-openai";
47+
48+
@BuildStep
49+
FeatureBuildItem feature() {
50+
return new FeatureBuildItem(FEATURE);
51+
}
52+
53+
@BuildStep(onlyIf = NativeOrNativeSourcesBuild.class)
54+
IndexDependencyBuildItem indexDependencies() {
55+
return new IndexDependencyBuildItem("com.openai", "openai-java-core");
56+
}
57+
58+
@BuildStep(onlyIf = NativeOrNativeSourcesBuild.class)
59+
void registerForReflection(
60+
Capabilities capabilities,
61+
CombinedIndexBuildItem combinedIndex,
62+
BuildProducer<IgnoreJsonDeserializeClassBuildItem> ignoredJsonDeserializeClass,
63+
BuildProducer<ReflectiveClassBuildItem> reflectiveClass,
64+
BuildProducer<ReflectiveHierarchyBuildItem> reflectiveHierarchy,
65+
BuildProducer<NativeImageResourcePatternsBuildItem> nativeResourcePatterns) {
66+
67+
reflectiveHierarchy.produce(ReflectiveHierarchyBuildItem
68+
.builder(Type.create(ChatCompletion.class)).ignoreNested(false)
69+
.build());
70+
71+
reflectiveHierarchy.produce(ReflectiveHierarchyBuildItem
72+
.builder(Type.create(ChatCompletionChunk.class)).ignoreNested(false)
73+
.build());
74+
75+
// Make quarkus-kotlin optional since not everything it provides is required
76+
if (capabilities.isMissing(Capability.KOTLIN)) {
77+
Stream.of(JsonField.class.getName(), JsonValue.class.getName())
78+
.map(DotName::createSimple)
79+
.forEach(className -> {
80+
// Suppress quarkus-jackson adding its own reflective config for JsonDeserialize so we can add our own
81+
ignoredJsonDeserializeClass.produce(new IgnoreJsonDeserializeClassBuildItem(className));
82+
reflectiveHierarchy.produce(ReflectiveHierarchyBuildItem
83+
.builder(Type.create(className, Type.Kind.CLASS)).ignoreNested(false)
84+
.build());
85+
});
86+
87+
Set<String> openAIModelClassNames = combinedIndex.getIndex()
88+
.getKnownClasses()
89+
.stream()
90+
.map(ClassInfo::name)
91+
.map(DotName::toString)
92+
.filter(className -> className.startsWith("com.openai.models"))
93+
.collect(Collectors.toSet());
94+
95+
reflectiveClass.produce(ReflectiveClassBuildItem.builder(openAIModelClassNames.toArray(new String[0]))
96+
.fields()
97+
.methods()
98+
.build());
99+
100+
nativeResourcePatterns.produce(NativeImageResourcePatternsBuildItem.builder()
101+
.includeGlobs("META-INF/**/*.kotlin_module",
102+
"META-INF/services/kotlin.reflect.*",
103+
"**/*.kotlin_builtins")
104+
.build());
105+
}
106+
}
107+
108+
@BuildStep(onlyIf = NativeOrNativeSourcesBuild.class)
109+
RemovedResourceBuildItem excludeNativeImageDirectives() {
110+
// Remove all native-image directives from openai-java-core as it's mostly redundant & inaccurate for Quarkus
111+
return new RemovedResourceBuildItem(
112+
ArtifactKey.fromString("com.openai:openai-java-core"),
113+
Set.of(
114+
"META-INF/native-image/jni-config.json",
115+
"META-INF/native-image/predefined-classes-config.json",
116+
"META-INF/native-image/proxy-config.json",
117+
"META-INF/native-image/reflect-config.json",
118+
"META-INF/native-image/resource-config.json",
119+
"META-INF/native-image/serialization-config.json"));
120+
}
121+
}

extensions/openai/pom.xml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
4+
Licensed to the Apache Software Foundation (ASF) under one or more
5+
contributor license agreements. See the NOTICE file distributed with
6+
this work for additional information regarding copyright ownership.
7+
The ASF licenses this file to You under the Apache License, Version 2.0
8+
(the "License"); you may not use this file except in compliance with
9+
the License. You may obtain a copy of the License at
10+
11+
http://www.apache.org/licenses/LICENSE-2.0
12+
13+
Unless required by applicable law or agreed to in writing, software
14+
distributed under the License is distributed on an "AS IS" BASIS,
15+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16+
See the License for the specific language governing permissions and
17+
limitations under the License.
18+
19+
-->
20+
<project xmlns="http://maven.apache.org/POM/4.0.0"
21+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
22+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
23+
<modelVersion>4.0.0</modelVersion>
24+
<parent>
25+
<groupId>org.apache.camel.quarkus</groupId>
26+
<artifactId>camel-quarkus-extensions</artifactId>
27+
<version>3.32.0-SNAPSHOT</version>
28+
<relativePath>../pom.xml</relativePath>
29+
</parent>
30+
31+
<artifactId>camel-quarkus-openai-parent</artifactId>
32+
<name>Camel Quarkus :: OpenAI</name>
33+
<packaging>pom</packaging>
34+
35+
<modules>
36+
<module>deployment</module>
37+
<module>runtime</module>
38+
</modules>
39+
</project>

0 commit comments

Comments
 (0)