From 428ab9ad4e19bfe20e5e6a96dcb906c1906515cd Mon Sep 17 00:00:00 2001 From: "Manni, William" Date: Thu, 14 Mar 2024 22:06:55 +0100 Subject: [PATCH 1/6] MS Entra authentication --- document-readers/tika-reader/pom.xml | 6 ++++ spring-ai-spring-boot-autoconfigure/pom.xml | 6 ++++ .../openai/AzureOpenAiAutoConfiguration.java | 36 ++++++++++++++++--- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/document-readers/tika-reader/pom.xml b/document-readers/tika-reader/pom.xml index 76f52a057a1..1cea0e71692 100644 --- a/document-readers/tika-reader/pom.xml +++ b/document-readers/tika-reader/pom.xml @@ -41,6 +41,12 @@ org.apache.tika tika-parsers-standard-package ${tika.version} + + + xml-apis + xml-apis + + diff --git a/spring-ai-spring-boot-autoconfigure/pom.xml b/spring-ai-spring-boot-autoconfigure/pom.xml index 80c6aacf12d..18917a1b842 100644 --- a/spring-ai-spring-boot-autoconfigure/pom.xml +++ b/spring-ai-spring-boot-autoconfigure/pom.xml @@ -223,6 +223,12 @@ true + + com.azure.spring + spring-cloud-azure-starter-active-directory + 5.8.0 + + diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiAutoConfiguration.java index 78efa6d76e3..07090be485b 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiAutoConfiguration.java @@ -5,7 +5,7 @@ * 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 + * 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, @@ -22,6 +22,12 @@ import com.azure.core.credential.AzureKeyCredential; import com.azure.core.util.ClientOptions; +import com.azure.core.credential.TokenCredential; +import com.azure.core.http.policy.HttpLogDetailLevel; +import com.azure.core.http.policy.HttpLogOptions; +import com.azure.core.management.AzureEnvironment; +import com.azure.core.management.profile.AzureProfile; +import com.azure.identity.ClientSecretCredentialBuilder; import org.springframework.ai.azure.openai.AzureOpenAiChatClient; import org.springframework.ai.azure.openai.AzureOpenAiEmbeddingClient; import org.springframework.ai.model.function.FunctionCallback; @@ -49,10 +55,30 @@ public OpenAIClient openAIClient(AzureOpenAiConnectionProperties connectionPrope Assert.hasText(connectionProperties.getApiKey(), "API key must not be empty"); Assert.hasText(connectionProperties.getEndpoint(), "Endpoint must not be empty"); - return new OpenAIClientBuilder().endpoint(connectionProperties.getEndpoint()) - .credential(new AzureKeyCredential(connectionProperties.getApiKey())) - .clientOptions(new ClientOptions().setApplicationId("spring-ai")) - .buildClient(); + if ("entra".equals(connectionProperties.getAuthType())) { + HttpLogOptions options = new HttpLogOptions(); + HttpLogDetailLevel level = HttpLogDetailLevel.BODY_AND_HEADERS; + options.setLogLevel(level); + options.setPrettyPrintBody(true); + + AzureProfile azureProfile = new AzureProfile(AzureEnvironment.AZURE); + TokenCredential tokenCredential = new ClientSecretCredentialBuilder() + .clientId(connectionProperties.getClientId()) + .clientSecret(connectionProperties.getClientSecret()) + .tenantId(connectionProperties.getTenantId()) + .authorityHost(azureProfile.getEnvironment().getActiveDirectoryEndpoint()) + .build(); + return new OpenAIClientBuilder().httpLogOptions(options) + .endpoint(connectionProperties.getEndpoint()) + .credential(tokenCredential) + .clientOptions(new ClientOptions().setApplicationId("spring-ai")) + .buildClient(); + } + else + return new OpenAIClientBuilder().endpoint(connectionProperties.getEndpoint()) + .credential(new AzureKeyCredential(connectionProperties.getApiKey())) + .clientOptions(new ClientOptions().setApplicationId("spring-ai")) + .buildClient(); } @Bean From 14b4ca5e6342dc6d7ba79ceb31da30639a5c758a Mon Sep 17 00:00:00 2001 From: "Manni, William" Date: Fri, 15 Mar 2024 07:46:16 +0100 Subject: [PATCH 2/6] Entra properties --- .../AzureOpenAiConnectionProperties.java | 64 +++++++++++++++++-- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiConnectionProperties.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiConnectionProperties.java index 16d0803fba9..b5e8914d555 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiConnectionProperties.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiConnectionProperties.java @@ -34,6 +34,38 @@ public class AzureOpenAiConnectionProperties { */ private String endpoint; + /** + * Azure OpenAI API authType. From the Azure AI OpenAI `Keys and Endpoint` section + * under `Resource Management`. + */ + private String authType; + + /** + * Azure OpenAI API clientId. From the Azure AI OpenAI `Keys and Endpoint` section + * under `Resource Management`. + */ + private String clientId; + + /** + * Azure OpenAI API clientSecret. From the Azure AI OpenAI `Keys and Endpoint` section + * under `Resource Management`. + */ + private String clientSecret; + + /** + * Azure OpenAI API tenantId. From the Azure AI OpenAI `Keys and Endpoint` section + * under `Resource Management`. + */ + private String tenantId; + + public void setApiKey(String apiKey) { + this.apiKey = apiKey; + } + + public String getApiKey() { + return apiKey; + } + public String getEndpoint() { return endpoint; } @@ -42,12 +74,36 @@ public void setEndpoint(String endpoint) { this.endpoint = endpoint; } - public void setApiKey(String apiKey) { - this.apiKey = apiKey; + public String getAuthType() { + return authType; } - public String getApiKey() { - return apiKey; + public void setAuthType(String authType) { + this.authType = authType; + } + + public String getClientId() { + return clientId; + } + + public void setClientId(String clientId) { + this.clientId = clientId; + } + + public String getClientSecret() { + return clientSecret; + } + + public void setClientSecret(String clientSecret) { + this.clientSecret = clientSecret; + } + + public String getTenantId() { + return tenantId; + } + + public void setTenantId(String tenantId) { + this.tenantId = tenantId; } } From ffa40fee638ab1e77634b39b3fc0f8da1b39507b Mon Sep 17 00:00:00 2001 From: "Manni, William" Date: Fri, 15 Mar 2024 11:51:13 +0100 Subject: [PATCH 3/6] code refactor Microsoft Entra authentication, part of the Entra ID identity platform, enhances security and simplifies user sign-in across devices, applications, and services. It goes beyond basic username and password verification, incorporating features like self-service password reset, multifactor authentication, hybrid integration for password changes, passwordless authentication, and policies to enforce strong passwords. These components work together to protect user identities, reduce help desk dependencies, and offer a more streamlined sign-in experience. https://learn.microsoft.com/en-us/entra/identity/authentication/overview-authentication https://learn.microsoft.com/en-us/azure/databricks/dev-tools/service-prin-aad-token --- .../openai/AzureOpenAiAutoConfiguration.java | 33 ++++++++++++++----- .../AzureOpenAiConnectionProperties.java | 14 ++++++++ 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiAutoConfiguration.java index 07090be485b..21455a01658 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiAutoConfiguration.java @@ -52,33 +52,50 @@ public class AzureOpenAiAutoConfiguration { @ConditionalOnMissingBean public OpenAIClient openAIClient(AzureOpenAiConnectionProperties connectionProperties) { - Assert.hasText(connectionProperties.getApiKey(), "API key must not be empty"); - Assert.hasText(connectionProperties.getEndpoint(), "Endpoint must not be empty"); - - if ("entra".equals(connectionProperties.getAuthType())) { - HttpLogOptions options = new HttpLogOptions(); + HttpLogOptions options = new HttpLogOptions(); + if (connectionProperties.getEnableLog()) { HttpLogDetailLevel level = HttpLogDetailLevel.BODY_AND_HEADERS; options.setLogLevel(level); options.setPrettyPrintBody(true); + } + + /* + * https://learn.microsoft.com/en-us/azure/databricks/dev-tools/service-prin-aad- + * token + */ + if ("entra".equals(connectionProperties.getAuthType())) { + Assert.hasText(connectionProperties.getEndpoint(), "Endpoint must not be empty"); + Assert.hasText(connectionProperties.getClientId(), "Client ID must not be empty"); + Assert.hasText(connectionProperties.getClientSecret(), "Client Secret must not be empty"); + Assert.hasText(connectionProperties.getTenantId(), "Tenant ID must not be empty"); AzureProfile azureProfile = new AzureProfile(AzureEnvironment.AZURE); + TokenCredential tokenCredential = new ClientSecretCredentialBuilder() .clientId(connectionProperties.getClientId()) .clientSecret(connectionProperties.getClientSecret()) .tenantId(connectionProperties.getTenantId()) .authorityHost(azureProfile.getEnvironment().getActiveDirectoryEndpoint()) .build(); + return new OpenAIClientBuilder().httpLogOptions(options) .endpoint(connectionProperties.getEndpoint()) .credential(tokenCredential) .clientOptions(new ClientOptions().setApplicationId("spring-ai")) .buildClient(); } - else - return new OpenAIClientBuilder().endpoint(connectionProperties.getEndpoint()) - .credential(new AzureKeyCredential(connectionProperties.getApiKey())) + else { + Assert.hasText(connectionProperties.getApiKey(), "API key must not be empty"); + Assert.hasText(connectionProperties.getEndpoint(), "Endpoint must not be empty"); + + AzureKeyCredential keyCredential = new AzureKeyCredential(connectionProperties.getApiKey()); + + return new OpenAIClientBuilder().httpLogOptions(options) + .endpoint(connectionProperties.getEndpoint()) + .credential(keyCredential) .clientOptions(new ClientOptions().setApplicationId("spring-ai")) .buildClient(); + } } @Bean diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiConnectionProperties.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiConnectionProperties.java index b5e8914d555..8e4b3466b86 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiConnectionProperties.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiConnectionProperties.java @@ -58,6 +58,12 @@ public class AzureOpenAiConnectionProperties { */ private String tenantId; + /** + * Azure OpenAI API enableLog. From the Azure AI OpenAI `Keys and Endpoint` section + * under `Resource Management`. + */ + private Boolean enableLog; + public void setApiKey(String apiKey) { this.apiKey = apiKey; } @@ -106,4 +112,12 @@ public void setTenantId(String tenantId) { this.tenantId = tenantId; } + public Boolean getEnableLog() { + return enableLog; + } + + public void setEnableLog(Boolean enableLog) { + this.enableLog = enableLog; + } + } From a2a8969f403ebb9cf6ca67b7a59e362293ee0d78 Mon Sep 17 00:00:00 2001 From: williamspindox Date: Mon, 20 May 2024 14:23:39 +0200 Subject: [PATCH 4/6] merge --- README.md | 2 +- .../TransformersEmbeddingClient.java | 9 ++++++--- .../ai/watsonx/api/WatsonxAiApi.java | 19 +++++++++++++++---- spring-ai-spring-boot-autoconfigure/pom.xml | 14 ++++++-------- .../openai/AzureOpenAiAutoConfiguration.java | 2 +- 5 files changed, 29 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 1b798a2c0a2..346ff99e4b7 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Let's make your `@Beans` intelligent! For further information go to our [Spring AI reference documentation](https://docs.spring.io/spring-ai/reference/). -### Breadking changes +### Breaking changes (15.05.2024) On our march to release 1.0 M1 we have made several breaking changes. Apologies, it is for the best! diff --git a/models/spring-ai-transformers/src/main/java/org/springframework/ai/transformers/TransformersEmbeddingClient.java b/models/spring-ai-transformers/src/main/java/org/springframework/ai/transformers/TransformersEmbeddingClient.java index d5b1d1933f0..e79970593f6 100644 --- a/models/spring-ai-transformers/src/main/java/org/springframework/ai/transformers/TransformersEmbeddingClient.java +++ b/models/spring-ai-transformers/src/main/java/org/springframework/ai/transformers/TransformersEmbeddingClient.java @@ -46,6 +46,7 @@ import org.springframework.ai.embedding.EmbeddingRequest; import org.springframework.ai.embedding.EmbeddingResponse; import org.springframework.beans.factory.InitializingBean; +import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; import org.springframework.util.Assert; @@ -61,11 +62,10 @@ public class TransformersEmbeddingClient extends AbstractEmbeddingClient impleme private static final Log logger = LogFactory.getLog(TransformersEmbeddingClient.class); // ONNX tokenizer for the all-MiniLM-L6-v2 generative - public final static String DEFAULT_ONNX_TOKENIZER_URI = "https://raw.githubusercontent.com/spring-projects/spring-ai/main/models/spring-ai-transformers/src/main/resources/onnx/all-MiniLM-L6-v2/tokenizer.json"; - + public final static String DEFAULT_ONNX_TOKENIZER_URI = "classpath:onnx/all-MiniLM-L6-v2/tokenizer.json"; // ONNX generative for all-MiniLM-L6-v2 pre-trained transformer: // https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2 - public final static String DEFAULT_ONNX_MODEL_URI = "https://github.com/spring-projects/spring-ai/raw/main/models/spring-ai-transformers/src/main/resources/onnx/all-MiniLM-L6-v2/model.onnx"; + public final static String DEFAULT_ONNX_MODEL_URI = "classpath:onnx/all-MiniLM-L6-v2/model.onnx"; public final static String DEFAULT_MODEL_OUTPUT_NAME = "last_hidden_state"; @@ -352,6 +352,9 @@ private List toDoubleList(float[] floats) { } private static Resource toResource(String uri) { + if (uri.startsWith("classpath:")) { + return new ClassPathResource(uri.substring("classpath:".length())); + } return new DefaultResourceLoader().getResource(uri); } diff --git a/models/spring-ai-watsonx-ai/src/main/java/org/springframework/ai/watsonx/api/WatsonxAiApi.java b/models/spring-ai-watsonx-ai/src/main/java/org/springframework/ai/watsonx/api/WatsonxAiApi.java index 18ae0c4b061..30673ce617b 100644 --- a/models/spring-ai-watsonx-ai/src/main/java/org/springframework/ai/watsonx/api/WatsonxAiApi.java +++ b/models/spring-ai-watsonx-ai/src/main/java/org/springframework/ai/watsonx/api/WatsonxAiApi.java @@ -20,8 +20,11 @@ import java.util.function.Consumer; import com.ibm.cloud.sdk.core.security.IamAuthenticator; +import com.ibm.cloud.sdk.core.security.IamToken; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.retry.annotation.Backoff; +import org.springframework.retry.annotation.Retryable; import reactor.core.publisher.Flux; import org.springframework.ai.retry.RetryUtils; @@ -50,6 +53,7 @@ public class WatsonxAiApi { private final String streamEndpoint; private final String textEndpoint; private final String projectId; + private IamToken token; /** * Create a new chat api. @@ -72,6 +76,7 @@ public WatsonxAiApi( this.textEndpoint = textEndpoint; this.projectId = projectId; this.iamAuthenticator = IamAuthenticator.fromConfiguration(Map.of("APIKEY", IAMToken)); + this.token = this.iamAuthenticator.requestToken(); Consumer defaultHeaders = headers -> { headers.setContentType(MediaType.APPLICATION_JSON); @@ -88,27 +93,33 @@ public WatsonxAiApi( .build(); } + @Retryable(retryFor = Exception.class, maxAttempts = 3, backoff = @Backoff(random = true, delay = 1200, maxDelay = 7000, multiplier = 2.5)) public ResponseEntity generate(WatsonxAiRequest watsonxAiRequest) { Assert.notNull(watsonxAiRequest, WATSONX_REQUEST_CANNOT_BE_NULL); - String bearer = this.iamAuthenticator.requestToken().getAccessToken(); + if(this.token.needsRefresh()) { + this.token = this.iamAuthenticator.requestToken(); + } return this.restClient.post() .uri(this.textEndpoint) - .header(HttpHeaders.AUTHORIZATION, "Bearer " + bearer) + .header(HttpHeaders.AUTHORIZATION, "Bearer " + this.token.getAccessToken()) .body(watsonxAiRequest.withProjectId(projectId)) .retrieve() .toEntity(WatsonxAiResponse.class); } + @Retryable(retryFor = Exception.class, maxAttempts = 3, backoff = @Backoff(random = true, delay = 1200, maxDelay = 7000, multiplier = 2.5)) public Flux generateStreaming(WatsonxAiRequest watsonxAiRequest) { Assert.notNull(watsonxAiRequest, WATSONX_REQUEST_CANNOT_BE_NULL); - String bearer = this.iamAuthenticator.requestToken().getAccessToken(); + if(this.token.needsRefresh()) { + this.token = this.iamAuthenticator.requestToken(); + } return this.webClient.post() .uri(this.streamEndpoint) - .header(HttpHeaders.AUTHORIZATION, "Bearer " + bearer) + .header(HttpHeaders.AUTHORIZATION, "Bearer " + this.token.getAccessToken()) .bodyValue(watsonxAiRequest.withProjectId(this.projectId)) .retrieve() .bodyToFlux(WatsonxAiResponse.class) diff --git a/spring-ai-spring-boot-autoconfigure/pom.xml b/spring-ai-spring-boot-autoconfigure/pom.xml index 6087c89ab70..66be71eb0c5 100644 --- a/spring-ai-spring-boot-autoconfigure/pom.xml +++ b/spring-ai-spring-boot-autoconfigure/pom.xml @@ -247,14 +247,6 @@ true - - com.azure.spring - spring-cloud-azure-starter-active-directory - 5.8.0 - - - - org.springframework.ai spring-ai-mongodb-atlas-store @@ -275,6 +267,12 @@ true + + com.azure.spring + spring-cloud-azure-starter-active-directory + 5.8.0 + + diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiAutoConfiguration.java index 94b6918e4f4..21455a01658 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiAutoConfiguration.java @@ -43,7 +43,7 @@ import org.springframework.util.CollectionUtils; @AutoConfiguration -@ConditionalOnClass({ OpenAIClientBuilder.class, AzureOpenAiChatClient.class }) +@ConditionalOnClass(OpenAIClientBuilder.class) @EnableConfigurationProperties({ AzureOpenAiChatProperties.class, AzureOpenAiEmbeddingProperties.class, AzureOpenAiConnectionProperties.class }) public class AzureOpenAiAutoConfiguration { From 3eff86bffa2bae960f14228476294481320e71aa Mon Sep 17 00:00:00 2001 From: "Manni, William" Date: Mon, 20 May 2024 23:13:05 +0200 Subject: [PATCH 5/6] spring-javaformat:apply --- .../ai/transformers/TransformersEmbeddingClient.java | 1 + 1 file changed, 1 insertion(+) diff --git a/models/spring-ai-transformers/src/main/java/org/springframework/ai/transformers/TransformersEmbeddingClient.java b/models/spring-ai-transformers/src/main/java/org/springframework/ai/transformers/TransformersEmbeddingClient.java index e79970593f6..fb913837b1e 100644 --- a/models/spring-ai-transformers/src/main/java/org/springframework/ai/transformers/TransformersEmbeddingClient.java +++ b/models/spring-ai-transformers/src/main/java/org/springframework/ai/transformers/TransformersEmbeddingClient.java @@ -63,6 +63,7 @@ public class TransformersEmbeddingClient extends AbstractEmbeddingClient impleme // ONNX tokenizer for the all-MiniLM-L6-v2 generative public final static String DEFAULT_ONNX_TOKENIZER_URI = "classpath:onnx/all-MiniLM-L6-v2/tokenizer.json"; + // ONNX generative for all-MiniLM-L6-v2 pre-trained transformer: // https://huggingface.co/sentence-transformers/all-MiniLM-L6-v2 public final static String DEFAULT_ONNX_MODEL_URI = "classpath:onnx/all-MiniLM-L6-v2/model.onnx"; From 1cb3f49c720aaee4b2b3bdc692a3e2ae06e3635d Mon Sep 17 00:00:00 2001 From: "Manni, William" Date: Fri, 24 May 2024 10:41:11 +0200 Subject: [PATCH 6/6] Merge branch 'main' of https://github.com/spring-projects/spring-ai # Conflicts: # spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiAutoConfiguration.java --- .../openai/AzureOpenAiAutoConfiguration.java | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiAutoConfiguration.java index 567eff2f378..62bafc2cf51 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/azure/openai/AzureOpenAiAutoConfiguration.java @@ -51,26 +51,17 @@ public class AzureOpenAiAutoConfiguration { @Bean @ConditionalOnMissingBean public OpenAIClient openAIClient(AzureOpenAiConnectionProperties connectionProperties) { - - HttpLogOptions options = new HttpLogOptions(); - if (connectionProperties.getEnableLog()) { - HttpLogDetailLevel level = HttpLogDetailLevel.BODY_AND_HEADERS; - options.setLogLevel(level); - options.setPrettyPrintBody(true); - } - /* * https://learn.microsoft.com/en-us/azure/databricks/dev-tools/service-prin-aad- * token */ - if ("entra".equals(connectionProperties.getAuthType())) { + if ("ms-entra-id".equals(connectionProperties.getAuthType())) { Assert.hasText(connectionProperties.getEndpoint(), "Endpoint must not be empty"); Assert.hasText(connectionProperties.getClientId(), "Client ID must not be empty"); Assert.hasText(connectionProperties.getClientSecret(), "Client Secret must not be empty"); Assert.hasText(connectionProperties.getTenantId(), "Tenant ID must not be empty"); AzureProfile azureProfile = new AzureProfile(AzureEnvironment.AZURE); - TokenCredential tokenCredential = new ClientSecretCredentialBuilder() .clientId(connectionProperties.getClientId()) .clientSecret(connectionProperties.getClientSecret()) @@ -78,6 +69,13 @@ public OpenAIClient openAIClient(AzureOpenAiConnectionProperties connectionPrope .authorityHost(azureProfile.getEnvironment().getActiveDirectoryEndpoint()) .build(); + HttpLogOptions options = new HttpLogOptions(); + if (connectionProperties.getEnableLog()) { + HttpLogDetailLevel level = HttpLogDetailLevel.BODY_AND_HEADERS; + options.setLogLevel(level); + options.setPrettyPrintBody(true); + } + return new OpenAIClientBuilder().httpLogOptions(options) .endpoint(connectionProperties.getEndpoint()) .credential(tokenCredential) @@ -87,6 +85,7 @@ public OpenAIClient openAIClient(AzureOpenAiConnectionProperties connectionPrope else { Assert.hasText(connectionProperties.getApiKey(), "API key must not be empty"); Assert.hasText(connectionProperties.getEndpoint(), "Endpoint must not be empty"); + return new OpenAIClientBuilder().endpoint(connectionProperties.getEndpoint()) .credential(new AzureKeyCredential(connectionProperties.getApiKey())) .clientOptions(new ClientOptions().setApplicationId("spring-ai"))