@@ -64,9 +64,18 @@ public class AzureOpenAiAutoConfiguration {
6464
6565 private static final String APPLICATION_ID = "spring-ai" ;
6666
67+ @ Bean
68+ @ ConditionalOnMissingBean
69+ public OpenAIClientBuilderCustomizer openAIClientBuilderCustomizer () {
70+ return clientBuilder -> {
71+ };
72+ }
73+
6774 @ Bean
6875 @ ConditionalOnMissingBean // ({ OpenAIClient.class, TokenCredential.class })
69- public OpenAIClientBuilder openAIClientBuilder (AzureOpenAiConnectionProperties connectionProperties ) {
76+ public OpenAIClientBuilder openAIClientBuilder (AzureOpenAiConnectionProperties connectionProperties ,
77+ ObjectProvider <OpenAIClientBuilderCustomizer > customizers ) {
78+
7079 if (StringUtils .hasText (connectionProperties .getApiKey ())) {
7180
7281 Assert .hasText (connectionProperties .getEndpoint (), "Endpoint must not be empty" );
@@ -77,17 +86,21 @@ public OpenAIClientBuilder openAIClientBuilder(AzureOpenAiConnectionProperties c
7786 .map (entry -> new Header (entry .getKey (), entry .getValue ()))
7887 .collect (Collectors .toList ());
7988 ClientOptions clientOptions = new ClientOptions ().setApplicationId (APPLICATION_ID ).setHeaders (headers );
80- return new OpenAIClientBuilder ().endpoint (connectionProperties .getEndpoint ())
89+ OpenAIClientBuilder clientBuilder = new OpenAIClientBuilder ().endpoint (connectionProperties .getEndpoint ())
8190 .credential (new AzureKeyCredential (connectionProperties .getApiKey ()))
8291 .clientOptions (clientOptions );
92+ applyOpenAIClientBuilderCustomizers (clientBuilder , customizers );
93+ return clientBuilder ;
8394 }
8495
8596 // Connect to OpenAI (e.g. not the Azure OpenAI). The deploymentName property is
8697 // used as OpenAI model name.
8798 if (StringUtils .hasText (connectionProperties .getOpenAiApiKey ())) {
88- return new OpenAIClientBuilder ().endpoint ("https://api.openai.com/v1" )
99+ OpenAIClientBuilder clientBuilder = new OpenAIClientBuilder ().endpoint ("https://api.openai.com/v1" )
89100 .credential (new KeyCredential (connectionProperties .getOpenAiApiKey ()))
90101 .clientOptions (new ClientOptions ().setApplicationId (APPLICATION_ID ));
102+ applyOpenAIClientBuilderCustomizers (clientBuilder , customizers );
103+ return clientBuilder ;
91104 }
92105
93106 throw new IllegalArgumentException ("Either API key or OpenAI API key must not be empty" );
@@ -97,14 +110,16 @@ public OpenAIClientBuilder openAIClientBuilder(AzureOpenAiConnectionProperties c
97110 @ ConditionalOnMissingBean
98111 @ ConditionalOnBean (TokenCredential .class )
99112 public OpenAIClientBuilder openAIClientWithTokenCredential (AzureOpenAiConnectionProperties connectionProperties ,
100- TokenCredential tokenCredential ) {
113+ TokenCredential tokenCredential , ObjectProvider < OpenAIClientBuilderCustomizer > customizers ) {
101114
102115 Assert .notNull (tokenCredential , "TokenCredential must not be null" );
103116 Assert .hasText (connectionProperties .getEndpoint (), "Endpoint must not be empty" );
104117
105- return new OpenAIClientBuilder ().endpoint (connectionProperties .getEndpoint ())
118+ OpenAIClientBuilder clientBuilder = new OpenAIClientBuilder ().endpoint (connectionProperties .getEndpoint ())
106119 .credential (tokenCredential )
107120 .clientOptions (new ClientOptions ().setApplicationId (APPLICATION_ID ));
121+ applyOpenAIClientBuilderCustomizers (clientBuilder , customizers );
122+ return clientBuilder ;
108123 }
109124
110125 @ Bean
@@ -169,4 +184,9 @@ public AzureOpenAiAudioTranscriptionModel azureOpenAiAudioTranscriptionModel(Ope
169184 return new AzureOpenAiAudioTranscriptionModel (openAIClient .buildClient (), audioProperties .getOptions ());
170185 }
171186
187+ private void applyOpenAIClientBuilderCustomizers (OpenAIClientBuilder clientBuilder ,
188+ ObjectProvider <OpenAIClientBuilderCustomizer > customizers ) {
189+ customizers .orderedStream ().forEach (customizer -> customizer .customize (clientBuilder ));
190+ }
191+
172192}
0 commit comments