diff --git a/camelBase/pom.xml b/camelBase/pom.xml index 514b5ddc..9eb6f9ff 100644 --- a/camelBase/pom.xml +++ b/camelBase/pom.xml @@ -97,6 +97,11 @@ org.apache.camel camel-jq + + org.apache.camel + camel-langchain4j-chat + + org.apache.camel camel-language diff --git a/commonBase/pom.xml b/commonBase/pom.xml index c7afc299..fd9765e2 100644 --- a/commonBase/pom.xml +++ b/commonBase/pom.xml @@ -283,6 +283,18 @@ + + + dev.langchain4j + langchain4j + ${langchain4j.version} + + + dev.langchain4j + langchain4j-google-ai-gemini + ${langchain4j-google-ai-gemini.version} + + \ No newline at end of file diff --git a/dil/pom.xml b/dil/pom.xml index e30b2a6b..4dd91860 100644 --- a/dil/pom.xml +++ b/dil/pom.xml @@ -50,6 +50,21 @@ ${activemq-classic.version} compile + + dev.langchain4j + langchain4j + 1.10.0 + + + dev.langchain4j + langchain4j-core + 1.10.0 + + + dev.langchain4j + langchain4j-google-ai-gemini + 1.10.0 + diff --git a/dil/src/main/java/org/assimbly/dil/blocks/connections/Connection.java b/dil/src/main/java/org/assimbly/dil/blocks/connections/Connection.java index 171b40a5..3260d3c3 100644 --- a/dil/src/main/java/org/assimbly/dil/blocks/connections/Connection.java +++ b/dil/src/main/java/org/assimbly/dil/blocks/connections/Connection.java @@ -68,6 +68,9 @@ private void startConnection() throws Exception{ case "rabbitmq", "spring-rabbitmq" -> new RabbitMQConnection(context, decryptedProperties, connectionId, "spring-rabbitmq").start(); + case "langchain4j" -> + new LangChain4jConnection(context, decryptedProperties, connectionId).start(); + case "ibmq" -> new IBMMQConnection(context, decryptedProperties, connectionId, connectionType).start(); diff --git a/dil/src/main/java/org/assimbly/dil/blocks/connections/broker/LangChain4jConnection.java b/dil/src/main/java/org/assimbly/dil/blocks/connections/broker/LangChain4jConnection.java new file mode 100644 index 00000000..108bcac1 --- /dev/null +++ b/dil/src/main/java/org/assimbly/dil/blocks/connections/broker/LangChain4jConnection.java @@ -0,0 +1,83 @@ +package org.assimbly.dil.blocks.connections.broker; + +import org.apache.camel.CamelContext; +import org.jasypt.properties.EncryptableProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import dev.langchain4j.model.chat.ChatModel; +import dev.langchain4j.model.googleai.GoogleAiGeminiChatModel; +import java.time.Duration; + +public class LangChain4jConnection { + + protected Logger log = LoggerFactory.getLogger(getClass()); + + private final CamelContext context; + private final EncryptableProperties properties; + private final String connectionId; + + private String apiKey; + private String modelName; + private String timeout; + + public LangChain4jConnection(CamelContext context, EncryptableProperties properties, String connectionId) { + this.context = context; + this.properties = properties; + this.connectionId = connectionId; + } + + public void start() { + setFields(); + + if (checkConnection()) { + log.info("Creating new LangChain4j GoogleAiGeminiChatModel connection with id={}", connectionId); + setConnection(); + } else { + log.info("Reuse LangChain4j GoogleAiGeminiChatModel connection with id={}", connectionId); + } + } + + private void setFields() { + apiKey = properties.getProperty("connection." + connectionId + ".apikey"); + modelName = properties.getProperty("connection." + connectionId + ".modelname"); + timeout = properties.getProperty("connection." + connectionId + ".timeout"); + } + + private boolean checkConnection() { + Object isRegistered = context.getRegistry().lookupByName(connectionId); + if (isRegistered != null) { + return false; + } + + if (apiKey == null || apiKey.isEmpty()) { + throw new IllegalArgumentException("LangChain4j connection parameters are invalid. apikey is required"); + } + + return true; + } + + private void setConnection() { + log.info("Setting up LangChain4j GoogleAiGeminiChatModel connection. API Key length: {}, prefix: {}", + apiKey != null ? apiKey.length() : 0, + apiKey != null && apiKey.length() >= 5 ? apiKey.substring(0, 5) : "N/A"); + + String resolvedModel = (modelName != null && !modelName.isEmpty()) ? modelName : "gemini-3-flash-preview"; + long resolvedTimeout = 10; + if (timeout != null && !timeout.isEmpty()) { + try { + resolvedTimeout = Long.parseLong(timeout); + } catch (NumberFormatException e) { + log.warn("Invalid timeout value '{}', using default 10s", timeout); + } + } + + ChatModel chatModel = GoogleAiGeminiChatModel.builder() + .apiKey(apiKey) + .modelName(resolvedModel) + .timeout(Duration.ofSeconds(resolvedTimeout)) + .build(); + + context.getRegistry().bind(connectionId, chatModel); + log.info("Successfully bound LangChain4j ChatModel bean with id={} to the Camel registry", connectionId); + } +} diff --git a/dil/src/main/resources/kamelets/langchain4j-chat-action.kamelet.yaml b/dil/src/main/resources/kamelets/langchain4j-chat-action.kamelet.yaml new file mode 100644 index 00000000..af460207 --- /dev/null +++ b/dil/src/main/resources/kamelets/langchain4j-chat-action.kamelet.yaml @@ -0,0 +1,52 @@ +apiVersion: "camel.apache.org/v1" +kind: "Kamelet" +metadata: + name: "langchain4j-chat-action" + labels: + camel.apache.org/kamelet.type: "action" +spec: + definition: + title: "langchain4j-chat action" + description: "chat component for langchain4j" + type: "object" + properties: + path: + title: "Path" + description: "Path" + type: "string" + in: + title: "Source Endpoint" + type: "string" + default: "kamelet:source" + out: + title: "Sink Endpoint" + type: "string" + default: "kamelet:sink" + routeId: + title: "Route ID" + type: "string" + routeConfigurationId: + title: "Route Configuration ID" + type: "string" + default: "0" + chatModel: + title: "Chat Model Bean Name" + type: "string" + default: "#geminiChatModel" + dependencies: + - "camel:kamelet" + template: + route: + routeConfigurationId: "{{routeConfigurationId}}" + from: + uri: "{{in}}" + steps: + - step: + id: "{{routeId}}" + steps: + - convertBodyTo: + type: String + - to: + uri: "langchain4j-chat://{{routeId}}?chatModel={{chatModel}}" + - to: + uri: "{{out}}" diff --git a/pom.xml b/pom.xml index 55819cea..a293e2fb 100644 --- a/pom.xml +++ b/pom.xml @@ -58,6 +58,8 @@ 3.1.2 2.1.4 3.0.0 + 0.36.2 + 1.10.0 2.1.3 6.1.0 3.0.2