返回顶部
首页 > 资讯 > 移动开发 >Flutter+SpringBoot实现ChatGPT流实输出
  • 821
分享到

Flutter+SpringBoot实现ChatGPT流实输出

flutterspringbootchatgpt 2023-10-23 20:10:45 821人浏览 八月长安
摘要

Flutter+SpringBoot实现ChatGPT流式输出、上下文了连续对话 最终实现Flutter的流式输出+上下文连续对话。 这里就是提供一个简单版的工具类和使用案例,此处页面仅参考。 服务

Flutter+SpringBoot实现ChatGPT流式输出、上下文了连续对话

最终实现Flutter的流式输出+上下文连续对话。
在这里插入图片描述

这里就是提供一个简单版的工具类和使用案例,此处页面仅参考。

服务端

这里直接封装提供工具类,修改自己的apiKey即可使用,支持连续对话

工具类及使用

Http依赖这里使用okHttp

    <dependency>      <groupId>com.squareup.okhttp3groupId>      <artifactId>okhttpartifactId>      <version>4.9.3version>    dependency>
import com.alibaba.fastJSON2.jsON;import com.squareup.okhttp.Call;import com.squareup.okhttp.MediaType;import com.squareup.okhttp.OkHttpClient;import com.squareup.okhttp.Request;import com.squareup.okhttp.RequestBody;import com.squareup.okhttp.Response;import com.squareup.okhttp.ResponseBody;import lombok.AllArgsConstructor;import lombok.Builder;import lombok.Data;import lombok.Getter;import lombok.NoArgsConstructor;import lombok.extern.slf4j.Slf4j;import org.springframework.stereotype.Component;import org.springframework.util.StringUtils;import org.springframework.WEB.servlet.mvc.method.annotation.SseEmitter;import vip.ailtw.common.utils.StringUtil;import javax.annotation.PostConstruct;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.io.Serializable;import java.util.List;import java.util.concurrent.TimeUnit;import java.util.function.Consumer;import java.util.regex.Matcher;import java.util.regex.Pattern;@Slf4j@Componentpublic class ChatGptStreamUtil {        private final String apiKey = "xxxxxxxxxxxxxx";    public final String gptCompletionsUrl = "https://api.openai.com/v1/chat/completions";    private static final OkHttpClient client = new OkHttpClient();    private static MediaType mediaType;    private static Request.Builder requestBuilder;    public final static Pattern contentPattern = Pattern.compile("\"content\":\"(.*?)\"}");        public final static String EVENT_DATA = "d";        public final static String EVENT_ERROR = "e";        public final static String END = "<>";    @PostConstruct    public void init() {        client.setConnectTimeout(60, TimeUnit.SECONDS);        client.setReadTimeout(60, TimeUnit.SECONDS);        mediaType = MediaType.parse("application/json; charset=utf-8");        requestBuilder = new Request.Builder()                .url(gptCompletionsUrl)                .header("Content-Type", "application/json")                .header("Authorization", "Bearer " + apiKey);    }        public GptChatResultDTO chatStream(List<ChatGptDTO> talkList, Consumer<String> callable) throws Exception {        long start = System.currentTimeMillis();        StringBuilder resp = new StringBuilder();        Response response = chatStream(talkList);        //解析对话内容        try (ResponseBody responseBody = response.body();             InputStream inputStream = responseBody.byteStream();             BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream))) {            String line;            while ((line = bufferedReader.readLine()) != null) {                if (!StringUtils.hasLength(line)) {                    continue;                }                Matcher matcher = contentPattern.matcher(line);                if (matcher.find()) {                    String content = matcher.group(1);                    resp.append(content);                    callable.accept(content);                }            }        }        int WordSize = 0;        for (ChatGptDTO dto : talkList) {            String content = dto.getContent();            wordSize += content.toCharArray().length;        }        wordSize += resp.toString().toCharArray().length;        long end = System.currentTimeMillis();        return GptChatResultDTO.builder().resContent(resp.toString()).time(end - start).wordSize(wordSize).build();    }        private Response chatStream(List<ChatGptDTO> talkList) throws Exception {        ChatStreamDTO chatStreamDTO = new ChatStreamDTO(talkList);        RequestBody bodyOk = RequestBody.create(mediaType, chatStreamDTO.toString());        Request requestOk = requestBuilder.post(bodyOk).build();        Call call = client.newCall(requestOk);        Response response;        try {            response = call.execute();        } catch (IOException e) {            throw new IOException("请求时IO异常: " + e.getMessage());        }        if (response.isSuccessful()) {            return response;        }        try (ResponseBody body = response.body()) {            if (429 == response.code()) {                String msg = "Open Api key 已过期,msg: " + body.string();                log.error(msg);            }            throw new RuntimeException("chat api 请求异常, code: " + response.code() + "body: " + body.string());        }    }    private boolean sendToClient(String event, String data, SseEmitter emitter) {        try {            emitter.send(SseEmitter.event().name(event).data("{" + data + "}"));            return true;        } catch (IOException e) {            log.error("向客户端发送消息时出现异常", e);        }        return false;    }        public boolean sendData(String data, SseEmitter emitter) {        if (StringUtil.isBlank(data)) {            return true;        }        return sendToClient(EVENT_DATA, data, emitter);    }        public void sendEnd(SseEmitter emitter) {        try {            sendToClient(EVENT_DATA, END, emitter);        } finally {            emitter.complete();        }    }        public void sendError(SseEmitter emitter) {        try {            sendToClient(EVENT_ERROR, "我累垮了", emitter);        } finally {            emitter.complete();        }    }        @Data    @NoArgsConstructor    @AllArgsConstructor    @Builder    public static class GptChatResultDTO implements Serializable {                private String resContent;                private int wordSize;                private long time;    }        @Data    @Builder    @NoArgsConstructor    @AllArgsConstructor    public static class ChatGptDTO implements Serializable {                private String content;                private String role;    }        @Getter    public static enum GptRoleEnum {        USER_ROLE("user", "用户"),        GPT_ROLE("assistant", "ChatGPT本身"),                SYSTEM_ROLE("system", "对话设定"),        ;        private final String value;        private final String desc;        GptRoleEnum(String value, String desc) {            this.value = value;            this.desc = desc;        }    }        @Data    public static class ChatStreamDTO {        private static final String model = "gpt-3.5-turbo";        private static final boolean stream = true;        private List<ChatGptDTO> messages;        public ChatStreamDTO(List<ChatGptDTO> messages) {            this.messages = messages;        }        @Override        public String toString() {            return "{\"model\":\"" + model + "\"," +                    "\"messages\":" + JSON.toJSONString(messages) + "," +                    "\"stream\":" + stream + "}";        }    }}

使用案例:

    public static void main(String[] args) throws Exception {        ChatGptStreamUtil chatGptStreamUtil = new ChatGptStreamUtil();        chatGptStreamUtil.init();        //构建一个上下文对话情景        List<ChatGptDTO> talkList = new ArrayList<>();        //设定gpt        talkList.add(ChatGptDTO.builder().content("你是chatgpt助手,能过帮助我查阅资料,编写教学报告。").role(GptRoleEnum.GPT_ROLE.getValue()).build());        //开始提问        talkList.add(ChatGptDTO.builder().content("请帮我写一篇小学数学加法运算教案").role(GptRoleEnum.USER_ROLE.getValue()).build());        chatGptStreamUtil.chatStream(talkList, (respContent) -> {            //这里是gpt每次流式返回的内容            System.out.println("gpt返回:" + respContent);        });    }

SpringBoot接口

基于SpringBoot工程,提供接口,供Flutter端使用。

通过上面的工具类的使用,可以知道gpt返回给我们的内容是一段一段的,因此如果我们服务端也要提供类似的效果,提供两个思路和实现:

  • websocket,服务端接收gpt返回的内容时推送内容给flutter
  • 使用Http长链接,也就是 SseEmitter,这里也是采用这种方式。

代码:

@RestController@RequestMapping("/chat")@Slf4jpublic class ChatController {    @Autowired    private ChatGptStreamUtil chatGptStreamUtil;      @PostMapping(value = "/chatStream")    @ApiOperation("流式对话")    public SseEmitter chatStream() {        SseEmitter emitter = new SseEmitter(80000L);              //构建一个上下文对话情景        List<ChatGptDTO> talkList = new ArrayList<>();        //设定gpt        talkList.add(ChatGptDTO.builder().content("你是chatgpt助手,能过帮助我查阅资料,编写教学报告。").role(GptRoleEnum.GPT_ROLE.getValue()).build());        //开始提问        talkList.add(ChatGptDTO.builder().content("请帮我写一篇小学数学加法运算教案").role(GptRoleEnum.USER_ROLE.getValue()).build());        GptChatResultDTO gptChatResultDTO = chatGptStreamUtil.chatStream(talkList, (content) -> {          //这里服务端接收到消息就发送给Flutter               chatGptStreamUtil.sendData(content, emitter);            });        return emitter;    }}

Flutter端

这里使用dio作为网络请求的工具

依赖

dio: ^5.2.1+1

工具类

import 'dart:async';import 'dart:convert';import 'package:dio/dio.dart';import 'package:flutter/cupertino.dart';import 'package:flutter/foundation.dart';import 'package:get/get.dart' hide Response;///http工具类class HttpUtil {  Dio? client;  static HttpUtil of() {    return HttpUtil.init();  }  //初始化http工具  HttpUtil.init() {    if (client == null) {      var options = BaseOptions(          baseUrl: Config.baseUrl,          connectTimeout: const Duration(seconds: 100),          receiveTimeout: const Duration(seconds: 100));      client = Dio(options);      // 请求与响应拦截器/异常拦截器      client?.interceptors.add(OnReqResInterceptors());    }  }  Future<Stream<String>?> postStream(String path,      [Map<String, dynamic>? params]) async {    Response<ResponseBody> rs =    await Dio().post<ResponseBody>(Config.baseUrl + path,        options: Options(headers: {          "Accept": "text/event-stream",          "Cache-Control": "no-cache"        }, responseType: ResponseType.stream),        data: params     );    StreamTransfORMer<Uint8List, List<int>> unit8Transformer =    StreamTransformer.fromHandlers(      handleData: (data, sink) {        sink.add(List<int>.from(data));      },    );    var resp = rs.data?.stream        .transform(unit8Transformer)        .transform(const Utf8Decoder())        .transform(const LineSplitter());    return resp;  }/// Dio 请求与响应拦截器class OnReqResInterceptors extends InterceptorsWrapper {    Future<void> onRequest(      RequestOptions options, RequestInterceptorHandler handler) async {    //统一添加token    var headers = options.headers;    headers['Authorization'] = '请求头token';    return super.onRequest(options, handler);  }    void onError(DioError err, ErrorInterceptorHandler handler) {    if (err.type == DioErrorType.unknown) {      // 网络不可用,请稍后再试    }    return super.onError(err, handler);  }    void onResponse(      Response<dynamic> response, ResponseInterceptorHandler handler) {    Response res = response;    return super.onResponse(res, handler);  }}

使用

  //构建文章、流式对话  chatStream() async {    final stream = await HttpUtil.of().postStream("/api/chat/chatStream");    String respContent = "";    stream?.listen((content) {      debugPrint(content);      if (content != '' && content.contains("data:")) {        //解析数据        var start = content.indexOf("{") + 1;        var end = content.indexOf("}");        var substring = content.substring(start, end);        content = substring;        respContent += content;        print("返回的内容:$content");      }    });  }

来源地址:https://blog.csdn.net/wq2323/article/details/133523990

--结束END--

本文标题: Flutter+SpringBoot实现ChatGPT流实输出

本文链接: https://lsjlt.com/news/440863.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Flutter+SpringBoot实现ChatGPT流实输出
    Flutter+SpringBoot实现ChatGPT流式输出、上下文了连续对话 最终实现Flutter的流式输出+上下文连续对话。 这里就是提供一个简单版的工具类和使用案例,此处页面仅参考。 服务...
    99+
    2023-10-23
    flutter spring boot chatgpt
  • PHP实现OpenApi接口ChatGPT回复输出流文字流打字效果
    在做AI聊天时,回复文字时一般用实时打字文字流效果,那PHP实现ChatGPT回复输出流文字流打字效果怎么实现呢? 先看一下效果图: 注意看一下前端ajax请求是EventStream类型。具体什么...
    99+
    2023-09-10
    php chatgpt 开发语言
  • Java调用ChatGPT(基于SpringBoot和Vue)实现可连续对话和流式输出的ChatGPTAPI
    目录1. 配置阶段1.1 依赖引入1.2 配置application.yml文件1.3 注解添加2 使用2.1 生成回答2.1.1 测试2.2 生成图片2.2.1 测试2.3 下载图...
    99+
    2023-05-18
    Java调用ChatGPT实现ChatGPT API Java调用ChatGPT Java ChatGPT
  • PHP实现chatGPT流式输出代码,OpenAI对接,支持GPT3.5/GPT4
     源码下载地址:https://gitee.com/haoyachengge/chatgpt-speed.git header('Content-Type: text/event-stream'); header(...
    99+
    2023-09-01
    chatgpt php ai gpt-3
  • Java调用ChatGPT(基于SpringBoot和Vue)实现连续对话、流式输出和自定义baseUrl
    目录 版本更新说明1. 配置阶段1.1 依赖引入1.2 配置application.yml文件1.3 注解添加 2. 使用2.1 生成回答2.1.1 测试 2.2 生成图片2.2.1 测试 2.3 下载图片2.3.1...
    99+
    2023-08-16
    java springboot
  • Java实现带缓冲的输入输出流
    缓冲是 I/O 的一种性能优化。缓冲流为 I/O 流增加了内存缓冲区。 BufferedInputStream类 与 BufferedOutputStream类 BufferedIn...
    99+
    2024-04-02
  • chatgpt赋能python:Python换行输出:如何在Python中实现换行输出?
    Python换行输出:如何在Python中实现换行输出? 在Python编程中,如何将输出内容分行呈现,是开发者经常会遇到的问题。Python提供了多种方式来实现换行输出,这篇文章将会介绍其中三种。 ...
    99+
    2023-10-02
    chatgpt python 爬虫 计算机
  • Python Flask 封装ChatGPT流式输出接口
    首先, 恭喜你搜到了这篇文章, 因为, 我解决这个问题时, 也搜了很久的博客, 结果都无法正确实现 截至今日, 快有半年博客没有更新了, 今天忙里偷闲, 将最近在忙的事情做一个总结 之前搞了个域名, ...
    99+
    2023-09-08
    python flask chatgpt
  • Java怎么实现带缓冲的输入输出流
    本篇内容主要讲解“Java怎么实现带缓冲的输入输出流”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java怎么实现带缓冲的输入输出流”吧!缓冲是 I/O 的一种性能优化。缓冲流为 I/O 流增加...
    99+
    2023-06-29
  • 微信小程序怎么实现类似ChatGPT的流式传输
    这篇文章主要介绍“微信小程序怎么实现类似ChatGPT的流式传输”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“微信小程序怎么实现类似ChatGPT的流式传输”文章能帮助大家解决问题。小程序上实现流失...
    99+
    2023-07-05
  • 实时获取Python的print输出流
    我的应用场景是:使用shell执行python文件,并且通过调用的返回值获取python的标准输出流。 shell程序如下: cmd='python '$1' '$2' '$3' '$5' '$4 RESULT=eval $cm...
    99+
    2023-01-31
    实时 Python print
  • PostgreSQL如何实现输出
    这篇文章主要介绍了PostgreSQL如何实现输出,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一、输出参照current_date函数,首...
    99+
    2024-04-02
  • php如何实现输出
    这篇文章给大家分享的是有关php如何实现输出的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。php输出方法:1、使用echo语句输出,例“echo 'hi!'”;2、使用print语句输出;3、使用...
    99+
    2023-06-14
  • python实现输出日历
    终于还有一个星期就放暑假了,可以抽出时间来学点新的东西,想想半年多没登CSDN差点把密码忘了我也是醉了。 废话不多说,正文开始 以下是使用几个简单的函数实现给定指定年月实现当月日历输出的程序,大部分内容引用自网易云课堂哈工大开设的Pyth...
    99+
    2023-01-31
    日历 python
  • 解析springboot集成AOP实现日志输出的方法
    开发接口系统中主要的一环就是日志输出,如果系统出现问题,日志能帮我们去定位问题,最常见的日志是调用方 所调用的IP 接口地址 对应方法 参数值 以及接口方接收到请求 所返回的参数。如...
    99+
    2024-04-02
  • Flutter实现PopupMenu(弹出设置菜单)
    PopupMenuButton简介 PopupMenuButton是一个用于创建弹出菜单的小部件。它通常与IconButton或其他触发菜单显示的小部件一起使用。当用户点击触发按钮时,PopupMen...
    99+
    2023-09-28
    flutter android PopupMenuButton PopupMenuItem 弹出设置菜单
  • flutter底部弹出BottomSheet怎么实现
    本篇内容介绍了“flutter底部弹出BottomSheet怎么实现”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!效果图:ModalBott...
    99+
    2023-06-29
  • Java SpringBoot怎么集成ChatGPT实现AI聊天
    这篇文章主要介绍“Java SpringBoot怎么集成ChatGPT实现AI聊天”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“Java SpringBoot怎么集成ChatGP...
    99+
    2023-07-05
  • Flutter StaggeredGridView如何实现瀑布流效果
    这篇文章将为大家详细讲解有关Flutter StaggeredGridView如何实现瀑布流效果,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。具体内容如下在根目录pubspec.yaml文件中添...
    99+
    2023-06-29
  • Flutter异步操作实现流程详解
    目录一、FutureBuilder二、StreamBuilder在Flutter中,借助 FutureBuilder 组件和 StreamBuilder 组件,可以非常方便地完成异步...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作