From f5f58cdd4a16de6436a73717c14d19e61e3c4647 Mon Sep 17 00:00:00 2001 From: Ilayaperumal Gopinathan Date: Wed, 29 Jan 2025 09:43:52 +0000 Subject: [PATCH] Remove deprecated Amazon Bedrock chat models - Amzon Bedrock chat models were deprecated to support Amazon Bedrock Converse API for the chat models. - This PR removes all the references of the deprecated Amazon Bedrock chat models - Remove Amazon Bedrock chat models for anthropic, anthropic3, cohere, jurassic2, titan - Remove API, chat options and model - Remove tests and doc references - Update the doc to reflect the changes - Update upgrade notes Resolves #2124 Signed-off-by: Ilayaperumal Gopinathan --- .../anthropic/AnthropicChatOptions.java | 217 ------- .../anthropic/BedrockAnthropicChatModel.java | 127 ---- .../api/AnthropicChatBedrockApi.java | 282 --------- .../anthropic3/Anthropic3ChatOptions.java | 324 ---------- .../BedrockAnthropic3ChatModel.java | 218 ------- .../api/Anthropic3ChatBedrockApi.java | 590 ------------------ .../ai/bedrock/aot/BedrockRuntimeHints.java | 47 -- .../cohere/BedrockCohereChatModel.java | 130 ---- .../cohere/BedrockCohereChatOptions.java | 269 -------- .../cohere/api/CohereChatBedrockApi.java | 420 ------------- .../BedrockAi21Jurassic2ChatModel.java | 121 ---- .../BedrockAi21Jurassic2ChatOptions.java | 486 --------------- .../api/Ai21Jurassic2ChatBedrockApi.java | 471 -------------- .../bedrock/llama/BedrockLlamaChatModel.java | 153 ----- .../llama/BedrockLlamaChatOptions.java | 163 ----- .../llama/api/LlamaChatBedrockApi.java | 302 --------- .../bedrock/titan/BedrockTitanChatModel.java | 170 ----- .../titan/BedrockTitanChatOptions.java | 177 ------ .../titan/api/TitanChatBedrockApi.java | 320 ---------- .../BedrockAnthropicChatModelIT.java | 221 ------- .../BedrockAnthropicCreateRequestTests.java | 82 --- .../api/AnthropicChatBedrockApiIT.java | 92 --- .../BedrockAnthropic3ChatModelIT.java | 248 -------- .../BedrockAnthropic3CreateRequestTests.java | 82 --- .../api/Anthropic3ChatBedrockApiIT.java | 146 ----- .../bedrock/aot/BedrockRuntimeHintsTests.java | 9 +- .../BedrockCohereChatCreateRequestTests.java | 107 ---- .../cohere/BedrockCohereChatModelIT.java | 217 ------- .../cohere/api/CohereChatBedrockApiIT.java | 153 ----- .../BedrockAi21Jurassic2ChatModelIT.java | 180 ------ .../api/Ai21Jurassic2ChatBedrockApiIT.java | 67 -- .../llama/BedrockLlamaChatModelIT.java | 226 ------- .../llama/BedrockLlamaCreateRequestTests.java | 66 -- .../llama/api/LlamaChatBedrockApiIT.java | 82 --- ...drockTitanChatModelCreateRequestTests.java | 78 --- .../titan/BedrockTitanChatModelIT.java | 218 ------- .../titan/api/TitanChatBedrockApiIT.java | 75 --- .../src/main/antora/modules/ROOT/nav.adoc | 7 - .../modules/ROOT/pages/api/bedrock.adoc | 32 +- .../ROOT/pages/api/chat/anthropic-chat.adoc | 4 +- .../api/chat/bedrock/bedrock-anthropic.adoc | 267 -------- .../api/chat/bedrock/bedrock-anthropic3.adoc | 304 --------- .../api/chat/bedrock/bedrock-cohere.adoc | 278 --------- .../api/chat/bedrock/bedrock-jurassic2.adoc | 235 ------- .../pages/api/chat/bedrock/bedrock-llama.adoc | 255 -------- .../pages/api/chat/bedrock/bedrock-titan.adoc | 252 -------- .../modules/ROOT/pages/api/chatmodel.adoc | 5 - .../api/structured-output-converter.adoc | 4 - .../modules/ROOT/pages/upgrade-notes.adoc | 10 + ...BedrockAnthropicChatAutoConfiguration.java | 70 --- .../BedrockAnthropicChatProperties.java | 84 --- ...edrockAnthropic3ChatAutoConfiguration.java | 70 --- .../BedrockAnthropic3ChatProperties.java | 84 --- .../BedrockCohereChatAutoConfiguration.java | 69 -- .../cohere/BedrockCohereChatProperties.java | 72 --- ...ockAi21Jurassic2ChatAutoConfiguration.java | 72 --- .../BedrockAi21Jurassic2ChatProperties.java | 76 --- .../BedrockLlamaChatAutoConfiguration.java | 70 --- .../llama/BedrockLlamaChatProperties.java | 72 --- .../BedrockTitanChatAutoConfiguration.java | 68 -- .../titan/BedrockTitanChatProperties.java | 72 --- ...ot.autoconfigure.AutoConfiguration.imports | 6 - ...drockAnthropicChatAutoConfigurationIT.java | 156 ----- ...rockAnthropic3ChatAutoConfigurationIT.java | 156 ----- .../BedrockCohereChatAutoConfigurationIT.java | 172 ----- ...kAi21Jurassic2ChatAutoConfigurationIT.java | 135 ---- .../BedrockLlamaChatAutoConfigurationIT.java | 160 ----- .../BedrockTitanChatAutoConfigurationIT.java | 163 ----- 68 files changed, 23 insertions(+), 10793 deletions(-) delete mode 100644 models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/AnthropicChatOptions.java delete mode 100644 models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/BedrockAnthropicChatModel.java delete mode 100644 models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/api/AnthropicChatBedrockApi.java delete mode 100644 models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic3/Anthropic3ChatOptions.java delete mode 100644 models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic3/BedrockAnthropic3ChatModel.java delete mode 100644 models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic3/api/Anthropic3ChatBedrockApi.java delete mode 100644 models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/BedrockCohereChatModel.java delete mode 100644 models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/BedrockCohereChatOptions.java delete mode 100644 models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/api/CohereChatBedrockApi.java delete mode 100644 models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/jurassic2/BedrockAi21Jurassic2ChatModel.java delete mode 100644 models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/jurassic2/BedrockAi21Jurassic2ChatOptions.java delete mode 100644 models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/jurassic2/api/Ai21Jurassic2ChatBedrockApi.java delete mode 100644 models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/llama/BedrockLlamaChatModel.java delete mode 100644 models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/llama/BedrockLlamaChatOptions.java delete mode 100644 models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/llama/api/LlamaChatBedrockApi.java delete mode 100644 models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/BedrockTitanChatModel.java delete mode 100644 models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/BedrockTitanChatOptions.java delete mode 100644 models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/api/TitanChatBedrockApi.java delete mode 100644 models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/anthropic/BedrockAnthropicChatModelIT.java delete mode 100644 models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/anthropic/BedrockAnthropicCreateRequestTests.java delete mode 100644 models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/anthropic/api/AnthropicChatBedrockApiIT.java delete mode 100644 models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/anthropic3/BedrockAnthropic3ChatModelIT.java delete mode 100644 models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/anthropic3/BedrockAnthropic3CreateRequestTests.java delete mode 100644 models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/anthropic3/api/Anthropic3ChatBedrockApiIT.java delete mode 100644 models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/cohere/BedrockCohereChatCreateRequestTests.java delete mode 100644 models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/cohere/BedrockCohereChatModelIT.java delete mode 100644 models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/cohere/api/CohereChatBedrockApiIT.java delete mode 100644 models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/jurassic2/BedrockAi21Jurassic2ChatModelIT.java delete mode 100644 models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/jurassic2/api/Ai21Jurassic2ChatBedrockApiIT.java delete mode 100644 models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/llama/BedrockLlamaChatModelIT.java delete mode 100644 models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/llama/BedrockLlamaCreateRequestTests.java delete mode 100644 models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/llama/api/LlamaChatBedrockApiIT.java delete mode 100644 models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/titan/BedrockTitanChatModelCreateRequestTests.java delete mode 100644 models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/titan/BedrockTitanChatModelIT.java delete mode 100644 models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/titan/api/TitanChatBedrockApiIT.java delete mode 100644 spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock/bedrock-anthropic.adoc delete mode 100644 spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock/bedrock-anthropic3.adoc delete mode 100644 spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock/bedrock-cohere.adoc delete mode 100644 spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock/bedrock-jurassic2.adoc delete mode 100644 spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock/bedrock-llama.adoc delete mode 100644 spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock/bedrock-titan.adoc delete mode 100644 spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/anthropic/BedrockAnthropicChatAutoConfiguration.java delete mode 100644 spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/anthropic/BedrockAnthropicChatProperties.java delete mode 100644 spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/anthropic3/BedrockAnthropic3ChatAutoConfiguration.java delete mode 100644 spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/anthropic3/BedrockAnthropic3ChatProperties.java delete mode 100644 spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/cohere/BedrockCohereChatAutoConfiguration.java delete mode 100644 spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/cohere/BedrockCohereChatProperties.java delete mode 100644 spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/jurrasic2/BedrockAi21Jurassic2ChatAutoConfiguration.java delete mode 100644 spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/jurrasic2/BedrockAi21Jurassic2ChatProperties.java delete mode 100644 spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/llama/BedrockLlamaChatAutoConfiguration.java delete mode 100644 spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/llama/BedrockLlamaChatProperties.java delete mode 100644 spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/titan/BedrockTitanChatAutoConfiguration.java delete mode 100644 spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/titan/BedrockTitanChatProperties.java delete mode 100644 spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/anthropic/BedrockAnthropicChatAutoConfigurationIT.java delete mode 100644 spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/anthropic3/BedrockAnthropic3ChatAutoConfigurationIT.java delete mode 100644 spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/cohere/BedrockCohereChatAutoConfigurationIT.java delete mode 100644 spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/jurassic2/BedrockAi21Jurassic2ChatAutoConfigurationIT.java delete mode 100644 spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/llama/BedrockLlamaChatAutoConfigurationIT.java delete mode 100644 spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/titan/BedrockTitanChatAutoConfigurationIT.java diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/AnthropicChatOptions.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/AnthropicChatOptions.java deleted file mode 100644 index acccf0caeb5..00000000000 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/AnthropicChatOptions.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.anthropic; - -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.fasterxml.jackson.annotation.JsonProperty; - -import org.springframework.ai.chat.prompt.ChatOptions; - -/** - * Options for the Anthropic Chat API. - * - * @author Christian Tzolov - * @author Thomas Vitale - * @author Ilayaperumal Gopinathan - */ -@JsonInclude(Include.NON_NULL) -public class AnthropicChatOptions implements ChatOptions { - - // @formatter:off - /** - * Controls the randomness of the output. Values can range over [0.0,1.0], inclusive. A value closer to 1.0 will - * produce responses that are more varied, while a value closer to 0.0 will typically result in less surprising - * responses from the generative. This value specifies default to be used by the backend while making the call to - * the generative. - */ - private @JsonProperty("temperature") Double temperature; - - /** - * Specify the maximum number of tokens to use in the generated response. Note that the models may stop before - * reaching this maximum. This parameter only specifies the absolute maximum number of tokens to generate. We - * recommend a limit of 4,000 tokens for optimal performance. - */ - private @JsonProperty("max_tokens_to_sample") Integer maxTokensToSample; - - /** - * Specify the number of token choices the generative uses to generate the next token. - */ - private @JsonProperty("top_k") Integer topK; - - /** - * The maximum cumulative probability of tokens to consider when sampling. The generative uses combined Top-k and - * nucleus sampling. Nucleus sampling considers the smallest set of tokens whose probability sum is at least topP. - */ - private @JsonProperty("top_p") Double topP; - - /** - * Configure up to four sequences that the generative recognizes. After a stop sequence, the generative stops - * generating further tokens. The returned text doesn't contain the stop sequence. - */ - private @JsonProperty("stop_sequences") List stopSequences; - - /** - * The version of the generative to use. The default value is bedrock-2023-05-31. - */ - private @JsonProperty("anthropic_version") String anthropicVersion; - // @formatter:on - - public static Builder builder() { - return new Builder(); - } - - public static AnthropicChatOptions fromOptions(AnthropicChatOptions fromOptions) { - return builder().temperature(fromOptions.getTemperature()) - .maxTokensToSample(fromOptions.getMaxTokensToSample()) - .topK(fromOptions.getTopK()) - .topP(fromOptions.getTopP()) - .stopSequences(fromOptions.getStopSequences()) - .anthropicVersion(fromOptions.getAnthropicVersion()) - .build(); - } - - @Override - public Double getTemperature() { - return this.temperature; - } - - public void setTemperature(Double temperature) { - this.temperature = temperature; - } - - @Override - @JsonIgnore - public Integer getMaxTokens() { - return getMaxTokensToSample(); - } - - @JsonIgnore - public void setMaxTokens(Integer maxTokens) { - setMaxTokensToSample(maxTokens); - } - - public Integer getMaxTokensToSample() { - return this.maxTokensToSample; - } - - public void setMaxTokensToSample(Integer maxTokensToSample) { - this.maxTokensToSample = maxTokensToSample; - } - - @Override - public Integer getTopK() { - return this.topK; - } - - public void setTopK(Integer topK) { - this.topK = topK; - } - - @Override - public Double getTopP() { - return this.topP; - } - - public void setTopP(Double topP) { - this.topP = topP; - } - - @Override - public List getStopSequences() { - return this.stopSequences; - } - - public void setStopSequences(List stopSequences) { - this.stopSequences = stopSequences; - } - - public String getAnthropicVersion() { - return this.anthropicVersion; - } - - public void setAnthropicVersion(String anthropicVersion) { - this.anthropicVersion = anthropicVersion; - } - - @Override - @JsonIgnore - public String getModel() { - return null; - } - - @Override - @JsonIgnore - public Double getFrequencyPenalty() { - return null; - } - - @Override - @JsonIgnore - public Double getPresencePenalty() { - return null; - } - - @Override - public AnthropicChatOptions copy() { - return fromOptions(this); - } - - public static class Builder { - - private final AnthropicChatOptions options = new AnthropicChatOptions(); - - public Builder temperature(Double temperature) { - this.options.setTemperature(temperature); - return this; - } - - public Builder maxTokensToSample(Integer maxTokensToSample) { - this.options.setMaxTokensToSample(maxTokensToSample); - return this; - } - - public Builder topK(Integer topK) { - this.options.setTopK(topK); - return this; - } - - public Builder topP(Double topP) { - this.options.setTopP(topP); - return this; - } - - public Builder stopSequences(List stopSequences) { - this.options.setStopSequences(stopSequences); - return this; - } - - public Builder anthropicVersion(String anthropicVersion) { - this.options.setAnthropicVersion(anthropicVersion); - return this; - } - - public AnthropicChatOptions build() { - return this.options; - } - - } - -} diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/BedrockAnthropicChatModel.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/BedrockAnthropicChatModel.java deleted file mode 100644 index 087de9e266c..00000000000 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/BedrockAnthropicChatModel.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.anthropic; - -import java.util.List; - -import reactor.core.publisher.Flux; - -import org.springframework.ai.bedrock.MessageToPromptConverter; -import org.springframework.ai.bedrock.anthropic.api.AnthropicChatBedrockApi; -import org.springframework.ai.bedrock.anthropic.api.AnthropicChatBedrockApi.AnthropicChatRequest; -import org.springframework.ai.bedrock.anthropic.api.AnthropicChatBedrockApi.AnthropicChatResponse; -import org.springframework.ai.chat.messages.AssistantMessage; -import org.springframework.ai.chat.metadata.ChatGenerationMetadata; -import org.springframework.ai.chat.model.ChatModel; -import org.springframework.ai.chat.model.ChatResponse; -import org.springframework.ai.chat.model.Generation; -import org.springframework.ai.chat.model.StreamingChatModel; -import org.springframework.ai.chat.prompt.ChatOptions; -import org.springframework.ai.chat.prompt.Prompt; -import org.springframework.ai.model.ModelOptionsUtils; - -/** - * Java {@link ChatModel} and {@link StreamingChatModel} for the Bedrock Anthropic chat - * generative. - * - * @author Christian Tzolov - * @since 0.8.0 - * @deprecated in favor of the - * {@link org.springframework.ai.bedrock.converse.BedrockProxyChatModel}. - */ -@Deprecated -public class BedrockAnthropicChatModel implements ChatModel, StreamingChatModel { - - private final AnthropicChatBedrockApi anthropicChatApi; - - private final AnthropicChatOptions defaultOptions; - - public BedrockAnthropicChatModel(AnthropicChatBedrockApi chatApi) { - this(chatApi, - AnthropicChatOptions.builder() - .temperature(0.8) - .maxTokensToSample(500) - .topK(10) - .anthropicVersion(AnthropicChatBedrockApi.DEFAULT_ANTHROPIC_VERSION) - .build()); - } - - public BedrockAnthropicChatModel(AnthropicChatBedrockApi chatApi, AnthropicChatOptions options) { - this.anthropicChatApi = chatApi; - this.defaultOptions = options; - } - - @Override - public ChatResponse call(Prompt prompt) { - - AnthropicChatRequest request = createRequest(prompt); - - AnthropicChatResponse response = this.anthropicChatApi.chatCompletion(request); - - return new ChatResponse(List.of(new Generation(new AssistantMessage(response.completion())))); - } - - @Override - public Flux stream(Prompt prompt) { - - AnthropicChatRequest request = createRequest(prompt); - - Flux fluxResponse = this.anthropicChatApi.chatCompletionStream(request); - - return fluxResponse.map(response -> { - String stopReason = response.stopReason() != null ? response.stopReason() : null; - ChatGenerationMetadata chatGenerationMetadata = null; - if (response.amazonBedrockInvocationMetrics() != null) { - chatGenerationMetadata = ChatGenerationMetadata.builder() - .finishReason(stopReason) - .metadata("metrics", response.amazonBedrockInvocationMetrics()) - .build(); - } - return new ChatResponse( - List.of(new Generation(new AssistantMessage(response.completion()), chatGenerationMetadata))); - }); - } - - /** - * Accessible for testing. - */ - AnthropicChatRequest createRequest(Prompt prompt) { - - // Related to: https://github.com/spring-projects/spring-ai/issues/404 - final String promptValue = MessageToPromptConverter.create("\n").toPrompt(prompt.getInstructions()); - - AnthropicChatRequest request = AnthropicChatRequest.builder(promptValue).build(); - - if (this.defaultOptions != null) { - request = ModelOptionsUtils.merge(request, this.defaultOptions, AnthropicChatRequest.class); - } - - if (prompt.getOptions() != null) { - AnthropicChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(prompt.getOptions(), - ChatOptions.class, AnthropicChatOptions.class); - request = ModelOptionsUtils.merge(updatedRuntimeOptions, request, AnthropicChatRequest.class); - } - - return request; - } - - @Override - public ChatOptions getDefaultOptions() { - return AnthropicChatOptions.fromOptions(this.defaultOptions); - } - -} diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/api/AnthropicChatBedrockApi.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/api/AnthropicChatBedrockApi.java deleted file mode 100644 index afaa6c39d4b..00000000000 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/api/AnthropicChatBedrockApi.java +++ /dev/null @@ -1,282 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.anthropic.api; - -import java.time.Duration; -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.ObjectMapper; -import reactor.core.publisher.Flux; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.bedrock.anthropic.api.AnthropicChatBedrockApi.AnthropicChatRequest; -import org.springframework.ai.bedrock.anthropic.api.AnthropicChatBedrockApi.AnthropicChatResponse; -import org.springframework.ai.bedrock.api.AbstractBedrockApi; -import org.springframework.ai.model.ChatModelDescription; -import org.springframework.util.Assert; - -/** - * Anthropic Chat API. - * - * @author Christian Tzolov - * @author Thomas Vitale - * @author Wei Jiang - * @author Ilayaperumal Gopinathan - * @since 0.8.0 - */ -// @formatter:off -public class AnthropicChatBedrockApi extends - AbstractBedrockApi { - - public static final String PROMPT_TEMPLATE = "\n\nHuman:%s\n\nAssistant:"; - - /** - * Default version of the Anthropic chat model. - */ - public static final String DEFAULT_ANTHROPIC_VERSION = "bedrock-2023-05-31"; - - - /** - * Create a new AnthropicChatBedrockApi instance using the default credentials provider chain, the default object. - * @param modelId The model id to use. See the {@link AnthropicChatModel} for the supported models. - * @param region The AWS region to use. - */ - public AnthropicChatBedrockApi(String modelId, String region) { - super(modelId, region); - } - - /** - * Create a new AnthropicChatBedrockApi instance using the default credentials provider chain, the default object. - * @param modelId The model id to use. See the {@link AnthropicChatModel} for the supported models. - * @param region The AWS region to use. - * @param timeout The timeout to use. - */ - public AnthropicChatBedrockApi(String modelId, String region, Duration timeout) { - super(modelId, region, timeout); - } - - /** - * Create a new AnthropicChatBedrockApi instance using the provided credentials provider, region and object mapper. - * - * @param modelId The model id to use. See the {@link AnthropicChatModel} for the supported models. - * @param credentialsProvider The credentials provider to connect to AWS. - * @param region The AWS region to use. - * @param objectMapper The object mapper to use for JSON serialization and deserialization. - */ - public AnthropicChatBedrockApi(String modelId, AwsCredentialsProvider credentialsProvider, String region, - ObjectMapper objectMapper) { - super(modelId, credentialsProvider, region, objectMapper); - } - - /** - * Create a new AnthropicChatBedrockApi instance using the provided credentials provider, region and object mapper. - * - * @param modelId The model id to use. See the {@link AnthropicChatModel} for the supported models. - * @param credentialsProvider The credentials provider to connect to AWS. - * @param region The AWS region to use. - * @param objectMapper The object mapper to use for JSON serialization and deserialization. - * @param timeout The timeout to use. - */ - public AnthropicChatBedrockApi(String modelId, AwsCredentialsProvider credentialsProvider, String region, - ObjectMapper objectMapper, Duration timeout) { - super(modelId, credentialsProvider, region, objectMapper, timeout); - } - - /** - * Create a new AnthropicChatBedrockApi instance using the provided credentials provider, region and object mapper. - * - * @param modelId The model id to use. See the {@link AnthropicChatModel} for the supported models. - * @param credentialsProvider The credentials provider to connect to AWS. - * @param region The AWS region to use. - * @param objectMapper The object mapper to use for JSON serialization and deserialization. - * @param timeout The timeout to use. - */ - public AnthropicChatBedrockApi(String modelId, AwsCredentialsProvider credentialsProvider, Region region, - ObjectMapper objectMapper, Duration timeout) { - super(modelId, credentialsProvider, region, objectMapper, timeout); - } - - // https://github.com/build-on-aws/amazon-bedrock-java-examples/blob/main/example_code/bedrock-runtime/src/main/java/aws/community/examples/InvokeBedrockStreamingAsync.java - - // https://docs.anthropic.com/claude/reference/complete_post - - // https://docs.aws.amazon.com/bedrock/latest/userguide/br-product-ids.html - - // Anthropic Claude models: https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-claude.html - - @Override - public AnthropicChatResponse chatCompletion(AnthropicChatRequest anthropicRequest) { - Assert.notNull(anthropicRequest, "'anthropicRequest' must not be null"); - return this.internalInvocation(anthropicRequest, AnthropicChatResponse.class); - } - - @Override - public Flux chatCompletionStream(AnthropicChatRequest anthropicRequest) { - Assert.notNull(anthropicRequest, "'anthropicRequest' must not be null"); - return this.internalInvocationStream(anthropicRequest, AnthropicChatResponse.class); - } - - /** - * Anthropic models version. - */ - public enum AnthropicChatModel implements ChatModelDescription { - /** - * anthropic.claude-instant-v1 - */ - CLAUDE_INSTANT_V1("anthropic.claude-instant-v1"), - /** - * anthropic.claude-v2 - */ - CLAUDE_V2("anthropic.claude-v2"), - /** - * anthropic.claude-v2:1 - */ - CLAUDE_V21("anthropic.claude-v2:1"); - - private final String id; - - AnthropicChatModel(String value) { - this.id = value; - } - - /** - * @return The model id. - */ - public String id() { - return this.id; - } - - @Override - public String getName() { - return this.id; - } - } - - /** - * AnthropicChatRequest encapsulates the request parameters for the Anthropic chat model. - * https://docs.anthropic.com/claude/reference/complete_post - * - * @param prompt The prompt to use for the chat. - * @param temperature (default 0.5) The temperature to use for the chat. You should either alter temperature or - * top_p, but not both. - * @param maxTokensToSample (default 200) Specify the maximum number of tokens to use in the generated response. - * Note that the models may stop before reaching this maximum. This parameter only specifies the absolute maximum - * number of tokens to generate. We recommend a limit of 4,000 tokens for optimal performance. - * @param topK (default 250) Specify the number of token choices the model uses to generate the next token. - * @param topP (default 1) Nucleus sampling to specify the cumulative probability of the next token in range [0,1]. - * In nucleus sampling, we compute the cumulative distribution over all the options for each subsequent token in - * decreasing probability order and cut it off once it reaches a particular probability specified by top_p. You - * should either alter temperature or top_p, but not both. - * @param stopSequences (defaults to "\n\nHuman:") Configure up to four sequences that the model recognizes. After a - * stop sequence, the model stops generating further tokens. The returned text doesn't contain the stop sequence. - * @param anthropicVersion The version of the model to use. The default value is bedrock-2023-05-31. - */ - @JsonInclude(Include.NON_NULL) - public record AnthropicChatRequest( - @JsonProperty("prompt") String prompt, - @JsonProperty("temperature") Double temperature, - @JsonProperty("max_tokens_to_sample") Integer maxTokensToSample, - @JsonProperty("top_k") Integer topK, - @JsonProperty("top_p") Double topP, - @JsonProperty("stop_sequences") List stopSequences, - @JsonProperty("anthropic_version") String anthropicVersion) { - - public static Builder builder(String prompt) { - return new Builder(prompt); - } - - public static final class Builder { - private final String prompt; - private Double temperature; // = 0.7; - private Integer maxTokensToSample; // = 500; - private Integer topK; // = 10; - private Double topP; - private List stopSequences; - private String anthropicVersion; - - private Builder(String prompt) { - this.prompt = prompt; - } - - public Builder temperature(Double temperature) { - this.temperature = temperature; - return this; - } - - public Builder maxTokensToSample(Integer maxTokensToSample) { - this.maxTokensToSample = maxTokensToSample; - return this; - } - - public Builder topK(Integer topK) { - this.topK = topK; - return this; - } - - public Builder topP(Double tpoP) { - this.topP = tpoP; - return this; - } - - public Builder stopSequences(List stopSequences) { - this.stopSequences = stopSequences; - return this; - } - - public Builder anthropicVersion(String anthropicVersion) { - this.anthropicVersion = anthropicVersion; - return this; - } - - public AnthropicChatRequest build() { - return new AnthropicChatRequest( - this.prompt, - this.temperature, - this.maxTokensToSample, - this.topK, - this.topP, - this.stopSequences, - this.anthropicVersion - ); - } - } - } - - /** - * AnthropicChatResponse encapsulates the response parameters for the Anthropic chat model. - * - * @param type The type of the response. - * @param completion The generated text. - * @param stopReason The reason the model stopped generating text. - * @param stop The stop sequence that caused the model to stop generating text. - * @param amazonBedrockInvocationMetrics Metrics about the model invocation. - */ - @JsonInclude(Include.NON_NULL) - public record AnthropicChatResponse( - @JsonProperty("type") String type, - @JsonProperty("completion") String completion, - @JsonProperty("stop_reason") String stopReason, - @JsonProperty("stop") String stop, - @JsonProperty("amazon-bedrock-invocationMetrics") AmazonBedrockInvocationMetrics amazonBedrockInvocationMetrics) { - } - -} -// @formatter:on diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic3/Anthropic3ChatOptions.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic3/Anthropic3ChatOptions.java deleted file mode 100644 index c0f1b65e7ac..00000000000 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic3/Anthropic3ChatOptions.java +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.anthropic3; - -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.fasterxml.jackson.annotation.JsonProperty; - -import org.springframework.ai.chat.prompt.ChatOptions; - -/** - * Options for the Anthropic 3 chat API. - * - * @author Ben Middleton - * @author Thomas Vitale - * @since 1.0.0 - */ -@JsonInclude(Include.NON_NULL) -public class Anthropic3ChatOptions implements ChatOptions { - - // @formatter:off - /** - * Controls the randomness of the output. Values can range over [0.0,1.0], inclusive. A value closer to 1.0 will - * produce responses that are more varied, while a value closer to 0.0 will typically result in less surprising - * responses from the generative. This value specifies default to be used by the backend while making the call to - * the generative. - */ - private @JsonProperty("temperature") Double temperature; - - /** - * Specify the maximum number of tokens to use in the generated response. Note that the models may stop before - * reaching this maximum. This parameter only specifies the absolute maximum number of tokens to generate. We - * recommend a limit of 4,000 tokens for optimal performance. - */ - private @JsonProperty("max_tokens") Integer maxTokens; - - /** - * Specify the number of token choices the generative uses to generate the next token. - */ - private @JsonProperty("top_k") Integer topK; - - /** - * The maximum cumulative probability of tokens to consider when sampling. The generative uses combined Top-k and - * nucleus sampling. Nucleus sampling considers the smallest set of tokens whose probability sum is at least topP. - */ - private @JsonProperty("top_p") Double topP; - - /** - * Configure up to four sequences that the generative recognizes. After a stop sequence, the generative stops - * generating further tokens. The returned text doesn't contain the stop sequence. - */ - private @JsonProperty("stop_sequences") List stopSequences; - - /** - * The version of the generative to use. The default value is bedrock-2023-05-31. - */ - private @JsonProperty("anthropic_version") String anthropicVersion; - // @formatter:on - - public Anthropic3ChatOptions() { - } - - /** - * Create a new {@link Anthropic3ChatOptions}. - * @return a new {@link Anthropic3ChatOptions} - */ - public static Builder builder() { - return new Builder(); - } - - /** - * Create a new {@link Anthropic3ChatOptions} from the provided - * {@link Anthropic3ChatOptions}. - * @param fromOptions the options to copy - * @return a new {@link Anthropic3ChatOptions} - */ - public static Anthropic3ChatOptions fromOptions(Anthropic3ChatOptions fromOptions) { - return builder().temperature(fromOptions.getTemperature()) - .maxTokens(fromOptions.getMaxTokens()) - .topK(fromOptions.getTopK()) - .topP(fromOptions.getTopP()) - .stopSequences(fromOptions.getStopSequences()) - .anthropicVersion(fromOptions.getAnthropicVersion()) - .build(); - } - - /** - * Get the temperature. - * @return the temperature - */ - @Override - public Double getTemperature() { - return this.temperature; - } - - /** - * Set the temperature. - * @param temperature the temperature - */ - public void setTemperature(Double temperature) { - this.temperature = temperature; - } - - /** - * Get the maximum number of tokens. - * @return the maximum number of tokens - */ - @Override - public Integer getMaxTokens() { - return this.maxTokens; - } - - /** - * Set the maximum number of tokens. - * @param maxTokens the maximum number of tokens - */ - public void setMaxTokens(Integer maxTokens) { - this.maxTokens = maxTokens; - } - - /** - * Get the top k. - * @return the top k - */ - @Override - public Integer getTopK() { - return this.topK; - } - - /** - * Set the top k. - * @param topK the top k - */ - public void setTopK(Integer topK) { - this.topK = topK; - } - - /** - * Get the top p. - * @return the top p - */ - @Override - public Double getTopP() { - return this.topP; - } - - /** - * Set the top p. - * @param topP the top p - */ - public void setTopP(Double topP) { - this.topP = topP; - } - - /** - * Get the stop sequences. - * @return the stop sequences - */ - @Override - public List getStopSequences() { - return this.stopSequences; - } - - /** - * Set the stop sequences. - * @param stopSequences the stop sequences - */ - public void setStopSequences(List stopSequences) { - this.stopSequences = stopSequences; - } - - /** - * Get the version of the generative to use. - * @return the version of the generative to use - */ - public String getAnthropicVersion() { - return this.anthropicVersion; - } - - /** - * Set the version of the generative to use. - * @param anthropicVersion the version of the generative to use - */ - public void setAnthropicVersion(String anthropicVersion) { - this.anthropicVersion = anthropicVersion; - } - - /** - * Get the model. - * @return the model - */ - @Override - @JsonIgnore - public String getModel() { - return null; - } - - /** - * Get the frequency penalty. - * @return the frequency penalty - */ - @Override - @JsonIgnore - public Double getFrequencyPenalty() { - return null; - } - - /** - * Get the presence penalty. - * @return the presence penalty - */ - @Override - @JsonIgnore - public Double getPresencePenalty() { - return null; - } - - /** - * Get the embedding dimensions. - * @return the embedding dimensions - */ - @Override - public Anthropic3ChatOptions copy() { - return fromOptions(this); - } - - /** - * Builder for {@link Anthropic3ChatOptions}. - */ - public static final class Builder { - - private final Anthropic3ChatOptions options = new Anthropic3ChatOptions(); - - private Builder() { - } - - /** - * Set the temperature. - * @param temperature the temperature - * @return this {@link Builder} instance - */ - public Builder temperature(Double temperature) { - this.options.setTemperature(temperature); - return this; - } - - /** - * Set the maximum number of tokens. - * @param maxTokens the maximum number of tokens - * @return this {@link Builder} instance - */ - public Builder maxTokens(Integer maxTokens) { - this.options.setMaxTokens(maxTokens); - return this; - } - - /** - * Set the top k. - * @param topK the top k - * @return this {@link Builder} instance - */ - public Builder topK(Integer topK) { - this.options.setTopK(topK); - return this; - } - - /** - * Set the top p. - * @param topP the top p - * @return this {@link Builder} instance - */ - public Builder topP(Double topP) { - this.options.setTopP(topP); - return this; - } - - /** - * Set the stop sequences. - * @param stopSequences the stop sequences - * @return this {@link Builder} instance - */ - public Builder stopSequences(List stopSequences) { - this.options.setStopSequences(stopSequences); - return this; - } - - /** - * Set the version of the generative to use. - * @param anthropicVersion the version of the generative to use - * @return this {@link Builder} instance - */ - public Builder anthropicVersion(String anthropicVersion) { - this.options.setAnthropicVersion(anthropicVersion); - return this; - } - - /** - * Build the {@link Anthropic3ChatOptions}. - * @return the {@link Anthropic3ChatOptions} - */ - public Anthropic3ChatOptions build() { - return this.options; - } - - } - -} diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic3/BedrockAnthropic3ChatModel.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic3/BedrockAnthropic3ChatModel.java deleted file mode 100644 index 977539fccf3..00000000000 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic3/BedrockAnthropic3ChatModel.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.anthropic3; - -import java.util.ArrayList; -import java.util.Base64; -import java.util.List; -import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.Collectors; - -import reactor.core.publisher.Flux; - -import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi; -import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi.AnthropicChatRequest; -import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi.AnthropicChatResponse; -import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi.AnthropicChatStreamingResponse.StreamingType; -import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi.ChatCompletionMessage; -import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi.ChatCompletionMessage.Role; -import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi.MediaContent; -import org.springframework.ai.chat.messages.AssistantMessage; -import org.springframework.ai.chat.messages.Message; -import org.springframework.ai.chat.messages.MessageType; -import org.springframework.ai.chat.messages.UserMessage; -import org.springframework.ai.chat.metadata.ChatGenerationMetadata; -import org.springframework.ai.chat.metadata.ChatResponseMetadata; -import org.springframework.ai.chat.metadata.DefaultUsage; -import org.springframework.ai.chat.metadata.Usage; -import org.springframework.ai.chat.model.ChatModel; -import org.springframework.ai.chat.model.ChatResponse; -import org.springframework.ai.chat.model.Generation; -import org.springframework.ai.chat.model.StreamingChatModel; -import org.springframework.ai.chat.prompt.ChatOptions; -import org.springframework.ai.chat.prompt.Prompt; -import org.springframework.ai.model.ModelOptionsUtils; -import org.springframework.util.CollectionUtils; - -/** - * Java {@link ChatModel} and {@link StreamingChatModel} for the Bedrock Anthropic chat - * generative. - * - * @author Ben Middleton - * @author Christian Tzolov - * @author Wei Jiang - * @author Alexandros Pappas - * @since 1.0.0 - * @deprecated in favor of the - * {@link org.springframework.ai.bedrock.converse.BedrockProxyChatModel}. - */ -@Deprecated -public class BedrockAnthropic3ChatModel implements ChatModel, StreamingChatModel { - - private final Anthropic3ChatBedrockApi anthropicChatApi; - - private final Anthropic3ChatOptions defaultOptions; - - public BedrockAnthropic3ChatModel(Anthropic3ChatBedrockApi chatApi) { - this(chatApi, - Anthropic3ChatOptions.builder() - .temperature(0.8) - .maxTokens(500) - .topK(10) - .anthropicVersion(Anthropic3ChatBedrockApi.DEFAULT_ANTHROPIC_VERSION) - .build()); - } - - public BedrockAnthropic3ChatModel(Anthropic3ChatBedrockApi chatApi, Anthropic3ChatOptions options) { - this.anthropicChatApi = chatApi; - this.defaultOptions = options; - } - - @Override - public ChatResponse call(Prompt prompt) { - - AnthropicChatRequest request = createRequest(prompt); - - AnthropicChatResponse response = this.anthropicChatApi.chatCompletion(request); - - List generations = response.content() - .stream() - .map(content -> new Generation(new AssistantMessage(content.text()), - ChatGenerationMetadata.builder().finishReason(response.stopReason()).build())) - .toList(); - - ChatResponseMetadata metadata = ChatResponseMetadata.builder() - .id(response.id()) - .model(response.model()) - .usage(extractUsage(response)) - .build(); - - return new ChatResponse(generations, metadata); - } - - @Override - public Flux stream(Prompt prompt) { - - AnthropicChatRequest request = createRequest(prompt); - - Flux fluxResponse = this.anthropicChatApi - .chatCompletionStream(request); - - AtomicReference inputTokens = new AtomicReference<>(0); - return fluxResponse.map(response -> { - if (response.type() == StreamingType.MESSAGE_START) { - inputTokens.set(response.message().usage().inputTokens()); - } - String content = response.type() == StreamingType.CONTENT_BLOCK_DELTA ? response.delta().text() : ""; - ChatGenerationMetadata chatGenerationMetadata = null; - if (response.type() == StreamingType.MESSAGE_DELTA) { - chatGenerationMetadata = ChatGenerationMetadata.builder() - .finishReason(response.delta().stopReason()) - .metadata("usage", - new Anthropic3ChatBedrockApi.AnthropicUsage(inputTokens.get(), - response.usage().outputTokens())) - .build(); - } - return new ChatResponse(List.of(new Generation(new AssistantMessage(content), chatGenerationMetadata))); - }); - } - - protected Usage extractUsage(AnthropicChatResponse response) { - return new DefaultUsage(response.usage().inputTokens(), response.usage().outputTokens()); - } - - /** - * Accessible for testing. - */ - AnthropicChatRequest createRequest(Prompt prompt) { - - AnthropicChatRequest request = AnthropicChatRequest.builder(toAnthropicMessages(prompt)) - .system(toAnthropicSystemContext(prompt)) - .build(); - - if (this.defaultOptions != null) { - request = ModelOptionsUtils.merge(request, this.defaultOptions, AnthropicChatRequest.class); - } - - if (prompt.getOptions() != null) { - Anthropic3ChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(prompt.getOptions(), - ChatOptions.class, Anthropic3ChatOptions.class); - request = ModelOptionsUtils.merge(updatedRuntimeOptions, request, AnthropicChatRequest.class); - } - - return request; - } - - /** - * Extracts system context from prompt. - * @param prompt The prompt. - * @return The system context. - */ - private String toAnthropicSystemContext(Prompt prompt) { - - return prompt.getInstructions() - .stream() - .filter(m -> m.getMessageType() == MessageType.SYSTEM) - .map(Message::getText) - .collect(Collectors.joining(System.lineSeparator())); - } - - /** - * Extracts list of messages from prompt. - * @param prompt The prompt. - * @return The list of {@link ChatCompletionMessage}. - */ - private List toAnthropicMessages(Prompt prompt) { - - return prompt.getInstructions() - .stream() - .filter(m -> m.getMessageType() == MessageType.USER || m.getMessageType() == MessageType.ASSISTANT) - .map(message -> { - List contents = new ArrayList<>(List.of(new MediaContent(message.getText()))); - if (message instanceof UserMessage userMessage) { - if (!CollectionUtils.isEmpty(userMessage.getMedia())) { - List mediaContent = userMessage.getMedia() - .stream() - .map(media -> new MediaContent(media.getMimeType().toString(), - this.fromMediaData(media.getData()))) - .toList(); - contents.addAll(mediaContent); - } - } - return new ChatCompletionMessage(contents, Role.valueOf(message.getMessageType().name())); - }) - .toList(); - } - - private String fromMediaData(Object mediaData) { - if (mediaData instanceof byte[] bytes) { - return Base64.getEncoder().encodeToString(bytes); - } - else if (mediaData instanceof String text) { - return text; - } - else { - throw new IllegalArgumentException("Unsupported media data type: " + mediaData.getClass().getSimpleName()); - } - } - - @Override - public ChatOptions getDefaultOptions() { - return Anthropic3ChatOptions.fromOptions(this.defaultOptions); - } - -} diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic3/api/Anthropic3ChatBedrockApi.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic3/api/Anthropic3ChatBedrockApi.java deleted file mode 100644 index 43cb1050352..00000000000 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic3/api/Anthropic3ChatBedrockApi.java +++ /dev/null @@ -1,590 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.anthropic3.api; - -import java.time.Duration; -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.ObjectMapper; -import reactor.core.publisher.Flux; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi.AnthropicChatRequest; -import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi.AnthropicChatResponse; -import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi.AnthropicChatStreamingResponse; -import org.springframework.ai.bedrock.api.AbstractBedrockApi; -import org.springframework.ai.model.ChatModelDescription; -import org.springframework.util.Assert; - -/** - * Based on Bedrock's Anthropic - * Claude Messages API. - * - * It is meant to replace the previous Chat API, which is now deprecated. - * - * @author Ben Middleton - * @author Christian Tzolov - * @author Thomas Vitale - * @author Wei Jiang - * @since 1.0.0 - */ -// @formatter:off -public class Anthropic3ChatBedrockApi extends - AbstractBedrockApi { - - /** - * Default version of the Anthropic chat model. - */ - public static final String DEFAULT_ANTHROPIC_VERSION = "bedrock-2023-05-31"; - - /** - * Create a new AnthropicChatBedrockApi instance using the default credentials provider chain, the default object. - * @param modelId The model id to use. See the {@link AnthropicChatModel} for the supported models. - * @param region The AWS region to use. - */ - public Anthropic3ChatBedrockApi(String modelId, String region) { - super(modelId, region); - } - - /** - * Create a new AnthropicChatBedrockApi instance using the default credentials provider chain, the default object. - * @param modelId The model id to use. See the {@link AnthropicChatModel} for the supported models. - * @param region The AWS region to use. - * @param timeout The timeout to use. - */ - public Anthropic3ChatBedrockApi(String modelId, String region, Duration timeout) { - super(modelId, region, timeout); - } - - /** - * Create a new AnthropicChatBedrockApi instance using the provided credentials provider, region and object mapper. - * - * @param modelId The model id to use. See the {@link AnthropicChatModel} for the supported models. - * @param credentialsProvider The credentials provider to connect to AWS. - * @param region The AWS region to use. - * @param objectMapper The object mapper to use for JSON serialization and deserialization. - */ - public Anthropic3ChatBedrockApi(String modelId, AwsCredentialsProvider credentialsProvider, String region, - ObjectMapper objectMapper) { - super(modelId, credentialsProvider, region, objectMapper); - } - - /** - * Create a new AnthropicChatBedrockApi instance using the provided credentials provider, region and object mapper. - * - * @param modelId The model id to use. See the {@link AnthropicChatModel} for the supported models. - * @param credentialsProvider The credentials provider to connect to AWS. - * @param region The AWS region to use. - * @param objectMapper The object mapper to use for JSON serialization and deserialization. - * @param timeout The timeout to use. - */ - public Anthropic3ChatBedrockApi(String modelId, AwsCredentialsProvider credentialsProvider, String region, - ObjectMapper objectMapper, Duration timeout) { - super(modelId, credentialsProvider, region, objectMapper, timeout); - } - - /** - * Create a new AnthropicChatBedrockApi instance using the provided credentials provider, region and object mapper. - * - * @param modelId The model id to use. See the {@link AnthropicChatModel} for the supported models. - * @param credentialsProvider The credentials provider to connect to AWS. - * @param region The AWS region to use. - * @param objectMapper The object mapper to use for JSON serialization and deserialization. - * @param timeout The timeout to use. - */ - public Anthropic3ChatBedrockApi(String modelId, AwsCredentialsProvider credentialsProvider, Region region, - ObjectMapper objectMapper, Duration timeout) { - super(modelId, credentialsProvider, region, objectMapper, timeout); - } - - // https://github.com/build-on-aws/amazon-bedrock-java-examples/blob/main/example_code/bedrock-runtime/src/main/java/aws/community/examples/InvokeBedrockStreamingAsync.java - - // https://docs.anthropic.com/claude/reference/complete_post - - // https://docs.aws.amazon.com/bedrock/latest/userguide/br-product-ids.html - - // Anthropic Claude models: https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-claude.html - - @Override - public AnthropicChatResponse chatCompletion(AnthropicChatRequest anthropicRequest) { - Assert.notNull(anthropicRequest, "'anthropicRequest' must not be null"); - return this.internalInvocation(anthropicRequest, AnthropicChatResponse.class); - } - - @Override - public Flux chatCompletionStream(AnthropicChatRequest anthropicRequest) { - Assert.notNull(anthropicRequest, "'anthropicRequest' must not be null"); - return this.internalInvocationStream(anthropicRequest, AnthropicChatStreamingResponse.class); - } - - /** - * Anthropic models version. - */ - public enum AnthropicChatModel implements ChatModelDescription { - - /** - * anthropic.claude-instant-v1 - */ - CLAUDE_INSTANT_V1("anthropic.claude-instant-v1"), - /** - * anthropic.claude-v2 - */ - CLAUDE_V2("anthropic.claude-v2"), - /** - * anthropic.claude-v2:1 - */ - CLAUDE_V21("anthropic.claude-v2:1"), - /** - * anthropic.claude-3-sonnet-20240229-v1:0 - */ - CLAUDE_V3_SONNET("anthropic.claude-3-sonnet-20240229-v1:0"), - /** - * anthropic.claude-3-haiku-20240307-v1:0 - */ - CLAUDE_V3_HAIKU("anthropic.claude-3-haiku-20240307-v1:0"), - /** - * anthropic.claude-3-opus-20240229-v1:0 - */ - CLAUDE_V3_OPUS("anthropic.claude-3-opus-20240229-v1:0"), - /** - * anthropic.claude-3-5-sonnet-20240620-v1:0 - */ - CLAUDE_V3_5_SONNET("anthropic.claude-3-5-sonnet-20240620-v1:0"), - /** - * anthropic.claude-3-5-sonnet-20241022-v2:0 - */ - CLAUDE_V3_5_SONNET_V2("anthropic.claude-3-5-sonnet-20241022-v2:0"); - - private final String id; - - AnthropicChatModel(String value) { - this.id = value; - } - - /** - * Get the model id. - * @return The model id. - */ - public String id() { - return this.id; - } - - @Override - public String getName() { - return this.id; - } - - } - - /** - * AnthropicChatRequest encapsulates the request parameters for the Anthropic messages model. - * https://docs.anthropic.com/claude/reference/messages_post - * - * @param messages A list of messages comprising the conversation so far. - * @param system A system prompt, providing context and instructions to Claude, such as specifying a particular goal - * or role. - * @param temperature (default 0.5) The temperature to use for the chat. You should either alter temperature or - * top_p, but not both. - * @param maxTokens (default 200) Specify the maximum number of tokens to use in the generated response. - * Note that the models may stop before reaching this maximum. This parameter only specifies the absolute maximum - * number of tokens to generate. We recommend a limit of 4,000 tokens for optimal performance. - * @param topK (default 250) Specify the number of token choices the model uses to generate the next token. - * @param topP (default 1) Nucleus sampling to specify the cumulative probability of the next token in range [0,1]. - * In nucleus sampling, we compute the cumulative distribution over all the options for each subsequent token in - * decreasing probability order and cut it off once it reaches a particular probability specified by top_p. You - * should either alter temperature or top_p, but not both. - * @param stopSequences (defaults to "\n\nHuman:") Configure up to four sequences that the model recognizes. After a - * stop sequence, the model stops generating further tokens. The returned text doesn't contain the stop sequence. - * @param anthropicVersion The version of the model to use. The default value is bedrock-2023-05-31. - */ - @JsonInclude(Include.NON_NULL) - public record AnthropicChatRequest( - @JsonProperty("messages") List messages, - @JsonProperty("system") String system, - @JsonProperty("temperature") Double temperature, - @JsonProperty("max_tokens") Integer maxTokens, - @JsonProperty("top_k") Integer topK, - @JsonProperty("top_p") Double topP, - @JsonProperty("stop_sequences") List stopSequences, - @JsonProperty("anthropic_version") String anthropicVersion) { - - /** - * Create a new {@link AnthropicChatRequest} instance. - * @param messages A list of messages comprising the conversation so far. - * @return the {@link AnthropicChatRequest} - */ - public static Builder builder(List messages) { - return new Builder(messages); - } - - /** - * Builder for {@link AnthropicChatRequest}. - */ - public static final class Builder { - private final List messages; - private String system; - private Double temperature; // = 0.7; - private Integer maxTokens; // = 500; - private Integer topK; // = 10; - private Double topP; - private List stopSequences; - private String anthropicVersion; - - private Builder(List messages) { - this.messages = messages; - } - - /** - * Set the system prompt. - * @param system A system prompt - * @return this {@link Builder} instance - */ - public Builder system(String system) { - this.system = system; - return this; - } - - /** - * Set the temperature. - * @param temperature The temperature - * @return this {@link Builder} instance - */ - public Builder temperature(Double temperature) { - this.temperature = temperature; - return this; - } - - /** - * Set the max tokens. - * @param maxTokens The max tokens - * @return this {@link Builder} instance - */ - public Builder maxTokens(Integer maxTokens) { - this.maxTokens = maxTokens; - return this; - } - - /** - * Set the top k. - * @param topK The top k - * @return this {@link Builder} instance - */ - public Builder topK(Integer topK) { - this.topK = topK; - return this; - } - - /** - * Set the top p. - * @param tpoP The top p - * @return this {@link Builder} instance - */ - public Builder topP(Double tpoP) { - this.topP = tpoP; - return this; - } - - /** - * Set the stop sequences. - * @param stopSequences The stop sequences - * @return this {@link Builder} instance - */ - public Builder stopSequences(List stopSequences) { - this.stopSequences = stopSequences; - return this; - } - - /** - * Set the anthropic version. - * @param anthropicVersion The anthropic version - * @return this {@link Builder} instance - */ - public Builder anthropicVersion(String anthropicVersion) { - this.anthropicVersion = anthropicVersion; - return this; - } - - /** - * Build the {@link AnthropicChatRequest}. - * @return the {@link AnthropicChatRequest} - */ - public AnthropicChatRequest build() { - return new AnthropicChatRequest( - this.messages, - this.system, - this.temperature, - this.maxTokens, - this.topK, - this.topP, - this.stopSequences, - this.anthropicVersion - ); - } - } - } - - /** - * Encapsulates the Amazon Bedrock invocation metrics. - * @param type the content type can be "text" or "image". - * @param source The source of the media content. Applicable for "image" types only. - * @param text The text of the message. Applicable for "text" types only. - * @param index The index of the content block. Applicable only for streaming - * responses. - */ - @JsonInclude(Include.NON_NULL) - public record MediaContent( - // @formatter:off - @JsonProperty("type") Type type, - @JsonProperty("source") Source source, - @JsonProperty("text") String text, - @JsonProperty("index") Integer index // applicable only for streaming responses. - ) { - // @formatter:on - - /** - * Create a new media content. - * @param mediaType The media type of the content. - * @param data The base64-encoded data of the content. - */ - public MediaContent(String mediaType, String data) { - this(new Source(mediaType, data)); - } - - /** - * Create a new media content. - * @param source The source of the media content. - */ - public MediaContent(Source source) { - this(Type.IMAGE, source, null, null); - } - - /** - * Create a new media content. - * @param text The text of the message. - */ - public MediaContent(String text) { - this(Type.TEXT, null, text, null); - } - - /** - * The type of this message. - */ - public enum Type { - - /** - * Text message. - */ - @JsonProperty("text") - TEXT, - /** - * Image message. - */ - @JsonProperty("image") - IMAGE - - } - - /** - * The source of the media content. (Applicable for "image" types only) - * - * @param type The type of the media content. Only "base64" is supported at the - * moment. - * @param mediaType The media type of the content. For example, "image/png" or - * "image/jpeg". - * @param data The base64-encoded data of the content. - */ - @JsonInclude(Include.NON_NULL) - public record Source( - // @formatter:off - @JsonProperty("type") String type, - @JsonProperty("media_type") String mediaType, - @JsonProperty("data") String data) { - // @formatter:on - - /** - * Create a new source. - * @param mediaType The media type of the content. - * @param data The base64-encoded data of the content. - */ - public Source(String mediaType, String data) { - this("base64", mediaType, data); - } - - } - - } - - /** - * Message comprising the conversation. - * - * @param content The contents of the message. - * @param role The role of the messages author. Could be one of the {@link Role} - * types. - */ - @JsonInclude(Include.NON_NULL) - public record ChatCompletionMessage(@JsonProperty("content") List content, - @JsonProperty("role") Role role) { - - /** - * The role of the author of this message. - */ - public enum Role { - - /** - * User message. - */ - @JsonProperty("user") - USER, - /** - * Assistant message. - */ - @JsonProperty("assistant") - ASSISTANT - - } - - } - - /** - * Encapsulates the metrics about the model invocation. - * https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-anthropic-claude-messages.html#model-parameters-anthropic-claude-messages-request-response - * - * @param inputTokens The number of tokens in the input prompt. - * @param outputTokens The number of tokens in the generated text. - */ - @JsonInclude(Include.NON_NULL) - public record AnthropicUsage(@JsonProperty("input_tokens") Integer inputTokens, - @JsonProperty("output_tokens") Integer outputTokens) { - - } - - /** - * AnthropicChatResponse encapsulates the response parameters for the Anthropic - * messages model. - * - * @param id The unique response identifier. - * @param model The ID for the Anthropic Claude model that made the request. - * @param type The type of the response. - * @param role The role of the response. - * @param content The list of generated text. - * @param stopReason The reason the model stopped generating text: end_turn – The - * model reached a natural stopping point. max_tokens – The generated text exceeded - * the value of the max_tokens input field or exceeded the maximum number of tokens - * that the model supports. stop_sequence – The model generated one of the stop - * sequences that you specified in the stop_sequences input field. - * @param stopSequence The stop sequence that caused the model to stop generating - * text. - * @param usage Metrics about the model invocation. - * @param amazonBedrockInvocationMetrics The metrics about the model invocation. - */ - @JsonInclude(Include.NON_NULL) - public record AnthropicChatResponse(// formatter:off - @JsonProperty("id") String id, @JsonProperty("model") String model, @JsonProperty("type") String type, - @JsonProperty("role") String role, @JsonProperty("content") List content, - @JsonProperty("stop_reason") String stopReason, @JsonProperty("stop_sequence") String stopSequence, - @JsonProperty("usage") AnthropicUsage usage, - @JsonProperty("amazon-bedrock-invocationMetrics") AmazonBedrockInvocationMetrics amazonBedrockInvocationMetrics) { // formatter:on - - } - - /** - * AnthropicChatStreamingResponse encapsulates the streaming response parameters for - * the Anthropic messages model. - * https://docs.anthropic.com/claude/reference/messages-streaming - * - * @param type The streaming type. - * @param message The message details that made the request. - * @param index The delta index. - * @param contentBlock The generated text. - * @param delta The delta. - * @param usage The usage data. - * @param amazonBedrockInvocationMetrics The metrics about the model invocation. - */ - @JsonInclude(Include.NON_NULL) - public record AnthropicChatStreamingResponse(// formatter:off - @JsonProperty("type") StreamingType type, @JsonProperty("message") AnthropicChatResponse message, - @JsonProperty("index") Integer index, @JsonProperty("content_block") MediaContent contentBlock, - @JsonProperty("delta") Delta delta, @JsonProperty("usage") AnthropicUsage usage, - @JsonProperty("amazon-bedrock-invocationMetrics") AmazonBedrockInvocationMetrics amazonBedrockInvocationMetrics) { // formatter:on - - /** - * The streaming type of this message. - */ - public enum StreamingType { - - /** - * Message start. - */ - @JsonProperty("message_start") - MESSAGE_START, - /** - * Content block start. - */ - @JsonProperty("content_block_start") - CONTENT_BLOCK_START, - /** - * Ping. - */ - @JsonProperty("ping") - PING, - /** - * Content block delta. - */ - @JsonProperty("content_block_delta") - CONTENT_BLOCK_DELTA, - /** - * Content block stop. - */ - @JsonProperty("content_block_stop") - CONTENT_BLOCK_STOP, - /** - * Message delta. - */ - @JsonProperty("message_delta") - MESSAGE_DELTA, - /** - * Message stop. - */ - @JsonProperty("message_stop") - MESSAGE_STOP - - } - - /** - * Encapsulates a delta. - * https://docs.anthropic.com/claude/reference/messages-streaming * - * - * @param type The type of the message. - * @param text The text message. - * @param stopReason The stop reason. - * @param stopSequence The stop sequence. - */ - @JsonInclude(Include.NON_NULL) - public record Delta(@JsonProperty("type") String type, @JsonProperty("text") String text, - @JsonProperty("stop_reason") String stopReason, @JsonProperty("stop_sequence") String stopSequence) { - - } - - } - -} -// @formatter:on diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/aot/BedrockRuntimeHints.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/aot/BedrockRuntimeHints.java index 0ec06b678e9..0bec3c1c9f3 100644 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/aot/BedrockRuntimeHints.java +++ b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/aot/BedrockRuntimeHints.java @@ -16,21 +16,10 @@ package org.springframework.ai.bedrock.aot; -import org.springframework.ai.bedrock.anthropic.AnthropicChatOptions; -import org.springframework.ai.bedrock.anthropic.api.AnthropicChatBedrockApi; -import org.springframework.ai.bedrock.anthropic3.Anthropic3ChatOptions; -import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi; import org.springframework.ai.bedrock.api.AbstractBedrockApi; -import org.springframework.ai.bedrock.cohere.BedrockCohereChatOptions; import org.springframework.ai.bedrock.cohere.BedrockCohereEmbeddingOptions; -import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi; import org.springframework.ai.bedrock.cohere.api.CohereEmbeddingBedrockApi; -import org.springframework.ai.bedrock.jurassic2.api.Ai21Jurassic2ChatBedrockApi; -import org.springframework.ai.bedrock.llama.BedrockLlamaChatOptions; -import org.springframework.ai.bedrock.llama.api.LlamaChatBedrockApi; -import org.springframework.ai.bedrock.titan.BedrockTitanChatOptions; import org.springframework.ai.bedrock.titan.BedrockTitanEmbeddingOptions; -import org.springframework.ai.bedrock.titan.api.TitanChatBedrockApi; import org.springframework.ai.bedrock.titan.api.TitanEmbeddingBedrockApi; import org.springframework.aot.hint.MemberCategory; import org.springframework.aot.hint.RuntimeHints; @@ -55,16 +44,7 @@ public void registerHints(RuntimeHints hints, ClassLoader classLoader) { for (var tr : findJsonAnnotatedClassesInPackage(AbstractBedrockApi.class)) { hints.reflection().registerType(tr, mcs); } - for (var tr : findJsonAnnotatedClassesInPackage(Ai21Jurassic2ChatBedrockApi.class)) { - hints.reflection().registerType(tr, mcs); - } - for (var tr : findJsonAnnotatedClassesInPackage(CohereChatBedrockApi.class)) { - hints.reflection().registerType(tr, mcs); - } - for (var tr : findJsonAnnotatedClassesInPackage(BedrockCohereChatOptions.class)) { - hints.reflection().registerType(tr, mcs); - } for (var tr : findJsonAnnotatedClassesInPackage(CohereEmbeddingBedrockApi.class)) { hints.reflection().registerType(tr, mcs); } @@ -72,39 +52,12 @@ public void registerHints(RuntimeHints hints, ClassLoader classLoader) { hints.reflection().registerType(tr, mcs); } - for (var tr : findJsonAnnotatedClassesInPackage(LlamaChatBedrockApi.class)) { - hints.reflection().registerType(tr, mcs); - } - for (var tr : findJsonAnnotatedClassesInPackage(BedrockLlamaChatOptions.class)) { - hints.reflection().registerType(tr, mcs); - } - - for (var tr : findJsonAnnotatedClassesInPackage(TitanChatBedrockApi.class)) { - hints.reflection().registerType(tr, mcs); - } - for (var tr : findJsonAnnotatedClassesInPackage(BedrockTitanChatOptions.class)) { - hints.reflection().registerType(tr, mcs); - } for (var tr : findJsonAnnotatedClassesInPackage(BedrockTitanEmbeddingOptions.class)) { hints.reflection().registerType(tr, mcs); } for (var tr : findJsonAnnotatedClassesInPackage(TitanEmbeddingBedrockApi.class)) { hints.reflection().registerType(tr, mcs); } - - for (var tr : findJsonAnnotatedClassesInPackage(AnthropicChatBedrockApi.class)) { - hints.reflection().registerType(tr, mcs); - } - for (var tr : findJsonAnnotatedClassesInPackage(AnthropicChatOptions.class)) { - hints.reflection().registerType(tr, mcs); - } - - for (var tr : findJsonAnnotatedClassesInPackage(Anthropic3ChatBedrockApi.class)) { - hints.reflection().registerType(tr, mcs); - } - for (var tr : findJsonAnnotatedClassesInPackage(Anthropic3ChatOptions.class)) { - hints.reflection().registerType(tr, mcs); - } } } diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/BedrockCohereChatModel.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/BedrockCohereChatModel.java deleted file mode 100644 index 5506245932a..00000000000 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/BedrockCohereChatModel.java +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.cohere; - -import java.util.List; - -import reactor.core.publisher.Flux; - -import org.springframework.ai.bedrock.MessageToPromptConverter; -import org.springframework.ai.bedrock.api.AbstractBedrockApi; -import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi; -import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi.CohereChatRequest; -import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi.CohereChatResponse; -import org.springframework.ai.chat.messages.AssistantMessage; -import org.springframework.ai.chat.metadata.ChatGenerationMetadata; -import org.springframework.ai.chat.metadata.DefaultUsage; -import org.springframework.ai.chat.metadata.Usage; -import org.springframework.ai.chat.model.ChatModel; -import org.springframework.ai.chat.model.ChatResponse; -import org.springframework.ai.chat.model.Generation; -import org.springframework.ai.chat.model.StreamingChatModel; -import org.springframework.ai.chat.prompt.ChatOptions; -import org.springframework.ai.chat.prompt.Prompt; -import org.springframework.ai.model.ModelOptionsUtils; -import org.springframework.util.Assert; - -/** - * A {@link ChatModel} implementation that uses the Cohere Chat API. - * - * @author Christian Tzolov - * @since 0.8.0 - * @deprecated in favor of the - * {@link org.springframework.ai.bedrock.converse.BedrockProxyChatModel}. - */ -@Deprecated -public class BedrockCohereChatModel implements ChatModel, StreamingChatModel { - - private final CohereChatBedrockApi chatApi; - - private final BedrockCohereChatOptions defaultOptions; - - public BedrockCohereChatModel(CohereChatBedrockApi chatApi) { - this(chatApi, BedrockCohereChatOptions.builder().build()); - } - - public BedrockCohereChatModel(CohereChatBedrockApi chatApi, BedrockCohereChatOptions options) { - Assert.notNull(chatApi, "CohereChatBedrockApi must not be null"); - Assert.notNull(options, "BedrockCohereChatOptions must not be null"); - - this.chatApi = chatApi; - this.defaultOptions = options; - } - - @Override - public ChatResponse call(Prompt prompt) { - CohereChatResponse response = this.chatApi.chatCompletion(this.createRequest(prompt, false)); - List generations = response.generations() - .stream() - .map(g -> new Generation(new AssistantMessage(g.text()))) - .toList(); - - return new ChatResponse(generations); - } - - @Override - public Flux stream(Prompt prompt) { - return this.chatApi.chatCompletionStream(this.createRequest(prompt, true)).map(g -> { - if (g.isFinished()) { - String finishReason = g.finishReason().name(); - Usage usage = getDefaultUsage(g.amazonBedrockInvocationMetrics()); - return new ChatResponse(List.of(new Generation(new AssistantMessage(""), - ChatGenerationMetadata.builder().finishReason(finishReason).metadata("usage", usage).build()))); - } - return new ChatResponse(List.of(new Generation(new AssistantMessage(g.text())))); - }); - } - - private DefaultUsage getDefaultUsage(AbstractBedrockApi.AmazonBedrockInvocationMetrics usage) { - return new DefaultUsage(usage.inputTokenCount().intValue(), usage.outputTokenCount().intValue(), - usage.inputTokenCount().intValue() + usage.outputTokenCount().intValue(), usage); - } - - /** - * Test access. - */ - CohereChatRequest createRequest(Prompt prompt, boolean stream) { - final String promptValue = MessageToPromptConverter.create().toPrompt(prompt.getInstructions()); - - var request = CohereChatRequest.builder(promptValue) - .temperature(this.defaultOptions.getTemperature()) - .topP(this.defaultOptions.getTopP()) - .topK(this.defaultOptions.getTopK()) - .maxTokens(this.defaultOptions.getMaxTokens()) - .stopSequences(this.defaultOptions.getStopSequences()) - .returnLikelihoods(this.defaultOptions.getReturnLikelihoods()) - .stream(stream) - .numGenerations(this.defaultOptions.getNumGenerations()) - .logitBias(this.defaultOptions.getLogitBias()) - .truncate(this.defaultOptions.getTruncate()) - .build(); - - if (prompt.getOptions() != null) { - BedrockCohereChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(prompt.getOptions(), - ChatOptions.class, BedrockCohereChatOptions.class); - request = ModelOptionsUtils.merge(updatedRuntimeOptions, request, CohereChatRequest.class); - } - - return request; - } - - @Override - public ChatOptions getDefaultOptions() { - return BedrockCohereChatOptions.fromOptions(this.defaultOptions); - } - -} diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/BedrockCohereChatOptions.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/BedrockCohereChatOptions.java deleted file mode 100644 index cbde17d425b..00000000000 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/BedrockCohereChatOptions.java +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.cohere; - -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.fasterxml.jackson.annotation.JsonProperty; - -import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi.CohereChatRequest.LogitBias; -import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi.CohereChatRequest.ReturnLikelihoods; -import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi.CohereChatRequest.Truncate; -import org.springframework.ai.chat.prompt.ChatOptions; - -/** - * Options for the Bedrock Cohere chat API. - * - * @author Christian Tzolov - * @author Thomas Vitale - * @author Ilayaperumal Gopinathan - * @since 0.8.0 - */ -@JsonInclude(Include.NON_NULL) -public class BedrockCohereChatOptions implements ChatOptions { - - // @formatter:off - /** - * (optional) Use a lower value to decrease randomness in the response. Defaults to - * 0.7. - */ - @JsonProperty("temperature") - Double temperature; - /** - * (optional) The maximum cumulative probability of tokens to consider when sampling. - * The generative uses combined Top-k and nucleus sampling. Nucleus sampling considers - * the smallest set of tokens whose probability sum is at least topP. - */ - @JsonProperty("p") - Double topP; - /** - * (optional) Specify the number of token choices the generative uses to generate the - * next token. - */ - @JsonProperty("k") - Integer topK; - /** - * (optional) Specify the maximum number of tokens to use in the generated response. - */ - @JsonProperty("max_tokens") - Integer maxTokens; - /** - * (optional) Configure up to four sequences that the generative recognizes. After a - * stop sequence, the generative stops generating further tokens. The returned text - * doesn't contain the stop sequence. - */ - @JsonProperty("stop_sequences") - List stopSequences; - /** - * (optional) Specify how and if the token likelihoods are returned with the response. - */ - @JsonProperty("return_likelihoods") - ReturnLikelihoods returnLikelihoods; - /** - * (optional) The maximum number of generations that the generative should return. - */ - @JsonProperty("num_generations") - Integer numGenerations; - /** - * Prevents the model from generating unwanted tokens or incentivize the model to include desired tokens. - */ - @JsonProperty("logit_bias") - LogitBias logitBias; - /** - * (optional) Specifies how the API handles inputs longer than the maximum token - * length. - */ - @JsonProperty("truncate") - Truncate truncate; - // @formatter:on - - public static Builder builder() { - return new Builder(); - } - - public static BedrockCohereChatOptions fromOptions(BedrockCohereChatOptions fromOptions) { - return builder().temperature(fromOptions.getTemperature()) - .topP(fromOptions.getTopP()) - .topK(fromOptions.getTopK()) - .maxTokens(fromOptions.getMaxTokens()) - .stopSequences(fromOptions.getStopSequences()) - .returnLikelihoods(fromOptions.getReturnLikelihoods()) - .numGenerations(fromOptions.getNumGenerations()) - .logitBias(fromOptions.getLogitBias()) - .truncate(fromOptions.getTruncate()) - .build(); - } - - @Override - public Double getTemperature() { - return this.temperature; - } - - public void setTemperature(Double temperature) { - this.temperature = temperature; - } - - @Override - public Double getTopP() { - return this.topP; - } - - public void setTopP(Double topP) { - this.topP = topP; - } - - @Override - public Integer getTopK() { - return this.topK; - } - - public void setTopK(Integer topK) { - this.topK = topK; - } - - @Override - public Integer getMaxTokens() { - return this.maxTokens; - } - - public void setMaxTokens(Integer maxTokens) { - this.maxTokens = maxTokens; - } - - @Override - public List getStopSequences() { - return this.stopSequences; - } - - public void setStopSequences(List stopSequences) { - this.stopSequences = stopSequences; - } - - public ReturnLikelihoods getReturnLikelihoods() { - return this.returnLikelihoods; - } - - public void setReturnLikelihoods(ReturnLikelihoods returnLikelihoods) { - this.returnLikelihoods = returnLikelihoods; - } - - public Integer getNumGenerations() { - return this.numGenerations; - } - - public void setNumGenerations(Integer numGenerations) { - this.numGenerations = numGenerations; - } - - public LogitBias getLogitBias() { - return this.logitBias; - } - - public void setLogitBias(LogitBias logitBias) { - this.logitBias = logitBias; - } - - public Truncate getTruncate() { - return this.truncate; - } - - public void setTruncate(Truncate truncate) { - this.truncate = truncate; - } - - @Override - @JsonIgnore - public String getModel() { - return null; - } - - @Override - @JsonIgnore - public Double getFrequencyPenalty() { - return null; - } - - @Override - @JsonIgnore - public Double getPresencePenalty() { - return null; - } - - @Override - public BedrockCohereChatOptions copy() { - return fromOptions(this); - } - - public static class Builder { - - private final BedrockCohereChatOptions options = new BedrockCohereChatOptions(); - - public Builder temperature(Double temperature) { - this.options.setTemperature(temperature); - return this; - } - - public Builder topP(Double topP) { - this.options.setTopP(topP); - return this; - } - - public Builder topK(Integer topK) { - this.options.setTopK(topK); - return this; - } - - public Builder maxTokens(Integer maxTokens) { - this.options.setMaxTokens(maxTokens); - return this; - } - - public Builder stopSequences(List stopSequences) { - this.options.setStopSequences(stopSequences); - return this; - } - - public Builder returnLikelihoods(ReturnLikelihoods returnLikelihoods) { - this.options.setReturnLikelihoods(returnLikelihoods); - return this; - } - - public Builder numGenerations(Integer numGenerations) { - this.options.setNumGenerations(numGenerations); - return this; - } - - public Builder logitBias(LogitBias logitBias) { - this.options.setLogitBias(logitBias); - return this; - } - - public Builder truncate(Truncate truncate) { - this.options.setTruncate(truncate); - return this; - } - - public BedrockCohereChatOptions build() { - return this.options; - } - - } - -} diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/api/CohereChatBedrockApi.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/api/CohereChatBedrockApi.java deleted file mode 100644 index 4ae18f12bb7..00000000000 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/api/CohereChatBedrockApi.java +++ /dev/null @@ -1,420 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.cohere.api; - -// @formatter:off - -import java.time.Duration; -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.ObjectMapper; -import reactor.core.publisher.Flux; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.bedrock.api.AbstractBedrockApi; -import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi.CohereChatRequest; -import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi.CohereChatResponse; -import org.springframework.ai.model.ChatModelDescription; -import org.springframework.util.Assert; - -/** - * Java client for the Bedrock Cohere chat model. - * https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-cohere.html - * - * @author Christian Tzolov - * @author Thomas Vitale - * @author Wei Jiang - * @author Ilayaperumal Gopinathan - * @since 0.8.0 - */ -public class CohereChatBedrockApi extends - AbstractBedrockApi { - - /** - * Create a new CohereChatBedrockApi instance using the default credentials provider chain, the default object - * mapper, default temperature and topP values. - * - * @param modelId The model id to use. See the {@link CohereChatModel} for the supported models. - * @param region The AWS region to use. - */ - public CohereChatBedrockApi(String modelId, String region) { - super(modelId, region); - } - - /** - * Create a new CohereChatBedrockApi instance using the provided credentials provider, region and object mapper. - * - * @param modelId The model id to use. See the {@link CohereChatModel} for the supported models. - * @param credentialsProvider The credentials provider to connect to AWS. - * @param region The AWS region to use. - * @param objectMapper The object mapper to use for JSON serialization and deserialization. - */ - public CohereChatBedrockApi(String modelId, AwsCredentialsProvider credentialsProvider, String region, - ObjectMapper objectMapper) { - super(modelId, credentialsProvider, region, objectMapper); - } - - /** - * Create a new CohereChatBedrockApi instance using the default credentials provider chain, the default object - * mapper, default temperature and topP values. - * - * @param modelId The model id to use. See the {@link CohereChatModel} for the supported models. - * @param region The AWS region to use. - * @param timeout The timeout to use. - */ - public CohereChatBedrockApi(String modelId, String region, Duration timeout) { - super(modelId, region, timeout); - } - - /** - * Create a new CohereChatBedrockApi instance using the provided credentials provider, region and object mapper. - * - * @param modelId The model id to use. See the {@link CohereChatModel} for the supported models. - * @param credentialsProvider The credentials provider to connect to AWS. - * @param region The AWS region to use. - * @param objectMapper The object mapper to use for JSON serialization and deserialization. - * @param timeout The timeout to use. - */ - public CohereChatBedrockApi(String modelId, AwsCredentialsProvider credentialsProvider, String region, - ObjectMapper objectMapper, Duration timeout) { - super(modelId, credentialsProvider, region, objectMapper, timeout); - } - - /** - * Create a new CohereChatBedrockApi instance using the provided credentials provider, region and object mapper. - * - * @param modelId The model id to use. See the {@link CohereChatModel} for the supported models. - * @param credentialsProvider The credentials provider to connect to AWS. - * @param region The AWS region to use. - * @param objectMapper The object mapper to use for JSON serialization and deserialization. - * @param timeout The timeout to use. - */ - public CohereChatBedrockApi(String modelId, AwsCredentialsProvider credentialsProvider, Region region, - ObjectMapper objectMapper, Duration timeout) { - super(modelId, credentialsProvider, region, objectMapper, timeout); - } - - @Override - public CohereChatResponse chatCompletion(CohereChatRequest request) { - Assert.isTrue(!request.stream(), "The request must be configured to return the complete response!"); - return this.internalInvocation(request, CohereChatResponse.class); - } - - @Override - public Flux chatCompletionStream(CohereChatRequest request) { - Assert.isTrue(request.stream(), "The request must be configured to stream the response!"); - return this.internalInvocationStream(request, CohereChatResponse.Generation.class); - } - - /** - * Cohere models version. - */ - public enum CohereChatModel implements ChatModelDescription { - - /** - * cohere.command-light-text-v14 - */ - COHERE_COMMAND_LIGHT_V14("cohere.command-light-text-v14"), - - /** - * cohere.command-text-v14 - */ - COHERE_COMMAND_V14("cohere.command-text-v14"); - - private final String id; - - CohereChatModel(String value) { - this.id = value; - } - - /** - * @return The model id. - */ - public String id() { - return this.id; - } - - @Override - public String getName() { - return this.id; - } - } - - /** - * CohereChatRequest encapsulates the request parameters for the Cohere command model. - * - * @param prompt The input prompt to generate the response from. - * @param temperature (optional) Use a lower value to decrease randomness in the response. - * @param topP (optional) Use a lower value to ignore less probable options. Set to 0 or 1.0 to disable. - * @param topK (optional) Specify the number of token choices the model uses to generate the next token. - * @param maxTokens (optional) Specify the maximum number of tokens to use in the generated response. - * @param stopSequences (optional) Configure up to four sequences that the model recognizes. After a stop sequence, - * the model stops generating further tokens. The returned text doesn't contain the stop sequence. - * @param returnLikelihoods (optional) Specify how and if the token likelihoods are returned with the response. - * @param stream (optional) Specify true to return the response piece-by-piece in real-time and false to return the - * complete response after the process finishes. - * @param numGenerations (optional) The maximum number of generations that the model should return. - * @param logitBias (optional) prevents the model from generating unwanted tokens or incentivize the model to - * include desired tokens. The format is {token_id: bias} where bias is a float between -10 and 10. Tokens can be - * obtained from text using any tokenization service, such as Cohere’s Tokenize endpoint. - * @param truncate (optional) Specifies how the API handles inputs longer than the maximum token length. - */ - @JsonInclude(Include.NON_NULL) - public record CohereChatRequest( - @JsonProperty("prompt") String prompt, - @JsonProperty("temperature") Double temperature, - @JsonProperty("p") Double topP, - @JsonProperty("k") Integer topK, - @JsonProperty("max_tokens") Integer maxTokens, - @JsonProperty("stop_sequences") List stopSequences, - @JsonProperty("return_likelihoods") ReturnLikelihoods returnLikelihoods, - @JsonProperty("stream") boolean stream, - @JsonProperty("num_generations") Integer numGenerations, - @JsonProperty("logit_bias") LogitBias logitBias, - @JsonProperty("truncate") Truncate truncate) { - - /** - * Get CohereChatRequest builder. - * @param prompt compulsory request prompt parameter. - * @return CohereChatRequest builder. - */ - public static Builder builder(String prompt) { - return new Builder(prompt); - } - - /** - * (optional) Specify how and if the token likelihoods are returned with the response. - */ - public enum ReturnLikelihoods { - /** - * Only return likelihoods for generated tokens. - */ - GENERATION, - /** - * Return likelihoods for all tokens. - */ - ALL, - /** - * (Default) Don't return any likelihoods. - */ - NONE - } - - /** - * Specifies how the API handles inputs longer than the maximum token length. If you specify START or END, the - * model discards the input until the remaining input is exactly the maximum input token length for the model. - */ - public enum Truncate { - /** - * Returns an error when the input exceeds the maximum input token length. - */ - NONE, - /** - * Discard the start of the input. - */ - START, - /** - * (Default) Discards the end of the input. - */ - END - } - - /** - * Prevents the model from generating unwanted tokens or incentivize the model to include desired tokens. - * - * @param token The token likelihoods. - * @param bias A float between -10 and 10. - */ - @JsonInclude(Include.NON_NULL) - public record LogitBias( - @JsonProperty("token") String token, - @JsonProperty("bias") Float bias) { - } - - /** - * Builder for the CohereChatRequest. - */ - public static class Builder { - private final String prompt; - private Double temperature; - private Double topP; - private Integer topK; - private Integer maxTokens; - private List stopSequences; - private ReturnLikelihoods returnLikelihoods; - private boolean stream; - private Integer numGenerations; - private LogitBias logitBias; - private Truncate truncate; - - public Builder(String prompt) { - this.prompt = prompt; - } - - public Builder temperature(Double temperature) { - this.temperature = temperature; - return this; - } - - public Builder topP(Double topP) { - this.topP = topP; - return this; - } - - public Builder topK(Integer topK) { - this.topK = topK; - return this; - } - - public Builder maxTokens(Integer maxTokens) { - this.maxTokens = maxTokens; - return this; - } - - public Builder stopSequences(List stopSequences) { - this.stopSequences = stopSequences; - return this; - } - - public Builder returnLikelihoods(ReturnLikelihoods returnLikelihoods) { - this.returnLikelihoods = returnLikelihoods; - return this; - } - - public Builder stream(boolean stream) { - this.stream = stream; - return this; - } - - public Builder numGenerations(Integer numGenerations) { - this.numGenerations = numGenerations; - return this; - } - - public Builder logitBias(LogitBias logitBias) { - this.logitBias = logitBias; - return this; - } - - public Builder truncate(Truncate truncate) { - this.truncate = truncate; - return this; - } - - public CohereChatRequest build() { - return new CohereChatRequest( - this.prompt, - this.temperature, - this.topP, - this.topK, - this.maxTokens, - this.stopSequences, - this.returnLikelihoods, - this.stream, - this.numGenerations, - this.logitBias, - this.truncate - ); - } - } - } - - /** - * CohereChatResponse encapsulates the response parameters for the Cohere command model. - * - * @param id An identifier for the request (always returned). - * @param prompt The prompt from the input request. (Always returned). - * @param generations A list of generated results along with the likelihoods for tokens requested. (Always - * returned). - */ - @JsonInclude(Include.NON_NULL) - public record CohereChatResponse( - @JsonProperty("id") String id, - @JsonProperty("prompt") String prompt, - @JsonProperty("generations") List generations) { - - /** - * Generated result along with the likelihoods for tokens requested. - * - * @param id An identifier for the generation. (Always returned). - * @param eventType The type of event that occurred. (Always returned). - * @param likelihood The likelihood of the output. The value is the average of the token likelihoods in - * token_likelihoods. Returned if you specify the return_likelihoods input parameter. - * @param tokenLikelihoods An array of per token likelihoods. Returned if you specify the return_likelihoods - * input parameter. - * @param finishReason states the reason why the model finished generating tokens. - * @param isFinished A boolean field used only when stream is true, signifying whether or not there are - * additional tokens that will be generated as part of the streaming response. (Not always returned). - * @param text The generated text. - * @param index In a streaming response, use to determine which generation a given token belongs to. When only - * one response is streamed, all tokens belong to the same generation and index is not returned. index therefore - * is only returned in a streaming request with a value for num_generations that is larger than one. - * @param amazonBedrockInvocationMetrics Encapsulates the metrics about the model invocation. - */ - @JsonInclude(Include.NON_NULL) - public record Generation( - @JsonProperty("id") String id, - @JsonProperty("event_type") String eventType, - @JsonProperty("likelihood") Float likelihood, - @JsonProperty("token_likelihoods") List tokenLikelihoods, - @JsonProperty("finish_reason") FinishReason finishReason, - @JsonProperty("is_finished") Boolean isFinished, - @JsonProperty("text") String text, - @JsonProperty("index") Integer index, - @JsonProperty("amazon-bedrock-invocationMetrics") AmazonBedrockInvocationMetrics amazonBedrockInvocationMetrics) { - - /** - * The reason the response finished being generated. - */ - public enum FinishReason { - /** - * The model sent back a finished reply. - */ - COMPLETE, - /** - * The reply was cut off because the model reached the maximum number of tokens for its context length. - */ - MAX_TOKENS, - /** - * Something went wrong when generating the reply. - */ - ERROR, - /** - * the model generated a reply that was deemed toxic. finish_reason is returned only when - * is_finished=true. (Not always returned). - */ - ERROR_TOXIC - } - - /** - * Token likelihood. - * @param token The token. - * @param likelihood The likelihood of the token. - */ - @JsonInclude(Include.NON_NULL) - public record TokenLikelihood( - @JsonProperty("token") String token, - @JsonProperty("likelihood") Float likelihood) { - } - } - } -} -// @formatter:on diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/jurassic2/BedrockAi21Jurassic2ChatModel.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/jurassic2/BedrockAi21Jurassic2ChatModel.java deleted file mode 100644 index a7981a8f487..00000000000 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/jurassic2/BedrockAi21Jurassic2ChatModel.java +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.jurassic2; - -import org.springframework.ai.bedrock.MessageToPromptConverter; -import org.springframework.ai.bedrock.jurassic2.api.Ai21Jurassic2ChatBedrockApi; -import org.springframework.ai.bedrock.jurassic2.api.Ai21Jurassic2ChatBedrockApi.Ai21Jurassic2ChatRequest; -import org.springframework.ai.chat.messages.AssistantMessage; -import org.springframework.ai.chat.metadata.ChatGenerationMetadata; -import org.springframework.ai.chat.model.ChatModel; -import org.springframework.ai.chat.model.ChatResponse; -import org.springframework.ai.chat.model.Generation; -import org.springframework.ai.chat.prompt.ChatOptions; -import org.springframework.ai.chat.prompt.Prompt; -import org.springframework.ai.model.ModelOptionsUtils; -import org.springframework.util.Assert; - -/** - * Java {@link ChatModel} for the Bedrock Jurassic2 chat generative model. - * - * @author Ahmed Yousri - * @since 1.0.0 - * @deprecated in favor of the - * {@link org.springframework.ai.bedrock.converse.BedrockProxyChatModel}. - */ -@Deprecated -public class BedrockAi21Jurassic2ChatModel implements ChatModel { - - private final Ai21Jurassic2ChatBedrockApi chatApi; - - private final BedrockAi21Jurassic2ChatOptions defaultOptions; - - public BedrockAi21Jurassic2ChatModel(Ai21Jurassic2ChatBedrockApi chatApi, BedrockAi21Jurassic2ChatOptions options) { - Assert.notNull(chatApi, "Ai21Jurassic2ChatBedrockApi must not be null"); - Assert.notNull(options, "BedrockAi21Jurassic2ChatOptions must not be null"); - - this.chatApi = chatApi; - this.defaultOptions = options; - } - - public BedrockAi21Jurassic2ChatModel(Ai21Jurassic2ChatBedrockApi chatApi) { - this(chatApi, BedrockAi21Jurassic2ChatOptions.builder().temperature(0.8).topP(0.9).maxTokens(100).build()); - } - - public static Builder builder(Ai21Jurassic2ChatBedrockApi chatApi) { - return new Builder(chatApi); - } - - @Override - public ChatResponse call(Prompt prompt) { - var request = createRequest(prompt); - var response = this.chatApi.chatCompletion(request); - - return new ChatResponse(response.completions() - .stream() - .map(completion -> new Generation(new AssistantMessage(completion.data().text()), - ChatGenerationMetadata.builder().finishReason(completion.finishReason().reason()).build())) - .toList()); - } - - private Ai21Jurassic2ChatRequest createRequest(Prompt prompt) { - - final String promptValue = MessageToPromptConverter.create().toPrompt(prompt.getInstructions()); - - Ai21Jurassic2ChatRequest request = Ai21Jurassic2ChatRequest.builder(promptValue).build(); - - if (prompt.getOptions() != null) { - BedrockAi21Jurassic2ChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(prompt.getOptions(), - ChatOptions.class, BedrockAi21Jurassic2ChatOptions.class); - request = ModelOptionsUtils.merge(updatedRuntimeOptions, request, Ai21Jurassic2ChatRequest.class); - } - - if (this.defaultOptions != null) { - request = ModelOptionsUtils.merge(request, this.defaultOptions, Ai21Jurassic2ChatRequest.class); - } - - return request; - } - - @Override - public ChatOptions getDefaultOptions() { - return BedrockAi21Jurassic2ChatOptions.fromOptions(this.defaultOptions); - } - - public static class Builder { - - private final Ai21Jurassic2ChatBedrockApi chatApi; - - private BedrockAi21Jurassic2ChatOptions options; - - public Builder(Ai21Jurassic2ChatBedrockApi chatApi) { - this.chatApi = chatApi; - } - - public Builder withOptions(BedrockAi21Jurassic2ChatOptions options) { - this.options = options; - return this; - } - - public BedrockAi21Jurassic2ChatModel build() { - return new BedrockAi21Jurassic2ChatModel(this.chatApi, - this.options != null ? this.options : BedrockAi21Jurassic2ChatOptions.builder().build()); - } - - } - -} diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/jurassic2/BedrockAi21Jurassic2ChatOptions.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/jurassic2/BedrockAi21Jurassic2ChatOptions.java deleted file mode 100644 index 2784ac2a4fa..00000000000 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/jurassic2/BedrockAi21Jurassic2ChatOptions.java +++ /dev/null @@ -1,486 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.jurassic2; - -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; - -import org.springframework.ai.chat.prompt.ChatOptions; - -/** - * Request body for the /complete endpoint of the Jurassic-2 API. - * - * @author Ahmed Yousri - * @author Thomas Vitale - * @author Ilayaperumal Gopinathan - * @since 1.0.0 - */ -@JsonInclude(JsonInclude.Include.NON_NULL) -public class BedrockAi21Jurassic2ChatOptions implements ChatOptions { - - /** - * The text which the model is requested to continue. - */ - @JsonProperty("prompt") - private String prompt; - - /** - * Number of completions to sample and return. - */ - @JsonProperty("numResults") - private Integer numResults; - - /** - * The maximum number of tokens to generate per result. - */ - @JsonProperty("maxTokens") - private Integer maxTokens; - - /** - * The minimum number of tokens to generate per result. - */ - @JsonProperty("minTokens") - private Integer minTokens; - - /** - * Modifies the distribution from which tokens are sampled. - */ - @JsonProperty("temperature") - private Double temperature; - - /** - * Sample tokens from the corresponding top percentile of probability mass. - */ - @JsonProperty("topP") - private Double topP; - - /** - * Return the top-K (topKReturn) alternative tokens. - */ - @JsonProperty("topKReturn") - private Integer topK; - - /** - * Stops decoding if any of the strings is generated. - */ - @JsonProperty("stopSequences") - private List stopSequences; - - /** - * Penalty object for frequency. - */ - @JsonProperty("frequencyPenalty") - private Penalty frequencyPenaltyOptions; - - /** - * Penalty object for presence. - */ - @JsonProperty("presencePenalty") - private Penalty presencePenaltyOptions; - - /** - * Penalty object for count. - */ - @JsonProperty("countPenalty") - private Penalty countPenaltyOptions; - - // Getters and setters - - public static Builder builder() { - return new Builder(); - } - - public static BedrockAi21Jurassic2ChatOptions fromOptions(BedrockAi21Jurassic2ChatOptions fromOptions) { - return builder().prompt(fromOptions.getPrompt()) - .numResults(fromOptions.getNumResults()) - .maxTokens(fromOptions.getMaxTokens()) - .minTokens(fromOptions.getMinTokens()) - .temperature(fromOptions.getTemperature()) - .topP(fromOptions.getTopP()) - .topK(fromOptions.getTopK()) - .stopSequences(fromOptions.getStopSequences()) - .frequencyPenaltyOptions(fromOptions.getFrequencyPenaltyOptions()) - .presencePenaltyOptions(fromOptions.getPresencePenaltyOptions()) - .countPenaltyOptions(fromOptions.getCountPenaltyOptions()) - .build(); - } - - /** - * Gets the prompt text for the model to continue. - * @return The prompt text. - */ - public String getPrompt() { - return this.prompt; - } - - /** - * Sets the prompt text for the model to continue. - * @param prompt The prompt text. - */ - public void setPrompt(String prompt) { - this.prompt = prompt; - } - - /** - * Gets the number of completions to sample and return. - * @return The number of results. - */ - public Integer getNumResults() { - return this.numResults; - } - - /** - * Sets the number of completions to sample and return. - * @param numResults The number of results. - */ - public void setNumResults(Integer numResults) { - this.numResults = numResults; - } - - /** - * Gets the maximum number of tokens to generate per result. - * @return The maximum number of tokens. - */ - @Override - public Integer getMaxTokens() { - return this.maxTokens; - } - - /** - * Sets the maximum number of tokens to generate per result. - * @param maxTokens The maximum number of tokens. - */ - public void setMaxTokens(Integer maxTokens) { - this.maxTokens = maxTokens; - } - - /** - * Gets the minimum number of tokens to generate per result. - * @return The minimum number of tokens. - */ - public Integer getMinTokens() { - return this.minTokens; - } - - /** - * Sets the minimum number of tokens to generate per result. - * @param minTokens The minimum number of tokens. - */ - public void setMinTokens(Integer minTokens) { - this.minTokens = minTokens; - } - - /** - * Gets the temperature for modifying the token sampling distribution. - * @return The temperature. - */ - @Override - public Double getTemperature() { - return this.temperature; - } - - /** - * Sets the temperature for modifying the token sampling distribution. - * @param temperature The temperature. - */ - public void setTemperature(Double temperature) { - this.temperature = temperature; - } - - /** - * Gets the topP parameter for sampling tokens from the top percentile of probability - * mass. - * @return The topP parameter. - */ - @Override - public Double getTopP() { - return this.topP; - } - - /** - * Sets the topP parameter for sampling tokens from the top percentile of probability - * mass. - * @param topP The topP parameter. - */ - public void setTopP(Double topP) { - this.topP = topP; - } - - /** - * Gets the top-K (topKReturn) alternative tokens to return. - * @return The top-K parameter. (topKReturn) - */ - @Override - public Integer getTopK() { - return this.topK; - } - - /** - * Sets the top-K (topKReturn) alternative tokens to return. - * @param topK The top-K parameter (topKReturn). - */ - public void setTopK(Integer topK) { - this.topK = topK; - } - - /** - * Gets the stop sequences for stopping decoding if any of the strings is generated. - * @return The stop sequences. - */ - @Override - public List getStopSequences() { - return this.stopSequences; - } - - /** - * Sets the stop sequences for stopping decoding if any of the strings is generated. - * @param stopSequences The stop sequences. - */ - public void setStopSequences(List stopSequences) { - this.stopSequences = stopSequences; - } - - @Override - @JsonIgnore - public Double getFrequencyPenalty() { - return getFrequencyPenaltyOptions() != null ? getFrequencyPenaltyOptions().scale() : null; - } - - @JsonIgnore - public void setFrequencyPenalty(Double frequencyPenalty) { - if (frequencyPenalty != null) { - setFrequencyPenaltyOptions(Penalty.builder().scale(frequencyPenalty).build()); - } - } - - /** - * Gets the frequency penalty object. - * @return The frequency penalty object. - */ - public Penalty getFrequencyPenaltyOptions() { - return this.frequencyPenaltyOptions; - } - - /** - * Sets the frequency penalty object. - * @param frequencyPenaltyOptions The frequency penalty object. - */ - public void setFrequencyPenaltyOptions(Penalty frequencyPenaltyOptions) { - this.frequencyPenaltyOptions = frequencyPenaltyOptions; - } - - @Override - @JsonIgnore - public Double getPresencePenalty() { - return getPresencePenaltyOptions() != null ? getPresencePenaltyOptions().scale() : null; - } - - @JsonIgnore - public void setPresencePenalty(Double presencePenalty) { - if (presencePenalty != null) { - setPresencePenaltyOptions(Penalty.builder().scale(presencePenalty).build()); - } - } - - /** - * Gets the presence penalty object. - * @return The presence penalty object. - */ - public Penalty getPresencePenaltyOptions() { - return this.presencePenaltyOptions; - } - - /** - * Sets the presence penalty object. - * @param presencePenaltyOptions The presence penalty object. - */ - public void setPresencePenaltyOptions(Penalty presencePenaltyOptions) { - this.presencePenaltyOptions = presencePenaltyOptions; - } - - /** - * Gets the count penalty object. - * @return The count penalty object. - */ - public Penalty getCountPenaltyOptions() { - return this.countPenaltyOptions; - } - - /** - * Sets the count penalty object. - * @param countPenaltyOptions The count penalty object. - */ - public void setCountPenaltyOptions(Penalty countPenaltyOptions) { - this.countPenaltyOptions = countPenaltyOptions; - } - - @Override - @JsonIgnore - public String getModel() { - return null; - } - - @Override - public BedrockAi21Jurassic2ChatOptions copy() { - return fromOptions(this); - } - - public static class Builder { - - private final BedrockAi21Jurassic2ChatOptions request = new BedrockAi21Jurassic2ChatOptions(); - - public Builder prompt(String prompt) { - this.request.setPrompt(prompt); - return this; - } - - public Builder numResults(Integer numResults) { - this.request.setNumResults(numResults); - return this; - } - - public Builder maxTokens(Integer maxTokens) { - this.request.setMaxTokens(maxTokens); - return this; - } - - public Builder minTokens(Integer minTokens) { - this.request.setMinTokens(minTokens); - return this; - } - - public Builder temperature(Double temperature) { - this.request.setTemperature(temperature); - return this; - } - - public Builder topP(Double topP) { - this.request.setTopP(topP); - return this; - } - - public Builder stopSequences(List stopSequences) { - this.request.setStopSequences(stopSequences); - return this; - } - - public Builder topK(Integer topKReturn) { - this.request.setTopK(topKReturn); - return this; - } - - public Builder frequencyPenaltyOptions(BedrockAi21Jurassic2ChatOptions.Penalty frequencyPenalty) { - this.request.setFrequencyPenaltyOptions(frequencyPenalty); - return this; - } - - public Builder presencePenaltyOptions(BedrockAi21Jurassic2ChatOptions.Penalty presencePenalty) { - this.request.setPresencePenaltyOptions(presencePenalty); - return this; - } - - public Builder countPenaltyOptions(BedrockAi21Jurassic2ChatOptions.Penalty countPenalty) { - this.request.setCountPenaltyOptions(countPenalty); - return this; - } - - public BedrockAi21Jurassic2ChatOptions build() { - return this.request; - } - - } - - /** - * Penalty object for frequency, presence, and count penalties. - * - * @param scale The scale of the penalty. - * @param applyToNumbers Whether to apply the penalty to numbers. - * @param applyToPunctuations Whether to apply the penalty to punctuations. - * @param applyToStopwords Whether to apply the penalty to stopwords. - * @param applyToWhitespaces Whether to apply the penalty to whitespaces. - * @param applyToEmojis Whether to apply the penalty to emojis. - */ - @JsonInclude(JsonInclude.Include.NON_NULL) - public record Penalty(@JsonProperty("scale") Double scale, @JsonProperty("applyToNumbers") Boolean applyToNumbers, - @JsonProperty("applyToPunctuations") Boolean applyToPunctuations, - @JsonProperty("applyToStopwords") Boolean applyToStopwords, - @JsonProperty("applyToWhitespaces") Boolean applyToWhitespaces, - @JsonProperty("applyToEmojis") Boolean applyToEmojis) { - - public static Builder builder() { - return new Builder(); - } - - public static class Builder { - - private Double scale; - - // can't keep it null due to modelOptionsUtils#mapToClass convert null to - // false - private Boolean applyToNumbers = true; - - private Boolean applyToPunctuations = true; - - private Boolean applyToStopwords = true; - - private Boolean applyToWhitespaces = true; - - private Boolean applyToEmojis = true; - - public Builder scale(Double scale) { - this.scale = scale; - return this; - } - - public Builder applyToNumbers(Boolean applyToNumbers) { - this.applyToNumbers = applyToNumbers; - return this; - } - - public Builder applyToPunctuations(Boolean applyToPunctuations) { - this.applyToPunctuations = applyToPunctuations; - return this; - } - - public Builder applyToStopwords(Boolean applyToStopwords) { - this.applyToStopwords = applyToStopwords; - return this; - } - - public Builder applyToWhitespaces(Boolean applyToWhitespaces) { - this.applyToWhitespaces = applyToWhitespaces; - return this; - } - - public Builder applyToEmojis(Boolean applyToEmojis) { - this.applyToEmojis = applyToEmojis; - return this; - } - - public Penalty build() { - return new Penalty(this.scale, this.applyToNumbers, this.applyToPunctuations, this.applyToStopwords, - this.applyToWhitespaces, this.applyToEmojis); - } - - } - - } - -} diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/jurassic2/api/Ai21Jurassic2ChatBedrockApi.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/jurassic2/api/Ai21Jurassic2ChatBedrockApi.java deleted file mode 100644 index bcd5c837192..00000000000 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/jurassic2/api/Ai21Jurassic2ChatBedrockApi.java +++ /dev/null @@ -1,471 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.jurassic2.api; - -// @formatter:off - -import java.time.Duration; -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.ObjectMapper; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.bedrock.api.AbstractBedrockApi; -import org.springframework.ai.bedrock.jurassic2.api.Ai21Jurassic2ChatBedrockApi.Ai21Jurassic2ChatRequest; -import org.springframework.ai.bedrock.jurassic2.api.Ai21Jurassic2ChatBedrockApi.Ai21Jurassic2ChatResponse; -import org.springframework.ai.model.ChatModelDescription; - -/** - * Java client for the Bedrock Jurassic2 chat model. - * https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-jurassic2.html - * - * @author Christian Tzolov - * @author Thomas Vitale - * @author Wei Jiang - * @since 0.8.0 - */ -public class Ai21Jurassic2ChatBedrockApi extends - AbstractBedrockApi { - - /** - * Create a new Ai21Jurassic2ChatBedrockApi instance using the default credentials provider chain, the default - * object mapper, default temperature and topP values. - * - * @param modelId The model id to use. See the {@link Ai21Jurassic2ChatModel} for the supported models. - * @param region The AWS region to use. - */ - public Ai21Jurassic2ChatBedrockApi(String modelId, String region) { - super(modelId, region); - } - - - /** - * Create a new Ai21Jurassic2ChatBedrockApi instance. - * - * @param modelId The model id to use. See the {@link Ai21Jurassic2ChatBedrockApi.Ai21Jurassic2ChatModel} for the supported models. - * @param credentialsProvider The credentials provider to connect to AWS. - * @param region The AWS region to use. - * @param objectMapper The object mapper to use for JSON serialization and deserialization. - */ - public Ai21Jurassic2ChatBedrockApi(String modelId, AwsCredentialsProvider credentialsProvider, String region, - ObjectMapper objectMapper) { - super(modelId, credentialsProvider, region, objectMapper); - } - - /** - * Create a new Ai21Jurassic2ChatBedrockApi instance using the default credentials provider chain, the default - * object mapper, default temperature and topP values. - * - * @param modelId The model id to use. See the {@link Ai21Jurassic2ChatModel} for the supported models. - * @param region The AWS region to use. - * @param timeout The timeout to use. - */ - public Ai21Jurassic2ChatBedrockApi(String modelId, String region, Duration timeout) { - super(modelId, region, timeout); - } - - - /** - * Create a new Ai21Jurassic2ChatBedrockApi instance. - * - * @param modelId The model id to use. See the {@link Ai21Jurassic2ChatBedrockApi.Ai21Jurassic2ChatModel} for the supported models. - * @param credentialsProvider The credentials provider to connect to AWS. - * @param region The AWS region to use. - * @param objectMapper The object mapper to use for JSON serialization and deserialization. - * @param timeout The timeout to use. - */ - public Ai21Jurassic2ChatBedrockApi(String modelId, AwsCredentialsProvider credentialsProvider, String region, - ObjectMapper objectMapper, Duration timeout) { - super(modelId, credentialsProvider, region, objectMapper, timeout); - } - - /** - * Create a new Ai21Jurassic2ChatBedrockApi instance. - * - * @param modelId The model id to use. See the {@link Ai21Jurassic2ChatBedrockApi.Ai21Jurassic2ChatModel} for the supported models. - * @param credentialsProvider The credentials provider to connect to AWS. - * @param region The AWS region to use. - * @param objectMapper The object mapper to use for JSON serialization and deserialization. - * @param timeout The timeout to use. - */ - public Ai21Jurassic2ChatBedrockApi(String modelId, AwsCredentialsProvider credentialsProvider, Region region, - ObjectMapper objectMapper, Duration timeout) { - super(modelId, credentialsProvider, region, objectMapper, timeout); - } - - @Override - public Ai21Jurassic2ChatResponse chatCompletion(Ai21Jurassic2ChatRequest request) { - return this.internalInvocation(request, Ai21Jurassic2ChatResponse.class); - } - - /** - * Ai21 Jurassic2 models version. - */ - public enum Ai21Jurassic2ChatModel implements ChatModelDescription { - - /** - * ai21.j2-mid-v1 - */ - AI21_J2_MID_V1("ai21.j2-mid-v1"), - - /** - * ai21.j2-ultra-v1 - */ - AI21_J2_ULTRA_V1("ai21.j2-ultra-v1"); - - private final String id; - - Ai21Jurassic2ChatModel(String value) { - this.id = value; - } - - /** - * The model id. - * @return the model id. - */ - public String id() { - return this.id; - } - - /** - * The model id. - * @return the model id. - */ - @Override - public String getName() { - return this.id; - } - } - - /** - * AI21 Jurassic2 chat request parameters. - * - * @param prompt The prompt to use for the chat. - * @param temperature The temperature value controls the randomness of the generated text. - * @param topP The topP value controls the diversity of the generated text. Use a lower value to ignore less - * probable options. - * @param maxTokens Specify the maximum number of tokens to use in the generated response. - * @param stopSequences Configure stop sequences that the model recognizes and after which it stops generating - * further tokens. Press the Enter key to insert a newline character in a stop sequence. Use the Tab key to finish - * inserting a stop sequence. - * @param countPenalty Control repetition in the generated response. Use a higher value to lower the probability of - * generating new tokens that already appear at least once in the prompt or in the completion. Proportional to the - * number of appearances. - * @param presencePenalty Control repetition in the generated response. Use a higher value to lower the probability - * of generating new tokens that already appear at least once in the prompt or in the completion. - * @param frequencyPenalty Control repetition in the generated response. Use a high value to lower the probability - * of generating new tokens that already appear at least once in the prompt or in the completion. The value is - * proportional to the frequency of the token appearances (normalized to text length). - */ - @JsonInclude(Include.NON_NULL) - public record Ai21Jurassic2ChatRequest( - @JsonProperty("prompt") String prompt, - @JsonProperty("temperature") Double temperature, - @JsonProperty("topP") Double topP, - @JsonProperty("maxTokens") Integer maxTokens, - @JsonProperty("stopSequences") List stopSequences, - @JsonProperty("countPenalty") IntegerScalePenalty countPenalty, - @JsonProperty("presencePenalty") FloatScalePenalty presencePenalty, - @JsonProperty("frequencyPenalty") IntegerScalePenalty frequencyPenalty) { - - /** - * Create a new {@link Ai21Jurassic2ChatRequest} instance. - * @param prompt The prompt to use for the chat. - * @return a new {@link Ai21Jurassic2ChatRequest} instance. - */ - public static Builder builder(String prompt) { - return new Builder(prompt); - } - - /** - * Penalty with integer scale value. - * - * @param scale The scale value controls the strength of the penalty. Use a higher value to lower the - * probability of generating new tokens that already appear at least once in the prompt or in the completion. - * @param applyToWhitespaces Reduce the probability of repetition of special characters. A true value applies - * the penalty to whitespaces and new lines. - * @param applyToPunctuations Reduce the probability of repetition of special characters. A true value applies - * the penalty to punctuations. - * @param applyToNumbers Reduce the probability of repetition of special characters. A true value applies the - * penalty to numbers. - * @param applyToStopwords Reduce the probability of repetition of special characters. A true value applies the - * penalty to stopwords. - * @param applyToEmojis Reduce the probability of repetition of special characters. A true value applies the - * penalty to emojis. - */ - @JsonInclude(Include.NON_NULL) - public record IntegerScalePenalty( - @JsonProperty("scale") Integer scale, - @JsonProperty("applyToWhitespaces") boolean applyToWhitespaces, - @JsonProperty("applyToPunctuations") boolean applyToPunctuations, - @JsonProperty("applyToNumbers") boolean applyToNumbers, - @JsonProperty("applyToStopwords") boolean applyToStopwords, - @JsonProperty("applyToEmojis") boolean applyToEmojis) { - } - - /** - * Penalty with float scale value. - * - * @param scale The scale value controls the strength of the penalty. Use a higher value to lower the - * probability of generating new tokens that already appear at least once in the prompt or in the completion. - * @param applyToWhitespaces Reduce the probability of repetition of special characters. A true value applies - * the penalty to whitespaces and new lines. - * @param applyToPunctuations Reduce the probability of repetition of special characters. A true value applies - * the penalty to punctuations. - * @param applyToNumbers Reduce the probability of repetition of special characters. A true value applies the - * penalty to numbers. - * @param applyToStopwords Reduce the probability of repetition of special characters. A true value applies the - * penalty to stopwords. - * @param applyToEmojis Reduce the probability of repetition of special characters. A true value applies the - * penalty to emojis. - */ - @JsonInclude(Include.NON_NULL) - public record FloatScalePenalty(@JsonProperty("scale") Float scale, - @JsonProperty("applyToWhitespaces") boolean applyToWhitespaces, - @JsonProperty("applyToPunctuations") boolean applyToPunctuations, - @JsonProperty("applyToNumbers") boolean applyToNumbers, - @JsonProperty("applyToStopwords") boolean applyToStopwords, - @JsonProperty("applyToEmojis") boolean applyToEmojis) { - } - - /** - * Builder for {@link Ai21Jurassic2ChatRequest}. - */ - public static final class Builder { - private String prompt; - private Double temperature; - private Double topP; - private Integer maxTokens; - private List stopSequences; - private IntegerScalePenalty countPenalty; - private FloatScalePenalty presencePenalty; - private IntegerScalePenalty frequencyPenalty; - - private Builder(String prompt) { - this.prompt = prompt; - } - - /** - * Set the temperature. - * @param temperature the temperature - * @return this {@link Builder} instance - */ - public Builder temperature(Double temperature) { - this.temperature = temperature; - return this; - } - - /** - * Set the topP. - * @param topP the topP - * @return this {@link Builder} instance - */ - public Builder topP(Double topP) { - this.topP = topP; - return this; - } - - /** - * Set the maxTokens. - * @param maxTokens the maxTokens - * @return this {@link Builder} instance - */ - public Builder maxTokens(Integer maxTokens) { - this.maxTokens = maxTokens; - return this; - } - - /** - * Set the stopSequences. - * @param stopSequences the stopSequences - * @return this {@link Builder} instance - */ - public Builder stopSequences(List stopSequences) { - this.stopSequences = stopSequences; - return this; - } - - /** - * Set the countPenalty. - * @param countPenalty the countPenalty - * @return this {@link Builder} instance - */ - public Builder countPenalty(IntegerScalePenalty countPenalty) { - this.countPenalty = countPenalty; - return this; - } - - /** - * Set the presencePenalty. - * @param presencePenalty the presencePenalty - * @return this {@link Builder} instance - */ - public Builder presencePenalty(FloatScalePenalty presencePenalty) { - this.presencePenalty = presencePenalty; - return this; - } - - /** - * Set the frequencyPenalty. - * @param frequencyPenalty the frequencyPenalty - * @return this {@link Builder} instance - */ - public Builder frequencyPenalty(IntegerScalePenalty frequencyPenalty) { - this.frequencyPenalty = frequencyPenalty; - return this; - } - - /** - * Build the {@link Ai21Jurassic2ChatRequest} instance. - * @return a new {@link Ai21Jurassic2ChatRequest} instance - */ - public Ai21Jurassic2ChatRequest build() { - return new Ai21Jurassic2ChatRequest( - this.prompt, - this.temperature, - this.topP, - this.maxTokens, - this.stopSequences, - this.countPenalty, - this.presencePenalty, - this.frequencyPenalty - ); - } - } - } - - /** - * Ai21 Jurassic2 chat response. - * https://docs.ai21.com/reference/j2-complete-api-ref#response - * - * @param id The unique identifier of the response. - * @param prompt The prompt used for the chat. - * @param completions The completions generated by the model. - * @param amazonBedrockInvocationMetrics The metrics about the model invocation. - */ - @JsonInclude(Include.NON_NULL) - public record Ai21Jurassic2ChatResponse( - @JsonProperty("id") String id, - @JsonProperty("prompt") Prompt prompt, - @JsonProperty("completions") List completions, - @JsonProperty("amazon-bedrock-invocationMetrics") AmazonBedrockInvocationMetrics amazonBedrockInvocationMetrics) { - - /** - * The completions generated by the model. - * @param data The data field contains the prompt used for the completion. - * @param finishReason The finishReason field provides detailed information about why the completion was halted. - */ - @JsonInclude(Include.NON_NULL) - public record Completion( - @JsonProperty("data") Prompt data, - @JsonProperty("finishReason") FinishReason finishReason) { - } - - /** - * Provides detailed information about each token in both the prompt and the completions. - * - * @param generatedToken The generatedToken fields. - * @param topTokens The topTokens field is a list of the top K alternative tokens for this position, sorted by - * probability, according to the topKReturn request parameter. If topKReturn is set to 0, this field will be - * null. - * @param textRange The textRange field indicates the start and end offsets of the token in the decoded text - * string. - */ - @JsonInclude(Include.NON_NULL) - public record Token( - @JsonProperty("generatedToken") GeneratedToken generatedToken, - @JsonProperty("topTokens") List topTokens, - @JsonProperty("textRange") TextRange textRange) { - } - - /** - * The generatedToken fields. - * - * @param token TThe string representation of the token. - * @param logprob The predicted log probability of the token after applying the sampling parameters as a float - * value. - * @param rawLogprob The raw predicted log probability of the token as a float value. For the indifferent values - * (namely, temperature=1, topP=1) we get raw_logprob=logprob. - */ - @JsonInclude(Include.NON_NULL) - public record GeneratedToken( - @JsonProperty("token") String token, - @JsonProperty("logprob") Float logprob, - @JsonProperty("raw_logprob") Float rawLogprob) { - - } - - /** - * The topTokens field is a list of the top K alternative tokens for this position, sorted by probability, - * according to the topKReturn request parameter. If topKReturn is set to 0, this field will be null. - * - * @param token The string representation of the alternative token. - * @param logprob The predicted log probability of the alternative token. - */ - @JsonInclude(Include.NON_NULL) - public record TopToken( - @JsonProperty("token") String token, - @JsonProperty("logprob") Float logprob) { - } - - /** - * The textRange field indicates the start and end offsets of the token in the decoded text string. - * - * @param start The starting index of the token in the decoded text string. - * @param end The ending index of the token in the decoded text string. - */ - @JsonInclude(Include.NON_NULL) - public record TextRange( - @JsonProperty("start") Integer start, - @JsonProperty("end") Integer end) { - } - - /** - * The prompt includes the raw text, the tokens with their log probabilities, and the top-K alternative tokens - * at each position, if requested. - * - * @param text The raw text of the prompt. - * @param tokens Provides detailed information about each token in both the prompt and the completions. - */ - @JsonInclude(Include.NON_NULL) - public record Prompt( - @JsonProperty("text") String text, - @JsonProperty("tokens") List tokens) { - } - - /** - * Explains why the generation process was halted for a specific completion. - * - * @param reason The reason field indicates the reason for the completion to stop. - * @param length The length field indicates the number of tokens generated in the completion. - * @param sequence The sequence field indicates the stop sequence that caused the completion to stop. - */ - @JsonInclude(Include.NON_NULL) - public record FinishReason( - @JsonProperty("reason") String reason, - @JsonProperty("length") String length, - @JsonProperty("sequence") String sequence) { - } - } - - -} -// @formatter:on diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/llama/BedrockLlamaChatModel.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/llama/BedrockLlamaChatModel.java deleted file mode 100644 index d76b5d3920e..00000000000 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/llama/BedrockLlamaChatModel.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.llama; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import reactor.core.publisher.Flux; - -import org.springframework.ai.bedrock.MessageToPromptConverter; -import org.springframework.ai.bedrock.llama.api.LlamaChatBedrockApi; -import org.springframework.ai.bedrock.llama.api.LlamaChatBedrockApi.LlamaChatRequest; -import org.springframework.ai.bedrock.llama.api.LlamaChatBedrockApi.LlamaChatResponse; -import org.springframework.ai.chat.messages.AssistantMessage; -import org.springframework.ai.chat.metadata.ChatGenerationMetadata; -import org.springframework.ai.chat.metadata.Usage; -import org.springframework.ai.chat.model.ChatModel; -import org.springframework.ai.chat.model.ChatResponse; -import org.springframework.ai.chat.model.Generation; -import org.springframework.ai.chat.model.StreamingChatModel; -import org.springframework.ai.chat.prompt.ChatOptions; -import org.springframework.ai.chat.prompt.Prompt; -import org.springframework.ai.model.ModelOptionsUtils; -import org.springframework.util.Assert; - -/** - * Java {@link ChatModel} and {@link StreamingChatModel} for the Bedrock Llama chat - * generative. - * - * @author Christian Tzolov - * @author Wei Jiang - * @since 0.8.0 - * @deprecated in favor of the - * {@link org.springframework.ai.bedrock.converse.BedrockProxyChatModel}. - */ -@Deprecated -public class BedrockLlamaChatModel implements ChatModel, StreamingChatModel { - - private final LlamaChatBedrockApi chatApi; - - private final BedrockLlamaChatOptions defaultOptions; - - public BedrockLlamaChatModel(LlamaChatBedrockApi chatApi) { - this(chatApi, BedrockLlamaChatOptions.builder().temperature(0.8).topP(0.9).maxGenLen(100).build()); - } - - public BedrockLlamaChatModel(LlamaChatBedrockApi chatApi, BedrockLlamaChatOptions options) { - Assert.notNull(chatApi, "LlamaChatBedrockApi must not be null"); - Assert.notNull(options, "BedrockLlamaChatOptions must not be null"); - - this.chatApi = chatApi; - this.defaultOptions = options; - } - - @Override - public ChatResponse call(Prompt prompt) { - - var request = createRequest(prompt); - - LlamaChatResponse response = this.chatApi.chatCompletion(request); - - return new ChatResponse(List.of(new Generation(new AssistantMessage(response.generation()), - ChatGenerationMetadata.builder() - .finishReason(response.stopReason().name()) - .metadata("usage", extractUsage(response)) - .build()))); - } - - @Override - public Flux stream(Prompt prompt) { - - var request = createRequest(prompt); - - Flux fluxResponse = this.chatApi.chatCompletionStream(request); - - return fluxResponse.map(response -> { - String stopReason = response.stopReason() != null ? response.stopReason().name() : null; - return new ChatResponse(List.of(new Generation(new AssistantMessage(response.generation()), - ChatGenerationMetadata.builder() - .finishReason(stopReason) - .metadata("usage", extractUsage(response)) - .build()))); - }); - } - - private Usage extractUsage(LlamaChatResponse response) { - return new Usage() { - - @Override - public Integer getPromptTokens() { - return response.promptTokenCount(); - } - - @Override - public Integer getCompletionTokens() { - return response.generationTokenCount(); - } - - @Override - public Map getNativeUsage() { - Map usage = new HashMap<>(); - usage.put("promptTokens", getPromptTokens()); - usage.put("completionTokens", getCompletionTokens()); - usage.put("totalTokens", getTotalTokens()); - return usage; - } - }; - } - - /** - * Accessible for testing. - */ - LlamaChatRequest createRequest(Prompt prompt) { - - final String promptValue = MessageToPromptConverter.create().toPrompt(prompt.getInstructions()); - - LlamaChatRequest request = LlamaChatRequest.builder(promptValue).build(); - - if (this.defaultOptions != null) { - request = ModelOptionsUtils.merge(request, this.defaultOptions, LlamaChatRequest.class); - } - - if (prompt.getOptions() != null) { - BedrockLlamaChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(prompt.getOptions(), - ChatOptions.class, BedrockLlamaChatOptions.class); - - request = ModelOptionsUtils.merge(updatedRuntimeOptions, request, LlamaChatRequest.class); - } - - return request; - } - - @Override - public ChatOptions getDefaultOptions() { - return BedrockLlamaChatOptions.fromOptions(this.defaultOptions); - } - -} diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/llama/BedrockLlamaChatOptions.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/llama/BedrockLlamaChatOptions.java deleted file mode 100644 index 9bb97a34d7b..00000000000 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/llama/BedrockLlamaChatOptions.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.llama; - -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.fasterxml.jackson.annotation.JsonProperty; - -import org.springframework.ai.chat.prompt.ChatOptions; - -/** - * Options for the Bedrock Llama Chat API. - * - * @author Christian Tzolov - * @author Thomas Vitale - * @author Ilayaperumal Gopinathan - */ -@JsonInclude(Include.NON_NULL) -public class BedrockLlamaChatOptions implements ChatOptions { - - /** - * The temperature value controls the randomness of the generated text. Use a lower - * value to decrease randomness in the response. - */ - private @JsonProperty("temperature") Double temperature; - - /** - * The topP value controls the diversity of the generated text. Use a lower value to - * ignore less probable options. Set to 0 or 1.0 to disable. - */ - private @JsonProperty("top_p") Double topP; - - /** - * The maximum length of the generated text. - */ - private @JsonProperty("max_gen_len") Integer maxGenLen; - - public static Builder builder() { - return new Builder(); - } - - public static BedrockLlamaChatOptions fromOptions(BedrockLlamaChatOptions fromOptions) { - return builder().temperature(fromOptions.getTemperature()) - .topP(fromOptions.getTopP()) - .maxGenLen(fromOptions.getMaxGenLen()) - .build(); - } - - @Override - public Double getTemperature() { - return this.temperature; - } - - public void setTemperature(Double temperature) { - this.temperature = temperature; - } - - @Override - public Double getTopP() { - return this.topP; - } - - public void setTopP(Double topP) { - this.topP = topP; - } - - @Override - @JsonIgnore - public Integer getMaxTokens() { - return getMaxGenLen(); - } - - @JsonIgnore - public void setMaxTokens(Integer maxTokens) { - setMaxGenLen(maxTokens); - } - - public Integer getMaxGenLen() { - return this.maxGenLen; - } - - public void setMaxGenLen(Integer maxGenLen) { - this.maxGenLen = maxGenLen; - } - - @Override - @JsonIgnore - public String getModel() { - return null; - } - - @Override - @JsonIgnore - public Double getFrequencyPenalty() { - return null; - } - - @Override - @JsonIgnore - public Double getPresencePenalty() { - return null; - } - - @Override - @JsonIgnore - public List getStopSequences() { - return null; - } - - @Override - @JsonIgnore - public Integer getTopK() { - return null; - } - - @Override - public BedrockLlamaChatOptions copy() { - return fromOptions(this); - } - - public static class Builder { - - private BedrockLlamaChatOptions options = new BedrockLlamaChatOptions(); - - public Builder temperature(Double temperature) { - this.options.setTemperature(temperature); - return this; - } - - public Builder topP(Double topP) { - this.options.setTopP(topP); - return this; - } - - public Builder maxGenLen(Integer maxGenLen) { - this.options.setMaxGenLen(maxGenLen); - return this; - } - - public BedrockLlamaChatOptions build() { - return this.options; - } - - } - -} diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/llama/api/LlamaChatBedrockApi.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/llama/api/LlamaChatBedrockApi.java deleted file mode 100644 index e6e5f194ad8..00000000000 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/llama/api/LlamaChatBedrockApi.java +++ /dev/null @@ -1,302 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.llama.api; - -import java.time.Duration; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.ObjectMapper; -import reactor.core.publisher.Flux; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.bedrock.api.AbstractBedrockApi; -import org.springframework.ai.bedrock.llama.api.LlamaChatBedrockApi.LlamaChatRequest; -import org.springframework.ai.bedrock.llama.api.LlamaChatBedrockApi.LlamaChatResponse; -import org.springframework.ai.model.ChatModelDescription; - -// @formatter:off -/** - * Java client for the Bedrock Llama chat model. - * https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-meta.html - * - * Model IDs can be found here https://docs.aws.amazon.com/bedrock/latest/userguide/model-ids.html - * - * @author Christian Tzolov - * @author Thomas Vitale - * @author Wei Jiang - * @author Ilayaperumal Gopinathan - * @since 1.0.0 - */ -public class LlamaChatBedrockApi extends - AbstractBedrockApi { - - /** - * Create a new LlamaChatBedrockApi instance using the default credentials provider chain, the default object - * mapper, default temperature and topP values. - * - * @param modelId The model id to use. See the {@link LlamaChatModel} for the supported models. - * @param region The AWS region to use. - */ - public LlamaChatBedrockApi(String modelId, String region) { - super(modelId, region); - } - - /** - * Create a new LlamaChatBedrockApi instance using the provided credentials provider, region and object mapper. - * - * @param modelId The model id to use. See the {@link LlamaChatModel} for the supported models. - * @param credentialsProvider The credentials provider to connect to AWS. - * @param region The AWS region to use. - * @param objectMapper The object mapper to use for JSON serialization and deserialization. - */ - public LlamaChatBedrockApi(String modelId, AwsCredentialsProvider credentialsProvider, String region, - ObjectMapper objectMapper) { - super(modelId, credentialsProvider, region, objectMapper); - } - - /** - * Create a new LlamaChatBedrockApi instance using the default credentials provider chain, the default object - * mapper, default temperature and topP values. - * - * @param modelId The model id to use. See the {@link LlamaChatModel} for the supported models. - * @param region The AWS region to use. - * @param timeout The timeout to use. - */ - public LlamaChatBedrockApi(String modelId, String region, Duration timeout) { - super(modelId, region, timeout); - } - - /** - * Create a new LlamaChatBedrockApi instance using the provided credentials provider, region and object mapper. - * - * @param modelId The model id to use. See the {@link LlamaChatModel} for the supported models. - * @param credentialsProvider The credentials provider to connect to AWS. - * @param region The AWS region to use. - * @param objectMapper The object mapper to use for JSON serialization and deserialization. - * @param timeout The timeout to use. - */ - public LlamaChatBedrockApi(String modelId, AwsCredentialsProvider credentialsProvider, String region, - ObjectMapper objectMapper, Duration timeout) { - super(modelId, credentialsProvider, region, objectMapper, timeout); - } - - /** - * Create a new LlamaChatBedrockApi instance using the provided credentials provider, region and object mapper. - * - * @param modelId The model id to use. See the {@link LlamaChatModel} for the supported models. - * @param credentialsProvider The credentials provider to connect to AWS. - * @param region The AWS region to use. - * @param objectMapper The object mapper to use for JSON serialization and deserialization. - * @param timeout The timeout to use. - */ - public LlamaChatBedrockApi(String modelId, AwsCredentialsProvider credentialsProvider, Region region, - ObjectMapper objectMapper, Duration timeout) { - super(modelId, credentialsProvider, region, objectMapper, timeout); - } - - @Override - public LlamaChatResponse chatCompletion(LlamaChatRequest request) { - return this.internalInvocation(request, LlamaChatResponse.class); - } - - @Override - public Flux chatCompletionStream(LlamaChatRequest request) { - return this.internalInvocationStream(request, LlamaChatResponse.class); - } - - /** - * Llama models version. - */ - public enum LlamaChatModel implements ChatModelDescription { - - /** - * meta.llama2-13b-chat-v1 - */ - LLAMA2_13B_CHAT_V1("meta.llama2-13b-chat-v1"), - - /** - * meta.llama2-70b-chat-v1 - */ - LLAMA2_70B_CHAT_V1("meta.llama2-70b-chat-v1"), - - /** - * meta.llama3-8b-instruct-v1:0 - */ - LLAMA3_8B_INSTRUCT_V1("meta.llama3-8b-instruct-v1:0"), - - /** - * meta.llama3-70b-instruct-v1:0 - */ - LLAMA3_70B_INSTRUCT_V1("meta.llama3-70b-instruct-v1:0"), - - /** - * meta.llama3-1-8b-instruct-v1:0 - */ - LLAMA3_1_8B_INSTRUCT_V1("meta.llama3-1-8b-instruct-v1:0"), - - /** - * meta.llama3-1-70b-instruct-v1:0 - */ - LLAMA3_1_70B_INSTRUCT_V1("meta.llama3-1-70b-instruct-v1:0"), - - /** - * meta.llama3-1-405b-instruct-v1:0 - */ - LLAMA3_1_405B_INSTRUCT_V1("meta.llama3-1-405b-instruct-v1:0"), - - /** - * meta.llama3-2-1b-instruct-v1:0 - */ - LLAMA3_2_1B_INSTRUCT_V1("meta.llama3-2-1b-instruct-v1:0"), - - /** - * meta.llama3-2-3b-instruct-v1:0 - */ - LLAMA3_2_3B_INSTRUCT_V1("meta.llama3-2-3b-instruct-v1:0"), - - /** - * meta.llama3-2-11b-instruct-v1:0 - */ - LLAMA3_2_11B_INSTRUCT_V1("meta.llama3-2-11b-instruct-v1:0"), - - /** - * meta.llama3-2-90b-instruct-v1:0 - */ - LLAMA3_2_90B_INSTRUCT_V1("meta.llama3-2-90b-instruct-v1:0"); - - private final String id; - - LlamaChatModel(String value) { - this.id = value; - } - - /** - * @return The model id. - */ - public String id() { - return this.id; - } - - @Override - public String getName() { - return this.id; - } - } - - /** - * LlamaChatRequest encapsulates the request parameters for the Meta Llama chat model. - * - * @param prompt The prompt to use for the chat. - * @param temperature The temperature value controls the randomness of the generated text. Use a lower value to - * decrease randomness in the response. - * @param topP The topP value controls the diversity of the generated text. Use a lower value to ignore less - * probable options. Set to 0 or 1.0 to disable. - * @param maxGenLen The maximum length of the generated text. - */ - @JsonInclude(Include.NON_NULL) - public record LlamaChatRequest( - @JsonProperty("prompt") String prompt, - @JsonProperty("temperature") Double temperature, - @JsonProperty("top_p") Double topP, - @JsonProperty("max_gen_len") Integer maxGenLen) { - - /** - * Create a new LlamaChatRequest builder. - * @param prompt compulsory prompt parameter. - * @return a new LlamaChatRequest builder. - */ - public static Builder builder(String prompt) { - return new Builder(prompt); - } - - public static class Builder { - private String prompt; - private Double temperature; - private Double topP; - private Integer maxGenLen; - - public Builder(String prompt) { - this.prompt = prompt; - } - - public Builder temperature(Double temperature) { - this.temperature = temperature; - return this; - } - - public Builder topP(Double topP) { - this.topP = topP; - return this; - } - - public Builder maxGenLen(Integer maxGenLen) { - this.maxGenLen = maxGenLen; - return this; - } - - public LlamaChatRequest build() { - return new LlamaChatRequest( - this.prompt, - this.temperature, - this.topP, - this.maxGenLen - ); - } - } - } - - /** - * LlamaChatResponse encapsulates the response parameters for the Meta Llama chat model. - * - * @param generation The generated text. - * @param promptTokenCount The number of tokens in the prompt. - * @param generationTokenCount The number of tokens in the response. - * @param stopReason The reason why the response stopped generating text. Possible values are: (1) stop – The model - * has finished generating text for the input prompt. (2) length – The length of the tokens for the generated text - * exceeds the value of max_gen_len in the call. The response is truncated to max_gen_len tokens. Consider - * increasing the value of max_gen_len and trying again. - * @param amazonBedrockInvocationMetrics The Amazon Bedrock invocation metrics. - */ - @JsonInclude(Include.NON_NULL) - public record LlamaChatResponse( - @JsonProperty("generation") String generation, - @JsonProperty("prompt_token_count") Integer promptTokenCount, - @JsonProperty("generation_token_count") Integer generationTokenCount, - @JsonProperty("stop_reason") StopReason stopReason, - @JsonProperty("amazon-bedrock-invocationMetrics") AmazonBedrockInvocationMetrics amazonBedrockInvocationMetrics) { - - /** - * The reason the response finished being generated. - */ - public enum StopReason { - /** - * The model has finished generating text for the input prompt. - */ - @JsonProperty("stop") - STOP, - /** - * The response was truncated because of the response length you set. - */ - @JsonProperty("length") - LENGTH - } - } -} -// @formatter:on diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/BedrockTitanChatModel.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/BedrockTitanChatModel.java deleted file mode 100644 index 41eb229f214..00000000000 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/BedrockTitanChatModel.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.titan; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import reactor.core.publisher.Flux; - -import org.springframework.ai.bedrock.MessageToPromptConverter; -import org.springframework.ai.bedrock.titan.api.TitanChatBedrockApi; -import org.springframework.ai.bedrock.titan.api.TitanChatBedrockApi.TitanChatRequest; -import org.springframework.ai.bedrock.titan.api.TitanChatBedrockApi.TitanChatResponse; -import org.springframework.ai.bedrock.titan.api.TitanChatBedrockApi.TitanChatResponseChunk; -import org.springframework.ai.chat.messages.AssistantMessage; -import org.springframework.ai.chat.metadata.ChatGenerationMetadata; -import org.springframework.ai.chat.metadata.Usage; -import org.springframework.ai.chat.model.ChatModel; -import org.springframework.ai.chat.model.ChatResponse; -import org.springframework.ai.chat.model.Generation; -import org.springframework.ai.chat.model.StreamingChatModel; -import org.springframework.ai.chat.prompt.ChatOptions; -import org.springframework.ai.chat.prompt.Prompt; -import org.springframework.ai.model.ModelOptionsUtils; -import org.springframework.util.Assert; - -/** - * Implementation of the {@link ChatModel} and {@link StreamingChatModel} interfaces that - * uses the Titan Chat API. - * - * @author Christian Tzolov - * @since 0.8.0 - * @deprecated in favor of the - * {@link org.springframework.ai.bedrock.converse.BedrockProxyChatModel}. - */ -@Deprecated -public class BedrockTitanChatModel implements ChatModel, StreamingChatModel { - - private final TitanChatBedrockApi chatApi; - - private final BedrockTitanChatOptions defaultOptions; - - public BedrockTitanChatModel(TitanChatBedrockApi chatApi) { - this(chatApi, BedrockTitanChatOptions.builder().withTemperature(0.8).build()); - } - - public BedrockTitanChatModel(TitanChatBedrockApi chatApi, BedrockTitanChatOptions defaultOptions) { - Assert.notNull(chatApi, "ChatApi must not be null"); - Assert.notNull(defaultOptions, "DefaultOptions must not be null"); - this.chatApi = chatApi; - this.defaultOptions = defaultOptions; - } - - @Override - public ChatResponse call(Prompt prompt) { - TitanChatResponse response = this.chatApi.chatCompletion(this.createRequest(prompt)); - List generations = response.results() - .stream() - .map(result -> new Generation(new AssistantMessage(result.outputText()))) - .toList(); - - return new ChatResponse(generations); - } - - @Override - public Flux stream(Prompt prompt) { - return this.chatApi.chatCompletionStream(this.createRequest(prompt)).map(chunk -> { - ChatGenerationMetadata chatGenerationMetadata = null; - if (chunk.amazonBedrockInvocationMetrics() != null) { - String completionReason = chunk.completionReason().name(); - chatGenerationMetadata = ChatGenerationMetadata.builder() - .finishReason(completionReason) - .metadata("usage", chunk.amazonBedrockInvocationMetrics()) - .build(); - } - else if (chunk.inputTextTokenCount() != null && chunk.totalOutputTextTokenCount() != null) { - String completionReason = chunk.completionReason().name(); - chatGenerationMetadata = ChatGenerationMetadata.builder() - .finishReason(completionReason) - .metadata("usage", extractUsage(chunk)) - .build(); - } - return new ChatResponse( - List.of(new Generation(new AssistantMessage(chunk.outputText()), chatGenerationMetadata))); - }); - } - - /** - * Test access. - */ - TitanChatRequest createRequest(Prompt prompt) { - final String promptValue = MessageToPromptConverter.create().toPrompt(prompt.getInstructions()); - - var requestBuilder = TitanChatRequest.builder(promptValue); - - if (this.defaultOptions != null) { - requestBuilder = update(requestBuilder, this.defaultOptions); - } - - if (prompt.getOptions() != null) { - BedrockTitanChatOptions updatedRuntimeOptions = ModelOptionsUtils.copyToTarget(prompt.getOptions(), - ChatOptions.class, BedrockTitanChatOptions.class); - - requestBuilder = update(requestBuilder, updatedRuntimeOptions); - } - - return requestBuilder.build(); - } - - private TitanChatRequest.Builder update(TitanChatRequest.Builder builder, BedrockTitanChatOptions options) { - if (options.getTemperature() != null) { - builder.temperature(options.getTemperature()); - } - if (options.getTopP() != null) { - builder.topP(options.getTopP()); - } - if (options.getMaxTokenCount() != null) { - builder.maxTokenCount(options.getMaxTokenCount()); - } - if (options.getStopSequences() != null) { - builder.stopSequences(options.getStopSequences()); - } - return builder; - } - - private Usage extractUsage(TitanChatResponseChunk response) { - return new Usage() { - - @Override - public Integer getPromptTokens() { - return response.inputTextTokenCount(); - } - - @Override - public Integer getCompletionTokens() { - return response.totalOutputTextTokenCount(); - } - - @Override - public Map getNativeUsage() { - Map usage = new HashMap<>(); - usage.put("promptTokens", getPromptTokens()); - usage.put("completionTokens", getCompletionTokens()); - usage.put("totalTokens", getTotalTokens()); - return usage; - } - }; - } - - @Override - public ChatOptions getDefaultOptions() { - return BedrockTitanChatOptions.fromOptions(this.defaultOptions); - } - -} diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/BedrockTitanChatOptions.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/BedrockTitanChatOptions.java deleted file mode 100644 index f7e947ee3dc..00000000000 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/BedrockTitanChatOptions.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.titan; - -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.fasterxml.jackson.annotation.JsonProperty; - -import org.springframework.ai.chat.prompt.ChatOptions; - -/** - * Options for the Titan Chat API. - * - * @author Christian Tzolov - * @author Thomas Vitale - * @since 0.8.0 - */ -@JsonInclude(Include.NON_NULL) -public class BedrockTitanChatOptions implements ChatOptions { - - // @formatter:off - /** - * The temperature value controls the randomness of the generated text. - */ - private @JsonProperty("temperature") Double temperature; - - /** - * The topP value controls the diversity of the generated text. Use a lower value to ignore less probable options. - */ - private @JsonProperty("topP") Double topP; - - /** - * Maximum number of tokens to generate. - */ - private @JsonProperty("maxTokenCount") Integer maxTokenCount; - - /** - * A list of tokens that the model should stop generating after. - */ - private @JsonProperty("stopSequences") List stopSequences; - // @formatter:on - - public static Builder builder() { - return new Builder(); - } - - public static BedrockTitanChatOptions fromOptions(BedrockTitanChatOptions fromOptions) { - return builder().withTemperature(fromOptions.getTemperature()) - .withTopP(fromOptions.getTopP()) - .withMaxTokenCount(fromOptions.getMaxTokenCount()) - .withStopSequences(fromOptions.getStopSequences()) - .build(); - } - - @Override - public Double getTemperature() { - return this.temperature; - } - - public void setTemperature(Double temperature) { - this.temperature = temperature; - } - - @Override - public Double getTopP() { - return this.topP; - } - - public void setTopP(Double topP) { - this.topP = topP; - } - - @Override - @JsonIgnore - public Integer getMaxTokens() { - return getMaxTokenCount(); - } - - @JsonIgnore - public void setMaxTokens(Integer maxTokens) { - setMaxTokenCount(maxTokens); - } - - public Integer getMaxTokenCount() { - return this.maxTokenCount; - } - - public void setMaxTokenCount(Integer maxTokenCount) { - this.maxTokenCount = maxTokenCount; - } - - @Override - public List getStopSequences() { - return this.stopSequences; - } - - public void setStopSequences(List stopSequences) { - this.stopSequences = stopSequences; - } - - @Override - @JsonIgnore - public String getModel() { - return null; - } - - @Override - @JsonIgnore - public Double getFrequencyPenalty() { - return null; - } - - @Override - @JsonIgnore - public Double getPresencePenalty() { - return null; - } - - @Override - @JsonIgnore - public Integer getTopK() { - return null; - } - - @Override - public BedrockTitanChatOptions copy() { - return fromOptions(this); - } - - public static class Builder { - - private BedrockTitanChatOptions options = new BedrockTitanChatOptions(); - - public Builder withTemperature(Double temperature) { - this.options.temperature = temperature; - return this; - } - - public Builder withTopP(Double topP) { - this.options.topP = topP; - return this; - } - - public Builder withMaxTokenCount(Integer maxTokenCount) { - this.options.maxTokenCount = maxTokenCount; - return this; - } - - public Builder withStopSequences(List stopSequences) { - this.options.stopSequences = stopSequences; - return this; - } - - public BedrockTitanChatOptions build() { - return this.options; - } - - } - -} diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/api/TitanChatBedrockApi.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/api/TitanChatBedrockApi.java deleted file mode 100644 index 0519cfde7c6..00000000000 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/api/TitanChatBedrockApi.java +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.titan.api; - -import java.time.Duration; -import java.util.List; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonInclude.Include; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.fasterxml.jackson.databind.ObjectMapper; -import reactor.core.publisher.Flux; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.bedrock.api.AbstractBedrockApi; -import org.springframework.ai.bedrock.titan.api.TitanChatBedrockApi.TitanChatRequest; -import org.springframework.ai.bedrock.titan.api.TitanChatBedrockApi.TitanChatResponse; -import org.springframework.ai.bedrock.titan.api.TitanChatBedrockApi.TitanChatResponse.CompletionReason; -import org.springframework.ai.bedrock.titan.api.TitanChatBedrockApi.TitanChatResponseChunk; -import org.springframework.ai.model.ChatModelDescription; - -/** - * Java client for the Bedrock Titan chat model. - * https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-titan-text.html - *

- * https://docs.aws.amazon.com/bedrock/latest/userguide/titan-text-models.html - * - * @author Christian Tzolov - * @author Thomas Vitale - * @author Wei Jiang - * @author Ilayaperumal Gopinathan - * @since 0.8.0 - */ -// @formatter:off -public class TitanChatBedrockApi extends - AbstractBedrockApi { - - /** - * Create a new TitanChatBedrockApi instance using the default credentials provider chain, the default object mapper. - * - * @param modelId The model id to use. See the {@link TitanChatModel} for the supported models. - * @param region The AWS region to use. - */ - public TitanChatBedrockApi(String modelId, String region) { - super(modelId, region); - } - - /** - * Create a new TitanChatBedrockApi instance using the provided credentials provider, region and object mapper. - * - * @param modelId The model id to use. See the {@link TitanChatModel} for the supported models. - * @param credentialsProvider The credentials provider to connect to AWS. - * @param region The AWS region to use. - * @param objectMapper The object mapper to use for JSON serialization and deserialization. - */ - public TitanChatBedrockApi(String modelId, AwsCredentialsProvider credentialsProvider, String region, - ObjectMapper objectMapper) { - super(modelId, credentialsProvider, region, objectMapper); - } - - /** - * Create a new TitanChatBedrockApi instance using the default credentials provider chain, the default object mapper. - * - * @param modelId The model id to use. See the {@link TitanChatModel} for the supported models. - * @param region The AWS region to use. - * @param timeout The timeout to use. - */ - public TitanChatBedrockApi(String modelId, String region, Duration timeout) { - super(modelId, region, timeout); - } - - /** - * Create a new TitanChatBedrockApi instance using the provided credentials provider, region and object mapper. - * - * @param modelId The model id to use. See the {@link TitanChatModel} for the supported models. - * @param credentialsProvider The credentials provider to connect to AWS. - * @param region The AWS region to use. - * @param objectMapper The object mapper to use for JSON serialization and deserialization. - * @param timeout The timeout to use. - */ - public TitanChatBedrockApi(String modelId, AwsCredentialsProvider credentialsProvider, String region, - ObjectMapper objectMapper, Duration timeout) { - super(modelId, credentialsProvider, region, objectMapper, timeout); - } - - /** - * Create a new TitanChatBedrockApi instance using the provided credentials provider, region and object mapper. - * - * @param modelId The model id to use. See the {@link TitanChatModel} for the supported models. - * @param credentialsProvider The credentials provider to connect to AWS. - * @param region The AWS region to use. - * @param objectMapper The object mapper to use for JSON serialization and deserialization. - * @param timeout The timeout to use. - */ - public TitanChatBedrockApi(String modelId, AwsCredentialsProvider credentialsProvider, Region region, - ObjectMapper objectMapper, Duration timeout) { - super(modelId, credentialsProvider, region, objectMapper, timeout); - } - - @Override - public TitanChatResponse chatCompletion(TitanChatRequest request) { - return this.internalInvocation(request, TitanChatResponse.class); - } - - @Override - public Flux chatCompletionStream(TitanChatRequest request) { - return this.internalInvocationStream(request, TitanChatResponseChunk.class); - } - - /** - * Titan models version. - */ - public enum TitanChatModel implements ChatModelDescription { - - /** - * amazon.titan-text-lite-v1 - */ - TITAN_TEXT_LITE_V1("amazon.titan-text-lite-v1"), - - /** - * amazon.titan-text-express-v1 - */ - TITAN_TEXT_EXPRESS_V1("amazon.titan-text-express-v1"), - - /** - * amazon.titan-text-premier-v1:0 - */ - TITAN_TEXT_PREMIER_V1("amazon.titan-text-premier-v1:0"); - - private final String id; - - TitanChatModel(String value) { - this.id = value; - } - - /** - * @return The model id. - */ - public String id() { - return this.id; - } - - @Override - public String getName() { - return this.id; - } - } - - /** - * TitanChatRequest encapsulates the request parameters for the Titan chat model. - * - * @param inputText The prompt to use for the chat. - * @param textGenerationConfig The text generation configuration. - */ - @JsonInclude(Include.NON_NULL) - public record TitanChatRequest( - @JsonProperty("inputText") String inputText, - @JsonProperty("textGenerationConfig") TextGenerationConfig textGenerationConfig) { - - /** - * Create a new TitanChatRequest builder. - * @param inputText The prompt to use for the chat. - * @return A new TitanChatRequest builder. - */ - public static Builder builder(String inputText) { - return new Builder(inputText); - } - - /** - * Titan request text generation configuration. - * https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-titan-text.html - * - * @param temperature The temperature value controls the randomness of the generated text. - * @param topP The topP value controls the diversity of the generated text. Use a lower value to ignore less - * probable options. - * @param maxTokenCount The maximum number of tokens to generate. - * @param stopSequences A list of sequences to stop the generation at. Specify character sequences to indicate - * where the model should stop. Use the | (pipe) character to separate different sequences (maximum 20 - * characters). - */ - @JsonInclude(Include.NON_NULL) - public record TextGenerationConfig( - @JsonProperty("temperature") Double temperature, - @JsonProperty("topP") Double topP, - @JsonProperty("maxTokenCount") Integer maxTokenCount, - @JsonProperty("stopSequences") List stopSequences) { - } - - public static class Builder { - private final String inputText; - private Double temperature; - private Double topP; - private Integer maxTokenCount; - private List stopSequences; - - public Builder(String inputText) { - this.inputText = inputText; - } - - public Builder temperature(Double temperature) { - this.temperature = temperature; - return this; - } - - public Builder topP(Double topP) { - this.topP = topP; - return this; - } - - public Builder maxTokenCount(Integer maxTokenCount) { - this.maxTokenCount = maxTokenCount; - return this; - } - - public Builder stopSequences(List stopSequences) { - this.stopSequences = stopSequences; - return this; - } - - public TitanChatRequest build() { - - if (this.temperature == null && this.topP == null && this.maxTokenCount == null - && this.stopSequences == null) { - return new TitanChatRequest(this.inputText, null); - } - else { - return new TitanChatRequest(this.inputText, - new TextGenerationConfig( - this.temperature, - this.topP, - this.maxTokenCount, - this.stopSequences - )); - } - } - } - } - - /** - * TitanChatResponse encapsulates the response parameters for the Titan chat model. - * - * @param inputTextTokenCount The number of tokens in the input text. - * @param results The list of generated responses. - */ - @JsonInclude(Include.NON_NULL) - public record TitanChatResponse( - @JsonProperty("inputTextTokenCount") Integer inputTextTokenCount, - @JsonProperty("results") List results) { - - /** - * The reason the response finished being generated. - */ - public enum CompletionReason { - /** - * The response was fully generated. - */ - FINISH, - - /** - * The response was truncated because of the response length you set. - */ - LENGTH, - - /** - * The response was truncated because of restrictions. - */ - CONTENT_FILTERED - } - - /** - * Titan response result. - * - * @param tokenCount The number of tokens in the generated text. - * @param outputText The generated text. - * @param completionReason The reason the response finished being generated. - */ - @JsonInclude(Include.NON_NULL) - public record Result( - @JsonProperty("tokenCount") Integer tokenCount, - @JsonProperty("outputText") String outputText, - @JsonProperty("completionReason") CompletionReason completionReason) { - } - } - - /** - * Titan chat model streaming response. - * - * @param outputText The generated text in this chunk. - * @param index The index of the chunk in the streaming response. - * @param inputTextTokenCount The number of tokens in the prompt. - * @param totalOutputTextTokenCount The number of tokens in the response. - * @param completionReason The reason the response finished being generated. - * @param amazonBedrockInvocationMetrics The metrics for the invocation. - */ - @JsonInclude(Include.NON_NULL) - public record TitanChatResponseChunk( - @JsonProperty("outputText") String outputText, - @JsonProperty("index") Integer index, - @JsonProperty("inputTextTokenCount") Integer inputTextTokenCount, - @JsonProperty("totalOutputTextTokenCount") Integer totalOutputTextTokenCount, - @JsonProperty("completionReason") CompletionReason completionReason, - @JsonProperty("amazon-bedrock-invocationMetrics") AmazonBedrockInvocationMetrics amazonBedrockInvocationMetrics) { - } -} -// @formatter:on diff --git a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/anthropic/BedrockAnthropicChatModelIT.java b/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/anthropic/BedrockAnthropicChatModelIT.java deleted file mode 100644 index 532e0751248..00000000000 --- a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/anthropic/BedrockAnthropicChatModelIT.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.anthropic; - -import java.time.Duration; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import reactor.core.publisher.Flux; -import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.bedrock.RequiresAwsCredentials; -import org.springframework.ai.bedrock.anthropic.api.AnthropicChatBedrockApi; -import org.springframework.ai.chat.messages.AssistantMessage; -import org.springframework.ai.chat.messages.Message; -import org.springframework.ai.chat.messages.UserMessage; -import org.springframework.ai.chat.model.ChatResponse; -import org.springframework.ai.chat.model.Generation; -import org.springframework.ai.chat.prompt.Prompt; -import org.springframework.ai.chat.prompt.PromptTemplate; -import org.springframework.ai.chat.prompt.SystemPromptTemplate; -import org.springframework.ai.converter.BeanOutputConverter; -import org.springframework.ai.converter.ListOutputConverter; -import org.springframework.ai.converter.MapOutputConverter; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.SpringBootConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.Bean; -import org.springframework.core.convert.support.DefaultConversionService; -import org.springframework.core.io.Resource; -import org.springframework.core.log.LogAccessor; - -import static org.assertj.core.api.Assertions.assertThat; - -@SpringBootTest -@RequiresAwsCredentials -class BedrockAnthropicChatModelIT { - - private static final LogAccessor logger = new LogAccessor(BedrockAnthropicChatModelIT.class); - - @Autowired - private BedrockAnthropicChatModel chatModel; - - @Value("classpath:/prompts/system-message.st") - private Resource systemResource; - - @Test - void multipleStreamAttempts() { - - Flux joke1Stream = this.chatModel.stream(new Prompt(new UserMessage("Tell me a joke?"))); - Flux joke2Stream = this.chatModel.stream(new Prompt(new UserMessage("Tell me a toy joke?"))); - - String joke1 = joke1Stream.collectList() - .block() - .stream() - .map(ChatResponse::getResults) - .flatMap(List::stream) - .map(Generation::getOutput) - .map(AssistantMessage::getText) - .collect(Collectors.joining()); - String joke2 = joke2Stream.collectList() - .block() - .stream() - .map(ChatResponse::getResults) - .flatMap(List::stream) - .map(Generation::getOutput) - .map(AssistantMessage::getText) - .collect(Collectors.joining()); - - assertThat(joke1).isNotBlank(); - assertThat(joke2).isNotBlank(); - } - - @Test - void roleTest() { - UserMessage userMessage = new UserMessage( - "Tell me about 3 famous pirates from the Golden Age of Piracy and why they did."); - SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(this.systemResource); - Message systemMessage = systemPromptTemplate.createMessage(Map.of("name", "Bob", "voice", "pirate")); - - Prompt prompt = new Prompt(List.of(userMessage, systemMessage)); - - ChatResponse response = this.chatModel.call(prompt); - - assertThat(response.getResult().getOutput().getText()).contains("Blackbeard"); - } - - @Test - void listOutputConverter() { - DefaultConversionService conversionService = new DefaultConversionService(); - ListOutputConverter converter = new ListOutputConverter(conversionService); - - String format = converter.getFormat(); - String template = """ - List five {subject} - {format} - """; - PromptTemplate promptTemplate = new PromptTemplate(template, - Map.of("subject", "ice cream flavors.", "format", format)); - Prompt prompt = new Prompt(promptTemplate.createMessage()); - Generation generation = this.chatModel.call(prompt).getResult(); - - List list = converter.convert(generation.getOutput().getText()); - assertThat(list).hasSize(5); - } - - @Disabled - @Test - void mapOutputConvert() { - MapOutputConverter outputConverter = new MapOutputConverter(); - - String format = outputConverter.getFormat(); - String template = """ - Provide me a List of {subject} - {format} - """; - PromptTemplate promptTemplate = new PromptTemplate(template, - Map.of("subject", "an array of numbers from 1 to 9 under they key name 'numbers'", "format", format)); - Prompt prompt = new Prompt(promptTemplate.createMessage()); - Generation generation = this.chatModel.call(prompt).getResult(); - - Map result = outputConverter.convert(generation.getOutput().getText()); - assertThat(result.get("numbers")).isEqualTo(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9)); - - } - - @Disabled - @Test - void beanOutputConverterRecords() { - - BeanOutputConverter outputConvert = new BeanOutputConverter<>(ActorsFilmsRecord.class); - - String format = outputConvert.getFormat(); - String template = """ - Generate the filmography of 5 movies for Tom Hanks. - Remove non JSON tex blocks from the output. - {format} - Provide your answer in the JSON format with the feature names as the keys. - """; - PromptTemplate promptTemplate = new PromptTemplate(template, Map.of("format", format)); - Prompt prompt = new Prompt(promptTemplate.createMessage()); - Generation generation = this.chatModel.call(prompt).getResult(); - - ActorsFilmsRecord actorsFilms = outputConvert.convert(generation.getOutput().getText()); - assertThat(actorsFilms.actor()).isEqualTo("Tom Hanks"); - assertThat(actorsFilms.movies()).hasSize(5); - } - - @Test - void beanStreamOutputConverterRecords() { - - BeanOutputConverter outputConverter = new BeanOutputConverter<>(ActorsFilmsRecord.class); - - String format = outputConverter.getFormat(); - String template = """ - Generate the filmography of 5 movies for Tom Hanks. - {format} - Remove Markdown code blocks from the output. - """; - PromptTemplate promptTemplate = new PromptTemplate(template, Map.of("format", format)); - Prompt prompt = new Prompt(promptTemplate.createMessage()); - - String generationTextFromStream = this.chatModel.stream(prompt) - .collectList() - .block() - .stream() - .map(ChatResponse::getResults) - .flatMap(List::stream) - .map(Generation::getOutput) - .map(AssistantMessage::getText) - .collect(Collectors.joining()); - - ActorsFilmsRecord actorsFilms = outputConverter.convert(generationTextFromStream); - logger.info("" + actorsFilms); - assertThat(actorsFilms.actor()).isEqualTo("Tom Hanks"); - assertThat(actorsFilms.movies()).hasSize(5); - } - - record ActorsFilmsRecord(String actor, List movies) { - - } - - @SpringBootConfiguration - public static class TestConfiguration { - - @Bean - public AnthropicChatBedrockApi anthropicApi() { - return new AnthropicChatBedrockApi(AnthropicChatBedrockApi.AnthropicChatModel.CLAUDE_V21.id(), - EnvironmentVariableCredentialsProvider.create(), Region.US_EAST_1.id(), new ObjectMapper(), - Duration.ofMinutes(2)); - } - - @Bean - public BedrockAnthropicChatModel anthropicChatModel(AnthropicChatBedrockApi anthropicApi) { - return new BedrockAnthropicChatModel(anthropicApi); - } - - } - -} diff --git a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/anthropic/BedrockAnthropicCreateRequestTests.java b/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/anthropic/BedrockAnthropicCreateRequestTests.java deleted file mode 100644 index 467db83a17f..00000000000 --- a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/anthropic/BedrockAnthropicCreateRequestTests.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.anthropic; - -import java.time.Duration; -import java.util.List; - -import org.junit.jupiter.api.Test; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.bedrock.anthropic.api.AnthropicChatBedrockApi; -import org.springframework.ai.bedrock.anthropic.api.AnthropicChatBedrockApi.AnthropicChatModel; -import org.springframework.ai.chat.prompt.Prompt; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Christian Tzolov - */ -public class BedrockAnthropicCreateRequestTests { - - private AnthropicChatBedrockApi anthropicChatApi = new AnthropicChatBedrockApi(AnthropicChatModel.CLAUDE_V2.id(), - Region.US_EAST_1.id(), Duration.ofMillis(1000L)); - - @Test - public void createRequestWithChatOptions() { - - var client = new BedrockAnthropicChatModel(this.anthropicChatApi, - AnthropicChatOptions.builder() - .temperature(66.6) - .topK(66) - .topP(0.66) - .maxTokensToSample(666) - .anthropicVersion("X.Y.Z") - .stopSequences(List.of("stop1", "stop2")) - .build()); - - var request = client.createRequest(new Prompt("Test message content")); - - assertThat(request.prompt()).isNotEmpty(); - assertThat(request.temperature()).isEqualTo(66.6); - assertThat(request.topK()).isEqualTo(66); - assertThat(request.topP()).isEqualTo(0.66); - assertThat(request.maxTokensToSample()).isEqualTo(666); - assertThat(request.anthropicVersion()).isEqualTo("X.Y.Z"); - assertThat(request.stopSequences()).containsExactly("stop1", "stop2"); - - request = client.createRequest(new Prompt("Test message content", - AnthropicChatOptions.builder() - .temperature(99.9) - .topP(0.99) - .maxTokensToSample(999) - .anthropicVersion("zzz") - .stopSequences(List.of("stop3", "stop4")) - .build() - - )); - - assertThat(request.prompt()).isNotEmpty(); - assertThat(request.temperature()).isEqualTo(99.9); - assertThat(request.topK()).as("unchanged from the default options").isEqualTo(66); - assertThat(request.topP()).isEqualTo(0.99); - assertThat(request.maxTokensToSample()).isEqualTo(999); - assertThat(request.anthropicVersion()).isEqualTo("zzz"); - assertThat(request.stopSequences()).containsExactly("stop3", "stop4"); - } - -} diff --git a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/anthropic/api/AnthropicChatBedrockApiIT.java b/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/anthropic/api/AnthropicChatBedrockApiIT.java deleted file mode 100644 index f68a4094844..00000000000 --- a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/anthropic/api/AnthropicChatBedrockApiIT.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.anthropic.api; - -import java.time.Duration; -import java.util.List; -import java.util.stream.Collectors; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Test; -import reactor.core.publisher.Flux; -import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.bedrock.RequiresAwsCredentials; -import org.springframework.ai.bedrock.anthropic.api.AnthropicChatBedrockApi.AnthropicChatModel; -import org.springframework.ai.bedrock.anthropic.api.AnthropicChatBedrockApi.AnthropicChatRequest; -import org.springframework.ai.bedrock.anthropic.api.AnthropicChatBedrockApi.AnthropicChatResponse; -import org.springframework.core.log.LogAccessor; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Christian Tzolov - */ -@RequiresAwsCredentials -public class AnthropicChatBedrockApiIT { - - private static final LogAccessor logger = new LogAccessor(AnthropicChatBedrockApiIT.class); - - private AnthropicChatBedrockApi anthropicChatApi = new AnthropicChatBedrockApi(AnthropicChatModel.CLAUDE_V2.id(), - EnvironmentVariableCredentialsProvider.create(), Region.US_EAST_1.id(), new ObjectMapper(), - Duration.ofMinutes(2)); - - @Test - public void chatCompletion() { - - AnthropicChatRequest request = AnthropicChatRequest - .builder(String.format(AnthropicChatBedrockApi.PROMPT_TEMPLATE, "Name 3 famous pirates")) - .temperature(0.8) - .maxTokensToSample(300) - .topK(10) - .build(); - - AnthropicChatResponse response = this.anthropicChatApi.chatCompletion(request); - - System.out.println(response.completion()); - assertThat(response).isNotNull(); - assertThat(response.completion()).isNotEmpty(); - assertThat(response.completion()).contains("Blackbeard"); - assertThat(response.stopReason()).isEqualTo("stop_sequence"); - assertThat(response.stop()).isEqualTo("\n\nHuman:"); - assertThat(response.amazonBedrockInvocationMetrics()).isNull(); - - logger.info("" + response); - } - - @Test - public void chatCompletionStream() { - - AnthropicChatRequest request = AnthropicChatRequest - .builder(String.format(AnthropicChatBedrockApi.PROMPT_TEMPLATE, "Name 3 famous pirates")) - .temperature(0.8) - .maxTokensToSample(300) - .topK(10) - .stopSequences(List.of("\n\nHuman:")) - .build(); - - Flux responseStream = this.anthropicChatApi.chatCompletionStream(request); - - List responses = responseStream.collectList().block(); - assertThat(responses).isNotNull(); - assertThat(responses).hasSizeGreaterThan(10); - assertThat(responses.stream().map(AnthropicChatResponse::completion).collect(Collectors.joining())) - .contains("Blackbeard"); - } - -} diff --git a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/anthropic3/BedrockAnthropic3ChatModelIT.java b/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/anthropic3/BedrockAnthropic3ChatModelIT.java deleted file mode 100644 index 65f25976a83..00000000000 --- a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/anthropic3/BedrockAnthropic3ChatModelIT.java +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.anthropic3; - -import java.io.IOException; -import java.time.Duration; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Test; -import reactor.core.publisher.Flux; -import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.bedrock.RequiresAwsCredentials; -import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi; -import org.springframework.ai.chat.messages.AssistantMessage; -import org.springframework.ai.chat.messages.Message; -import org.springframework.ai.chat.messages.UserMessage; -import org.springframework.ai.chat.model.ChatResponse; -import org.springframework.ai.chat.model.Generation; -import org.springframework.ai.chat.prompt.Prompt; -import org.springframework.ai.chat.prompt.PromptTemplate; -import org.springframework.ai.chat.prompt.SystemPromptTemplate; -import org.springframework.ai.converter.BeanOutputConverter; -import org.springframework.ai.converter.ListOutputConverter; -import org.springframework.ai.converter.MapOutputConverter; -import org.springframework.ai.model.Media; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.SpringBootConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.Bean; -import org.springframework.core.convert.support.DefaultConversionService; -import org.springframework.core.io.ClassPathResource; -import org.springframework.core.io.Resource; -import org.springframework.core.log.LogAccessor; -import org.springframework.util.MimeTypeUtils; - -import static org.assertj.core.api.Assertions.assertThat; - -@SpringBootTest -@RequiresAwsCredentials -class BedrockAnthropic3ChatModelIT { - - private static final LogAccessor logger = new LogAccessor(BedrockAnthropic3ChatModelIT.class); - - @Autowired - private BedrockAnthropic3ChatModel chatModel; - - @Value("classpath:/prompts/system-message.st") - private Resource systemResource; - - @Test - void multipleStreamAttempts() { - - Flux joke1Stream = this.chatModel.stream(new Prompt(new UserMessage("Tell me a joke?"))); - Flux joke2Stream = this.chatModel.stream(new Prompt(new UserMessage("Tell me a toy joke?"))); - - String joke1 = joke1Stream.collectList() - .block() - .stream() - .map(ChatResponse::getResults) - .flatMap(List::stream) - .map(Generation::getOutput) - .map(AssistantMessage::getText) - .collect(Collectors.joining()); - String joke2 = joke2Stream.collectList() - .block() - .stream() - .map(ChatResponse::getResults) - .flatMap(List::stream) - .map(Generation::getOutput) - .map(AssistantMessage::getText) - .collect(Collectors.joining()); - - assertThat(joke1).isNotBlank(); - assertThat(joke2).isNotBlank(); - } - - @Test - void roleTest() { - UserMessage userMessage = new UserMessage( - "Tell me about 3 famous pirates from the Golden Age of Piracy and why they did."); - SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(this.systemResource); - Message systemMessage = systemPromptTemplate.createMessage(Map.of("name", "Bob", "voice", "pirate")); - - Prompt prompt = new Prompt(List.of(userMessage, systemMessage)); - - ChatResponse response = this.chatModel.call(prompt); - - assertThat(response.getResult().getOutput().getText()).contains("Blackbeard"); - } - - @Test - void listOutputConverter() { - DefaultConversionService conversionService = new DefaultConversionService(); - ListOutputConverter outputConverter = new ListOutputConverter(conversionService); - - String format = outputConverter.getFormat(); - String template = """ - List five {subject} - {format} - """; - PromptTemplate promptTemplate = new PromptTemplate(template, - Map.of("subject", "ice cream flavors.", "format", format)); - Prompt prompt = new Prompt(promptTemplate.createMessage()); - Generation generation = this.chatModel.call(prompt).getResult(); - - List list = outputConverter.convert(generation.getOutput().getText()); - assertThat(list).hasSize(5); - } - - @Test - void mapOutputConverter() { - MapOutputConverter outputConverter = new MapOutputConverter(); - - String format = outputConverter.getFormat(); - String template = """ - Provide me a List of {subject} - {format} - Remove the ```json code blocks from the output. - """; - PromptTemplate promptTemplate = new PromptTemplate(template, - Map.of("subject", "an array of numbers from 1 to 9 under they key name 'numbers'", "format", format)); - Prompt prompt = new Prompt(promptTemplate.createMessage()); - Generation generation = this.chatModel.call(prompt).getResult(); - - Map result = outputConverter.convert(generation.getOutput().getText()); - assertThat(result.get("numbers")).isEqualTo(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9)); - - } - - @Test - void beanOutputConverterRecords() { - - BeanOutputConverter outputConverter = new BeanOutputConverter<>(ActorsFilmsRecord.class); - - String format = outputConverter.getFormat(); - String template = """ - Generate the filmography of 5 movies for Tom Hanks. - {format} - Provide your answer in the JSON format with the feature names as the keys. - Remove Markdown code blocks from the output. - """; - PromptTemplate promptTemplate = new PromptTemplate(template, Map.of("format", format)); - Prompt prompt = new Prompt(promptTemplate.createMessage()); - Generation generation = this.chatModel.call(prompt).getResult(); - - ActorsFilmsRecord actorsFilms = outputConverter.convert(generation.getOutput().getText()); - assertThat(actorsFilms.actor()).isEqualTo("Tom Hanks"); - assertThat(actorsFilms.movies()).hasSize(5); - } - - @Test - void beanStreamOutputConverterRecords() { - - BeanOutputConverter outputConverter = new BeanOutputConverter<>(ActorsFilmsRecord.class); - - String format = outputConverter.getFormat(); - String template = """ - Generate the filmography of 5 movies for Tom Hanks. - {format} - Remove Markdown code blocks from the output. - """; - PromptTemplate promptTemplate = new PromptTemplate(template, Map.of("format", format)); - Prompt prompt = new Prompt(promptTemplate.createMessage()); - - String generationTextFromStream = this.chatModel.stream(prompt) - .collectList() - .block() - .stream() - .map(ChatResponse::getResults) - .flatMap(List::stream) - .map(Generation::getOutput) - .map(AssistantMessage::getText) - .collect(Collectors.joining()); - - ActorsFilmsRecord actorsFilms = outputConverter.convert(generationTextFromStream); - logger.info("" + actorsFilms); - assertThat(actorsFilms.actor()).isEqualTo("Tom Hanks"); - assertThat(actorsFilms.movies()).hasSize(5); - } - - @Test - void multiModalityTest() throws IOException { - - var imageData = new ClassPathResource("/test.png"); - - var userMessage = new UserMessage("Explain what do you see o this picture?", - List.of(new Media(MimeTypeUtils.IMAGE_PNG, imageData))); - - var response = this.chatModel.call(new Prompt(List.of(userMessage))); - - logger.info(response.getResult().getOutput().getText()); - assertThat(response.getResult().getOutput().getText()).contains("bananas", "apple", "basket"); - } - - @Test - void stopSequencesWithEmptyContents() { - Anthropic3ChatOptions chatOptions = new Anthropic3ChatOptions(); - chatOptions.setStopSequences(List.of("Hello")); - - var response = this.chatModel.call(new Prompt("hi", chatOptions)); - - assertThat(response).isNotNull(); - assertThat(response.getResults()).isEmpty(); - } - - record ActorsFilmsRecord(String actor, List movies) { - - } - - @SpringBootConfiguration - public static class TestConfiguration { - - @Bean - public Anthropic3ChatBedrockApi anthropicApi() { - return new Anthropic3ChatBedrockApi(Anthropic3ChatBedrockApi.AnthropicChatModel.CLAUDE_V3_SONNET.id(), - EnvironmentVariableCredentialsProvider.create(), Region.US_EAST_1.id(), new ObjectMapper(), - Duration.ofMinutes(5)); - } - - @Bean - public BedrockAnthropic3ChatModel anthropicChatModel(Anthropic3ChatBedrockApi anthropicApi) { - return new BedrockAnthropic3ChatModel(anthropicApi); - } - - } - -} diff --git a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/anthropic3/BedrockAnthropic3CreateRequestTests.java b/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/anthropic3/BedrockAnthropic3CreateRequestTests.java deleted file mode 100644 index 3b4431fdaa8..00000000000 --- a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/anthropic3/BedrockAnthropic3CreateRequestTests.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.anthropic3; - -import java.time.Duration; -import java.util.List; - -import org.junit.jupiter.api.Test; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi; -import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi.AnthropicChatModel; -import org.springframework.ai.chat.prompt.Prompt; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Christian Tzolov - */ -public class BedrockAnthropic3CreateRequestTests { - - private Anthropic3ChatBedrockApi anthropicChatApi = new Anthropic3ChatBedrockApi(AnthropicChatModel.CLAUDE_V2.id(), - Region.US_EAST_1.id(), Duration.ofMillis(1000L)); - - @Test - public void createRequestWithChatOptions() { - - var client = new BedrockAnthropic3ChatModel(this.anthropicChatApi, - Anthropic3ChatOptions.builder() - .temperature(66.6) - .topK(66) - .topP(0.66) - .maxTokens(666) - .anthropicVersion("X.Y.Z") - .stopSequences(List.of("stop1", "stop2")) - .build()); - - var request = client.createRequest(new Prompt("Test message content")); - - assertThat(request.messages()).isNotEmpty(); - assertThat(request.temperature()).isEqualTo(66.6); - assertThat(request.topK()).isEqualTo(66); - assertThat(request.topP()).isEqualTo(0.66); - assertThat(request.maxTokens()).isEqualTo(666); - assertThat(request.anthropicVersion()).isEqualTo("X.Y.Z"); - assertThat(request.stopSequences()).containsExactly("stop1", "stop2"); - - request = client.createRequest(new Prompt("Test message content", - Anthropic3ChatOptions.builder() - .temperature(99.9) - .topP(0.99) - .maxTokens(999) - .anthropicVersion("zzz") - .stopSequences(List.of("stop3", "stop4")) - .build() - - )); - - assertThat(request.messages()).isNotEmpty(); - assertThat(request.temperature()).isEqualTo(99.9); - assertThat(request.topK()).as("unchanged from the default options").isEqualTo(66); - assertThat(request.topP()).isEqualTo(0.99); - assertThat(request.maxTokens()).isEqualTo(999); - assertThat(request.anthropicVersion()).isEqualTo("zzz"); - assertThat(request.stopSequences()).containsExactly("stop3", "stop4"); - } - -} diff --git a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/anthropic3/api/Anthropic3ChatBedrockApiIT.java b/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/anthropic3/api/Anthropic3ChatBedrockApiIT.java deleted file mode 100644 index 59209d9cadd..00000000000 --- a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/anthropic3/api/Anthropic3ChatBedrockApiIT.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.anthropic3.api; - -import java.time.Duration; -import java.util.List; -import java.util.stream.Collectors; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Test; -import reactor.core.publisher.Flux; -import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.bedrock.RequiresAwsCredentials; -import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi.AnthropicChatModel; -import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi.AnthropicChatRequest; -import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi.AnthropicChatResponse; -import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi.AnthropicChatStreamingResponse.StreamingType; -import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi.ChatCompletionMessage; -import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi.ChatCompletionMessage.Role; -import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi.MediaContent; -import org.springframework.core.log.LogAccessor; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Ben Middleton - */ -@RequiresAwsCredentials -public class Anthropic3ChatBedrockApiIT { - - private static final LogAccessor logger = new LogAccessor(Anthropic3ChatBedrockApiIT.class); - - private Anthropic3ChatBedrockApi anthropicChatApi = new Anthropic3ChatBedrockApi( - AnthropicChatModel.CLAUDE_INSTANT_V1.id(), EnvironmentVariableCredentialsProvider.create(), - Region.US_EAST_1.id(), new ObjectMapper(), Duration.ofMinutes(2)); - - @Test - public void chatCompletion() { - - MediaContent anthropicMessage = new MediaContent("Name 3 famous pirates"); - ChatCompletionMessage chatCompletionMessage = new ChatCompletionMessage(List.of(anthropicMessage), Role.USER); - AnthropicChatRequest request = AnthropicChatRequest.builder(List.of(chatCompletionMessage)) - .temperature(0.8) - .maxTokens(300) - .topK(10) - .anthropicVersion( - org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi.DEFAULT_ANTHROPIC_VERSION) - .build(); - - AnthropicChatResponse response = this.anthropicChatApi.chatCompletion(request); - - logger.info("" + response.content()); - - assertThat(response).isNotNull(); - assertThat(response.content().get(0).text()).isNotEmpty(); - assertThat(response.content().get(0).text()).contains("Blackbeard"); - assertThat(response.stopReason()).isEqualTo("end_turn"); - assertThat(response.stopSequence()).isNull(); - assertThat(response.usage().inputTokens()).isGreaterThan(10); - assertThat(response.usage().outputTokens()).isGreaterThan(100); - - logger.info("" + response); - } - - @Test - public void chatMultiCompletion() { - - MediaContent anthropicInitialMessage = new MediaContent("Name 3 famous pirates"); - ChatCompletionMessage chatCompletionInitialMessage = new ChatCompletionMessage(List.of(anthropicInitialMessage), - Role.USER); - - MediaContent anthropicAssistantMessage = new MediaContent( - "Here are 3 famous pirates: Blackbeard, Calico Jack, Henry Morgan"); - ChatCompletionMessage chatCompletionAssistantMessage = new ChatCompletionMessage( - List.of(anthropicAssistantMessage), Role.ASSISTANT); - - MediaContent anthropicFollowupMessage = new MediaContent("Why are they famous?"); - ChatCompletionMessage chatCompletionFollowupMessage = new ChatCompletionMessage( - List.of(anthropicFollowupMessage), Role.USER); - - AnthropicChatRequest request = AnthropicChatRequest - .builder(List.of(chatCompletionInitialMessage, chatCompletionAssistantMessage, - chatCompletionFollowupMessage)) - .temperature(0.8) - .maxTokens(400) - .topK(10) - .anthropicVersion( - org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi.DEFAULT_ANTHROPIC_VERSION) - .build(); - - AnthropicChatResponse response = this.anthropicChatApi.chatCompletion(request); - - logger.info("" + response.content()); - assertThat(response).isNotNull(); - assertThat(response.content().get(0).text()).isNotEmpty(); - assertThat(response.content().get(0).text()).contains("Blackbeard"); - assertThat(response.stopReason()).isEqualTo("end_turn"); - assertThat(response.stopSequence()).isNull(); - assertThat(response.usage().inputTokens()).isGreaterThan(30); - assertThat(response.usage().outputTokens()).isGreaterThan(200); - - logger.info("" + response); - } - - @Test - public void chatCompletionStream() { - MediaContent anthropicMessage = new MediaContent("Name 3 famous pirates"); - ChatCompletionMessage chatCompletionMessage = new ChatCompletionMessage(List.of(anthropicMessage), Role.USER); - - AnthropicChatRequest request = AnthropicChatRequest.builder(List.of(chatCompletionMessage)) - .temperature(0.8) - .maxTokens(300) - .topK(10) - .anthropicVersion( - org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi.DEFAULT_ANTHROPIC_VERSION) - .build(); - - Flux responseStream = this.anthropicChatApi - .chatCompletionStream(request); - - List responses = responseStream.collectList().block(); - assertThat(responses).isNotNull(); - assertThat(responses).hasSizeGreaterThan(10); - assertThat(responses.stream() - .filter(message -> message.type() == StreamingType.CONTENT_BLOCK_DELTA) - .map(message -> message.delta().text()) - .collect(Collectors.joining())).contains("Blackbeard"); - } - -} diff --git a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/aot/BedrockRuntimeHintsTests.java b/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/aot/BedrockRuntimeHintsTests.java index aa3ff8bdf3a..3a87d56dd15 100644 --- a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/aot/BedrockRuntimeHintsTests.java +++ b/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/aot/BedrockRuntimeHintsTests.java @@ -22,12 +22,7 @@ import org.junit.jupiter.api.Test; -import org.springframework.ai.bedrock.anthropic.api.AnthropicChatBedrockApi; -import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi; import org.springframework.ai.bedrock.cohere.api.CohereEmbeddingBedrockApi; -import org.springframework.ai.bedrock.jurassic2.api.Ai21Jurassic2ChatBedrockApi; -import org.springframework.ai.bedrock.llama.api.LlamaChatBedrockApi; -import org.springframework.ai.bedrock.titan.api.TitanChatBedrockApi; import org.springframework.ai.bedrock.titan.api.TitanEmbeddingBedrockApi; import org.springframework.aot.hint.RuntimeHints; import org.springframework.aot.hint.TypeReference; @@ -44,9 +39,7 @@ void registerHints() { BedrockRuntimeHints bedrockRuntimeHints = new BedrockRuntimeHints(); bedrockRuntimeHints.registerHints(runtimeHints, null); - List classList = Arrays.asList(Ai21Jurassic2ChatBedrockApi.class, CohereChatBedrockApi.class, - CohereEmbeddingBedrockApi.class, LlamaChatBedrockApi.class, TitanChatBedrockApi.class, - TitanEmbeddingBedrockApi.class, AnthropicChatBedrockApi.class); + List classList = Arrays.asList(CohereEmbeddingBedrockApi.class, TitanEmbeddingBedrockApi.class); for (Class aClass : classList) { Set jsonAnnotatedClasses = findJsonAnnotatedClassesInPackage(aClass); diff --git a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/cohere/BedrockCohereChatCreateRequestTests.java b/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/cohere/BedrockCohereChatCreateRequestTests.java deleted file mode 100644 index 8b1056bc682..00000000000 --- a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/cohere/BedrockCohereChatCreateRequestTests.java +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.cohere; - -import java.time.Duration; -import java.util.List; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Test; -import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi; -import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi.CohereChatModel; -import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi.CohereChatRequest; -import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi.CohereChatRequest.LogitBias; -import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi.CohereChatRequest.ReturnLikelihoods; -import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi.CohereChatRequest.Truncate; -import org.springframework.ai.chat.prompt.Prompt; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Christian Tzolov - */ -public class BedrockCohereChatCreateRequestTests { - - private CohereChatBedrockApi chatApi = new CohereChatBedrockApi(CohereChatModel.COHERE_COMMAND_V14.id(), - EnvironmentVariableCredentialsProvider.create(), Region.US_EAST_1.id(), new ObjectMapper(), - Duration.ofMinutes(2)); - - @Test - public void createRequestWithChatOptions() { - - var client = new BedrockCohereChatModel(this.chatApi, - BedrockCohereChatOptions.builder() - .temperature(66.6) - .topK(66) - .topP(0.66) - .maxTokens(678) - .stopSequences(List.of("stop1", "stop2")) - .returnLikelihoods(ReturnLikelihoods.ALL) - .numGenerations(3) - .logitBias(new LogitBias("t", 6.6f)) - .truncate(Truncate.END) - .build()); - - CohereChatRequest request = client.createRequest(new Prompt("Test message content"), true); - - assertThat(request.prompt()).isNotEmpty(); - assertThat(request.stream()).isTrue(); - - assertThat(request.temperature()).isEqualTo(66.6); - assertThat(request.topK()).isEqualTo(66); - assertThat(request.topP()).isEqualTo(0.66); - assertThat(request.maxTokens()).isEqualTo(678); - assertThat(request.stopSequences()).containsExactly("stop1", "stop2"); - assertThat(request.returnLikelihoods()).isEqualTo(ReturnLikelihoods.ALL); - assertThat(request.numGenerations()).isEqualTo(3); - assertThat(request.logitBias()).isEqualTo(new LogitBias("t", 6.6f)); - assertThat(request.truncate()).isEqualTo(Truncate.END); - - request = client.createRequest(new Prompt("Test message content", - BedrockCohereChatOptions.builder() - .temperature(99.9) - .topK(99) - .topP(0.99) - .maxTokens(888) - .stopSequences(List.of("stop3", "stop4")) - .returnLikelihoods(ReturnLikelihoods.GENERATION) - .numGenerations(13) - .logitBias(new LogitBias("t", 9.9f)) - .truncate(Truncate.START) - .build()), - false - - ); - - assertThat(request.prompt()).isNotEmpty(); - assertThat(request.stream()).isFalse(); - - assertThat(request.temperature()).isEqualTo(99.9); - assertThat(request.topK()).isEqualTo(99); - assertThat(request.topP()).isEqualTo(0.99); - assertThat(request.maxTokens()).isEqualTo(888); - assertThat(request.stopSequences()).containsExactly("stop3", "stop4"); - assertThat(request.returnLikelihoods()).isEqualTo(ReturnLikelihoods.GENERATION); - assertThat(request.numGenerations()).isEqualTo(13); - assertThat(request.logitBias()).isEqualTo(new LogitBias("t", 9.9f)); - assertThat(request.truncate()).isEqualTo(Truncate.START); - } - -} diff --git a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/cohere/BedrockCohereChatModelIT.java b/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/cohere/BedrockCohereChatModelIT.java deleted file mode 100644 index edce30d3497..00000000000 --- a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/cohere/BedrockCohereChatModelIT.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.cohere; - -import java.time.Duration; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import reactor.core.publisher.Flux; -import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.bedrock.RequiresAwsCredentials; -import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi; -import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi.CohereChatModel; -import org.springframework.ai.chat.messages.AssistantMessage; -import org.springframework.ai.chat.messages.Message; -import org.springframework.ai.chat.messages.UserMessage; -import org.springframework.ai.chat.model.ChatResponse; -import org.springframework.ai.chat.model.Generation; -import org.springframework.ai.chat.prompt.Prompt; -import org.springframework.ai.chat.prompt.PromptTemplate; -import org.springframework.ai.chat.prompt.SystemPromptTemplate; -import org.springframework.ai.converter.BeanOutputConverter; -import org.springframework.ai.converter.ListOutputConverter; -import org.springframework.ai.converter.MapOutputConverter; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.SpringBootConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.Bean; -import org.springframework.core.convert.support.DefaultConversionService; -import org.springframework.core.io.Resource; - -import static org.assertj.core.api.Assertions.assertThat; - -@SpringBootTest -@RequiresAwsCredentials -@Disabled("COHERE_COMMAND_V14 is not supported anymore") -class BedrockCohereChatModelIT { - - @Autowired - private BedrockCohereChatModel chatModel; - - @Value("classpath:/prompts/system-message.st") - private Resource systemResource; - - @Test - void multipleStreamAttempts() { - - Flux joke1Stream = this.chatModel.stream(new Prompt(new UserMessage("Tell me a joke?"))); - Flux joke2Stream = this.chatModel.stream(new Prompt(new UserMessage("Tell me a toy joke?"))); - - String joke1 = joke1Stream.collectList() - .block() - .stream() - .map(ChatResponse::getResults) - .flatMap(List::stream) - .map(Generation::getOutput) - .map(AssistantMessage::getText) - .collect(Collectors.joining()); - String joke2 = joke2Stream.collectList() - .block() - .stream() - .map(ChatResponse::getResults) - .flatMap(List::stream) - .map(Generation::getOutput) - .map(AssistantMessage::getText) - .collect(Collectors.joining()); - - assertThat(joke1).isNotBlank(); - assertThat(joke2).isNotBlank(); - } - - @Test - void roleTest() { - String request = "Tell me about 3 famous pirates from the Golden Age of Piracy and why they did."; - String name = "Bob"; - String voice = "pirate"; - UserMessage userMessage = new UserMessage(request); - SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(this.systemResource); - Message systemMessage = systemPromptTemplate.createMessage(Map.of("name", name, "voice", voice)); - Prompt prompt = new Prompt(List.of(userMessage, systemMessage)); - ChatResponse response = this.chatModel.call(prompt); - assertThat(response.getResult().getOutput().getText()).contains("Blackbeard"); - } - - @Test - void listOutputConverter() { - DefaultConversionService conversionService = new DefaultConversionService(); - ListOutputConverter outputConverter = new ListOutputConverter(conversionService); - - String format = outputConverter.getFormat(); - String template = """ - List five {subject} - {format} - """; - PromptTemplate promptTemplate = new PromptTemplate(template, - Map.of("subject", "ice cream flavors.", "format", format)); - Prompt prompt = new Prompt(promptTemplate.createMessage()); - Generation generation = this.chatModel.call(prompt).getResult(); - - List list = outputConverter.convert(generation.getOutput().getText()); - assertThat(list).hasSize(5); - } - - @Test - void mapOutputConverter() { - MapOutputConverter outputConverter = new MapOutputConverter(); - - String format = outputConverter.getFormat(); - String template = """ - Remove Markdown code blocks from the output. - Provide me a List of {subject} - {format} - """; - PromptTemplate promptTemplate = new PromptTemplate(template, - Map.of("subject", "an array of numbers from 1 to 9 under they key name 'numbers'", "format", format)); - Prompt prompt = new Prompt(promptTemplate.createMessage()); - Generation generation = this.chatModel.call(prompt).getResult(); - - Map result = outputConverter.convert(generation.getOutput().getText()); - assertThat(result.get("numbers")).isEqualTo(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9)); - - } - - @Test - void beanOutputConverterRecords() { - - BeanOutputConverter outputConverter = new BeanOutputConverter<>(ActorsFilmsRecord.class); - - String format = outputConverter.getFormat(); - String template = """ - Generate the filmography of 5 movies for Tom Hanks. - {format} - Remove Markdown code blocks from the output. - """; - PromptTemplate promptTemplate = new PromptTemplate(template, Map.of("format", format)); - Prompt prompt = new Prompt(promptTemplate.createMessage()); - Generation generation = this.chatModel.call(prompt).getResult(); - - ActorsFilmsRecord actorsFilms = outputConverter.convert(generation.getOutput().getText()); - assertThat(actorsFilms.actor()).isEqualTo("Tom Hanks"); - assertThat(actorsFilms.movies()).hasSize(5); - } - - @Test - void beanStreamOutputConverterRecords() { - - BeanOutputConverter outputConverter = new BeanOutputConverter<>(ActorsFilmsRecord.class); - - String format = outputConverter.getFormat(); - String template = """ - Generate the filmography of 5 movies for Tom Hanks. - {format} - Remove Markdown code blocks from the output. - """; - PromptTemplate promptTemplate = new PromptTemplate(template, Map.of("format", format)); - Prompt prompt = new Prompt(promptTemplate.createMessage()); - - String generationTextFromStream = this.chatModel.stream(prompt) - .collectList() - .block() - .stream() - .map(ChatResponse::getResults) - .flatMap(List::stream) - .map(Generation::getOutput) - .map(AssistantMessage::getText) - .collect(Collectors.joining()); - - ActorsFilmsRecord actorsFilms = outputConverter.convert(generationTextFromStream); - System.out.println(actorsFilms); - assertThat(actorsFilms.actor()).isEqualTo("Tom Hanks"); - assertThat(actorsFilms.movies()).hasSize(5); - } - - record ActorsFilmsRecord(String actor, List movies) { - - } - - @SpringBootConfiguration - public static class TestConfiguration { - - @Bean - public CohereChatBedrockApi cohereApi() { - return new CohereChatBedrockApi(CohereChatModel.COHERE_COMMAND_V14.id(), - EnvironmentVariableCredentialsProvider.create(), Region.US_EAST_1.id(), new ObjectMapper(), - Duration.ofMinutes(2)); - } - - @Bean - public BedrockCohereChatModel cohereChatModel(CohereChatBedrockApi cohereApi) { - return new BedrockCohereChatModel(cohereApi); - } - - } - -} diff --git a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/cohere/api/CohereChatBedrockApiIT.java b/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/cohere/api/CohereChatBedrockApiIT.java deleted file mode 100644 index 5029acf74a4..00000000000 --- a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/cohere/api/CohereChatBedrockApiIT.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.cohere.api; - -import java.time.Duration; -import java.util.List; - -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import reactor.core.publisher.Flux; -import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.bedrock.RequiresAwsCredentials; -import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi.CohereChatModel; -import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi.CohereChatRequest; -import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi.CohereChatRequest.Truncate; -import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi.CohereChatResponse; -import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi.CohereChatResponse.Generation.FinishReason; -import org.springframework.ai.model.ModelOptionsUtils; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; - -/** - * @author Christian Tzolov - */ -@RequiresAwsCredentials -public class CohereChatBedrockApiIT { - - private CohereChatBedrockApi cohereChatApi = new CohereChatBedrockApi(CohereChatModel.COHERE_COMMAND_V14.id(), - EnvironmentVariableCredentialsProvider.create(), Region.US_EAST_1.id(), ModelOptionsUtils.OBJECT_MAPPER, - Duration.ofMinutes(2)); - - @Test - public void requestBuilder() { - - CohereChatRequest request1 = new CohereChatRequest( - "What is the capital of Bulgaria and what is the size? What it the national anthem?", 0.5, 0.9, 15, 40, - List.of("END"), CohereChatRequest.ReturnLikelihoods.ALL, false, 1, null, Truncate.NONE); - - var request2 = CohereChatRequest - .builder("What is the capital of Bulgaria and what is the size? What it the national anthem?") - .temperature(0.5) - .topP(0.9) - .topK(15) - .maxTokens(40) - .stopSequences(List.of("END")) - .returnLikelihoods(CohereChatRequest.ReturnLikelihoods.ALL) - .stream(false) - .numGenerations(1) - .logitBias(null) - .truncate(Truncate.NONE) - .build(); - - assertThat(request1).isEqualTo(request2); - } - - @Test - @Disabled("Due to model version has reached the end of its life") - public void chatCompletion() { - - var request = CohereChatRequest - .builder("What is the capital of Bulgaria and what is the size? What it the national anthem?") - .stream(false) - .temperature(0.5) - .topP(0.8) - .topK(15) - .maxTokens(100) - .stopSequences(List.of("END")) - .returnLikelihoods(CohereChatRequest.ReturnLikelihoods.ALL) - .numGenerations(3) - .logitBias(null) - .truncate(Truncate.NONE) - .build(); - - CohereChatResponse response = this.cohereChatApi.chatCompletion(request); - - assertThat(response).isNotNull(); - assertThat(response.prompt()).isEqualTo(request.prompt()); - assertThat(response.generations()).hasSize(request.numGenerations()); - assertThat(response.generations().get(0).text()).isNotEmpty(); - } - - @Disabled("Due to model version has reached the end of its life") - @Test - public void chatCompletionStream() { - - var request = CohereChatRequest - .builder("What is the capital of Bulgaria and what is the size? What it the national anthem?") - .stream(true) - .temperature(0.5) - .topP(0.8) - .topK(15) - .maxTokens(100) - .stopSequences(List.of("END")) - .returnLikelihoods(CohereChatRequest.ReturnLikelihoods.ALL) - .numGenerations(3) - .logitBias(null) - .truncate(Truncate.NONE) - .build(); - - Flux responseStream = this.cohereChatApi.chatCompletionStream(request); - List responses = responseStream.collectList().block(); - - assertThat(responses).isNotNull(); - assertThat(responses).hasSizeGreaterThan(10); - assertThat(responses.get(0).text()).isNotEmpty(); - - CohereChatResponse.Generation lastResponse = responses.get(responses.size() - 1); - assertThat(lastResponse.text()).isNull(); - assertThat(lastResponse.isFinished()).isTrue(); - assertThat(lastResponse.finishReason()).isEqualTo(FinishReason.MAX_TOKENS); - assertThat(lastResponse.amazonBedrockInvocationMetrics()).isNotNull(); - } - - @Test - public void testStreamConfigurations() { - var streamRequest = CohereChatRequest - .builder("What is the capital of Bulgaria and what is the size? What it the national anthem?") - .stream(true) - .build(); - - assertThatThrownBy(() -> this.cohereChatApi.chatCompletion(streamRequest)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("The request must be configured to return the complete response!"); - - var notStreamRequest = CohereChatRequest - .builder("What is the capital of Bulgaria and what is the size? What it the national anthem?") - .stream(false) - .build(); - - assertThatThrownBy(() -> this.cohereChatApi.chatCompletionStream(notStreamRequest)) - .isInstanceOf(IllegalArgumentException.class) - .hasMessageContaining("The request must be configured to stream the response!"); - - } - -} diff --git a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/jurassic2/BedrockAi21Jurassic2ChatModelIT.java b/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/jurassic2/BedrockAi21Jurassic2ChatModelIT.java deleted file mode 100644 index d33f3db3fd2..00000000000 --- a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/jurassic2/BedrockAi21Jurassic2ChatModelIT.java +++ /dev/null @@ -1,180 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.jurassic2; - -import java.time.Duration; -import java.util.Arrays; -import java.util.List; -import java.util.Map; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.bedrock.RequiresAwsCredentials; -import org.springframework.ai.bedrock.jurassic2.api.Ai21Jurassic2ChatBedrockApi; -import org.springframework.ai.chat.messages.Message; -import org.springframework.ai.chat.messages.UserMessage; -import org.springframework.ai.chat.model.ChatResponse; -import org.springframework.ai.chat.model.Generation; -import org.springframework.ai.chat.prompt.Prompt; -import org.springframework.ai.chat.prompt.PromptTemplate; -import org.springframework.ai.chat.prompt.SystemPromptTemplate; -import org.springframework.ai.converter.MapOutputConverter; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.SpringBootConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.Bean; -import org.springframework.core.io.Resource; - -import static org.assertj.core.api.Assertions.assertThat; - -@SpringBootTest -@RequiresAwsCredentials -class BedrockAi21Jurassic2ChatModelIT { - - @Autowired - private BedrockAi21Jurassic2ChatModel chatModel; - - @Value("classpath:/prompts/system-message.st") - private Resource systemResource; - - @Test - void roleTest() { - UserMessage userMessage = new UserMessage( - "Tell me about 3 famous pirates from the Golden Age of Piracy and why they did."); - SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(this.systemResource); - Message systemMessage = systemPromptTemplate.createMessage(Map.of("name", "Bob", "voice", "pirate")); - - Prompt prompt = new Prompt(List.of(userMessage, systemMessage)); - - ChatResponse response = this.chatModel.call(prompt); - String content = response.getResult().getOutput().getText(); - - // System.out.println("Response content: " + content); - - assertThat(content).satisfies(text -> { - // Check for name - assertThat(text).contains("Bob"); - - // Check for pirate speech patterns with better error message - assertThat(text).matches( - t -> t.contains("Arrr") || t.contains("matey") || t.contains("ye") || t.contains("yer") - || t.contains("shiver me timbers") || t.contains("scurvy"), - "should contain pirate speech patterns"); - }); - } - - @Test - void testEmojiPenaltyFalse() { - BedrockAi21Jurassic2ChatOptions.Penalty penalty = new BedrockAi21Jurassic2ChatOptions.Penalty.Builder() - .applyToEmojis(false) - .build(); - BedrockAi21Jurassic2ChatOptions options = new BedrockAi21Jurassic2ChatOptions.Builder() - .presencePenaltyOptions(penalty) - .build(); - - UserMessage userMessage = new UserMessage("Can you express happiness using an emoji like 😄 ?"); - Prompt prompt = new Prompt(List.of(userMessage), options); - - ChatResponse response = this.chatModel.call(prompt); - assertThat(response.getResult().getOutput().getText()) - .matches(content -> content.contains("😄") || content.contains(":)")); - - } - - @Test - @Disabled("This test is failing when run in combination with the other tests") - void emojiPenaltyWhenTrueByDefaultApplyPenaltyTest() { - // applyToEmojis is by default true - BedrockAi21Jurassic2ChatOptions.Penalty penalty = new BedrockAi21Jurassic2ChatOptions.Penalty.Builder().build(); - BedrockAi21Jurassic2ChatOptions options = new BedrockAi21Jurassic2ChatOptions.Builder() - .presencePenaltyOptions(penalty) - .build(); - - UserMessage userMessage = new UserMessage("Can you express happiness using an emoji like 😄?"); - SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(this.systemResource); - Message systemMessage = systemPromptTemplate.createMessage(Map.of("name", "Bob", "voice", "pirate")); - - Prompt prompt = new Prompt(List.of(userMessage, systemMessage), options); - - ChatResponse response = this.chatModel.call(prompt); - - assertThat(response.getResult().getOutput().getText()).doesNotContain("😄"); - } - - @Test - void mapOutputConverter() { - MapOutputConverter outputConverter = new MapOutputConverter(); - - String format = outputConverter.getFormat(); - String template = """ - Provide me a List of {subject} - {format} - """; - PromptTemplate promptTemplate = new PromptTemplate(template, - Map.of("subject", "an array of numbers from 1 to 9 under they key name 'numbers'", "format", format)); - Prompt prompt = new Prompt(promptTemplate.createMessage()); - Generation generation = this.chatModel.call(prompt).getResult(); - - Map result = outputConverter.convert(generation.getOutput().getText()); - assertThat(result.get("numbers")).isEqualTo(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9)); - - } - - @Disabled("Jurrasic2 is very unstable") - @Test - void simpleChatResponse() { - UserMessage userMessage = new UserMessage("Tell me a joke about AI."); - SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(this.systemResource); - Message systemMessage = systemPromptTemplate.createMessage(Map.of("name", "Bob", "voice", "pirate")); - - Prompt prompt = new Prompt(List.of(userMessage, systemMessage)); - - ChatResponse response = this.chatModel.call(prompt); - - assertThat(response.getResult().getOutput().getText()).contains("AI"); - } - - @SpringBootConfiguration - public static class TestConfiguration { - - @Bean - public Ai21Jurassic2ChatBedrockApi jurassic2ChatBedrockApi() { - return new Ai21Jurassic2ChatBedrockApi( - Ai21Jurassic2ChatBedrockApi.Ai21Jurassic2ChatModel.AI21_J2_ULTRA_V1.id(), - EnvironmentVariableCredentialsProvider.create(), Region.US_EAST_1.id(), new ObjectMapper(), - Duration.ofMinutes(2)); - } - - @Bean - public BedrockAi21Jurassic2ChatModel bedrockAi21Jurassic2ChatModel( - Ai21Jurassic2ChatBedrockApi jurassic2ChatBedrockApi) { - return new BedrockAi21Jurassic2ChatModel(jurassic2ChatBedrockApi, - BedrockAi21Jurassic2ChatOptions.builder() - .temperature(0.5) - .maxTokens(500) - // .withTopP(0.9) - .build()); - } - - } - -} diff --git a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/jurassic2/api/Ai21Jurassic2ChatBedrockApiIT.java b/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/jurassic2/api/Ai21Jurassic2ChatBedrockApiIT.java deleted file mode 100644 index a1d95eb21d7..00000000000 --- a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/jurassic2/api/Ai21Jurassic2ChatBedrockApiIT.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.jurassic2.api; - -import java.time.Duration; -import java.util.stream.Collectors; - -import org.junit.jupiter.api.Test; -import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.bedrock.RequiresAwsCredentials; -import org.springframework.ai.bedrock.jurassic2.api.Ai21Jurassic2ChatBedrockApi.Ai21Jurassic2ChatModel; -import org.springframework.ai.bedrock.jurassic2.api.Ai21Jurassic2ChatBedrockApi.Ai21Jurassic2ChatRequest; -import org.springframework.ai.bedrock.jurassic2.api.Ai21Jurassic2ChatBedrockApi.Ai21Jurassic2ChatResponse; -import org.springframework.ai.model.ModelOptionsUtils; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Christian Tzolov - */ -@RequiresAwsCredentials -public class Ai21Jurassic2ChatBedrockApiIT { - - Ai21Jurassic2ChatBedrockApi api = new Ai21Jurassic2ChatBedrockApi(Ai21Jurassic2ChatModel.AI21_J2_MID_V1.id(), - EnvironmentVariableCredentialsProvider.create(), Region.US_EAST_1.id(), ModelOptionsUtils.OBJECT_MAPPER, - Duration.ofMinutes(2)); - - @Test - public void chatCompletion() { - Ai21Jurassic2ChatRequest request = new Ai21Jurassic2ChatRequest("Give me the names of 3 famous pirates?", 0.9, - 0.9, 100, null, // List.of("END"), - new Ai21Jurassic2ChatRequest.IntegerScalePenalty(1, true, true, true, true, true), - new Ai21Jurassic2ChatRequest.FloatScalePenalty(0.5f, true, true, true, true, true), - new Ai21Jurassic2ChatRequest.IntegerScalePenalty(1, true, true, true, true, true)); - - Ai21Jurassic2ChatResponse response = this.api.chatCompletion(request); - - assertThat(response).isNotNull(); - assertThat(response.completions()).isNotEmpty(); - assertThat(response.amazonBedrockInvocationMetrics()).isNull(); - - String responseContent = response.completions() - .stream() - .map(c -> c.data().text()) - .collect(Collectors.joining(System.lineSeparator())); - assertThat(responseContent).contains("Blackbeard"); - } - - // Note: Ai21Jurassic2 doesn't support streaming yet! - -} diff --git a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/llama/BedrockLlamaChatModelIT.java b/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/llama/BedrockLlamaChatModelIT.java deleted file mode 100644 index 20e33963c97..00000000000 --- a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/llama/BedrockLlamaChatModelIT.java +++ /dev/null @@ -1,226 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.llama; - -import java.time.Duration; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Test; -import reactor.core.publisher.Flux; -import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.bedrock.RequiresAwsCredentials; -import org.springframework.ai.bedrock.llama.api.LlamaChatBedrockApi; -import org.springframework.ai.bedrock.llama.api.LlamaChatBedrockApi.LlamaChatModel; -import org.springframework.ai.chat.messages.AssistantMessage; -import org.springframework.ai.chat.messages.Message; -import org.springframework.ai.chat.messages.UserMessage; -import org.springframework.ai.chat.model.ChatResponse; -import org.springframework.ai.chat.model.Generation; -import org.springframework.ai.chat.prompt.Prompt; -import org.springframework.ai.chat.prompt.PromptTemplate; -import org.springframework.ai.chat.prompt.SystemPromptTemplate; -import org.springframework.ai.converter.BeanOutputConverter; -import org.springframework.ai.converter.ListOutputConverter; -import org.springframework.ai.converter.MapOutputConverter; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.SpringBootConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.Bean; -import org.springframework.core.convert.support.DefaultConversionService; -import org.springframework.core.io.Resource; - -import static org.assertj.core.api.Assertions.assertThat; - -@SpringBootTest -@RequiresAwsCredentials -class BedrockLlamaChatModelIT { - - @Autowired - private BedrockLlamaChatModel chatModel; - - @Value("classpath:/prompts/system-message.st") - private Resource systemResource; - - @Test - void multipleStreamAttempts() { - - Flux joke2Stream = this.chatModel.stream(new Prompt(new UserMessage("Tell me a Toy joke?"))); - Flux joke1Stream = this.chatModel.stream(new Prompt(new UserMessage("Tell me a joke?"))); - - String joke1 = joke1Stream.collectList() - .block() - .stream() - .map(ChatResponse::getResults) - .flatMap(List::stream) - .map(Generation::getOutput) - .map(AssistantMessage::getText) - .collect(Collectors.joining()); - String joke2 = joke2Stream.collectList() - .block() - .stream() - .map(ChatResponse::getResults) - .flatMap(List::stream) - .map(Generation::getOutput) - .map(AssistantMessage::getText) - .collect(Collectors.joining()); - - assertThat(joke1).isNotBlank(); - assertThat(joke2).isNotBlank(); - } - - @Test - void roleTest() { - String message = """ - Describe 3 of the most feared and legendary pirates from the Golden Age of Piracy, particularly - those known for their intimidating tactics and whose stories influenced popular culture. - """; - UserMessage userMessage = new UserMessage(message); - SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(this.systemResource); - Message systemMessage = systemPromptTemplate.createMessage(Map.of("name", "Bob", "voice", "pirate")); - - Prompt prompt = new Prompt(List.of(userMessage, systemMessage)); - - ChatResponse response = this.chatModel.call(prompt); - assertThat(response.getResult().getOutput().getText()).satisfies(content -> { - // Check for name - assertThat(content).contains("Bob"); - - // Check for pirate speech patterns - should match at least one - assertThat(content).matches(text -> text.contains("Arrr") || text.contains("matey") || text.contains("ye") - || text.contains("yer") || text.contains("shiver me timbers") || text.contains("scurvy")); - }); - } - - @Test - void listOutputConverter() { - DefaultConversionService conversionService = new DefaultConversionService(); - ListOutputConverter outputConverter = new ListOutputConverter(conversionService); - - String format = outputConverter.getFormat(); - String template = """ - List exactly five {subject}, no more and no less. - {format} - """; - PromptTemplate promptTemplate = new PromptTemplate(template, - Map.of("subject", "ice cream flavors.", "format", format)); - Prompt prompt = new Prompt(promptTemplate.createMessage()); - Generation generation = this.chatModel.call(prompt).getResult(); - - List list = outputConverter.convert(generation.getOutput().getText()); - assertThat(list).hasSize(5); - } - - @Test - void mapOutputConverter() { - MapOutputConverter outputConverter = new MapOutputConverter(); - - String format = outputConverter.getFormat(); - String template = """ - Provide me a List of {subject} - {format} - """; - PromptTemplate promptTemplate = new PromptTemplate(template, - Map.of("subject", "an array of numbers from 1 to 9 under they key name 'numbers'", "format", format)); - Prompt prompt = new Prompt(promptTemplate.createMessage()); - Generation generation = this.chatModel.call(prompt).getResult(); - - Map result = outputConverter.convert(generation.getOutput().getText()); - assertThat(result.get("numbers")).isEqualTo(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9)); - - } - - @Test - void beanOutputConverterRecords() { - - BeanOutputConverter outputConverter = new BeanOutputConverter<>(ActorsFilmsRecord.class); - - String format = outputConverter.getFormat(); - String template = """ - Generate the filmography of 5 movies for Tom Hanks. - {format} - Remove non JSON tex blocks from the output. - Provide your answer in the JSON format with the feature names as the keys. - """; - PromptTemplate promptTemplate = new PromptTemplate(template, Map.of("format", format)); - Prompt prompt = new Prompt(promptTemplate.createMessage()); - Generation generation = this.chatModel.call(prompt).getResult(); - - ActorsFilmsRecord actorsFilms = outputConverter.convert(generation.getOutput().getText()); - assertThat(actorsFilms.actor()).isEqualTo("Tom Hanks"); - assertThat(actorsFilms.movies()).hasSize(5); - } - - @Test - void beanStreamOutputConverterRecords() { - - BeanOutputConverter outputConverter = new BeanOutputConverter<>(ActorsFilmsRecord.class); - - String format = outputConverter.getFormat(); - String template = """ - Generate the filmography of 5 movies for Tom Hanks. - {format} - Remove Markdown code blocks from the output. - """; - PromptTemplate promptTemplate = new PromptTemplate(template, Map.of("format", format)); - Prompt prompt = new Prompt(promptTemplate.createMessage()); - - String generationTextFromStream = this.chatModel.stream(prompt) - .collectList() - .block() - .stream() - .map(ChatResponse::getResults) - .flatMap(List::stream) - .map(Generation::getOutput) - .map(AssistantMessage::getText) - .collect(Collectors.joining()); - - ActorsFilmsRecord actorsFilms = outputConverter.convert(generationTextFromStream); - System.out.println(actorsFilms); - assertThat(actorsFilms.actor()).isEqualTo("Tom Hanks"); - assertThat(actorsFilms.movies()).hasSize(5); - } - - record ActorsFilmsRecord(String actor, List movies) { - - } - - @SpringBootConfiguration - public static class TestConfiguration { - - @Bean - public LlamaChatBedrockApi llamaApi() { - return new LlamaChatBedrockApi(LlamaChatModel.LLAMA3_70B_INSTRUCT_V1.id(), - EnvironmentVariableCredentialsProvider.create(), Region.US_EAST_1.id(), new ObjectMapper(), - Duration.ofMinutes(2)); - } - - @Bean - public BedrockLlamaChatModel llamaChatModel(LlamaChatBedrockApi llamaApi) { - return new BedrockLlamaChatModel(llamaApi, - BedrockLlamaChatOptions.builder().temperature(0.5).maxGenLen(100).topP(0.9).build()); - } - - } - -} diff --git a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/llama/BedrockLlamaCreateRequestTests.java b/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/llama/BedrockLlamaCreateRequestTests.java deleted file mode 100644 index 679fcc5f1e1..00000000000 --- a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/llama/BedrockLlamaCreateRequestTests.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.llama; - -import java.time.Duration; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Test; -import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.bedrock.RequiresAwsCredentials; -import org.springframework.ai.bedrock.llama.api.LlamaChatBedrockApi; -import org.springframework.ai.bedrock.llama.api.LlamaChatBedrockApi.LlamaChatModel; -import org.springframework.ai.chat.prompt.Prompt; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Christian Tzolov - * @author Wei Jiang - */ -@RequiresAwsCredentials -public class BedrockLlamaCreateRequestTests { - - private LlamaChatBedrockApi api = new LlamaChatBedrockApi(LlamaChatModel.LLAMA3_70B_INSTRUCT_V1.id(), - EnvironmentVariableCredentialsProvider.create(), Region.US_EAST_1.id(), new ObjectMapper(), - Duration.ofMinutes(2)); - - @Test - public void createRequestWithChatOptions() { - - var client = new BedrockLlamaChatModel(this.api, - BedrockLlamaChatOptions.builder().temperature(66.6).maxGenLen(666).topP(0.66).build()); - - var request = client.createRequest(new Prompt("Test message content")); - - assertThat(request.prompt()).isNotEmpty(); - assertThat(request.temperature()).isEqualTo(66.6); - assertThat(request.topP()).isEqualTo(0.66); - assertThat(request.maxGenLen()).isEqualTo(666); - - request = client.createRequest(new Prompt("Test message content", - BedrockLlamaChatOptions.builder().temperature(99.9).maxGenLen(999).topP(0.99).build())); - - assertThat(request.prompt()).isNotEmpty(); - assertThat(request.temperature()).isEqualTo(99.9); - assertThat(request.topP()).isEqualTo(0.99); - assertThat(request.maxGenLen()).isEqualTo(999); - } - -} diff --git a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/llama/api/LlamaChatBedrockApiIT.java b/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/llama/api/LlamaChatBedrockApiIT.java deleted file mode 100644 index 23367d6bf63..00000000000 --- a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/llama/api/LlamaChatBedrockApiIT.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.llama.api; - -import java.time.Duration; -import java.util.List; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Test; -import reactor.core.publisher.Flux; -import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.bedrock.RequiresAwsCredentials; -import org.springframework.ai.bedrock.llama.api.LlamaChatBedrockApi.LlamaChatModel; -import org.springframework.ai.bedrock.llama.api.LlamaChatBedrockApi.LlamaChatRequest; -import org.springframework.ai.bedrock.llama.api.LlamaChatBedrockApi.LlamaChatResponse; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Christian Tzolov - * @author Wei Jiang - */ -@RequiresAwsCredentials -public class LlamaChatBedrockApiIT { - - private LlamaChatBedrockApi llamaChatApi = new LlamaChatBedrockApi(LlamaChatModel.LLAMA3_70B_INSTRUCT_V1.id(), - EnvironmentVariableCredentialsProvider.create(), Region.US_EAST_1.id(), new ObjectMapper(), - Duration.ofMinutes(2)); - - @Test - public void chatCompletion() { - - LlamaChatRequest request = LlamaChatRequest.builder("Hello, my name is") - .temperature(0.9) - .topP(0.9) - .maxGenLen(20) - .build(); - - LlamaChatResponse response = this.llamaChatApi.chatCompletion(request); - - System.out.println(response.generation()); - assertThat(response).isNotNull(); - assertThat(response.generation()).isNotEmpty(); - assertThat(response.generationTokenCount()).isGreaterThan(10); - assertThat(response.generationTokenCount()).isLessThanOrEqualTo(20); - assertThat(response.stopReason()).isNotNull(); - assertThat(response.amazonBedrockInvocationMetrics()).isNull(); - } - - @Test - public void chatCompletionStream() { - - LlamaChatRequest request = new LlamaChatRequest("Hello, my name is", 0.9, 0.9, 20); - Flux responseStream = this.llamaChatApi.chatCompletionStream(request); - List responses = responseStream.collectList().block(); - - assertThat(responses).isNotNull(); - assertThat(responses).hasSizeGreaterThan(10); - assertThat(responses.get(0).generation()).isNotEmpty(); - - LlamaChatResponse lastResponse = responses.get(responses.size() - 1); - assertThat(lastResponse.stopReason()).isNotNull(); - assertThat(lastResponse.amazonBedrockInvocationMetrics()).isNotNull(); - } - -} diff --git a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/titan/BedrockTitanChatModelCreateRequestTests.java b/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/titan/BedrockTitanChatModelCreateRequestTests.java deleted file mode 100644 index 81c62d70b41..00000000000 --- a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/titan/BedrockTitanChatModelCreateRequestTests.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.titan; - -import java.time.Duration; -import java.util.List; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Test; -import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.bedrock.titan.api.TitanChatBedrockApi; -import org.springframework.ai.bedrock.titan.api.TitanChatBedrockApi.TitanChatModel; -import org.springframework.ai.chat.prompt.Prompt; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Christian Tzolov - */ -public class BedrockTitanChatModelCreateRequestTests { - - private TitanChatBedrockApi api = new TitanChatBedrockApi(TitanChatModel.TITAN_TEXT_EXPRESS_V1.id(), - EnvironmentVariableCredentialsProvider.create(), Region.US_EAST_1.id(), new ObjectMapper(), - Duration.ofMinutes(2)); - - @Test - public void createRequestWithChatOptions() { - - var model = new BedrockTitanChatModel(this.api, - BedrockTitanChatOptions.builder() - .withTemperature(66.6) - .withTopP(0.66) - .withMaxTokenCount(666) - .withStopSequences(List.of("stop1", "stop2")) - .build()); - - var request = model.createRequest(new Prompt("Test message content")); - - assertThat(request.inputText()).isNotEmpty(); - assertThat(request.textGenerationConfig().temperature()).isEqualTo(66.6); - assertThat(request.textGenerationConfig().topP()).isEqualTo(0.66); - assertThat(request.textGenerationConfig().maxTokenCount()).isEqualTo(666); - assertThat(request.textGenerationConfig().stopSequences()).containsExactly("stop1", "stop2"); - - request = model.createRequest(new Prompt("Test message content", - BedrockTitanChatOptions.builder() - .withTemperature(99.9) - .withTopP(0.99) - .withMaxTokenCount(999) - .withStopSequences(List.of("stop3", "stop4")) - .build() - - )); - - assertThat(request.inputText()).isNotEmpty(); - assertThat(request.textGenerationConfig().temperature()).isEqualTo(99.9); - assertThat(request.textGenerationConfig().topP()).isEqualTo(0.99); - assertThat(request.textGenerationConfig().maxTokenCount()).isEqualTo(999); - assertThat(request.textGenerationConfig().stopSequences()).containsExactly("stop3", "stop4"); - } - -} diff --git a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/titan/BedrockTitanChatModelIT.java b/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/titan/BedrockTitanChatModelIT.java deleted file mode 100644 index 98c8152b428..00000000000 --- a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/titan/BedrockTitanChatModelIT.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.titan; - -import java.time.Duration; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.junit.jupiter.api.Disabled; -import org.junit.jupiter.api.Test; -import reactor.core.publisher.Flux; -import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.bedrock.RequiresAwsCredentials; -import org.springframework.ai.bedrock.titan.api.TitanChatBedrockApi; -import org.springframework.ai.bedrock.titan.api.TitanChatBedrockApi.TitanChatModel; -import org.springframework.ai.chat.messages.AssistantMessage; -import org.springframework.ai.chat.messages.Message; -import org.springframework.ai.chat.messages.UserMessage; -import org.springframework.ai.chat.model.ChatResponse; -import org.springframework.ai.chat.model.Generation; -import org.springframework.ai.chat.prompt.Prompt; -import org.springframework.ai.chat.prompt.PromptTemplate; -import org.springframework.ai.chat.prompt.SystemPromptTemplate; -import org.springframework.ai.converter.BeanOutputConverter; -import org.springframework.ai.converter.ListOutputConverter; -import org.springframework.ai.converter.MapOutputConverter; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.boot.SpringBootConfiguration; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.context.annotation.Bean; -import org.springframework.core.convert.support.DefaultConversionService; -import org.springframework.core.io.Resource; - -import static org.assertj.core.api.Assertions.assertThat; - -@SpringBootTest -@RequiresAwsCredentials -class BedrockTitanChatModelIT { - - @Autowired - private BedrockTitanChatModel chatModel; - - @Value("classpath:/prompts/system-message.st") - private Resource systemResource; - - @Test - void multipleStreamAttempts() { - - Flux joke1Stream = this.chatModel.stream(new Prompt(new UserMessage("Tell me a joke?"))); - Flux joke2Stream = this.chatModel.stream(new Prompt(new UserMessage("Tell me a toy joke?"))); - - String joke1 = joke1Stream.collectList() - .block() - .stream() - .map(ChatResponse::getResults) - .flatMap(List::stream) - .map(Generation::getOutput) - .map(AssistantMessage::getText) - .collect(Collectors.joining()); - String joke2 = joke2Stream.collectList() - .block() - .stream() - .map(ChatResponse::getResults) - .flatMap(List::stream) - .map(Generation::getOutput) - .map(AssistantMessage::getText) - .collect(Collectors.joining()); - - assertThat(joke1).isNotBlank(); - assertThat(joke2).isNotBlank(); - } - - @Test - void roleTest() { - String request = "Tell me about 3 famous pirates from the Golden Age of Piracy and why they did."; - String name = "Bob"; - String voice = "pirate"; - UserMessage userMessage = new UserMessage(request); - SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(this.systemResource); - Message systemMessage = systemPromptTemplate.createMessage(Map.of("name", name, "voice", voice)); - Prompt prompt = new Prompt(List.of(userMessage, systemMessage)); - ChatResponse response = this.chatModel.call(prompt); - assertThat(response.getResult().getOutput().getText()).contains("Blackbeard"); - } - - @Test - void listOutputConverter() { - DefaultConversionService conversionService = new DefaultConversionService(); - ListOutputConverter outputConverter = new ListOutputConverter(conversionService); - - String format = outputConverter.getFormat(); - String template = """ - List five {subject} - {format} - """; - PromptTemplate promptTemplate = new PromptTemplate(template, - Map.of("subject", "ice cream flavors.", "format", format)); - Prompt prompt = new Prompt(promptTemplate.createMessage()); - Generation generation = this.chatModel.call(prompt).getResult(); - - List list = outputConverter.convert(generation.getOutput().getText()); - assertThat(list).hasSize(5); - } - - @Test - void mapOutputConverter() { - MapOutputConverter outputConverter = new MapOutputConverter(); - - String format = outputConverter.getFormat(); - String template = """ - Remove Markdown code blocks from the output. - Provide me a List of {subject} - {format} - """; - PromptTemplate promptTemplate = new PromptTemplate(template, - Map.of("subject", "an array of numbers from 1 to 9 under they key name 'numbers'", "format", format)); - Prompt prompt = new Prompt(promptTemplate.createMessage()); - - Generation generation = this.chatModel.call(prompt).getResult(); - - Map result = outputConverter.convert(generation.getOutput().getText()); - assertThat(result.get("numbers")).isEqualTo(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8, 9)); - - } - - @Disabled("TODO: Fix the converter instructions to return the correct format") - @Test - void beanOutputConverterRecords() { - - BeanOutputConverter outputConverter = new BeanOutputConverter<>(ActorsFilmsRecord.class); - - String format = outputConverter.getFormat(); - String template = """ - Generate the filmography of 5 movies for Tom Hanks. - {format} - Remove Markdown code blocks from the output. - """; - PromptTemplate promptTemplate = new PromptTemplate(template, Map.of("format", format)); - Prompt prompt = new Prompt(promptTemplate.createMessage()); - Generation generation = this.chatModel.call(prompt).getResult(); - - ActorsFilmsRecord actorsFilms = outputConverter.convert(generation.getOutput().getText()); - assertThat(actorsFilms.actor()).isEqualTo("Tom Hanks"); - assertThat(actorsFilms.movies()).hasSize(5); - } - - @Disabled("TODO: Fix the converter instructions to return the correct format") - @Test - void beanStreamOutputConverterRecords() { - - BeanOutputConverter outputConverter = new BeanOutputConverter<>(ActorsFilmsRecord.class); - - String format = outputConverter.getFormat(); - String template = """ - Generate the filmography of 5 movies for Tom Hanks. - {format} - Remove Markdown code blocks from the output. - """; - PromptTemplate promptTemplate = new PromptTemplate(template, Map.of("format", format)); - Prompt prompt = new Prompt(promptTemplate.createMessage()); - - String generationTextFromStream = this.chatModel.stream(prompt) - .collectList() - .block() - .stream() - .map(ChatResponse::getResults) - .flatMap(List::stream) - .map(Generation::getOutput) - .map(AssistantMessage::getText) - .collect(Collectors.joining()); - - ActorsFilmsRecord actorsFilms = outputConverter.convert(generationTextFromStream); - System.out.println(actorsFilms); - assertThat(actorsFilms.actor()).isEqualTo("Tom Hanks"); - assertThat(actorsFilms.movies()).hasSize(5); - } - - @SpringBootConfiguration - public static class TestConfiguration { - - @Bean - public TitanChatBedrockApi titanApi() { - return new TitanChatBedrockApi(TitanChatModel.TITAN_TEXT_PREMIER_V1.id(), - EnvironmentVariableCredentialsProvider.create(), Region.US_EAST_1.id(), new ObjectMapper(), - Duration.ofMinutes(2)); - } - - @Bean - public BedrockTitanChatModel titanChatModel(TitanChatBedrockApi titanApi) { - return new BedrockTitanChatModel(titanApi); - } - - } - - record ActorsFilmsRecord(String actor, List movies) { - } - -} diff --git a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/titan/api/TitanChatBedrockApiIT.java b/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/titan/api/TitanChatBedrockApiIT.java deleted file mode 100644 index 5ce71a7ff5c..00000000000 --- a/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/titan/api/TitanChatBedrockApiIT.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.bedrock.titan.api; - -import java.time.Duration; -import java.util.List; -import java.util.stream.Collectors; - -import org.junit.jupiter.api.Test; -import reactor.core.publisher.Flux; -import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.bedrock.RequiresAwsCredentials; -import org.springframework.ai.bedrock.titan.api.TitanChatBedrockApi.TitanChatModel; -import org.springframework.ai.bedrock.titan.api.TitanChatBedrockApi.TitanChatRequest; -import org.springframework.ai.bedrock.titan.api.TitanChatBedrockApi.TitanChatResponse; -import org.springframework.ai.bedrock.titan.api.TitanChatBedrockApi.TitanChatResponseChunk; -import org.springframework.ai.model.ModelOptionsUtils; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Christian Tzolov - */ -@RequiresAwsCredentials -public class TitanChatBedrockApiIT { - - TitanChatBedrockApi titanBedrockApi = new TitanChatBedrockApi(TitanChatModel.TITAN_TEXT_EXPRESS_V1.id(), - EnvironmentVariableCredentialsProvider.create(), Region.US_EAST_1.id(), ModelOptionsUtils.OBJECT_MAPPER, - Duration.ofMinutes(2)); - - TitanChatRequest titanChatRequest = TitanChatRequest.builder("Give me the names of 3 famous pirates?") - .temperature(0.5) - .topP(0.9) - .maxTokenCount(100) - .stopSequences(List.of("|")) - .build(); - - @Test - public void chatCompletion() { - TitanChatResponse response = this.titanBedrockApi.chatCompletion(this.titanChatRequest); - assertThat(response.results()).hasSize(1); - assertThat(response.results().get(0).outputText()).contains("Blackbeard"); - } - - @Test - public void chatCompletionStream() { - Flux response = this.titanBedrockApi.chatCompletionStream(this.titanChatRequest); - List results = response.collectList().block(); - - String combinedResponse = results.stream() - .map(TitanChatResponseChunk::outputText) - .collect(Collectors.joining(System.lineSeparator())); - - assertThat(combinedResponse) - .matches(text -> text.contains("Teach") || text.contains("Blackbeard") || text.contains("Roberts") - || text.contains("Rackham") || text.contains("Morgan") || text.contains("Kidd")); - } - -} diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/nav.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/nav.adoc index 71242652d57..685951457d1 100644 --- a/spring-ai-docs/src/main/antora/modules/ROOT/nav.adoc +++ b/spring-ai-docs/src/main/antora/modules/ROOT/nav.adoc @@ -7,13 +7,6 @@ ** xref:api/chatmodel.adoc[Chat Models] *** xref:api/chat/comparison.adoc[Chat Models Comparison] *** xref:api/chat/bedrock-converse.adoc[Amazon Bedrock Converse] -*** xref:api/bedrock-chat.adoc[Amazon Bedrock] -**** xref:api/chat/bedrock/bedrock-anthropic3.adoc[Anthropic3] -**** xref:api/chat/bedrock/bedrock-anthropic.adoc[Anthropic2] -**** xref:api/chat/bedrock/bedrock-llama.adoc[Llama] -**** xref:api/chat/bedrock/bedrock-cohere.adoc[Cohere] -**** xref:api/chat/bedrock/bedrock-titan.adoc[Titan] -**** xref:api/chat/bedrock/bedrock-jurassic2.adoc[Jurassic2] *** xref:api/chat/anthropic-chat.adoc[Anthropic 3] **** xref:api/chat/functions/anthropic-chat-functions.adoc[Anthropic Function Calling] *** xref:api/chat/azure-openai-chat.adoc[Azure OpenAI] diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/bedrock.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/bedrock.adoc index f2aa97eadec..03d332a8ac4 100644 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/bedrock.adoc +++ b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/bedrock.adoc @@ -2,8 +2,8 @@ [NOTE] ==== -Following the Bedrock recommendations, Spring AI is transitioning to using Amazon Bedrock's Converse API for all Chat conversation implementations in Spring AI. -While the existing `InvokeModel API` supports conversation applications, we strongly recommend adopting the xref:api/chat/bedrock-converse.adoc[Bedrock Converse API] for several key benefits: +Following the Bedrock recommendations, Spring AI transitioned to using Amazon Bedrock's Converse API for all Chat conversation implementations in Spring AI. +The xref:api/chat/bedrock-converse.adoc[Bedrock Converse API] has the following key benefits: - Unified Interface: Write your code once and use it with any supported Amazon Bedrock model - Model Flexibility: Seamlessly switch between different conversation models without code changes @@ -18,7 +18,7 @@ The Converse API does not support embedding operations, so these will remain in link:https://docs.aws.amazon.com/bedrock/latest/userguide/what-is-bedrock.html[Amazon Bedrock] is a managed service that provides foundation models from various AI providers, available through a unified API. -Spring AI supports https://docs.aws.amazon.com/bedrock/latest/userguide/model-ids-arns.html[all the Chat and Embedding AI models] available through Amazon Bedrock by implementing the Spring interfaces `ChatModel`, `StreamingChatModel`, and `EmbeddingModel`. +Spring AI supports https://docs.aws.amazon.com/bedrock/latest/userguide/model-ids-arns.html[the Embedding AI models] available through Amazon Bedrock by implementing the Spring `EmbeddingModel` interface. Additionally, Spring AI provides Spring Auto-Configurations and Boot Starters for all clients, making it easy to bootstrap and configure for the Bedrock models. @@ -93,34 +93,22 @@ NOTE: For example, using Spring-AI and https://spring.io/projects/spring-cloud-a === Enable selected Bedrock model -NOTE: By default, all models are disabled. You have to enable the chosen Bedrock models explicitly using the `spring.ai.bedrock...enabled=true` property. +NOTE: By default, all models are disabled. You have to enable the chosen Bedrock models explicitly using the `spring.ai.bedrock..embedding.enabled=true` property. -Here are the supported `` and `` combinations: +Here are the supported ``s: [cols="|,|,|,|"] |==== -| Model | Chat | Chat Streaming | Embedding - -| llama | Yes | Yes | No -| jurassic2 | Yes | No | No -| cohere | Yes | Yes | Yes -| anthropic 2 | Yes | Yes | No -| anthropic 3 | Yes | Yes | No -| jurassic2 (WIP) | Yes | No | No -| titan | Yes | Yes | Yes (however, no batch support) +| Model +| cohere +| titan (no batch support yet) |==== -For example, to enable the Bedrock Llama chat model, you need to set `spring.ai.bedrock.llama.chat.enabled=true`. +For example, to enable the Bedrock Cohere embedding model, you need to set `spring.ai.bedrock.cohere.embedding.enabled=true`. -Next, you can use the `spring.ai.bedrock...*` properties to configure each model as provided. +Next, you can use the `spring.ai.bedrock..embedding.*` properties to configure each model as provided. For more information, refer to the documentation below for each supported model. -* xref:api/chat/bedrock/bedrock-anthropic.adoc[Spring AI Bedrock Anthropic 2 Chat]: `spring.ai.bedrock.anthropic.chat.enabled=true` -* xref:api/chat/bedrock/bedrock-anthropic3.adoc[Spring AI Bedrock Anthropic 3 Chat]: `spring.ai.bedrock.anthropic3.chat.enabled=true` -* xref:api/chat/bedrock/bedrock-llama.adoc[Spring AI Bedrock Llama Chat]: `spring.ai.bedrock.llama.chat.enabled=true` -* xref:api/chat/bedrock/bedrock-cohere.adoc[Spring AI Bedrock Cohere Chat]: `spring.ai.bedrock.cohere.chat.enabled=true` * xref:api/embeddings/bedrock-cohere-embedding.adoc[Spring AI Bedrock Cohere Embeddings]: `spring.ai.bedrock.cohere.embedding.enabled=true` -* xref:api/chat/bedrock/bedrock-titan.adoc[Spring AI Bedrock Titan Chat]: `spring.ai.bedrock.titan.chat.enabled=true` * xref:api/embeddings/bedrock-titan-embedding.adoc[Spring AI Bedrock Titan Embeddings]: `spring.ai.bedrock.titan.embedding.enabled=true` -* xref:api/chat/bedrock/bedrock-jurassic2.adoc[Spring AI Bedrock Ai21 Jurassic2 Chat]: `spring.ai.bedrock.jurassic2.chat.enabled=true` diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/anthropic-chat.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/anthropic-chat.adoc index 340b1ba30a2..186762f1144 100644 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/anthropic-chat.adoc +++ b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/anthropic-chat.adoc @@ -5,8 +5,8 @@ For developers and businesses, you can leverage the API access and build directl Spring AI supports the Anthropic link:https://docs.anthropic.com/claude/reference/messages_post[Messaging API] for sync and streaming text generations. -TIP: Anthropic’s Claude models are also available through Amazon Bedrock. -Spring AI provides dedicated xref:api/chat/bedrock/bedrock-anthropic.adoc[Amazon Bedrock Anthropic] client implementations as well. +TIP: Anthropic’s Claude models are also available through Amazon Bedrock Converse. +Spring AI provides dedicated xref:api/chat/bedrock-converse.adoc[Amazon Bedrock Converse Anthropic] client implementations as well. == Prerequisites diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock/bedrock-anthropic.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock/bedrock-anthropic.adoc deleted file mode 100644 index 56389f71f2f..00000000000 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock/bedrock-anthropic.adoc +++ /dev/null @@ -1,267 +0,0 @@ -= Bedrock Anthropic 2 Chat - -[NOTE] -==== -Following the Bedrock recommendations, Spring AI is transitioning to using Amazon Bedrock's Converse API for all chat conversation implementations in Spring AI. -While the existing `InvokeModel API` supports conversation applications, we strongly recommend adopting the xref:api/chat/bedrock-converse.adoc[Bedrock Converse API] for several key benefits: - -- Unified Interface: Write your code once and use it with any supported Amazon Bedrock model -- Model Flexibility: Seamlessly switch between different conversation models without code changes -- Extended Functionality: Support for model-specific parameters through dedicated structures -- Tool Support: Native integration with function calling and tool usage capabilities -- Multimodal Capabilities: Built-in support for vision and other multimodal features -- Future-Proof: Aligned with Amazon Bedrock's recommended best practices -==== - -NOTE: The Anthropic 2 Chat API is deprecated and replaced by the new Anthropic Claude 3 Message API. -Please use the xref:api/chat/bedrock/bedrock-anthropic3.adoc[Anthropic Claude 3 Message API] for new projects. - -https://www.anthropic.com/product[Anthropic's Claude] is an AI assistant based on Anthropic’s research into training helpful, honest, and harmless AI systems. -The Claude model has the following high level features - -* 200k Token Context Window: Claude boasts a generous token capacity of 200,000, making it ideal for handling extensive information in applications like technical documentation, codebase, and literary works. -* Supported Tasks: Claude's versatility spans tasks such as summarization, Q&A, trend forecasting, and document comparisons, enabling a wide range of applications from dialogues to content generation. -* AI Safety Features: Built on Anthropic's safety research, Claude prioritizes helpfulness, honesty, and harmlessness in its interactions, reducing brand risk and ensuring responsible AI behavior. - -The https://aws.amazon.com/bedrock/claude[AWS Bedrock Anthropic Model Page] and https://docs.aws.amazon.com/bedrock/latest/userguide/what-is-bedrock.html[Amazon Bedrock User Guide] contains detailed information on how to use the AWS hosted model. - -TIP: Anthropic’s Claude 2 and 3 models are also available directly on the Anthropic's own cloud platform. -Spring AI provides dedicated xref:api/chat/anthropic-chat.adoc[Anthropic Claude] client to access it. - -== Prerequisites - -Refer to the xref:api/bedrock.adoc[Spring AI documentation on Amazon Bedrock] for setting up API access. - -=== Add Repositories and BOM - -Spring AI artifacts are published in Spring Milestone and Snapshot repositories. Refer to the xref:getting-started.adoc#repositories[Repositories] section to add these repositories to your build system. - -To help with dependency management, Spring AI provides a BOM (bill of materials) to ensure that a consistent version of Spring AI is used throughout the entire project. Refer to the xref:getting-started.adoc#dependency-management[Dependency Management] section to add the Spring AI BOM to your build system. - - -== Auto-configuration - -Add the `spring-ai-bedrock-ai-spring-boot-starter` dependency to your project's Maven `pom.xml` file: - -[source,xml] ----- - - org.springframework.ai - spring-ai-bedrock-ai-spring-boot-starter - ----- - -or to your Gradle `build.gradle` build file. - -[source,gradle] ----- -dependencies { - implementation 'org.springframework.ai:spring-ai-bedrock-ai-spring-boot-starter' -} ----- - -TIP: Refer to the xref:getting-started.adoc#dependency-management[Dependency Management] section to add the Spring AI BOM to your build file. - -=== Enable Anthropic Chat - -By default the Anthropic model is disabled. -To enable it set the `spring.ai.bedrock.anthropic.chat.enabled` property to `true`. -Exporting environment variable is one way to set this configuration property: - -[source,shell] ----- -export SPRING_AI_BEDROCK_ANTHROPIC_CHAT_ENABLED=true ----- - -=== Chat Properties - -The prefix `spring.ai.bedrock.aws` is the property prefix to configure the connection to AWS Bedrock. - -[cols="3,3,1"] -|==== -| Property | Description | Default - -| spring.ai.bedrock.aws.region | AWS region to use. | us-east-1 -| spring.ai.bedrock.aws.timeout | AWS timeout to use. | 5m -| spring.ai.bedrock.aws.access-key | AWS access key. | - -| spring.ai.bedrock.aws.secret-key | AWS secret key. | - -|==== - -The prefix `spring.ai.bedrock.anthropic.chat` is the property prefix that configures the chat model implementation for Claude. - -[cols="2,5,1"] -|==== -| Property | Description | Default - -| spring.ai.bedrock.anthropic.chat.enabled | Enable Bedrock Anthropic chat model. Disabled by default | false -| spring.ai.bedrock.anthropic.chat.model | The model id to use. See the https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/api/AnthropicChatBedrockApi.java[AnthropicChatModel] for the supported models. | anthropic.claude-v2 -| spring.ai.bedrock.anthropic.chat.options.temperature | Controls the randomness of the output. Values can range over [0.0,1.0] | 0.8 -| spring.ai.bedrock.anthropic.chat.options.topP | The maximum cumulative probability of tokens to consider when sampling. | AWS Bedrock default -| spring.ai.bedrock.anthropic.chat.options.topK | Specify the number of token choices the generative uses to generate the next token. | AWS Bedrock default -| spring.ai.bedrock.anthropic.chat.options.stopSequences | Configure up to four sequences that the generative recognizes. After a stop sequence, the generative stops generating further tokens. The returned text doesn't contain the stop sequence. | 10 -| spring.ai.bedrock.anthropic.chat.options.anthropicVersion | The version of the generative to use. | bedrock-2023-05-31 -| spring.ai.bedrock.anthropic.chat.options.maxTokensToSample | Specify the maximum number of tokens to use in the generated response. Note that the models may stop before reaching this maximum. This parameter only specifies the absolute maximum number of tokens to generate. We recommend a limit of 4,000 tokens for optimal performance. | 500 -|==== - -Look at the https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/api/AnthropicChatBedrockApi.java[AnthropicChatModel] for other model IDs. -Supported values are: `anthropic.claude-instant-v1`, `anthropic.claude-v2` and `anthropic.claude-v2:1`. -Model ID values can also be found in the https://docs.aws.amazon.com/bedrock/latest/userguide/model-ids-arns.html[AWS Bedrock documentation for base model IDs]. - -TIP: All properties prefixed with `spring.ai.bedrock.anthropic.chat.options` can be overridden at runtime by adding a request specific <> to the `Prompt` call. - -== Runtime Options [[chat-options]] - -The https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/AnthropicChatOptions.java[AnthropicChatOptions.java] provides model configurations, such as temperature, topK, topP, etc. - -On start-up, the default options can be configured with the `BedrockAnthropicChatModel(api, options)` constructor or the `spring.ai.bedrock.anthropic.chat.options.*` properties. - -At run-time you can override the default options by adding new, request specific, options to the `Prompt` call. -For example to override the default temperature for a specific request: - -[source,java] ----- -ChatResponse response = chatModel.call( - new Prompt( - "Generate the names of 5 famous pirates.", - AnthropicChatOptions.builder() - .temperature(0.4) - .build() - )); ----- - -TIP: In addition to the model specific https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/AnthropicChatOptions.java[AnthropicChatOptions] you can use a portable https://github.com/spring-projects/spring-ai/blob/main/spring-ai-core/src/main/java/org/springframework/ai/chat/prompt/ChatOptions.java[ChatOptions] instance, created with the https://github.com/spring-projects/spring-ai/blob/main/spring-ai-core/src/main/java/org/springframework/ai/chat/prompt/ChatOptionsBuilder.java[ChatOptionsBuilder#builder()]. - -== Sample Controller - -https://start.spring.io/[Create] a new Spring Boot project and add the `spring-ai-bedrock-ai-spring-boot-starter` to your pom (or gradle) dependencies. - -Add a `application.properties` file, under the `src/main/resources` directory, to enable and configure the Anthropic chat model: - -[source] ----- -spring.ai.bedrock.aws.region=eu-central-1 -spring.ai.bedrock.aws.timeout=1000ms -spring.ai.bedrock.aws.access-key=${AWS_ACCESS_KEY_ID} -spring.ai.bedrock.aws.secret-key=${AWS_SECRET_ACCESS_KEY} - -spring.ai.bedrock.anthropic.chat.enabled=true -spring.ai.bedrock.anthropic.chat.options.temperature=0.8 -spring.ai.bedrock.anthropic.chat.options.top-k=15 ----- - -TIP: replace the `regions`, `access-key` and `secret-key` with your AWS credentials. - -This will create a `BedrockAnthropicChatModel` implementation that you can inject into your class. -Here is an example of a simple `@Controller` class that uses the chat model for text generations. - -[source,java] ----- -@RestController -public class ChatController { - - private final BedrockAnthropicChatModel chatModel; - - @Autowired - public ChatController(BedrockAnthropicChatModel chatModel) { - this.chatModel = chatModel; - } - - @GetMapping("/ai/generate") - public Map generate(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) { - return Map.of("generation", this.chatModel.call(message)); - } - - @GetMapping("/ai/generateStream") - public Flux generateStream(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) { - Prompt prompt = new Prompt(new UserMessage(message)); - return this.chatModel.stream(prompt); - } -} ----- - -== Manual Configuration - -The https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/BedrockAnthropicChatModel.java[BedrockAnthropicChatModel] implements the `ChatModel` and `StreamingChatModel` and uses the <> to connect to the Bedrock Anthropic service. - -Add the `spring-ai-bedrock` dependency to your project's Maven `pom.xml` file: - -[source,xml] ----- - - org.springframework.ai - spring-ai-bedrock - ----- - -or to your Gradle `build.gradle` build file. - -[source,gradle] ----- -dependencies { - implementation 'org.springframework.ai:spring-ai-bedrock' -} ----- - -TIP: Refer to the xref:getting-started.adoc#dependency-management[Dependency Management] section to add the Spring AI BOM to your build file. - -Next, create an https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/BedrockAnthropicChatModel.java[BedrockAnthropicChatModel] and use it for text generations: - -[source,java] ----- -AnthropicChatBedrockApi anthropicApi = new AnthropicChatBedrockApi( - AnthropicChatBedrockApi.AnthropicModel.CLAUDE_V2.id(), - EnvironmentVariableCredentialsProvider.create(), - Region.US_EAST_1.id(), - new ObjectMapper(), - Duration.ofMillis(1000L)); - -BedrockAnthropicChatModel chatModel = new BedrockAnthropicChatModel(this.anthropicApi, - AnthropicChatOptions.builder() - .temperature(0.6) - .topK(10) - .topP(0.8) - .maxTokensToSample(100) - .anthropicVersion(AnthropicChatBedrockApi.DEFAULT_ANTHROPIC_VERSION) - .build()); - -ChatResponse response = this.chatModel.call( - new Prompt("Generate the names of 5 famous pirates.")); - -// Or with streaming responses -Flux response = this.chatModel.stream( - new Prompt("Generate the names of 5 famous pirates.")); ----- - -=== Low-level AnthropicChatBedrockApi Client [[low-level-api]] - -The https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/api/AnthropicChatBedrockApi.java[AnthropicChatBedrockApi] provides is lightweight Java client on top of AWS Bedrock link:https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-claude.html[Anthropic Claude models]. - -Following class diagram illustrates the AnthropicChatBedrockApi interface and building blocks: - -image::bedrock/bedrock-anthropic-chat-api.png[AnthropicChatBedrockApi Class Diagram] - -Client supports the `anthropic.claude-instant-v1`, `anthropic.claude-v2` and `anthropic.claude-v2:1` models for both synchronous (e.g. `chatCompletion()`) and streaming (e.g. `chatCompletionStream()`) responses. - -Here is a simple snippet how to use the api programmatically: - -[source,java] ----- -AnthropicChatBedrockApi anthropicChatApi = new AnthropicChatBedrockApi( - AnthropicModel.CLAUDE_V2.id(), Region.US_EAST_1.id(), Duration.ofMillis(1000L)); - -AnthropicChatRequest request = AnthropicChatRequest - .builder(String.format(AnthropicChatBedrockApi.PROMPT_TEMPLATE, "Name 3 famous pirates")) - .temperature(0.8) - .maxTokensToSample(300) - .topK(10) - .build(); - -// Sync request -AnthropicChatResponse response = this.anthropicChatApi.chatCompletion(this.request); - -// Streaming request -Flux responseStream = this.anthropicChatApi.chatCompletionStream(this.request); -List responses = this.responseStream.collectList().block(); ----- - -Follow the https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/api/AnthropicChatBedrockApi.java[AnthropicChatBedrockApi.java]'s JavaDoc for further information. diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock/bedrock-anthropic3.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock/bedrock-anthropic3.adoc deleted file mode 100644 index e8a4ed0cb06..00000000000 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock/bedrock-anthropic3.adoc +++ /dev/null @@ -1,304 +0,0 @@ -= Bedrock Anthropic 3 - -[NOTE] -==== -Following the Bedrock recommendations, Spring AI is transitioning to using Amazon Bedrock's Converse API for all chat conversation implementations in Spring AI. -While the existing `InvokeModel API` supports conversation applications, we strongly recommend adopting the xref:api/chat/bedrock-converse.adoc[Bedrock Converse API] for several key benefits: - -- Unified Interface: Write your code once and use it with any supported Amazon Bedrock model -- Model Flexibility: Seamlessly switch between different conversation models without code changes -- Extended Functionality: Support for model-specific parameters through dedicated structures -- Tool Support: Native integration with function calling and tool usage capabilities -- Multimodal Capabilities: Built-in support for vision and other multimodal features -- Future-Proof: Aligned with Amazon Bedrock's recommended best practices -==== - -link:https://www.anthropic.com/[Anthropic Claude] is a family of foundational AI models that can be used in a variety of applications. - -The Claude model has the following high level features - -* 200k Token Context Window: Claude boasts a generous token capacity of 200,000, making it ideal for handling extensive information in applications like technical documentation, codebase, and literary works. -* Supported Tasks: Claude's versatility spans tasks such as summarization, Q&A, trend forecasting, and document comparisons, enabling a wide range of applications from dialogues to content generation. -* AI Safety Features: Built on Anthropic's safety research, Claude prioritizes helpfulness, honesty, and harmlessness in its interactions, reducing brand risk and ensuring responsible AI behavior. - -The https://aws.amazon.com/bedrock/claude[AWS Bedrock Anthropic Model Page] and https://docs.aws.amazon.com/bedrock/latest/userguide/what-is-bedrock.html[Amazon Bedrock User Guide] contains detailed information on how to use the AWS hosted model. - -TIP: Anthropic’s Claude 2 and 3 models are also available directly on the Anthropic's own cloud platform. -Spring AI provides dedicated xref:api/chat/anthropic-chat.adoc[Anthropic Claude] client to access it. - -== Prerequisites - -Refer to the xref:api/bedrock.adoc[Spring AI documentation on Amazon Bedrock] for setting up API access. - -=== Add Repositories and BOM - -Spring AI artifacts are published in Spring Milestone and Snapshot repositories. Refer to the xref:getting-started.adoc#repositories[Repositories] section to add these repositories to your build system. - -To help with dependency management, Spring AI provides a BOM (bill of materials) to ensure that a consistent version of Spring AI is used throughout the entire project. Refer to the xref:getting-started.adoc#dependency-management[Dependency Management] section to add the Spring AI BOM to your build system. - -== Auto-configuration - -Add the `spring-ai-bedrock-ai-spring-boot-starter` dependency to your project's Maven `pom.xml` file: - -[source,xml] ----- - - org.springframework.ai - spring-ai-bedrock-ai-spring-boot-starter - ----- - -or to your Gradle `build.gradle` build file. - -[source,gradle] ----- -dependencies { - implementation 'org.springframework.ai:spring-ai-bedrock-ai-spring-boot-starter' -} ----- - -TIP: Refer to the xref:getting-started.adoc#dependency-management[Dependency Management] section to add the Spring AI BOM to your build file. - -=== Enable Anthropic Chat - -By default the Anthropic model is disabled. -To enable it set the `spring.ai.bedrock.anthropic3.chat.enabled` property to `true`. -Exporting environment variable is one way to set this configuration property: - -[source,shell] ----- -export SPRING_AI_BEDROCK_ANTHROPIC3_CHAT_ENABLED=true ----- - -=== Chat Properties - -The prefix `spring.ai.bedrock.aws` is the property prefix to configure the connection to AWS Bedrock. - -[cols="3,3,1"] -|==== -| Property | Description | Default - -| spring.ai.bedrock.aws.region | AWS region to use. | us-east-1 -| spring.ai.bedrock.aws.timeout | AWS timeout to use. | 5m -| spring.ai.bedrock.aws.access-key | AWS access key. | - -| spring.ai.bedrock.aws.secret-key | AWS secret key. | - -|==== - -The prefix `spring.ai.bedrock.anthropic3.chat` is the property prefix that configures the chat model implementation for Claude. - -[cols="2,5,1"] -|==== -| Property | Description | Default - -| spring.ai.bedrock.anthropic3.chat.enabled | Enable Bedrock Anthropic chat model. Disabled by default | false -| spring.ai.bedrock.anthropic3.chat.model | The model id to use. Supports the `anthropic.claude-3-sonnet-20240229-v1:0`,`anthropic.claude-3-haiku-20240307-v1:0` and the legacy `anthropic.claude-v2`, `anthropic.claude-v2:1` and `anthropic.claude-instant-v1` models for both synchronous and streaming responses. | `anthropic.claude-3-sonnet-20240229-v1:0` -| spring.ai.bedrock.anthropic3.chat.options.temperature | Controls the randomness of the output. Values can range over [0.0,1.0] | 0.8 -| spring.ai.bedrock.anthropic3.chat.options.top-p | The maximum cumulative probability of tokens to consider when sampling. | AWS Bedrock default -| spring.ai.bedrock.anthropic3.chat.options.top-k | Specify the number of token choices the generative uses to generate the next token. | AWS Bedrock default -| spring.ai.bedrock.anthropic3.chat.options.stop-sequences | Configure up to four sequences that the generative recognizes. After a stop sequence, the generative stops generating further tokens. The returned text doesn't contain the stop sequence. | 10 -| spring.ai.bedrock.anthropic3.chat.options.anthropic-version | The version of the generative to use. | bedrock-2023-05-31 -| spring.ai.bedrock.anthropic3.chat.options.max-tokens | Specify the maximum number of tokens to use in the generated response. Note that the models may stop before reaching this maximum. This parameter only specifies the absolute maximum number of tokens to generate. We recommend a limit of 4,000 tokens for optimal performance. | 500 -|==== - -Look at the https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic3/api/Anthropic3ChatBedrockApi.java[AnthropicChatModel] for other model IDs. -Supported values are: `anthropic.claude-instant-v1`, `anthropic.claude-v2` and `anthropic.claude-v2:1`. -Model ID values can also be found in the https://docs.aws.amazon.com/bedrock/latest/userguide/model-ids-arns.html[AWS Bedrock documentation for base model IDs]. - -TIP: All properties prefixed with `spring.ai.bedrock.anthropic3.chat.options` can be overridden at runtime by adding a request specific <> to the `Prompt` call. - -== Runtime Options [[chat-options]] - -The https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic3/Anthropic3ChatOptions.java[Anthropic3ChatOptions.java] provides model configurations, such as temperature, topK, topP, etc. - -On start-up, the default options can be configured with the `BedrockAnthropicChatModel(api, options)` constructor or the `spring.ai.bedrock.anthropic3.chat.options.*` properties. - -At run-time you can override the default options by adding new, request specific, options to the `Prompt` call. -For example to override the default temperature for a specific request: - -[source,java] ----- -ChatResponse response = chatModel.call( - new Prompt( - "Generate the names of 5 famous pirates.", - Anthropic3ChatOptions.builder() - .temperature(0.4) - .build() - )); ----- - -TIP: In addition to the model specific https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic3/Anthropic3ChatOptions.java[AnthropicChatOptions] you can use a portable https://github.com/spring-projects/spring-ai/blob/main/spring-ai-core/src/main/java/org/springframework/ai/chat/prompt/ChatOptions.java[ChatOptions] instance, created with the https://github.com/spring-projects/spring-ai/blob/main/spring-ai-core/src/main/java/org/springframework/ai/chat/prompt/ChatOptionsBuilder.java[ChatOptionsBuilder#builder()]. - - -== Multimodal - -Multimodality refers to a model's ability to simultaneously understand and process information from various sources, including text, images, audio, and other data formats. This paradigm represents a significant advancement in AI models. - -Currently, Anthropic Claude 3 supports the `base64` source type for `images`, and the `image/jpeg`, `image/png`, `image/gif`, and `image/webp` media types. -Check the link:https://docs.anthropic.com/claude/docs/vision[Vision guide] for more information. - -Spring AI's `Message` interface supports multimodal AI models by introducing the Media type. -This type contains data and information about media attachments in messages, using Spring's `org.springframework.util.MimeType` and a `java.lang.Object` for the raw media data. - -Below is a simple code example extracted from https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-anthropic/src/test/java/org/springframework/ai/anthropic3/Anthropic3ChatModelIT.java[Anthropic3ChatModelIT.java], demonstrating the combination of user text with an image. - -[source,java] ----- - byte[] imageData = new ClassPathResource("/test.png").getContentAsByteArray(); - - var userMessage = new UserMessage("Explain what do you see o this picture?", - List.of(new Media(MimeTypeUtils.IMAGE_PNG, this.imageData))); - - ChatResponse response = chatModel.call(new Prompt(List.of(this.userMessage))); - - assertThat(response.getResult().getOutput().getContent()).contains("bananas", "apple", "basket"); ----- - -It takes as an input the `test.png` image: - -image::multimodal.test.png[Multimodal Test Image, 200, 200, align="left"] - -along with the text message "Explain what do you see on this picture?", and generates a response something like: - ----- -The image shows a close-up view of a wire fruit basket containing several pieces of fruit. -The basket appears to be made of thin metal wires formed into a round shape with an elevated handle. - -Inside the basket, there are a few yellow bananas and a couple of red apples or possibly tomatoes. -The vibrant colors of the fruit contrast nicely against the metallic tones of the wire basket. - -The shallow depth of field in the photograph puts the focus squarely on the fruit in the foreground, while the basket handle extending upwards is slightly blurred, creating a pleasing bokeh effect in the background. - -The composition and lighting give the image a clean, minimalist aesthetic that highlights the natural beauty and freshness of the fruit displayed in this elegant wire basket. ----- - - -== Sample Controller - -https://start.spring.io/[Create] a new Spring Boot project and add the `spring-ai-bedrock-ai-spring-boot-starter` to your pom (or gradle) dependencies. - -Add a `application.properties` file, under the `src/main/resources` directory, to enable and configure the Anthropic chat model: - -[source] ----- -spring.ai.bedrock.aws.region=eu-central-1 -spring.ai.bedrock.aws.timeout=1000ms -spring.ai.bedrock.aws.access-key=${AWS_ACCESS_KEY_ID} -spring.ai.bedrock.aws.secret-key=${AWS_SECRET_ACCESS_KEY} - -spring.ai.bedrock.anthropic3.chat.enabled=true -spring.ai.bedrock.anthropic3.chat.options.temperature=0.8 -spring.ai.bedrock.anthropic3.chat.options.top-k=15 ----- - -TIP: replace the `regions`, `access-key` and `secret-key` with your AWS credentials. - -This will create a `BedrockAnthropicChatModel` implementation that you can inject into your class. -Here is an example of a simple `@Controller` class that uses the chat model for text generations. - -[source,java] ----- -@RestController -public class ChatController { - - private final BedrockAnthropic3ChatModel chatModel; - - @Autowired - public ChatController(BedrockAnthropic3ChatModel chatModel) { - this.chatModel = chatModel; - } - - @GetMapping("/ai/generate") - public Map generate(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) { - return Map.of("generation", this.chatModel.call(message)); - } - - @GetMapping("/ai/generateStream") - public Flux generateStream(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) { - Prompt prompt = new Prompt(new UserMessage(message)); - return this.chatModel.stream(prompt); - } -} ----- - -== Manual Configuration - -The https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic3/BedrockAnthropic3ChatModel.java[BedrockAnthropic3ChatModel] implements the `ChatModel` and `StreamingChatModel` and uses the <> to connect to the Bedrock Anthropic service. - -Add the `spring-ai-bedrock` dependency to your project's Maven `pom.xml` file: - -[source,xml] ----- - - org.springframework.ai - spring-ai-bedrock - ----- - -or to your Gradle `build.gradle` build file. - -[source,gradle] ----- -dependencies { - implementation 'org.springframework.ai:spring-ai-bedrock' -} ----- - -TIP: Refer to the xref:getting-started.adoc#dependency-management[Dependency Management] section to add the Spring AI BOM to your build file. - -Next, create an https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic3/BedrockAnthropic3ChatModel.java[BedrockAnthropic3ChatModel] and use it for text generations: - -[source,java] ----- -Anthropic3ChatBedrockApi anthropicApi = new Anthropic3ChatBedrockApi( - AnthropicChatBedrockApi.AnthropicModel.CLAUDE_V3_SONNET.id(), - EnvironmentVariableCredentialsProvider.create(), - Region.US_EAST_1.id(), - new ObjectMapper(), - Duration.ofMillis(1000L)); - -BedrockAnthropic3ChatModel chatModel = new BedrockAnthropic3ChatModel(this.anthropicApi, - AnthropicChatOptions.builder() - .temperature(0.6) - .topK(10) - .topP(0.8) - .maxTokensToSample(100) - .anthropicVersion(AnthropicChatBedrockApi.DEFAULT_ANTHROPIC_VERSION) - .build()); - -ChatResponse response = this.chatModel.call( - new Prompt("Generate the names of 5 famous pirates.")); - -// Or with streaming responses -Flux response = this.chatModel.stream( - new Prompt("Generate the names of 5 famous pirates.")); ----- - -=== Low-level Anthropic3ChatBedrockApi Client [[low-level-api]] - -The https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic3/api/Anthropic3ChatBedrockApi.java[Anthropic3ChatBedrockApi] provides is lightweight Java client on top of AWS Bedrock link:https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-claude.html[Anthropic Claude models]. - -Client supports the `anthropic.claude-3-opus-20240229-v1:0`,`anthropic.claude-3-sonnet-20240229-v1:0`,`anthropic.claude-3-haiku-20240307-v1:0` and the legacy `anthropic.claude-v2`, `anthropic.claude-v2:1` and `anthropic.claude-instant-v1` models for both synchronous (e.g. `chatCompletion()`) and streaming (e.g. `chatCompletionStream()`) responses. - -Here is a simple snippet how to use the api programmatically: - -[source,java] ----- -Anthropic3ChatBedrockApi anthropicChatApi = new Anthropic3ChatBedrockApi( - AnthropicModel.CLAUDE_V2.id(), Region.US_EAST_1.id(), Duration.ofMillis(1000L)); - -AnthropicChatRequest request = AnthropicChatRequest - .builder(String.format(Anthropic3ChatBedrockApi.PROMPT_TEMPLATE, "Name 3 famous pirates")) - .temperature(0.8) - .maxTokensToSample(300) - .topK(10) - .build(); - -// Sync request -AnthropicChatResponse response = this.anthropicChatApi.chatCompletion(this.request); - -// Streaming request -Flux responseStream = this.anthropicChatApi.chatCompletionStream(this.request); -List responses = this.responseStream.collectList().block(); ----- - -Follow the https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic3/api/Anthropic3ChatBedrockApi.java[Anthropic3ChatBedrockApi.java]'s JavaDoc for further information. diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock/bedrock-cohere.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock/bedrock-cohere.adoc deleted file mode 100644 index 6ab0800b49d..00000000000 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock/bedrock-cohere.adoc +++ /dev/null @@ -1,278 +0,0 @@ -= Cohere Chat - -[NOTE] -==== -Following the Bedrock recommendations, Spring AI is transitioning to using Amazon Bedrock's Converse API for all Chat conversation implementations in Spring AI. -While the existing `InvokeModel API` supports conversation applications, we strongly recommend adopting the xref:api/chat/bedrock-converse.adoc[Bedrock Converse API] for several key benefits: - -- Unified Interface: Write your code once and use it with any supported Amazon Bedrock model -- Model Flexibility: Seamlessly switch between different conversation models without code changes -- Extended Functionality: Support for model-specific parameters through dedicated structures -- Tool Support: Native integration with function calling and tool usage capabilities -- Multimodal Capabilities: Built-in support for vision and other multimodal features -- Future-Proof: Aligned with Amazon Bedrock's recommended best practices -==== - -Provides Bedrock Cohere chat model. -Integrate generative AI capabilities into essential apps and workflows that improve business outcomes. - -The https://aws.amazon.com/bedrock/cohere-command-embed/[AWS Bedrock Cohere Model Page] and https://docs.aws.amazon.com/bedrock/latest/userguide/what-is-bedrock.html[Amazon Bedrock User Guide] contains detailed information on how to use the AWS hosted model. - -== Prerequisites - -Refer to the xref:api/bedrock.adoc[Spring AI documentation on Amazon Bedrock] for setting up API access. - -=== Add Repositories and BOM - -Spring AI artifacts are published in Spring Milestone and Snapshot repositories. Refer to the xref:getting-started.adoc#repositories[Repositories] section to add these repositories to your build system. - -To help with dependency management, Spring AI provides a BOM (bill of materials) to ensure that a consistent version of Spring AI is used throughout the entire project. Refer to the xref:getting-started.adoc#dependency-management[Dependency Management] section to add the Spring AI BOM to your build system. - - -== Auto-configuration - -Add the `spring-ai-bedrock-ai-spring-boot-starter` dependency to your project's Maven `pom.xml` file: - -[source,xml] ----- - - org.springframework.ai - spring-ai-bedrock-ai-spring-boot-starter - ----- - -or to your Gradle `build.gradle` build file. - -[source,gradle] ----- -dependencies { - implementation 'org.springframework.ai:spring-ai-bedrock-ai-spring-boot-starter' -} ----- - -TIP: Refer to the xref:getting-started.adoc#dependency-management[Dependency Management] section to add the Spring AI BOM to your build file. - -=== Enable Cohere Chat Support - -By default the Cohere model is disabled. -To enable it set the `spring.ai.bedrock.cohere.chat.enabled` property to `true`. -Exporting environment variable is one way to set this configuration property: - -[source,shell] ----- -export SPRING_AI_BEDROCK_COHERE_CHAT_ENABLED=true ----- - -=== Chat Properties - -The prefix `spring.ai.bedrock.aws` is the property prefix to configure the connection to AWS Bedrock. - -[cols="3,3,3"] -|==== -| Property | Description | Default - -| spring.ai.bedrock.aws.region | AWS region to use. | us-east-1 -| spring.ai.bedrock.aws.timeout | AWS timeout to use. | 5m -| spring.ai.bedrock.aws.access-key | AWS access key. | - -| spring.ai.bedrock.aws.secret-key | AWS secret key. | - -|==== - -The prefix `spring.ai.bedrock.cohere.chat` is the property prefix that configures the chat model implementation for Cohere. - -[cols="2,5,1"] -|==== -| Property | Description | Default - -| spring.ai.bedrock.cohere.chat.enabled | Enable or disable support for Cohere | false -| spring.ai.bedrock.cohere.chat.model | The model id to use. See the https://github.com/spring-projects/spring-ai/blob/4ba9a3cd689b9fd3a3805f540debe398a079c6ef/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/api/CohereChatBedrockApi.java#L326C14-L326C29[CohereChatModel] for the supported models. | cohere.command-text-v14 -| spring.ai.bedrock.cohere.chat.options.temperature | Controls the randomness of the output. Values can range over [0.0,1.0] | 0.7 -| spring.ai.bedrock.cohere.chat.options.topP | The maximum cumulative probability of tokens to consider when sampling. | AWS Bedrock default -| spring.ai.bedrock.cohere.chat.options.topK | Specify the number of token choices the model uses to generate the next token | AWS Bedrock default -| spring.ai.bedrock.cohere.chat.options.maxTokens | Specify the maximum number of tokens to use in the generated response. | AWS Bedrock default -| spring.ai.bedrock.cohere.chat.options.stopSequences | Configure up to four sequences that the model recognizes. | AWS Bedrock default -| spring.ai.bedrock.cohere.chat.options.returnLikelihoods | The token likelihoods are returned with the response. | AWS Bedrock default -| spring.ai.bedrock.cohere.chat.options.numGenerations | The maximum number of generations that the model should return. | AWS Bedrock default -| spring.ai.bedrock.cohere.chat.options.logitBias | Prevents the model from generating unwanted tokens or incentivize the model to include desired tokens. | AWS Bedrock default -| spring.ai.bedrock.cohere.chat.options.truncate | Specifies how the API handles inputs longer than the maximum token length | AWS Bedrock default -|==== - -Look at the https://github.com/spring-projects/spring-ai/blob/4ba9a3cd689b9fd3a3805f540debe398a079c6ef/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/api/CohereChatBedrockApi.java#L326C14-L326C29[CohereChatModel] for other model IDs. -Supported values are: `cohere.command-light-text-v14` and `cohere.command-text-v14`. -Model ID values can also be found in the https://docs.aws.amazon.com/bedrock/latest/userguide/model-ids-arns.html[AWS Bedrock documentation for base model IDs]. - -TIP: All properties prefixed with `spring.ai.bedrock.cohere.chat.options` can be overridden at runtime by adding a request specific <> to the `Prompt` call. - -== Runtime Options [[chat-options]] - -The https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/BedrockCohereChatOptions.java[BedrockCohereChatOptions.java] provides model configurations, such as temperature, topK, topP, etc. - -On start-up, the default options can be configured with the `BedrockCohereChatModel(api, options)` constructor or the `spring.ai.bedrock.cohere.chat.options.*` properties. - -At run-time you can override the default options by adding new, request specific, options to the `Prompt` call. -For example to override the default temperature for a specific request: - -[source,java] ----- -ChatResponse response = chatModel.call( - new Prompt( - "Generate the names of 5 famous pirates.", - BedrockCohereChatOptions.builder() - .temperature(0.4) - .build() - )); ----- - -TIP: In addition to the model specific https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/BedrockCohereChatOptions.java[BedrockCohereChatOptions] you can use a portable https://github.com/spring-projects/spring-ai/blob/main/spring-ai-core/src/main/java/org/springframework/ai/chat/prompt/ChatOptions.java[ChatOptions] instance, created with the https://github.com/spring-projects/spring-ai/blob/main/spring-ai-core/src/main/java/org/springframework/ai/chat/prompt/ChatOptionsBuilder.java[ChatOptionsBuilder#builder()]. - -== Sample Controller - -https://start.spring.io/[Create] a new Spring Boot project and add the `spring-ai-bedrock-ai-spring-boot-starter` to your pom (or gradle) dependencies. - -Add a `application.properties` file, under the `src/main/resources` directory, to enable and configure the Cohere chat model: - -[source] ----- -spring.ai.bedrock.aws.region=eu-central-1 -spring.ai.bedrock.aws.timeout=1000ms -spring.ai.bedrock.aws.access-key=${AWS_ACCESS_KEY_ID} -spring.ai.bedrock.aws.secret-key=${AWS_SECRET_ACCESS_KEY} - -spring.ai.bedrock.cohere.chat.enabled=true -spring.ai.bedrock.cohere.chat.options.temperature=0.8 ----- - -TIP: replace the `regions`, `access-key` and `secret-key` with your AWS credentials. - -This will create a `BedrockCohereChatModel` implementation that you can inject into your class. -Here is an example of a simple `@Controller` class that uses the chat model for text generations. - -[source,java] ----- -@RestController -public class ChatController { - - private final BedrockCohereChatModel chatModel; - - @Autowired - public ChatController(BedrockCohereChatModel chatModel) { - this.chatModel = chatModel; - } - - @GetMapping("/ai/generate") - public Map generate(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) { - return Map.of("generation", this.chatModel.call(message)); - } - - @GetMapping("/ai/generateStream") - public Flux generateStream(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) { - Prompt prompt = new Prompt(new UserMessage(message)); - return this.chatModel.stream(prompt); - } -} ----- - -== Manual Configuration - -The https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/BedrockCohereChatModel.java[BedrockCohereChatModel] implements the `ChatModel` and `StreamingChatModel` and uses the <> to connect to the Bedrock Cohere service. - -Add the `spring-ai-bedrock` dependency to your project's Maven `pom.xml` file: - -[source,xml] ----- - - org.springframework.ai - spring-ai-bedrock - ----- - -or to your Gradle `build.gradle` build file. - -[source,gradle] ----- -dependencies { - implementation 'org.springframework.ai:spring-ai-bedrock' -} ----- - -TIP: Refer to the xref:getting-started.adoc#dependency-management[Dependency Management] section to add the Spring AI BOM to your build file. - -Next, create an https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/BedrockCohereChatModel.java[BedrockCohereChatModel] and use it for text generations: - -[source,java] ----- -CohereChatBedrockApi api = new CohereChatBedrockApi(CohereChatModel.COHERE_COMMAND_V14.id(), - EnvironmentVariableCredentialsProvider.create(), - Region.US_EAST_1.id(), - new ObjectMapper(), - Duration.ofMillis(1000L)); - -BedrockCohereChatModel chatModel = new BedrockCohereChatModel(this.api, - BedrockCohereChatOptions.builder() - .temperature(0.6) - .topK(10) - .topP(0.5) - .maxTokens(678) - .build()); - -ChatResponse response = this.chatModel.call( - new Prompt("Generate the names of 5 famous pirates.")); - -// Or with streaming responses -Flux response = this.chatModel.stream( - new Prompt("Generate the names of 5 famous pirates.")); ----- - -== Low-level CohereChatBedrockApi Client [[low-level-api]] - -The https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/api/CohereChatBedrockApi.java[CohereChatBedrockApi] provides is lightweight Java client on top of AWS Bedrock https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-cohere-command.html[Cohere Command models]. - -Following class diagram illustrates the CohereChatBedrockApi interface and building blocks: - -image::bedrock/bedrock-cohere-chat-low-level-api.jpg[align="center", width="800px"] - -The CohereChatBedrockApi supports the `cohere.command-light-text-v14` and `cohere.command-text-v14` models for both synchronous (e.g. `chatCompletion()`) and streaming (e.g. `chatCompletionStream()`) requests. - -Here is a simple snippet how to use the api programmatically: - -[source,java] ----- -CohereChatBedrockApi cohereChatApi = new CohereChatBedrockApi( - CohereChatModel.COHERE_COMMAND_V14.id(), - Region.US_EAST_1.id(), - Duration.ofMillis(1000L)); - -var request = CohereChatRequest - .builder("What is the capital of Bulgaria and what is the size? What is the national anthem?") - .stream(false) - .temperature(0.5) - .topP(0.8) - .topK(15) - .maxTokens(100) - .stopSequences(List.of("END")) - .returnLikelihoods(CohereChatRequest.ReturnLikelihoods.ALL) - .numGenerations(3) - .logitBias(null) - .truncate(Truncate.NONE) - .build(); - -CohereChatResponse response = this.cohereChatApi.chatCompletion(this.request); - -var request = CohereChatRequest - .builder("What is the capital of Bulgaria and what is the size? What it the national anthem?") - .stream(true) - .temperature(0.5) - .topP(0.8) - .topK(15) - .maxTokens(100) - .stopSequences(List.of("END")) - .returnLikelihoods(CohereChatRequest.ReturnLikelihoods.ALL) - .numGenerations(3) - .logitBias(null) - .truncate(Truncate.NONE) - .build(); - -Flux responseStream = this.cohereChatApi.chatCompletionStream(this.request); -List responses = this.responseStream.collectList().block(); ----- - - diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock/bedrock-jurassic2.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock/bedrock-jurassic2.adoc deleted file mode 100644 index 07a2214bc52..00000000000 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock/bedrock-jurassic2.adoc +++ /dev/null @@ -1,235 +0,0 @@ -= Jurassic-2 Chat - -[NOTE] -==== -Following the Bedrock recommendations, Spring AI is transitioning to using Amazon Bedrock's Converse API for all Chat conversation implementations in Spring AI. -While the existing `InvokeModel API` supports conversation applications, we strongly recommend adopting the xref:api/chat/bedrock-converse.adoc[Bedrock Converse API] for several key benefits: - -- Unified Interface: Write your code once and use it with any supported Amazon Bedrock model -- Model Flexibility: Seamlessly switch between different conversation models without code changes -- Extended Functionality: Support for model-specific parameters through dedicated structures -- Tool Support: Native integration with function calling and tool usage capabilities -- Multimodal Capabilities: Built-in support for vision and other multimodal features -- Future-Proof: Aligned with Amazon Bedrock's recommended best practices -==== - -https://aws.amazon.com/bedrock/jurassic/[AI21 Labs Jurassic on Amazon Bedrock -] Jurassic is AI21 Labs’ family of reliable FMs for the enterprise, powering sophisticated language generation tasks – such as question answering, text generation, search, and summarization – across thousands of live applications. - - -== Prerequisites - -Refer to the xref:api/bedrock.adoc[Spring AI documentation on Amazon Bedrock] for setting up API access. - -=== Add Repositories and BOM - -Spring AI artifacts are published in Spring Milestone and Snapshot repositories. Refer to the xref:getting-started.adoc#repositories[Repositories] section to add these repositories to your build system. - -To help with dependency management, Spring AI provides a BOM (bill of materials) to ensure that a consistent version of Spring AI is used throughout the entire project. Refer to the xref:getting-started.adoc#dependency-management[Dependency Management] section to add the Spring AI BOM to your build system. - - -== Auto-configuration - -Add the `spring-ai-bedrock-ai-spring-boot-starter` dependency to your project's Maven `pom.xml` file: - -[source,xml] ----- - - org.springframework.ai - spring-ai-bedrock-ai-spring-boot-starter - ----- - -or to your Gradle `build.gradle` build file. - -[source,gradle] ----- -dependencies { - implementation 'org.springframework.ai:spring-ai-bedrock-ai-spring-boot-starter' -} ----- - -TIP: Refer to the xref:getting-started.adoc#dependency-management[Dependency Management] section to add the Spring AI BOM to your build file. - -=== Enable Jurassic-2 - -By default the Bedrock Jurassic-2 model is disabled. -To enable it set the `spring.ai.bedrock.jurassic2.chat.enabled` property to `true`. -Exporting environment variable is one way to set this configuration property: - -[source,shell] ----- -export SPRING_AI_BEDROCK_JURASSIC2_CHAT_ENABLED=true ----- - -=== Chat Properties - -The prefix `spring.ai.bedrock.aws` is the property prefix to configure the connection to AWS Bedrock. - -[cols="3,3,3"] -|==== -| Property | Description | Default - -| spring.ai.bedrock.aws.region | AWS region to use. | us-east-1 -| spring.ai.bedrock.aws.timeout | AWS timeout to use. | 5m -| spring.ai.bedrock.aws.access-key | AWS access key. | - -| spring.ai.bedrock.aws.secret-key | AWS secret key. | - -|==== - - -The prefix `spring.ai.bedrock.jurassic2.chat` is the property prefix that configures the chat model implementation for Jurassic-2. - -[cols="2,5,1"] -|==== -| Property | Description | Default - -| spring.ai.bedrock.jurassic2.chat.enabled | Enable or disable support for Jurassic-2 | false -| spring.ai.bedrock.jurassic2.chat.model | The model id to use (See Below) | ai21.j2-mid-v1 -| spring.ai.bedrock.jurassic2.chat.options.temperature | Controls the randomness of the output. Values can range over [0.0,1.0], inclusive. A value closer to 1.0 will produce responses that are more varied, while a value closer to 0.0 will typically result in less surprising responses from the model. This value specifies default to be used by the backend while making the call to the model. | 0.7 -| spring.ai.bedrock.jurassic2.chat.options.top-p | The maximum cumulative probability of tokens to consider when sampling. The model uses combined Top-k and nucleus sampling. Nucleus sampling considers the smallest set of tokens whose probability sum is at least topP. | AWS Bedrock default -| spring.ai.bedrock.jurassic2.chat.options.max-tokens | Specify the maximum number of tokens to use in the generated response. The model truncates the response once the generated text exceeds maxTokens. | 500 -|==== - -Look at https://github.com/spring-projects/spring-ai/blob/4ba9a3cd689b9fd3a3805f540debe398a079c6ef/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/jurassic2/api/Ai21Jurassic2ChatBedrockApi.java#L164[Ai21Jurassic2ChatBedrockApi#Ai21Jurassic2ChatModel] for other model IDs. The other value supported is `ai21.j2-ultra-v1`. -Model ID values can also be found in the https://docs.aws.amazon.com/bedrock/latest/userguide/model-ids-arns.html[AWS Bedrock documentation for base model IDs]. - -TIP: All properties prefixed with `spring.ai.bedrock.jurassic2.chat.options` can be overridden at runtime by adding a request specific <> to the `Prompt` call. - -== Runtime Options [[chat-options]] - -The https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/jurassic2/BedrockAi21Jurassic2ChatOptions.java[BedrockAi21Jurassic2ChatOptions.java] provides model configurations, such as temperature, topP, maxTokens, etc. - -On start-up, the default options can be configured with the `BedrockAi21Jurassic2ChatModel(api, options)` constructor or the `spring.ai.bedrock.jurassic2.chat.options.*` properties. - -At run-time you can override the default options by adding new, request specific, options to the `Prompt` call. -For example to override the default temperature for a specific request: - -[source,java] ----- -ChatResponse response = chatModel.call( - new Prompt( - "Generate the names of 5 famous pirates.", - BedrockAi21Jurassic2ChatOptions.builder() - .temperature(0.4) - .build() - )); ----- - -TIP: In addition to the model specific https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/jurassic2/BedrockAi21Jurassic2ChatOptions.java[BedrockAi21Jurassic2ChatOptions] you can use a portable https://github.com/spring-projects/spring-ai/blob/main/spring-ai-core/src/main/java/org/springframework/ai/chat/prompt/ChatOptions.java[ChatOptions] instance, created with the https://github.com/spring-projects/spring-ai/blob/main/spring-ai-core/src/main/java/org/springframework/ai/chat/prompt/ChatOptionsBuilder.java[ChatOptionsBuilder#builder()]. - -== Sample Controller - -https://start.spring.io/[Create] a new Spring Boot project and add the `spring-ai-bedrock-ai-spring-boot-starter` to your pom (or gradle) dependencies. - -Add a `application.properties` file, under the `src/main/resources` directory, to enable and configure the Jurassic-2 chat model: - -[source] ----- -spring.ai.bedrock.aws.region=eu-central-1 -spring.ai.bedrock.aws.timeout=1000ms -spring.ai.bedrock.aws.access-key=${AWS_ACCESS_KEY_ID} -spring.ai.bedrock.aws.secret-key=${AWS_SECRET_ACCESS_KEY} - -spring.ai.bedrock.jurassic2.chat.enabled=true -spring.ai.bedrock.jurassic2.chat.options.temperature=0.8 ----- - -TIP: replace the `regions`, `access-key` and `secret-key` with your AWS credentials. - -This will create a `BedrockAi21Jurassic2ChatModel` implementation that you can inject into your class. -Here is an example of a simple `@Controller` class that uses the chat model for text generations. - -[source,java] ----- -@RestController -public class ChatController { - - private final BedrockAi21Jurassic2ChatModel chatModel; - - @Autowired - public ChatController(BedrockAi21Jurassic2ChatModel chatModel) { - this.chatModel = chatModel; - } - - @GetMapping("/ai/generate") - public Map generate(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) { - return Map.of("generation", this.chatModel.call(message)); - } - -} ----- - -== Manual Configuration - -The https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/jurassic2/BedrockAi21Jurassic2ChatModel.java[BedrockAi21Jurassic2ChatModel] implements the `ChatModel` uses the <> to connect to the Bedrock Jurassic-2 service. - -Add the `spring-ai-bedrock` dependency to your project's Maven `pom.xml` file: - -[source,xml] ----- - - org.springframework.ai - spring-ai-bedrock - ----- - -or to your Gradle `build.gradle` build file. - -[source,gradle] ----- -dependencies { - implementation 'org.springframework.ai:spring-ai-bedrock' -} ----- - -TIP: Refer to the xref:getting-started.adoc#dependency-management[Dependency Management] section to add the Spring AI BOM to your build file. - -Next, create an https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/jurassic2/BedrockAi21Jurassic2ChatModel.java[BedrockAi21Jurassic2ChatModel] and use it for text generations: - -[source,java] ----- -Ai21Jurassic2ChatBedrockApi api = new Ai21Jurassic2ChatBedrockApi(Ai21Jurassic2ChatModel.AI21_J2_MID_V1.id(), - EnvironmentVariableCredentialsProvider.create(), - Region.US_EAST_1.id(), - new ObjectMapper(), - Duration.ofMillis(1000L)); - -BedrockAi21Jurassic2ChatModel chatModel = new BedrockAi21Jurassic2ChatModel(this.api, - BedrockAi21Jurassic2ChatOptions.builder() - .temperature(0.5) - .maxTokens(100) - .topP(0.9).build()); - -ChatResponse response = this.chatModel.call( - new Prompt("Generate the names of 5 famous pirates.")); - ----- - -== Low-level Client [[low-level-api]] - -https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/jurassic2/api/Ai21Jurassic2ChatBedrockApi.java[Ai21Jurassic2ChatBedrockApi] provides a lightweight Java client on top of AWS Bedrock https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-jurassic2.html[Jurassic-2 and Jurassic-2 Chat models]. - -The `Ai21Jurassic2ChatBedrockApi` supports the `ai21.j2-mid-v1` and `ai21.j2-ultra-v1` models and only support synchronous ( `chatCompletion()`). - -Here is a simple snippet on how to use the API programmatically: - - -[source,java] ----- -Ai21Jurassic2ChatBedrockApi jurassic2ChatApi = new Ai21Jurassic2ChatBedrockApi( - Ai21Jurassic2ChatModel.AI21_J2_MID_V1.id(), - Region.US_EAST_1.id(), - Duration.ofMillis(1000L)); - -Ai21Jurassic2ChatRequest request = Ai21Jurassic2ChatRequest.builder("Hello, my name is") - .temperature(0.9) - .topP(0.9) - .maxTokens(20) - .build(); - -Ai21Jurassic2ChatResponse response = this.jurassic2ChatApi.chatCompletion(this.request); - - ----- - -Follow the https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/jurassic2/api/Ai21Jurassic2ChatBedrockApi.java[Ai21Jurassic2ChatBedrockApi.java]'s JavaDoc for further information. diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock/bedrock-llama.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock/bedrock-llama.adoc deleted file mode 100644 index e5a9c61a46f..00000000000 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock/bedrock-llama.adoc +++ /dev/null @@ -1,255 +0,0 @@ -= Llama Chat - -[NOTE] -==== -Following the Bedrock recommendations, Spring AI is transitioning to using Amazon Bedrock's Converse API for all Chat conversation implementations in Spring AI. -While the existing `InvokeModel API` supports conversation applications, we strongly recommend adopting the xref:api/chat/bedrock-converse.adoc[Bedrock Converse API] for several key benefits: - -- Unified Interface: Write your code once and use it with any supported Amazon Bedrock model -- Model Flexibility: Seamlessly switch between different conversation models without code changes -- Extended Functionality: Support for model-specific parameters through dedicated structures -- Tool Support: Native integration with function calling and tool usage capabilities -- Multimodal Capabilities: Built-in support for vision and other multimodal features -- Future-Proof: Aligned with Amazon Bedrock's recommended best practices -==== - -https://ai.meta.com/llama/[Meta's Llama Chat] is part of the Llama collection of large language models. -It excels in dialogue-based applications with a parameter scale ranging from 7 billion to 70 billion. -Leveraging public datasets and over 1 million human annotations, Llama Chat offers context-aware dialogues. - -Trained on 2 trillion tokens from public data sources, Llama-Chat provides extensive knowledge for insightful conversations. -Rigorous testing, including over 1,000 hours of red-teaming and annotation, ensures both performance and safety, making it a reliable choice for AI-driven dialogues. - -The https://aws.amazon.com/bedrock/llama/[AWS Llama Model Page] and https://docs.aws.amazon.com/bedrock/latest/userguide/what-is-bedrock.html[Amazon Bedrock User Guide] contains detailed information on how to use the AWS hosted model. - -== Prerequisites - -Refer to the xref:api/bedrock.adoc[Spring AI documentation on Amazon Bedrock] for setting up API access. - -=== Add Repositories and BOM - -Spring AI artifacts are published in Spring Milestone and Snapshot repositories. Refer to the xref:getting-started.adoc#repositories[Repositories] section to add these repositories to your build system. - -To help with dependency management, Spring AI provides a BOM (bill of materials) to ensure that a consistent version of Spring AI is used throughout the entire project. Refer to the xref:getting-started.adoc#dependency-management[Dependency Management] section to add the Spring AI BOM to your build system. - - -== Auto-configuration - -Add the `spring-ai-bedrock-ai-spring-boot-starter` dependency to your project's Maven `pom.xml` file: - -[source,xml] ----- - - org.springframework.ai - spring-ai-bedrock-ai-spring-boot-starter - ----- - -or to your Gradle `build.gradle` build file. - -[source,gradle] ----- -dependencies { - implementation 'org.springframework.ai:spring-ai-bedrock-ai-spring-boot-starter' -} ----- - -TIP: Refer to the xref:getting-started.adoc#dependency-management[Dependency Management] section to add the Spring AI BOM to your build file. - -=== Enable Llama Chat Support - -By default the Bedrock Llama model is disabled. -To enable it set the `spring.ai.bedrock.llama.chat.enabled` property to `true`. -Exporting environment variable is one way to set this configuration property: - -[source,shell] ----- -export SPRING_AI_BEDROCK_LLAMA_CHAT_ENABLED=true ----- - -=== Chat Properties - -The prefix `spring.ai.bedrock.aws` is the property prefix to configure the connection to AWS Bedrock. - -[cols="3,3,3"] -|==== -| Property | Description | Default - -| spring.ai.bedrock.aws.region | AWS region to use. | us-east-1 -| spring.ai.bedrock.aws.timeout | AWS timeout to use. | 5m -| spring.ai.bedrock.aws.access-key | AWS access key. | - -| spring.ai.bedrock.aws.secret-key | AWS secret key. | - -|==== - - -The prefix `spring.ai.bedrock.llama.chat` is the property prefix that configures the chat model implementation for Llama. - -[cols="2,5,1"] -|==== -| Property | Description | Default - -| spring.ai.bedrock.llama.chat.enabled | Enable or disable support for Llama | false -| spring.ai.bedrock.llama.chat.model | The model id to use (See Below) | meta.llama3-70b-instruct-v1:0 -| spring.ai.bedrock.llama.chat.options.temperature | Controls the randomness of the output. Values can range over [0.0,1.0], inclusive. A value closer to 1.0 will produce responses that are more varied, while a value closer to 0.0 will typically result in less surprising responses from the model. This value specifies default to be used by the backend while making the call to the model. | 0.7 -| spring.ai.bedrock.llama.chat.options.top-p | The maximum cumulative probability of tokens to consider when sampling. The model uses combined Top-k and nucleus sampling. Nucleus sampling considers the smallest set of tokens whose probability sum is at least topP. | AWS Bedrock default -| spring.ai.bedrock.llama.chat.options.max-gen-len | Specify the maximum number of tokens to use in the generated response. The model truncates the response once the generated text exceeds maxGenLen. | 300 -|==== - -Look at https://github.com/spring-projects/spring-ai/blob/4ba9a3cd689b9fd3a3805f540debe398a079c6ef/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/llama/api/LlamaChatBedrockApi.java#L164[LlamaChatBedrockApi#LlamaChatModel] for other model IDs. The other value supported is `meta.llama2-13b-chat-v1`. -Model ID values can also be found in the https://docs.aws.amazon.com/bedrock/latest/userguide/model-ids-arns.html[AWS Bedrock documentation for base model IDs]. - -TIP: All properties prefixed with `spring.ai.bedrock.llama.chat.options` can be overridden at runtime by adding a request specific <> to the `Prompt` call. - -== Runtime Options [[chat-options]] - -The https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/llama/BedrockLlamaChatOptions.java[BedrockLlChatOptions.java] provides model configurations, such as temperature, topK, topP, etc. - -On start-up, the default options can be configured with the `BedrockLlamaChatModel(api, options)` constructor or the `spring.ai.bedrock.llama.chat.options.*` properties. - -At run-time you can override the default options by adding new, request specific, options to the `Prompt` call. -For example to override the default temperature for a specific request: - -[source,java] ----- -ChatResponse response = chatModel.call( - new Prompt( - "Generate the names of 5 famous pirates.", - BedrockLlamaChatOptions.builder() - .temperature(0.4) - .build() - )); ----- - -TIP: In addition to the model specific https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/llama/BedrockLlamaChatOptions.java[BedrockLlamaChatOptions] you can use a portable https://github.com/spring-projects/spring-ai/blob/main/spring-ai-core/src/main/java/org/springframework/ai/chat/prompt/ChatOptions.java[ChatOptions] instance, created with the https://github.com/spring-projects/spring-ai/blob/main/spring-ai-core/src/main/java/org/springframework/ai/chat/prompt/ChatOptionsBuilder.java[ChatOptionsBuilder#builder()]. - -== Sample Controller - -https://start.spring.io/[Create] a new Spring Boot project and add the `spring-ai-bedrock-ai-spring-boot-starter` to your pom (or gradle) dependencies. - -Add a `application.properties` file, under the `src/main/resources` directory, to enable and configure the Anthropic chat model: - -[source] ----- -spring.ai.bedrock.aws.region=eu-central-1 -spring.ai.bedrock.aws.timeout=1000ms -spring.ai.bedrock.aws.access-key=${AWS_ACCESS_KEY_ID} -spring.ai.bedrock.aws.secret-key=${AWS_SECRET_ACCESS_KEY} - -spring.ai.bedrock.llama.chat.enabled=true -spring.ai.bedrock.llama.chat.options.temperature=0.8 ----- - -TIP: replace the `regions`, `access-key` and `secret-key` with your AWS credentials. - -This will create a `BedrockLlamaChatModel` implementation that you can inject into your class. -Here is an example of a simple `@Controller` class that uses the chat model for text generations. - -[source,java] ----- -@RestController -public class ChatController { - - private final BedrockLlamaChatModel chatModel; - - @Autowired - public ChatController(BedrockLlamaChatModel chatModel) { - this.chatModel = chatModel; - } - - @GetMapping("/ai/generate") - public Map generate(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) { - return Map.of("generation", this.chatModel.call(message)); - } - - @GetMapping("/ai/generateStream") - public Flux generateStream(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) { - Prompt prompt = new Prompt(new UserMessage(message)); - return this.chatModel.stream(prompt); - } -} ----- - -== Manual Configuration - -The https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/llama/BedrockLlamaChatModel.java[BedrockLlamaChatModel] implements the `ChatModel` and `StreamingChatModel` and uses the <> to connect to the Bedrock Anthropic service. - -Add the `spring-ai-bedrock` dependency to your project's Maven `pom.xml` file: - -[source,xml] ----- - - org.springframework.ai - spring-ai-bedrock - ----- - -or to your Gradle `build.gradle` build file. - -[source,gradle] ----- -dependencies { - implementation 'org.springframework.ai:spring-ai-bedrock' -} ----- - -TIP: Refer to the xref:getting-started.adoc#dependency-management[Dependency Management] section to add the Spring AI BOM to your build file. - -Next, create an https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/llama/BedrockLlamaChatModel.java[BedrockLlamaChatModel] and use it for text generations: - -[source,java] ----- -LlamaChatBedrockApi api = new LlamaChatBedrockApi(LlamaChatModel.LLAMA2_70B_CHAT_V1.id(), - EnvironmentVariableCredentialsProvider.create(), - Region.US_EAST_1.id(), - new ObjectMapper(), - Duration.ofMillis(1000L)); - -BedrockLlamaChatModel chatModel = new BedrockLlamaChatModel(this.api, - BedrockLlamaChatOptions.builder() - .temperature(0.5) - .maxGenLen(100) - .topP(0.9).build()); - -ChatResponse response = this.chatModel.call( - new Prompt("Generate the names of 5 famous pirates.")); - -// Or with streaming responses -Flux response = this.chatModel.stream( - new Prompt("Generate the names of 5 famous pirates.")); ----- - -== Low-level LlamaChatBedrockApi Client [[low-level-api]] - -https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/llama/api/LlamaChatBedrockApi.java[LlamaChatBedrockApi] provides is lightweight Java client on top of AWS Bedrock https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-meta.html[Meta Llama 2 and Llama 2 Chat models]. - -Following class diagram illustrates the LlamaChatBedrockApi interface and building blocks: - -image::bedrock/bedrock-llama-chat-api.jpg[LlamaChatBedrockApi Class Diagram] - -The LlamaChatBedrockApi supports the `meta.llama3-8b-instruct-v1:0`,`meta.llama3-70b-instruct-v1:0`,`meta.llama2-13b-chat-v1` and `meta.llama2-70b-chat-v1` models for both synchronous (e.g. `chatCompletion()`) and streaming (e.g. `chatCompletionStream()`) responses. - -Here is a simple snippet how to use the api programmatically: - -[source,java] ----- -LlamaChatBedrockApi llamaChatApi = new LlamaChatBedrockApi( - LlamaChatModel.LLAMA3_70B_INSTRUCT_V1.id(), - Region.US_EAST_1.id(), - Duration.ofMillis(1000L)); - -LlamaChatRequest request = LlamaChatRequest.builder("Hello, my name is") - .temperature(0.9) - .topP(0.9) - .maxGenLen(20) - .build(); - -LlamaChatResponse response = this.llamaChatApi.chatCompletion(this.request); - -// Streaming response -Flux responseStream = this.llamaChatApi.chatCompletionStream(this.request); -List responses = this.responseStream.collectList().block(); ----- - -Follow the https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/llama/api/LlamaChatBedrockApi.java[LlamaChatBedrockApi.java]'s JavaDoc for further information. - - diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock/bedrock-titan.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock/bedrock-titan.adoc deleted file mode 100644 index 98d184c5d71..00000000000 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/bedrock/bedrock-titan.adoc +++ /dev/null @@ -1,252 +0,0 @@ -= Titan Chat - -[NOTE] -==== -Following the Bedrock recommendations, Spring AI is transitioning to using Amazon Bedrock's Converse API for all Chat conversation implementations in Spring AI. -While the existing `InvokeModel API` supports conversation applications, we strongly recommend adopting the xref:api/chat/bedrock-converse.adoc[Bedrock Converse API] for several key benefits: - -- Unified Interface: Write your code once and use it with any supported Amazon Bedrock model -- Model Flexibility: Seamlessly switch between different conversation models without code changes -- Extended Functionality: Support for model-specific parameters through dedicated structures -- Tool Support: Native integration with function calling and tool usage capabilities -- Multimodal Capabilities: Built-in support for vision and other multimodal features -- Future-Proof: Aligned with Amazon Bedrock's recommended best practices -==== - -link:https://aws.amazon.com/bedrock/titan/[Amazon Titan] foundation models (FMs) provide customers with a breadth of high-performing image, multimodal embeddings, and text model choices, via a fully managed API. -Amazon Titan models are created by AWS and pretrained on large datasets, making them powerful, general-purpose models built to support a variety of use cases, while also supporting the responsible use of AI. -Use them as is or privately customize them with your own data. - -The https://aws.amazon.com/bedrock/titan/[AWS Bedrock Titan Model Page] and https://docs.aws.amazon.com/bedrock/latest/userguide/what-is-bedrock.html[Amazon Bedrock User Guide] contains detailed information on how to use the AWS hosted model. - -== Prerequisites - -Refer to the xref:api/bedrock.adoc[Spring AI documentation on Amazon Bedrock] for setting up API access. - -=== Add Repositories and BOM - -Spring AI artifacts are published in Spring Milestone and Snapshot repositories. Refer to the xref:getting-started.adoc#repositories[Repositories] section to add these repositories to your build system. - -To help with dependency management, Spring AI provides a BOM (bill of materials) to ensure that a consistent version of Spring AI is used throughout the entire project. Refer to the xref:getting-started.adoc#dependency-management[Dependency Management] section to add the Spring AI BOM to your build system. - - -== Auto-configuration - -Add the `spring-ai-bedrock-ai-spring-boot-starter` dependency to your project's Maven `pom.xml` file: - -[source,xml] ----- - - org.springframework.ai - spring-ai-bedrock-ai-spring-boot-starter - ----- - -or to your Gradle `build.gradle` build file. - -[source,gradle] ----- -dependencies { - implementation 'org.springframework.ai:spring-ai-bedrock-ai-spring-boot-starter' -} ----- - -TIP: Refer to the xref:getting-started.adoc#dependency-management[Dependency Management] section to add the Spring AI BOM to your build file. - -=== Enable Titan Chat - -By default the Titan model is disabled. -To enable it set the `spring.ai.bedrock.titan.chat.enabled` property to `true`. -Exporting environment variable is one way to set this configuration property: - -[source,shell] ----- -export SPRING_AI_BEDROCK_TITAN_CHAT_ENABLED=true ----- - -=== Chat Properties - -The prefix `spring.ai.bedrock.aws` is the property prefix to configure the connection to AWS Bedrock. - -[cols="3,4,1"] -|==== -| Property | Description | Default - -| spring.ai.bedrock.aws.region | AWS region to use. | us-east-1 -| spring.ai.bedrock.aws.timeout | AWS timeout to use. | 5m -| spring.ai.bedrock.aws.access-key | AWS access key. | - -| spring.ai.bedrock.aws.secret-key | AWS secret key. | - -|==== - -The prefix `spring.ai.bedrock.titan.chat` is the property prefix that configures the chat model implementation for Titan. - -[cols="3,4,1"] -|==== -| Property | Description | Default - -| spring.ai.bedrock.titan.chat.enabled | Enable Bedrock Titan chat model. Disabled by default | false -| spring.ai.bedrock.titan.chat.model | The model id to use. See the link:https://github.com/spring-projects/spring-ai/blob/4839a6175cd1ec89498b97d3efb6647022c3c7cb/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/api/TitanChatBedrockApi.java#L220[TitanChatBedrockApi#TitanChatModel] for the supported models. | amazon.titan-text-lite-v1 -| spring.ai.bedrock.titan.chat.options.temperature | Controls the randomness of the output. Values can range over [0.0,1.0] | 0.7 -| spring.ai.bedrock.titan.chat.options.topP | The maximum cumulative probability of tokens to consider when sampling. | AWS Bedrock default -| spring.ai.bedrock.titan.chat.options.stopSequences | Configure up to four sequences that the generative recognizes. After a stop sequence, the generative stops generating further tokens. The returned text doesn't contain the stop sequence. | AWS Bedrock default -| spring.ai.bedrock.titan.chat.options.maxTokenCount | Specify the maximum number of tokens to use in the generated response. Note that the models may stop before reaching this maximum. This parameter only specifies the absolute maximum number of tokens to generate. We recommend a limit of 4,000 tokens for optimal performance. | AWS Bedrock default -|==== - -Look at the https://github.com/spring-projects/spring-ai/blob/4839a6175cd1ec89498b97d3efb6647022c3c7cb/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/api/TitanChatBedrockApi.java#L220[TitanChatBedrockApi#TitanChatModel] for other model IDs. -Supported values are: `amazon.titan-text-lite-v1`, `amazon.titan-text-express-v1` and `amazon.titan-text-premier-v1:0`. -Model ID values can also be found in the https://docs.aws.amazon.com/bedrock/latest/userguide/model-ids-arns.html[AWS Bedrock documentation for base model IDs]. - -TIP: All properties prefixed with `spring.ai.bedrock.titan.chat.options` can be overridden at runtime by adding a request specific <> to the `Prompt` call. - -== Runtime Options [[chat-options]] - -The https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/BedrockTitanChatOptions.java[BedrockTitanChatOptions.java] provides model configurations, such as temperature, topP, etc. - -On start-up, the default options can be configured with the `BedrockTitanChatModel(api, options)` constructor or the `spring.ai.bedrock.titan.chat.options.*` properties. - -At run-time you can override the default options by adding new, request specific, options to the `Prompt` call. -For example to override the default temperature for a specific request: - -[source,java] ----- -ChatResponse response = chatModel.call( - new Prompt( - "Generate the names of 5 famous pirates.", - BedrockTitanChatOptions.builder() - .temperature(0.4) - .build() - )); ----- - -TIP: In addition to the model specific https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/BedrockTitanChatOptions.java[BedrockTitanChatOptions] you can use a portable https://github.com/spring-projects/spring-ai/blob/main/spring-ai-core/src/main/java/org/springframework/ai/chat/prompt/ChatOptions.java[ChatOptions] instance, created with the https://github.com/spring-projects/spring-ai/blob/main/spring-ai-core/src/main/java/org/springframework/ai/chat/prompt/ChatOptionsBuilder.java[ChatOptionsBuilder#builder()]. - -== Sample Controller - -https://start.spring.io/[Create] a new Spring Boot project and add the `spring-ai-bedrock-ai-spring-boot-starter` to your pom (or gradle) dependencies. - -Add a `application.properties` file, under the `src/main/resources` directory, to enable and configure the Titan chat model: - -[source] ----- -spring.ai.bedrock.aws.region=eu-central-1 -spring.ai.bedrock.aws.timeout=1000ms -spring.ai.bedrock.aws.access-key=${AWS_ACCESS_KEY_ID} -spring.ai.bedrock.aws.secret-key=${AWS_SECRET_ACCESS_KEY} - -spring.ai.bedrock.titan.chat.enabled=true -spring.ai.bedrock.titan.chat.options.temperature=0.8 ----- - -TIP: replace the `regions`, `access-key` and `secret-key` with your AWS credentials. - -This will create a `BedrockTitanChatModel` implementation that you can inject into your class. -Here is an example of a simple `@Controller` class that uses the chat model for text generations. - -[source,java] ----- -@RestController -public class ChatController { - - private final BedrockTitanChatModel chatModel; - - @Autowired - public ChatController(BedrockTitanChatModel chatModel) { - this.chatModel = chatModel; - } - - @GetMapping("/ai/generate") - public Map generate(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) { - return Map.of("generation", this.chatModel.call(message)); - } - - @GetMapping("/ai/generateStream") - public Flux generateStream(@RequestParam(value = "message", defaultValue = "Tell me a joke") String message) { - Prompt prompt = new Prompt(new UserMessage(message)); - return this.chatModel.stream(prompt); - } -} ----- - -== Manual Configuration - -The https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/BedrockTitanChatModel.java[BedrockTitanChatModel] implements the `ChatModel` and `StreamingChatModel` and uses the <> to connect to the Bedrock Titanic service. - -Add the `spring-ai-bedrock` dependency to your project's Maven `pom.xml` file: - -[source,xml] ----- - - org.springframework.ai - spring-ai-bedrock - ----- - -or to your Gradle `build.gradle` build file. - -[source,gradle] ----- -dependencies { - implementation 'org.springframework.ai:spring-ai-bedrock' -} ----- - -TIP: Refer to the xref:getting-started.adoc#dependency-management[Dependency Management] section to add the Spring AI BOM to your build file. - -Next, create an https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/BedrockTitanChatModel.java[BedrockTitanChatModel] and use it for text generations: - -[source,java] ----- -TitanChatBedrockApi titanApi = new TitanChatBedrockApi( - TitanChatModel.TITAN_TEXT_EXPRESS_V1.id(), - EnvironmentVariableCredentialsProvider.create(), - Region.US_EAST_1.id(), - new ObjectMapper(), - Duration.ofMillis(1000L)); - -BedrockTitanChatModel chatModel = new BedrockTitanChatModel(this.titanApi, - BedrockTitanChatOptions.builder() - .temperature(0.6) - .topP(0.8) - .maxTokenCount(100) - .build()); - -ChatResponse response = this.chatModel.call( - new Prompt("Generate the names of 5 famous pirates.")); - -// Or with streaming responses -Flux response = this.chatModel.stream( - new Prompt("Generate the names of 5 famous pirates.")); ----- - -== Low-level TitanChatBedrockApi Client [[low-level-api]] - -The https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/api/TitanChatBedrockApi.java[TitanChatBedrockApi] provides is lightweight Java client on top of AWS Bedrock link:https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-titan-text.html[Bedrock Titan models]. - -Following class diagram illustrates the TitanChatBedrockApi interface and building blocks: - -image::bedrock/bedrock-titan-chat-low-level-api.jpg[width=800,align="center"] - -Client supports the `amazon.titan-text-lite-v1` and `amazon.titan-text-express-v1` models for both synchronous (e.g. `chatCompletion()`) and streaming (e.g. `chatCompletionStream()`) responses. - -Here is a simple snippet how to use the api programmatically: - -[source,java] ----- -TitanChatBedrockApi titanBedrockApi = new TitanChatBedrockApi(TitanChatCompletionModel.TITAN_TEXT_EXPRESS_V1.id(), - Region.US_EAST_1.id(), Duration.ofMillis(1000L)); - -TitanChatRequest titanChatRequest = TitanChatRequest.builder("Give me the names of 3 famous pirates?") - .temperature(0.5) - .topP(0.9) - .maxTokenCount(100) - .stopSequences(List.of("|")) - .build(); - -TitanChatResponse response = this.titanBedrockApi.chatCompletion(this.titanChatRequest); - -Flux response = this.titanBedrockApi.chatCompletionStream(this.titanChatRequest); - -List results = this.response.collectList().block(); ----- - -Follow the https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/api/TitanChatBedrockApi.java[TitanChatBedrockApi]'s JavaDoc for further information. diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chatmodel.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chatmodel.adoc index a52b1c8c676..3fc8e65e04b 100644 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chatmodel.adoc +++ b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chatmodel.adoc @@ -223,11 +223,6 @@ image::spring-ai-chat-completions-clients.jpg[align="center", width="1000px"] * xref:api/chat/huggingface.adoc[Hugging Face Chat Completion] (no streaming support) * xref:api/chat/vertexai-gemini-chat.adoc[Google Vertex AI Gemini Chat Completion] (streaming, multi-modality & function-calling support) * xref:api/bedrock.adoc[Amazon Bedrock] -** xref:api/chat/bedrock/bedrock-cohere.adoc[Cohere Chat Completion] -** xref:api/chat/bedrock/bedrock-llama.adoc[Llama Chat Completion] -** xref:api/chat/bedrock/bedrock-titan.adoc[Titan Chat Completion] -** xref:api/chat/bedrock/bedrock-anthropic.adoc[Anthropic Chat Completion] -** xref:api/chat/bedrock/bedrock-jurassic2.adoc[Jurassic2 Chat Completion] * xref:api/chat/mistralai-chat.adoc[Mistral AI Chat Completion] (streaming & function-calling support) * xref:api/chat/anthropic-chat.adoc[Anthropic Chat Completion] (streaming & function-calling support) diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/structured-output-converter.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/structured-output-converter.adoc index 79591e656b3..8b277d6d7ea 100644 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/structured-output-converter.adoc +++ b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/structured-output-converter.adoc @@ -266,10 +266,6 @@ The following AI Models have been tested to support List, Map and Bean structure | xref:api/chat/mistralai-chat.adoc[Mistral AI] | link:https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-mistral-ai/src/test/java/org/springframework/ai/mistralai/MistralAiChatModelIT.java[MistralAiChatModelIT.java] | xref:api/chat/ollama-chat.adoc[Ollama] | link:https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-ollama/src/test/java/org/springframework/ai/ollama/OllamaChatModelIT.java[OllamaChatModelIT.java] | xref:api/chat/vertexai-gemini-chat.adoc[Vertex AI Gemini] | link:https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-vertex-ai-gemini/src/test/java/org/springframework/ai/vertexai/gemini/VertexAiGeminiChatModelIT.java[VertexAiGeminiChatModelIT.java] -| xref:api/chat/bedrock/bedrock-anthropic.adoc[Bedrock Anthropic 2] | link:https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/anthropic/BedrockAnthropicChatModelIT.java[BedrockAnthropicChatModelIT.java] -| xref:api/chat/bedrock/bedrock-anthropic3.adoc[Bedrock Anthropic 3] | link:https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/anthropic3/BedrockAnthropic3ChatModelIT.java[BedrockAnthropic3ChatModelIT.java] -| xref:api/chat/bedrock/bedrock-cohere.adoc[Bedrock Cohere] | link:https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/cohere/BedrockCohereChatModelIT.java[BedrockCohereChatModelIT.java] -| xref:api/chat/bedrock/bedrock-llama.adoc[Bedrock Llama] | link:https://github.com/spring-projects/spring-ai/blob/main/models/spring-ai-bedrock/src/test/java/org/springframework/ai/bedrock/llama/BedrockLlamaChatModelIT.java[BedrockLlamaChatModelIT.java.java] |==== == Built-in JSON mode diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/upgrade-notes.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/upgrade-notes.adoc index 593d74745e6..5579117c075 100644 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/upgrade-notes.adoc +++ b/spring-ai-docs/src/main/antora/modules/ROOT/pages/upgrade-notes.adoc @@ -36,6 +36,16 @@ 3. When constructing link:https://github.com/spring-projects/spring-ai/blob/main/spring-ai-core/src/main/java/org/springframework/ai/chat/metadata/DefaultUsage.java[DefaultUsage], use the parameter name `completionTokens` instead of `generationTokens` 4. If you're serializing `DefaultUsage` objects to JSON, update your code to use the new field names + +=== Removal of deprecated Amazon Bedrock chat models + +Starting 1.0.0-M6, Spring AI transitioned to using Amazon Bedrock's Converse API for all Chat conversation implementations in Spring AI. +All the Amazon Bedrock Chat models are removed except the Embedding models for Cohere and Titan. + +=== Migration Guide + +Refer to xref:api/chat/bedrock-converse.adoc[Bedrock Converse] documentation for using the chat models. + == Upgrading to 1.0.0.M5 * Vector Builders have been refactored for consistency. diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/anthropic/BedrockAnthropicChatAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/anthropic/BedrockAnthropicChatAutoConfiguration.java deleted file mode 100644 index 77a8912839b..00000000000 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/anthropic/BedrockAnthropicChatAutoConfiguration.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.autoconfigure.bedrock.anthropic; - -import com.fasterxml.jackson.databind.ObjectMapper; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; -import software.amazon.awssdk.regions.providers.AwsRegionProvider; - -import org.springframework.ai.autoconfigure.bedrock.BedrockAwsConnectionConfiguration; -import org.springframework.ai.autoconfigure.bedrock.BedrockAwsConnectionProperties; -import org.springframework.ai.bedrock.anthropic.BedrockAnthropicChatModel; -import org.springframework.ai.bedrock.anthropic.api.AnthropicChatBedrockApi; -import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Import; - -/** - * {@link AutoConfiguration Auto-configuration} for Bedrock Anthropic Chat Client. - * - * Leverages the Spring Cloud AWS to resolve the {@link AwsCredentialsProvider}. - * - * @author Christian Tzolov - * @author Wei Jiang - * @since 0.8.0 - */ -@AutoConfiguration -@ConditionalOnClass(AnthropicChatBedrockApi.class) -@EnableConfigurationProperties({ BedrockAnthropicChatProperties.class, BedrockAwsConnectionProperties.class }) -@ConditionalOnProperty(prefix = BedrockAnthropicChatProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true") -@Import(BedrockAwsConnectionConfiguration.class) -public class BedrockAnthropicChatAutoConfiguration { - - @Bean - @ConditionalOnMissingBean - @ConditionalOnBean({ AwsCredentialsProvider.class, AwsRegionProvider.class }) - public AnthropicChatBedrockApi anthropicApi(AwsCredentialsProvider credentialsProvider, - AwsRegionProvider regionProvider, BedrockAnthropicChatProperties properties, - BedrockAwsConnectionProperties awsProperties, ObjectMapper objectMapper) { - return new AnthropicChatBedrockApi(properties.getModel(), credentialsProvider, regionProvider.getRegion(), - objectMapper, awsProperties.getTimeout()); - } - - @Bean - @ConditionalOnMissingBean - @ConditionalOnBean(AnthropicChatBedrockApi.class) - public BedrockAnthropicChatModel anthropicChatModel(AnthropicChatBedrockApi anthropicApi, - BedrockAnthropicChatProperties properties) { - return new BedrockAnthropicChatModel(anthropicApi, properties.getOptions()); - } - -} diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/anthropic/BedrockAnthropicChatProperties.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/anthropic/BedrockAnthropicChatProperties.java deleted file mode 100644 index c9f3d7971e9..00000000000 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/anthropic/BedrockAnthropicChatProperties.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.autoconfigure.bedrock.anthropic; - -import java.util.List; - -import org.springframework.ai.bedrock.anthropic.AnthropicChatOptions; -import org.springframework.ai.bedrock.anthropic.api.AnthropicChatBedrockApi.AnthropicChatModel; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.context.properties.NestedConfigurationProperty; -import org.springframework.util.Assert; - -/** - * Configuration properties for Bedrock Anthropic. - * - * @author Christian Tzolov - * @since 0.8.0 - */ -@ConfigurationProperties(BedrockAnthropicChatProperties.CONFIG_PREFIX) -public class BedrockAnthropicChatProperties { - - public static final String CONFIG_PREFIX = "spring.ai.bedrock.anthropic.chat"; - - /** - * Enable Bedrock Anthropic chat model. Disabled by default. - */ - private boolean enabled = false; - - /** - * The generative id to use. See the {@link AnthropicChatModel} for the supported - * models. - */ - private String model = AnthropicChatModel.CLAUDE_V2.id(); - - @NestedConfigurationProperty - private AnthropicChatOptions options = AnthropicChatOptions.builder() - .temperature(0.7) - .maxTokensToSample(300) - .topK(10) - .stopSequences(List.of("\n\nHuman:")) - .build(); - - public boolean isEnabled() { - return this.enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public String getModel() { - return this.model; - } - - public void setModel(String model) { - this.model = model; - } - - public AnthropicChatOptions getOptions() { - return this.options; - } - - public void setOptions(AnthropicChatOptions options) { - Assert.notNull(options, "AnthropicChatOptions must not be null"); - Assert.notNull(options.getTemperature(), "AnthropicChatOptions.temperature must not be null"); - - this.options = options; - } - -} diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/anthropic3/BedrockAnthropic3ChatAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/anthropic3/BedrockAnthropic3ChatAutoConfiguration.java deleted file mode 100644 index f385c18acef..00000000000 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/anthropic3/BedrockAnthropic3ChatAutoConfiguration.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.autoconfigure.bedrock.anthropic3; - -import com.fasterxml.jackson.databind.ObjectMapper; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; -import software.amazon.awssdk.regions.providers.AwsRegionProvider; - -import org.springframework.ai.autoconfigure.bedrock.BedrockAwsConnectionConfiguration; -import org.springframework.ai.autoconfigure.bedrock.BedrockAwsConnectionProperties; -import org.springframework.ai.bedrock.anthropic3.BedrockAnthropic3ChatModel; -import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi; -import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Import; - -/** - * {@link AutoConfiguration Auto-configuration} for Bedrock Anthropic Chat Client. - * - * Leverages the Spring Cloud AWS to resolve the {@link AwsCredentialsProvider}. - * - * @author Christian Tzolov - * @author Wei Jiang - * @since 0.8.0 - */ -@AutoConfiguration -@ConditionalOnClass(Anthropic3ChatBedrockApi.class) -@EnableConfigurationProperties({ BedrockAnthropic3ChatProperties.class, BedrockAwsConnectionProperties.class }) -@ConditionalOnProperty(prefix = BedrockAnthropic3ChatProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true") -@Import(BedrockAwsConnectionConfiguration.class) -public class BedrockAnthropic3ChatAutoConfiguration { - - @Bean - @ConditionalOnMissingBean - @ConditionalOnBean({ AwsCredentialsProvider.class, AwsRegionProvider.class }) - public Anthropic3ChatBedrockApi anthropic3Api(AwsCredentialsProvider credentialsProvider, - AwsRegionProvider regionProvider, BedrockAnthropic3ChatProperties properties, - BedrockAwsConnectionProperties awsProperties, ObjectMapper objectMapper) { - return new Anthropic3ChatBedrockApi(properties.getModel(), credentialsProvider, regionProvider.getRegion(), - objectMapper, awsProperties.getTimeout()); - } - - @Bean - @ConditionalOnMissingBean - @ConditionalOnBean(Anthropic3ChatBedrockApi.class) - public BedrockAnthropic3ChatModel anthropic3ChatModel(Anthropic3ChatBedrockApi anthropicApi, - BedrockAnthropic3ChatProperties properties) { - return new BedrockAnthropic3ChatModel(anthropicApi, properties.getOptions()); - } - -} diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/anthropic3/BedrockAnthropic3ChatProperties.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/anthropic3/BedrockAnthropic3ChatProperties.java deleted file mode 100644 index 4feb0fb7de5..00000000000 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/anthropic3/BedrockAnthropic3ChatProperties.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.autoconfigure.bedrock.anthropic3; - -import org.springframework.ai.bedrock.anthropic3.Anthropic3ChatOptions; -import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi; -import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi.AnthropicChatModel; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.context.properties.NestedConfigurationProperty; -import org.springframework.util.Assert; - -/** - * Configuration properties for Bedrock Anthropic Claude 3. - * - * @author Christian Tzolov - * @since 1.0.0 - */ -@ConfigurationProperties(BedrockAnthropic3ChatProperties.CONFIG_PREFIX) -public class BedrockAnthropic3ChatProperties { - - public static final String CONFIG_PREFIX = "spring.ai.bedrock.anthropic3.chat"; - - /** - * Enable Bedrock Anthropic chat model. Disabled by default. - */ - private boolean enabled = false; - - /** - * The generative id to use. See the {@link AnthropicChatModel} for the supported - * models. - */ - private String model = AnthropicChatModel.CLAUDE_V3_SONNET.id(); - - @NestedConfigurationProperty - private Anthropic3ChatOptions options = Anthropic3ChatOptions.builder() - .temperature(0.7) - .maxTokens(300) - .topK(10) - .anthropicVersion(Anthropic3ChatBedrockApi.DEFAULT_ANTHROPIC_VERSION) - // .withStopSequences(List.of("\n\nHuman:")) - .build(); - - public boolean isEnabled() { - return this.enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public String getModel() { - return this.model; - } - - public void setModel(String model) { - this.model = model; - } - - public Anthropic3ChatOptions getOptions() { - return this.options; - } - - public void setOptions(Anthropic3ChatOptions options) { - Assert.notNull(options, "Anthropic3ChatOptions must not be null"); - Assert.notNull(options.getTemperature(), "Anthropic3ChatOptions.temperature must not be null"); - - this.options = options; - } - -} diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/cohere/BedrockCohereChatAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/cohere/BedrockCohereChatAutoConfiguration.java deleted file mode 100644 index 95e1a18964f..00000000000 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/cohere/BedrockCohereChatAutoConfiguration.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.autoconfigure.bedrock.cohere; - -import com.fasterxml.jackson.databind.ObjectMapper; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; -import software.amazon.awssdk.regions.providers.AwsRegionProvider; - -import org.springframework.ai.autoconfigure.bedrock.BedrockAwsConnectionConfiguration; -import org.springframework.ai.autoconfigure.bedrock.BedrockAwsConnectionProperties; -import org.springframework.ai.bedrock.cohere.BedrockCohereChatModel; -import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi; -import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Import; - -/** - * {@link AutoConfiguration Auto-configuration} for Bedrock Cohere Chat Client. - * - * @author Christian Tzolov - * @author Wei Jiang - * @since 0.8.0 - */ -@AutoConfiguration -@ConditionalOnClass(CohereChatBedrockApi.class) -@EnableConfigurationProperties({ BedrockCohereChatProperties.class, BedrockAwsConnectionProperties.class }) -@ConditionalOnProperty(prefix = BedrockCohereChatProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true") -@Import(BedrockAwsConnectionConfiguration.class) -public class BedrockCohereChatAutoConfiguration { - - @Bean - @ConditionalOnMissingBean - @ConditionalOnBean({ AwsCredentialsProvider.class, AwsRegionProvider.class }) - public CohereChatBedrockApi cohereChatApi(AwsCredentialsProvider credentialsProvider, - AwsRegionProvider regionProvider, BedrockCohereChatProperties properties, - BedrockAwsConnectionProperties awsProperties, ObjectMapper objectMapper) { - return new CohereChatBedrockApi(properties.getModel(), credentialsProvider, regionProvider.getRegion(), - objectMapper, awsProperties.getTimeout()); - } - - @Bean - @ConditionalOnMissingBean - @ConditionalOnBean(CohereChatBedrockApi.class) - public BedrockCohereChatModel cohereChatModel(CohereChatBedrockApi cohereChatApi, - BedrockCohereChatProperties properties) { - - return new BedrockCohereChatModel(cohereChatApi, properties.getOptions()); - } - -} diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/cohere/BedrockCohereChatProperties.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/cohere/BedrockCohereChatProperties.java deleted file mode 100644 index 723c91ef228..00000000000 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/cohere/BedrockCohereChatProperties.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.autoconfigure.bedrock.cohere; - -import org.springframework.ai.bedrock.cohere.BedrockCohereChatOptions; -import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.context.properties.NestedConfigurationProperty; - -/** - * Bedrock Cohere Chat autoconfiguration properties. - * - * @author Christian Tzolov - * @since 0.8.0 - */ -@ConfigurationProperties(BedrockCohereChatProperties.CONFIG_PREFIX) -public class BedrockCohereChatProperties { - - public static final String CONFIG_PREFIX = "spring.ai.bedrock.cohere.chat"; - - /** - * Enable Bedrock Cohere Chat Client. False by default. - */ - private boolean enabled = false; - - /** - * Bedrock Cohere Chat generative name. Defaults to 'cohere-command-v14'. - */ - private String model = CohereChatBedrockApi.CohereChatModel.COHERE_COMMAND_V14.id(); - - @NestedConfigurationProperty - private BedrockCohereChatOptions options = BedrockCohereChatOptions.builder().build(); - - public boolean isEnabled() { - return this.enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public String getModel() { - return this.model; - } - - public void setModel(String model) { - this.model = model; - } - - public BedrockCohereChatOptions getOptions() { - return this.options; - } - - public void setOptions(BedrockCohereChatOptions options) { - this.options = options; - } - -} diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/jurrasic2/BedrockAi21Jurassic2ChatAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/jurrasic2/BedrockAi21Jurassic2ChatAutoConfiguration.java deleted file mode 100644 index b84fbb11279..00000000000 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/jurrasic2/BedrockAi21Jurassic2ChatAutoConfiguration.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.autoconfigure.bedrock.jurrasic2; - -import com.fasterxml.jackson.databind.ObjectMapper; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; -import software.amazon.awssdk.regions.providers.AwsRegionProvider; - -import org.springframework.ai.autoconfigure.bedrock.BedrockAwsConnectionConfiguration; -import org.springframework.ai.autoconfigure.bedrock.BedrockAwsConnectionProperties; -import org.springframework.ai.bedrock.jurassic2.BedrockAi21Jurassic2ChatModel; -import org.springframework.ai.bedrock.jurassic2.api.Ai21Jurassic2ChatBedrockApi; -import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Import; - -/** - * {@link AutoConfiguration Auto-configuration} for Bedrock Jurassic2 Chat Client. - * - * @author Ahmed Yousri - * @author Wei Jiang - * @since 1.0.0 - */ -@AutoConfiguration -@ConditionalOnClass(Ai21Jurassic2ChatBedrockApi.class) -@EnableConfigurationProperties({ BedrockAi21Jurassic2ChatProperties.class, BedrockAwsConnectionProperties.class }) -@ConditionalOnProperty(prefix = BedrockAi21Jurassic2ChatProperties.CONFIG_PREFIX, name = "enabled", - havingValue = "true") -@Import(BedrockAwsConnectionConfiguration.class) -public class BedrockAi21Jurassic2ChatAutoConfiguration { - - @Bean - @ConditionalOnMissingBean - @ConditionalOnBean({ AwsCredentialsProvider.class, AwsRegionProvider.class }) - public Ai21Jurassic2ChatBedrockApi ai21Jurassic2ChatBedrockApi(AwsCredentialsProvider credentialsProvider, - AwsRegionProvider regionProvider, BedrockAi21Jurassic2ChatProperties properties, - BedrockAwsConnectionProperties awsProperties, ObjectMapper objectMapper) { - return new Ai21Jurassic2ChatBedrockApi(properties.getModel(), credentialsProvider, regionProvider.getRegion(), - objectMapper, awsProperties.getTimeout()); - } - - @Bean - @ConditionalOnMissingBean - @ConditionalOnBean(Ai21Jurassic2ChatBedrockApi.class) - public BedrockAi21Jurassic2ChatModel jurassic2ChatModel(Ai21Jurassic2ChatBedrockApi ai21Jurassic2ChatBedrockApi, - BedrockAi21Jurassic2ChatProperties properties) { - - return BedrockAi21Jurassic2ChatModel.builder(ai21Jurassic2ChatBedrockApi) - .withOptions(properties.getOptions()) - .build(); - } - -} diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/jurrasic2/BedrockAi21Jurassic2ChatProperties.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/jurrasic2/BedrockAi21Jurassic2ChatProperties.java deleted file mode 100644 index 6c6b0ffed2e..00000000000 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/jurrasic2/BedrockAi21Jurassic2ChatProperties.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.autoconfigure.bedrock.jurrasic2; - -import org.springframework.ai.bedrock.jurassic2.BedrockAi21Jurassic2ChatOptions; -import org.springframework.ai.bedrock.jurassic2.api.Ai21Jurassic2ChatBedrockApi.Ai21Jurassic2ChatModel; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.context.properties.NestedConfigurationProperty; - -/** - * Configuration properties for Bedrock Ai21Jurassic2. - * - * @author Ahmed Yousri - * @since 1.0.0 - */ -@ConfigurationProperties(BedrockAi21Jurassic2ChatProperties.CONFIG_PREFIX) -public class BedrockAi21Jurassic2ChatProperties { - - public static final String CONFIG_PREFIX = "spring.ai.bedrock.jurassic2.chat"; - - /** - * Enable Bedrock Ai21Jurassic2 chat model. Disabled by default. - */ - private boolean enabled = false; - - /** - * The generative id to use. See the {@link Ai21Jurassic2ChatModel} for the supported - * models. - */ - private String model = Ai21Jurassic2ChatModel.AI21_J2_MID_V1.id(); - - @NestedConfigurationProperty - private BedrockAi21Jurassic2ChatOptions options = BedrockAi21Jurassic2ChatOptions.builder() - .temperature(0.7) - .maxTokens(500) - .build(); - - public boolean isEnabled() { - return this.enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public String getModel() { - return this.model; - } - - public void setModel(String model) { - this.model = model; - } - - public BedrockAi21Jurassic2ChatOptions getOptions() { - return this.options; - } - - public void setOptions(BedrockAi21Jurassic2ChatOptions options) { - this.options = options; - } - -} diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/llama/BedrockLlamaChatAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/llama/BedrockLlamaChatAutoConfiguration.java deleted file mode 100644 index b97204ea35d..00000000000 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/llama/BedrockLlamaChatAutoConfiguration.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.autoconfigure.bedrock.llama; - -import com.fasterxml.jackson.databind.ObjectMapper; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; -import software.amazon.awssdk.regions.providers.AwsRegionProvider; - -import org.springframework.ai.autoconfigure.bedrock.BedrockAwsConnectionConfiguration; -import org.springframework.ai.autoconfigure.bedrock.BedrockAwsConnectionProperties; -import org.springframework.ai.bedrock.llama.BedrockLlamaChatModel; -import org.springframework.ai.bedrock.llama.api.LlamaChatBedrockApi; -import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Import; - -/** - * {@link AutoConfiguration Auto-configuration} for Bedrock Llama Chat Client. - * - * Leverages the Spring Cloud AWS to resolve the {@link AwsCredentialsProvider}. - * - * @author Christian Tzolov - * @author Wei Jiang - * @since 0.8.0 - */ -@AutoConfiguration -@ConditionalOnClass(LlamaChatBedrockApi.class) -@EnableConfigurationProperties({ BedrockLlamaChatProperties.class, BedrockAwsConnectionProperties.class }) -@ConditionalOnProperty(prefix = BedrockLlamaChatProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true") -@Import(BedrockAwsConnectionConfiguration.class) -public class BedrockLlamaChatAutoConfiguration { - - @Bean - @ConditionalOnMissingBean - @ConditionalOnBean({ AwsCredentialsProvider.class, AwsRegionProvider.class }) - public LlamaChatBedrockApi llamaApi(AwsCredentialsProvider credentialsProvider, AwsRegionProvider regionProvider, - BedrockLlamaChatProperties properties, BedrockAwsConnectionProperties awsProperties, - ObjectMapper objectMapper) { - return new LlamaChatBedrockApi(properties.getModel(), credentialsProvider, regionProvider.getRegion(), - objectMapper, awsProperties.getTimeout()); - } - - @Bean - @ConditionalOnMissingBean - @ConditionalOnBean(LlamaChatBedrockApi.class) - public BedrockLlamaChatModel llamaChatModel(LlamaChatBedrockApi llamaApi, BedrockLlamaChatProperties properties) { - - return new BedrockLlamaChatModel(llamaApi, properties.getOptions()); - } - -} diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/llama/BedrockLlamaChatProperties.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/llama/BedrockLlamaChatProperties.java deleted file mode 100644 index 29d367c8e18..00000000000 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/llama/BedrockLlamaChatProperties.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.autoconfigure.bedrock.llama; - -import org.springframework.ai.bedrock.llama.BedrockLlamaChatOptions; -import org.springframework.ai.bedrock.llama.api.LlamaChatBedrockApi.LlamaChatModel; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.context.properties.NestedConfigurationProperty; - -/** - * Configuration properties for Bedrock Llama. - * - * @author Christian Tzolov - * @since 0.8.0 - */ -@ConfigurationProperties(BedrockLlamaChatProperties.CONFIG_PREFIX) -public class BedrockLlamaChatProperties { - - public static final String CONFIG_PREFIX = "spring.ai.bedrock.llama.chat"; - - /** - * Enable Bedrock Llama chat model. Disabled by default. - */ - private boolean enabled = false; - - /** - * The generative id to use. See the {@link LlamaChatModel} for the supported models. - */ - private String model = LlamaChatModel.LLAMA3_70B_INSTRUCT_V1.id(); - - @NestedConfigurationProperty - private BedrockLlamaChatOptions options = BedrockLlamaChatOptions.builder().temperature(0.7).maxGenLen(300).build(); - - public boolean isEnabled() { - return this.enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public String getModel() { - return this.model; - } - - public void setModel(String model) { - this.model = model; - } - - public BedrockLlamaChatOptions getOptions() { - return this.options; - } - - public void setOptions(BedrockLlamaChatOptions options) { - this.options = options; - } - -} diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/titan/BedrockTitanChatAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/titan/BedrockTitanChatAutoConfiguration.java deleted file mode 100644 index c6b0e19ae99..00000000000 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/titan/BedrockTitanChatAutoConfiguration.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.autoconfigure.bedrock.titan; - -import com.fasterxml.jackson.databind.ObjectMapper; -import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; -import software.amazon.awssdk.regions.providers.AwsRegionProvider; - -import org.springframework.ai.autoconfigure.bedrock.BedrockAwsConnectionConfiguration; -import org.springframework.ai.autoconfigure.bedrock.BedrockAwsConnectionProperties; -import org.springframework.ai.bedrock.titan.BedrockTitanChatModel; -import org.springframework.ai.bedrock.titan.api.TitanChatBedrockApi; -import org.springframework.boot.autoconfigure.AutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Import; - -/** - * {@link AutoConfiguration Auto-configuration} for Bedrock Titan Chat Client. - * - * @author Christian Tzolov - * @author Wei Jiang - * @since 0.8.0 - */ -@AutoConfiguration -@ConditionalOnClass(TitanChatBedrockApi.class) -@EnableConfigurationProperties({ BedrockTitanChatProperties.class, BedrockAwsConnectionProperties.class }) -@ConditionalOnProperty(prefix = BedrockTitanChatProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true") -@Import(BedrockAwsConnectionConfiguration.class) -public class BedrockTitanChatAutoConfiguration { - - @Bean - @ConditionalOnMissingBean - @ConditionalOnBean({ AwsCredentialsProvider.class, AwsRegionProvider.class }) - public TitanChatBedrockApi titanChatBedrockApi(AwsCredentialsProvider credentialsProvider, - AwsRegionProvider regionProvider, BedrockTitanChatProperties properties, - BedrockAwsConnectionProperties awsProperties, ObjectMapper objectMapper) { - return new TitanChatBedrockApi(properties.getModel(), credentialsProvider, regionProvider.getRegion(), - objectMapper, awsProperties.getTimeout()); - } - - @Bean - @ConditionalOnBean(TitanChatBedrockApi.class) - public BedrockTitanChatModel titanChatModel(TitanChatBedrockApi titanChatApi, - BedrockTitanChatProperties properties) { - - return new BedrockTitanChatModel(titanChatApi, properties.getOptions()); - } - -} diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/titan/BedrockTitanChatProperties.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/titan/BedrockTitanChatProperties.java deleted file mode 100644 index d54327a6d88..00000000000 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/titan/BedrockTitanChatProperties.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.autoconfigure.bedrock.titan; - -import org.springframework.ai.bedrock.titan.BedrockTitanChatOptions; -import org.springframework.ai.bedrock.titan.api.TitanChatBedrockApi.TitanChatModel; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.boot.context.properties.NestedConfigurationProperty; - -/** - * Bedrock Titan Chat autoconfiguration properties. - * - * @author Christian Tzolov - * @since 0.8.0 - */ -@ConfigurationProperties(BedrockTitanChatProperties.CONFIG_PREFIX) -public class BedrockTitanChatProperties { - - public static final String CONFIG_PREFIX = "spring.ai.bedrock.titan.chat"; - - /** - * Enable Bedrock Titan Chat Client. False by default. - */ - private boolean enabled = false; - - /** - * Bedrock Titan Chat generative name. Defaults to 'amazon.titan-text-express-v1'. - */ - private String model = TitanChatModel.TITAN_TEXT_EXPRESS_V1.id(); - - @NestedConfigurationProperty - private BedrockTitanChatOptions options = BedrockTitanChatOptions.builder().withTemperature(0.7).build(); - - public boolean isEnabled() { - return this.enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - public String getModel() { - return this.model; - } - - public void setModel(String model) { - this.model = model; - } - - public BedrockTitanChatOptions getOptions() { - return this.options; - } - - public void setOptions(BedrockTitanChatOptions options) { - this.options = options; - } - -} diff --git a/spring-ai-spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/spring-ai-spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index f3e5633efc0..022b4a8b5e7 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/spring-ai-spring-boot-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -21,13 +21,7 @@ org.springframework.ai.autoconfigure.stabilityai.StabilityAiImageAutoConfigurati org.springframework.ai.autoconfigure.transformers.TransformersEmbeddingModelAutoConfiguration org.springframework.ai.autoconfigure.huggingface.HuggingfaceChatAutoConfiguration org.springframework.ai.autoconfigure.vertexai.gemini.VertexAiGeminiAutoConfiguration -org.springframework.ai.autoconfigure.bedrock.jurrasic2.BedrockAi21Jurassic2ChatAutoConfiguration -org.springframework.ai.autoconfigure.bedrock.llama.BedrockLlamaChatAutoConfiguration -org.springframework.ai.autoconfigure.bedrock.cohere.BedrockCohereChatAutoConfiguration org.springframework.ai.autoconfigure.bedrock.cohere.BedrockCohereEmbeddingAutoConfiguration -org.springframework.ai.autoconfigure.bedrock.anthropic.BedrockAnthropicChatAutoConfiguration -org.springframework.ai.autoconfigure.bedrock.anthropic3.BedrockAnthropic3ChatAutoConfiguration -org.springframework.ai.autoconfigure.bedrock.titan.BedrockTitanChatAutoConfiguration org.springframework.ai.autoconfigure.bedrock.titan.BedrockTitanEmbeddingAutoConfiguration org.springframework.ai.autoconfigure.bedrock.converse.BedrockConverseProxyChatAutoConfiguration org.springframework.ai.autoconfigure.chat.observation.ChatObservationAutoConfiguration diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/anthropic/BedrockAnthropicChatAutoConfigurationIT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/anthropic/BedrockAnthropicChatAutoConfigurationIT.java deleted file mode 100644 index c20e3cf2ef9..00000000000 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/anthropic/BedrockAnthropicChatAutoConfigurationIT.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.autoconfigure.bedrock.anthropic; - -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import org.junit.jupiter.api.Test; -import reactor.core.publisher.Flux; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.autoconfigure.bedrock.BedrockAwsConnectionProperties; -import org.springframework.ai.autoconfigure.bedrock.BedrockTestUtils; -import org.springframework.ai.autoconfigure.bedrock.RequiresAwsCredentials; -import org.springframework.ai.bedrock.anthropic.BedrockAnthropicChatModel; -import org.springframework.ai.bedrock.anthropic.api.AnthropicChatBedrockApi.AnthropicChatModel; -import org.springframework.ai.chat.messages.AssistantMessage; -import org.springframework.ai.chat.messages.Message; -import org.springframework.ai.chat.messages.UserMessage; -import org.springframework.ai.chat.model.ChatResponse; -import org.springframework.ai.chat.model.Generation; -import org.springframework.ai.chat.prompt.Prompt; -import org.springframework.ai.chat.prompt.SystemPromptTemplate; -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.AssertionsForClassTypes.within; - -/** - * @author Christian Tzolov - * @author Mark Pollack - * @since 1.0.0 - */ -@RequiresAwsCredentials -public class BedrockAnthropicChatAutoConfigurationIT { - - private final ApplicationContextRunner contextRunner = BedrockTestUtils.getContextRunner() - .withPropertyValues("spring.ai.bedrock.anthropic.chat.enabled=true", - "spring.ai.bedrock.anthropic.chat.model=" + AnthropicChatModel.CLAUDE_V2.id(), - "spring.ai.bedrock.anthropic.chat.options.temperature=0.5") - .withConfiguration(AutoConfigurations.of(BedrockAnthropicChatAutoConfiguration.class)); - - private final Message systemMessage = new SystemPromptTemplate(""" - You are a helpful AI assistant. Your name is {name}. - You are an AI assistant that helps people find information. - Your name is {name} - You should reply to the user's request with your name and also in the style of a {voice}. - """).createMessage(Map.of("name", "Bob", "voice", "pirate")); - - private final UserMessage userMessage = new UserMessage( - "Tell me about 3 famous pirates from the Golden Age of Piracy and why they did."); - - @Test - public void chatCompletion() { - this.contextRunner.run(context -> { - BedrockAnthropicChatModel anthropicChatModel = context.getBean(BedrockAnthropicChatModel.class); - ChatResponse response = anthropicChatModel.call(new Prompt(List.of(this.userMessage, this.systemMessage))); - assertThat(response.getResult().getOutput().getText()).contains("Blackbeard"); - }); - } - - @Test - public void chatCompletionStreaming() { - this.contextRunner.run(context -> { - - BedrockAnthropicChatModel anthropicChatModel = context.getBean(BedrockAnthropicChatModel.class); - - Flux response = anthropicChatModel - .stream(new Prompt(List.of(this.userMessage, this.systemMessage))); - - List responses = response.collectList().block(); - assertThat(responses.size()).isGreaterThan(2); - - String stitchedResponseContent = responses.stream() - .map(ChatResponse::getResults) - .flatMap(List::stream) - .map(Generation::getOutput) - .map(AssistantMessage::getText) - .collect(Collectors.joining()); - - assertThat(stitchedResponseContent).contains("Blackbeard"); - }); - } - - @Test - public void propertiesTest() { - - BedrockTestUtils.getContextRunnerWithUserConfiguration() - .withPropertyValues("spring.ai.bedrock.anthropic.chat.enabled=true", - "spring.ai.bedrock.aws.access-key=ACCESS_KEY", "spring.ai.bedrock.aws.secret-key=SECRET_KEY", - "spring.ai.bedrock.anthropic.chat.model=MODEL_XYZ", - "spring.ai.bedrock.aws.region=" + Region.US_EAST_1.id(), - "spring.ai.bedrock.anthropic.chat.options.temperature=0.55") - .withConfiguration(AutoConfigurations.of(BedrockAnthropicChatAutoConfiguration.class)) - .run(context -> { - var anthropicChatProperties = context.getBean(BedrockAnthropicChatProperties.class); - var awsProperties = context.getBean(BedrockAwsConnectionProperties.class); - - assertThat(anthropicChatProperties.isEnabled()).isTrue(); - assertThat(awsProperties.getRegion()).isEqualTo(Region.US_EAST_1.id()); - - assertThat(anthropicChatProperties.getOptions().getTemperature()).isCloseTo(0.55, within(0.0001)); - assertThat(anthropicChatProperties.getModel()).isEqualTo("MODEL_XYZ"); - - assertThat(awsProperties.getAccessKey()).isEqualTo("ACCESS_KEY"); - assertThat(awsProperties.getSecretKey()).isEqualTo("SECRET_KEY"); - }); - } - - @Test - public void chatCompletionDisabled() { - - // It is disabled by default - BedrockTestUtils.getContextRunnerWithUserConfiguration() - .withConfiguration(AutoConfigurations.of(BedrockAnthropicChatAutoConfiguration.class)) - .run(context -> { - assertThat(context.getBeansOfType(BedrockAnthropicChatProperties.class)).isEmpty(); - assertThat(context.getBeansOfType(BedrockAnthropicChatModel.class)).isEmpty(); - }); - - // Explicitly enable the chat auto-configuration. - BedrockTestUtils.getContextRunnerWithUserConfiguration() - .withPropertyValues("spring.ai.bedrock.anthropic.chat.enabled=true") - .withConfiguration(AutoConfigurations.of(BedrockAnthropicChatAutoConfiguration.class)) - .run(context -> { - assertThat(context.getBeansOfType(BedrockAnthropicChatProperties.class)).isNotEmpty(); - assertThat(context.getBeansOfType(BedrockAnthropicChatModel.class)).isNotEmpty(); - }); - - // Explicitly disable the chat auto-configuration. - BedrockTestUtils.getContextRunnerWithUserConfiguration() - .withPropertyValues("spring.ai.bedrock.anthropic.chat.enabled=false") - .withConfiguration(AutoConfigurations.of(BedrockAnthropicChatAutoConfiguration.class)) - .run(context -> { - assertThat(context.getBeansOfType(BedrockAnthropicChatProperties.class)).isEmpty(); - assertThat(context.getBeansOfType(BedrockAnthropicChatModel.class)).isEmpty(); - }); - } - -} diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/anthropic3/BedrockAnthropic3ChatAutoConfigurationIT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/anthropic3/BedrockAnthropic3ChatAutoConfigurationIT.java deleted file mode 100644 index afdf1518a07..00000000000 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/anthropic3/BedrockAnthropic3ChatAutoConfigurationIT.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.autoconfigure.bedrock.anthropic3; - -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import org.junit.jupiter.api.Test; -import reactor.core.publisher.Flux; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.autoconfigure.bedrock.BedrockAwsConnectionProperties; -import org.springframework.ai.autoconfigure.bedrock.BedrockTestUtils; -import org.springframework.ai.autoconfigure.bedrock.RequiresAwsCredentials; -import org.springframework.ai.bedrock.anthropic3.BedrockAnthropic3ChatModel; -import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi.AnthropicChatModel; -import org.springframework.ai.chat.messages.AssistantMessage; -import org.springframework.ai.chat.messages.Message; -import org.springframework.ai.chat.messages.UserMessage; -import org.springframework.ai.chat.model.ChatResponse; -import org.springframework.ai.chat.model.Generation; -import org.springframework.ai.chat.prompt.Prompt; -import org.springframework.ai.chat.prompt.SystemPromptTemplate; -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.AssertionsForClassTypes.within; - -/** - * @author Christian Tzolov - * @since 1.0.0 - */ -@RequiresAwsCredentials -public class BedrockAnthropic3ChatAutoConfigurationIT { - - private final ApplicationContextRunner contextRunner = BedrockTestUtils.getContextRunner() - .withPropertyValues("spring.ai.bedrock.anthropic3.chat.enabled=true", - "spring.ai.bedrock.anthropic3.chat.model=" + AnthropicChatModel.CLAUDE_V3_SONNET.id(), - "spring.ai.bedrock.anthropic3.chat.options.temperature=0.5") - .withConfiguration(AutoConfigurations.of(BedrockAnthropic3ChatAutoConfiguration.class)); - - private final Message systemMessage = new SystemPromptTemplate(""" - You are a helpful AI assistant. Your name is {name}. - You are an AI assistant that helps people find information. - Your name is {name} - You should reply to the user's request with your name and also in the style of a {voice}. - """).createMessage(Map.of("name", "Bob", "voice", "pirate")); - - private final UserMessage userMessage = new UserMessage( - "Tell me about 3 famous pirates from the Golden Age of Piracy and why they did."); - - @Test - public void chatCompletion() { - this.contextRunner.run(context -> { - BedrockAnthropic3ChatModel anthropicChatModel = context.getBean(BedrockAnthropic3ChatModel.class); - ChatResponse response = anthropicChatModel.call(new Prompt(List.of(this.userMessage, this.systemMessage))); - assertThat(response.getResult().getOutput().getText()).contains("Blackbeard"); - }); - } - - @Test - public void chatCompletionStreaming() { - this.contextRunner.run(context -> { - - BedrockAnthropic3ChatModel anthropicChatModel = context.getBean(BedrockAnthropic3ChatModel.class); - - Flux response = anthropicChatModel - .stream(new Prompt(List.of(this.userMessage, this.systemMessage))); - - List responses = response.collectList().block(); - assertThat(responses.size()).isGreaterThan(2); - - String stitchedResponseContent = responses.stream() - .map(ChatResponse::getResults) - .flatMap(List::stream) - .map(Generation::getOutput) - .map(AssistantMessage::getText) - .collect(Collectors.joining()); - - assertThat(stitchedResponseContent).contains("Blackbeard"); - }); - } - - @Test - public void propertiesTest() { - - BedrockTestUtils.getContextRunnerWithUserConfiguration() - .withPropertyValues("spring.ai.bedrock.anthropic3.chat.enabled=true", - "spring.ai.bedrock.aws.access-key=ACCESS_KEY", "spring.ai.bedrock.aws.secret-key=SECRET_KEY", - "spring.ai.bedrock.anthropic3.chat.model=MODEL_XYZ", - "spring.ai.bedrock.aws.region=" + Region.US_EAST_1.id(), - "spring.ai.bedrock.anthropic3.chat.options.temperature=0.55") - .withConfiguration(AutoConfigurations.of(BedrockAnthropic3ChatAutoConfiguration.class)) - .run(context -> { - var anthropicChatProperties = context.getBean(BedrockAnthropic3ChatProperties.class); - var awsProperties = context.getBean(BedrockAwsConnectionProperties.class); - - assertThat(anthropicChatProperties.isEnabled()).isTrue(); - assertThat(awsProperties.getRegion()).isEqualTo(Region.US_EAST_1.id()); - - assertThat(anthropicChatProperties.getOptions().getTemperature()).isCloseTo(0.55, within(0.0001)); - assertThat(anthropicChatProperties.getModel()).isEqualTo("MODEL_XYZ"); - - assertThat(awsProperties.getAccessKey()).isEqualTo("ACCESS_KEY"); - assertThat(awsProperties.getSecretKey()).isEqualTo("SECRET_KEY"); - }); - } - - @Test - public void chatCompletionDisabled() { - - // It is disabled by default - BedrockTestUtils.getContextRunnerWithUserConfiguration() - .withConfiguration(AutoConfigurations.of(BedrockAnthropic3ChatAutoConfiguration.class)) - - .run(context -> { - assertThat(context.getBeansOfType(BedrockAnthropic3ChatProperties.class)).isEmpty(); - assertThat(context.getBeansOfType(BedrockAnthropic3ChatModel.class)).isEmpty(); - }); - - // Explicitly enable the chat auto-configuration. - BedrockTestUtils.getContextRunnerWithUserConfiguration() - .withPropertyValues("spring.ai.bedrock.anthropic3.chat.enabled=true") - .withConfiguration(AutoConfigurations.of(BedrockAnthropic3ChatAutoConfiguration.class)) - .run(context -> { - assertThat(context.getBeansOfType(BedrockAnthropic3ChatProperties.class)).isNotEmpty(); - assertThat(context.getBeansOfType(BedrockAnthropic3ChatModel.class)).isNotEmpty(); - }); - - // Explicitly disable the chat auto-configuration. - BedrockTestUtils.getContextRunnerWithUserConfiguration() - .withPropertyValues("spring.ai.bedrock.anthropic3.chat.enabled=false") - .withConfiguration(AutoConfigurations.of(BedrockAnthropic3ChatAutoConfiguration.class)) - .run(context -> { - assertThat(context.getBeansOfType(BedrockAnthropic3ChatProperties.class)).isEmpty(); - assertThat(context.getBeansOfType(BedrockAnthropic3ChatModel.class)).isEmpty(); - }); - } - -} diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/cohere/BedrockCohereChatAutoConfigurationIT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/cohere/BedrockCohereChatAutoConfigurationIT.java deleted file mode 100644 index 890286312c6..00000000000 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/cohere/BedrockCohereChatAutoConfigurationIT.java +++ /dev/null @@ -1,172 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.autoconfigure.bedrock.cohere; - -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import org.junit.jupiter.api.Test; -import reactor.core.publisher.Flux; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.autoconfigure.bedrock.BedrockAwsConnectionProperties; -import org.springframework.ai.autoconfigure.bedrock.BedrockTestUtils; -import org.springframework.ai.autoconfigure.bedrock.RequiresAwsCredentials; -import org.springframework.ai.bedrock.cohere.BedrockCohereChatModel; -import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi.CohereChatModel; -import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi.CohereChatRequest.ReturnLikelihoods; -import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi.CohereChatRequest.Truncate; -import org.springframework.ai.chat.messages.AssistantMessage; -import org.springframework.ai.chat.messages.Message; -import org.springframework.ai.chat.messages.UserMessage; -import org.springframework.ai.chat.model.ChatResponse; -import org.springframework.ai.chat.model.Generation; -import org.springframework.ai.chat.prompt.Prompt; -import org.springframework.ai.chat.prompt.SystemPromptTemplate; -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.AssertionsForClassTypes.within; - -/** - * @author Christian Tzolov - * @author Mark Pollack - * @since 1.0.0 - */ -@RequiresAwsCredentials -public class BedrockCohereChatAutoConfigurationIT { - - private final ApplicationContextRunner contextRunner = BedrockTestUtils.getContextRunner() - .withPropertyValues("spring.ai.bedrock.cohere.chat.enabled=true", - "spring.ai.bedrock.cohere.chat.model=" + CohereChatModel.COHERE_COMMAND_V14.id(), - "spring.ai.bedrock.cohere.chat.options.temperature=0.5", - "spring.ai.bedrock.cohere.chat.options.maxTokens=500") - .withConfiguration(AutoConfigurations.of(BedrockCohereChatAutoConfiguration.class)); - - private final Message systemMessage = new SystemPromptTemplate(""" - You are a helpful AI assistant. Your name is {name}. - You are an AI assistant that helps people find information. - Your name is {name} - You should reply to the user's request with your name and also in the style of a {voice}. - """).createMessage(Map.of("name", "Bob", "voice", "pirate")); - - private final UserMessage userMessage = new UserMessage( - "Tell me about 3 famous pirates from the Golden Age of Piracy and why they did."); - - @Test - public void chatCompletion() { - this.contextRunner.run(context -> { - BedrockCohereChatModel cohereChatModel = context.getBean(BedrockCohereChatModel.class); - ChatResponse response = cohereChatModel.call(new Prompt(List.of(this.userMessage, this.systemMessage))); - assertThat(response.getResult().getOutput().getText()).contains("Blackbeard"); - }); - } - - @Test - public void chatCompletionStreaming() { - this.contextRunner.run(context -> { - - BedrockCohereChatModel cohereChatModel = context.getBean(BedrockCohereChatModel.class); - - Flux response = cohereChatModel - .stream(new Prompt(List.of(this.userMessage, this.systemMessage))); - - List responses = response.collectList().block(); - assertThat(responses.size()).isGreaterThan(2); - - String stitchedResponseContent = responses.stream() - .map(ChatResponse::getResults) - .flatMap(List::stream) - .map(Generation::getOutput) - .map(AssistantMessage::getText) - .collect(Collectors.joining()); - - assertThat(stitchedResponseContent).contains("Blackbeard"); - }); - } - - @Test - public void propertiesTest() { - - BedrockTestUtils.getContextRunnerWithUserConfiguration() - .withPropertyValues("spring.ai.bedrock.cohere.chat.enabled=true", - "spring.ai.bedrock.aws.access-key=ACCESS_KEY", "spring.ai.bedrock.aws.secret-key=SECRET_KEY", - "spring.ai.bedrock.cohere.chat.model=MODEL_XYZ", - "spring.ai.bedrock.aws.region=" + Region.US_EAST_1.id(), - "spring.ai.bedrock.cohere.chat.options.temperature=0.55", - "spring.ai.bedrock.cohere.chat.options.topP=0.55", "spring.ai.bedrock.cohere.chat.options.topK=10", - "spring.ai.bedrock.cohere.chat.options.stopSequences=END1,END2", - "spring.ai.bedrock.cohere.chat.options.returnLikelihoods=ALL", - "spring.ai.bedrock.cohere.chat.options.numGenerations=3", - "spring.ai.bedrock.cohere.chat.options.truncate=START", - "spring.ai.bedrock.cohere.chat.options.maxTokens=123") - .withConfiguration(AutoConfigurations.of(BedrockCohereChatAutoConfiguration.class)) - .run(context -> { - var chatProperties = context.getBean(BedrockCohereChatProperties.class); - var aswProperties = context.getBean(BedrockAwsConnectionProperties.class); - - assertThat(chatProperties.isEnabled()).isTrue(); - assertThat(aswProperties.getRegion()).isEqualTo(Region.US_EAST_1.id()); - assertThat(chatProperties.getModel()).isEqualTo("MODEL_XYZ"); - - assertThat(chatProperties.getOptions().getTemperature()).isCloseTo(0.55, within(0.0001)); - assertThat(chatProperties.getOptions().getTopP()).isCloseTo(0.55, within(0.0001)); - assertThat(chatProperties.getOptions().getTopK()).isEqualTo(10); - assertThat(chatProperties.getOptions().getStopSequences()).isEqualTo(List.of("END1", "END2")); - assertThat(chatProperties.getOptions().getReturnLikelihoods()).isEqualTo(ReturnLikelihoods.ALL); - assertThat(chatProperties.getOptions().getNumGenerations()).isEqualTo(3); - assertThat(chatProperties.getOptions().getTruncate()).isEqualTo(Truncate.START); - assertThat(chatProperties.getOptions().getMaxTokens()).isEqualTo(123); - - assertThat(aswProperties.getAccessKey()).isEqualTo("ACCESS_KEY"); - assertThat(aswProperties.getSecretKey()).isEqualTo("SECRET_KEY"); - }); - } - - @Test - public void chatCompletionDisabled() { - - // It is disabled by default - BedrockTestUtils.getContextRunner() - .withConfiguration(AutoConfigurations.of(BedrockCohereChatAutoConfiguration.class)) - .run(context -> { - assertThat(context.getBeansOfType(BedrockCohereChatProperties.class)).isEmpty(); - assertThat(context.getBeansOfType(BedrockCohereChatModel.class)).isEmpty(); - }); - - // Explicitly enable the chat auto-configuration. - BedrockTestUtils.getContextRunner() - .withPropertyValues("spring.ai.bedrock.cohere.chat.enabled=true") - .withConfiguration(AutoConfigurations.of(BedrockCohereChatAutoConfiguration.class)) - .run(context -> { - assertThat(context.getBeansOfType(BedrockCohereChatProperties.class)).isNotEmpty(); - assertThat(context.getBeansOfType(BedrockCohereChatModel.class)).isNotEmpty(); - }); - - // Explicitly disable the chat auto-configuration. - BedrockTestUtils.getContextRunner() - .withPropertyValues("spring.ai.bedrock.cohere.chat.enabled=false") - .withConfiguration(AutoConfigurations.of(BedrockCohereChatAutoConfiguration.class)) - .run(context -> { - assertThat(context.getBeansOfType(BedrockCohereChatProperties.class)).isEmpty(); - assertThat(context.getBeansOfType(BedrockCohereChatModel.class)).isEmpty(); - }); - } - -} diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/jurassic2/BedrockAi21Jurassic2ChatAutoConfigurationIT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/jurassic2/BedrockAi21Jurassic2ChatAutoConfigurationIT.java deleted file mode 100644 index 2e1eeb59b7c..00000000000 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/jurassic2/BedrockAi21Jurassic2ChatAutoConfigurationIT.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.autoconfigure.bedrock.jurassic2; - -import java.util.List; -import java.util.Map; - -import org.junit.jupiter.api.Test; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.autoconfigure.bedrock.BedrockAwsConnectionProperties; -import org.springframework.ai.autoconfigure.bedrock.BedrockTestUtils; -import org.springframework.ai.autoconfigure.bedrock.RequiresAwsCredentials; -import org.springframework.ai.autoconfigure.bedrock.jurrasic2.BedrockAi21Jurassic2ChatAutoConfiguration; -import org.springframework.ai.autoconfigure.bedrock.jurrasic2.BedrockAi21Jurassic2ChatProperties; -import org.springframework.ai.bedrock.jurassic2.BedrockAi21Jurassic2ChatModel; -import org.springframework.ai.bedrock.jurassic2.api.Ai21Jurassic2ChatBedrockApi; -import org.springframework.ai.chat.messages.Message; -import org.springframework.ai.chat.messages.UserMessage; -import org.springframework.ai.chat.model.ChatResponse; -import org.springframework.ai.chat.prompt.Prompt; -import org.springframework.ai.chat.prompt.SystemPromptTemplate; -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.AssertionsForClassTypes.within; - -/** - * @author Ahmed Yousri - * @since 1.0.0 - */ -@RequiresAwsCredentials -public class BedrockAi21Jurassic2ChatAutoConfigurationIT { - - private final ApplicationContextRunner contextRunner = BedrockTestUtils.getContextRunner() - .withPropertyValues("spring.ai.bedrock.jurassic2.chat.enabled=true", - "spring.ai.bedrock.jurassic2.chat.model=" - + Ai21Jurassic2ChatBedrockApi.Ai21Jurassic2ChatModel.AI21_J2_ULTRA_V1.id(), - "spring.ai.bedrock.jurassic2.chat.options.temperature=0.5", - "spring.ai.bedrock.jurassic2.chat.options.maxGenLen=500") - .withConfiguration(AutoConfigurations.of(BedrockAi21Jurassic2ChatAutoConfiguration.class)); - - private final Message systemMessage = new SystemPromptTemplate(""" - You are a helpful AI assistant. Your name is {name}. - You are an AI assistant that helps people find information. - Your name is {name} - You should reply to the user's request with your name and also in the style of a {voice}. - """).createMessage(Map.of("name", "Bob", "voice", "pirate")); - - private final UserMessage userMessage = new UserMessage( - "Tell me about 3 famous pirates from the Golden Age of Piracy and why they did."); - - @Test - public void chatCompletion() { - this.contextRunner.run(context -> { - BedrockAi21Jurassic2ChatModel ai21Jurassic2ChatModel = context.getBean(BedrockAi21Jurassic2ChatModel.class); - ChatResponse response = ai21Jurassic2ChatModel - .call(new Prompt(List.of(this.userMessage, this.systemMessage))); - assertThat(response.getResult().getOutput().getText()).contains("Blackbeard"); - }); - } - - @Test - public void propertiesTest() { - - BedrockTestUtils.getContextRunnerWithUserConfiguration() - .withPropertyValues("spring.ai.bedrock.jurassic2.chat.enabled=true", - "spring.ai.bedrock.aws.access-key=ACCESS_KEY", "spring.ai.bedrock.aws.secret-key=SECRET_KEY", - "spring.ai.bedrock.jurassic2.chat.model=MODEL_XYZ", - "spring.ai.bedrock.aws.region=" + Region.US_EAST_1.id(), - "spring.ai.bedrock.jurassic2.chat.options.temperature=0.55", - "spring.ai.bedrock.jurassic2.chat.options.maxTokens=123") - .withConfiguration(AutoConfigurations.of(BedrockAi21Jurassic2ChatAutoConfiguration.class)) - .run(context -> { - var chatProperties = context.getBean(BedrockAi21Jurassic2ChatProperties.class); - var awsProperties = context.getBean(BedrockAwsConnectionProperties.class); - - assertThat(chatProperties.isEnabled()).isTrue(); - assertThat(awsProperties.getRegion()).isEqualTo(Region.US_EAST_1.id()); - - assertThat(chatProperties.getOptions().getTemperature()).isCloseTo(0.55, within(0.0001)); - assertThat(chatProperties.getOptions().getMaxTokens()).isEqualTo(123); - assertThat(chatProperties.getModel()).isEqualTo("MODEL_XYZ"); - - assertThat(awsProperties.getAccessKey()).isEqualTo("ACCESS_KEY"); - assertThat(awsProperties.getSecretKey()).isEqualTo("SECRET_KEY"); - }); - } - - @Test - public void chatCompletionDisabled() { - - // It is disabled by default - BedrockTestUtils.getContextRunnerWithUserConfiguration() - .withConfiguration(AutoConfigurations.of(BedrockAi21Jurassic2ChatAutoConfiguration.class)) - .run(context -> { - assertThat(context.getBeansOfType(BedrockAi21Jurassic2ChatProperties.class)).isEmpty(); - assertThat(context.getBeansOfType(BedrockAi21Jurassic2ChatModel.class)).isEmpty(); - }); - - // Explicitly enable the chat auto-configuration. - BedrockTestUtils.getContextRunnerWithUserConfiguration() - .withPropertyValues("spring.ai.bedrock.jurassic2.chat.enabled=true") - .withConfiguration(AutoConfigurations.of(BedrockAi21Jurassic2ChatAutoConfiguration.class)) - .run(context -> { - assertThat(context.getBeansOfType(BedrockAi21Jurassic2ChatProperties.class)).isNotEmpty(); - assertThat(context.getBeansOfType(BedrockAi21Jurassic2ChatModel.class)).isNotEmpty(); - }); - - // Explicitly disable the chat auto-configuration. - BedrockTestUtils.getContextRunnerWithUserConfiguration() - .withPropertyValues("spring.ai.bedrock.jurassic2.chat.enabled=false") - .withConfiguration(AutoConfigurations.of(BedrockAi21Jurassic2ChatAutoConfiguration.class)) - .run(context -> { - assertThat(context.getBeansOfType(BedrockAi21Jurassic2ChatProperties.class)).isEmpty(); - assertThat(context.getBeansOfType(BedrockAi21Jurassic2ChatModel.class)).isEmpty(); - }); - } - -} diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/llama/BedrockLlamaChatAutoConfigurationIT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/llama/BedrockLlamaChatAutoConfigurationIT.java deleted file mode 100644 index 786d9ec5656..00000000000 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/llama/BedrockLlamaChatAutoConfigurationIT.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.autoconfigure.bedrock.llama; - -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import org.junit.jupiter.api.Test; -import reactor.core.publisher.Flux; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.autoconfigure.bedrock.BedrockAwsConnectionProperties; -import org.springframework.ai.autoconfigure.bedrock.BedrockTestUtils; -import org.springframework.ai.autoconfigure.bedrock.RequiresAwsCredentials; -import org.springframework.ai.bedrock.llama.BedrockLlamaChatModel; -import org.springframework.ai.bedrock.llama.api.LlamaChatBedrockApi.LlamaChatModel; -import org.springframework.ai.chat.messages.AssistantMessage; -import org.springframework.ai.chat.messages.Message; -import org.springframework.ai.chat.messages.UserMessage; -import org.springframework.ai.chat.model.ChatResponse; -import org.springframework.ai.chat.model.Generation; -import org.springframework.ai.chat.prompt.Prompt; -import org.springframework.ai.chat.prompt.SystemPromptTemplate; -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.AssertionsForClassTypes.within; - -/** - * @author Christian Tzolov - * @author Wei Jiang - * @author Mark Pollack - * @since 1.0.0 - */ -@RequiresAwsCredentials -public class BedrockLlamaChatAutoConfigurationIT { - - private final ApplicationContextRunner contextRunner = BedrockTestUtils.getContextRunner() - .withPropertyValues("spring.ai.bedrock.llama.chat.enabled=true", - "spring.ai.bedrock.llama.chat.model=" + LlamaChatModel.LLAMA3_70B_INSTRUCT_V1.id(), - "spring.ai.bedrock.llama.chat.options.temperature=0.5", - "spring.ai.bedrock.llama.chat.options.maxGenLen=500") - .withConfiguration(AutoConfigurations.of(BedrockLlamaChatAutoConfiguration.class)); - - private final Message systemMessage = new SystemPromptTemplate(""" - You are a helpful AI assistant. Your name is {name}. - You are an AI assistant that helps people find information. - Your name is {name} - You should reply to the user's request with your name and also in the style of a {voice}. - """).createMessage(Map.of("name", "Bob", "voice", "pirate")); - - private final UserMessage userMessage = new UserMessage( - "Describe 3 of the most feared and legendary pirates from the Golden Age of Piracy, particularly those known for their intimidating tactics and whose stories influenced popular culture."); - - @Test - public void chatCompletion() { - this.contextRunner.run(context -> { - BedrockLlamaChatModel llamaChatModel = context.getBean(BedrockLlamaChatModel.class); - ChatResponse response = llamaChatModel.call(new Prompt(List.of(this.userMessage, this.systemMessage))); - assertThat(response.getResult().getOutput().getText()).contains("Blackbeard"); - }); - } - - @Test - public void chatCompletionStreaming() { - this.contextRunner.run(context -> { - - BedrockLlamaChatModel llamaChatModel = context.getBean(BedrockLlamaChatModel.class); - - Flux response = llamaChatModel - .stream(new Prompt(List.of(this.userMessage, this.systemMessage))); - - List responses = response.collectList().block(); - assertThat(responses.size()).isGreaterThan(2); - - String stitchedResponseContent = responses.stream() - .map(ChatResponse::getResults) - .flatMap(List::stream) - .map(Generation::getOutput) - .map(AssistantMessage::getText) - .collect(Collectors.joining()); - - assertThat(stitchedResponseContent).contains("Blackbeard"); - }); - } - - @Test - public void propertiesTest() { - - BedrockTestUtils.getContextRunnerWithUserConfiguration() - .withPropertyValues("spring.ai.bedrock.llama.chat.enabled=true", - "spring.ai.bedrock.aws.access-key=ACCESS_KEY", "spring.ai.bedrock.aws.secret-key=SECRET_KEY", - "spring.ai.bedrock.llama.chat.model=MODEL_XYZ", - "spring.ai.bedrock.aws.region=" + Region.US_EAST_1.id(), - "spring.ai.bedrock.llama.chat.options.temperature=0.55", - "spring.ai.bedrock.llama.chat.options.maxGenLen=123") - .withConfiguration(AutoConfigurations.of(BedrockLlamaChatAutoConfiguration.class)) - .run(context -> { - var llamaChatProperties = context.getBean(BedrockLlamaChatProperties.class); - var awsProperties = context.getBean(BedrockAwsConnectionProperties.class); - - assertThat(llamaChatProperties.isEnabled()).isTrue(); - assertThat(awsProperties.getRegion()).isEqualTo(Region.US_EAST_1.id()); - - assertThat(llamaChatProperties.getOptions().getTemperature()).isCloseTo(0.55, within(0.0001)); - assertThat(llamaChatProperties.getOptions().getMaxGenLen()).isEqualTo(123); - assertThat(llamaChatProperties.getModel()).isEqualTo("MODEL_XYZ"); - - assertThat(awsProperties.getAccessKey()).isEqualTo("ACCESS_KEY"); - assertThat(awsProperties.getSecretKey()).isEqualTo("SECRET_KEY"); - }); - } - - @Test - public void chatCompletionDisabled() { - - // It is disabled by default - BedrockTestUtils.getContextRunnerWithUserConfiguration() - .withConfiguration(AutoConfigurations.of(BedrockLlamaChatAutoConfiguration.class)) - .run(context -> { - assertThat(context.getBeansOfType(BedrockLlamaChatProperties.class)).isEmpty(); - assertThat(context.getBeansOfType(BedrockLlamaChatModel.class)).isEmpty(); - }); - - // Explicitly enable the chat auto-configuration. - BedrockTestUtils.getContextRunnerWithUserConfiguration() - .withPropertyValues("spring.ai.bedrock.llama.chat.enabled=true") - .withConfiguration(AutoConfigurations.of(BedrockLlamaChatAutoConfiguration.class)) - .run(context -> { - assertThat(context.getBeansOfType(BedrockLlamaChatProperties.class)).isNotEmpty(); - assertThat(context.getBeansOfType(BedrockLlamaChatModel.class)).isNotEmpty(); - }); - - // Explicitly disable the chat auto-configuration. - BedrockTestUtils.getContextRunnerWithUserConfiguration() - .withPropertyValues("spring.ai.bedrock.llama.chat.enabled=false") - .withConfiguration(AutoConfigurations.of(BedrockLlamaChatAutoConfiguration.class)) - .run(context -> { - assertThat(context.getBeansOfType(BedrockLlamaChatProperties.class)).isEmpty(); - assertThat(context.getBeansOfType(BedrockLlamaChatModel.class)).isEmpty(); - }); - } - -} diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/titan/BedrockTitanChatAutoConfigurationIT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/titan/BedrockTitanChatAutoConfigurationIT.java deleted file mode 100644 index a3dd9b42bec..00000000000 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/titan/BedrockTitanChatAutoConfigurationIT.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright 2023-2024 the original author or authors. - * - * Licensed 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 - * - * https://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. - */ - -package org.springframework.ai.autoconfigure.bedrock.titan; - -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import org.junit.jupiter.api.Test; -import reactor.core.publisher.Flux; -import software.amazon.awssdk.regions.Region; - -import org.springframework.ai.autoconfigure.bedrock.BedrockAwsConnectionProperties; -import org.springframework.ai.autoconfigure.bedrock.BedrockTestUtils; -import org.springframework.ai.autoconfigure.bedrock.RequiresAwsCredentials; -import org.springframework.ai.bedrock.titan.BedrockTitanChatModel; -import org.springframework.ai.bedrock.titan.api.TitanChatBedrockApi.TitanChatModel; -import org.springframework.ai.chat.messages.AssistantMessage; -import org.springframework.ai.chat.messages.Message; -import org.springframework.ai.chat.messages.UserMessage; -import org.springframework.ai.chat.model.ChatResponse; -import org.springframework.ai.chat.model.Generation; -import org.springframework.ai.chat.prompt.Prompt; -import org.springframework.ai.chat.prompt.SystemPromptTemplate; -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.AssertionsForClassTypes.within; - -/** - * @author Christian Tzolov - * @author Mark Pollack - * @since 1.0.0 - */ -@RequiresAwsCredentials -public class BedrockTitanChatAutoConfigurationIT { - - private final ApplicationContextRunner contextRunner = BedrockTestUtils.getContextRunner() - .withPropertyValues("spring.ai.bedrock.titan.chat.enabled=true", - "spring.ai.bedrock.titan.chat.model=" + TitanChatModel.TITAN_TEXT_EXPRESS_V1.id(), - "spring.ai.bedrock.titan.chat.options.temperature=0.5", - "spring.ai.bedrock.titan.chat.options.maxTokenCount=500") - .withConfiguration(AutoConfigurations.of(BedrockTitanChatAutoConfiguration.class)); - - private final Message systemMessage = new SystemPromptTemplate(""" - You are a helpful AI assistant. Your name is {name}. - You are an AI assistant that helps people find information. - Your name is {name} - You should reply to the user's request with your name and also in the style of a {voice}. - """).createMessage(Map.of("name", "Bob", "voice", "pirate")); - - private final UserMessage userMessage = new UserMessage( - "Tell me about 3 famous pirates from the Golden Age of Piracy and why they did."); - - @Test - public void chatCompletion() { - this.contextRunner.run(context -> { - BedrockTitanChatModel chatModel = context.getBean(BedrockTitanChatModel.class); - ChatResponse response = chatModel.call(new Prompt(List.of(this.userMessage, this.systemMessage))); - assertThat(response.getResult().getOutput().getText()).contains("Blackbeard"); - }); - } - - @Test - public void chatCompletionStreaming() { - this.contextRunner.run(context -> { - - BedrockTitanChatModel chatModel = context.getBean(BedrockTitanChatModel.class); - - Flux response = chatModel.stream(new Prompt(List.of(this.userMessage, this.systemMessage))); - - List responses = response.collectList().block(); - assertThat(responses.size()).isGreaterThan(1); - - String stitchedResponseContent = responses.stream() - .map(ChatResponse::getResults) - .flatMap(List::stream) - .map(Generation::getOutput) - .map(AssistantMessage::getText) - .collect(Collectors.joining()); - - assertThat(stitchedResponseContent).contains("Blackbeard"); - }); - } - - @Test - public void propertiesTest() { - - BedrockTestUtils.getContextRunnerWithUserConfiguration() - .withPropertyValues("spring.ai.bedrock.titan.chat.enabled=true", - "spring.ai.bedrock.aws.access-key=ACCESS_KEY", "spring.ai.bedrock.aws.secret-key=SECRET_KEY", - "spring.ai.bedrock.titan.chat.model=MODEL_XYZ", - "spring.ai.bedrock.aws.region=" + Region.US_EAST_1.id(), - "spring.ai.bedrock.titan.chat.options.temperature=0.55", - "spring.ai.bedrock.titan.chat.options.topP=0.55", - "spring.ai.bedrock.titan.chat.options.stopSequences=END1,END2", - "spring.ai.bedrock.titan.chat.options.maxTokenCount=123") - .withConfiguration(AutoConfigurations.of(BedrockTitanChatAutoConfiguration.class)) - .run(context -> { - var chatProperties = context.getBean(BedrockTitanChatProperties.class); - var aswProperties = context.getBean(BedrockAwsConnectionProperties.class); - - assertThat(chatProperties.isEnabled()).isTrue(); - assertThat(aswProperties.getRegion()).isEqualTo(Region.US_EAST_1.id()); - assertThat(chatProperties.getModel()).isEqualTo("MODEL_XYZ"); - - assertThat(chatProperties.getOptions().getTemperature()).isCloseTo(0.55, within(0.0001)); - assertThat(chatProperties.getOptions().getTopP()).isCloseTo(0.55, within(0.0001)); - - assertThat(chatProperties.getOptions().getStopSequences()).isEqualTo(List.of("END1", "END2")); - assertThat(chatProperties.getOptions().getMaxTokenCount()).isEqualTo(123); - - assertThat(aswProperties.getAccessKey()).isEqualTo("ACCESS_KEY"); - assertThat(aswProperties.getSecretKey()).isEqualTo("SECRET_KEY"); - }); - } - - @Test - public void chatCompletionDisabled() { - - // It is disabled by default - BedrockTestUtils.getContextRunnerWithUserConfiguration() - .withConfiguration(AutoConfigurations.of(BedrockTitanChatAutoConfiguration.class)) - .run(context -> { - assertThat(context.getBeansOfType(BedrockTitanChatProperties.class)).isEmpty(); - assertThat(context.getBeansOfType(BedrockTitanChatModel.class)).isEmpty(); - }); - - // Explicitly enable the chat auto-configuration. - BedrockTestUtils.getContextRunnerWithUserConfiguration() - .withPropertyValues("spring.ai.bedrock.titan.chat.enabled=true") - .withConfiguration(AutoConfigurations.of(BedrockTitanChatAutoConfiguration.class)) - .run(context -> { - assertThat(context.getBeansOfType(BedrockTitanChatProperties.class)).isNotEmpty(); - assertThat(context.getBeansOfType(BedrockTitanChatModel.class)).isNotEmpty(); - }); - - // Explicitly disable the chat auto-configuration. - BedrockTestUtils.getContextRunnerWithUserConfiguration() - .withPropertyValues("spring.ai.bedrock.titan.chat.enabled=false") - .withConfiguration(AutoConfigurations.of(BedrockTitanChatAutoConfiguration.class)) - .run(context -> { - assertThat(context.getBeansOfType(BedrockTitanChatProperties.class)).isEmpty(); - assertThat(context.getBeansOfType(BedrockTitanChatModel.class)).isEmpty(); - }); - } - -}