Spring Boot集成sse实现chatgpt流式交互

 ​

博客主页:     南来_北往

系列专栏:Spring Boot实战


什么是sse?

SSE可以指代两种不同的概念:一是指“服务器发送事件”(Server-Sent Events),另一种是指英特尔的“因特网数据流单指令序列扩展”(Streaming SIMD Extensions)。下面将逐一解释这两种概念:

  1. 服务器发送事件
    • SSE是一种基于HTTP协议的服务器向客户端实时推送数据的机制。利用HTTP的长连接特性,服务器可以不断地向客户端发送数据,从而实现实时通信。
    • SSE与传统的HTTP请求响应模型不同,它允许服务器主动向客户端发送消息,无需客户端发起请求。这一机制适用于实时更新、在线聊天、股票价格提醒等场景。
    • SSE与WebSocket在某些功能上相似,但更轻量级和简单。相比于WebSocket的双向通信,SSE仅支持单向(从服务器到客户端)的消息传递,因此在一些只需要服务器推送的场景下更为适用。
  2. 因特网数据流单指令序列扩展
    • SSE是英特尔在其计算机芯片Pentium III中引入的一种指令集,用于提升多媒体和图形应用的性能。该技术在保持MMX指令的同时,增加了70条新指令,加快浮点运算并提高内存使用效率。
    • SSE通过提供新的寄存器、数据类型和指令,结合单指令多数据(SIMD)技术,显著提高了应用程序的效率。这种提升对3D几何运算、图形处理、视频编辑等领域尤为明显。
    • SSE包含8个128位的通用寄存器(XMM0~XMM7),支持紧缩的128位浮点数操作。这使得程序设计人员可以开发混合使用SSE和MMX指令的算法。

综上所述,SSE既可以指服务器向客户端实时推送数据的“服务器发送事件”技术,也可以指英特尔为提升多媒体处理性能而开发的“因特网数据流单指令序列扩展”指令集。这两种技术虽然应用领域不同,但都极大地提升了相应领域的效率和体验。

SSE和WebSocket 

SSE(Server-Sent Events)和WebSocket都是实现实时通信的重要技术,但它们在设计理念、实现方式和适用场景上存在显著差异

SSE是一种基于HTTP协议的单向通信技术,允许服务器主动向客户端推送数据。相比之下,WebSocket提供了一个全双工通信通道,支持客户端和服务器之间的双向数据交换。下面从多个角度详细对比这两种技术:

  1. 技术原理与实现方式
    • SSE
      • SSE通过HTTP协议工作,利用持久连接实现服务器向客户端的数据推送。
      • 客户端使用EventSource接口监听服务器发送的消息,无需重复请求。
      • 每次数据传递完毕,连接暂时关闭,需要时重新连接。
    • WebSocket
      • WebSocket基于独立的TCP连接,并使用自定义的协议进行双向通信。
      • 一旦建立连接,该连接一直保持打开状态,直到手动关闭。
      • 支持文本和二进制数据的传输。
  2. 应用场景与优势
    • SSE
      • 适用于只需要服务器向客户端实时推送数据的场景,如新闻更新、股票行情等。
      • 优势在于简单易用、依赖标准HTTP协议,浏览器兼容性好。
      • 局限性在于仅支持单向通信。
    • WebSocket
      • 适用于需要快速、双向交互的应用,如在线游戏、实时聊天等。
      • 优势在于支持全双工通信,低延迟。
      • 局限性在于实现较为复杂,需特定服务器支持。
  3. 性能特征与复杂性
    • SSE
      • 协议简单,易于实现,自动支持断线重连。
      • 只能发送文本数据,无法发送二进制数据。
    • WebSocket
      • 支持更复杂的应用场景,可以发送任何类型的数据。
      • 实现复杂,可能需要额外的服务器资源和代码来处理连接和消息。
  4. 调试与测试工具
    • SSE
      • 可以通过设置HTTP类型项目和使用时间线视图监控数据流。
      • Apifox等工具提供便利的调试支持。
    • WebSocket
      • 使用专门接口配置,发送和接收消息,查看响应结果。
      • 同样可以利用Apifox等工具进行有效的调试。

综上所述,如果应用只需服务器单向推送数据且要求简单实现,SSE是理想选择;而对于需要高度互动、双向数据传输的场景,WebSocket则更具优势。在选择实时通信技术时,应根据具体需求来决定采用SSE还是WebSocket,从而更好地满足项目需求和提升用户体验。

代码工程

实现chatgpt流式交互 

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>springboot-demo</artifactId><groupId>com.et</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>sse</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- java基础工具包 --><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.8.9</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies>
</project>

 controller

package com.et.sse.controller;import cn.hutool.core.util.IdUtil;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;import java.io.IOException;
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;@Controller
@RequestMapping("/chat")
public class ChatController {Map<String, String> msgMap = new ConcurrentHashMap<>();/*** send meaaage* @param msg* @return*/@ResponseBody@PostMapping("/sendMsg")public String sendMsg(String msg) {String msgId = IdUtil.simpleUUID();msgMap.put(msgId, msg);return msgId;}/*** conversation* @param msgId mapper with sendmsg* @return*/@GetMapping(value = "/conversation/{msgId}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public SseEmitter conversation(@PathVariable("msgId") String msgId) {SseEmitter emitter = new SseEmitter();String msg = msgMap.remove(msgId);//mock chatgpt responsenew Thread(() -> {try {for (int i = 0; i < 10; i++) {ChatMessage  chatMessage =  new ChatMessage("test", new String(i+""));emitter.send(chatMessage);Thread.sleep(1000);}emitter.send(SseEmitter.event().name("stop").data(""));emitter.complete(); // close connection} catch (IOException | InterruptedException e) {emitter.completeWithError(e); // error finish}}).start();return emitter;}
}

chat.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>ChatGpt test</title><link rel="stylesheet" href="lib/element-ui/index.css"><style type="text/css">body{background-color:white;}#outputCard{height: 300px;overflow:auto;}#inputCard{height: 100px;overflow:auto;}#outputBody{line-height:30px;}.cursor-img{height:24px;vertical-align: text-bottom;}</style><script src="lib/jquery/jquery-3.6.0.min.js"></script><script src="lib/vue/vue.min.js"></script><script src="lib/element-ui/index.js"></script>
</head>
<body>
<h1 align="center">ChatGpt Test</h1><div id="chatWindow"><el-row id="outputArea"><el-card id="inputCard"><div id="inputTxt"></div></el-card><el-card id="outputCard"><div id="outputBody"><span id="outputTxt"></span><img v-if="blink" class="cursor-img" src="img/cursor-text-blink.gif" v-show="cursorImgVisible"><img v-if="!blink" class="cursor-img" src="img/cursor-text-black.png" v-show="cursorImgVisible"></div></el-card></el-row><el-row id="inputArea"><el-col :span="21"><el-input id="sendTxt" v-model="input" placeholder="input content" @keyup.native="keyUp"></el-input></el-col><el-col :span="3"><el-button id="sendBtn" type="primary" :disabled="sendBtnDisabled" @click="sendMsg">send</el-button></el-col></el-row>
</div></body>
<script type="text/javascript">var app = new Vue({el: '#chatWindow',data: {input: '',sendBtnDisabled: false,cursorImgVisible: false,blink: true},mounted: function(){},methods: {keyUp: function(event){if(event.keyCode==13){this.sendMsg();}},sendMsg: function(){var that = this;//init$('#outputTxt').html('');var sendTxt = $('#sendTxt').val();$('#inputTxt').html(sendTxt);$('#sendTxt').val('');that.sendBtnDisabled = true;that.cursorImgVisible = true;//send request$.ajax({type: "post",url:"/chat/sendMsg",data:{msg: sendTxt},contentType: 'application/x-www-form-urlencoded',success:function(data){var eventSource = new EventSource('/chat/conversation/'+data)eventSource.addEventListener('open', function(e) {console.log("EventSource连接成功");});var blinkTimeout = null;eventSource.addEventListener("message", function(evt){var data = evt.data;var json = JSON.parse(data);var content = json.content ? json.content : '';content = content.replaceAll('\n','<br/>');console.log(json)var outputTxt = $('#outputTxt');outputTxt.html(outputTxt.html()+content);var outputCard = $('#outputCard');var scrollHeight = outputCard[0].scrollHeight;outputCard.scrollTop(scrollHeight);//cusor blinkthat.blink = false;window.clearTimeout(blinkTimeout);//200ms blink=trueblinkTimeout = window.setTimeout(function(){that.blink = true;}, 200)});eventSource.addEventListener('error', function (e) {console.log("EventSource error");if (e.target.readyState === EventSource.CLOSED) {console.log('Disconnected');} else if (e.target.readyState === EventSource.CONNECTING) {console.log('Connecting...');}});eventSource.addEventListener('stop', e => {console.log('EventSource连接结束');eventSource.close();that.sendBtnDisabled = false;that.cursorImgVisible = false;}, false);},error: function(){that.sendBtnDisabled = false;that.cursorImgVisible = false;}});}}})</script>
</html>

 以上只是一些关键代码,具体根据自己项目进行编码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/390867.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

循环结构(三)——do-while语句

目录 &#x1f341;引言 &#x1f341;一、语句格式 &#x1f680;格式1 &#x1f680;格式2 &#x1f341;二、语句执行过程 &#x1f341;三、实例 &#x1f680;【例1】 &#x1f680;【例2】 &#x1f680;【例3】 &#x1f341;总结 &#x1f341;备注 &am…

Unity获取Animator动画播放完成事件

整理了一些在日常经验中处理动画播放完成事件的方法 方法: 1.Dotween配合异步实现 2.状态机计时方法实现 3.原生动画行为方法实现 方法一&#xff1a;Dotween异步方法 using UnityEngine; using System.Threading.Tasks; using DG.Tweening;public class PlayerAnimAsync : M…

Java——多线程(6/9):线程池、处理Runnable、Callable任务(认识线程池-线程池的工作原理,ThreadPoolExecutor构造器)

目录 认识线程池 介绍 线程池的工作原理 如何创建线程池 介绍 ThreadPoolExecutor构造器 代码实例 线程池的注意事项 线程池处理Runnable任务 ExecutorService的常用方法 代码实例 新任务拒绝策略 线程池处理Callable任务 ExecutorService的常用方法 代码实例…

如何从智联招聘网站快速抓取职位详情?两大技巧揭秘

摘要&#xff1a; 本文将揭秘如何利用Python爬虫技术&#xff0c;高效且合法地从智联招聘网站抓取职位详情信息。通过实战示例&#xff0c;展现两大核心技巧&#xff0c;助你在大数据时代抢占先机&#xff0c;为你的市场分析、人才研究提供强大支持。 一、引言&#xff1a;数据…

排序算法:冒泡排序,golang实现

目录 前言 冒泡排序 代码示例 1. 算法包 2. 冒泡排序代码 3. 模拟排序 4. 运行程序 5. 从大到小排序 循环细节 外层循环 内层循环 总结 循环次数测试 假如 10 条数据进行排序 假如 20 条数据进行排序 假如 30 条数据进行排序 假设 5000 条数据&#xff0c;对比…

荒原之梦考研:专科考研成功的可能性大吗?

专科还是本科不是决定考研能否成功的关键因素&#xff0c;决定考研能否成功的关键因素是自己是否有清晰的规划、是否有足够的专注能力&#xff0c;以及是否能够吃得了考研的“苦”。 首先要有清晰的规划&#xff0c;比如说&#xff0c;不是我们每个人足够努力就都能考上 TOP1 …

很简单的Win10+Win7双系统教程|UEFI篇

前言 前段时间有写过一篇关于Windows10Windows7双系统安装教程&#xff0c;但这个教程为了比较保险&#xff0c;就进入了WinPE维护系统进行操作。 但有很多小伙伴就有点搞不懂了&#xff0c;都不知道WinPE是什么系统&#xff0c;也不知道怎么去解决这个问题。 今天咱们就来讲…

centos7部署智能dns实战应用

主DNS&#xff1a;192.168.101.129 备DNS&#xff1a;192.168.101.128 原理&#xff1a; 一、下载软件 bind-9.17.9.tar.xz的下载地址&#xff1a;https://ftp.isc.org/isc/bind9/9.17.9/bind-9.17.9.tar.xz。更多的bind版本可以从https://ftp.isc.org/isc/bind9/下载。 二&a…

【深入探秘Hadoop生态系统】全面解析各组件及其实际应用

深入探秘Hadoop生态系统&#xff1a;全面解析各组件及其实际应用 引言 在大数据时代&#xff0c;如何高效处理和存储海量数据成为企业面临的重大挑战。根据Gartner的统计&#xff0c;到2025年&#xff0c;全球数据量将达到175泽字节&#xff08;ZB&#xff09;&#xff0c;传…

学习安卓开发遇到的问题

问题1&#xff1a;学习禁用与恢复按钮中&#xff1a; java代码报错&#xff1a;报错代码是 R.id.btn_enable;case R.id.btn_disable;case R.id.btn_test: 代码如下&#xff1a;&#xff08;实现功能在代码后面&#xff09; package com.example.apptest;import static java.…

【时时三省】unity test 测试框架 介绍(适用于C语言进行测试的)

1&#xff0c;关于 unity test 测试框架的介绍 unity test 是 ThrowTheSwitch.org 的一个主要工程。它是专注于为嵌入式工具链而生的C语言单元测试框架。它可以适用于大工程或者小工程都可以。它的核心文件是一个.c文件和两个头文件。 备注&#xff1a; 下载源码地址&#xff…

应急响应-Web3

打开虚拟机之后&#xff0c;运行解题系统&#xff1a; 共有三个问题&#xff01; 攻击者的两个IP地址 首先我们看到机器的桌面上还是存在phpstudy&#xff0c;那就还是先去看看是不是从web层面进行的攻击&#xff0c;上传webshell从而getshell。 利用D盾尝试对phpstudy目录进…

WordPress资源下载类主题 CeoMax-Pro_v7.6绕授权开心版

CeoMax-Pro强大的功能 在不久的将来Ta能实现你一切幻想&#xff01;我们也在为此而不断努力。适用于资源站、下载站、交易站、素材站、源码站、课程站、cms等等等等&#xff0c;Ta 为追求极致的你而生。多风格多样式多类型多行业多功能 源码下载&#xff1a;ceomax-pro7.6.zip…

【系统架构设计师】二十四、安全架构设计理论与实践②

目录 三、系统安全体系架构规划框架 3.1 信息系统安全体系规划 3.2 信息系统安全规划框架 3.2.1 信息系统安全规划依托企业信息化战略规划 3.2.2 信息系统安全规划需要围绕技术安全、管理安全、组织安全考虑 3.2.3 信息系统安全规划以信息系统与信息资源的安全保护为核心…

[环境配置]Pycharm:Failed to start [PowerShell.exe]

解决方法&#xff0c;点Local旁边的 号&#xff0c;点击Command Prompt&#xff0c;即可在Pycharm中呼出控制台。 如果要修改Command Prompt的启动时访问的cmd.exe的路径&#xff0c;可以去Settings→Tools→Terminal中&#xff0c;修改Shell Path实现&#xff0c;改为cmd.exe…

AWS开发人工智能:如何基于云进行开发人工智能AI

随着人工智能技术的飞速发展&#xff0c;企业对高效、易用的AI服务需求日益增长。Amazon Bedrock是AWS推出的一项创新服务&#xff0c;旨在为企业提供一个简单、安全的平台&#xff0c;以访问和集成先进的基础模型。本文中九河云将详细介绍Amazon Bedrock的功能特点以及其收费方…

117页PPT埃森哲-物流行业信息化整体规划方案

一、埃森哲-物流行业信息化整体规划方案 资料下载方式&#xff0c;请看每张图片右下角信息 埃森哲在物流行业信息化整体规划项目中的核心内容&#xff0c;旨在帮助物流企业通过信息技术的应用实现业务流程的优化、运营效率的提升以及市场竞争力的增强。以下是埃森哲在此类项目…

C语言指针(1)

目录 一、内存和地址 1、生活中的例子 2、内存的关系 二、指针变量和地址 1、&符号&#xff0c;%p占位符 2、一个简单的指针代码。 3、理解指针 4、解引用操作符 5、指针变量的大小。 三、指针变量类型的意义 1、指针解引用的作用 2、指针指针 3、指针-指针 4…

Python初学者必须掌握的基础知识点

Python初学者必须掌握的基础知识点包括数据类型与变量、控制结构&#xff08;条件语句和循环语句&#xff09;、基本数据结构&#xff08;列表、元组、字典、集合&#xff09;、函数与模块、以及字符串处理等。以下是对这些基础知识点及其对应代码的详细介绍&#xff1a; 1. …

利用Llama 3 API实现盈利:细节解析

随着人工智能技术的快速发展,基于大模型的服务成为了众多初创企业关注的焦点。Llama 3 API作为一种强大的语言模型接口,为小型公司提供了利用先进AI技术的机会。本文将探讨这些小公司如何通过Llama 3 API实现盈利,并分析其中的关键因素。 一、Llama 3 API性能概览 批处理输…