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

 @Autowired
 private 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\":\"(.*?)\"}");
 	@Async
    public 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();
        }
    }

测试

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux:搭建ntp服务器

我准备两个centos7服务器 一个为主服务器连接着外网,并且搭建了ntp服务给其他主机同步 另外一个没有连接外网,通过第一台设备去同步时间 首先两个服务器都要安装ntp软件 yum -y install ntp 再把他俩的时间都改成别的 左侧的是主服务器,主…

【Docker篇】自定义Dockerfile的操作

文章目录 🍔镜像结构🛸什么是Dockerfile⭐基于Ubuntu镜像构建一个新镜像,运行一个java项目🔎使用 java:8-alpine 🍔镜像结构 镜像是将应用程序及其需要的系统函数库、环境、配置、依赖打包而成。 我们以MySQL为例&am…

JVM中对象创建过程

在JVM中对象的创建,我们从一个new指令开始: 这个过程大概图示如下: 虚拟机收到new指令触发。 类加载检查:如果类没有被类加载器加载,则执行类加载流程(将class信息加载到JVM的运行时数据区的过程&#xff…

KiCad 从原理图创建或者导出原理图符号

KiCad 从原理图创建或者导出原理图符号 原理图中,在下那个要导出的符号上点击右键-》属性-》编辑符号 在符号编辑中选择:文件-》导出符号 加微信:jiyuyun18, 交流电子技术 留言:CSND 电子技术交流群,加入电子微信电…

如何利用生成式AI进行品牌定位调研?

在激烈的市场竞争中,一个明确的品牌定位能够帮助企业突出其独特性,吸引并保留目标消费者。品牌定位调研是企业了解自身、竞争对手以及市场需求的重要手段,是制定有效市场策略的基础。本文将详细介绍如何进行品牌定位调研,包括调研…

PyTorch学习笔记之激活函数篇(四)

4、 Leaky ReLU 函数 4.1 公式 Leaky ReLU函数的公式&#xff1a; f ( x ) { x , x > 0 λ x , x < 0 , λ ∈ ( 0 , 1 ) f(x) \begin{cases} x&,x>0 \\ \lambda x&,x<0,\lambda \in(0,1) \end{cases} f(x){xλx​,x>0,x<0,λ∈(0,1)​ Leakly R…

MySQL连接数不足导致服务异常GetConnectionTimeoutException

文章目录 场景复现解决方案一、调整连接数二、优化程序 场景复现 已经上线正常运行的项目突然很多功能无法使用&#xff0c;查看程序日志发现MySQL报错&#xff0c;异常信息: Could not open JDBC Connection for transaction; nested exception is com.alibaba.druid.pool.Ge…

分布式(计算机算法)

目录 分布式计算 分布式​编辑 分布式和集群 分布式和集群的应用场景 分布式应用场景 集群应用场景 哪种技术更优、更快、更好呢 性能 稳定性 以下概念来源于百度百科 分布式计算 分布式计算是近年提出的一种新的计算方式。所谓分布式计算就是在两个或多个软件互相共享信息…

【ArcGISProSDK】添加异步执行时进度窗口

运行结果 代码 protected override async Task InitializeAsync(){using (ProgressorSource progressorSource new ProgressorSource("初始化...")){await QueuedTask.Run(delegate{MessageBox.Show(licenseExpirationDate.ToString());}, progressorSource.Progres…

介绍一下Spring的AOP

一、问题解析 典型回答 AOP(Aspect-Oriented Programming)&#xff0c;即面向切面编程&#xff0c;用人话说就是把公共的逻辑抽出来&#xff0c;让开发者可以更专注于业务逻辑开发。 和IOC一样&#xff0c;AOP也指的是一种思想。AOP思想是OOP&#xff08;Object-Oriented Prog…

【Java刷题篇】滑动窗口

文章目录 &#x1f4c3;滑动窗口&#x1f4dc;基本概念&#x1f4dc;核心思路 ✍最大连续1的个数 III✍水果成篮 &#x1f4c3;滑动窗口 &#x1f4dc;基本概念 滑动窗口是一种基于双指针的一种思想&#xff0c;两个指针指向的元素之间形成一个窗口。 分类&#xff1a;窗口有…

C++语言现在还有人学吗?

在当今信息爆炸的时代&#xff0c;计算机编程语言繁多&#xff0c;涌现了许多新兴的编程语言&#xff0c;如Python、JavaScript等。针对C编程语言是否还有人学的问题&#xff0c;我个人认为可以从以下几个方面进行讨论。 首先&#xff0c;C诞生于1979年&#xff0c;起初是为了开…

AI预测福彩3D第12弹【2024年3月18日预测--第3套算法重新开始计算第1次测试】

前面的第2套算法感觉效果比较差&#xff0c;与真实结果差距较大&#xff0c;因此&#xff0c;果断放弃第2套算法&#xff0c;再次进行了改进后&#xff0c;咱们从今天开始测试第3套算法。第3套算法加入了012路的权重。废话不多说了&#xff0c;直接上结果吧~ 最终&#xff0c;经…

数据驱动校园管理:山海鲸可视化软件看板搭建记

随着信息化时代的到来&#xff0c;校园管理也逐渐向数字化、可视化转型。作为一名数据分析师&#xff0c;我有幸参与了使用山海鲸可视化软件搭建校园管理可视化看板的项目&#xff0c;山海鲸可视化软件是近些年新崛起的一款可视化产品&#xff0c;支持免费可视化编辑、私有化部…

网络学习:IPV6地址详解

目录 前言&#xff1a; 一、IPV6的由来 二、什么是IPV6地址&#xff1f; IPV6地址结构&#xff1a; 前言&#xff1a; IPV6&#xff08;Internet Protocol Version 6&#xff09;是网络层协议的第二代标准协议&#xff0c;也被称为IPng&#xff08;IP Next Generation&…

SolidWorks教育版 科研版 商业版区别

SolidWorks是一款功能强大的三维CAD软件&#xff0c;广泛应用于机械设计、工业设计、建筑设计等领域。SolidWorks提供了多个版本&#xff0c;以满足不同用户的需求。本文将详细介绍SolidWorks教育版、科研版与商业版的区别&#xff0c;帮助你更好地选择适合自己的版本。 首先&…

sentinel熔断降级

熔断降级 Slot 责任链上的最后一环&#xff1a;熔断降级 DegradeSlot,熔断降级作为保护系统的一种强大手段,可以根据慢调用、异常比例和异常数进行熔断,并自定义持续时间以实现系统保护 规则配置 规则类中属性解析 与控制面板对应 // 其中资源名称在 AbstractRule 里。 pu…

计算机一级word 文字处理理论+实操试题

计算机一级word 文字处理理论实操试题 单选题&#xff1a; 1、在Word编辑状态下&#xff0c;要将另一文档的内容全部添加在当前文档的当前光标处&#xff0c;应选择的操作是依次单击______。 A.“文件”选项卡和“打开”项 B.“文件”选项卡和“新建”项 C.“插入”选项卡…

windows server 下的mysql 8.0.28修改数据库目录

1. 查看当前数据库存储位置 show global variables like %datadir%; 默认是&#xff1a;C:\ProgramData\MySQL\MySQL Server 8.0\Data 2. 修改 C:\ProgramData\MySQL\MySQL Server 8.0\my.ini配置文件。如下&#xff1a; datadirD:/ProgramData/MySQL/MySQL Server 8.0/Dat…

【HyperLips:】数字人——控制嘴唇 项目源码python实现

最近受到商汤“复活”汤晓鸥的视频刺激&#xff0c;大大的amazing&#xff01;没看过的小伙伴可以自行百度&#xff0c;看了不研究一下【数字人】技术&#xff0c;都要跟时代脱轨了&#xff0c;那就以HyperLips为开篇吧。 目录 &#x1f34e;&#x1f34e;1.摘要 &#x1f3…