From eccf33a6ecd6406d6e9ce657de2e991d415e7404 Mon Sep 17 00:00:00 2001 From: Alexandros Pappas Date: Mon, 16 Dec 2024 18:50:19 +0100 Subject: [PATCH] Refactor WatsonxAiChatOptions builder methods - Refactor the builder methods to remove `with` as the prefix. - Introduce new methods with updated naming conventions. - Deprecate the existing `with*` methods to maintain backward compatibility. - Update WatsonxAi documentation --- .../ai/watsonx/WatsonxAiChatModel.java | 17 ++- .../ai/watsonx/WatsonxAiChatOptions.java | 143 +++++++++++++++--- .../ai/watsonx/WatsonxAiChatModelTest.java | 53 ++++--- .../watsonx/api/WatsonxAiChatOptionTest.java | 63 ++++---- .../ROOT/pages/api/chat/watsonx-ai-chat.adoc | 20 +-- .../watsonxai/WatsonxAiChatProperties.java | 19 +-- 6 files changed, 208 insertions(+), 107 deletions(-) diff --git a/models/spring-ai-watsonx-ai/src/main/java/org/springframework/ai/watsonx/WatsonxAiChatModel.java b/models/spring-ai-watsonx-ai/src/main/java/org/springframework/ai/watsonx/WatsonxAiChatModel.java index bf40d60a9..469f69512 100644 --- a/models/spring-ai-watsonx-ai/src/main/java/org/springframework/ai/watsonx/WatsonxAiChatModel.java +++ b/models/spring-ai-watsonx-ai/src/main/java/org/springframework/ai/watsonx/WatsonxAiChatModel.java @@ -49,6 +49,7 @@ import org.springframework.util.Assert; * @author Pablo Sanchidrian Herrera * @author John Jario Moreno Rojas * @author Christian Tzolov + * @author Alexandros Pappas * @since 1.0.0 */ public class WatsonxAiChatModel implements ChatModel, StreamingChatModel { @@ -60,14 +61,14 @@ public class WatsonxAiChatModel implements ChatModel, StreamingChatModel { public WatsonxAiChatModel(WatsonxAiApi watsonxAiApi) { this(watsonxAiApi, WatsonxAiChatOptions.builder() - .withTemperature(0.7) - .withTopP(1.0) - .withTopK(50) - .withDecodingMethod("greedy") - .withMaxNewTokens(20) - .withMinNewTokens(0) - .withRepetitionPenalty(1.0) - .withStopSequences(List.of()) + .temperature(0.7) + .topP(1.0) + .topK(50) + .decodingMethod("greedy") + .maxNewTokens(20) + .minNewTokens(0) + .repetitionPenalty(1.0) + .stopSequences(List.of()) .build()); } diff --git a/models/spring-ai-watsonx-ai/src/main/java/org/springframework/ai/watsonx/WatsonxAiChatOptions.java b/models/spring-ai-watsonx-ai/src/main/java/org/springframework/ai/watsonx/WatsonxAiChatOptions.java index 5273f6de3..d41b0022b 100644 --- a/models/spring-ai-watsonx-ai/src/main/java/org/springframework/ai/watsonx/WatsonxAiChatOptions.java +++ b/models/spring-ai-watsonx-ai/src/main/java/org/springframework/ai/watsonx/WatsonxAiChatOptions.java @@ -37,6 +37,7 @@ import org.springframework.ai.chat.prompt.ChatOptions; * @author Pablo Sanchidrian Herrera * @author John Jairo Moreno Rojas * @author Thomas Vitale + * @author Alexandros Pappas * @since 1.0.0 * @see watsonx.ai @@ -155,17 +156,17 @@ public class WatsonxAiChatOptions implements ChatOptions { public static WatsonxAiChatOptions fromOptions(WatsonxAiChatOptions fromOptions) { return WatsonxAiChatOptions.builder() - .withTemperature(fromOptions.getTemperature()) - .withTopP(fromOptions.getTopP()) - .withTopK(fromOptions.getTopK()) - .withDecodingMethod(fromOptions.getDecodingMethod()) - .withMaxNewTokens(fromOptions.getMaxNewTokens()) - .withMinNewTokens(fromOptions.getMinNewTokens()) - .withStopSequences(fromOptions.getStopSequences()) - .withRepetitionPenalty(fromOptions.getRepetitionPenalty()) - .withRandomSeed(fromOptions.getRandomSeed()) - .withModel(fromOptions.getModel()) - .withAdditionalProperties(fromOptions.getAdditionalProperties()) + .temperature(fromOptions.getTemperature()) + .topP(fromOptions.getTopP()) + .topK(fromOptions.getTopK()) + .decodingMethod(fromOptions.getDecodingMethod()) + .maxNewTokens(fromOptions.getMaxNewTokens()) + .minNewTokens(fromOptions.getMinNewTokens()) + .stopSequences(fromOptions.getStopSequences()) + .repetitionPenalty(fromOptions.getRepetitionPenalty()) + .randomSeed(fromOptions.getRandomSeed()) + .model(fromOptions.getModel()) + .additionalProperties(fromOptions.getAdditionalProperties()) .build(); } @@ -326,66 +327,162 @@ public class WatsonxAiChatOptions implements ChatOptions { WatsonxAiChatOptions options = new WatsonxAiChatOptions(); - public Builder withTemperature(Double temperature) { + public Builder temperature(Double temperature) { this.options.temperature = temperature; return this; } - public Builder withTopP(Double topP) { + public Builder topP(Double topP) { this.options.topP = topP; return this; } - public Builder withTopK(Integer topK) { + public Builder topK(Integer topK) { this.options.topK = topK; return this; } - public Builder withDecodingMethod(String decodingMethod) { + public Builder decodingMethod(String decodingMethod) { this.options.decodingMethod = decodingMethod; return this; } - public Builder withMaxNewTokens(Integer maxNewTokens) { + public Builder maxNewTokens(Integer maxNewTokens) { this.options.maxNewTokens = maxNewTokens; return this; } - public Builder withMinNewTokens(Integer minNewTokens) { + public Builder minNewTokens(Integer minNewTokens) { this.options.minNewTokens = minNewTokens; return this; } - public Builder withStopSequences(List stopSequences) { + public Builder stopSequences(List stopSequences) { this.options.stopSequences = stopSequences; return this; } - public Builder withRepetitionPenalty(Double repetitionPenalty) { + public Builder repetitionPenalty(Double repetitionPenalty) { this.options.repetitionPenalty = repetitionPenalty; return this; } - public Builder withRandomSeed(Integer randomSeed) { + public Builder randomSeed(Integer randomSeed) { this.options.randomSeed = randomSeed; return this; } - public Builder withModel(String model) { + public Builder model(String model) { this.options.model = model; return this; } - public Builder withAdditionalProperty(String key, Object value) { + public Builder additionalProperty(String key, Object value) { this.options.additional.put(key, value); return this; } - public Builder withAdditionalProperties(Map properties) { + public Builder additionalProperties(Map properties) { this.options.additional.putAll(properties); return this; } + /** + * @deprecated use {@link #temperature(Double)} instead. + */ + @Deprecated(forRemoval = true, since = "1.0.0-M5") + public Builder withTemperature(Double temperature) { + return temperature(temperature); + } + + /** + * @deprecated use {@link #topP(Double)} instead. + */ + @Deprecated(forRemoval = true, since = "1.0.0-M5") + public Builder withTopP(Double topP) { + return topP(topP); + } + + /** + * @deprecated use {@link #topK(Integer)} instead. + */ + @Deprecated(forRemoval = true, since = "1.0.0-M5") + public Builder withTopK(Integer topK) { + return topK(topK); + } + + /** + * @deprecated use {@link #decodingMethod(String)} instead. + */ + @Deprecated(forRemoval = true, since = "1.0.0-M5") + public Builder withDecodingMethod(String decodingMethod) { + return decodingMethod(decodingMethod); + } + + /** + * @deprecated use {@link #maxNewTokens(Integer)} instead. + */ + @Deprecated(forRemoval = true, since = "1.0.0-M5") + public Builder withMaxNewTokens(Integer maxNewTokens) { + return maxNewTokens(maxNewTokens); + } + + /** + * @deprecated use {@link #minNewTokens(Integer)} instead. + */ + @Deprecated(forRemoval = true, since = "1.0.0-M5") + public Builder withMinNewTokens(Integer minNewTokens) { + return minNewTokens(minNewTokens); + } + + /** + * @deprecated use {@link #stopSequences(List)} instead. + */ + @Deprecated(forRemoval = true, since = "1.0.0-M5") + public Builder withStopSequences(List stopSequences) { + return stopSequences(stopSequences); + } + + /** + * @deprecated use {@link #repetitionPenalty(Double)} instead. + */ + @Deprecated(forRemoval = true, since = "1.0.0-M5") + public Builder withRepetitionPenalty(Double repetitionPenalty) { + return repetitionPenalty(repetitionPenalty); + } + + /** + * @deprecated use {@link #randomSeed(Integer)} instead. + */ + @Deprecated(forRemoval = true, since = "1.0.0-M5") + public Builder withRandomSeed(Integer randomSeed) { + return randomSeed(randomSeed); + } + + /** + * @deprecated use {@link #model(String)} instead. + */ + @Deprecated(forRemoval = true, since = "1.0.0-M5") + public Builder withModel(String model) { + return model(model); + } + + /** + * @deprecated use {@link #additionalProperty(String, Object)} instead. + */ + @Deprecated(forRemoval = true, since = "1.0.0-M5") + public Builder withAdditionalProperty(String key, Object value) { + return additionalProperty(key, value); + } + + /** + * @deprecated use {@link #additionalProperties(Map)} instead. + */ + @Deprecated(forRemoval = true, since = "1.0.0-M5") + public Builder withAdditionalProperties(Map properties) { + return additionalProperties(properties); + } + public WatsonxAiChatOptions build() { return this.options; } diff --git a/models/spring-ai-watsonx-ai/src/test/java/org/springframework/ai/watsonx/WatsonxAiChatModelTest.java b/models/spring-ai-watsonx-ai/src/test/java/org/springframework/ai/watsonx/WatsonxAiChatModelTest.java index 990960040..60c871b1c 100644 --- a/models/spring-ai-watsonx-ai/src/test/java/org/springframework/ai/watsonx/WatsonxAiChatModelTest.java +++ b/models/spring-ai-watsonx-ai/src/test/java/org/springframework/ai/watsonx/WatsonxAiChatModelTest.java @@ -47,6 +47,7 @@ import static org.mockito.Mockito.mock; /** * @author Pablo Sanchidrian Herrera * @author John Jairo Moreno Rojas + * @author Alexandros Pappas */ public class WatsonxAiChatModelTest { @@ -66,9 +67,7 @@ public class WatsonxAiChatModelTest { String msg = "Test message"; - WatsonxAiChatOptions modelOptions = WatsonxAiChatOptions.builder() - .withModel("meta-llama/llama-2-70b-chat") - .build(); + WatsonxAiChatOptions modelOptions = WatsonxAiChatOptions.builder().model("meta-llama/llama-2-70b-chat").build(); Prompt prompt = new Prompt(msg, modelOptions); WatsonxAiChatRequest request = this.chatModel.request(prompt); @@ -91,16 +90,16 @@ public class WatsonxAiChatModelTest { String msg = "Test message"; WatsonxAiChatOptions modelOptions = WatsonxAiChatOptions.builder() - .withModel("meta-llama/llama-2-70b-chat") - .withDecodingMethod("sample") - .withTemperature(0.1) - .withTopP(0.2) - .withTopK(10) - .withMaxNewTokens(30) - .withMinNewTokens(10) - .withRepetitionPenalty(1.4) - .withStopSequences(List.of("\n\n\n")) - .withRandomSeed(4) + .model("meta-llama/llama-2-70b-chat") + .decodingMethod("sample") + .temperature(0.1) + .topP(0.2) + .topK(10) + .maxNewTokens(30) + .minNewTokens(10) + .repetitionPenalty(1.4) + .stopSequences(List.of("\n\n\n")) + .randomSeed(4) .build(); Prompt prompt = new Prompt(msg, modelOptions); @@ -125,16 +124,16 @@ public class WatsonxAiChatModelTest { String msg = "Test message"; WatsonxAiChatOptions modelOptions = WatsonxAiChatOptions.builder() - .withModel("meta-llama/llama-2-70b-chat") - .withDecodingMethod("sample") - .withTemperature(0.1) - .withTopP(0.2) - .withTopK(10) - .withMaxNewTokens(30) - .withMinNewTokens(10) - .withRepetitionPenalty(1.4) - .withStopSequences(List.of("\n\n\n")) - .withRandomSeed(4) + .model("meta-llama/llama-2-70b-chat") + .decodingMethod("sample") + .temperature(0.1) + .topP(0.2) + .topK(10) + .maxNewTokens(30) + .minNewTokens(10) + .repetitionPenalty(1.4) + .stopSequences(List.of("\n\n\n")) + .randomSeed(4) .build(); Prompt prompt = new Prompt(msg, modelOptions); @@ -160,9 +159,9 @@ public class WatsonxAiChatModelTest { WatsonxAiChatModel chatModel = new WatsonxAiChatModel(mockChatApi); Prompt prompt = new Prompt(List.of(new SystemMessage("Your prompt here")), - WatsonxAiChatOptions.builder().withModel("google/flan-ul2").build()); + WatsonxAiChatOptions.builder().model("google/flan-ul2").build()); - WatsonxAiChatOptions parameters = WatsonxAiChatOptions.builder().withModel("google/flan-ul2").build(); + WatsonxAiChatOptions parameters = WatsonxAiChatOptions.builder().model("google/flan-ul2").build(); WatsonxAiChatResults fakeResults = new WatsonxAiChatResults("LLM response", 4, 3, "max_tokens"); @@ -193,9 +192,9 @@ public class WatsonxAiChatModelTest { WatsonxAiChatModel chatModel = new WatsonxAiChatModel(mockChatApi); Prompt prompt = new Prompt(List.of(new SystemMessage("Your prompt here")), - WatsonxAiChatOptions.builder().withModel("google/flan-ul2").build()); + WatsonxAiChatOptions.builder().model("google/flan-ul2").build()); - WatsonxAiChatOptions parameters = WatsonxAiChatOptions.builder().withModel("google/flan-ul2").build(); + WatsonxAiChatOptions parameters = WatsonxAiChatOptions.builder().model("google/flan-ul2").build(); WatsonxAiChatResults fakeResultsFirst = new WatsonxAiChatResults("LLM resp", 0, 0, "max_tokens"); WatsonxAiChatResults fakeResultsSecond = new WatsonxAiChatResults("onse", 4, 3, "not_finished"); diff --git a/models/spring-ai-watsonx-ai/src/test/java/org/springframework/ai/watsonx/api/WatsonxAiChatOptionTest.java b/models/spring-ai-watsonx-ai/src/test/java/org/springframework/ai/watsonx/api/WatsonxAiChatOptionTest.java index ac71fe43e..4e9fcc3e9 100644 --- a/models/spring-ai-watsonx-ai/src/test/java/org/springframework/ai/watsonx/api/WatsonxAiChatOptionTest.java +++ b/models/spring-ai-watsonx-ai/src/test/java/org/springframework/ai/watsonx/api/WatsonxAiChatOptionTest.java @@ -28,21 +28,22 @@ import static org.assertj.core.api.Assertions.assertThat; /** * @author Pablo Sanchidrian Herrera * @author John Jairo Moreno Rojas + * @author Alexandros Pappas */ public class WatsonxAiChatOptionTest { @Test public void testOptions() { WatsonxAiChatOptions options = WatsonxAiChatOptions.builder() - .withDecodingMethod("sample") - .withTemperature(1.2) - .withTopK(20) - .withTopP(0.5) - .withMaxNewTokens(100) - .withMinNewTokens(20) - .withStopSequences(List.of("\n\n\n")) - .withRepetitionPenalty(1.1) - .withRandomSeed(4) + .decodingMethod("sample") + .temperature(1.2) + .topK(20) + .topP(0.5) + .maxNewTokens(100) + .minNewTokens(20) + .stopSequences(List.of("\n\n\n")) + .repetitionPenalty(1.1) + .randomSeed(4) .build(); var optionsMap = options.toMap(); @@ -61,17 +62,17 @@ public class WatsonxAiChatOptionTest { @Test public void testOptionsWithAdditionalParamsOneByOne() { WatsonxAiChatOptions options = WatsonxAiChatOptions.builder() - .withDecodingMethod("sample") - .withTemperature(1.2) - .withTopK(20) - .withTopP(0.5) - .withMaxNewTokens(100) - .withMinNewTokens(20) - .withStopSequences(List.of("\n\n\n")) - .withRepetitionPenalty(1.1) - .withRandomSeed(4) - .withAdditionalProperty("HAP", true) - .withAdditionalProperty("typicalP", 0.5f) + .decodingMethod("sample") + .temperature(1.2) + .topK(20) + .topP(0.5) + .maxNewTokens(100) + .minNewTokens(20) + .stopSequences(List.of("\n\n\n")) + .repetitionPenalty(1.1) + .randomSeed(4) + .additionalProperty("HAP", true) + .additionalProperty("typicalP", 0.5f) .build(); var optionsMap = options.toMap(); @@ -92,16 +93,16 @@ public class WatsonxAiChatOptionTest { @Test public void testOptionsWithAdditionalParamsMap() { WatsonxAiChatOptions options = WatsonxAiChatOptions.builder() - .withDecodingMethod("sample") - .withTemperature(1.2) - .withTopK(20) - .withTopP(0.5) - .withMaxNewTokens(100) - .withMinNewTokens(20) - .withStopSequences(List.of("\n\n\n")) - .withRepetitionPenalty(1.1) - .withRandomSeed(4) - .withAdditionalProperties(Map.of("HAP", true, "typicalP", 0.5f, "test_value", "test")) + .decodingMethod("sample") + .temperature(1.2) + .topK(20) + .topP(0.5) + .maxNewTokens(100) + .minNewTokens(20) + .stopSequences(List.of("\n\n\n")) + .repetitionPenalty(1.1) + .randomSeed(4) + .additionalProperties(Map.of("HAP", true, "typicalP", 0.5f, "test_value", "test")) .build(); var optionsMap = options.toMap(); @@ -122,7 +123,7 @@ public class WatsonxAiChatOptionTest { @Test public void testFilterOut() { - WatsonxAiChatOptions options = WatsonxAiChatOptions.builder().withModel("google/flan-ul2").build(); + WatsonxAiChatOptions options = WatsonxAiChatOptions.builder().model("google/flan-ul2").build(); var mappedOptions = WatsonxAiChatOptions.filterNonSupportedFields(options.toMap()); assertThat(mappedOptions).doesNotContainEntry("model", "google/flan-ul2"); } diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/watsonx-ai-chat.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/watsonx-ai-chat.adoc index 5f0727dcf..d102f8026 100644 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/watsonx-ai-chat.adoc +++ b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/chat/watsonx-ai-chat.adoc @@ -87,7 +87,7 @@ ChatResponse response = chatModel.call( new Prompt( "Generate the names of 5 famous pirates.", WatsonxAiChatOptions.builder() - .withTemperature(0.4) + .temperature(0.4) .build() )); ---- @@ -112,10 +112,11 @@ public class MyClass { public String generate(String userInput) { - WatsonxAiOptions options = WatsonxAiOptions.create() - .withModel(MODEL) - .withDecodingMethod("sample") - .withRandomSeed(1); + WatsonxAiChatOptions options = WatsonxAiChatOptions.builder() + .model(MODEL) + .decodingMethod("sample") + .randomSeed(1) + .build(); Prompt prompt = new Prompt(new SystemMessage(userInput), options); @@ -128,10 +129,11 @@ public class MyClass { public String generateStream(String userInput) { - WatsonxAiOptions options = WatsonxAiOptions.create() - .withModel(MODEL) - .withDecodingMethod("greedy") - .withRandomSeed(2); + WatsonxAiChatOptions options = WatsonxAiChatOptions.builder() + .model(MODEL) + .decodingMethod("greedy") + .randomSeed(2) + .build(); Prompt prompt = new Prompt(new SystemMessage(userInput), options); diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/watsonxai/WatsonxAiChatProperties.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/watsonxai/WatsonxAiChatProperties.java index 80b9abbf5..fbd14c698 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/watsonxai/WatsonxAiChatProperties.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/watsonxai/WatsonxAiChatProperties.java @@ -26,6 +26,7 @@ import org.springframework.boot.context.properties.NestedConfigurationProperty; * Chat properties for Watsonx.AI Chat. * * @author Christian Tzolov + * @author Alexandros Pappas * @since 1.0.0 */ @ConfigurationProperties(WatsonxAiChatProperties.CONFIG_PREFIX) @@ -43,15 +44,15 @@ public class WatsonxAiChatProperties { */ @NestedConfigurationProperty private WatsonxAiChatOptions options = WatsonxAiChatOptions.builder() - .withModel("google/flan-ul2") - .withTemperature(0.7) - .withTopP(1.0) - .withTopK(50) - .withDecodingMethod("greedy") - .withMaxNewTokens(20) - .withMinNewTokens(0) - .withRepetitionPenalty(1.0) - .withStopSequences(List.of()) + .model("google/flan-ul2") + .temperature(0.7) + .topP(1.0) + .topK(50) + .decodingMethod("greedy") + .maxNewTokens(20) + .minNewTokens(0) + .repetitionPenalty(1.0) + .stopSequences(List.of()) .build(); public boolean isEnabled() {