Skip to content

Commit 1f0cdf8

Browse files
committed
perf(stability-ai): Support HTTP client timeout configuration
Signed-off-by: yinh <[email protected]>
1 parent 4b1b566 commit 1f0cdf8

File tree

4 files changed

+104
-4
lines changed

4 files changed

+104
-4
lines changed

auto-configurations/models/spring-ai-autoconfigure-model-stability-ai/src/main/java/org/springframework/ai/model/stabilityai/autoconfigure/StabilityAiConnectionProperties.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,15 @@
1616

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

19+
import java.time.Duration;
20+
21+
import jakarta.annotation.Nullable;
22+
1923
import org.springframework.ai.stabilityai.api.StabilityAiApi;
2024
import org.springframework.boot.context.properties.ConfigurationProperties;
25+
import org.springframework.boot.context.properties.NestedConfigurationProperty;
26+
import org.springframework.boot.http.client.HttpRedirects;
27+
import org.springframework.boot.http.client.autoconfigure.HttpClientSettingsProperties;
2128

2229
@ConfigurationProperties(StabilityAiConnectionProperties.CONFIG_PREFIX)
2330
public class StabilityAiConnectionProperties extends StabilityAiParentProperties {
@@ -26,8 +33,47 @@ public class StabilityAiConnectionProperties extends StabilityAiParentProperties
2633

2734
public static final String DEFAULT_BASE_URL = StabilityAiApi.DEFAULT_BASE_URL;
2835

36+
@NestedConfigurationProperty
37+
private final HttpClientSettingsProperties http = new HttpClientSettingsProperties() {
38+
};
39+
2940
public StabilityAiConnectionProperties() {
3041
super.setBaseUrl(DEFAULT_BASE_URL);
3142
}
3243

44+
@Nullable
45+
public HttpRedirects getRedirects() {
46+
return this.http.getRedirects();
47+
}
48+
49+
public void setRedirects(HttpRedirects redirects) {
50+
this.http.setRedirects(redirects);
51+
}
52+
53+
@Nullable
54+
public Duration getConnectTimeout() {
55+
return this.http.getConnectTimeout();
56+
}
57+
58+
public void setConnectTimeout(Duration connectTimeout) {
59+
this.http.setConnectTimeout(connectTimeout);
60+
}
61+
62+
@Nullable
63+
public Duration getReadTimeout() {
64+
return this.http.getReadTimeout();
65+
}
66+
67+
public void setReadTimeout(Duration readTimeout) {
68+
this.http.setReadTimeout(readTimeout);
69+
}
70+
71+
public HttpClientSettingsProperties.Ssl getSsl() {
72+
return this.http.getSsl();
73+
}
74+
75+
public HttpClientSettingsProperties getHttp() {
76+
return this.http;
77+
}
78+
3379
}

auto-configurations/models/spring-ai-autoconfigure-model-stability-ai/src/main/java/org/springframework/ai/model/stabilityai/autoconfigure/StabilityAiImageAutoConfiguration.java

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,13 @@
2626
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
2727
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
2828
import org.springframework.boot.context.properties.EnableConfigurationProperties;
29+
import org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder;
30+
import org.springframework.boot.http.client.HttpClientSettings;
31+
import org.springframework.boot.http.client.autoconfigure.HttpClientSettingsPropertyMapper;
2932
import org.springframework.boot.restclient.autoconfigure.RestClientAutoConfiguration;
33+
import org.springframework.boot.ssl.SslBundles;
3034
import org.springframework.context.annotation.Bean;
35+
import org.springframework.http.client.ClientHttpRequestFactory;
3136
import org.springframework.util.Assert;
3237
import org.springframework.util.StringUtils;
3338
import org.springframework.web.client.RestClient;
@@ -50,7 +55,9 @@ public class StabilityAiImageAutoConfiguration {
5055
@Bean
5156
@ConditionalOnMissingBean
5257
public StabilityAiApi stabilityAiApi(StabilityAiConnectionProperties commonProperties,
53-
StabilityAiImageProperties imageProperties, ObjectProvider<RestClient.Builder> restClientBuilderProvider) {
58+
StabilityAiImageProperties imageProperties, ObjectProvider<RestClient.Builder> restClientBuilderProvider,
59+
ObjectProvider<SslBundles> sslBundles, ObjectProvider<HttpClientSettings> globalHttpClientSettings,
60+
ObjectProvider<ClientHttpRequestFactoryBuilder<?>> factoryBuilder) {
5461

5562
String apiKey = StringUtils.hasText(imageProperties.getApiKey()) ? imageProperties.getApiKey()
5663
: commonProperties.getApiKey();
@@ -61,8 +68,15 @@ public StabilityAiApi stabilityAiApi(StabilityAiConnectionProperties commonPrope
6168
Assert.hasText(apiKey, "StabilityAI API key must be set");
6269
Assert.hasText(baseUrl, "StabilityAI base URL must be set");
6370

64-
return new StabilityAiApi(apiKey, imageProperties.getOptions().getModel(), baseUrl,
65-
restClientBuilderProvider.getIfAvailable(RestClient::builder));
71+
HttpClientSettingsPropertyMapper mapper = new HttpClientSettingsPropertyMapper(sslBundles.getIfAvailable(),
72+
globalHttpClientSettings.getIfAvailable());
73+
HttpClientSettings httpClientSettings = mapper.map(commonProperties.getHttp());
74+
75+
RestClient.Builder restClientBuilder = restClientBuilderProvider.getIfAvailable(RestClient::builder);
76+
applyRestClientSettings(restClientBuilder, httpClientSettings,
77+
factoryBuilder.getIfAvailable(ClientHttpRequestFactoryBuilder::detect));
78+
79+
return new StabilityAiApi(apiKey, imageProperties.getOptions().getModel(), baseUrl, restClientBuilder);
6680
}
6781

6882
@Bean
@@ -72,4 +86,10 @@ public StabilityAiImageModel stabilityAiImageModel(StabilityAiApi stabilityAiApi
7286
return new StabilityAiImageModel(stabilityAiApi, stabilityAiImageProperties.getOptions());
7387
}
7488

89+
private void applyRestClientSettings(RestClient.Builder builder, HttpClientSettings httpClientSettings,
90+
ClientHttpRequestFactoryBuilder<?> factoryBuilder) {
91+
ClientHttpRequestFactory requestFactory = factoryBuilder.build(httpClientSettings);
92+
builder.requestFactory(requestFactory);
93+
}
94+
7595
}

auto-configurations/models/spring-ai-autoconfigure-model-stability-ai/src/test/java/org/springframework/ai/model/stabilityai/autoconfigure/StabilityAiAutoConfigurationIT.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,4 +60,29 @@ void generate() {
6060
});
6161
}
6262

63+
@Test
64+
void generateWithCustomTimeout() {
65+
this.contextRunner
66+
.withPropertyValues("spring.ai.stabilityai.connect-timeout=1s", "spring.ai.stabilityai.read-timeout=1s")
67+
.withConfiguration(AutoConfigurations.of(StabilityAiImageAutoConfiguration.class))
68+
.run(context -> {
69+
ImageModel imageModel = context.getBean(ImageModel.class);
70+
StabilityAiImageOptions imageOptions = StabilityAiImageOptions.builder()
71+
.stylePreset(StyleEnum.PHOTOGRAPHIC)
72+
.build();
73+
74+
var instructions = """
75+
A light cream colored mini golden doodle.
76+
""";
77+
78+
ImagePrompt imagePrompt = new ImagePrompt(instructions, imageOptions);
79+
ImageResponse imageResponse = imageModel.call(imagePrompt);
80+
81+
ImageGeneration imageGeneration = imageResponse.getResult();
82+
Image image = imageGeneration.getOutput();
83+
84+
assertThat(image.getB64Json()).isNotEmpty();
85+
});
86+
}
87+
6388
}

auto-configurations/models/spring-ai-autoconfigure-model-stability-ai/src/test/java/org/springframework/ai/model/stabilityai/autoconfigure/StabilityAiImagePropertiesTests.java

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

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

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

2123
import org.springframework.ai.stabilityai.StabilityAiImageModel;
@@ -48,12 +50,16 @@ public void chatPropertiesTest() {
4850
"spring.ai.stabilityai.image.options.sampler=K_EULER",
4951
"spring.ai.stabilityai.image.options.seed=0",
5052
"spring.ai.stabilityai.image.options.steps=30",
51-
"spring.ai.stabilityai.image.options.style-preset=neon-punk"
53+
"spring.ai.stabilityai.image.options.style-preset=neon-punk",
54+
55+
"spring.ai.stabilityai.connect-timeout=5s",
56+
"spring.ai.stabilityai.read-timeout=30s"
5257
)
5358
// @formatter:on
5459
.withConfiguration(AutoConfigurations.of(StabilityAiImageAutoConfiguration.class))
5560
.run(context -> {
5661
var chatProperties = context.getBean(StabilityAiImageProperties.class);
62+
var connectionProperties = context.getBean(StabilityAiConnectionProperties.class);
5763

5864
assertThat(chatProperties.getBaseUrl()).isEqualTo("ENDPOINT");
5965
assertThat(chatProperties.getApiKey()).isEqualTo("API_KEY");
@@ -69,6 +75,9 @@ public void chatPropertiesTest() {
6975
assertThat(chatProperties.getOptions().getSeed()).isEqualTo(0);
7076
assertThat(chatProperties.getOptions().getSteps()).isEqualTo(30);
7177
assertThat(chatProperties.getOptions().getStylePreset()).isEqualTo("neon-punk");
78+
79+
assertThat(connectionProperties.getConnectTimeout()).isEqualTo(Duration.ofSeconds(5));
80+
assertThat(connectionProperties.getReadTimeout()).isEqualTo(Duration.ofSeconds(30));
7281
});
7382
}
7483

0 commit comments

Comments
 (0)