大模型落地开发实战指南!请关注微信公众号:「AGI启程号」 深入浅出,助你轻松入门!
数据分析、深度学习、大模型与算法的综合进阶,尽在CSDN博客主页
\app\utils\stream.ts
的逐步详细解析,帮助你深入理解该文件在 NextChat 中的作用以及具体逻辑:
此文件的主要作用是在Tauri环境中,封装一个自定义的流式网络请求函数fetch
,替代浏览器原生的fetch
函数,以实现通过Tauri后端与外部API交互。
核心功能:
stream_fetch
命令发起HTTP请求。stream-response
)逐步接收数据块。Response
对象。fetch
函数。该文件无外部依赖,仅使用了内置类型定义:
type ResponseEvent = {
id: number;
payload: {
request_id: number;
status?: number;
chunk?: number[];
};
};
type StreamResponse = {
request_id: number;
status: number;
status_text: string;
headers: Record<string, string>;
};
ResponseEvent
:后端推送的事件数据格式(流式数据块)。StreamResponse
:后端invoke("stream_fetch")
命令返回的请求初始响应(头信息等)。fetch(url, options)
函数签名:
export function fetch(url: string, options?: RequestInit): Promise<Response>
功能:
stream_fetch
发起HTTP请求。fetch
请求。fetch
函数详细步骤解析if (window.__TAURI__) {
const {
signal,
method = "GET",
headers: _headers = {},
body = [],
} = options || {};
window.__TAURI__
标识是否存在,判断是否为Tauri环境。TransformStream
)const ts = new TransformStream();
const writer = ts.writable.getWriter();
let closed = false;
const close = () => {
if (closed) return;
closed = true;
unlisten && unlisten();
writer.ready.then(() => {
writer.close().catch((e) => console.error(e));
});
};
stream-response
window.__TAURI__.event
.listen("stream-response", (e: ResponseEvent) =>
requestIdPromise.then((request_id) => {
const { request_id: rid, chunk, status } = e?.payload || {};
if (request_id != rid) return;
if (chunk) {
writer.ready.then(() => {
writer.write(new Uint8Array(chunk));
});
} else if (status === 0) {
// 流结束标志
close();
}
}),
)
.then((u: Function) => (unlisten = u));
作用:
chunk
),则逐步写入到数据流(writer
)中。status === 0
表示流结束,则关闭数据流。const headers: Record<string, string> = {
Accept: "application/json, text/plain, */*",
"Accept-Language": "en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7",
"User-Agent": navigator.userAgent,
};
for (const item of new Headers(_headers || {})) {
headers[item[0]] = item[1];
}
stream_fetch
)return window.__TAURI__
.invoke("stream_fetch", {
method: method.toUpperCase(),
url,
headers,
body:
typeof body === "string"
? Array.from(new TextEncoder().encode(body))
: [],
})
stream_fetch
方法,发送实际HTTP请求。body
)转换为Uint8Array
数组格式发送。Response
对象.then((res: StreamResponse) => {
const { request_id, status, status_text: statusText, headers } = res;
setRequestId?.(request_id);
const response = new Response(ts.readable, {
status,
statusText,
headers,
});
if (status >= 300) {
setTimeout(close, 100);
}
return response;
})
.catch((e) => {
console.error("stream error", e);
return new Response("", { status: 599 });
});
Response
对象。ts.readable
)作为Response的body
,实现逐步获取数据。return window.fetch(url, options);
fetch
请求,保证函数通用性。客户端调用fetch()函数
│
├─Tauri环境?
│ ├─ 是 → 调用Tauri后端`stream_fetch`发起请求
│ │ ├─监听后端返回的`stream-response`事件
│ │ │ ├─ 接收数据块(chunk)→写入数据流(TransformStream)
│ │ │ ├─ 接收到流结束标志(status=0)→关闭数据流
│ │ └─ 使用数据流构造Response对象,返回给调用方
│ └─ 否 → 使用浏览器原生fetch()发起请求
└─ 请求完成 → 返回Response对象
Python风格伪代码模拟:
def fetch(url, method="GET", headers=None, body=None):
if is_tauri_env():
stream = TransformStream()
tauri_response = tauri.invoke("stream_fetch", url, method, headers, body)
def on_stream_event(event):
if event.chunk:
stream.write(event.chunk)
if event.status == 0:
stream.close()
tauri.listen("stream-response", on_stream_event)
response = Response(stream.readable, status=tauri_response.status)
return response
else:
return native_fetch(url, method, headers, body)
stream.ts
文件封装了一个兼容Tauri环境和浏览器环境的HTTP请求工具:
TransformStream
将流式数据逐步推送给前端。通过以上详细解析,帮助你更好地理解 NextChat 在不同环境下的数据请求实现机制!
客户端请求 -> API路由入口([provider]/[…path]/route.ts)
路由分发到特定提供商处理器(openai.ts等)
身份验证与访问控制(auth.ts)
请求转发到实际服务提供商(common.ts中的requestOpenai等函数)
响应处理与返回给客户端
NextChat支持多种LLM提供商(OpenAI、Azure、Claude等),通过不同的处理器来处理各提供商的请求格式差异。
支持访问码验证:用户可以使用ACCESS_CODE_PREFIX开头的访问码
多密钥支持:系统会根据请求的模型提供商选择对应的系统API密钥
用户API密钥:可以配置是否允许用户使用自己的API密钥
路径重写:将NextChat内部路径映射到各服务提供商的API路径
头部处理:正确设置Authorization和其他必要的请求头
超时控制:设置请求超时时间,防止请求无限等待
通过customModels配置可以限制某些模型的使用,例如禁用GPT-4或只允许特定模型。
动态路由机制:利用Next.js的动态路由处理不同API路径
无服务器函数:使用Edge Runtime优化性能
请求转发:维护API兼容性的同时实现对多服务的支持
响应流处理:支持流式响应(Stream),允许增量返回生成内容
配置灵活性:通过环境变量和服务器配置提供高度自定义能力
通过这种设计,NextChat能够作为各种LLM服务的统一前端,同时保持API的一致性和可扩展性。