最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java調(diào)用第三方接口實(shí)現(xiàn)流式輸出的示例代碼

 更新時間:2025年12月10日 09:06:33   作者:愛吃土豆的馬鈴薯?????????  
本文主要介紹了java調(diào)用第三方接口實(shí)現(xiàn)流式輸出,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

源代碼

@Operation(summary = "問答問題查詢接口")
@PostMapping(value = "/question/answer")
public String questionAnswer(@Parameter(description = "用戶問題", required = true) @RequestParam("message") String message,
                             @Parameter(description = "Admin-Token", required = true) @RequestHeader( required = false) String token) throws IOException {
    return projectService.questionAnswer(message, token);
}


public String questionAnswer(String message,String token){
    String chatNormalResult = this.chatNormal(message,chatModel);
    return chatNormalResult;
}


public String chatNormal(String message,String modelName){
    try {
        long startTime = System.nanoTime();
        ObjectMapper objectMapper = new ObjectMapper();
        // 調(diào)用chatNormal做數(shù)據(jù)分析
        String chatNormalUrl = "http://localhost:5670/api/v2/chat/completions";
        Map<String, Object> chatNormalBody = new HashMap<>();
        // 設(shè)置請求頭
        Map<String, String> headers = new HashMap<>();
        headers.put("accept", "application/json");
        headers.put("Content-Type", "application/json");
        chatNormalBody.put("messages",message);
        chatNormalBody.put("model",modelName);
        chatNormalBody.put("stream",true);
        chatNormalBody.put("temperature",0.5);
        chatNormalBody.put("max_new_tokens",4000);
        chatNormalBody.put("conv_uid", UUID.randomUUID().toString());
        String chatNormalBodyJson = objectMapper.writeValueAsString(chatNormalBody);

        // 發(fā)送POST請求
        long startTime2 = System.nanoTime();
        String resultData = okHttpUtil.postJson(chatNormalUrl, chatNormalBodyJson, headers);
        return resultData;
    }catch (Exception e){
        return "暫無數(shù)據(jù)";
    }
}

基于原有代碼的最小改動方案

1. 首先,修改pom.xml添加必要依賴

<!-- 如果還沒有OkHttp,添加這個依賴 -->
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.9.3</version>
</dependency>

2. 修改Controller接口(增加流式接口,原接口不變)

import org.springframework.http.MediaType;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;

@Operation(summary = "問答問題查詢接口(流式)")
@PostMapping(value = "/question/answer/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public void questionAnswerStream(
        @Parameter(description = "用戶問題", required = true) @RequestParam("message") String message,
        @Parameter(description = "Admin-Token", required = true) @RequestHeader(required = false) String token,
        HttpServletResponse response) throws IOException {
    
    projectService.questionAnswerStream(message, token, response);
}

// 原有的同步接口保持不變
@Operation(summary = "問答問題查詢接口")
@PostMapping(value = "/question/answer")
public String questionAnswer(
        @Parameter(description = "用戶問題", required = true) @RequestParam("message") String message,
        @Parameter(description = "Admin-Token", required = true) @RequestHeader(required = false) String token) throws IOException {
    
    return projectService.questionAnswer(message, token);
}

3. 修改Service方法(最簡單的方式)

import okhttp3.*;
import com.fasterxml.jackson.databind.ObjectMapper;

public void questionAnswerStream(String message, String token, HttpServletResponse response) throws IOException {
    response.setContentType("text/event-stream");
    response.setCharacterEncoding("UTF-8");
    response.setHeader("Cache-Control", "no-cache");
    response.setHeader("Connection", "keep-alive");
    
    PrintWriter writer = response.getWriter();
    
    try {
        ObjectMapper objectMapper = new ObjectMapper();
        String chatNormalUrl = "http://localhost:5670/api/v2/chat/completions";
        
        // 構(gòu)建請求體
        Map<String, Object> requestBody = new HashMap<>();
        Map<String, String> userMessage = new HashMap<>();
        userMessage.put("role", "user");
        userMessage.put("content", message);
        
        requestBody.put("messages", new Map[]{userMessage});
        requestBody.put("model", "deepseek-ai/DeepSeek-R1");
        requestBody.put("stream", true);  // 這里改為true
        requestBody.put("temperature", 0.5);
        requestBody.put("max_new_tokens", 4000);
        requestBody.put("conv_uid", UUID.randomUUID().toString());
        
        String requestBodyJson = objectMapper.writeValueAsString(requestBody);
        
        // 使用OkHttp進(jìn)行流式調(diào)用
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(chatNormalUrl)
                .post(RequestBody.create(requestBodyJson, MediaType.parse("application/json")))
                .addHeader("accept", "application/json")
                .addHeader("Content-Type", "application/json")
                .build();
        
        // 關(guān)鍵:使用流式響應(yīng)
        Response apiResponse = client.newCall(request).execute();
        
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(apiResponse.body().byteStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                if (line.startsWith("data: ")) {
                    // 直接轉(zhuǎn)發(fā)給前端
                    writer.write(line + "\n\n");
                    writer.flush();
                }
            }
        }
        
    } catch (Exception e) {
        // 發(fā)送錯誤信息
        writer.write("data: {\"error\": \"" + e.getMessage() + "\"}\n\n");
        writer.flush();
        e.printStackTrace();
    }
}

// 原有的同步方法保持不變
public String questionAnswer(String message, String token) {
    try {
        // 這里可以調(diào)用一個新的方法,或者復(fù)用部分邏輯,但stream=false
        return callChatAPI(message, false);
    } catch (Exception e) {
        return "請求失敗: " + e.getMessage();
    }
}

// 如果想把流式和非流式邏輯統(tǒng)一,可以這樣重構(gòu)
private String callChatAPI(String message, boolean isStream) throws Exception {
    ObjectMapper objectMapper = new ObjectMapper();
    String chatNormalUrl = "http://localhost:5670/api/v2/chat/completions";
    
    Map<String, Object> requestBody = new HashMap<>();
    Map<String, String> userMessage = new HashMap<>();
    userMessage.put("role", "user");
    userMessage.put("content", message);
    
    requestBody.put("messages", new Map[]{userMessage});
    requestBody.put("model", "deepseek-ai/DeepSeek-R1");
    requestBody.put("stream", isStream);  // 根據(jù)參數(shù)決定是否流式
    requestBody.put("temperature", 0.5);
    requestBody.put("max_new_tokens", 4000);
    requestBody.put("conv_uid", UUID.randomUUID().toString());
    
    String requestBodyJson = objectMapper.writeValueAsString(requestBody);
    
    Map<String, String> headers = new HashMap<>();
    headers.put("accept", "application/json");
    headers.put("Content-Type", "application/json");
    
    if (isStream) {
        // 流式邏輯 - 這里需要不同的處理,但暫時不實(shí)現(xiàn)
        return "流式調(diào)用需使用特定方法";
    } else {
        // 非流式邏輯
        String resultData = okHttpUtil.postJson(chatNormalUrl, requestBodyJson, headers);
        
        // 解析結(jié)果
        Map<String, Object> result = objectMapper.readValue(resultData, Map.class);
        List<Map<String, Object>> choices = (List<Map<String, Object>>) result.get("choices");
        if (choices != null && !choices.isEmpty()) {
            Map<String, Object> messageObj = (Map<String, Object>) choices.get(0).get("message");
            return (String) messageObj.get("content");
        }
        return "暫無數(shù)據(jù)";
    }
}

4. 如果不想用OkHttp,想保留原有的okHttpUtil,可以用這種方式

public void questionAnswerStream(String message, String token, HttpServletResponse response) throws IOException {
    response.setContentType("text/event-stream");
    response.setCharacterEncoding("UTF-8");
    response.setHeader("Cache-Control", "no-cache");
    response.setHeader("Connection", "keep-alive");
    
    PrintWriter writer = response.getWriter();
    
    try {
        // 使用Socket直接連接,這是最直接的流式處理方式
        Socket socket = new Socket("localhost", 5670);
        
        // 構(gòu)建HTTP請求
        String requestBody = buildRequestBody(message);
        String httpRequest = 
            "POST /api/v2/chat/completions HTTP/1.1\r\n" +
            "Host: localhost:5670\r\n" +
            "Accept: application/json\r\n" +
            "Content-Type: application/json\r\n" +
            "Content-Length: " + requestBody.length() + "\r\n" +
            "Connection: close\r\n" +
            "\r\n" +
            requestBody;
        
        // 發(fā)送請求
        OutputStream out = socket.getOutputStream();
        out.write(httpRequest.getBytes(StandardCharsets.UTF_8));
        out.flush();
        
        // 讀取響應(yīng)
        BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        
        // 跳過HTTP響應(yīng)頭
        String line;
        while ((line = reader.readLine()) != null && !line.isEmpty()) {
            // 跳過頭部
        }
        
        // 讀取SSE數(shù)據(jù)
        while ((line = reader.readLine()) != null) {
            if (line.startsWith("data: ")) {
                writer.write(line + "\n\n");
                writer.flush();
                
                if (line.equals("data: [DONE]")) {
                    break;
                }
            }
        }
        
        socket.close();
        
    } catch (Exception e) {
        writer.write("data: {\"error\": \"" + e.getMessage() + "\"}\n\n");
        writer.flush();
        e.printStackTrace();
    }
}

private String buildRequestBody(String message) throws Exception {
    ObjectMapper objectMapper = new ObjectMapper();
    Map<String, Object> requestBody = new HashMap<>();
    Map<String, String> userMessage = new HashMap<>();
    userMessage.put("role", "user");
    userMessage.put("content", message);
    
    requestBody.put("messages", new Map[]{userMessage});
    requestBody.put("model", "deepseek-ai/DeepSeek-R1");
    requestBody.put("stream", true);
    requestBody.put("temperature", 0.5);
    requestBody.put("max_new_tokens", 4000);
    requestBody.put("conv_uid", UUID.randomUUID().toString());
    
    return objectMapper.writeValueAsString(requestBody);
}

5. 最簡單的測試版本(先驗(yàn)證能否流式)

public void questionAnswerStream(String message, String token, HttpServletResponse response) throws IOException {
    response.setContentType("text/event-stream");
    response.setCharacterEncoding("UTF-8");
    
    PrintWriter writer = response.getWriter();
    
    // 先模擬流式輸出,驗(yàn)證前端能收到
    writer.write("data: {\"choices\":[{\"delta\":{\"content\":\"正在處理您的問題...\\n\"}}]}\n\n");
    writer.flush();
    
    Thread.sleep(1000);
    
    writer.write("data: {\"choices\":[{\"delta\":{\"content\":\"這是流式輸出的第一段內(nèi)容。\\n\"}}]}\n\n");
    writer.flush();
    
    Thread.sleep(1000);
    
    writer.write("data: {\"choices\":[{\"delta\":{\"content\":\"這是第二段內(nèi)容。\\n\"}}]}\n\n");
    writer.flush();
    
    Thread.sleep(1000);
    
    writer.write("data: [DONE]\n\n");
    writer.flush();
}

6. 前端調(diào)用(最簡單的HTML頁面)

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>測試流式輸出</title>
</head>
<body>
    <h2>測試流式問答</h2>
    <input type="text" id="question" placeholder="輸入問題">
    <button onclick="askQuestion()">提問</button>
    <div id="answer" style="border:1px solid #ccc; padding:10px; margin-top:10px; min-height:100px;"></div>

    <script>
        function askQuestion() {
            const question = document.getElementById('question').value;
            const answerDiv = document.getElementById('answer');
            answerDiv.innerHTML = '';
            
            // 使用EventSource接收流式數(shù)據(jù)
            const eventSource = new EventSource(`/api/question/answer/stream?message=${encodeURIComponent(question)}`);
            
            eventSource.onmessage = function(event) {
                const data = event.data;
                
                if (data === '[DONE]') {
                    eventSource.close();
                    return;
                }
                
                try {
                    const json = JSON.parse(data);
                    if (json.choices && json.choices[0].delta && json.choices[0].delta.content) {
                        answerDiv.innerHTML += json.choices[0].delta.content;
                    }
                } catch (e) {
                    console.error('解析錯誤:', e);
                }
            };
            
            eventSource.onerror = function(error) {
                console.error('連接錯誤:', error);
                eventSource.close();
            };
        }
    </script>
</body>
</html>

關(guān)鍵改動總結(jié):

  1. 新增一個流式接口:使用 produces = MediaType.TEXT_EVENT_STREAM_VALUE
  2. 修改HttpServletResponse:設(shè)置SSE相關(guān)響應(yīng)頭
  3. 保持原有接口不變:不影響現(xiàn)有調(diào)用
  4. 使用PrintWriter流式輸出:最簡單的流式輸出方式
  5. 前端使用EventSource接收:最簡潔的前端實(shí)現(xiàn)

如果希望更簡單地集成,這里是最簡單的方案:

@PostMapping(value = "/question/answer/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public void questionAnswerStream(
        @RequestParam("message") String message,
        @RequestHeader(required = false) String token,
        HttpServletResponse response) throws IOException {
    
    response.setContentType("text/event-stream");
    response.setCharacterEncoding("UTF-8");
    
    PrintWriter writer = response.getWriter();
    
    // 直接調(diào)用外部命令(如果API支持命令行調(diào)用)
    try {
        // 構(gòu)建curl命令調(diào)用DeepSeek API
        String[] cmd = {
            "curl", "-X", "POST",
            "http://localhost:5670/api/v2/chat/completions",
            "-H", "Content-Type: application/json",
            "-H", "accept: application/json",
            "-d", String.format("{\"messages\":[{\"role\":\"user\",\"content\":\"%s\"}],\"model\":\"deepseek-ai/DeepSeek-R1\",\"stream\":true}", message)
        };
        
        Process process = Runtime.getRuntime().exec(cmd);
        BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
        
        String line;
        while ((line = reader.readLine()) != null) {
            writer.write(line + "\n\n");
            writer.flush();
        }
        
        process.waitFor();
        
    } catch (Exception e) {
        writer.write("data: {\"error\": \"" + e.getMessage() + "\"}\n\n");
        writer.flush();
    }
}

只需要新增一個接口,就可以實(shí)現(xiàn)最直接的流式輸出方式

集成到現(xiàn)有OkHttpUtil工具類的流式輸出方案

作為資深專家,我會充分復(fù)用現(xiàn)有的工具類。以下是基于現(xiàn)有代碼的最小改動方案:

1. 首先,在OkHttpUtil中添加流式處理方法

@Slf4j
@Component
public class OkHttpUtil {

    private static final OkHttpClient client = new OkHttpClient.Builder()
            .connectTimeout(60, TimeUnit.SECONDS)
            .readTimeout(60, TimeUnit.MINUTES)
            .writeTimeout(30, TimeUnit.MINUTES)
            .callTimeout(90, TimeUnit.MINUTES)
            .build();

    /**
     * 流式POST請求 - 專為SSE設(shè)計(jì)
     */
    public void postJsonStream(String url, String json, Map<String, String> headers, 
                              Consumer<String> lineConsumer) throws IOException {
        Request.Builder builder = new Request.Builder()
                .url(url)
                .post(RequestBody.create(json, okhttp3.MediaType.parse("application/json")));
        
        if (headers != null) {
            headers.forEach(builder::addHeader);
        }
        
        Request request = builder.build();
        
        try (Response response = client.newCall(request).execute()) {
            if (!response.isSuccessful()) {
                throw new IOException("請求失敗: " + response.code());
            }
            
            ResponseBody body = response.body();
            if (body == null) {
                return;
            }
            
            try (BufferedReader reader = new BufferedReader(new InputStreamReader(body.byteStream()))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    lineConsumer.accept(line);
                }
            }
        }
    }
    
    // 原有的同步方法保持不變
    public String postJson(String url, String json, Map<String, String> headers) throws IOException {
        // ... 原有的實(shí)現(xiàn) ...
        return null;
    }
}

2. 修改Service方法(最小改動)

import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;

public void questionAnswerStream(String message, String token, HttpServletResponse response) throws IOException {
    // 設(shè)置SSE響應(yīng)頭
    response.setContentType("text/event-stream");
    response.setCharacterEncoding("UTF-8");
    response.setHeader("Cache-Control", "no-cache");
    response.setHeader("Connection", "keep-alive");
    
    PrintWriter writer = response.getWriter();
    
    try {
        // 復(fù)用原有的請求構(gòu)建邏輯
        ObjectMapper objectMapper = new ObjectMapper();
        
        // 構(gòu)建請求體 - 和原有代碼一模一樣,只是stream=true
        Map<String, Object> chatNormalBody = new HashMap<>();
        
        // 構(gòu)建messages - 注意這里需要是數(shù)組
        List<Map<String, String>> messages = new ArrayList<>();
        Map<String, String> userMessage = new HashMap<>();
        userMessage.put("role", "user");
        userMessage.put("content", message);
        messages.add(userMessage);
        
        chatNormalBody.put("messages", messages);
        chatNormalBody.put("model", "deepseek-ai/DeepSeek-R1");
        chatNormalBody.put("stream", true);  // 關(guān)鍵:改為true
        chatNormalBody.put("temperature", 0.5);
        chatNormalBody.put("max_new_tokens", 4000);
        chatNormalBody.put("conv_uid", UUID.randomUUID().toString());
        
        String chatNormalBodyJson = objectMapper.writeValueAsString(chatNormalBody);
        
        // 構(gòu)建請求頭
        Map<String, String> headers = new HashMap<>();
        headers.put("accept", "application/json");
        headers.put("Content-Type", "application/json");
        
        // 關(guān)鍵:使用新的流式方法調(diào)用
        okHttpUtil.postJsonStream(
            "http://localhost:5670/api/v2/chat/completions",
            chatNormalBodyJson,
            headers,
            line -> {
                // 處理每一行流式數(shù)據(jù)
                if (line.startsWith("data: ")) {
                    try {
                        writer.write(line + "\n\n");
                        writer.flush();
                        
                        // 如果收到結(jié)束標(biāo)志,可以在這里做額外處理
                        if (line.equals("data: [DONE]")) {
                            log.info("流式輸出完成");
                        }
                    } catch (Exception e) {
                        log.error("寫入響應(yīng)失敗", e);
                    }
                }
            }
        );
        
    } catch (Exception e) {
        log.error("流式請求失敗", e);
        // 發(fā)送錯誤信息給前端
        try {
            Map<String, String> error = new HashMap<>();
            error.put("error", e.getMessage());
            String errorJson = objectMapper.writeValueAsString(error);
            writer.write("data: " + errorJson + "\n\n");
            writer.flush();
        } catch (Exception ex) {
            // 忽略
        }
    }
}

// 原有的同步方法完全保持不變
public String questionAnswer(String message, String token) {
    String chatNormalResult = this.chatNormal(message, "deepseek-ai/DeepSeek-R1");
    return chatNormalResult;
}

// 原有的chatNormal方法完全保持不變
public String chatNormal(String message, String modelName) {
    try {
        long startTime = System.nanoTime();
        ObjectMapper objectMapper = new ObjectMapper();
        String chatNormalUrl = "http://localhost:5670/api/v2/chat/completions";
        Map<String, Object> chatNormalBody = new HashMap<>();
        Map<String, String> headers = new HashMap<>();
        headers.put("accept", "application/json");
        headers.put("Content-Type", "application/json");
        
        // 注意:這里messages應(yīng)該是數(shù)組,看原有代碼怎么寫的
        // 假設(shè)原有代碼已經(jīng)處理好了
        chatNormalBody.put("messages", message); // 這里可能需要調(diào)整
        chatNormalBody.put("model", modelName);
        chatNormalBody.put("stream", false); // 同步請求不流式
        chatNormalBody.put("temperature", 0.5);
        chatNormalBody.put("max_new_tokens", 4000);
        chatNormalBody.put("conv_uid", UUID.randomUUID().toString());
        
        String chatNormalBodyJson = objectMapper.writeValueAsString(chatNormalBody);
        String resultData = okHttpUtil.postJson(chatNormalUrl, chatNormalBodyJson, headers);
        return resultData;
    } catch (Exception e) {
        return "暫無數(shù)據(jù)";
    }
}

3. 或者,更簡單的方式 - 直接修改chatNormal方法支持流式

如果想讓代碼更統(tǒng)一,可以這樣修改:

// 在Service類中添加這個方法
public void chatNormalStream(String message, String modelName, PrintWriter writer) {
    try {
        ObjectMapper objectMapper = new ObjectMapper();
        
        // 構(gòu)建messages
        List<Map<String, String>> messages = new ArrayList<>();
        Map<String, String> userMessage = new HashMap<>();
        userMessage.put("role", "user");
        userMessage.put("content", message);
        messages.add(userMessage);
        
        // 構(gòu)建請求體
        Map<String, Object> requestBody = new HashMap<>();
        requestBody.put("messages", messages);
        requestBody.put("model", modelName);
        requestBody.put("stream", true);
        requestBody.put("temperature", 0.5);
        requestBody.put("max_new_tokens", 4000);
        requestBody.put("conv_uid", UUID.randomUUID().toString());
        
        String jsonBody = objectMapper.writeValueAsString(requestBody);
        
        // 請求頭
        Map<String, String> headers = new HashMap<>();
        headers.put("accept", "application/json");
        headers.put("Content-Type", "application/json");
        
        // 使用OkHttp直接調(diào)用(不通過工具類,因?yàn)樾枰魇教幚恚?
        OkHttpClient client = new OkHttpClient();
        okhttp3.Request request = new okhttp3.Request.Builder()
                .url("http://localhost:5670/api/v2/chat/completions")
                .post(okhttp3.RequestBody.create(
                    jsonBody, 
                    okhttp3.MediaType.parse("application/json")
                ))
                .headers(okhttp3.Headers.of(headers))
                .build();
        
        try (okhttp3.Response response = client.newCall(request).execute()) {
            if (response.isSuccessful()) {
                ResponseBody body = response.body();
                if (body != null) {
                    BufferedReader reader = new BufferedReader(
                        new InputStreamReader(body.byteStream())
                    );
                    
                    String line;
                    while ((line = reader.readLine()) != null) {
                        // 直接轉(zhuǎn)發(fā)SSE格式數(shù)據(jù)
                        if (line.startsWith("data: ")) {
                            writer.write(line + "\n\n");
                            writer.flush();
                        }
                    }
                }
            }
        }
        
    } catch (Exception e) {
        log.error("流式請求失敗", e);
        try {
            writer.write("data: {\"error\": \"" + e.getMessage() + "\"}\n\n");
            writer.flush();
        } catch (Exception ex) {
            // 忽略
        }
    }
}

4. 最簡化的Controller調(diào)用

@Operation(summary = "問答問題查詢接口 - 流式")
@PostMapping(value = "/question/answer/stream", produces = "text/event-stream;charset=UTF-8")
public void questionAnswerStream(
        @RequestParam("message") String message,
        @RequestHeader(required = false) String token,
        HttpServletResponse response) throws IOException {
    
    // 設(shè)置SSE響應(yīng)頭
    response.setContentType("text/event-stream");
    response.setCharacterEncoding("UTF-8");
    response.setHeader("Cache-Control", "no-cache");
    response.setHeader("Connection", "keep-alive");
    
    // 直接調(diào)用
    projectService.chatNormalStream(message, "deepseek-ai/DeepSeek-R1", response.getWriter());
}

5. 如果不想修改OkHttpUtil,最簡單的版本

// 直接在Service中處理流式請求
public void questionAnswerStream(String message, String token, HttpServletResponse response) throws IOException {
    response.setContentType("text/event-stream");
    response.setCharacterEncoding("UTF-8");
    
    PrintWriter writer = response.getWriter();
    
    try {
        // 復(fù)用原有的OkHttpClient配置
        OkHttpClient client = OkHttpUtil.getClient(); // 如果client是public或提供getter
        
        // 構(gòu)建請求體(和原有代碼一致)
        ObjectMapper mapper = new ObjectMapper();
        Map<String, Object> requestBody = new HashMap<>();
        
        // 構(gòu)建messages數(shù)組
        List<Map<String, String>> messages = new ArrayList<>();
        Map<String, String> userMsg = new HashMap<>();
        userMsg.put("role", "user");
        userMsg.put("content", message);
        messages.add(userMsg);
        
        requestBody.put("messages", messages);
        requestBody.put("model", "deepseek-ai/DeepSeek-R1");
        requestBody.put("stream", true);
        requestBody.put("temperature", 0.5);
        requestBody.put("max_new_tokens", 4000);
        requestBody.put("conv_uid", UUID.randomUUID().toString());
        
        String json = mapper.writeValueAsString(requestBody);
        
        // 構(gòu)建請求
        okhttp3.Request request = new okhttp3.Request.Builder()
                .url("http://localhost:5670/api/v2/chat/completions")
                .post(okhttp3.RequestBody.create(json, 
                    okhttp3.MediaType.parse("application/json; charset=utf-8")))
                .addHeader("accept", "application/json")
                .addHeader("Content-Type", "application/json")
                .build();
        
        // 執(zhí)行請求并處理流式響應(yīng)
        try (okhttp3.Response apiResponse = client.newCall(request).execute()) {
            if (apiResponse.isSuccessful()) {
                ResponseBody body = apiResponse.body();
                if (body != null) {
                    // 逐行讀取流式響應(yīng)
                    BufferedReader reader = new BufferedReader(
                        new InputStreamReader(body.byteStream())
                    );
                    
                    String line;
                    while ((line = reader.readLine()) != null) {
                        if (line.startsWith("data: ")) {
                            // 直接轉(zhuǎn)發(fā)給前端
                            writer.write(line + "\n\n");
                            writer.flush();
                        }
                    }
                }
            }
        }
        
    } catch (Exception e) {
        log.error("流式請求異常", e);
        writer.write("data: {\"error\": \"服務(wù)異常: " + e.getMessage() + "\"}\n\n");
        writer.flush();
    }
}

6. 前端調(diào)用(極簡版)

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>流式問答</title>
</head>
<body>
    <input type="text" id="question" placeholder="輸入問題">
    <button onclick="ask()">提問</button>
    <div id="answer" style="white-space: pre-wrap; border:1px solid #ccc; padding:10px; margin-top:10px;"></div>

    <script>
        function ask() {
            const question = document.getElementById('question').value;
            const answerDiv = document.getElementById('answer');
            answerDiv.innerHTML = '';
            
            // 使用EventSource接收流式數(shù)據(jù)
            const es = new EventSource(`/api/question/answer/stream?message=${encodeURIComponent(question)}`);
            
            es.onmessage = function(e) {
                const data = e.data;
                if (data === '[DONE]') {
                    es.close();
                    return;
                }
                
                try {
                    const json = JSON.parse(data);
                    if (json.choices && json.choices[0].delta && json.choices[0].delta.content) {
                        answerDiv.innerHTML += json.choices[0].delta.content;
                    }
                } catch(err) {
                    // 忽略解析錯誤
                }
            };
            
            es.onerror = function() {
                es.close();
            };
        }
    </script>
</body>
</html>

到此這篇關(guān)于java調(diào)用第三方接口實(shí)現(xiàn)流式輸出的示例代碼的文章就介紹到這了,更多相關(guān)java 流式輸出內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java?ArrayList遍歷foreach與iterator時remove的區(qū)別

    Java?ArrayList遍歷foreach與iterator時remove的區(qū)別

    這篇文章主要介紹了Java?ArrayList遍歷foreach與iterator時remove的區(qū)別,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價值,需要的朋友可以參考一下
    2022-07-07
  • java實(shí)現(xiàn)ModbusCRC16校驗(yàn)的示例代碼

    java實(shí)現(xiàn)ModbusCRC16校驗(yàn)的示例代碼

    本文介紹了使用Java實(shí)現(xiàn)ModbusCRC16校驗(yàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-11-11
  • 關(guān)于jdk8升級jdk21 cxf報(bào)錯的踩坑記錄

    關(guān)于jdk8升級jdk21 cxf報(bào)錯的踩坑記錄

    在升級Java項(xiàng)目時,從JDK1.8和Spring2遷移到JDK21和Spring3后,遇到了JAXBException錯誤,原因是從JDK11開始移除了jaxb模塊,而cxf在編譯動態(tài)客戶端時默認(rèn)classpath不包含必要的類,解決方法是在jar包同級目錄創(chuàng)建libs并添加jakarta.xml.bind-api
    2024-10-10
  • SpringBoot實(shí)現(xiàn)短信驗(yàn)證碼校驗(yàn)方法思路詳解

    SpringBoot實(shí)現(xiàn)短信驗(yàn)證碼校驗(yàn)方法思路詳解

    最近做項(xiàng)目遇到這樣的需求,前端是基于BootStrap,html代碼中有BootStrap樣式實(shí)現(xiàn)的,具體后臺實(shí)現(xiàn)代碼大家通過本文一起學(xué)習(xí)吧
    2017-08-08
  • 通過實(shí)例了解Java jdk和jre的區(qū)別

    通過實(shí)例了解Java jdk和jre的區(qū)別

    這篇文章主要介紹了通過實(shí)例了解Java jdk和jre的區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-05-05
  • SpringMVC異常全局捕獲與錯誤響應(yīng)的處理方法

    SpringMVC異常全局捕獲與錯誤響應(yīng)的處理方法

    編程式異常處理是通過在代碼中?顯式編寫異常捕獲邏輯(如?try-catch?塊)來管理異常的方式,開發(fā)者需要手動處理每一個可能拋出異常的代碼段,本文給大家介紹SpringMVC異常全局捕獲與錯誤響應(yīng)的處理方法,感興趣的朋友一起看看吧
    2025-03-03
  • idea?compile項(xiàng)目正常啟動項(xiàng)目的時候build失敗報(bào)“找不到符號”等問題及解決方案

    idea?compile項(xiàng)目正常啟動項(xiàng)目的時候build失敗報(bào)“找不到符號”等問題及解決方案

    這篇文章主要介紹了idea?compile項(xiàng)目正常,啟動項(xiàng)目的時候build失敗,報(bào)“找不到符號”等問題,這種問題屬于lombok編譯失敗導(dǎo)致,可能原因是依賴jar包沒有更新到最新版本,需要的朋友可以參考下
    2023-10-10
  • 關(guān)于Springboot的日志配置

    關(guān)于Springboot的日志配置

    Spring Boot默認(rèn)使用LogBack日志系統(tǒng),如果不需要更改為其他日志系統(tǒng)如Log4j2等,則無需多余的配置,LogBack默認(rèn)將日志打印到控制臺上,需要的朋友可以參考下
    2023-05-05
  • mybatis?plus常用注解的具體使用

    mybatis?plus常用注解的具體使用

    本文主要介紹了mybatis?plus常用注解的具體使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • Java中LinkedHashSet的源碼剖析

    Java中LinkedHashSet的源碼剖析

    這篇文章主要介紹了Java中LinkedHashSet的源碼剖析,LinkedHashSet是HashSet的子類,LinkedHashSet底層是一個LinkedHashMap,底層維護(hù)了一個數(shù)組+雙向鏈表,需要的朋友可以參考下
    2023-09-09

最新評論

石狮市| 东海县| 呈贡县| 绿春县| 邵阳县| 伊吾县| 扶余县| 招远市| 滦南县| 公主岭市| 霍州市| 分宜县| 滦南县| 南康市| 缙云县| 南雄市| 庄河市| 淳化县| 永仁县| 日照市| 英德市| 彰化市| 五华县| 宜都市| 保定市| 广河县| 木里| 恩施市| 公安县| 日喀则市| 双江| 秦安县| 滦平县| 高清| 潞城市| 竹山县| 上林县| 黄大仙区| 长沙县| 甘洛县| 蒲城县|