Skip to content

Commit 2b0dc84

Browse files
committed
perf(elevenLabs): support HTTP client timeout configuration
Signed-off-by: yinh <fottas@163.com>
1 parent 5cafbb2 commit 2b0dc84

File tree

4 files changed

+66
-5
lines changed

4 files changed

+66
-5
lines changed

auto-configurations/models/spring-ai-autoconfigure-model-elevenlabs/src/main/java/org/springframework/ai/model/elevenlabs/autoconfigure/ElevenLabsAutoConfiguration.java

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,17 @@
2727
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2828
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
2929
import org.springframework.boot.context.properties.EnableConfigurationProperties;
30+
import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;
31+
import org.springframework.boot.http.client.HttpClientSettings;
32+
import org.springframework.boot.http.client.autoconfigure.HttpClientSettingsPropertyMapper;
33+
import org.springframework.boot.http.client.reactive.ClientHttpConnectorBuilder;
3034
import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration;
35+
import org.springframework.boot.ssl.SslBundles;
3136
import org.springframework.boot.webclient.autoconfigure.WebClientAutoConfiguration;
3237
import org.springframework.context.annotation.Bean;
3338
import org.springframework.core.retry.RetryTemplate;
39+
import org.springframework.http.client.ClientHttpRequestFactory;
40+
import org.springframework.http.client.reactive.ClientHttpConnector;
3441
import org.springframework.web.client.ResponseErrorHandler;
3542
import org.springframework.web.client.RestClient;
3643
import org.springframework.web.reactive.function.client.WebClient;
@@ -52,13 +59,28 @@ public class ElevenLabsAutoConfiguration {
5259
@ConditionalOnMissingBean
5360
public ElevenLabsApi elevenLabsApi(ElevenLabsConnectionProperties connectionProperties,
5461
ObjectProvider<RestClient.Builder> restClientBuilderProvider,
55-
ObjectProvider<WebClient.Builder> webClientBuilderProvider, ResponseErrorHandler responseErrorHandler) {
62+
ObjectProvider<WebClient.Builder> webClientBuilderProvider, ResponseErrorHandler responseErrorHandler,
63+
ObjectProvider<SslBundles> sslBundles, ObjectProvider<HttpClientSettings> globalHttpClientSettings,
64+
ObjectProvider<ClientHttpRequestFactoryBuilder<?>> factoryBuilder,
65+
ObjectProvider<ClientHttpConnectorBuilder<?>> webConnectorBuilderProvider) {
66+
67+
HttpClientSettingsPropertyMapper mapper = new HttpClientSettingsPropertyMapper(sslBundles.getIfAvailable(),
68+
globalHttpClientSettings.getIfAvailable());
69+
HttpClientSettings httpClientSettings = mapper.map(connectionProperties);
70+
71+
RestClient.Builder restClientBuilder = restClientBuilderProvider.getIfAvailable(RestClient::builder);
72+
applyRestClientSettings(restClientBuilder, httpClientSettings,
73+
factoryBuilder.getIfAvailable(ClientHttpRequestFactoryBuilder::detect));
74+
75+
WebClient.Builder webClientBuilder = webClientBuilderProvider.getIfAvailable(WebClient::builder);
76+
applyWebClientSettings(webClientBuilder, httpClientSettings,
77+
webConnectorBuilderProvider.getIfAvailable(ClientHttpConnectorBuilder::detect));
5678

5779
return ElevenLabsApi.builder()
5880
.baseUrl(connectionProperties.getBaseUrl())
5981
.apiKey(connectionProperties.getApiKey())
60-
.restClientBuilder(restClientBuilderProvider.getIfAvailable(RestClient::builder))
61-
.webClientBuilder(webClientBuilderProvider.getIfAvailable(WebClient::builder))
82+
.restClientBuilder(restClientBuilder)
83+
.webClientBuilder(webClientBuilder)
6284
.responseErrorHandler(responseErrorHandler)
6385
.build();
6486
}
@@ -75,4 +97,16 @@ public ElevenLabsTextToSpeechModel elevenLabsSpeechModel(ElevenLabsApi elevenLab
7597
.build();
7698
}
7799

100+
private void applyRestClientSettings(RestClient.Builder builder, HttpClientSettings httpClientSettings,
101+
ClientHttpRequestFactoryBuilder<?> factoryBuilder) {
102+
ClientHttpRequestFactory requestFactory = factoryBuilder.build(httpClientSettings);
103+
builder.requestFactory(requestFactory);
104+
}
105+
106+
private void applyWebClientSettings(WebClient.Builder builder, HttpClientSettings httpClientSettings,
107+
ClientHttpConnectorBuilder<?> connectorBuilder) {
108+
ClientHttpConnector connector = connectorBuilder.build(httpClientSettings);
109+
builder.clientConnector(connector);
110+
}
111+
78112
}

auto-configurations/models/spring-ai-autoconfigure-model-elevenlabs/src/main/java/org/springframework/ai/model/elevenlabs/autoconfigure/ElevenLabsConnectionProperties.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,15 @@
1818

1919
import org.springframework.ai.elevenlabs.api.ElevenLabsApi;
2020
import org.springframework.boot.context.properties.ConfigurationProperties;
21+
import org.springframework.boot.http.client.autoconfigure.HttpClientSettingsProperties;
2122

2223
/**
2324
* Configuration properties for the ElevenLabs API connection.
2425
*
2526
* @author Alexandros Pappas
2627
*/
2728
@ConfigurationProperties(ElevenLabsConnectionProperties.CONFIG_PREFIX)
28-
public class ElevenLabsConnectionProperties {
29+
public class ElevenLabsConnectionProperties extends HttpClientSettingsProperties {
2930

3031
public static final String CONFIG_PREFIX = "spring.ai.elevenlabs";
3132

auto-configurations/models/spring-ai-autoconfigure-model-elevenlabs/src/test/java/org/springframework/ai/model/elevenlabs/autoconfigure/ElevenLabsAutoConfigurationIT.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.ai.model.elevenlabs.autoconfigure;
1818

19+
import java.time.Duration;
1920
import java.util.Arrays;
2021

2122
import org.junit.jupiter.api.Test;
@@ -73,6 +74,23 @@ void speechStream() {
7374
});
7475
}
7576

77+
@Test
78+
void speechWithCustomTimeout() {
79+
this.contextRunner.withConfiguration(SpringAiTestAutoConfigurations.of(ElevenLabsAutoConfiguration.class))
80+
.withPropertyValues("spring.ai.elevenlabs.connect-timeout=1ms", "spring.ai.elevenlabs.read-timeout=1ms")
81+
.run(context -> {
82+
ElevenLabsTextToSpeechModel speechModel = context.getBean(ElevenLabsTextToSpeechModel.class);
83+
var connectionProperties = context.getBean(ElevenLabsConnectionProperties.class);
84+
assertThat(connectionProperties.getConnectTimeout()).isEqualTo(Duration.ofMillis(1));
85+
assertThat(connectionProperties.getReadTimeout()).isEqualTo(Duration.ofMillis(1));
86+
87+
byte[] response = speechModel.call("H");
88+
assertThat(response).isNotNull();
89+
90+
logger.info("Response with custom timeout: " + Arrays.toString(response));
91+
});
92+
}
93+
7694
public boolean verifyMp3FrameHeader(byte[] audioResponse) {
7795
if (audioResponse == null || audioResponse.length < 3) {
7896
return false;

auto-configurations/models/spring-ai-autoconfigure-model-elevenlabs/src/test/java/org/springframework/ai/model/elevenlabs/autoconfigure/ElevenLabsPropertiesTests.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package org.springframework.ai.model.elevenlabs.autoconfigure;
1818

19+
import java.time.Duration;
20+
1921
import org.junit.jupiter.api.Test;
2022

2123
import org.springframework.ai.elevenlabs.ElevenLabsTextToSpeechModel;
@@ -46,7 +48,10 @@ public void connectionProperties() {
4648
"spring.ai.elevenlabs.tts.options.voice-settings.similarity-boost=0.8",
4749
"spring.ai.elevenlabs.tts.options.voice-settings.style=0.2",
4850
"spring.ai.elevenlabs.tts.options.voice-settings.use-speaker-boost=false",
49-
"spring.ai.elevenlabs.tts.options.voice-settings.speed=1.5"
51+
"spring.ai.elevenlabs.tts.options.voice-settings.speed=1.5",
52+
53+
"spring.ai.elevenlabs.connect-timeout=1s",
54+
"spring.ai.elevenlabs.read-timeout=1s"
5055
// @formatter:on
5156
).withConfiguration(SpringAiTestAutoConfigurations.of(ElevenLabsAutoConfiguration.class)).run(context -> {
5257
var speechProperties = context.getBean(ElevenLabsSpeechProperties.class);
@@ -62,6 +67,9 @@ public void connectionProperties() {
6267
assertThat(speechProperties.getOptions().getVoiceSettings().style()).isEqualTo(0.2);
6368
assertThat(speechProperties.getOptions().getVoiceSettings().useSpeakerBoost()).isFalse();
6469
assertThat(speechProperties.getOptions().getSpeed()).isEqualTo(1.5f);
70+
71+
assertThat(connectionProperties.getConnectTimeout()).isEqualTo(Duration.ofSeconds(1));
72+
assertThat(connectionProperties.getReadTimeout()).isEqualTo(Duration.ofSeconds(1));
6573
});
6674
}
6775

0 commit comments

Comments
 (0)