JAVA 对接第三方AI接口(流式/非流式输出)

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);
    }

}

  

posted @ 2025-05-12 16:51  90的生力军  阅读(470)  评论(1)    收藏  举报