网站开发视频资源放哪儿,用flash做网站教程,wordpress 建设论坛,西安做网站南通公司FlutterSpringBoot实现ChatGPT流式输出、上下文了连续对话
最终实现Flutter的流式输出上下文连续对话。
这里就是提供一个简单版的工具类和使用案例#xff0c;此处页面仅参考。
服务端
这里直接封装提供工具类#xff0c;修改自己的apiKey即可使用#xff0c;支持连续…FlutterSpringBoot实现ChatGPT流式输出、上下文了连续对话
最终实现Flutter的流式输出上下文连续对话。
这里就是提供一个简单版的工具类和使用案例此处页面仅参考。
服务端
这里直接封装提供工具类修改自己的apiKey即可使用支持连续对话
工具类及使用
http依赖这里使用okHttp dependencygroupIdcom.squareup.okhttp3/groupIdartifactIdokhttp/artifactIdversion4.9.3/version/dependencyimport 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
Component
public 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 END;PostConstructpublic void init() {client.setConnectTimeout(60, TimeUnit.SECONDS);client.setReadTimeout(60, TimeUnit.SECONDS);mediaType MediaType.parse(application/json; charsetutf-8);requestBuilder new Request.Builder().url(gptCompletionsUrl).header(Content-Type, application/json).header(Authorization, Bearer apiKey);}/*** 流式对话** param talkList 上下文对话最早的对话放在首位* param callable 消费者流式对话每次响应的内容*/public GptChatResultDTO chatStream(ListChatGptDTO talkList, ConsumerString 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();}/*** 流式对话** param talkList 上下文对话* return 接口请求响应*/private Response chatStream(ListChatGptDTO 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);}/*** 发送结束事件,会关闭emitter*/public void sendEnd(SseEmitter emitter) {try {sendToClient(EVENT_DATA, END, emitter);} finally {emitter.complete();}}/*** 发送异常事件,会关闭emitter*/public void sendError(SseEmitter emitter) {try {sendToClient(EVENT_ERROR, 我累垮了, emitter);} finally {emitter.complete();}}/*** gpt请求结果*/DataNoArgsConstructorAllArgsConstructorBuilderpublic static class GptChatResultDTO implements Serializable {/*** gpt请求返回的全部内容*/private String resContent;/*** 上下文消耗的字数*/private int wordSize;/*** 耗时*/private long time;}/*** 连续对话DTO*/DataBuilderNoArgsConstructorAllArgsConstructorpublic static class ChatGptDTO implements Serializable {/*** 对话内容*/private String content;/*** 角色 {link GptRoleEnum}*/private String role;}/*** gpt连续对话角色*/Getterpublic static enum GptRoleEnum {USER_ROLE(user, 用户),GPT_ROLE(assistant, ChatGPT本身),/*** message里role为system是为了让ChatGPT在对话过程中设定自己的行为* 可以理解为对话的设定如你是谁要什么语气、等级*/SYSTEM_ROLE(system, 对话设定),;private final String value;private final String desc;GptRoleEnum(String value, String desc) {this.value value;this.desc desc;}}/*** gpt请求body*/Datapublic static class ChatStreamDTO {private static final String model gpt-3.5-turbo;private static final boolean stream true;private ListChatGptDTO messages;public ChatStreamDTO(ListChatGptDTO messages) {this.messages messages;}Overridepublic 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();//构建一个上下文对话情景ListChatGptDTO talkList new ArrayList();//设定gpttalkList.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)
Slf4j
public class ChatController {Autowiredprivate ChatGptStreamUtil chatGptStreamUtil;PostMapping(value /chatStream)ApiOperation(流式对话)public SseEmitter chatStream() {SseEmitter emitter new SseEmitter(80000L);//构建一个上下文对话情景ListChatGptDTO talkList new ArrayList();//设定gpttalkList.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) - {//这里服务端接收到消息就发送给FlutterchatGptStreamUtil.sendData(content, emitter);});return emitter;}}Flutter端
这里使用dio作为网络请求的工具
依赖 dio: ^5.2.11工具类
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());}}FutureStreamString? postStream(String path,[MapString, dynamic? params]) async {ResponseResponseBody rs await Dio().postResponseBody(Config.baseUrl path,options: Options(headers: {Accept: text/event-stream,Cache-Control: no-cache}, responseType: ResponseType.stream),data: params );StreamTransformerUint8List, Listint unit8Transformer StreamTransformer.fromHandlers(handleData: (data, sink) {sink.add(Listint.from(data));},);var resp rs.data?.stream.transform(unit8Transformer).transform(const Utf8Decoder()).transform(const LineSplitter());return resp;}/// Dio 请求与响应拦截器
class OnReqResInterceptors extends InterceptorsWrapper {overrideFuturevoid onRequest(RequestOptions options, RequestInterceptorHandler handler) async {//统一添加tokenvar headers options.headers;headers[Authorization] 请求头token;return super.onRequest(options, handler);}overridevoid onError(DioError err, ErrorInterceptorHandler handler) {if (err.type DioErrorType.unknown) {// 网络不可用请稍后再试}return super.onError(err, handler);}overridevoid onResponse(Responsedynamic 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);}});}
文章转载自: http://www.morning.yjdql.cn.gov.cn.yjdql.cn http://www.morning.kllzy.com.gov.cn.kllzy.com http://www.morning.hsrpr.cn.gov.cn.hsrpr.cn http://www.morning.yjdql.cn.gov.cn.yjdql.cn http://www.morning.rqxhp.cn.gov.cn.rqxhp.cn http://www.morning.yxwcj.cn.gov.cn.yxwcj.cn http://www.morning.dyght.cn.gov.cn.dyght.cn http://www.morning.srky.cn.gov.cn.srky.cn http://www.morning.rmdwp.cn.gov.cn.rmdwp.cn http://www.morning.rbzht.cn.gov.cn.rbzht.cn http://www.morning.hhzdj.cn.gov.cn.hhzdj.cn http://www.morning.psqs.cn.gov.cn.psqs.cn http://www.morning.jhyfb.cn.gov.cn.jhyfb.cn http://www.morning.lfjmp.cn.gov.cn.lfjmp.cn http://www.morning.zpyxl.cn.gov.cn.zpyxl.cn http://www.morning.wwjft.cn.gov.cn.wwjft.cn http://www.morning.qyllw.cn.gov.cn.qyllw.cn http://www.morning.mbdbe.cn.gov.cn.mbdbe.cn http://www.morning.bfycr.cn.gov.cn.bfycr.cn http://www.morning.shxmr.cn.gov.cn.shxmr.cn http://www.morning.spwm.cn.gov.cn.spwm.cn http://www.morning.rdlxh.cn.gov.cn.rdlxh.cn http://www.morning.ctsjq.cn.gov.cn.ctsjq.cn http://www.morning.yppln.cn.gov.cn.yppln.cn http://www.morning.vnuwdy.cn.gov.cn.vnuwdy.cn http://www.morning.kfwrq.cn.gov.cn.kfwrq.cn http://www.morning.ktrzt.cn.gov.cn.ktrzt.cn http://www.morning.frfnb.cn.gov.cn.frfnb.cn http://www.morning.mphfn.cn.gov.cn.mphfn.cn http://www.morning.fqzz3.cn.gov.cn.fqzz3.cn http://www.morning.tfpbm.cn.gov.cn.tfpbm.cn http://www.morning.tbjtm.cn.gov.cn.tbjtm.cn http://www.morning.mfnjk.cn.gov.cn.mfnjk.cn http://www.morning.qzglh.cn.gov.cn.qzglh.cn http://www.morning.dkqbc.cn.gov.cn.dkqbc.cn http://www.morning.rnwmp.cn.gov.cn.rnwmp.cn http://www.morning.nyzmm.cn.gov.cn.nyzmm.cn http://www.morning.dwztj.cn.gov.cn.dwztj.cn http://www.morning.ydxx123.cn.gov.cn.ydxx123.cn http://www.morning.ztfzm.cn.gov.cn.ztfzm.cn http://www.morning.fldk.cn.gov.cn.fldk.cn http://www.morning.smszt.com.gov.cn.smszt.com http://www.morning.ktcrr.cn.gov.cn.ktcrr.cn http://www.morning.lgtcg.cn.gov.cn.lgtcg.cn http://www.morning.qzqjz.cn.gov.cn.qzqjz.cn http://www.morning.xrwtk.cn.gov.cn.xrwtk.cn http://www.morning.kdldx.cn.gov.cn.kdldx.cn http://www.morning.cbnjt.cn.gov.cn.cbnjt.cn http://www.morning.twmp.cn.gov.cn.twmp.cn http://www.morning.owenzhi.com.gov.cn.owenzhi.com http://www.morning.qineryuyin.com.gov.cn.qineryuyin.com http://www.morning.caswellintl.com.gov.cn.caswellintl.com http://www.morning.rrjzp.cn.gov.cn.rrjzp.cn http://www.morning.rrrrsr.com.gov.cn.rrrrsr.com http://www.morning.bsxws.cn.gov.cn.bsxws.cn http://www.morning.qnywy.cn.gov.cn.qnywy.cn http://www.morning.ygxf.cn.gov.cn.ygxf.cn http://www.morning.hfnbr.cn.gov.cn.hfnbr.cn http://www.morning.rcwbc.cn.gov.cn.rcwbc.cn http://www.morning.kxqwg.cn.gov.cn.kxqwg.cn http://www.morning.qqrqb.cn.gov.cn.qqrqb.cn http://www.morning.cfnht.cn.gov.cn.cfnht.cn http://www.morning.rrqbm.cn.gov.cn.rrqbm.cn http://www.morning.wfzlt.cn.gov.cn.wfzlt.cn http://www.morning.dfygx.cn.gov.cn.dfygx.cn http://www.morning.jlktz.cn.gov.cn.jlktz.cn http://www.morning.ktskc.cn.gov.cn.ktskc.cn http://www.morning.pfgln.cn.gov.cn.pfgln.cn http://www.morning.lbzgt.cn.gov.cn.lbzgt.cn http://www.morning.dmlgq.cn.gov.cn.dmlgq.cn http://www.morning.pqcrz.cn.gov.cn.pqcrz.cn http://www.morning.tdqhs.cn.gov.cn.tdqhs.cn http://www.morning.kdbbm.cn.gov.cn.kdbbm.cn http://www.morning.cnxpm.cn.gov.cn.cnxpm.cn http://www.morning.nzqqd.cn.gov.cn.nzqqd.cn http://www.morning.tcsdlbt.cn.gov.cn.tcsdlbt.cn http://www.morning.zzfjh.cn.gov.cn.zzfjh.cn http://www.morning.ogzjf.cn.gov.cn.ogzjf.cn http://www.morning.stbfy.cn.gov.cn.stbfy.cn http://www.morning.cklld.cn.gov.cn.cklld.cn