remove use of @OpenAiApiKey annotation
This commit is contained in:
@@ -1,35 +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.openai.api;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* Qualifier annotation for OpenAI API key beans. Used to distinguish OpenAI API keys from
|
||||
* other provider API keys.
|
||||
*
|
||||
* @author Mark Pollack
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Qualifier
|
||||
public @interface OpenAiApiKey {
|
||||
|
||||
}
|
||||
@@ -27,12 +27,10 @@ import org.springframework.ai.autoconfigure.retry.SpringAiRetryAutoConfiguration
|
||||
import org.springframework.ai.chat.observation.ChatModelObservationConvention;
|
||||
import org.springframework.ai.embedding.observation.EmbeddingModelObservationConvention;
|
||||
import org.springframework.ai.image.observation.ImageModelObservationConvention;
|
||||
import org.springframework.ai.model.SimpleApiKey;
|
||||
import org.springframework.ai.model.function.DefaultFunctionCallbackResolver;
|
||||
import org.springframework.ai.model.function.FunctionCallback;
|
||||
import org.springframework.ai.model.function.FunctionCallbackResolver;
|
||||
import org.springframework.ai.model.ApiKey;
|
||||
import org.springframework.ai.model.SimpleApiKey;
|
||||
import org.springframework.ai.openai.api.OpenAiApiKey;
|
||||
import org.springframework.ai.openai.OpenAiAudioSpeechModel;
|
||||
import org.springframework.ai.openai.OpenAiAudioTranscriptionModel;
|
||||
import org.springframework.ai.openai.OpenAiChatModel;
|
||||
@@ -80,13 +78,6 @@ import org.springframework.web.reactive.function.client.WebClient;
|
||||
WebClientAutoConfiguration.class })
|
||||
public class OpenAiAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(ApiKey.class)
|
||||
@OpenAiApiKey
|
||||
public ApiKey openAiApiKey(OpenAiConnectionProperties properties) {
|
||||
return new SimpleApiKey(properties.getApiKey());
|
||||
}
|
||||
|
||||
private static @NotNull ResolvedConnectionProperties resolveConnectionProperties(
|
||||
OpenAiParentProperties commonProperties, OpenAiParentProperties modelProperties, String modelType) {
|
||||
|
||||
@@ -126,11 +117,11 @@ public class OpenAiAutoConfiguration {
|
||||
ObjectProvider<WebClient.Builder> webClientBuilderProvider, List<FunctionCallback> toolFunctionCallbacks,
|
||||
FunctionCallbackResolver functionCallbackResolver, RetryTemplate retryTemplate,
|
||||
ResponseErrorHandler responseErrorHandler, ObjectProvider<ObservationRegistry> observationRegistry,
|
||||
ObjectProvider<ChatModelObservationConvention> observationConvention, @OpenAiApiKey ApiKey apiKey) {
|
||||
ObjectProvider<ChatModelObservationConvention> observationConvention) {
|
||||
|
||||
var openAiApi = openAiApi(chatProperties, commonProperties,
|
||||
restClientBuilderProvider.getIfAvailable(RestClient::builder),
|
||||
webClientBuilderProvider.getIfAvailable(WebClient::builder), responseErrorHandler, "chat", apiKey);
|
||||
webClientBuilderProvider.getIfAvailable(WebClient::builder), responseErrorHandler, "chat");
|
||||
|
||||
var chatModel = new OpenAiChatModel(openAiApi, chatProperties.getOptions(), functionCallbackResolver,
|
||||
toolFunctionCallbacks, retryTemplate, observationRegistry.getIfUnique(() -> ObservationRegistry.NOOP));
|
||||
@@ -148,11 +139,11 @@ public class OpenAiAutoConfiguration {
|
||||
OpenAiEmbeddingProperties embeddingProperties, ObjectProvider<RestClient.Builder> restClientBuilderProvider,
|
||||
ObjectProvider<WebClient.Builder> webClientBuilderProvider, RetryTemplate retryTemplate,
|
||||
ResponseErrorHandler responseErrorHandler, ObjectProvider<ObservationRegistry> observationRegistry,
|
||||
ObjectProvider<EmbeddingModelObservationConvention> observationConvention, @OpenAiApiKey ApiKey apiKey) {
|
||||
ObjectProvider<EmbeddingModelObservationConvention> observationConvention) {
|
||||
|
||||
var openAiApi = openAiApi(embeddingProperties, commonProperties,
|
||||
restClientBuilderProvider.getIfAvailable(RestClient::builder),
|
||||
webClientBuilderProvider.getIfAvailable(WebClient::builder), responseErrorHandler, "embedding", apiKey);
|
||||
webClientBuilderProvider.getIfAvailable(WebClient::builder), responseErrorHandler, "embedding");
|
||||
|
||||
var embeddingModel = new OpenAiEmbeddingModel(openAiApi, embeddingProperties.getMetadataMode(),
|
||||
embeddingProperties.getOptions(), retryTemplate,
|
||||
@@ -165,14 +156,14 @@ public class OpenAiAutoConfiguration {
|
||||
|
||||
private OpenAiApi openAiApi(OpenAiChatProperties chatProperties, OpenAiConnectionProperties commonProperties,
|
||||
RestClient.Builder restClientBuilder, WebClient.Builder webClientBuilder,
|
||||
ResponseErrorHandler responseErrorHandler, String modelType, ApiKey apiKey) {
|
||||
ResponseErrorHandler responseErrorHandler, String modelType) {
|
||||
|
||||
ResolvedConnectionProperties resolved = resolveConnectionProperties(commonProperties, chatProperties,
|
||||
modelType);
|
||||
|
||||
return OpenAiApi.builder()
|
||||
.baseUrl(resolved.baseUrl())
|
||||
.apiKey(apiKey)
|
||||
.apiKey(new SimpleApiKey(resolved.apiKey()))
|
||||
.headers(resolved.headers())
|
||||
.completionsPath(chatProperties.getCompletionsPath())
|
||||
.embeddingsPath(OpenAiEmbeddingProperties.DEFAULT_EMBEDDINGS_PATH)
|
||||
@@ -184,15 +175,14 @@ public class OpenAiAutoConfiguration {
|
||||
|
||||
private OpenAiApi openAiApi(OpenAiEmbeddingProperties embeddingProperties,
|
||||
OpenAiConnectionProperties commonProperties, RestClient.Builder restClientBuilder,
|
||||
WebClient.Builder webClientBuilder, ResponseErrorHandler responseErrorHandler, String modelType,
|
||||
ApiKey apiKey) {
|
||||
WebClient.Builder webClientBuilder, ResponseErrorHandler responseErrorHandler, String modelType) {
|
||||
|
||||
ResolvedConnectionProperties resolved = resolveConnectionProperties(commonProperties, embeddingProperties,
|
||||
modelType);
|
||||
|
||||
return OpenAiApi.builder()
|
||||
.baseUrl(resolved.baseUrl())
|
||||
.apiKey(apiKey)
|
||||
.apiKey(new SimpleApiKey(resolved.apiKey()))
|
||||
.headers(resolved.headers())
|
||||
.completionsPath(OpenAiChatProperties.DEFAULT_COMPLETIONS_PATH)
|
||||
.embeddingsPath(embeddingProperties.getEmbeddingsPath())
|
||||
|
||||
@@ -1,125 +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.openai;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.ai.model.ApiKey;
|
||||
import org.springframework.ai.model.SimpleApiKey;
|
||||
import org.springframework.ai.openai.api.OpenAiApiKey;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for OpenAI ApiKey configuration behavior.
|
||||
*
|
||||
* @author Mark Pollack
|
||||
*/
|
||||
class OpenAiApiKeyConfigurationTests {
|
||||
|
||||
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||
.withPropertyValues("spring.ai.openai.apiKey=test-key")
|
||||
.withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class));
|
||||
|
||||
@Configuration
|
||||
static class CustomConfiguration {
|
||||
|
||||
@Bean
|
||||
@OpenAiApiKey
|
||||
public ApiKey customOpenAiKey() {
|
||||
return new ApiKey() {
|
||||
@Override
|
||||
public String getValue() {
|
||||
return "custom-key";
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
void defaultApiKeyConfiguration() {
|
||||
this.contextRunner.run(context -> {
|
||||
ApiKey apiKey = context.getBean(ApiKey.class, ApiKey.class);
|
||||
assertThat(apiKey).isNotNull();
|
||||
assertThat(apiKey).isInstanceOf(SimpleApiKey.class);
|
||||
assertThat(apiKey.getValue()).isEqualTo("test-key");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void customApiKeyConfiguration() {
|
||||
this.contextRunner.withUserConfiguration(CustomConfiguration.class).run(context -> {
|
||||
ApiKey apiKey = context.getBean(ApiKey.class, ApiKey.class);
|
||||
assertThat(apiKey).isNotNull();
|
||||
assertThat(apiKey).isNotInstanceOf(SimpleApiKey.class);
|
||||
assertThat(apiKey.getValue()).isEqualTo("custom-key");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void multipleUnqualifiedApiKeysFailsToStart() {
|
||||
this.contextRunner.withUserConfiguration(MultipleUnqualifiedApiKeysConfiguration.class).run(context -> {
|
||||
assertThat(context).hasFailed();
|
||||
Throwable failure = context.getStartupFailure();
|
||||
while (failure.getCause() != null && !(failure instanceof NoSuchBeanDefinitionException)) {
|
||||
failure = failure.getCause();
|
||||
}
|
||||
assertThat(failure).isInstanceOf(NoSuchBeanDefinitionException.class)
|
||||
.hasMessageContaining(
|
||||
"No qualifying bean of type 'org.springframework.ai.model.ApiKey' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.ai.openai.api.OpenAiApiKey()}");
|
||||
});
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class MultipleUnqualifiedApiKeysConfiguration {
|
||||
|
||||
@Bean
|
||||
public ApiKey openAiKey() {
|
||||
return () -> "openai-key";
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ApiKey otherKey() {
|
||||
return () -> "other-key";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class MultipleQualifiedApiKeysConfiguration {
|
||||
|
||||
@Bean
|
||||
@OpenAiApiKey
|
||||
public ApiKey openAiKey() {
|
||||
return () -> "openai-key";
|
||||
}
|
||||
|
||||
@Bean
|
||||
@OtherApiKey
|
||||
public ApiKey otherKey() {
|
||||
return () -> "other-key";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user