更新时间:2023年03月27日 08:56:54 作者:扫地盲僧
这篇文章主要为大家介绍了微信小程序如何实现类似的流式传输示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
目录
正文
最近指导群里小兄弟技术问题,发现一个让我也棘手的难题。于是激发了我潜意识精神力-干到底。 由于最近沉浸在中,很久不用和百度搜索东西了,正如我所料一般,他们也没有这方面的解决方案。于是,记录一下探索研究的过程,给各位水友一个分享扩展。
小程序上实现流失传输
模拟的效果,实现流式传输,通过处理流数据,实现打字机的效果。
什么是流式传输?
在解决问题之前,我们需要了解什么是流式传输。流式传输指的是将数据分成多个数据流,通过网络传输,以减少网络延迟和提高性能。在某些情况下,流式传输也可以用于将视频流和音频流传输到客户端。流式传输是一种高效的数据传输方式,常用于大文件下载和在线视频播放等场景。
为什么小程序不支持流式传输?
尽管流式传输在某些情况下非常有用,但小程序目前不支持流式传输。主要原因是小程序的架构和限制。
小程序的开发框架提供了一个小程序的开发和调试环境。在这个环境中,小程序的代码和资源都是打包在一个文件中的。这意味着小程序依赖此框架的环境,无法调用浏览器标准的API,需要框架的整体升级和支持。
此外,小程序对网络请求的限制也是一个因素。小程序中的网络请求必须使用微信提供的API,这些API通常只支持完整的请求和响应。这就使得小程序无法使用流式传输。
我的解决方案
但这些都是常规方案,实现也比较麻烦,把正常的请求复杂化了。抛弃~
常规方案Axios
基础html模式就不列举了,axios更便捷,我很自信这个方案可行性。
重点:
request({ url: '/api/prompt', //请求头需要改为stream模式 headers: { Accept: 'text/event-stream', }, //响应类型设置stream responseType: 'stream', method: 'POST', data: { prompt: prompt, }, }).then(res => { console.log(res) }).catch(err => { console.log(err) })
他们又问我要打字机效果,我的方案:接收到以后解码数据。
.then((res) => { const arrayBuffer = res.data; const uint8Array = new Uint8Array(arrayBuffer); const textDecoder = new TextDecoder('utf-8'); const text = textDecoder.decode(uint8Array); for (let i = 0; i { resultText += text[i]; console.log(resultText); }, i * 100); } })
ok,浏览器没问题,小程序调试工具没问题,我依旧自信我的方案
但是,小程序报错了,无法打印流数据,无法支持方法。完犊子,顾问成瞎指挥了。
另辟蹊径:方案
微信官方文档中提到, wx.中支持分段式传输
重点:
const requestTask = wx.request({ url: '/api/prompt', //请求头需要改为stream模式 header: { "Transfer-Encoding": 'chunked' }, timeout: 15000, responseType: 'text', method: 'POST', enableChunked: true, data: { prompt: prompt, }, }).then(res => { console.log(res) }).catch(err => { console.log(err) })
这样,我们就发起了流式传输请求,当然后端也要支持的,后面我会举例子。
当他们执行时,又出问题了,搞不定替代方案。我查了一下,好像有个方案,小不自信了。 使用””替代库,然后给出建议:
import {TextEncoder, TextDecoder} from "fastestsmallesttextencoderdecoder"; const encode = (new TextEncoder).encode; const decode = (new TextDecoder).decode;
等了一天没找我,哼哼,小菜一碟,完工。
这边又来了,大佬你的方法不好使,引入执行又又报错了。
稳住别慌… 试试手写转方案:text- 然后亲自测试,搞不定就把-plus关掉。
最终版:
let buffer='' requestTask.onChunkReceived(function (response) { const arrayBuffer = response.data; const uint8Array = new Uint8Array(arrayBuffer); let text = String.fromCharCode.apply(null, uint8Array); buffer += text; full_command.value = buffer })
其实,第二个方案是可行的,只是我也没时间具体看报了什么错误。最终使用了的方法,恰好可以处理,当然还一些过滤和解码,根据业务需要写了。
后端接口配置
后端配置教程比较多,主要是添加请求头,支持分段传输的方式。
public static function prompt($message) { $openAi = self::getOpenAI(); header('Access-Control-Allow-Credentials: true'); // 设置响应头信息 header('Transfer-Encoding: chunked'); header('Content-Type: text/plain'); header('Cache-Control: no-cache'); header('Access-Control-Allow-Methods: GET, POST, OPTIONS'); header('Access-Control-Allow-Headers: Content-Type'); header('Connection: keep-alive'); $msg = ""; $openAi->prompt([ 'messages' => $message, 'model' => 'gpt-3.5-turbo', "stream" => true, ], function ($curl_info, $response) { //闭包函数处理流 $data = []; $lines = explode("n", $response); foreach ($lines as $line) { if (!str_contains($line, ':')) { continue; } [$name, $value] = explode(':', $line, 2); if ($name == 'data') { $data[] = trim($value); } } foreach ($data as $message) { if ('[DONE]' === $message) { echo "0rnrn"; } else { $message = json_decode($message, true); $input = $message['choices'][0]['delta']['content'] ?? ''; $msg .= $input; echo dechex(strlen($msg)) . "rn" . $msg . "rn"; } } ob_flush(); flush(); return strlen($response); }); }
至此,整个浏览已完成,相信有技术嗅觉的小伙伴一定会大有所用。目前,还没有看到太多小程序支持流的平替方案,至少md格式,代码高亮,打字效果处理成和官网一样的交互,还是比较棘手的。不过可以试试这个,我用着还挺好,起码交互上。后面还会发一个整合所有平替的分享,大家可以嫖到老。
以上就是详解小程序如何实现类似的流式传输的详细内容,更多关于小程序流式传输的资料请关注脚本之家其它相关文章!