.NET 如何实现ChatGPT的Stream传输

net,如何,实现,chatgpt,stream,传输 · 浏览次数 : 589

小编点评

.NET 如何实现ChatGPT的Stream传输ChatGPT是如何实现不适用websocket进行一个一个字返回到前端的? 1. **EventSource 接口**是 Web 内容与服务器发送事件通信的接口。 2. **EventSource**实例会对 HTTP 服务器开启一个持久化的连接,以 **text/event-stream** 格式发送事件,此连接会一直保持开启直到通过调用 **EventSource.close()** 关闭。 3. **EventTarget** 是 **EventSource** 的实现,它将来自服务端传入的消息会以事件的形式分发至你代码中。 4. **EventSource**使用单向的模式,服务端可以向客户端发送事件,但客户端只能向服务端发送事件。 5. **IAsyncEnumerable** 是一个用于异步迭代的接口,它允许你迭代一个可无限流的序列。 **Client 的实现** ```javascript async function fetchAsStream(url, data) { const response = await fetch(url, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(data), }); if (!response.ok) { const reader = response.body?.getReader(); const { done, value } = await reader.read(); throw new Error(`Failed to fetch ${value}`); } if (!response.body) { throw new Error("ReadableStream not supported in this browser."); } const reader = response.body.getReader(); return { [Symbol.asyncIterator]() => { return { async next() { const { done, value } = await reader.read(); if (done) { return { done: true, value: null }; } return { done: false, value: new TextDecoder("utf-8").decode(value) }; }, }; }}; } ``` **效果** 当执行以下代码时,会发现控制台一个一个字显示内容: ```javascript var stream = await fetchAsStream("http://localhost:5255/stream"); for await (var c of stream) { console.log(c); } ```

正文

.NET 如何实现ChatGPT的Stream传输

ChatGPT是如何实现不适用websocket进行一个一个字返回到前端的?

下面我们会介绍一下EventSource

EventSource

EventSource 接口是 web 内容与服务器发送事件通信的接口。

一个 EventSource 实例会对 HTTP 服务器开启一个持久化的连接,以 text/event-stream 格式发送事件,此连接会一直保持开启直到通过调用 EventSource.close() 关闭。

EventTarget <= EventSource

一旦连接开启,来自服务端传入的消息会以事件的形式分发至你代码中。如果接收消息中有一个 event 字段,触发的事件与 event 字段的值相同。如果不存在 event 字段,则将触发通用的 message 事件。

WebSocket 不同的是,服务器发送事件是单向的。数据消息只能从服务端到发送到客户端(如用户的浏览器)。这使其成为不需要从客户端往服务器发送消息的情况下的最佳选择。例如,对于处理如社交媒体状态更新、消息来源(news feed)或将数据传递到客户端存储机制(如 IndexedDBweb 存储)之类的,EventSource 无疑是一个有效方案。

使用场景

  • ChatGPT的Stream式对话,可以一个字一个字相应,增加用户体验
  • 简单的大数据量的数据进行推送到客户端
  • 耗时并且持续化的数据传输

ASP.NET Core 实现

创建WebApi项目

Controllers中新建一个StreamController.cs文件,并且提供一个IAsyncEnumerable<out T>的Demo

  • IAsyncEnumerable<out T>
    • 公开对指定类型的值提供异步迭代的枚举器。

StreamController.cs

using Microsoft.AspNetCore.Mvc;

namespace WebApplication1.Controllers;

[ApiController]
[Route("[controller]")]
public class StreamController : ControllerBase
{
    [HttpPost]
    public async IAsyncEnumerable<char> Test()
    {
        const string value = "这是一个完整的测试数据;为了测试IAsyncEnumerable<T>的使用";

        foreach (var v in value)
        {
            await Task.Delay(500);
            yield return v;
        }

        await Task.CompletedTask;
    }
}

上面案例的接口使用了IAsyncEnumerable<char>,作为返回值,将value字符串一个一个字符返回到前端。

每次返回等待500,这是服务端的实现,下面写客户端的实现,客户端也是用.NET

使用js实现调用

首先启动api服务,然后在打开的swagger的浏览器界面中打开开发者工具使用F12打开开发者工具

在控制台中添加fetchAsStream方法用于调用IAsyncEnumerable<char>的接口服务,代码如下

async function fetchAsStream(url,data) {
    const response = await fetch(url, {
      method: "POST",
      headers: {
        "Content-Type": "application/json"
      },
      body: JSON.stringify(data),
    });
    if (!response.ok) {
      const reader = response.body?.getReader();
      const { done, value } = await reader.read();
      throw new Error(
        `Failed to fetch `
      );
    }
    if (!response.body) {
      throw new Error("ReadableStream not supported in this browser.");
    }

    const reader = response.body.getReader();
    return {
      [Symbol.asyncIterator]() {
        return {
          async next() {
            const { done, value } = await reader.read();
            if (done) {
              return { done: true, value: null };
            }
            return {
              done: false,
              value: new TextDecoder("utf-8").decode(value),
            };
          },
        };
      },
    };

  }

输入完成按回车键会显示一个undefined

然后下一步就调用这个方法,当执行下面这个代码会发现控制台会一个一个字显示内容。

var stream =  await fetchAsStream("http://localhost:5255/stream");

for await(var c of stream){
    console.log(c);
}

看效果控制台的字在一个一个输出,请注意不要使用axios,默认是不支持的。

结尾

来自token的分享

技术交流群:737776595

与.NET 如何实现ChatGPT的Stream传输相似的内容:

.NET 如何实现ChatGPT的Stream传输

# .NET 如何实现ChatGPT的Stream传输 ChatGPT是如何实现不适用websocket进行一个一个字返回到前端的? 下面我们会介绍一下`EventSource` ## EventSource **`EventSource`** 接口是 web 内容与[服务器发送事件](https:

使用.NET查询日出日落时间

在WPF中,通过资源文件实现主题切换是个常见的功能,有不少文章介绍了如何实现手动切换主题。那如何实现自动切换主题呢?通常有两种机制:一是跟随系统明暗主题切换,二是像手机操作系统那样根据日出日落时间自动切换。本文将以终为始,采用倒推法一步步介绍如何使用.NET免费获取日出日落时间。 获取日出日落时间

【Azure 应用服务】在App Service for Windows中实现反向代理

问题描述 如何在App Service for Windows(.NET Stack)中,如何实现反向代理呢? 正向代理:客户端想要访问一个服务器,但是它可能无法直接访问这台服务器,这时候这可找一台可以访问目标服务器的另外一台服务器,而这台服务器就被当做是代理人的角色 ,称之为代理服务器,于是客户端

[转帖]Keepalived如何实现Nginx高可用

https://www.jb51.net/article/266305.htm Keepalived安装可参考Mysql+Keepalived实现双主热备 Master上的keepalived.conf 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

[转帖]什么是负载均衡?DNS如何实现负载均衡?

https://blog.csdn.net/weixin_53018687/category_11107683.html 在配置域名解析的时候,我们可以将一个域名指向多个IP吗?答案是可以的,这也是我们通过DNS实现负载均衡的常见做法。 一、什么是负载均衡? 一些大型的视频、游戏网站或应用,每时每刻

直播预约|漫漫用户增长之路,如何快人一手

![](https://oscimg.oschina.net/oscnet/up-7fdd8d6d86b797b2041a2cda61ede5145c2.jpg) **【导读】** 如何实现用户增长及提升用户活跃度是各大开发者关注的重点之一,日常运营过程中,消息推送作为一个触达用户的有效手段,通过恰

在.NET Core,除了VB的LikeString,还有其它方法吗?(四种LikeString实现分享)

Like运算符很好用,特别是它所提供的其中*、?这两种通配符,在Windows文件系统和各类项目中运用非常广泛。 但Like运算符仅在VB中支持,在C#中,如何实现呢? 以下是关于LikeString的四种实现方式,其中第四种为Regex正则表达式实现,且在.NET Standard 2.0及以上平...

Windows 虚拟地址 到底是如何映射到 物理地址 的?

## 一:背景 ### 1. 讲故事 我发现有很多的 .NET程序员 写了很多年的代码都没弄清楚什么是 `虚拟地址`,更不用谈什么是 `物理地址` 以及Windows是如何实现地址映射的了?这一篇我们就来聊一聊这两者之间的联系。 ## 二:地址映射研究 ### 1. 找虚拟地址 怎么去找 `虚拟地址

.NET周刊【9月第1期 2023-09-03】

## 国内文章 ### 如何正确实现一个自定义 Exception https://www.cnblogs.com/kklldog/p/how-to-design-exception.html 最近在公司的项目中,编写了几个自定义的 Exception 类。提交 PR 的时候,sonarqube 提

.Net Core 如何数据导出 Excel?(EPPlus->OfficeOpenXml 实现固定列和动态列导出)

对于将数据以 Excel 表格文件输出,还是比较常用的,也存在诸多情况,比如列固定或不固定、数据类型为 List