spring boot 实现接入 deepseek gpt接口 流式输出

controller

复制代码
package com.xmkjsoft.ssegpt;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

@CrossOrigin
@RestController
@RequestMapping("/chat")
public class ChatController {

    @Value("${deepseek.api.key}")
    private String apiKey;

    @Value("${deepseek.api.url}")
    private String apiUrl;

    // 简单保存 prompt 用,实际可优化
    private final ConcurrentHashMap<String, String> promptMap = new ConcurrentHashMap<>();

    @PostMapping("/start")
    public StartResponse startChat(@RequestBody ChatRequest userRequest) {
        String id = UUID.randomUUID().toString();
        promptMap.put(id, userRequest.getPrompt());
        return new StartResponse(id);
    }

    @GetMapping("/stream")
    public SseEmitter stream(@RequestParam String id) {
        SseEmitter emitter = new SseEmitter(0L);
        String prompt = promptMap.get(id);
        if (prompt == null) {
            emitter.completeWithError(new IllegalArgumentException("无效的id"));
            return emitter;
        }

        new Thread(() -> {
            try {
                String json = """
                    {
                      "model": "deepseek-chat",
                      "stream": true,
                      "messages": [
                        { "role": "system", "content": "You are a helpful assistant." },
                        { "role": "user", "content": "%s" }
                      ]
                    }
                    """.formatted(prompt);

                URL url = new URL(apiUrl);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("POST");
                conn.setRequestProperty("Content-Type", "application/json");
                conn.setRequestProperty("Authorization", "Bearer " + apiKey);
                conn.setDoOutput(true);
                conn.getOutputStream().write(json.getBytes());

                try (BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()))) {
                    String line;
                    while ((line = reader.readLine()) != null) {
                        if (line.startsWith("data: ")) {
                            String data = line.substring("data: ".length());
                            if ("[DONE]".equals(data)) break;
                            emitter.send(data);
                        }
                    }
                }
                emitter.complete();
                promptMap.remove(id);
            } catch (Exception e) {
                emitter.completeWithError(e);
            }
        }).start();

        return emitter;
    }

    @Data
    public static class ChatRequest {
        private String prompt;
    }

    @Data
    public static class StartResponse {
        private final String id;
    }
}

application.properties

复制代码
spring.application.name=ssegpt
#deepseek.model=deepseek-reasoner
deepseek.model=deepseek-chat
deepseek.api.key=自己去获取
deepseek.api.url=https://api.deepseek.com/v1/chat/completions

index.html

复制代码
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8" />
    <title>SSE Chat Demo</title>
</head>
<body>
<textarea id="input" rows="3" cols="40" placeholder="输入你的问题"></textarea><br/>
<button id="sendBtn">发送</button>

<div id="output" style="white-space: pre-wrap; border: 1px solid #ccc; padding: 10px; margin-top: 10px;"></div>

<script>
    document.getElementById('sendBtn').onclick = () => {
        const prompt = document.getElementById('input').value.trim();
        if (!prompt) return alert("请输入内容");

        fetch('/chat/start', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ prompt })
        }).then(res => res.json())
            .then(data => {
                if (!data.id) throw new Error("启动失败");
                listenSSE(data.id);
            }).catch(err => alert("启动错误:" + err));
    };

    function listenSSE(id) {
        const evtSource = new EventSource('/chat/stream?id=' + encodeURIComponent(id));
        const output = document.getElementById('output');
        output.textContent = '';  // 清空之前内容

        evtSource.onmessage = (e) => {
            if (e.data === '[DONE]') {
                evtSource.close();
                return;
            }
            try {
                const json = JSON.parse(e.data);
                const content = json.choices && json.choices[0] && json.choices[0].delta && json.choices[0].delta.content;
                if (content !== undefined) {
                    output.textContent += content;
                }
            } catch (err) {
                output.textContent += e.data;
            }
        };

        evtSource.onerror = (e) => {
            console.error("连接错误", e);
            evtSource.close();
        };
    }
</script>

</body>
</html>

maven 依赖

复制代码
 <dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-web</artifactId>
 </dependency>

 <dependency>
    <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
相关推荐
可乐鸡翅yeah_5 小时前
M3U8 防盗链 URL‑Token 签名,新手开发实操避坑
开发语言·javascript·ios·音视频·safari
2603_965896625 小时前
JS原型与原型链|对象继承与实例底层原理
开发语言·javascript·原型模式
JustHappy6 小时前
「vConsole MCP🛠️」我让 AI 直接看见任何 H5 的日志和请求帮你 debug
前端·javascript·程序员
xieter7 小时前
【技术精选】Node.js 核心事件循环机制与异步 I/O 深度剖析 (2026-10-02)
前端·javascript
想吃火锅10057 小时前
【leetcode】238.除了自身以外数组的乘积js
javascript·算法·leetcode
光依旧8 小时前
MCP实战手记(八):从“能跑“到“能上线“——无状态MCP Server的生产落地清单
java·人工智能·spring boot·架构·ai agent·mcp
web打印社区8 小时前
政务办事大厅:叫号小票、办理回执网页怎么静默出纸
前端·javascript·vue.js·pdf·html·政务
MZ_ZXD0019 小时前
【关注可白嫖源码】--课程设计--毕业设计-- 29210 Vue.js 3+Springboot中药材基本信息与图片查询系统
javascript·spring boot·课程设计·毕设·大作业·程序开发·毕设代做
汤姆yu9 小时前
GPT‑6 Astra大模型综述
gpt·ai·大模型
Cheney Pan9 小时前
第4篇 Spring Boot 应用监控:Micrometer 与 JVM 指标
jvm·spring boot·后端·prometheus