You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ac...@apache.org on 2024/03/13 09:42:41 UTC
(camel) 01/01: CAMEL-20560 - Camel-AWS-Bedrock: Support Anthropic models
This is an automated email from the ASF dual-hosted git repository.
acosentino pushed a commit to branch CAMEL-20560
in repository https://gitbox.apache.org/repos/asf/camel.git
commit b3d453b4ed3a4d19bc5bf3195f8ccd80f63ca075
Author: Andrea Cosentino <an...@gmail.com>
AuthorDate: Wed Mar 13 10:30:23 2024 +0100
CAMEL-20560 - Camel-AWS-Bedrock: Support Anthropic models
Signed-off-by: Andrea Cosentino <an...@gmail.com>
---
.../component/aws2/bedrock/BedrockModels.java | 5 +-
.../aws2/bedrock/runtime/BedrockProducer.java | 26 ++++
.../runtime/integration/BedrockProducerIT.java | 150 ++++++++++++++++++++-
3 files changed, 174 insertions(+), 7 deletions(-)
diff --git a/components/camel-aws/camel-aws-bedrock/src/main/java/org/apache/camel/component/aws2/bedrock/BedrockModels.java b/components/camel-aws/camel-aws-bedrock/src/main/java/org/apache/camel/component/aws2/bedrock/BedrockModels.java
index ef994e22ff5..d8d9bf561a9 100644
--- a/components/camel-aws/camel-aws-bedrock/src/main/java/org/apache/camel/component/aws2/bedrock/BedrockModels.java
+++ b/components/camel-aws/camel-aws-bedrock/src/main/java/org/apache/camel/component/aws2/bedrock/BedrockModels.java
@@ -25,8 +25,9 @@ public enum BedrockModels {
JURASSIC2_ULTRA("ai21.j2-ultra-v1"),
JURASSIC2_MID("ai21.j2-mid-v1"),
ANTROPHIC_CLAUDE_INSTANT_V1("anthropic.claude-instant-v1"),
- ANTROPHIC_CLAUDE_INSTANT_V2("anthropic.claude-v2"),
- ANTROPHIC_CLAUDE_INSTANT_V2_1("anthropic.claude-v2:1");
+ ANTROPHIC_CLAUDE_V2("anthropic.claude-v2"),
+ ANTROPHIC_CLAUDE_V2_1("anthropic.claude-v2:1"),
+ ANTROPHIC_CLAUDE_V3("anthropic.claude-3-sonnet-20240229-v1:0");
public final String model;
diff --git a/components/camel-aws/camel-aws-bedrock/src/main/java/org/apache/camel/component/aws2/bedrock/runtime/BedrockProducer.java b/components/camel-aws/camel-aws-bedrock/src/main/java/org/apache/camel/component/aws2/bedrock/runtime/BedrockProducer.java
index e79c7138234..e553972684f 100644
--- a/components/camel-aws/camel-aws-bedrock/src/main/java/org/apache/camel/component/aws2/bedrock/runtime/BedrockProducer.java
+++ b/components/camel-aws/camel-aws-bedrock/src/main/java/org/apache/camel/component/aws2/bedrock/runtime/BedrockProducer.java
@@ -242,6 +242,20 @@ public class BedrockProducer extends DefaultProducer {
throw new RuntimeException(e);
}
}
+ case "anthropic.claude-instant-v1", "anthropic.claude-v2", "anthropic.claude-v2:1" -> {
+ try {
+ setAnthropicText(result, message);
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ case "anthropic.claude-3-sonnet-20240229-v1:0" -> {
+ try {
+ setAnthropicV3Text(result, message);
+ } catch (JsonProcessingException e) {
+ throw new RuntimeException(e);
+ }
+ }
default -> throw new IllegalStateException("Unexpected value: " + getConfiguration().getModelId());
}
}
@@ -256,6 +270,18 @@ public class BedrockProducer extends DefaultProducer {
message.setBody(jsonString.get("completions"));
}
+ private void setAnthropicText(InvokeModelResponse result, Message message) throws JsonProcessingException {
+ ObjectMapper mapper = new ObjectMapper();
+ JsonNode jsonString = mapper.readTree(result.body().asUtf8String());
+ message.setBody(jsonString.get("completion"));
+ }
+
+ private void setAnthropicV3Text(InvokeModelResponse result, Message message) throws JsonProcessingException {
+ ObjectMapper mapper = new ObjectMapper();
+ JsonNode jsonString = mapper.readTree(result.body().asUtf8String());
+ message.setBody(jsonString);
+ }
+
public static Message getMessageForResponse(final Exchange exchange) {
return exchange.getMessage();
}
diff --git a/components/camel-aws/camel-aws-bedrock/src/test/java/org/apache/camel/component/aws2/bedrock/runtime/integration/BedrockProducerIT.java b/components/camel-aws/camel-aws-bedrock/src/test/java/org/apache/camel/component/aws2/bedrock/runtime/integration/BedrockProducerIT.java
index aa2044461e3..bfe93173df8 100644
--- a/components/camel-aws/camel-aws-bedrock/src/test/java/org/apache/camel/component/aws2/bedrock/runtime/integration/BedrockProducerIT.java
+++ b/components/camel-aws/camel-aws-bedrock/src/test/java/org/apache/camel/component/aws2/bedrock/runtime/integration/BedrockProducerIT.java
@@ -17,10 +17,7 @@
package org.apache.camel.component.aws2.bedrock.runtime.integration;
import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.node.ArrayNode;
-import com.fasterxml.jackson.databind.node.IntNode;
-import com.fasterxml.jackson.databind.node.ObjectNode;
-import com.fasterxml.jackson.databind.node.TextNode;
+import com.fasterxml.jackson.databind.node.*;
import org.apache.camel.EndpointInject;
import org.apache.camel.Exchange;
import org.apache.camel.ProducerTemplate;
@@ -220,6 +217,125 @@ class BedrockProducerIT extends CamelTestSupport {
MockEndpoint.assertIsSatisfied(context);
}
+ @Test
+ public void testInvokeAnthropicV1Model() throws InterruptedException {
+
+ result.expectedMessageCount(1);
+ final Exchange result = template.send("direct:send_anthropic_v1_model", exchange -> {
+ ObjectMapper mapper = new ObjectMapper();
+ ObjectNode rootNode = mapper.createObjectNode();
+ rootNode.putIfAbsent("prompt",
+ new TextNode("Human: Can you tell the history of Mayflower? \\n\\Assistant:"));
+
+ ArrayNode stopSequences = mapper.createArrayNode();
+ stopSequences.add("Human:");
+ rootNode.putIfAbsent("max_tokens_to_sample", new IntNode(300));
+ rootNode.putIfAbsent("stop_sequences", stopSequences);
+ rootNode.putIfAbsent("temperature", new DoubleNode(0.5));
+ rootNode.putIfAbsent("top_p", new IntNode(1));
+ rootNode.putIfAbsent("top_k", new IntNode(250));
+ rootNode.putIfAbsent("anthropic_version", new TextNode("bedrock-2023-05-31"));
+
+ exchange.getMessage().setBody(mapper.writer().writeValueAsString(rootNode));
+ exchange.getMessage().setHeader(BedrockConstants.MODEL_CONTENT_TYPE, "application/json");
+ exchange.getMessage().setHeader(BedrockConstants.MODEL_ACCEPT_CONTENT_TYPE, "application/json");
+ });
+
+ MockEndpoint.assertIsSatisfied(context);
+ }
+
+ @Test
+ public void testInvokeAnthropicV2Model() throws InterruptedException {
+
+ result.expectedMessageCount(1);
+ final Exchange result = template.send("direct:send_anthropic_v2_model", exchange -> {
+ ObjectMapper mapper = new ObjectMapper();
+ ObjectNode rootNode = mapper.createObjectNode();
+ rootNode.putIfAbsent("prompt",
+ new TextNode("Human: Can you tell the history of Mayflower? \\n\\Assistant:"));
+
+ ArrayNode stopSequences = mapper.createArrayNode();
+ stopSequences.add("Human:");
+ rootNode.putIfAbsent("max_tokens_to_sample", new IntNode(300));
+ rootNode.putIfAbsent("stop_sequences", stopSequences);
+ rootNode.putIfAbsent("temperature", new DoubleNode(0.5));
+ rootNode.putIfAbsent("top_p", new IntNode(1));
+ rootNode.putIfAbsent("top_k", new IntNode(250));
+ rootNode.putIfAbsent("anthropic_version", new TextNode("bedrock-2023-05-31"));
+
+ exchange.getMessage().setBody(mapper.writer().writeValueAsString(rootNode));
+ exchange.getMessage().setHeader(BedrockConstants.MODEL_CONTENT_TYPE, "application/json");
+ exchange.getMessage().setHeader(BedrockConstants.MODEL_ACCEPT_CONTENT_TYPE, "application/json");
+ });
+
+ MockEndpoint.assertIsSatisfied(context);
+ }
+
+ @Test
+ public void testInvokeAnthropicV21Model() throws InterruptedException {
+
+ result.expectedMessageCount(1);
+ final Exchange result = template.send("direct:send_anthropic_v21_model", exchange -> {
+ ObjectMapper mapper = new ObjectMapper();
+ ObjectNode rootNode = mapper.createObjectNode();
+ rootNode.putIfAbsent("prompt",
+ new TextNode("Human: Can you tell the history of Mayflower? \\n\\Assistant:"));
+
+ ArrayNode stopSequences = mapper.createArrayNode();
+ stopSequences.add("Human:");
+ rootNode.putIfAbsent("max_tokens_to_sample", new IntNode(300));
+ rootNode.putIfAbsent("stop_sequences", stopSequences);
+ rootNode.putIfAbsent("temperature", new DoubleNode(0.5));
+ rootNode.putIfAbsent("top_p", new IntNode(1));
+ rootNode.putIfAbsent("top_k", new IntNode(250));
+ rootNode.putIfAbsent("anthropic_version", new TextNode("bedrock-2023-05-31"));
+
+ exchange.getMessage().setBody(mapper.writer().writeValueAsString(rootNode));
+ exchange.getMessage().setHeader(BedrockConstants.MODEL_CONTENT_TYPE, "application/json");
+ exchange.getMessage().setHeader(BedrockConstants.MODEL_ACCEPT_CONTENT_TYPE, "application/json");
+ });
+
+ MockEndpoint.assertIsSatisfied(context);
+ }
+
+ @Test
+ public void testInvokeAnthropicV3Model() throws InterruptedException {
+
+ result.expectedMessageCount(1);
+ final Exchange result = template.send("direct:send_anthropic_v3_model", exchange -> {
+ ObjectMapper mapper = new ObjectMapper();
+ ObjectNode rootNode = mapper.createObjectNode();
+
+ ArrayNode messages = mapper.createArrayNode();
+
+ ObjectNode element = mapper.createObjectNode();
+ element.putIfAbsent("role", new TextNode("user"));
+
+ ArrayNode content = mapper.createArrayNode();
+
+ ObjectNode textContent = mapper.createObjectNode();
+
+ textContent.putIfAbsent("type", new TextNode("text"));
+ textContent.putIfAbsent("text", new TextNode("Can you tell the history of Mayflower?"));
+
+ content.add(textContent);
+
+ element.putIfAbsent("content", content);
+
+ messages.add(element);
+
+ rootNode.putIfAbsent("messages", messages);
+ rootNode.putIfAbsent("max_tokens", new IntNode(1000));
+ rootNode.putIfAbsent("anthropic_version", new TextNode("bedrock-2023-05-31"));
+
+ exchange.getMessage().setBody(mapper.writer().writeValueAsString(rootNode));
+ exchange.getMessage().setHeader(BedrockConstants.MODEL_CONTENT_TYPE, "application/json");
+ exchange.getMessage().setHeader(BedrockConstants.MODEL_ACCEPT_CONTENT_TYPE, "application/json");
+ });
+
+ MockEndpoint.assertIsSatisfied(context);
+ }
+
@Override
protected RouteBuilder createRouteBuilder() {
return new RouteBuilder() {
@@ -257,12 +373,36 @@ class BedrockProducerIT extends CamelTestSupport {
.to(result);
from("direct:send_jurassic2_mid_model")
- .to("aws-bedrock:label?accessKey=RAW({{aws.manual.access.key}})&secretKey=RAW({{aws.manual.secret.key}}®ion=us-east-1&operation=invokeTextModel&modelId="
+ .to("aws-bedrock:label?useDefaultCredentialsProvider=true®ion=us-east-1&operation=invokeTextModel&modelId="
+ BedrockModels.JURASSIC2_MID.model)
.split(body())
.transform().jq(".data.text")
.log("Completions: ${body}")
.to(result);
+
+ from("direct:send_anthropic_v1_model")
+ .to("aws-bedrock:label?accessKey=RAW({{aws.manual.access.key}})&secretKey=RAW({{aws.manual.secret.key}}®ion=us-east-1&operation=invokeTextModel&modelId="
+ + BedrockModels.ANTROPHIC_CLAUDE_INSTANT_V1.model)
+ .log("${body}")
+ .to(result);
+
+ from("direct:send_anthropic_v2_model")
+ .to("aws-bedrock:label?accessKey=RAW({{aws.manual.access.key}})&secretKey=RAW({{aws.manual.secret.key}}®ion=us-east-1&operation=invokeTextModel&modelId="
+ + BedrockModels.ANTROPHIC_CLAUDE_V2.model)
+ .log("${body}")
+ .to(result);
+
+ from("direct:send_anthropic_v21_model")
+ .to("aws-bedrock:label?accessKey=RAW({{aws.manual.access.key}})&secretKey=RAW({{aws.manual.secret.key}}®ion=us-east-1&operation=invokeTextModel&modelId="
+ + BedrockModels.ANTROPHIC_CLAUDE_V2_1.model)
+ .log("${body}")
+ .to(result);
+
+ from("direct:send_anthropic_v3_model")
+ .to("aws-bedrock:label?accessKey=RAW({{aws.manual.access.key}})&secretKey=RAW({{aws.manual.secret.key}}®ion=us-east-1&operation=invokeTextModel&modelId="
+ + BedrockModels.ANTROPHIC_CLAUDE_V3.model)
+ .log("Completions: ${body}")
+ .to(result);
}
};
}