ASP.NET Core Web API 流式返回,实现ChatGPT逐字显示
时间:2024-03-30 14:10:53 来源:网络cs 作者:付梓 栏目:卖家故事 阅读:
🏆作者:科技、互联网行业优质创作者
🏆专注领域:.Net技术、软件架构、人工智能、数字化转型、DeveloperSharp、微服务、工业互联网、智能制造
🏆欢迎关注我(Net数字智慧化基地),里面有很多高价值技术文章,是你刻苦努力也积累不到的经验,能助你快速成长。升职+涨薪!!
Websocket、SSE(Server-Sent Events)和长轮询(Long Polling)都是用于网页和服务端通信的技术。
Websocket是一种全双工通信协议,能够实现客户端和服务端之间的实时通信。它基于TCP协议,并且允许服务器主动向客户端推送数据,同时也允许客户端向服务器发送数据。
SSE是一种单向通信协议,允许服务器向客户端推送数据,但不支持客户端向服务器发送数据。SSE建立在HTTP协议上,通过在HTTP响应中使用特殊的Content-Type和事件流(event stream)格式来实现。
长轮询是一种技术,客户端向服务器发送一个请求,并且服务器保持连接打开直到有数据可以返回给客户端。如果在指定的时间内没有数据可用,则服务器会关闭连接,客户端需要重新建立连接并再次发起请求。
New Bing聊天页面是通过WebSocket进行通信。
Open AI的ChatGPT接口则是通过SSE协议由服务端推送数据
事实上,以上几种方式包括长轮询,都可以实现逐字显示的效果。那还有没有其他的办法可以实现这种效果了呢?
流式响应
当客户端返回流的时候,客户端可以实时捕获到返回的信息,并不需要等全部Response结束了再处理。
下面就用ASP.NET Core Web API作为服务端实现流式响应。
返回文本内容
服务端
[HttpPost("text")]public async Task Post(){ string filePath = "文档.txt"; Response.ContentType = "application/octet-stream"; var reader = new StreamReader(filePath); var buffer = new Memory<char>(new char[5]); int writeLength = 0; //每次读取5个字符写入到流中 while ((writeLength = await reader.ReadBlockAsync(buffer)) > 0) { if (writeLength < buffer.Length) { buffer = buffer[..writeLength]; } await Response.WriteAsync(buffer.ToString()); await Task.Delay(100); }}
客户端
C# HttpClient
public async void GetText(){ var url = "http://localhost:5000/config/text"; var client = new HttpClient(); using HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, url); var response = await client.SendAsync(httpRequestMessage, HttpCompletionOption.ResponseHeadersRead); await using var stream = await response.Content.ReadAsStreamAsync(); var bytes = new byte[20]; int writeLength = 0; while ((writeLength = stream.Read(bytes, 0, bytes.Length)) > 0) { Console.Write(Encoding.UTF8.GetString(bytes, 0, writeLength)); } Console.WriteLine(); Console.WriteLine("END");}
HttpCompletionOption
枚举有两个值,默认情况下使用的是ResponseContentRead
ResponseContentRead
:等到整个响应完成才完成操作
ResponseHeadersRead
:一旦获取到响应头即完成操作,不用等到整个内容响应
js XMLHttpRequest
<script> var div = document.getElementById("content") var url = "http://localhost:5000/config/text" var client = new XMLHttpRequest() client.open("POST", url) client.onprogress = function (progressEvent) { div.innerText = progressEvent.target.responseText } client.onloadend = function (progressEvent) { div.append("END") } client.send()</script>
用axios请求就是监听onDownloadProgress
了。
浏览器是通过
Response Header
中的Content-Type
来解析服务端响应体的。如果后端接口没有设置Response.ContentType = "application/octet-stream"
,onprogress
只会在响应全部完成后触发。
返回图片
服务端
[HttpGet("img")]public async Task Stream(){ string filePath = "pixelcity.png"; new FileExtensionContentTypeProvider().TryGetContentType(filePath, out string contentType); Response.ContentType = contentType ?? "application/octet-stream"; var fileStream = System.IO.File.OpenRead(filePath); var bytes = new byte[1024]; int writeLength = 0; while ((writeLength = fileStream.Read(bytes, 0, bytes.Length)) > 0) { await Response.Body.WriteAsync(bytes, 0, writeLength); await Task.Delay(100); }}
🏆欢迎关注我(Net数字智慧化基地),里面有很多高价值技术文章,是你刻苦努力也积累不到的经验,能助你升职+涨薪!!
🏆点击下方卡片关注公众号,里面有很多大佬的技术文章,能助你快速成长。还可免费领取如下15个视频教程!回复'面试',获取C#/.NET/.NET Core面试宝典
回复'C#',领取零基础学习C#编程
回复'NET',领取.NET零基础入门到实战
回复'Linux',领取Linux从入门到精通
回复'wpf',领取高薪热门【WPF上位机+工业互联网】从零手写实战
回复'Modbus',领取初识C#+上位机Modbus通信
回复'PLC',领取C#语言与西门子PLC的通信实操
回复'blazor',领取blazor从入门到实战
回复'TypeScript',领取前端热门TypeScript系统教程
回复'vue',领取vue前端从入门到精通
回复'23P',领取C#实现23种常见设计模式
回复'MongoDB',领取MongoDB实战
回复'Trans',领取分布式事务
回复'Lock',领取分布式锁实践
回复'Docker',领取微服务+Docker综合实战
回复'K8s',领取K8s部署微服务
回复'加群',进.NET技术社区交流群
阅读本书更多章节>>>>
本文链接:https://www.kjpai.cn/gushi/2024-03-30/150909.html,文章来源:网络cs,作者:付梓,版权归作者所有,如需转载请注明来源和作者,否则将追究法律责任!