|
16 | 16 |
|
17 | 17 | package org.springframework.ai.openai.api;
|
18 | 18 |
|
19 |
| -import java.io.IOException; |
20 |
| -import java.nio.charset.StandardCharsets; |
21 | 19 | import java.util.List;
|
22 | 20 | import java.util.Map;
|
23 |
| -import java.util.function.Consumer; |
24 | 21 | import java.util.function.Predicate;
|
25 | 22 |
|
26 | 23 | import com.fasterxml.jackson.annotation.JsonInclude;
|
|
30 | 27 | import reactor.core.publisher.Mono;
|
31 | 28 |
|
32 | 29 | import org.springframework.ai.model.ModelOptionsUtils;
|
| 30 | +import org.springframework.ai.openai.api.common.ApiUtils; |
33 | 31 | import org.springframework.boot.context.properties.bind.ConstructorBinding;
|
34 | 32 | import org.springframework.core.ParameterizedTypeReference;
|
35 |
| -import org.springframework.http.HttpHeaders; |
36 |
| -import org.springframework.http.MediaType; |
37 | 33 | import org.springframework.http.ResponseEntity;
|
38 |
| -import org.springframework.http.client.ClientHttpResponse; |
39 |
| -import org.springframework.lang.NonNull; |
40 | 34 | import org.springframework.util.Assert;
|
41 | 35 | import org.springframework.util.CollectionUtils;
|
42 |
| -import org.springframework.util.StreamUtils; |
43 |
| -import org.springframework.web.client.ResponseErrorHandler; |
44 | 36 | import org.springframework.web.client.RestClient;
|
45 | 37 | import org.springframework.web.reactive.function.client.WebClient;
|
46 | 38 |
|
@@ -89,72 +81,128 @@ public OpenAiApi(String baseUrl, String openAiToken) {
|
89 | 81 | */
|
90 | 82 | public OpenAiApi(String baseUrl, String openAiToken, RestClient.Builder restClientBuilder) {
|
91 | 83 |
|
92 |
| - Consumer<HttpHeaders> jsonContentHeaders = headers -> { |
93 |
| - headers.setBearerAuth(openAiToken); |
94 |
| - headers.setContentType(MediaType.APPLICATION_JSON); |
95 |
| - }; |
96 |
| - |
97 |
| - var responseErrorHandler = new ResponseErrorHandler() { |
98 |
| - |
99 |
| - @Override |
100 |
| - public boolean hasError(@NonNull ClientHttpResponse response) throws IOException { |
101 |
| - return response.getStatusCode().isError(); |
102 |
| - } |
103 |
| - |
104 |
| - @Override |
105 |
| - public void handleError(@NonNull ClientHttpResponse response) throws IOException { |
106 |
| - if (response.getStatusCode().isError()) { |
107 |
| - String error = StreamUtils.copyToString(response.getBody(), StandardCharsets.UTF_8); |
108 |
| - String message = String.format("%s - %s", response.getStatusCode().value(), error); |
109 |
| - if (response.getStatusCode().is4xxClientError()) { |
110 |
| - throw new OpenAiApiClientErrorException(message); |
111 |
| - } |
112 |
| - throw new OpenAiApiException(message); |
113 |
| - } |
114 |
| - } |
115 |
| - }; |
116 |
| - |
117 | 84 | this.restClient = restClientBuilder
|
118 | 85 | .baseUrl(baseUrl)
|
119 |
| - .defaultHeaders(jsonContentHeaders) |
120 |
| - .defaultStatusHandler(responseErrorHandler) |
| 86 | + .defaultHeaders(ApiUtils.getJsonContentHeaders(openAiToken)) |
| 87 | + .defaultStatusHandler(ApiUtils.DEFAULT_RESPONSE_ERROR_HANDLER) |
121 | 88 | .build();
|
122 | 89 |
|
123 | 90 | this.webClient = WebClient.builder()
|
124 | 91 | .baseUrl(baseUrl)
|
125 |
| - .defaultHeaders(jsonContentHeaders) |
| 92 | + .defaultHeaders(ApiUtils.getJsonContentHeaders(openAiToken)) |
126 | 93 | .build();
|
127 | 94 | }
|
128 | 95 |
|
129 |
| - |
130 | 96 | /**
|
131 |
| - * Non HTTP Error related exceptions |
| 97 | + * OpenAI Chat Completion Models: |
| 98 | + * <a href="https://platform.openai.com/docs/models/gpt-4-and-gpt-4-turbo">GPT-4 and GPT-4 Turbo</a> and |
| 99 | + * <a href="https://platform.openai.com/docs/models/gpt-3-5-turbo">GPT-3.5 Turbo</a>. |
132 | 100 | */
|
133 |
| - public static class OpenAiApiException extends RuntimeException { |
| 101 | + enum ChatModel { |
| 102 | + /** |
| 103 | + * (New) GPT-4 Turbo - latest GPT-4 model intended to reduce cases |
| 104 | + * of “laziness” where the model doesn’t complete a task. |
| 105 | + * Returns a maximum of 4,096 output tokens. |
| 106 | + * Context window: 128k tokens |
| 107 | + */ |
| 108 | + GPT_4_0125_PREVIEW("gpt-4-0125-preview"), |
| 109 | + |
| 110 | + /** |
| 111 | + * Currently points to gpt-4-0125-preview - model featuring improved |
| 112 | + * instruction following, JSON mode, reproducible outputs, |
| 113 | + * parallel function calling, and more. |
| 114 | + * Returns a maximum of 4,096 output tokens |
| 115 | + * Context window: 128k tokens |
| 116 | + */ |
| 117 | + GPT_4_TURBO_PREVIEW("gpt-4-turbo-preview"), |
| 118 | + |
| 119 | + /** |
| 120 | + * GPT-4 with the ability to understand images, in addition |
| 121 | + * to all other GPT-4 Turbo capabilities. Currently points |
| 122 | + * to gpt-4-1106-vision-preview. |
| 123 | + * Returns a maximum of 4,096 output tokens |
| 124 | + * Context window: 128k tokens |
| 125 | + */ |
| 126 | + GPT_4_VISION_PREVIEW("gpt-4-vision-preview"), |
| 127 | + |
| 128 | + /** |
| 129 | + * Currently points to gpt-4-0613. |
| 130 | + * Snapshot of gpt-4 from June 13th 2023 with improved |
| 131 | + * function calling support. |
| 132 | + * Context window: 8k tokens |
| 133 | + */ |
| 134 | + GPT_4("gpt-4"), |
| 135 | + |
| 136 | + /** |
| 137 | + * Currently points to gpt-4-32k-0613. |
| 138 | + * Snapshot of gpt-4-32k from June 13th 2023 with improved |
| 139 | + * function calling support. |
| 140 | + * Context window: 32k tokens |
| 141 | + */ |
| 142 | + GPT_4_32K("gpt-4-32k"), |
| 143 | + |
| 144 | + /** |
| 145 | + *Currently points to gpt-3.5-turbo-0125. |
| 146 | + * model with higher accuracy at responding in requested |
| 147 | + * formats and a fix for a bug which caused a text |
| 148 | + * encoding issue for non-English language function calls. |
| 149 | + * Returns a maximum of 4,096 |
| 150 | + * Context window: 16k tokens |
| 151 | + */ |
| 152 | + GPT_3_5_TURBO("gpt-3.5-turbo"), |
134 | 153 |
|
135 |
| - public OpenAiApiException(String message) { |
136 |
| - super(message); |
| 154 | + /** |
| 155 | + * GPT-3.5 Turbo model with improved instruction following, |
| 156 | + * JSON mode, reproducible outputs, parallel function calling, |
| 157 | + * and more. Returns a maximum of 4,096 output tokens. |
| 158 | + * Context window: 16k tokens. |
| 159 | + */ |
| 160 | + GPT_3_5_TURBO_1106("gpt-3.5-turbo-1106"); |
| 161 | + |
| 162 | + public final String value; |
| 163 | + |
| 164 | + ChatModel(String value) { |
| 165 | + this.value = value; |
137 | 166 | }
|
138 | 167 |
|
139 |
| - public OpenAiApiException(String message, Throwable cause) { |
140 |
| - super(message, cause); |
| 168 | + public String getValue() { |
| 169 | + return value; |
141 | 170 | }
|
142 | 171 | }
|
143 | 172 |
|
144 | 173 | /**
|
145 |
| - * Thrown on 4xx client errors, such as 401 - Incorrect API key provided, |
146 |
| - * 401 - You must be a member of an organization to use the API, |
147 |
| - * 429 - Rate limit reached for requests, 429 - You exceeded your current quota |
148 |
| - * , please check your plan and billing details. |
| 174 | + * OpenAI Embeddings Models: |
| 175 | + * <a href="https://platform.openai.com/docs/models/embeddings">Embeddings</a>. |
149 | 176 | */
|
150 |
| - public static class OpenAiApiClientErrorException extends RuntimeException { |
| 177 | + enum EmbeddingModel { |
| 178 | + |
| 179 | + /** |
| 180 | + * Most capable embedding model for both english and non-english tasks. |
| 181 | + * DIMENSION: 3072 |
| 182 | + */ |
| 183 | + TEXT_EMBEDDING_3_LARGE("text-embedding-3-large"), |
| 184 | + |
| 185 | + /** |
| 186 | + * Increased performance over 2nd generation ada embedding model. |
| 187 | + * DIMENSION: 1536 |
| 188 | + */ |
| 189 | + TEXT_EMBEDDING_3_SMALL("text-embedding-3-small"), |
| 190 | + |
| 191 | + /** |
| 192 | + * Most capable 2nd generation embedding model, replacing 16 first |
| 193 | + * generation models. |
| 194 | + * DIMENSION: 1536 |
| 195 | + */ |
| 196 | + TEXT_EMBEDDING_ADA_002("text-embedding-ada-002"); |
| 197 | + |
| 198 | + public final String value; |
151 | 199 |
|
152 |
| - public OpenAiApiClientErrorException(String message) { |
153 |
| - super(message); |
| 200 | + EmbeddingModel(String value) { |
| 201 | + this.value = value; |
154 | 202 | }
|
155 | 203 |
|
156 |
| - public OpenAiApiClientErrorException(String message, Throwable cause) { |
157 |
| - super(message, cause); |
| 204 | + public String getValue() { |
| 205 | + return value; |
158 | 206 | }
|
159 | 207 | }
|
160 | 208 |
|
|
0 commit comments