chatgpt 逐字输出 使用fetch/eventSource/fetchEventSouce进行sse流式处理

这篇具有很好参考价值的文章主要介绍了chatgpt 逐字输出 使用fetch/eventSource/fetchEventSouce进行sse流式处理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

chatgpt 逐字输出 使用fetch/eventSource/fetchEventSouce进行sse流式处理
前端使用vue

1.逐字输出 闪动css样式

<span id="response_row" class="result-streaming">{{ item.assistantContent }}</span>
.result-streaming:after {
  -webkit-animation: blink 1s steps(5, start) infinite;
  animation: blink 1s steps(5, start) infinite;
  content: "▋";
  margin-left: 0.25rem;
  vertical-align: baseline;
}

2.使用fetch/eventSource/fetchEventSource进行sse流式处理

先贴最后成功使用的
使用fetchEventSource方法
参考代码:https://blog.csdn.net/cuiyuchen111/article/details/129468291
参考/下载文档:https://www.npmjs.com/package/@microsoft/fetch-event-source?activeTab=readme

以下为后端接口要求
chatgpt 逐字输出 使用fetch/eventSource/fetchEventSouce进行sse流式处理
前端代码

<p v-if="item.requestFlag" class="content robot_content"><span id="response_row" class="result-streaming">{{ item.assistantContent }}</span></p>
<p class="content robot_content"><span v-html="item.assistantContent"></span></p>
 async getResponseFromAPI() {
          const that = this;
          this.sendLoading = true;
          // 用户提问时间
          let userTime = that.getNowTime();
          const form = JSON.parse(JSON.stringify(this.form));
          console.log(form, "请求里的form");
          //物理添加 页面
          that.conversations.push({
            userContentId: "",
            userContent: form.prompt,
            userContentDatetime: userTime,
            assistantContentId: "",
            assistantContent: "",
            assistantContentDatetime: userTime,
            requestFlag: true,
          });
          // 对话请求
          const abortController = new AbortController();
          let formData = new FormData();
          formData.append("chatid", this.currentChatId);
          formData.append("clientid", form.clientid);
          formData.append("prompt", form.prompt);
          const url = "xxxxx";
          const headers = new Headers();
          const body = formData;
          const eventSource = fetchEventSource(url, {
            method: "POST",
            headers,
            body,
            signal: abortController.signal,
            onmessage(e) {
              that.handleScrollBottom();
              that.form.prompt = "";
              const response_row = document.getElementById("response_row");
              console.log(e.data);
              let res = JSON.parse(e.data);
              let index = that.conversations.length - 1;
              if (res.message == "[DONE]") {
                res.data = JSON.parse(res.data);
                console.log(res.data);
                let obj = {
                  userContentId: res.data.userContentId,
                  userContent: res.data.userContent,
                  userContentDatetime: userTime,
                  assistantContentId: res.data.assistantContentId,
                  assistantContent: res.data.assistantContent,
                  assistantContentDatetime: that.getNowTime(),
                  requestFlag: false,
                };
                console.log(obj);
                that.$set(that.conversations, index, obj);
                that.sendLoading = false;
                abortController.abort();
                eventSource.close();
                console.log("我是结束!!");
              } else {
                var content = res.data;
                response_row.innerText += content;
                // console.log(content)
                // if (content.includes("[ENTRY]")) {
                //   content = content.replaceAll("[ENTRY]", "\n");
                // }
              }
            },
            onclose() {
              console.log("close");
              that.sendLoading = false;
              abortController.abort();
              eventSource.close();
            },
            onerror(error) {
              let index = that.conversations.length - 1;
              that.conversations.splice(index, 1);
              that.sendLoading = false;
              console.log("error", error);
              abortController.abort();
              eventSource.close();
            },
          });
        }

遇到的问题:
1.只调用一次事件 但fetch请求发送了两次或多次且终止失败

//按照fetchEventSource文档内的写法 请求暂停无效
const ctrl = new AbortController();
fetchEventSource('/api/sse', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
    },
    body: JSON.stringify({
        foo: 'bar'
    }),
    signal: ctrl.signal,
});

//而后看到一种说法,fetchEventSource是针对EventSource API的,而不是xhr或fetch API
//因此定义EventSource存储接口所返回的数据 使用EventSource的暂停方法 =》 fetchEventSource暂停成功
const eventSource = fetchEventSource(url, {
            method: "POST",
            headers,
            body,
            signal: abortController.signal,
            onmessage(e) {
                eventSource.close();
            },
            onclose() {
              eventSource.close();
            },
            onerror(error) {
              eventSource.close();
            },
          });

以下为fetch/eventSource使用过程中遇到的问题

1.使用fetch方式进行sse流式处理
优点:可以使用post请求
缺点:获取到的数据处理困难 获取事件返回格式或有错误
参考代码:https://blog.csdn.net/betterAndBetter_/article/details/129900233
     http://681314.com/A/YaHyYpjoPF

async function send() {
    const input = document.getElementById("input").value;
    const output = document.getElementById("output");
    output.innerText = "";
    const url = "/api/stream";
    const data = { "Prompt": input };
//直接获取 Fetch 的response, 无法使用 await的话, Promise的方式也是可以的。
    const response = await fetch(url, {
        method: "POST",
        body: JSON.stringify(data),
        headers: {
            "Content-Type": "application/json"
        }
    })
	//获取UTF8的解码
    const encode = new TextDecoder("utf-8");
	//获取body的reader
	  const reader = response.body.getReader();
	// 循环读取reponse中的内容
    while (true) {
        const { done, value } = await reader.read();
        if (done) {
            break;
        }
	// 解码内容
        const text = encode.decode(value);
	// 当获取错误token时,输出错误信息
        if (text === "<ERR>") {
            output.innerText = "Error";
            break;
        } else {
	// 获取正常信息时,逐字追加输出
            output.innerText += text;
        }
    }
}

【记得补截图】

2.使用eventSource进行sse流式处理
优点:获取到的数据格式规范 易处理
缺点:无法使用post请求
参考b站视频:https://www.bilibili.com/video/BV1QA411C7mN/?spm_id_from=333.880.my_history.page.click&vd_source=384646ea9baa6985ceb5331bff5b87b0

var rsource = (this.rsource = new EventSource(
        `/api/chat/repeat/${this.cid}`
      ));
      rsource.addEventListener("open", function () {
        console.log("connect");
      });

      //如果服务器响应报文中没有指明事件,默认触发message事件
      rsource.addEventListener("message", function (e) {
        console.log(`resp:(${e.data})`);
        var rconv = that.conversation[that.conversation.length - 1];
        if (e.data == "[DONE]") {
          rsource.close();

          rconv["loading"] = false;
          that.convLoading = false;
          that.refrechConversation();
          that.rsource = undefined;
          return;
        }

        var content = e.data;
        if (content.includes("[ENTRY]")) {
          content = content.replaceAll("[ENTRY]", "\n");
        }

        // 滚动到最下面
        that.handleScrollBottom();

        var idx = rconv.idx;
        rconv["speeches"][idx] += content;
        that.refrechConversation();
      });

      //发生错误,则会触发error事件
      rsource.addEventListener("error", function (e) {
        console.log("error:" + e.data);
        rsource.close();
        that.rsource = undefined;
      });

由于eventSource获取到的数据比fetch流畅许多,所以研究过eventSource能否使用post请求,使用过以下代码,但失败了
chatgpt 逐字输出 使用fetch/eventSource/fetchEventSouce进行sse流式处理
3.fetch和eventSource同时使用
优点:可以很顺利的请求并且获取到数据
缺点:fetch支持post eventSource不支持post 对接口请求方式有要求 几乎不太能兼容文章来源地址https://www.toymoban.com/news/detail-467166.html

// 获取表单元素
const form = document.querySelector('#my-form');

// 监听表单提交事件
form.addEventListener('submit', (event) => {
  event.preventDefault(); // 阻止默认提交行为

  const formData = new FormData(form); // 创建 FormData 对象

  // 发送 POST 请求并接收 SSE 流式输出
  fetch('/api/submit-form', {
    method: 'POST',
    body: formData
  }).then((response) => {
    // 如果请求成功,则创建 EventSource 对象监听 SSE 输出
    if (response.ok) {
      const eventSource = new EventSource('/api/stream');

      eventSource.onmessage = (event) => {
        const data = JSON.parse(event.data);
        console.log(data); // 处理接收到的数据
      };

      eventSource.onerror = (error) => { // 监听错误事件
        console.error(error);
      };
    }
  }).catch((error) => {
    console.error(error);
  });
});

到了这里,关于chatgpt 逐字输出 使用fetch/eventSource/fetchEventSouce进行sse流式处理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • WPF实现类似ChatGPT的逐字打印效果

    前一段时间ChatGPT类的应用十分火爆,这类应用在回答用户的问题时逐字打印输出,像极了真人打字回复消息。出于对这个效果的兴趣,决定用WPF模拟这个效果。 真实的ChatGPT逐字输出效果涉及其语言生成模型原理以及服务端与前端通信机制,本文不做过多阐述,重点是如何用

    2024年02月13日
    浏览(29)
  • Android okHttp-sse 实现chatgpt逐字逐句效果

    1. 什么是SSE Server-Send Events 服务器发送事件,简称SSE。服务器主动向客户端推送消息,我们常见的有 WebSocket (SignalR) ,SSE 也是其中一种。     SSE 是HTML5规范的一部分,该规范非常简单,主要由两部分组成:第一部分是服务端与浏览器端的通讯协议(Http协议),第二部分是

    2024年02月07日
    浏览(48)
  • 用thinkphp+js模拟ChatGPT逐字打印的效果踩坑指南

    最近对ChatGPT里逐字输出的效果很感兴趣,起初以为是接口内容返回之后使用css+js实现的纯前端效果,深入一调研发现用的是Server-Sent Events(SSE)数据流实现的,看了sse的基本原理之后,就开始上手测试了,结果碰到一个小坑,卡了很久,这里分享一下: 直接问ChatGPT用thinkP

    2024年02月03日
    浏览(35)
  • ASP.NET Core Web API 流式返回,实现ChatGPT逐字显示

    🏆作者:科技、互联网行业优质创作者 🏆专注领域:.Net技术、软件架构、人工智能、数字化转型、DeveloperSharp、微服务、工业互联网、智能制造 🏆欢迎关注我(Net数字智慧化基地),里面有很多 高价值 技术文章, 是你刻苦努力也积累不到的经验 ,能助你快速成长。升职

    2024年02月22日
    浏览(43)
  • python+flask+eventSource打造流式chatGPT生成式API接口

    后端用python,前端用web,怎么打通chatGPT API连接? 如果你遇到这样的情况: 科学上网登chat.openai.com开启一个新聊天,总是出现网页错误,刷新几次就没有对话的想法了。 获取了chatGPT的APIkey,用网上一大堆PHP/JSP/CURL的代码去试,效果很差,不是反应慢,就是兼容性不好。 用

    2024年02月04日
    浏览(36)
  • ChatGPT 使用 拓展资料:吴恩达大咖 Building Systems with the ChatGPT API 输出检查

    ChatGPT 使用 拓展资料:吴恩达大咖 Building Systems with the ChatGPT API 输出检查 在本视频中,将重点检查系统生成的输出。在向用户展示输出之前检查输出对于确保质量非常重要,提供给他们的响应的相关性和安全性,或者使用自动化或学习如何使用Moderation API。 但这一节课中,使

    2024年02月08日
    浏览(43)
  • vue2中使用EventSource(EventSourcePolyfill)实现持续的消息推送

    需求:要实现一个 管理员启动、暂停、结束等一系列操作任务的时候,后端将消息通过EventSource传递给前端,前端展示出来 为什么要用EventSourcePolyfill,而不是EventSource? 答:因为在和后端建立连接的时候,需要传递token用来建立身份标识,而eventSource的官网没有找到相关传参

    2024年02月01日
    浏览(31)
  • OpenAI ChatGPT API + FaskAPI SSE Stream 流式周转技术 以及前端Fetch 流式请求获取案例

    这篇文章当时写得比较匆忙,这里进行一下更深入的补充 SSE 技术不是什么新鲜东西,就是一个 HTTP 请求和响应,关键就是响应这个环节,原始的响应都是一次性的,普通的响应是这样的: Nginx 是一个静态服务器,所谓静态服务器,就是将一个静态文件按照大小不同情况选择

    2024年02月08日
    浏览(37)
  • 【Qt】使用Qt实现Web服务器(九):EventSource+JSON实现工业界面数据刷新

    效果如下,实时刷新温度、湿度

    2024年04月08日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包