import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.luck.ai.dto.ChatAiDTO;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.*;
import org.springframework.web.client.RestTemplate;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Data
@Slf4j
public class JavaUtil {
private static final String BASE_URL = "https://api.siliconflow.cn/v1/chat/completions";
private static final String API_KEY = "****";
private static final String MODEL = "Pro/deepseek-ai/DeepSeek-V3";
private static final ObjectMapper objectMapper = new ObjectMapper();
private static final RestTemplate restTemplate = new RestTemplate();
// 响应基础结构
@Data
public static class OpenAIResponse {
private String id; // 本次请求的唯一标识ID
private String object; // 对象类型
private long created; // 请求时间戳
private String model; // 使用的模型名称
private List<Choice> choices; // 生成结果列表
private Usage usage; // token使用情况
}
// 生成结果项
@Data
public static class Choice {
private int index; // 结果索引
private Message message; // 消息内容
@JsonProperty("finish_reason")
private String finishReason; // 结束原因(stop表示正常结束)
private Object logprobs; // 日志概率(当前示例为null)
private Delta delta; // 用于流式响应
}
// 用于流式响应的增量内容
@Data
public static class Delta {
private String content;
}
// 消息结构
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class Message {
private String role; // 角色标识
private String content; // 消息内容
}
// token使用详情
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Usage {
@JsonProperty("prompt_tokens")
private int promptTokens; // 提示词消耗token数
@JsonProperty("completion_tokens")
private int completionTokens; // 生成内容消耗token数
@JsonProperty("total_tokens")
private int totalTokens; // 总消耗token数
@JsonProperty("prompt_tokens_details")
private PromptTokensDetails promptTokensDetails; // 提示词token详情
@JsonProperty("completion_tokens_details")
private CompletionTokensDetails completionTokensDetails; // 生成内容token详情
}
// 提示词token详情
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class PromptTokensDetails {
@JsonProperty("cached_tokens")
private int cachedTokens; // 缓存的token数量
}
// 生成内容token详情
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class CompletionTokensDetails {
@JsonProperty("reasoning_tokens")
private int reasoningTokens; // 推理消耗token数
}
public static JSONObject fomaitcontentToJson(JavaUtil.OpenAIResponse oir){
String returnStr = oir.getChoices().get(0).getMessage().getContent();
if(StringUtils.isNotBlank(returnStr)){
returnStr = oir.getChoices().get(0).getMessage().getContent()
.replaceAll("json","")
.replaceAll("```","")
.replaceAll("\\n","");
}
return JSONObject.parseObject(returnStr);
}
/**
* 同步调用OpenAI Chat Completion API
* @param messages 消息列表
* @return API响应对象
*/
public static OpenAIResponse chatCompletionV2(List<Message> messages, ChatAiDTO dto) {
log.info("chatCompletion request-body-messages: {}", messages);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Bearer " + API_KEY);
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("model", MODEL);
requestBody.put("messages", messages);
requestBody.put("stream", dto.getIsStream());
requestBody.put("temperature", 0.7);
requestBody.put("top_p", 1);
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
int retryCount = 0;
while (retryCount < dto.getMaxRetries()) {
try {
ResponseEntity<OpenAIResponse> response = restTemplate.exchange(
BASE_URL,
HttpMethod.POST,
requestEntity,
OpenAIResponse.class
);
OpenAIResponse or = response.getBody();
log.info("OpenAIResponse : {}",or);
if(dto.getIsReturnJson()){
JavaUtil.fomaitcontentToJson(or);
}
return or;
} catch (Exception e) {
retryCount++;
if (retryCount >= dto.getMaxRetries()) {
log.warn("deepseek 请求异常!");
}
}
// 可以添加短暂的延迟再重试
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
}
return null;
}
/**
* 同步调用OpenAI Chat Completion API
* @param messages 消息列表
* @param stream 是否使用流式响应
* @param maxRetries 重试次数
* @return API响应对象
*/
public static OpenAIResponse chatCompletion(List<Message> messages, boolean stream,int maxRetries) {
log.info("chatCompletion request-body-messages: {}", messages);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("Authorization", "Bearer " + API_KEY);
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("model", MODEL);
requestBody.put("messages", messages);
requestBody.put("stream", stream);
requestBody.put("temperature", 0.7);
requestBody.put("top_p", 1);
HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(requestBody, headers);
int retryCount = 0;
while (retryCount < maxRetries) {
try {
ResponseEntity<OpenAIResponse> response = restTemplate.exchange(
BASE_URL,
HttpMethod.POST,
requestEntity,
OpenAIResponse.class
);
OpenAIResponse or = response.getBody();
log.info("OpenAIResponse : {}",or);
return or;
} catch (Exception e) {
retryCount++;
if (retryCount >= maxRetries) {
log.warn("deepseek 请求异常!");
}
}
// 可以添加短暂的延迟再重试
try {
Thread.sleep(500);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}
}
return null;
}
/**
* 流式聊天回调接口
*/
public interface StreamChatCallback {
void onContent(String line,String content);
void onError(Exception error);
void onDone();
}
/**
* 流式调用OpenAI Chat Completion API
* @param messages 消息列表
* @param callback 回调接口
*/
public static void streamChatCompletion(List<Message> messages, StreamChatCallback callback) {
HttpURLConnection connection = null;
try {
// 准备请求体
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("model", MODEL);
requestBody.put("messages", messages);
requestBody.put("stream", true);
requestBody.put("temperature", 0.7);
requestBody.put("top_p", 1);
String jsonBody = objectMapper.writeValueAsString(requestBody);
log.info("streamChatCompletion request-body-messages: {}", messages);
// 建立连接
URL url = new URL(BASE_URL);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setRequestProperty("Authorization", "Bearer " + API_KEY);
connection.setDoOutput(true);
connection.setReadTimeout(60000);
// 发送请求
connection.getOutputStream().write(jsonBody.getBytes(StandardCharsets.UTF_8));
// 检查响应状态
int responseCode = connection.getResponseCode();
if (responseCode != 200) {
throw new IOException("HTTP 错误! 状态: " + responseCode);
}
// 读取响应流
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(connection.getInputStream(), StandardCharsets.UTF_8))) {
String line;
while ((line = reader.readLine()) != null) {
if (line.startsWith("data:") && !line.contains("[DONE]")) {
try {
String jsonData = line.substring(5).trim();
Map<String, Object> data = objectMapper.readValue(jsonData, Map.class);
List<Map<String, Object>> choices = (List<Map<String, Object>>) data.get("choices");
if (choices != null && !choices.isEmpty()) {
Map<String, Object> delta = (Map<String, Object>) choices.get(0).get("delta");
if (delta != null && delta.containsKey("content")) {
String content = (String) delta.get("content");
if (content != null && !content.isEmpty()) {
log.info("streamChatCompletion content: {}", content);
callback.onContent(line.replace("data:",""),content);
}
}
}
} catch (Exception e) {
log.error("解析JSON失败: " + line, e);
}
} else if (line.contains("[DONE]")) {
callback.onDone();
}
}
}
} catch (Exception e) {
log.error("流式API请求失败", e);
callback.onError(e);
} finally {
if (connection != null) {
connection.disconnect();
}
}
}
/**
* 创建消息对象的辅助方法
*/
public static Message createMessage(String role, String content) {
return new Message(role, content);
}
}