diff --git a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiApi.java b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiApi.java index 0183fa65a..962b873aa 100644 --- a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiApi.java +++ b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiApi.java @@ -34,6 +34,7 @@ import reactor.core.publisher.Mono; import org.springframework.ai.model.ApiKey; import org.springframework.ai.model.ChatModelDescription; import org.springframework.ai.model.ModelOptionsUtils; +import org.springframework.ai.model.NoopApiKey; import org.springframework.ai.model.SimpleApiKey; import org.springframework.ai.openai.api.common.OpenAiApiConstants; import org.springframework.ai.retry.RetryUtils; @@ -200,7 +201,10 @@ public class OpenAiApi { this.embeddingsPath = embeddingsPath; // @formatter:off Consumer finalHeaders = h -> { - h.setBearerAuth(apiKey.getValue()); + if(!(apiKey instanceof NoopApiKey)) { + h.setBearerAuth(apiKey.getValue()); + } + h.setContentType(MediaType.APPLICATION_JSON); h.addAll(headers); }; diff --git a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiAudioApi.java b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiAudioApi.java index 1f4ca2a59..b68f1f637 100644 --- a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiAudioApi.java +++ b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiAudioApi.java @@ -72,7 +72,14 @@ public class OpenAiAudioApi { public OpenAiAudioApi(String baseUrl, String openAiToken, RestClient.Builder restClientBuilder, ResponseErrorHandler responseErrorHandler) { - Consumer authHeaders = h -> h.setBearerAuth(openAiToken); + Consumer authHeaders; + if (openAiToken != null && !openAiToken.isEmpty()) { + authHeaders = h -> h.setBearerAuth(openAiToken); + } + else { + authHeaders = h -> { + }; + } this.restClient = restClientBuilder.baseUrl(baseUrl) .defaultHeaders(authHeaders) @@ -111,7 +118,9 @@ public class OpenAiAudioApi { ResponseErrorHandler responseErrorHandler) { Consumer authHeaders = h -> { - h.setBearerAuth(apiKey); + if (apiKey != null && !apiKey.isEmpty()) { + h.setBearerAuth(apiKey); + } h.addAll(headers); // h.setContentType(MediaType.APPLICATION_JSON); }; @@ -135,7 +144,7 @@ public class OpenAiAudioApi { /** * Streams audio generated from the input text. - * + *

* This method sends a POST request to the OpenAI API to generate audio from the * provided text. The audio is streamed back as a Flux of ResponseEntity objects, each * containing a byte array of the audio data. diff --git a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiImageApi.java b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiImageApi.java index bfb846c05..06f071a1b 100644 --- a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiImageApi.java +++ b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiImageApi.java @@ -87,7 +87,9 @@ public class OpenAiImageApi { // @formatter:off this.restClient = restClientBuilder.baseUrl(baseUrl) .defaultHeaders(h -> { - h.setBearerAuth(apiKey); + if(apiKey != null && !apiKey.isEmpty()) { + h.setBearerAuth(apiKey); + } h.setContentType(MediaType.APPLICATION_JSON); h.addAll(headers); }) diff --git a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiModerationApi.java b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiModerationApi.java index f4522dc0e..9496df687 100644 --- a/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiModerationApi.java +++ b/models/spring-ai-openai/src/main/java/org/springframework/ai/openai/api/OpenAiModerationApi.java @@ -20,7 +20,6 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; - import org.springframework.ai.retry.RetryUtils; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; @@ -59,7 +58,9 @@ public class OpenAiModerationApi { this.objectMapper = new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); this.restClient = restClientBuilder.baseUrl(baseUrl).defaultHeaders(h -> { - h.setBearerAuth(openAiToken); + if (openAiToken != null && !openAiToken.isEmpty()) { + h.setBearerAuth(openAiToken); + } h.setContentType(MediaType.APPLICATION_JSON); }).defaultStatusHandler(responseErrorHandler).build(); } diff --git a/spring-ai-core/src/main/java/org/springframework/ai/model/NoopApiKey.java b/spring-ai-core/src/main/java/org/springframework/ai/model/NoopApiKey.java new file mode 100644 index 000000000..4740dbef9 --- /dev/null +++ b/spring-ai-core/src/main/java/org/springframework/ai/model/NoopApiKey.java @@ -0,0 +1,32 @@ +/* + * Copyright 2025-2025 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.model; + +/** + * This implementation of ApiKey indicates that no API key should be used, e.g. no HTTP + * headers should be set. + * + * @author Paul Bakker + */ +public class NoopApiKey implements ApiKey { + + @Override + public String getValue() { + return ""; + } + +}