JAVA后端调用OpenAI接口 实现打字机效果(SSE)

SSE

SSE(Server-Sent Events,服务器发送事件)是一种基于HTTP协议的通信技术,它允许服务器持续地将数据推送给客户端,而无需客户端发起请求。这种通信方式通常用于实时性要求较高的场景,如实时更新、通知、或者数据流式传输。
SSE与传统的Ajax轮询或长轮询相比,具有更低的延迟、更高的效率,并且更易于实现。它建立在HTTP协议之上,利用HTTP/1.1的持久连接,允许服务器在连接建立后持续地向客户端发送数据,客户端通过监听一个HTTP连接来接收这些数据。
在Web开发中,服务器通常会使用特殊的HTTP响应头(如"Content-Type: text/event-stream")来指示客户端这是一个SSE流,并且按照一定的格式发送事件数据给客户端。客户端则可以使用JavaScript中的EventSource对象来接收并处理这些事件,从而实现实时的数据更新。

SseEmitter

SseEmitter是Spring框架中的一个类,专门用于Java。SSE代表服务器发送事件,是一种使服务器能够通过HTTP向Web客户端推送数据更新的技术。SseEmitter是在Spring应用程序中实现SSE服务器支持的便捷方式。
使用SseEmitter,您可以在Spring应用程序中创建一个端点,客户端可以连接到该端点,服务器可以通过此连接向客户端推送事件。这对于实时更新非常有用,例如显示实时通知、进度更新或流式传输数据。

实现:

  • OpenAI支持Stream流格式接收

在这里插入图片描述

接口连续的数据读取

官网示例

在这里插入图片描述

{"id":"chatcmpl-123","object":"chat.completion.chunk","created":1694268190,"model":"gpt-3.5-turbo-0125", "system_fingerprint": "fp_44709d6fcb", "choices":[{"index":0,"delta":{"role":"assistant","content":""},"logprobs":null,"finish_reason":null}]}{"id":"chatcmpl-123","object":"chat.completion.chunk","created":1694268190,"model":"gpt-3.5-turbo-0125", "system_fingerprint": "fp_44709d6fcb", "choices":[{"index":0,"delta":{"content":"Hello"},"logprobs":null,"finish_reason":null}]}
...
{"id":"chatcmpl-123","object":"chat.completion.chunk","created":1694268190,"model":"gpt-3.5-turbo-0125", "system_fingerprint": "fp_44709d6fcb", "choices":[{"index":0,"delta":{},"logprobs":null,"finish_reason":"stop"}]}
demo
  private static final String API_KEY = "********************";private static final Pattern contentPattern = Pattern.compile("\"content\":\"(.*?)\"}");private static final String MODEL_ENGINE = "gpt-3.5-turbo";public static void test() throws InterruptedException, IOException {//params 的入参封装 这里省略 参考上面图片 或去官网 需要stream形式请求HttpRequest httpRequest = HttpRequest.post("https://api.openai.com/v1/chat/completions").header("Content-Type", "application/json").header("Authorization", "Bearer " + API_KEY).body(JSONUtil.toJsonStr(params));//TODO 代理 到shadowsocks httpRequest.setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890)));HttpResponse execute = httpRequest.execute();InputStream inputStream = execute.bodyStream();BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));String line;while ((line = bufferedReader.readLine()) != null) {if (StringUtils.hasLength(line)) {System.out.println(line);Matcher matcher = contentPattern.matcher(line);if (matcher.find()) {String content = matcher.group(1);System.out.println(content);}}}
}

SSE发送

demo

ChatController

 @Autowiredprivate ChatService chatService;@GetMapping("/test")public SseEmitter test(String question) {SseEmitter sseEmitter = new SseEmitter();chatService.question(question, sseEmitter);return sseEmitter;}

ChatService

  private static final String API_KEY = "********************";private static final Pattern contentPattern = Pattern.compile("\"content\":\"(.*?)\"}");@Asyncpublic void question(String question, SseEmitter sseEmitter) {try {// 构建请求参数String params = "{\"model\":\"gpt-3.5-turbo\",\"messages\":[{\"role\":\"user\",\"content\":\"" + question + "\"}],\"stream\":true}";// 发起 HTTP 请求HttpRequest httpRequest = HttpRequest.post("https://api.openai.com/v1/chat/completions").header("Content-Type", "application/json").header("Authorization", "Bearer " + API_KEY).body(JSONUtil.toJsonStr(params)).setProxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("127.0.0.1", 7890)));// 执行 HTTP 请求HttpResponse execute = httpRequest.execute();// 处理响应流try (InputStream inputStream = execute.bodyStream();BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {String line;while ((line = bufferedReader.readLine()) != null) {if (StringUtils.hasLength(line)) {// 输出响应内容System.out.println(line);// 提取内容Matcher matcher = contentPattern.matcher(line);if (matcher.find()) {String content = matcher.group(1);System.out.println(content);// 发送 SSE 事件 (模拟延迟)Thread.sleep(1000);sseEmitter.send(SseEmitter.event().name("answer").data("{" + content + "}"));}}}}} catch (IOException | InterruptedException e) {// 异常处理throw new RuntimeException(e);} finally {// 完成 SSE 连接sseEmitter.complete();}}

测试

在这里插入图片描述

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

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

相关文章

Python Flask框架 -- 模版继承

一个网站中,大部分网页的模块是重复的,比如顶部的导航栏,底部的备案信息。如果在每个页面中都重复的去写这些代码,会让项目变得臃肿,提高后期维护成本。比较好的做法是,通过模板继承,把一些重复…

STM32-Flash闪存

简介 STM32F1系列的FLASH包含程序存储器、系统存储器和选项字节三个部分,通过闪存存储器接口(外设)可以对程序存储器和选项字节进行擦除和编程。 读写Flash的用途 1.利用程序存储器的剩余空间来保存掉电不丢失的用户数据。 2.通过在程序中…

CVE-2024-24112 XMall后台管理系统 SQL 注入漏洞分析

------作者本科毕业设计项目 基于 Spring Boot Vue 开发而成...... [Affected Component] /item/list /item/listSearch /sys/log /order/list /member/list (need time-based blind injection) /member/list/remove 项目下载地址 Exrick/xmall: 基于SOA架构的分布式…

Django日志(一)

一、概念与配置 1.1、概述 日志是程序员经常在代码中使用快速和方便的调试工具。它在调试方面比print更加的优雅和灵活 而且日志记录对于调试很有用,可以提供更多,更好的结构化,有关应用程序的状态和运行状况的信息 Django框架的日志通过python内置的logging模块实现的,可…

Elasticsearch:让你的 Elasticsearch 索引与 Python 和 Google Cloud Platform 功能保持同步

作者:来自 Elastic Garson Elasticsearch 内的索引 (index) 是你可以将数据存储在文档中的位置。 在使用索引时,如果你使用的是动态数据集,数据可能会很快变旧。 为了避免此问题,你可以创建一个 Python 脚本来更新索引&#xff0…

每日OJ题_牛客WY3 小易的升级之路(IO型OJ)

目录 牛客WY3 小易的升级之路 解析代码 牛客WY3 小易的升级之路 小易的升级之路_牛客题霸_牛客网 解析代码 #include <iostream> #include <vector> using namespace std;int getVal(int a, int b) {if (a > b)swap(a, b);for (int i a; i > 1; --i){if…

科研绘图一:箱线图(添加贝赛尔曲线)

R语言绘图系列—箱线图贝赛尔曲线 &#xff08;一&#xff09;: 科研绘图一&#xff1a;箱线图&#xff08;添加贝赛尔曲线&#xff09; 文章目录 R语言绘图系列---箱线图贝赛尔曲线&#xff08;一&#xff09;: 科研绘图一&#xff1a;箱线图&#xff08;添加贝赛尔曲线&…

【MySQL】MySQL用户管理

文章目录 一、用户1.用户信息2.创建用户3.删除用户4.修改用户密码 二、数据库的权限1.给用户授权2.回收权限 一、用户 如果我们只能使用root用户&#xff0c;这样存在安全隐患。这时&#xff0c;就需要使用MySQL的用户管理。 1.用户信息 我们安装mysql之后&#xff0c;会自动…

DC-1靶场

一.环境搭建 下载地址 http://www.five86.com/downloads/DC-1.zip 把桥接设置为nat模式&#xff0c;打开靶机的时候会提示几个错误&#xff0c;点击重试即可 启动靶机&#xff0c;如下图所示即可 二.开始打靶 1.信息收集 arp-scan -l 扫描跟kali&#xff08;攻击机&…

MySQL基础(DDL,DML,DQL)

目录 一DDL 1.1数据库操作 1.1.1查询所有数据库&#xff1a; 1.1.2创建数据库 1.1.3 使用数据库 1.1.4 删除数据库 1.2表操作 1.2.1表操作 1.2.1.1创建表 1.2.1.1.1约束 1.2.1.1.2 数据类型 1.2.1.1.2.1 数值类型 1.2.1.1.2.2 字符串类型 1.2.1.1.2.3日期类型 1.…

Linux:执行命令的命令eval与Bash解析命令的方式

相关阅读 Linuxhttps://blog.csdn.net/weixin_45791458/category_12234591.html?spm1001.2014.3001.5482 eval命令用于接收参数&#xff0c;并将这些参数作为一行命令执行&#xff0c;这也许会使人困惑&#xff0c;为什么我不能直接执行命令而需要使用eval命令间接执行呢&…

【应用笔记】LAT1305+使用STM32+TT类型IO的注意事项

1. 概述 在 STM32 系列 MCU 中&#xff0c; 除了一些特殊管脚外&#xff0c;绝大多数管脚都可以分类为 FT (兼容5V 信号)或 TT&#xff08;兼容 3V3 信号&#xff09;类型的 IO&#xff0c;由于 MCU 内部设计的不同&#xff0c; TT IO 相比 5V IO 有更多的限制&#xff0c;下面…

【回溯专题part1】【蓝桥杯备考训练】:n-皇后问题、木棒、飞机降落【已更新完成】

目录 1、n-皇后问题&#xff08;回溯模板&#xff09; 2、木棒&#xff08;《算法竞赛进阶指南》、UVA307&#xff09; 3、飞机降落&#xff08;第十四届蓝桥杯省赛C B组&#xff09; 1、n-皇后问题&#xff08;回溯模板&#xff09; n皇后问题是指将 n 个皇后放在 nn 的国…

MySQL数据库索引

目录 一.索引的基本内容 1.索引的定义 2.索引的作用 &#xff08;1&#xff09;设置了合适的索引之后&#xff0c;数据库利用各种快速定位技术&#xff0c;能够大大加快查询速度&#xff0c;这是创建索引的最主要的原因。 &#xff08;2&#xff09;当表很大或查询涉及到多…

鸿蒙一次开发,多端部署(四)工程管理

DevEco Studio的基本使用&#xff0c;请参考DevEco Studio使用指南。本章主要介绍如何使用DevEco Studio进行多设备应用开发。 说明&#xff1a; 本章的内容基于DevEco Studio 3.1.1 Release版本进行介绍&#xff0c;如您使用DevEco Studio其它版本&#xff0c;可能存在文档与产…

python --- 练习题3

目录 1、猜数字游戏&#xff08;使用random模块完成&#xff09; &#xff1a;继上期题目&#xff0c;附加 2、用户登录注册案例 3、求50~150之间的质数是那些&#xff1f; 4、打印输出标准水仙花数&#xff0c;输出这些水仙花数 5、验证:任意一个大于9的整数减去它的各位…

行业模板|DataEase制造行业大屏模板推荐

DataEase开源数据可视化分析平台于2022年6月发布模板市场&#xff08;https://templates-de.fit2cloud.com&#xff09;&#xff0c;并于2024年1月新增适用于DataEase v2版本的模板分类。模板市场旨在为DataEase用户提供专业、美观、拿来即用的大屏模板&#xff0c;方便用户根据…

机器学习_正则化

文章目录 代价函数 如果我们有非常多的特征&#xff0c;我们通过学习得到的假设可能能够非常好地适应训练集&#xff08;代价函数可能几乎为 0&#xff09;&#xff0c;但是可能会不能推广到新的数据。 下图是一个回归问题的例子&#xff1a; 第一个模型是一个线性模型&#xf…

思科网络中DHCP协议的配置

一、什么是DHCP&#xff1f;DHCP有什么作用&#xff1f; &#xff08;1&#xff09;DHCP&#xff08;Dynamic Host Configuration Protocol&#xff09;是一种网络协议&#xff0c;用于在局域网中自动分配IP地址和其他网络配置信息给计算机设备。我们电脑连接WiFi的时一般就是…

鸿蒙一次开发,多端部署(三)应用UX设计原则

设计原则 当为多种不同的设备开发应用时&#xff0c;有如下设计原则&#xff1a; 差异性 充分了解所要支持的设备&#xff0c;包括屏幕尺寸、交互方式、使用场景、用户人群等&#xff0c;对设备的特性进行针对性的设计。 一致性 除了要考虑每个设备的特性外&#xff0c;还…