Skip to content

Commit f662824

Browse files
committed
fix: modify AI API
1 parent 08cb468 commit f662824

3 files changed

Lines changed: 67 additions & 104 deletions

File tree

base/src/main/java/com/tinyengine/it/common/exception/GlobalExceptionAdvice.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public Result<Map<String, String>> handleNullPointerException(HttpServletRequest
6969
* @param e the e
7070
* @return the result
7171
*/
72-
@ResponseStatus(HttpStatus.OK)
72+
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
7373
@ExceptionHandler(ServiceException.class)
7474
public Result<Map<String, String>> handleServiceException(ServiceException e) {
7575
// 修改为 log.error,传递异常对象以打印堆栈信息

base/src/main/java/com/tinyengine/it/controller/AiChatController.java

Lines changed: 21 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -71,36 +71,25 @@ public class AiChatController {
7171
@SystemControllerLog(description = "AI chat")
7272
@PostMapping("/ai/chat")
7373
public ResponseEntity<?> aiChat(@RequestBody ChatRequest request,
74-
@RequestHeader(value = "Authorization", required = false) String authorization) {
74+
@RequestHeader(value = "Authorization", required = false) String authorization) throws Exception {
7575

7676
if (authorization != null && authorization.startsWith("Bearer ")) {
7777
String token = authorization.replace("Bearer ", "");
7878
request.setApiKey(token);
7979
}
8080

81-
try {
82-
Object response = aiChatV1Service.chatCompletion(request);
81+
Object response = aiChatV1Service.chatCompletion(request);
8382

84-
if (request.isStream()) {
85-
return ResponseEntity.ok()
86-
.contentType(MediaType.TEXT_EVENT_STREAM)
87-
.body((StreamingResponseBody) response);
88-
} else {
89-
return ResponseEntity.ok(response);
90-
}
91-
} catch (Exception e) {
92-
// 根据异常类型返回不同的状态码
93-
if (e.getMessage() != null && e.getMessage().contains("401")) {
94-
return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
95-
.body("认证失败: " + e.getMessage());
96-
} else if (e.getMessage() != null && e.getMessage().contains("API密钥")) {
97-
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
98-
.body("API密钥错误: " + e.getMessage());
99-
} else {
100-
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
101-
.body("服务器内部错误: " + e.getMessage());
102-
}
83+
if (request.isStream()) {
84+
return ResponseEntity.ok()
85+
.contentType(MediaType.TEXT_EVENT_STREAM)
86+
.header("Cache-Control", "no-cache")
87+
.header("X-Accel-Buffering", "no") // 禁用Nginx缓冲
88+
.body((StreamingResponseBody) response);
89+
} else {
90+
return ResponseEntity.ok(response);
10391
}
92+
10493
}
10594

10695

@@ -121,34 +110,22 @@ public ResponseEntity<?> aiChat(@RequestBody ChatRequest request,
121110
@SystemControllerLog(description = "AI completions")
122111
@PostMapping("/chat/completions")
123112
public ResponseEntity<?> completions(@RequestBody ChatRequest request,
124-
@RequestHeader(value = "Authorization", required = false) String authorization) {
113+
@RequestHeader(value = "Authorization", required = false) String authorization) throws Exception {
125114
if (authorization != null && authorization.startsWith("Bearer ")) {
126115
String token = authorization.replace("Bearer ", "");
127116
request.setApiKey(token);
128117
}
129118

130-
try {
131-
Object response = aiChatV1Service.chatCompletion(request);
119+
Object response = aiChatV1Service.chatCompletion(request);
132120

133-
if (request.isStream()) {
134-
return ResponseEntity.ok()
135-
.contentType(MediaType.TEXT_EVENT_STREAM)
136-
.body((StreamingResponseBody) response);
137-
} else {
138-
return ResponseEntity.ok(response);
139-
}
140-
} catch (Exception e) {
141-
// 根据异常类型返回不同的状态码
142-
if (e.getMessage() != null && e.getMessage().contains("401")) {
143-
return ResponseEntity.status(HttpStatus.UNAUTHORIZED)
144-
.body("认证失败: " + e.getMessage());
145-
} else if (e.getMessage() != null && e.getMessage().contains("API密钥")) {
146-
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
147-
.body("API密钥错误: " + e.getMessage());
148-
} else {
149-
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
150-
.body("服务器内部错误: " + e.getMessage());
151-
}
121+
if (request.isStream()) {
122+
return ResponseEntity.ok()
123+
.contentType(MediaType.TEXT_EVENT_STREAM)
124+
.header("Cache-Control", "no-cache")
125+
.header("X-Accel-Buffering", "no") // 禁用Nginx缓冲
126+
.body((StreamingResponseBody) response);
127+
} else {
128+
return ResponseEntity.ok(response);
152129
}
153130
}
154131
/**

base/src/main/java/com/tinyengine/it/service/app/impl/v1/AiChatV1ServiceImpl.java

Lines changed: 45 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
package com.tinyengine.it.service.app.impl.v1;
1414

1515
import com.fasterxml.jackson.databind.JsonNode;
16+
import com.tinyengine.it.common.exception.ServiceException;
1617
import com.tinyengine.it.common.log.SystemServiceLog;
1718
import com.tinyengine.it.common.utils.JsonUtils;
1819
import com.tinyengine.it.common.utils.SM4Utils;
@@ -174,83 +175,68 @@ private String buildRequestBody(ChatRequest request) {
174175
return JsonUtils.encode(body);
175176
}
176177

177-
private JsonNode processStandardResponse(HttpRequest.Builder requestBuilder)
178-
throws Exception {
179-
HttpResponse<String> response = httpClient.send(
180-
requestBuilder.build(), HttpResponse.BodyHandlers.ofString());
178+
private JsonNode processStandardResponse(HttpRequest.Builder requestBuilder) {
179+
HttpResponse<String> response = null;
180+
String code = null;
181+
String message = null;
182+
try {
183+
response = httpClient.send(
184+
requestBuilder.build(), HttpResponse.BodyHandlers.ofString());
185+
code = String.valueOf(response.statusCode());
186+
if (response.statusCode() != 200) {
187+
String errorBody = response.body();
181188

182-
// 添加状态码检查
183-
if (response.statusCode() != 200) {
184-
String errorBody = response.body();
185-
try {
186189
// 尝试解析错误JSON
187190
JsonNode errorNode = JsonUtils.MAPPER.readTree(errorBody);
188-
throw new IOException("API请求失败: " + response.statusCode() + " - " +
189-
errorNode.get("error").get("message").asText());
190-
} catch (Exception e) {
191-
// 如果无法解析JSON,返回原始错误信息
192-
throw new IOException("API请求失败: " + response.statusCode() + " - " + errorBody);
191+
message = errorNode.get("error").get("message").asText();
192+
throw new ServiceException(code, message);
193193
}
194+
return JsonUtils.MAPPER.readTree(response.body());
195+
} catch (IOException | InterruptedException e) {
196+
throw new ServiceException(code, message);
194197
}
195198

196-
return JsonUtils.MAPPER.readTree(response.body());
199+
197200
}
201+
198202
private StreamingResponseBody processStreamResponse(HttpRequest.Builder requestBuilder) {
199203
return outputStream -> {
204+
HttpResponse<InputStream> response = null;
200205
try {
201-
// 使用相同的httpClient实例,确保配置一致
202-
HttpResponse<InputStream> response = httpClient.send(
203-
requestBuilder.build(),
204-
HttpResponse.BodyHandlers.ofInputStream()
206+
response = httpClient.send(
207+
requestBuilder.build(), HttpResponse.BodyHandlers.ofInputStream()
205208
);
209+
} catch (InterruptedException e) {
210+
throw new ServiceException("500", e.getMessage());
211+
}
206212

207-
// 立即检查状态码
208-
if (response.statusCode() != 200) {
209-
String errorBody = new String(response.body().readAllBytes(), StandardCharsets.UTF_8);
210-
// 格式化为正确的SSE错误事件
211-
String errorEvent = formatSSEError(response.statusCode(), errorBody);
212-
outputStream.write(errorEvent.getBytes(StandardCharsets.UTF_8));
213-
outputStream.flush();
214-
return; // 重要:立即返回,不再处理流
215-
}
213+
log.info("收到AI API响应,状态码: {}", response.statusCode());
216214

217-
// 正常流处理逻辑
218-
try (InputStream inputStream = response.body()) {
219-
byte[] buffer = new byte[8192];
220-
int bytesRead;
221-
while ((bytesRead = inputStream.read(buffer)) != -1) {
222-
outputStream.write(buffer, 0, bytesRead);
223-
outputStream.flush();
224-
}
225-
}
226-
} catch (Exception e) {
227-
try {
228-
// 格式化为标准SSE错误格式
229-
String errorEvent = formatSSEError(500, e.getMessage());
230-
outputStream.write(errorEvent.getBytes(StandardCharsets.UTF_8));
215+
if (response.statusCode() != 200) {
216+
String errorBody = new String(response.body().readAllBytes(), StandardCharsets.UTF_8);
217+
218+
log.info("错误响应内容: {}", errorBody);
219+
220+
JsonNode errorNode = JsonUtils.MAPPER.readTree(errorBody);
221+
throw new ServiceException(String.valueOf(response.statusCode()), errorNode.get("error").get("message").asText());
222+
}
223+
224+
// 正常流处理逻辑
225+
try (InputStream inputStream = response.body()) {
226+
byte[] buffer = new byte[8192];
227+
int bytesRead;
228+
while ((bytesRead = inputStream.read(buffer)) != -1) {
229+
outputStream.write(buffer, 0, bytesRead);
231230
outputStream.flush();
232-
} catch (IOException ioException) {
233-
log.error("无法发送错误信息: " + ioException.getMessage());
234231
}
232+
// 流正常结束时发送结束标记
233+
String doneEvent = "data: [DONE]\n\n";
234+
log.info("发送DONE事件: {}", doneEvent);
235+
outputStream.write(doneEvent.getBytes(StandardCharsets.UTF_8));
236+
outputStream.flush();
235237
}
236238
};
237239
}
238-
/**
239-
* 格式化SSE错误事件
240-
*/
241-
private String formatSSEError(int statusCode, String errorBody) {
242-
try {
243-
// 尝试解析API错误信息
244-
JsonNode errorNode = JsonUtils.MAPPER.readTree(errorBody);
245-
String errorMessage = errorNode.get("error").get("message").asText();
246-
return String.format("data: {\"error\": {\"code\": %d, \"message\": \"%s\"}}\n\n",
247-
statusCode, errorMessage);
248-
} catch (Exception e) {
249-
// 如果无法解析,返回原始错误
250-
return String.format("data: {\"error\": {\"code\": %d, \"message\": \"%s\"}}\n\n",
251-
statusCode, errorBody.replace("\"", "\\\""));
252-
}
253-
}
254240

255241
private String getApiKey(String encryptApiKey) throws Exception {
256242
String sm4Key = System.getenv("SM4KEY");

0 commit comments

Comments
 (0)