diff --git a/models/spring-ai-azure-openai/src/main/java/org/springframework/ai/azure/openai/aot/AzureOpenAiRuntimeHints.java b/models/spring-ai-azure-openai/src/main/java/org/springframework/ai/azure/openai/aot/AzureOpenAiRuntimeHints.java new file mode 100644 index 000000000..461e082dc --- /dev/null +++ b/models/spring-ai-azure-openai/src/main/java/org/springframework/ai/azure/openai/aot/AzureOpenAiRuntimeHints.java @@ -0,0 +1,61 @@ +/* + * Copyright 2024-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.azure.openai.aot; + +import com.azure.ai.openai.OpenAIAsyncClient; +import com.azure.ai.openai.OpenAIClient; +import com.azure.ai.openai.models.ChatChoice; + +import org.springframework.ai.aot.AiRuntimeHints; +import org.springframework.aot.hint.MemberCategory; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.RuntimeHintsRegistrar; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; + +/** + * @author Christian Tzolov + */ +public class AzureOpenAiRuntimeHints implements RuntimeHintsRegistrar { + + @Override + public void registerHints(@NonNull RuntimeHints hints, @Nullable ClassLoader classLoader) { + + var mcs = MemberCategory.values(); + + hints.reflection().registerType(OpenAIClient.class, mcs); + hints.reflection().registerType(OpenAIAsyncClient.class, mcs); + + // Register all com.azure.ai.openai.models.* classes + AiRuntimeHints + .findClassesInPackage(ChatChoice.class.getPackageName(), (metadataReader, metadataReaderFactory) -> true) + .forEach(clazz -> hints.reflection().registerType(clazz, mcs)); + + hints.proxies().registerJdkProxy(com.azure.ai.openai.implementation.OpenAIClientImpl.OpenAIClientService.class); + + try { + var resolver = new PathMatchingResourcePatternResolver(); + for (var resourceMatch : resolver.getResources("/azure-ai-openai.properties")) + hints.resources().registerResource(resourceMatch); + } + catch (Exception e) { + throw new RuntimeException(e); + } + } + +} diff --git a/models/spring-ai-azure-openai/src/main/resources/META-INF/spring/aot.factories b/models/spring-ai-azure-openai/src/main/resources/META-INF/spring/aot.factories new file mode 100644 index 000000000..09bc11ff7 --- /dev/null +++ b/models/spring-ai-azure-openai/src/main/resources/META-INF/spring/aot.factories @@ -0,0 +1,2 @@ +org.springframework.aot.hint.RuntimeHintsRegistrar=\ + org.springframework.ai.azure.openai.aot.AzureOpenAiRuntimeHints \ No newline at end of file diff --git a/models/spring-ai-azure-openai/src/test/java/org/springframework/ai/azure/openai/aot/AzureOpenAiRuntimeHintsTests.java b/models/spring-ai-azure-openai/src/test/java/org/springframework/ai/azure/openai/aot/AzureOpenAiRuntimeHintsTests.java new file mode 100644 index 000000000..128dd904e --- /dev/null +++ b/models/spring-ai-azure-openai/src/test/java/org/springframework/ai/azure/openai/aot/AzureOpenAiRuntimeHintsTests.java @@ -0,0 +1,53 @@ +/* + * Copyright 2024-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.azure.openai.aot; + +import java.util.Set; + +import com.azure.ai.openai.OpenAIAsyncClient; +import com.azure.ai.openai.OpenAIClient; +import com.azure.ai.openai.models.ChatChoice; +import org.junit.jupiter.api.Test; + +import org.springframework.ai.aot.AiRuntimeHints; +import org.springframework.aot.hint.RuntimeHints; +import org.springframework.aot.hint.TypeReference; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; +import static org.springframework.aot.hint.predicate.RuntimeHintsPredicates.reflection; +import static org.springframework.aot.hint.predicate.RuntimeHintsPredicates.resource; + +class AzureOpenAiRuntimeHintsTests { + + @Test + void registerHints() { + RuntimeHints runtimeHints = new RuntimeHints(); + AzureOpenAiRuntimeHints openAiRuntimeHints = new AzureOpenAiRuntimeHints(); + openAiRuntimeHints.registerHints(runtimeHints, null); + + Set azureModelTypes = AiRuntimeHints.findClassesInPackage(ChatChoice.class.getPackageName(), + (metadataReader, metadataReaderFactory) -> true); + for (TypeReference modelType : azureModelTypes) { + assertThat(runtimeHints).matches(reflection().onType(modelType)); + } + assertThat(runtimeHints).matches(reflection().onType(OpenAIClient.class)); + assertThat(runtimeHints).matches(reflection().onType(OpenAIAsyncClient.class)); + + assertThat(runtimeHints).matches(resource().forResource("/azure-ai-openai.properties")); + } + +} diff --git a/models/spring-ai-bedrock/pom.xml b/models/spring-ai-bedrock/pom.xml index 9c3f7abad..0762a147c 100644 --- a/models/spring-ai-bedrock/pom.xml +++ b/models/spring-ai-bedrock/pom.xml @@ -44,6 +44,12 @@ software.amazon.awssdk bedrockruntime ${bedrockruntime.version} + + + commons-logging + commons-logging + + 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 7c8e4857b..6aa2eecd2 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 @@ -1,10 +1,16 @@ 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.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.llama2.BedrockLlama2ChatOptions; import org.springframework.ai.bedrock.llama2.api.Llama2ChatBedrockApi; +import org.springframework.ai.bedrock.titan.BedrockTitanChatOptions; import org.springframework.ai.bedrock.titan.api.TitanChatBedrockApi; import org.springframework.ai.bedrock.titan.api.TitanEmbeddingBedrockApi; import org.springframework.aot.hint.MemberCategory; @@ -26,20 +32,36 @@ public class BedrockRuntimeHints implements RuntimeHintsRegistrar { @Override public void registerHints(RuntimeHints hints, ClassLoader classLoader) { var mcs = MemberCategory.values(); + 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); + for (var tr : findJsonAnnotatedClassesInPackage(BedrockCohereEmbeddingOptions.class)) + hints.reflection().registerType(tr, mcs); + for (var tr : findJsonAnnotatedClassesInPackage(Llama2ChatBedrockApi.class)) hints.reflection().registerType(tr, mcs); + for (var tr : findJsonAnnotatedClassesInPackage(BedrockLlama2ChatOptions.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(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); } } diff --git a/models/spring-ai-ollama/src/main/resources/META-INF/spring/aot.factories b/models/spring-ai-ollama/src/main/resources/META-INF/spring/aot.factories index 7529e3099..61514fe56 100644 --- a/models/spring-ai-ollama/src/main/resources/META-INF/spring/aot.factories +++ b/models/spring-ai-ollama/src/main/resources/META-INF/spring/aot.factories @@ -1,2 +1,2 @@ org.springframework.aot.hint.RuntimeHintsRegistrar=\ - org.springframework.ai.vertex.aot.OllamaRuntimeHints \ No newline at end of file + org.springframework.ai.ollama.aot.OllamaRuntimeHints \ No newline at end of file diff --git a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/aot/OpenAiRuntimeHintsTests.java b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/aot/OpenAiRuntimeHintsTests.java index c6d266fb3..ed61ba1fd 100644 --- a/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/aot/OpenAiRuntimeHintsTests.java +++ b/models/spring-ai-openai/src/test/java/org/springframework/ai/openai/aot/OpenAiRuntimeHintsTests.java @@ -1,3 +1,19 @@ +/* + * Copyright 2024-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.openai.aot; import org.junit.jupiter.api.Test; diff --git a/models/spring-ai-vertex-ai/src/main/java/org/springframework/ai/vertex/api/VertexAiApi.java b/models/spring-ai-vertex-ai/src/main/java/org/springframework/ai/vertex/api/VertexAiApi.java index ae25ae8a2..1a8c92795 100644 --- a/models/spring-ai-vertex-ai/src/main/java/org/springframework/ai/vertex/api/VertexAiApi.java +++ b/models/spring-ai-vertex-ai/src/main/java/org/springframework/ai/vertex/api/VertexAiApi.java @@ -197,6 +197,10 @@ public class VertexAiApi { return response != null ? response.embedding() : null; } + @JsonInclude(Include.NON_NULL) + record BatchEmbeddingResponse(List embeddings) { + } + /** * Generates a response from the model given an input. * @param texts List of texts to embed. @@ -205,9 +209,6 @@ public class VertexAiApi { public List batchEmbedText(List texts) { Assert.notNull(texts, "The texts can not be null."); - @JsonInclude(Include.NON_NULL) - record BatchEmbeddingResponse(List embeddings) { - } BatchEmbeddingResponse response = this.restClient.post() .uri("/models/{model}:batchEmbedText?key={apiKey}", this.embeddingModel, this.apiKey) diff --git a/spring-ai-core/src/main/java/org/springframework/ai/aot/AiRuntimeHints.java b/spring-ai-core/src/main/java/org/springframework/ai/aot/AiRuntimeHints.java index 204e2c0dd..64fd546ef 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/aot/AiRuntimeHints.java +++ b/spring-ai-core/src/main/java/org/springframework/ai/aot/AiRuntimeHints.java @@ -7,6 +7,7 @@ import org.slf4j.LoggerFactory; import org.springframework.aot.hint.TypeReference; import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; import org.springframework.core.type.filter.AnnotationTypeFilter; +import org.springframework.core.type.filter.TypeFilter; import java.lang.reflect.Executable; import java.util.*; @@ -24,9 +25,8 @@ public class AiRuntimeHints { private static final Logger log = LoggerFactory.getLogger(AiRuntimeHints.class); public static Set findJsonAnnotatedClassesInPackage(String packageName) { - var classPathScanningCandidateComponentProvider = new ClassPathScanningCandidateComponentProvider(false); var annotationTypeFilter = new AnnotationTypeFilter(JsonInclude.class); - classPathScanningCandidateComponentProvider.addIncludeFilter((metadataReader, metadataReaderFactory) -> { + TypeFilter typeFilter = (metadataReader, metadataReaderFactory) -> { try { var clazz = Class.forName(metadataReader.getClassMetadata().getClassName()); return annotationTypeFilter.match(metadataReader, metadataReaderFactory) @@ -35,7 +35,18 @@ public class AiRuntimeHints { catch (ClassNotFoundException e) { throw new RuntimeException(e); } - }); + }; + + return findClassesInPackage(packageName, typeFilter); + } + + public static Set findJsonAnnotatedClassesInPackage(Class packageClass) { + return findJsonAnnotatedClassesInPackage(packageClass.getPackageName()); + } + + public static Set findClassesInPackage(String packageName, TypeFilter typeFilter) { + var classPathScanningCandidateComponentProvider = new ClassPathScanningCandidateComponentProvider(false); + classPathScanningCandidateComponentProvider.addIncludeFilter(typeFilter); return classPathScanningCandidateComponentProvider// .findCandidateComponents(packageName)// .stream()// @@ -45,11 +56,6 @@ public class AiRuntimeHints { log.debug("registering [" + tr.getName() + ']'); }) .collect(Collectors.toUnmodifiableSet()); - - } - - public static Set findJsonAnnotatedClassesInPackage(Class packageClass) { - return findJsonAnnotatedClassesInPackage(packageClass.getPackageName()); } private static boolean hasJacksonAnnotations(Class type) { diff --git a/spring-ai-core/src/main/java/org/springframework/ai/aot/SpringAiCoreRuntimeHints.java b/spring-ai-core/src/main/java/org/springframework/ai/aot/SpringAiCoreRuntimeHints.java index 4b156bb6a..ae06b77ab 100644 --- a/spring-ai-core/src/main/java/org/springframework/ai/aot/SpringAiCoreRuntimeHints.java +++ b/spring-ai-core/src/main/java/org/springframework/ai/aot/SpringAiCoreRuntimeHints.java @@ -1,23 +1,39 @@ package org.springframework.ai.aot; import org.springframework.ai.chat.messages.*; +import org.springframework.ai.model.function.FunctionCallback; +import org.springframework.ai.model.function.FunctionCallbackContext; +import org.springframework.ai.model.function.FunctionCallbackWrapper; +import org.springframework.aot.hint.ExecutableMode; import org.springframework.aot.hint.RuntimeHints; import org.springframework.aot.hint.RuntimeHintsRegistrar; import org.springframework.core.io.ClassPathResource; +import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; +import org.springframework.util.ReflectionUtils; +import java.lang.reflect.Method; import java.util.Set; public class SpringAiCoreRuntimeHints implements RuntimeHintsRegistrar { @Override - public void registerHints(RuntimeHints hints, ClassLoader classLoader) { + public void registerHints(@NonNull RuntimeHints hints, @Nullable ClassLoader classLoader) { var chatTypes = Set.of(AbstractMessage.class, AssistantMessage.class, ChatMessage.class, FunctionMessage.class, - Message.class, MessageType.class, UserMessage.class, SystemMessage.class); + Message.class, MessageType.class, UserMessage.class, SystemMessage.class, FunctionCallbackContext.class, + FunctionCallback.class, FunctionCallbackWrapper.class); for (var c : chatTypes) { hints.reflection().registerType(c); } + Method getDescription = ReflectionUtils.findMethod(FunctionCallback.class, "getDescription"); + hints.reflection().registerMethod(getDescription, ExecutableMode.INVOKE); + Method getInputTypeSchema = ReflectionUtils.findMethod(FunctionCallback.class, "getInputTypeSchema"); + hints.reflection().registerMethod(getInputTypeSchema, ExecutableMode.INVOKE); + Method getName = ReflectionUtils.findMethod(FunctionCallback.class, "getName"); + hints.reflection().registerMethod(getName, ExecutableMode.INVOKE); + for (var r : Set.of("antlr4/org/springframework/ai/vectorstore/filter/antlr4/Filters.g4", "embedding/embedding-model-dimensions.properties")) hints.resources().registerResource(new ClassPathResource(r)); diff --git a/spring-ai-core/src/test/java/org/springframework/ai/aot/AiRuntimeHintsTests.java b/spring-ai-core/src/test/java/org/springframework/ai/aot/AiRuntimeHintsTests.java index cc9e6ee9f..72cdec4a0 100644 --- a/spring-ai-core/src/test/java/org/springframework/ai/aot/AiRuntimeHintsTests.java +++ b/spring-ai-core/src/test/java/org/springframework/ai/aot/AiRuntimeHintsTests.java @@ -1,17 +1,32 @@ +/* + * Copyright 2024-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.aot; +import java.util.Set; +import java.util.stream.Collectors; + import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import org.apache.commons.logging.LogFactory; import org.junit.jupiter.api.Test; + import org.springframework.aot.hint.TypeReference; import org.springframework.util.Assert; -import java.util.Set; -import java.util.stream.Collectors; - -import static org.assertj.core.api.Assertions.assertThat; - class AiRuntimeHintsTests { @JsonInclude diff --git a/spring-ai-core/src/test/java/org/springframework/ai/aot/KnuddelsRuntimeHintsTest.java b/spring-ai-core/src/test/java/org/springframework/ai/aot/KnuddelsRuntimeHintsTest.java index 4f63575a8..e11ab5bf0 100644 --- a/spring-ai-core/src/test/java/org/springframework/ai/aot/KnuddelsRuntimeHintsTest.java +++ b/spring-ai-core/src/test/java/org/springframework/ai/aot/KnuddelsRuntimeHintsTest.java @@ -1,3 +1,19 @@ +/* + * Copyright 2024-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.aot; import org.junit.jupiter.api.Test; diff --git a/spring-ai-core/src/test/java/org/springframework/ai/aot/SpringAiCoreRuntimeHintsTest.java b/spring-ai-core/src/test/java/org/springframework/ai/aot/SpringAiCoreRuntimeHintsTest.java index 9f4a9eaf5..97d15db30 100644 --- a/spring-ai-core/src/test/java/org/springframework/ai/aot/SpringAiCoreRuntimeHintsTest.java +++ b/spring-ai-core/src/test/java/org/springframework/ai/aot/SpringAiCoreRuntimeHintsTest.java @@ -1,9 +1,28 @@ +/* + * Copyright 2024-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.aot; import org.junit.jupiter.api.Test; + +import org.springframework.ai.model.function.FunctionCallback; import org.springframework.aot.hint.RuntimeHints; import static org.assertj.core.api.Assertions.assertThat; +import static org.springframework.aot.hint.predicate.RuntimeHintsPredicates.reflection; import static org.springframework.aot.hint.predicate.RuntimeHintsPredicates.resource; class SpringAiCoreRuntimeHintsTest { @@ -11,9 +30,13 @@ class SpringAiCoreRuntimeHintsTest { @Test void core() { var runtimeHints = new RuntimeHints(); - var knuddels = new SpringAiCoreRuntimeHints(); - knuddels.registerHints(runtimeHints, null); + var springAiCore = new SpringAiCoreRuntimeHints(); + springAiCore.registerHints(runtimeHints, null); assertThat(runtimeHints).matches(resource().forResource("embedding/embedding-model-dimensions.properties")); + + assertThat(runtimeHints).matches(reflection().onMethod(FunctionCallback.class, "getDescription")); + assertThat(runtimeHints).matches(reflection().onMethod(FunctionCallback.class, "getInputTypeSchema")); + assertThat(runtimeHints).matches(reflection().onMethod(FunctionCallback.class, "getName")); } } \ No newline at end of file diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/embeddings/onnx.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/embeddings/onnx.adoc index d55506af9..20d11976c 100644 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/embeddings/onnx.adoc +++ b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/embeddings/onnx.adoc @@ -81,7 +81,7 @@ List> embeddings = embeddingClient.embed(List.of("Hello world", "Wo ---- -Note that when created manually, you must call the `afterPropertiesSet()` after setting the properties and before using the client. +NOTE: that when created manually, you must call the `afterPropertiesSet()` after setting the properties and before using the client. The first `embed()` call downloads the large ONNX model and caches it on the local file system. Therefore, the first call might take longer than usual. diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiEmbeddingProperties.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiEmbeddingProperties.java index cb4980ee9..3f43304c4 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiEmbeddingProperties.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiEmbeddingProperties.java @@ -19,6 +19,7 @@ package org.springframework.ai.autoconfigure.azure.openai; import org.springframework.ai.azure.openai.AzureOpenAiEmbeddingOptions; import org.springframework.ai.document.MetadataMode; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.NestedConfigurationProperty; import org.springframework.util.Assert; @ConfigurationProperties(AzureOpenAiEmbeddingProperties.CONFIG_PREFIX) @@ -31,6 +32,7 @@ public class AzureOpenAiEmbeddingProperties { */ private boolean enabled = true; + @NestedConfigurationProperty private AzureOpenAiEmbeddingOptions options = AzureOpenAiEmbeddingOptions.builder() .withModel("text-embedding-ada-002") .build(); 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 index 0cecdc277..16282743d 100644 --- 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 @@ -44,7 +44,7 @@ public class BedrockCohereChatAutoConfiguration { @Bean @ConditionalOnMissingBean - public CohereChatBedrockApi cohereApi(AwsCredentialsProvider credentialsProvider, + public CohereChatBedrockApi cohereChatApi(AwsCredentialsProvider credentialsProvider, BedrockCohereChatProperties properties, BedrockAwsConnectionProperties awsProperties) { return new CohereChatBedrockApi(properties.getModel(), credentialsProvider, awsProperties.getRegion(), new ObjectMapper()); diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/cohere/BedrockCohereEmbeddingAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/cohere/BedrockCohereEmbeddingAutoConfiguration.java index 2b8d89617..6478b9153 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/cohere/BedrockCohereEmbeddingAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/cohere/BedrockCohereEmbeddingAutoConfiguration.java @@ -46,7 +46,7 @@ public class BedrockCohereEmbeddingAutoConfiguration { @Bean @ConditionalOnMissingBean - public CohereEmbeddingBedrockApi cohereApi(AwsCredentialsProvider credentialsProvider, + public CohereEmbeddingBedrockApi cohereEmbeddingApi(AwsCredentialsProvider credentialsProvider, BedrockCohereEmbeddingProperties properties, BedrockAwsConnectionProperties awsProperties) { return new CohereEmbeddingBedrockApi(properties.getModel(), credentialsProvider, awsProperties.getRegion(), new ObjectMapper()); diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/openai/OpenAiAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/openai/OpenAiAutoConfiguration.java index b3cf9aa7e..c925e9255 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/openai/OpenAiAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/openai/OpenAiAutoConfiguration.java @@ -16,7 +16,8 @@ package org.springframework.ai.autoconfigure.openai; -import org.springframework.ai.embedding.EmbeddingClient; +import java.util.List; + import org.springframework.ai.model.function.FunctionCallback; import org.springframework.ai.model.function.FunctionCallbackContext; import org.springframework.ai.openai.OpenAiChatClient; @@ -37,8 +38,6 @@ import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import org.springframework.web.client.RestClient; -import java.util.List; - @AutoConfiguration(after = { RestClientAutoConfiguration.class }) @ConditionalOnClass(OpenAiApi.class) @EnableConfigurationProperties({ OpenAiConnectionProperties.class, OpenAiChatProperties.class, @@ -82,7 +81,7 @@ public class OpenAiAutoConfiguration { @ConditionalOnMissingBean @ConditionalOnProperty(prefix = OpenAiEmbeddingProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true) - public EmbeddingClient openAiEmbeddingClient(OpenAiConnectionProperties commonProperties, + public OpenAiEmbeddingClient openAiEmbeddingClient(OpenAiConnectionProperties commonProperties, OpenAiEmbeddingProperties embeddingProperties, RestClient.Builder restClientBuilder) { String apiKey = StringUtils.hasText(embeddingProperties.getApiKey()) ? embeddingProperties.getApiKey() diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/transformers/TransformersEmbeddingClientAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/transformers/TransformersEmbeddingClientAutoConfiguration.java index 129fcea38..336cab5af 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/transformers/TransformersEmbeddingClientAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/transformers/TransformersEmbeddingClientAutoConfiguration.java @@ -40,7 +40,7 @@ public class TransformersEmbeddingClientAutoConfiguration { @ConditionalOnMissingBean @ConditionalOnProperty(prefix = TransformersEmbeddingClientProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true) - public EmbeddingClient embeddingClient(TransformersEmbeddingClientProperties properties) { + public TransformersEmbeddingClient embeddingClient(TransformersEmbeddingClientProperties properties) { TransformersEmbeddingClient embeddingClient = new TransformersEmbeddingClient(properties.getMetadataMode()); diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/transformers/TransformersEmbeddingClientProperties.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/transformers/TransformersEmbeddingClientProperties.java index 97ac8ebe8..b2e75b6da 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/transformers/TransformersEmbeddingClientProperties.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/transformers/TransformersEmbeddingClientProperties.java @@ -73,10 +73,11 @@ public class TransformersEmbeddingClientProperties { * 'truncation', 'padding', 'maxLength', 'stride' and 'padToMultipleOf'. Leave * empty to fall back to the defaults. */ + @NestedConfigurationProperty private Map options = new HashMap<>(); public String getUri() { - return uri; + return this.uri; } public void setUri(String uri) { @@ -84,7 +85,7 @@ public class TransformersEmbeddingClientProperties { } public Map getOptions() { - return options; + return this.options; } public void setOptions(Map options) { @@ -111,7 +112,7 @@ public class TransformersEmbeddingClientProperties { private String directory = DEFAULT_CACHE_DIRECTORY; public boolean isEnabled() { - return enabled; + return this.enabled; } public void setEnabled(boolean enabled) { @@ -119,7 +120,7 @@ public class TransformersEmbeddingClientProperties { } public String getDirectory() { - return directory; + return this.directory; } public void setDirectory(String directory) { @@ -135,7 +136,7 @@ public class TransformersEmbeddingClientProperties { private final Cache cache = new Cache(); public Cache getCache() { - return cache; + return this.cache; } public static class Onnx { @@ -161,7 +162,7 @@ public class TransformersEmbeddingClientProperties { private int gpuDeviceId = -1; public String getModelUri() { - return modelUri; + return this.modelUri; } public void setModelUri(String modelUri) { @@ -169,7 +170,7 @@ public class TransformersEmbeddingClientProperties { } public int getGpuDeviceId() { - return gpuDeviceId; + return this.gpuDeviceId; } public void setGpuDeviceId(int gpuDeviceId) { @@ -177,7 +178,7 @@ public class TransformersEmbeddingClientProperties { } public String getModelOutputName() { - return modelOutputName; + return this.modelOutputName; } public void setModelOutputName(String modelOutputName) { @@ -190,7 +191,7 @@ public class TransformersEmbeddingClientProperties { private final Onnx onnx = new Onnx(); public Onnx getOnnx() { - return onnx; + return this.onnx; } /** @@ -204,11 +205,11 @@ public class TransformersEmbeddingClientProperties { private MetadataMode metadataMode = MetadataMode.NONE; public Tokenizer getTokenizer() { - return tokenizer; + return this.tokenizer; } public MetadataMode getMetadataMode() { - return metadataMode; + return this.metadataMode; } public void setMetadataMode(MetadataMode metadataMode) {