diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/openai/OpenAiAudioSpeechProperties.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/openai/OpenAiAudioSpeechProperties.java index ee21e89c6..8d583c205 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/openai/OpenAiAudioSpeechProperties.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/openai/OpenAiAudioSpeechProperties.java @@ -28,6 +28,7 @@ import org.springframework.boot.context.properties.NestedConfigurationProperty; * alloy, and speed = 1. * * @author Ahmed Yousri + * @author Stefan Vassilev */ @ConfigurationProperties(OpenAiAudioSpeechProperties.CONFIG_PREFIX) public class OpenAiAudioSpeechProperties extends OpenAiParentProperties { @@ -42,6 +43,11 @@ public class OpenAiAudioSpeechProperties extends OpenAiParentProperties { private static final OpenAiAudioApi.SpeechRequest.AudioResponseFormat DEFAULT_RESPONSE_FORMAT = OpenAiAudioApi.SpeechRequest.AudioResponseFormat.MP3; + /** + * Enable OpenAI audio speech model. + */ + private boolean enabled = true; + @NestedConfigurationProperty private OpenAiAudioSpeechOptions options = OpenAiAudioSpeechOptions.builder() .withModel(DEFAULT_SPEECH_MODEL) @@ -58,4 +64,12 @@ public class OpenAiAudioSpeechProperties extends OpenAiParentProperties { this.options = options; } + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + } diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/openai/OpenAiAudioTranscriptionProperties.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/openai/OpenAiAudioTranscriptionProperties.java index ab27093f8..e8546e089 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/openai/OpenAiAudioTranscriptionProperties.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/openai/OpenAiAudioTranscriptionProperties.java @@ -31,6 +31,11 @@ public class OpenAiAudioTranscriptionProperties extends OpenAiParentProperties { private static final OpenAiAudioApi.TranscriptResponseFormat DEFAULT_RESPONSE_FORMAT = OpenAiAudioApi.TranscriptResponseFormat.TEXT; + /** + * Enable OpenAI audio transcription model. + */ + private boolean enabled = true; + @NestedConfigurationProperty private OpenAiAudioTranscriptionOptions options = OpenAiAudioTranscriptionOptions.builder() .withModel(DEFAULT_TRANSCRIPTION_MODEL) @@ -46,4 +51,12 @@ public class OpenAiAudioTranscriptionProperties extends OpenAiParentProperties { this.options = options; } + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + } 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 86d654945..44d9d80de 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 @@ -21,7 +21,6 @@ import org.springframework.ai.autoconfigure.retry.SpringAiRetryAutoConfiguration import org.springframework.ai.model.function.FunctionCallback; import org.springframework.ai.model.function.FunctionCallbackContext; import org.springframework.ai.openai.*; -import org.springframework.ai.openai.OpenAiChatModel; import org.springframework.ai.openai.api.OpenAiApi; import org.springframework.ai.openai.api.OpenAiAudioApi; import org.springframework.ai.openai.api.OpenAiImageApi; @@ -45,6 +44,7 @@ import org.springframework.web.reactive.function.client.WebClient; /** * @author Christian Tzolov + * @author Stefan Vassilev */ @AutoConfiguration(after = { RestClientAutoConfiguration.class, WebClientAutoConfiguration.class, SpringAiRetryAutoConfiguration.class }) @@ -132,6 +132,8 @@ public class OpenAiAutoConfiguration { @Bean @ConditionalOnMissingBean + @ConditionalOnProperty(prefix = OpenAiAudioTranscriptionProperties.CONFIG_PREFIX, name = "enabled", + havingValue = "true", matchIfMissing = true) public OpenAiAudioTranscriptionModel openAiAudioTranscriptionModel(OpenAiConnectionProperties commonProperties, OpenAiAudioTranscriptionProperties transcriptionProperties, RetryTemplate retryTemplate, RestClient.Builder restClientBuilder, WebClient.Builder webClientBuilder, @@ -157,6 +159,8 @@ public class OpenAiAutoConfiguration { @Bean @ConditionalOnMissingBean + @ConditionalOnProperty(prefix = OpenAiAudioSpeechProperties.CONFIG_PREFIX, name = "enabled", havingValue = "true", + matchIfMissing = true) public OpenAiAudioSpeechModel openAiAudioSpeechClient(OpenAiConnectionProperties commonProperties, OpenAiAudioSpeechProperties speechProperties, RestClient.Builder restClientBuilder, WebClient.Builder webClientBuilder, ResponseErrorHandler responseErrorHandler) { diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/openai/OpenAiPropertiesTests.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/openai/OpenAiPropertiesTests.java index bb54bf80a..3b3665340 100644 --- a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/openai/OpenAiPropertiesTests.java +++ b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/openai/OpenAiPropertiesTests.java @@ -15,12 +15,14 @@ */ package org.springframework.ai.autoconfigure.openai; +import static org.assertj.core.api.Assertions.assertThat; + import org.junit.jupiter.api.Test; import org.skyscreamer.jsonassert.JSONAssert; import org.skyscreamer.jsonassert.JSONCompareMode; - -import org.springframework.ai.autoconfigure.retry.SpringAiRetryAutoConfiguration; import org.springframework.ai.model.ModelOptionsUtils; +import org.springframework.ai.openai.OpenAiAudioSpeechModel; +import org.springframework.ai.openai.OpenAiAudioTranscriptionModel; import org.springframework.ai.openai.OpenAiChatModel; import org.springframework.ai.openai.OpenAiEmbeddingModel; import org.springframework.ai.openai.OpenAiImageModel; @@ -29,12 +31,8 @@ import org.springframework.ai.openai.api.OpenAiApi.ChatCompletionRequest.ToolCho import org.springframework.ai.openai.api.OpenAiApi.FunctionTool.Type; import org.springframework.ai.openai.api.OpenAiAudioApi; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.web.client.RestClientAutoConfiguration; -import org.springframework.boot.autoconfigure.web.reactive.function.client.WebClientAutoConfiguration; import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import static org.assertj.core.api.Assertions.assertThat; - /** * Unit Tests for {@link OpenAiConnectionProperties}, {@link OpenAiChatProperties} and * {@link OpenAiEmbeddingProperties}. @@ -55,8 +53,7 @@ public class OpenAiPropertiesTests { "spring.ai.openai.chat.options.model=MODEL_XYZ", "spring.ai.openai.chat.options.temperature=0.55") // @formatter:on - .withConfiguration(AutoConfigurations.of(SpringAiRetryAutoConfiguration.class, - RestClientAutoConfiguration.class, WebClientAutoConfiguration.class, OpenAiAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) .run(context -> { var chatProperties = context.getBean(OpenAiChatProperties.class); var connectionProperties = context.getBean(OpenAiConnectionProperties.class); @@ -82,8 +79,7 @@ public class OpenAiPropertiesTests { "spring.ai.openai.audio.transcription.options.model=MODEL_XYZ", "spring.ai.openai.audio.transcription.options.temperature=0.55") // @formatter:on - .withConfiguration(AutoConfigurations.of(SpringAiRetryAutoConfiguration.class, - RestClientAutoConfiguration.class, WebClientAutoConfiguration.class, OpenAiAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) .run(context -> { var transcriptionProperties = context.getBean(OpenAiAudioTranscriptionProperties.class); var connectionProperties = context.getBean(OpenAiConnectionProperties.class); @@ -111,8 +107,7 @@ public class OpenAiPropertiesTests { "spring.ai.openai.chat.options.model=MODEL_XYZ", "spring.ai.openai.chat.options.temperature=0.55") // @formatter:on - .withConfiguration(AutoConfigurations.of(SpringAiRetryAutoConfiguration.class, - RestClientAutoConfiguration.class, WebClientAutoConfiguration.class, OpenAiAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) .run(context -> { var chatProperties = context.getBean(OpenAiChatProperties.class); var connectionProperties = context.getBean(OpenAiConnectionProperties.class); @@ -140,8 +135,7 @@ public class OpenAiPropertiesTests { "spring.ai.openai.audio.transcription.options.model=MODEL_XYZ", "spring.ai.openai.audio.transcription.options.temperature=0.55") // @formatter:on - .withConfiguration(AutoConfigurations.of(SpringAiRetryAutoConfiguration.class, - RestClientAutoConfiguration.class, WebClientAutoConfiguration.class, OpenAiAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) .run(context -> { var transcriptionProperties = context.getBean(OpenAiAudioTranscriptionProperties.class); var connectionProperties = context.getBean(OpenAiConnectionProperties.class); @@ -169,8 +163,7 @@ public class OpenAiPropertiesTests { "spring.ai.openai.audio.speech.options.response-format=mp3", "spring.ai.openai.audio.speech.options.speed=0.75") // @formatter:on - .withConfiguration(AutoConfigurations.of(SpringAiRetryAutoConfiguration.class, - RestClientAutoConfiguration.class, WebClientAutoConfiguration.class, OpenAiAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) .run(context -> { var speechProperties = context.getBean(OpenAiAudioSpeechProperties.class); var connectionProperties = context.getBean(OpenAiConnectionProperties.class); @@ -201,8 +194,7 @@ public class OpenAiPropertiesTests { "spring.ai.openai.audio.speech.options.response-format=mp3", "spring.ai.openai.audio.speech.options.speed=0.75") // @formatter:on - .withConfiguration(AutoConfigurations.of(SpringAiRetryAutoConfiguration.class, - RestClientAutoConfiguration.class, WebClientAutoConfiguration.class, OpenAiAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) .run(context -> { var speechProperties = context.getBean(OpenAiAudioSpeechProperties.class); var connectionProperties = context.getBean(OpenAiConnectionProperties.class); @@ -232,8 +224,7 @@ public class OpenAiPropertiesTests { "spring.ai.openai.audio.speech.options.response-format=opus", "spring.ai.openai.audio.speech.options.speed=0.5") // @formatter:on - .withConfiguration(AutoConfigurations.of(SpringAiRetryAutoConfiguration.class, - RestClientAutoConfiguration.class, WebClientAutoConfiguration.class, OpenAiAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) .run(context -> { var speechProperties = context.getBean(OpenAiAudioSpeechProperties.class); var connectionProperties = context.getBean(OpenAiConnectionProperties.class); @@ -261,8 +252,7 @@ public class OpenAiPropertiesTests { "spring.ai.openai.api-key=abc123", "spring.ai.openai.embedding.options.model=MODEL_XYZ") // @formatter:on - .withConfiguration(AutoConfigurations.of(SpringAiRetryAutoConfiguration.class, - RestClientAutoConfiguration.class, WebClientAutoConfiguration.class, OpenAiAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) .run(context -> { var embeddingProperties = context.getBean(OpenAiEmbeddingProperties.class); var connectionProperties = context.getBean(OpenAiConnectionProperties.class); @@ -288,8 +278,7 @@ public class OpenAiPropertiesTests { "spring.ai.openai.embedding.api-key=456", "spring.ai.openai.embedding.options.model=MODEL_XYZ") // @formatter:on - .withConfiguration(AutoConfigurations.of(SpringAiRetryAutoConfiguration.class, - RestClientAutoConfiguration.class, WebClientAutoConfiguration.class, OpenAiAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) .run(context -> { var embeddingProperties = context.getBean(OpenAiEmbeddingProperties.class); var connectionProperties = context.getBean(OpenAiConnectionProperties.class); @@ -313,8 +302,7 @@ public class OpenAiPropertiesTests { "spring.ai.openai.image.options.model=MODEL_XYZ", "spring.ai.openai.image.options.n=3") // @formatter:on - .withConfiguration(AutoConfigurations.of(SpringAiRetryAutoConfiguration.class, - RestClientAutoConfiguration.class, WebClientAutoConfiguration.class, OpenAiAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) .run(context -> { var imageProperties = context.getBean(OpenAiImageProperties.class); var connectionProperties = context.getBean(OpenAiConnectionProperties.class); @@ -341,8 +329,7 @@ public class OpenAiPropertiesTests { "spring.ai.openai.image.options.model=MODEL_XYZ", "spring.ai.openai.image.options.n=3") // @formatter:on - .withConfiguration(AutoConfigurations.of(SpringAiRetryAutoConfiguration.class, - RestClientAutoConfiguration.class, WebClientAutoConfiguration.class, OpenAiAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) .run(context -> { var imageProperties = context.getBean(OpenAiImageProperties.class); var connectionProperties = context.getBean(OpenAiConnectionProperties.class); @@ -410,8 +397,7 @@ public class OpenAiPropertiesTests { "spring.ai.openai.chat.options.user=userXYZ" ) // @formatter:on - .withConfiguration(AutoConfigurations.of(SpringAiRetryAutoConfiguration.class, - RestClientAutoConfiguration.class, WebClientAutoConfiguration.class, OpenAiAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) .run(context -> { var chatProperties = context.getBean(OpenAiChatProperties.class); var connectionProperties = context.getBean(OpenAiConnectionProperties.class); @@ -464,8 +450,7 @@ public class OpenAiPropertiesTests { "spring.ai.openai.audio.transcription.options.temperature=0.55" ) // @formatter:on - .withConfiguration(AutoConfigurations.of(SpringAiRetryAutoConfiguration.class, - RestClientAutoConfiguration.class, WebClientAutoConfiguration.class, OpenAiAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) .run(context -> { var transcriptionProperties = context.getBean(OpenAiAudioTranscriptionProperties.class); var connectionProperties = context.getBean(OpenAiConnectionProperties.class); @@ -498,8 +483,7 @@ public class OpenAiPropertiesTests { "spring.ai.openai.embedding.options.user=userXYZ" ) // @formatter:on - .withConfiguration(AutoConfigurations.of(SpringAiRetryAutoConfiguration.class, - RestClientAutoConfiguration.class, WebClientAutoConfiguration.class, OpenAiAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) .run(context -> { var connectionProperties = context.getBean(OpenAiConnectionProperties.class); var embeddingProperties = context.getBean(OpenAiEmbeddingProperties.class); @@ -531,8 +515,7 @@ public class OpenAiPropertiesTests { "spring.ai.openai.image.options.user=userXYZ" ) // @formatter:on - .withConfiguration(AutoConfigurations.of(SpringAiRetryAutoConfiguration.class, - RestClientAutoConfiguration.class, WebClientAutoConfiguration.class, OpenAiAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) .run(context -> { var imageProperties = context.getBean(OpenAiImageProperties.class); var connectionProperties = context.getBean(OpenAiConnectionProperties.class); @@ -558,8 +541,7 @@ public class OpenAiPropertiesTests { new ApplicationContextRunner() .withPropertyValues("spring.ai.openai.api-key=API_KEY", "spring.ai.openai.base-url=TEST_BASE_URL", "spring.ai.openai.embedding.enabled=false") - .withConfiguration(AutoConfigurations.of(SpringAiRetryAutoConfiguration.class, - RestClientAutoConfiguration.class, WebClientAutoConfiguration.class, OpenAiAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) .run(context -> { assertThat(context.getBeansOfType(OpenAiEmbeddingProperties.class)).isNotEmpty(); assertThat(context.getBeansOfType(OpenAiEmbeddingModel.class)).isEmpty(); @@ -567,8 +549,7 @@ public class OpenAiPropertiesTests { new ApplicationContextRunner() .withPropertyValues("spring.ai.openai.api-key=API_KEY", "spring.ai.openai.base-url=TEST_BASE_URL") - .withConfiguration(AutoConfigurations.of(SpringAiRetryAutoConfiguration.class, - RestClientAutoConfiguration.class, WebClientAutoConfiguration.class, OpenAiAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) .run(context -> { assertThat(context.getBeansOfType(OpenAiEmbeddingProperties.class)).isNotEmpty(); assertThat(context.getBeansOfType(OpenAiEmbeddingModel.class)).isNotEmpty(); @@ -577,8 +558,7 @@ public class OpenAiPropertiesTests { new ApplicationContextRunner() .withPropertyValues("spring.ai.openai.api-key=API_KEY", "spring.ai.openai.base-url=TEST_BASE_URL", "spring.ai.openai.embedding.enabled=true") - .withConfiguration(AutoConfigurations.of(SpringAiRetryAutoConfiguration.class, - RestClientAutoConfiguration.class, WebClientAutoConfiguration.class, OpenAiAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) .run(context -> { assertThat(context.getBeansOfType(OpenAiEmbeddingProperties.class)).isNotEmpty(); assertThat(context.getBeansOfType(OpenAiEmbeddingModel.class)).isNotEmpty(); @@ -590,8 +570,7 @@ public class OpenAiPropertiesTests { new ApplicationContextRunner() .withPropertyValues("spring.ai.openai.api-key=API_KEY", "spring.ai.openai.base-url=TEST_BASE_URL", "spring.ai.openai.chat.enabled=false") - .withConfiguration(AutoConfigurations.of(SpringAiRetryAutoConfiguration.class, - RestClientAutoConfiguration.class, WebClientAutoConfiguration.class, OpenAiAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) .run(context -> { assertThat(context.getBeansOfType(OpenAiChatProperties.class)).isNotEmpty(); assertThat(context.getBeansOfType(OpenAiChatModel.class)).isEmpty(); @@ -599,8 +578,7 @@ public class OpenAiPropertiesTests { new ApplicationContextRunner() .withPropertyValues("spring.ai.openai.api-key=API_KEY", "spring.ai.openai.base-url=TEST_BASE_URL") - .withConfiguration(AutoConfigurations.of(SpringAiRetryAutoConfiguration.class, - RestClientAutoConfiguration.class, WebClientAutoConfiguration.class, OpenAiAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) .run(context -> { assertThat(context.getBeansOfType(OpenAiChatProperties.class)).isNotEmpty(); assertThat(context.getBeansOfType(OpenAiChatModel.class)).isNotEmpty(); @@ -609,8 +587,7 @@ public class OpenAiPropertiesTests { new ApplicationContextRunner() .withPropertyValues("spring.ai.openai.api-key=API_KEY", "spring.ai.openai.base-url=TEST_BASE_URL", "spring.ai.openai.chat.enabled=true") - .withConfiguration(AutoConfigurations.of(SpringAiRetryAutoConfiguration.class, - RestClientAutoConfiguration.class, WebClientAutoConfiguration.class, OpenAiAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) .run(context -> { assertThat(context.getBeansOfType(OpenAiChatProperties.class)).isNotEmpty(); assertThat(context.getBeansOfType(OpenAiChatModel.class)).isNotEmpty(); @@ -623,8 +600,7 @@ public class OpenAiPropertiesTests { new ApplicationContextRunner() .withPropertyValues("spring.ai.openai.api-key=API_KEY", "spring.ai.openai.base-url=TEST_BASE_URL", "spring.ai.openai.image.enabled=false") - .withConfiguration(AutoConfigurations.of(SpringAiRetryAutoConfiguration.class, - RestClientAutoConfiguration.class, WebClientAutoConfiguration.class, OpenAiAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) .run(context -> { assertThat(context.getBeansOfType(OpenAiImageProperties.class)).isNotEmpty(); assertThat(context.getBeansOfType(OpenAiImageModel.class)).isEmpty(); @@ -632,8 +608,7 @@ public class OpenAiPropertiesTests { new ApplicationContextRunner() .withPropertyValues("spring.ai.openai.api-key=API_KEY", "spring.ai.openai.base-url=TEST_BASE_URL") - .withConfiguration(AutoConfigurations.of(SpringAiRetryAutoConfiguration.class, - RestClientAutoConfiguration.class, WebClientAutoConfiguration.class, OpenAiAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) .run(context -> { assertThat(context.getBeansOfType(OpenAiImageProperties.class)).isNotEmpty(); assertThat(context.getBeansOfType(OpenAiImageModel.class)).isNotEmpty(); @@ -642,8 +617,7 @@ public class OpenAiPropertiesTests { new ApplicationContextRunner() .withPropertyValues("spring.ai.openai.api-key=API_KEY", "spring.ai.openai.base-url=TEST_BASE_URL", "spring.ai.openai.image.enabled=true") - .withConfiguration(AutoConfigurations.of(SpringAiRetryAutoConfiguration.class, - RestClientAutoConfiguration.class, WebClientAutoConfiguration.class, OpenAiAutoConfiguration.class)) + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) .run(context -> { assertThat(context.getBeansOfType(OpenAiImageProperties.class)).isNotEmpty(); assertThat(context.getBeansOfType(OpenAiImageModel.class)).isNotEmpty(); @@ -651,4 +625,64 @@ public class OpenAiPropertiesTests { } + @Test + void audioSpeechActivation() { + new ApplicationContextRunner() + .withPropertyValues("spring.ai.openai.api-key=API_KEY", "spring.ai.openai.base-url=TEST_BASE_URL", + "spring.ai.openai.audio.speech.enabled=false") + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) + .run(context -> { + assertThat(context.getBeansOfType(OpenAiAudioSpeechProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(OpenAiAudioSpeechModel.class)).isEmpty(); + }); + + new ApplicationContextRunner() + .withPropertyValues("spring.ai.openai.api-key=API_KEY", "spring.ai.openai.base-url=TEST_BASE_URL") + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) + .run(context -> { + assertThat(context.getBeansOfType(OpenAiAudioSpeechProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(OpenAiAudioSpeechModel.class)).isNotEmpty(); + }); + + new ApplicationContextRunner() + .withPropertyValues("spring.ai.openai.api-key=API_KEY", "spring.ai.openai.base-url=TEST_BASE_URL", + "spring.ai.openai.audio.speech.enabled=true") + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) + .run(context -> { + assertThat(context.getBeansOfType(OpenAiAudioSpeechProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(OpenAiAudioSpeechModel.class)).isNotEmpty(); + }); + + } + + @Test + void audioTranscriptionActivation() { + new ApplicationContextRunner() + .withPropertyValues("spring.ai.openai.api-key=API_KEY", "spring.ai.openai.base-url=TEST_BASE_URL", + "spring.ai.openai.audio.transcription.enabled=false") + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) + .run(context -> { + assertThat(context.getBeansOfType(OpenAiAudioTranscriptionProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(OpenAiAudioTranscriptionModel.class)).isEmpty(); + }); + + new ApplicationContextRunner() + .withPropertyValues("spring.ai.openai.api-key=API_KEY", "spring.ai.openai.base-url=TEST_BASE_URL") + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) + .run(context -> { + assertThat(context.getBeansOfType(OpenAiAudioTranscriptionProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(OpenAiAudioTranscriptionModel.class)).isNotEmpty(); + }); + + new ApplicationContextRunner() + .withPropertyValues("spring.ai.openai.api-key=API_KEY", "spring.ai.openai.base-url=TEST_BASE_URL", + "spring.ai.openai.audio.transcription.enabled=true") + .withConfiguration(AutoConfigurations.of(OpenAiAutoConfiguration.class)) + .run(context -> { + assertThat(context.getBeansOfType(OpenAiAudioTranscriptionProperties.class)).isNotEmpty(); + assertThat(context.getBeansOfType(OpenAiAudioTranscriptionModel.class)).isNotEmpty(); + }); + + } + }