This is an automated email from the ASF dual-hosted git repository.

acosentino pushed a commit to branch CAMEL-20476
in repository https://gitbox.apache.org/repos/asf/camel.git

commit e0e3223c650401c7b1dd0eb6dd7e646f472143dd
Author: Andrea Cosentino <anco...@gmail.com>
AuthorDate: Wed Feb 28 10:27:36 2024 +0100

    CAMEL-20476 - Camel-AWS-Bedrock: Support Amazon Titan Image Generator G1 
model
    
    Signed-off-by: Andrea Cosentino <anco...@gmail.com>
---
 components/camel-aws/camel-aws-bedrock/pom.xml     |  5 ++
 .../camel/component/aws2/bedrock/aws-bedrock.json  |  4 +-
 .../component/aws2/bedrock/BedrockModels.java      |  3 +-
 .../component/aws2/bedrock/BedrockOperations.java  |  4 +-
 .../component/aws2/bedrock/BedrockProducer.java    | 60 ++++++++++++++++++++++
 .../bedrock/integration/BedrockProducerIT.java     | 34 ++++++++++++
 6 files changed, 106 insertions(+), 4 deletions(-)

diff --git a/components/camel-aws/camel-aws-bedrock/pom.xml 
b/components/camel-aws/camel-aws-bedrock/pom.xml
index 522ceefc47c..40ba03486a3 100644
--- a/components/camel-aws/camel-aws-bedrock/pom.xml
+++ b/components/camel-aws/camel-aws-bedrock/pom.xml
@@ -66,6 +66,11 @@
             <artifactId>camel-test-spring-junit5</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-base64</artifactId>
+            <scope>test</scope>
+        </dependency>
 
 
         <dependency>
diff --git 
a/components/camel-aws/camel-aws-bedrock/src/generated/resources/META-INF/org/apache/camel/component/aws2/bedrock/aws-bedrock.json
 
b/components/camel-aws/camel-aws-bedrock/src/generated/resources/META-INF/org/apache/camel/component/aws2/bedrock/aws-bedrock.json
index 85c01b88d9a..02b0151a67e 100644
--- 
a/components/camel-aws/camel-aws-bedrock/src/generated/resources/META-INF/org/apache/camel/component/aws2/bedrock/aws-bedrock.json
+++ 
b/components/camel-aws/camel-aws-bedrock/src/generated/resources/META-INF/org/apache/camel/component/aws2/bedrock/aws-bedrock.json
@@ -26,7 +26,7 @@
     "configuration": { "index": 0, "kind": "property", "displayName": 
"Configuration", "group": "producer", "label": "", "required": false, "type": 
"object", "javaType": 
"org.apache.camel.component.aws2.bedrock.BedrockConfiguration", "deprecated": 
false, "autowired": false, "secret": false, "description": "Component 
configuration" },
     "lazyStartProducer": { "index": 1, "kind": "property", "displayName": 
"Lazy Start Producer", "group": "producer", "label": "producer", "required": 
false, "type": "boolean", "javaType": "boolean", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": false, "description": 
"Whether the producer should be started lazy (on the first message). By 
starting lazy you can use this to allow CamelContext and routes to startup in 
situations where a producer may otherwise fail [...]
     "modelId": { "index": 2, "kind": "property", "displayName": "Model Id", 
"group": "producer", "label": "", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": true, "configurationClass": 
"org.apache.camel.component.aws2.bedrock.BedrockConfiguration", 
"configurationField": "configuration", "description": "Define the model Id we 
are going to use" },
-    "operation": { "index": 3, "kind": "property", "displayName": "Operation", 
"group": "producer", "label": "", "required": true, "type": "object", 
"javaType": "org.apache.camel.component.aws2.bedrock.BedrockOperations", 
"enum": [ "invokeTextModel" ], "deprecated": false, "deprecationNote": "", 
"autowired": false, "secret": false, "configurationClass": 
"org.apache.camel.component.aws2.bedrock.BedrockConfiguration", 
"configurationField": "configuration", "description": "The operation to  [...]
+    "operation": { "index": 3, "kind": "property", "displayName": "Operation", 
"group": "producer", "label": "", "required": true, "type": "object", 
"javaType": "org.apache.camel.component.aws2.bedrock.BedrockOperations", 
"enum": [ "invokeTextModel", "invokeImageModel" ], "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, 
"configurationClass": 
"org.apache.camel.component.aws2.bedrock.BedrockConfiguration", 
"configurationField": "configuration", "description" [...]
     "overrideEndpoint": { "index": 4, "kind": "property", "displayName": 
"Override Endpoint", "group": "producer", "label": "", "required": false, 
"type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": false, "configurationClass": 
"org.apache.camel.component.aws2.bedrock.BedrockConfiguration", 
"configurationField": "configuration", "description": "Set the need for 
overriding the endpoint. This option needs to be used in combina [...]
     "pojoRequest": { "index": 5, "kind": "property", "displayName": "Pojo 
Request", "group": "producer", "label": "", "required": false, "type": 
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": false, "configurationClass": 
"org.apache.camel.component.aws2.bedrock.BedrockConfiguration", 
"configurationField": "configuration", "description": "If we want to use a POJO 
request as body or not" },
     "profileCredentialsName": { "index": 6, "kind": "property", "displayName": 
"Profile Credentials Name", "group": "producer", "label": "", "required": 
false, "type": "string", "javaType": "java.lang.String", "deprecated": false, 
"autowired": false, "secret": false, "defaultValue": "false", 
"configurationClass": 
"org.apache.camel.component.aws2.bedrock.BedrockConfiguration", 
"configurationField": "configuration", "description": "If using a profile 
credentials provider, this parameter wi [...]
@@ -55,7 +55,7 @@
   "properties": {
     "label": { "index": 0, "kind": "path", "displayName": "Label", "group": 
"producer", "label": "", "required": true, "type": "string", "javaType": 
"java.lang.String", "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "configurationClass": 
"org.apache.camel.component.aws2.bedrock.BedrockConfiguration", 
"configurationField": "configuration", "description": "Logical name" },
     "modelId": { "index": 1, "kind": "parameter", "displayName": "Model Id", 
"group": "producer", "label": "", "required": false, "type": "string", 
"javaType": "java.lang.String", "deprecated": false, "autowired": false, 
"secret": true, "configurationClass": 
"org.apache.camel.component.aws2.bedrock.BedrockConfiguration", 
"configurationField": "configuration", "description": "Define the model Id we 
are going to use" },
-    "operation": { "index": 2, "kind": "parameter", "displayName": 
"Operation", "group": "producer", "label": "", "required": true, "type": 
"object", "javaType": 
"org.apache.camel.component.aws2.bedrock.BedrockOperations", "enum": [ 
"invokeTextModel" ], "deprecated": false, "deprecationNote": "", "autowired": 
false, "secret": false, "configurationClass": 
"org.apache.camel.component.aws2.bedrock.BedrockConfiguration", 
"configurationField": "configuration", "description": "The operation to [...]
+    "operation": { "index": 2, "kind": "parameter", "displayName": 
"Operation", "group": "producer", "label": "", "required": true, "type": 
"object", "javaType": 
"org.apache.camel.component.aws2.bedrock.BedrockOperations", "enum": [ 
"invokeTextModel", "invokeImageModel" ], "deprecated": false, 
"deprecationNote": "", "autowired": false, "secret": false, 
"configurationClass": 
"org.apache.camel.component.aws2.bedrock.BedrockConfiguration", 
"configurationField": "configuration", "description [...]
     "overrideEndpoint": { "index": 3, "kind": "parameter", "displayName": 
"Override Endpoint", "group": "producer", "label": "", "required": false, 
"type": "boolean", "javaType": "boolean", "deprecated": false, "autowired": 
false, "secret": false, "defaultValue": false, "configurationClass": 
"org.apache.camel.component.aws2.bedrock.BedrockConfiguration", 
"configurationField": "configuration", "description": "Set the need for 
overriding the endpoint. This option needs to be used in combin [...]
     "pojoRequest": { "index": 4, "kind": "parameter", "displayName": "Pojo 
Request", "group": "producer", "label": "", "required": false, "type": 
"boolean", "javaType": "boolean", "deprecated": false, "autowired": false, 
"secret": false, "defaultValue": false, "configurationClass": 
"org.apache.camel.component.aws2.bedrock.BedrockConfiguration", 
"configurationField": "configuration", "description": "If we want to use a POJO 
request as body or not" },
     "profileCredentialsName": { "index": 5, "kind": "parameter", 
"displayName": "Profile Credentials Name", "group": "producer", "label": "", 
"required": false, "type": "string", "javaType": "java.lang.String", 
"deprecated": false, "autowired": false, "secret": false, "defaultValue": 
"false", "configurationClass": 
"org.apache.camel.component.aws2.bedrock.BedrockConfiguration", 
"configurationField": "configuration", "description": "If using a profile 
credentials provider, this parameter w [...]
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 25fb7bb0f47..c1cce5e044c 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
@@ -19,7 +19,8 @@ package org.apache.camel.component.aws2.bedrock;
 public enum BedrockModels {
 
     TITAN_TEXT_EXPRESS_V1("amazon.titan-text-express-v1"),
-    TITAN_TEXT_LITE_V1("amazon.titan-text-lite-v1");
+    TITAN_TEXT_LITE_V1("amazon.titan-text-lite-v1"),
+    TITAN_IMAGE_GENERATOR_V1("amazon.titan-image-generator-v1");
 
     public final String model;
 
diff --git 
a/components/camel-aws/camel-aws-bedrock/src/main/java/org/apache/camel/component/aws2/bedrock/BedrockOperations.java
 
b/components/camel-aws/camel-aws-bedrock/src/main/java/org/apache/camel/component/aws2/bedrock/BedrockOperations.java
index 6b84c2f46b6..e99f0e08f9e 100644
--- 
a/components/camel-aws/camel-aws-bedrock/src/main/java/org/apache/camel/component/aws2/bedrock/BedrockOperations.java
+++ 
b/components/camel-aws/camel-aws-bedrock/src/main/java/org/apache/camel/component/aws2/bedrock/BedrockOperations.java
@@ -18,5 +18,7 @@ package org.apache.camel.component.aws2.bedrock;
 
 public enum BedrockOperations {
 
-    invokeTextModel
+    invokeTextModel,
+
+    invokeImageModel
 }
diff --git 
a/components/camel-aws/camel-aws-bedrock/src/main/java/org/apache/camel/component/aws2/bedrock/BedrockProducer.java
 
b/components/camel-aws/camel-aws-bedrock/src/main/java/org/apache/camel/component/aws2/bedrock/BedrockProducer.java
index 675b7ca571f..990ff1f75e6 100644
--- 
a/components/camel-aws/camel-aws-bedrock/src/main/java/org/apache/camel/component/aws2/bedrock/BedrockProducer.java
+++ 
b/components/camel-aws/camel-aws-bedrock/src/main/java/org/apache/camel/component/aws2/bedrock/BedrockProducer.java
@@ -16,6 +16,9 @@
  */
 package org.apache.camel.component.aws2.bedrock;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.camel.Endpoint;
 import org.apache.camel.Exchange;
 import org.apache.camel.InvalidPayloadException;
@@ -50,6 +53,9 @@ public class BedrockProducer extends DefaultProducer {
             case invokeTextModel:
                 invokeTextModel(getEndpoint().getBedrockRuntimeClient(), 
exchange);
                 break;
+            case invokeImageModel:
+                invokeImageModel(getEndpoint().getBedrockRuntimeClient(), 
exchange);
+                break;
             default:
                 throw new IllegalArgumentException("Unsupported operation");
         }
@@ -124,6 +130,60 @@ public class BedrockProducer extends DefaultProducer {
         }
     }
 
+    private void invokeImageModel(BedrockRuntimeClient bedrockRuntimeClient, 
Exchange exchange) throws InvalidPayloadException {
+        if (getConfiguration().isPojoRequest()) {
+            Object payload = exchange.getMessage().getMandatoryBody();
+            if (payload instanceof InvokeModelRequest) {
+                InvokeModelResponse result;
+                try {
+                    result = 
bedrockRuntimeClient.invokeModel((InvokeModelRequest) payload);
+                } catch (AwsServiceException ase) {
+                    LOG.trace("Invoke Image Model command returned the error 
code {}", ase.awsErrorDetails().errorCode());
+                    throw ase;
+                }
+                Message message = getMessageForResponse(exchange);
+                message.setBody(result);
+            }
+        } else {
+            InvokeModelRequest.Builder builder = InvokeModelRequest.builder();
+            if 
(ObjectHelper.isNotEmpty(exchange.getMessage().getHeader(BedrockConstants.MODEL_CONTENT_TYPE)))
 {
+                String contentType = 
exchange.getIn().getHeader(BedrockConstants.MODEL_CONTENT_TYPE, String.class);
+                builder.contentType(contentType);
+            } else {
+                throw new IllegalArgumentException("Model Content Type must be 
specified");
+            }
+            if 
(ObjectHelper.isNotEmpty(exchange.getMessage().getHeader(BedrockConstants.MODEL_ACCEPT_CONTENT_TYPE)))
 {
+                String acceptContentType = 
exchange.getIn().getHeader(BedrockConstants.MODEL_ACCEPT_CONTENT_TYPE, 
String.class);
+                builder.accept(acceptContentType);
+            } else {
+                throw new IllegalArgumentException("Model Accept Content Type 
must be specified");
+            }
+            InvokeModelRequest request = builder
+                    
.body(SdkBytes.fromUtf8String(String.valueOf(exchange.getMessage().getBody())))
+                    .modelId(getConfiguration().getModelId())
+                    .build();
+            InvokeModelResponse result;
+            try {
+                result = bedrockRuntimeClient.invokeModel(request);
+            } catch (AwsServiceException ase) {
+                LOG.trace("Invoke Model command returned the error code {}", 
ase.awsErrorDetails().errorCode());
+                throw ase;
+            }
+            Message message = getMessageForResponse(exchange);
+            try {
+                setBase64Image(result, message);
+            } catch (JsonProcessingException e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+
+    private static void setBase64Image(InvokeModelResponse result, Message 
message) throws JsonProcessingException {
+        ObjectMapper mapper = new ObjectMapper();
+        JsonNode jsonString = mapper.readTree(result.body().asUtf8String());
+        message.setBody(jsonString.get("images").get(0));
+    }
+
     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/integration/BedrockProducerIT.java
 
b/components/camel-aws/camel-aws-bedrock/src/test/java/org/apache/camel/component/aws2/bedrock/integration/BedrockProducerIT.java
index bd6261e62e1..5fbab759ffd 100644
--- 
a/components/camel-aws/camel-aws-bedrock/src/test/java/org/apache/camel/component/aws2/bedrock/integration/BedrockProducerIT.java
+++ 
b/components/camel-aws/camel-aws-bedrock/src/test/java/org/apache/camel/component/aws2/bedrock/integration/BedrockProducerIT.java
@@ -98,6 +98,33 @@ class BedrockProducerIT extends CamelTestSupport {
         MockEndpoint.assertIsSatisfied(context);
     }
 
+    @Test
+    public void testInvokeTitanImageModel() throws InterruptedException {
+
+        result.expectedMessageCount(1);
+        final Exchange result = template.send("direct:send_titan_image", 
exchange -> {
+            ObjectMapper mapper = new ObjectMapper();
+            ObjectNode rootNode = mapper.createObjectNode();
+            ObjectNode textParameter = mapper.createObjectNode();
+            textParameter.put("text",
+                    "A ancient time camel running in the desert");
+            rootNode.put("textToImageParams", textParameter);
+            rootNode.put("taskType", "TEXT_IMAGE");
+            ObjectNode childNode = mapper.createObjectNode();
+            childNode.put("numberOfImages", 1);
+            childNode.put("quality", "standard");
+            childNode.put("cfgScale", 8).put("height", 512).put("width", 
512).put("seed", 0);
+
+            rootNode.put("imageGenerationConfig", childNode);
+
+            
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() {
@@ -112,6 +139,13 @@ class BedrockProducerIT extends CamelTestSupport {
                         
.to("aws-bedrock:label?accessKey=RAW({{aws.manual.access.key}})&secretKey=RAW({{aws.manual.secret.key}}&region=us-east-1&operation=invokeTextModel&modelId="
                             + BedrockModels.TITAN_TEXT_LITE_V1.model)
                         .to(result);
+
+                from("direct:send_titan_image")
+                        
.to("aws-bedrock:label?accessKey=RAW({{aws.manual.access.key}})&secretKey=RAW({{aws.manual.secret.key}}&region=us-east-1&operation=invokeImageModel&modelId="
+                            + BedrockModels.TITAN_IMAGE_GENERATOR_V1.model)
+                        .unmarshal().base64()
+                        .setHeader("CamelFileName", 
constant("image.png")).to("file:target/generated_images")
+                        .to(result);
             }
         };
     }

Reply via email to