打造聊天流式回复效果:Spring Boot+WebSocket + JS实战
本篇博客将带领你使用 Spring Boot、WebSocket 和 JavaScript 实现一个类似 ChatGPT 的流式回复效果。前端发送消息后,后端接收消息并请求 AI API,并将 AI 返回的流式响应实时推送到前端,最终在聊天界面呈现出逐字出现的打字效果。
技术原理
-
WebSocket 全双工通信: WebSocket 协议提供全双工通信通道,允许服务器和客户端之间进行双向实时数据传输,非常适合实现流式数据传输。
-
Spring WebFlux 响应式编程: Spring WebFlux 基于 Reactor 库,支持响应式流处理,可以处理 AI API 返回的流式数据。
-
SSE(Server-Sent Events): SSE 是一种基于 HTTP 的单向服务器推送技术,可以将 AI 返回的流式数据实时推送到前端。
实现步骤
一、后端实现 (Spring Boot)
- 添加依赖
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
- 创建 WebSocket 处理器
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.messaging.handler.annotation.MessageMapping;
import org.springframework.messaging.handler.annotation.Payload;
import org.springframework.messaging.simp.SimpMessagingTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Flux;import java.time.Duration;@Controller
public class ChatController {@Autowiredprivate SimpMessagingTemplate messagingTemplate;@Autowiredprivate WebClient webClient; // 用于调用 AI API@MessageMapping("/chat.sendMessage") // 接收来自客户端的消息public void sendMessage(@Payload Message message) throws Exception {// 构造 AI API 请求ApiRequest apiRequest = new ApiRequest(message.getContent()); // 假设 AI API 接受 ApiRequest 对象// 调用 AI API,获取流式响应Flux<String> apiResponse = callAiApi(apiRequest);// 处理 AI API 响应,并逐条发送给前端apiResponse.delayElements(Duration.ofMillis(50)) // 模拟打字延迟.subscribe(chunk -> {Message responseMessage = new Message("AI", chunk);messagingTemplate.convertAndSend("/topic/chat", responseMessage);});}// 调用 AI APIprivate Flux<String> callAiApi(ApiRequest request) {// 将 ApiRequest 对象转换为 JSON 字符串// ...// 发送 POST 请求,并指定返回数据类型为 Flux<String>return webClient.post().uri("https://api.example.com/ai-api") // 替换为实际的 AI API 地址.bodyValue(request).retrieve().bodyToFlux(String.class);}// 消息类public static class Message {private String sender;private String content;// 构造函数,getter 和 setter}// AI API 请求类public static class ApiRequest {private String prompt;// 构造函数,getter 和 setter}
}
- WebSocket 配置
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {@Overridepublic void configureMessageBroker(MessageBrokerRegistry config) {config.enableSimpleBroker("/topic");config.setApplicationDestinationPrefixes("/app");}@Overridepublic void registerStompEndpoints(StompEndpointRegistry registry) {registry.addEndpoint("/ws").withSockJS();}
}
二、前端实现 (JavaScript)
<!DOCTYPE html>
<html>
<head><title>Chat Application</title><script src="https://cdnjs.cloudflare.com/ajax/libs/sockjs-client/1.5.1/sockjs.min.js"></script><script src="https://cdnjs.cloudflare.com/ajax/libs/stomp.js/2.3.3/stomp.min.js"></script>
</head>
<body><div id="chat-container"><div id="chat-output"></div><input type="text" id="message-input" placeholder="Enter message..."><button onclick="sendMessage()">Send</button></div><script>// 连接 WebSocketvar socket = new SockJS('/ws');var stompClient = Stomp.over(socket);stompClient.connect({}, function(frame) {console.log('Connected: ' + frame);// 订阅聊天频道stompClient.subscribe('/topic/chat', function(message) {showMessage(JSON.parse(message.body));});});// 发送消息function sendMessage() {var message = document.getElementById('message-input').value;stompClient.send("/app/chat.sendMessage", {}, JSON.stringify({'sender': 'user', // 可替换为实际用户名'content': message}));}// 显示消息function showMessage(message) {var chatOutput = document.getElementById('chat-output');var messageElement = document.createElement('div');if (message.sender === 'AI') {// AI 回复逐字显示typeWriter(messageElement, message.content, 0);} else {messageElement.innerHTML = '<strong>' + message.sender + ':</strong> ' + message.content;chatOutput.appendChild(messageElement);}}// 模拟打字效果function typeWriter(element, text, i) {if (i < text.length) {element.innerHTML += text.charAt(i);setTimeout(function() {typeWriter(element, text, i + 1);}, 50); // 调整打字速度} else {document.getElementById('chat-output').appendChild(element);}}</script>
</body>
</html>
总结
本文介绍了如何使用 Spring Boot 和 WebSocket 实现类似 ChatGPT 的流式回复效果,并详细讲解了每个步骤的技术原理和代码实现。通过这种方式,我们可以构建更加 engaging 和 interactive 的 Web 应用,为用户带来全新的体验。
相关文章:
打造聊天流式回复效果:Spring Boot+WebSocket + JS实战
本篇博客将带领你使用 Spring Boot、WebSocket 和 JavaScript 实现一个类似 ChatGPT 的流式回复效果。前端发送消息后,后端接收消息并请求 AI API,并将 AI 返回的流式响应实时推送到前端,最终在聊天界面呈现出逐字出现的打字效果。 技术原理…...
202年版最新Python下载安装+PyCharm下载安装激活和使用教程!(附安装包+激活码)
一、Python解释器下载【运行环境】 Python官网: https://www.python.org Python各版本解释器官网: https://www.python.org/downloads/ 二、Windows系统安装Python解释器 下载Python版本解释器 现在已经更新到了3.13版本的Python解释器,但…...
【面试宝典】spring常见面试题总结[上]
一、什么是 Spring 框架? Spring 框架是一个为 Java 应用程序的开发提供了综合、广泛的基础性支持的 Java 平台。 Spring 帮助开发者解决基础性的问题,使开发者专注编写业务代码。 二、Spring Freamework 有哪些功能? IOC: 控制反转AOP: 面…...
NC单链表的排序
系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 描述 给定一个节点…...
阿里云部署open-webui实现openai代理服务(持续更新)
一、展示 xiezhaoxuan.top:8080 二、 环境准备 1. 阿里云服务器,ubuntu22系统 2. http代理(可访问外网) 3. openai API Key 三、实际操作记录(阿里云服务器端) 1. 根据官方文档安装open-webui服务端(看完这节再操作): 🚀 Getting Started | Open WebUI 1. 如果服务器配置比较…...
Vue3简介和快速体验
文章目录 前言1. Vue3介绍2. Vue3快速体验(非工程化方式) 前言 本次主要用VScode开发代码,vscode的安装很简单,不会的可以查询一下网上的资料 1. Vue3介绍 Vue (发音为 /vjuː/,类似 view) 是一款用于构建用户界面的 JavaScript 框架。它基于…...
LeetCode98 验证二叉搜索树
前言 题目: 98. 验证二叉搜索树 文档: 代码随想录——验证二叉搜索树 编程语言: C 解题状态: 对中序遍历理解不到位 思路 了解了中序遍历会返回一个有序数组后,本题就可以迎刃而解。只需要判断,返回的数组…...
llama的神经网络结构;llama的神经网络结构中没有MLP吗;nanogpt的神经网络结构;残差是什么;残差连接:主要梯度消失
目录 解释代码 潜在问题和修正 结论 llama的神经网络结构 神经网络结构概述 举例说明 llama的神经网络结构中没有MLP吗 nanogpt的神经网络结构 1. 词嵌入层(Embedding Layer) 2. Transformer编码器层(Transformer Encoder Layer) 3. 层归一化(Layer Normalizat…...
函数的常量引用入参const saclass sdf,可否传入一个指向saclass对象的指针 shared_ptr<saclass>
不可以直接将一个指向 saclass 对象的 shared_ptr<saclass> 作为参数直接传入一个期望 const saclass& 类型参数的函数。原因是类型不匹配:shared_ptr<saclass> 是一个智能指针类型,它封装了对 saclass 对象的指针,并提供了一…...
数据库:SQL——数据库操作的核心语言
数据库:SQL——数据库操作的核心语言 SQL(结构化查询语言)是关系型数据库管理系统中的标准语言,广泛用于数据的定义、操作、控制和查询。SQL 包含多个子语言,分别用于不同的数据库操作任务,包括数据定义&a…...
Unity + HybridCLR 从零开始
官方文档开始学习,快速上手 | HybridCLR (code-philosophy.com)是官方文档链接 1.建议使用2019.4.40、2020.3.26、 2021.3.0、2022.3.0 中任一版本至于其他2019-2022LTS版本可能出现打包失败情况 2. Windows Win下需要安装visual studio 2019或更高版本。安装时至少要包含 使…...
C++小总结
C小总结 接口 对外暴露头文件中,只需要声明接口函数即可,其他不暴露的函数不需要进行声明。接口的参数使用指针形式比较好,因为外部使用时可以对实参进行创建和析构,如果非接口函数使用new开辟,不太好进行析构。在使…...
从快到慢学习Git指令
Git是现在最流行的版本控制工具之一。无论是在开源社区还是企业软件开发中,Git都扮演着至关重要的角色。本文将根据不同的需求,分别提供快速上手和深入学习Git的指南。 如果你只想下载代码 如果你只是想下载GitHub或其他代码仓库的代码,那你只需要了解以下两个命令: git clo…...
传奇游戏发布渠道
传奇游戏发布渠道 回答:游戏发布平台|手机游戏发布平台 传奇游戏发布渠道作为游戏开发商直接控制的信息传播途径,其安全性自然有着较高的保障。首先,渠道通常会采用先进的加密技术和安全协议来保护数据传输过程中的安全,防止信息…...
如何有效阅读科研论文【方法论】
如何读论文【论文精读1】_哔哩哔哩_bilibili 如何有效阅读科研论文 科研论文是了解学术领域最新研究成果和技术发展的重要途径。有效地阅读论文不仅能够帮助我们掌握前沿知识,还能提升自己的研究能力。本文将介绍一种系统的论文阅读方法,并通过具体的步…...
【揭秘】层层加码,竟能加速渠道营销数字化?-eBest
国潮饮料品牌在eBest RTM系统的支持下,已经将数字化贯彻到每一个销售环节,且看eBest如何通过“层层加码”,进一步加速该饮料品牌渠道数字化进程,实现弯道超车? “一箱四码”垛码 五码实现渠道数字化 为提高营销和数字…...
基于WAMP环境的简单用户登录系统实现(v3版)(持续迭代)
目录 版本说明 实现环境: 流程逻辑框图: 数据库连接 登录页面:login.html 登录处理实现:doLogin.php 用户欢迎页面:welcome.php 密码修改页面:change_password.html 修改处理:doChangePa…...
大语言模型与多模态大模型loss计算
文章目录 前言一、大语言模型loss计算1、loss计算代码解读2、构建模型输入内容与label标签3、input_ids与labels格式 二、多模态大模型loss计算方法1、多模态loss计算代码解读2、多模态输入内容2、大语言模型输入内容3、图像embending如何嵌入文本embeding 前言 如果看了我前面…...
线上研讨会 | CATIA助力AI提升汽车造型设计
报名链接: 2024探索之旅第二季...
Unity新输入系统 之 InputAction(输入配置文件最基本的单位)
本文仅作笔记学习和分享,不用做任何商业用途 本文包括但不限于unity官方手册,unity唐老狮等教程知识,如有不足还请斧正 首先你应该了解新输入系统的构成结构:Unity新输入系统结构概览-CSDN博客 Input System - Unity 手册 1.In…...
【限时解密】Midjourney Anthotype印相黄金比例:1:1.618构图×植物色素衰减曲线=不可复制的复古质感
更多请点击: https://intelliparadigm.com 第一章:Midjourney Anthotype印相的本质溯源与时代语境 Anthotype(植物感光印相)是一种源于19世纪的古老摄影工艺,利用植物提取物(如甜菜根、黑醋栗或蒲公英花汁…...
AI大模型选型生死线(2026企业采购决策白皮书):API延迟、幻觉率、合规审计通过率三维淘汰制解析
更多请点击: https://intelliparadigm.com 第一章:AI大模型选型生死线:2026企业采购决策范式重构 当算力成本下降47%、推理延迟压缩至83ms、私有化微调周期缩短至4.2小时,企业不再比拼“谁用了大模型”,而是在验证“谁…...
AI写专著的高效秘诀:4款AI工具,20万字专著轻松到手
首次尝试写学术专著的挑战与 AI 工具解决方案 对于首次尝试写学术专著的研究者来说,撰写过程就像是一场“摸着石头过河”的探险,充满了许多未知的挑战。首先是在选题时容易迷失方向,不知道如何在“具有研究价值”和“可行性”之间找到一个合…...
SteamAutoCrack:3步自动化破解Steam游戏的终极指南
SteamAutoCrack:3步自动化破解Steam游戏的终极指南 【免费下载链接】Steam-auto-crack Steam Game Automatic Cracker 项目地址: https://gitcode.com/gh_mirrors/st/Steam-auto-crack 你是否厌倦了每次想玩Steam游戏都要联网验证?是否希望合法购…...
Visual C++运行库全家桶:一站式解决Windows软件兼容性问题的终极方案
Visual C运行库全家桶:一站式解决Windows软件兼容性问题的终极方案 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 还在为"应用程序无法启动&qu…...
SAP销售单文本处理保姆级教程:用SAVE_TEXT和READ_TEXT BAPI搞定抬头备注
SAP销售单文本处理实战指南:从业务需求到代码实现的完整闭环 销售订单处理过程中,文本信息承载着关键业务逻辑——加急标识、特殊包装要求、客户备注等非结构化数据往往决定了后续物流和财务流程的准确性。当这些信息在流转中丢失时,轻则导致…...
别再只会用t检验了!用Python的statsmodels库做单因素方差分析,5分钟搞定A/B测试结果解读
用Python实现单因素方差分析:A/B测试中的多组比较实战指南 当产品经理同时测试三种新按钮颜色对转化率的影响时,连续做了三次t检验对比各组差异——这个在互联网公司会议室里反复上演的场景,实际上犯了一个统计学上的典型错误。就像用三把尺…...
本地待办清单的革命:为什么My-TODOs让数据隐私与高效任务管理完美融合?
本地待办清单的革命:为什么My-TODOs让数据隐私与高效任务管理完美融合? 【免费下载链接】My-TODOs A cross-platform desktop To-Do list. 跨平台桌面待办小工具 项目地址: https://gitcode.com/gh_mirrors/my/My-TODOs 在云端存储成为主流的今天…...
现代化WPF可视化设计引擎:从XAML代码到拖拽式开发的效率革命
现代化WPF可视化设计引擎:从XAML代码到拖拽式开发的效率革命 【免费下载链接】WpfDesigner The WPF Designer from SharpDevelop 项目地址: https://gitcode.com/gh_mirrors/wp/WpfDesigner 在WPF应用程序开发中,手动编写XAML代码进行界面布局是每…...
基于LLM智能体的自动化研究工具autoresearch:从部署到实战调优
1. 项目概述:当AI成为你的全职研究助理如果你也曾在深夜面对海量文献、数据报告和网络信息感到无从下手,或者为一个研究课题的初步资料搜集耗费数天时间却收效甚微,那么darks0l/autoresearch这个项目可能会让你眼前一亮。简单来说,…...
