java流式实现chatGPT会话功能

简介: java流式实现chatGPT会话功能

环境

SpringBoot2.x

Maven3.x

JDK1.8


具体步骤

1. 了解相关api信息

首先前往openai api官网OpenAI API,登录自己的账号,然后选择API reference,然后就可以查看相关的模型比如“gpt-3.5-turbo”,还有很多的api。

这里是一些请求体信息:

curl https://api.openai.com/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "gpt-3.5-turbo",
    "messages": [
      {
        "role": "system",
        "content": "You are a helpful assistant."
      },
      {
        "role": "user",
        "content": "Hello!"
      }
    ]
  }'


这里是响应信息:

{
  "id": "chatcmpl-123",
  "object": "chat.completion",
  "created": 1677652288,
  "model": "gpt-3.5-turbo-0125",
  "system_fingerprint": "fp_44709d6fcb",
  "choices": [{
    "index": 0,
    "message": {
      "role": "assistant",
      "content": "\n\nHello there, how may I assist you today?",
    },
    "logprobs": null,
    "finish_reason": "stop"
  }],
  "usage": {
    "prompt_tokens": 9,
    "completion_tokens": 12,
    "total_tokens": 21
  }
}

最重要的是key,如果是新号则去申请,会送一个5美元的key,或者购买一个key。对了,国内的话需要设置代理才能访问。


2. 创建SpringBoot工程

创建工程后添加依赖

       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>

请求参数类:

public class ChatParams {
    // 模型
    private String model = "gpt-3.5-turbo";
 
    // 消息列表,获取上下文携带返回消息
    private List<ChatMessage> messages;
 
    // 采样温度,较高的值(如 0.8)将使输出更加随机,而较低的值(如 0.2)将使其更加集中和确定
    @DecimalMin("0.0")
    @DecimalMax("2.0")
    private Double temperature = 1.0;
 
    // 核心采用,其中模型考虑具有top_p概率质量的令牌的结果。因此,0.1 意味着只考虑包含前 10% 概率质量的结果集
    @DecimalMin("0.0")
    @DecimalMax("1.0")
    private Double top_p = 1.0;
 
    // 结果数,如果需要返回多个结果可以设置 n > 1
    @Min(1)
    private Integer n = 1;
 
    // 当前用户id,用于处理滥用行为
    private Long userId;
}

注意,本次是进行流式响应,所以还需一个stream参数:

public class ChatStreamParams extends ChatParams{
    private boolean stream = true;
}

后端使用WebClient向apenai api发起post请求以获得流式数据

@Transactional
    @Override
    public void chatStream2(ChatStreamParams chatParams, String chatId, String userId, Session session) {
        Flux<String> stringFlux = webClient.post()
                .uri(apiHost+"/v1/chat/completions")
                .header("Authorization", "Bearer " + apiKey)
                .bodyValue(chatParams)
                .retrieve()
                .bodyToFlux(String.class);
        stringFlux
                .takeWhile(data -> {
                    try {
                        JSONObject json = new JSONObject(data);
                        JSONArray choices = json.getJSONArray("choices");
                        String finish_reason = choices.getJSONObject(0).getString("finish_reason");
                        if (finish_reason.equals("stop")) {
                            String content = contentBuilder.toString();
                            System.out.println("content"+contentBuilder);
                            gptMessageService.save(chatId, Long.valueOf(userId), content, SystemConstants.MESSAGE_TYPE_GPT);
                            contentBuilder.setLength(0);
                        }
                        return !finish_reason.equals("stop"); // 继续处理数据,直到遇到停止条件
                    } catch (Exception e) {
                        e.printStackTrace();
                        return false; // 数据格式异常,停止处理数据
                    }
                })
                .subscribe(
                data -> {
                    try {
                        JSONObject json = new JSONObject(data);
                        JSONArray choices = json.getJSONArray("choices");
                        String finish_reason = choices.getJSONObject(0).getString("finish_reason");
                        if (finish_reason.equals("stop")) {
                            return;
                        }
                        String delta = choices.getJSONObject(0).getString("delta");
                        System.out.println(data);
                        JSONObject msg = new JSONObject(delta);
                        String content = msg.getString("content");
                        // 拼接消息,保存到数据库
                        contentBuilder.append(content);
                        session.getBasicRemote().sendText(content);
                    }catch (Exception e) {
                        e.printStackTrace();
                    }
                },
                error -> {
                    System.out.println("错误");
                    error.printStackTrace();
                }
        );
    }

参数释义:

chatParams:发送给api的请求参数;

chatId: 会话id;

userId: 用户id;

session: WebSocket的session,前后端流式响应会用到websoket

apiHost: 代理地址;

apiKey: key

注意:在subscribe回调函数里拿到流式数据,在takeWhile回调函数里设置停止条件


好了,通过这些步骤应该能流式响应了,如果遇到啥问题可以留言哦,看到会回。  


目录
相关文章
|
22天前
|
安全 Java 测试技术
🎉Java零基础:全面解析枚举的强大功能
【10月更文挑战第19天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
101 60
|
10天前
|
Java
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式
Java 8 引入的 Streams 功能强大,提供了一种简洁高效的处理数据集合的方式。本文介绍了 Streams 的基本概念和使用方法,包括创建 Streams、中间操作和终端操作,并通过多个案例详细解析了过滤、映射、归并、排序、分组和并行处理等操作,帮助读者更好地理解和掌握这一重要特性。
19 2
|
14天前
|
监控 Java 数据管理
java会话跟踪和拦截器过滤器
本文介绍了Web开发中的会话跟踪技术——Cookie与Session,以及过滤器(Filter)和监听器(Listener)的概念和应用。Cookie通过在客户端记录信息来识别用户,而Session则在服务器端保存用户状态。过滤器用于拦截和处理请求及响应,监听器则监控域对象的状态变化。文章详细解释了这些技术的实现方式、应用场景和主要方法,帮助开发者更好地理解和使用这些工具。
32 1
|
1月前
|
Java 程序员
在Java编程中,关键字不仅是简单的词汇,更是赋予代码强大功能的“魔法咒语”。
【10月更文挑战第13天】在Java编程中,关键字不仅是简单的词汇,更是赋予代码强大功能的“魔法咒语”。本文介绍了Java关键字的基本概念及其重要性,并通过定义类和对象、控制流程、访问修饰符等示例,展示了关键字的实际应用。掌握这些关键字,是成为优秀Java程序员的基础。
23 3
|
1月前
|
Java 数据安全/隐私保护
Java ffmpeg 实现视频加文字/图片水印功能
【10月更文挑战第22天】在 Java 中使用 FFmpeg 实现视频加文字或图片水印功能,需先安装 FFmpeg 并添加依赖(如 JavaCV)。通过构建 FFmpeg 命令行参数,使用 `drawtext` 滤镜添加文字水印,或使用 `overlay` 滤镜添加图片水印。示例代码展示了如何使用 JavaCV 实现文字水印。
|
1月前
|
Java
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
58 2
java实现从HDFS上下载文件及文件夹的功能,以流形式输出,便于用户自定义保存任何路径下
|
1月前
|
机器学习/深度学习 算法 Java
通过 Java Vector API 利用 SIMD 的强大功能
通过 Java Vector API 利用 SIMD 的强大功能
43 10
|
1月前
|
Oracle 安全 Java
Java 22 为开发人员带来了重大增强功能
Java 22 为开发人员带来了重大增强功能
37 9
|
1月前
|
Java
让星星⭐月亮告诉你,jdk1.8 Java函数式编程示例:Lambda函数/方法引用/4种内建函数式接口(功能性-/消费型/供给型/断言型)
本示例展示了Java中函数式接口的使用,包括自定义和内置的函数式接口。通过方法引用,实现对字符串操作如转换大写、数值转换等,并演示了Function、Consumer、Supplier及Predicate四种主要内置函数式接口的应用。
25 1
|
3月前
|
Java 开发者
Java多线程教程:使用ReentrantLock实现高级锁功能
Java多线程教程:使用ReentrantLock实现高级锁功能
46 1