mirror of
https://github.com/Yidadaa/ChatGPT-Next-Web.git
synced 2025-08-08 04:35:23 +08:00
merge main
This commit is contained in:
@@ -10,6 +10,7 @@ import {
|
||||
fetchEventSource,
|
||||
} from "@fortaine/fetch-event-source";
|
||||
import { prettyObject } from "./format";
|
||||
import { fetch as tauriFetch } from "./stream";
|
||||
|
||||
export function compressImage(file: Blob, maxSize: number): Promise<string> {
|
||||
return new Promise((resolve, reject) => {
|
||||
@@ -221,7 +222,7 @@ export function stream(
|
||||
),
|
||||
)
|
||||
.then((res) => {
|
||||
const content = JSON.stringify(res.data);
|
||||
let content = res.data || res?.statusText;
|
||||
if (res.status >= 300) {
|
||||
return Promise.reject(content);
|
||||
}
|
||||
@@ -236,7 +237,11 @@ export function stream(
|
||||
return content;
|
||||
})
|
||||
.catch((e) => {
|
||||
options?.onAfterTool?.({ ...tool, isError: true });
|
||||
options?.onAfterTool?.({
|
||||
...tool,
|
||||
isError: true,
|
||||
errorMsg: e.toString(),
|
||||
});
|
||||
return e.toString();
|
||||
})
|
||||
.then((content) => ({
|
||||
@@ -288,6 +293,7 @@ export function stream(
|
||||
REQUEST_TIMEOUT_MS,
|
||||
);
|
||||
fetchEventSource(chatPath, {
|
||||
fetch: tauriFetch as any,
|
||||
...chatPayload,
|
||||
async onopen(res) {
|
||||
clearTimeout(requestTimeoutId);
|
||||
|
@@ -1,19 +0,0 @@
|
||||
import { getClientConfig } from "../config/client";
|
||||
import { DEFAULT_API_HOST } from "../constant";
|
||||
|
||||
export function corsPath(path: string) {
|
||||
const baseUrl = getClientConfig()?.isApp ? `${DEFAULT_API_HOST}` : "";
|
||||
|
||||
if (baseUrl === "" && path === "") {
|
||||
return "";
|
||||
}
|
||||
if (!path.startsWith("/")) {
|
||||
path = "/" + path;
|
||||
}
|
||||
|
||||
if (!path.endsWith("/")) {
|
||||
path += "/";
|
||||
}
|
||||
|
||||
return `${baseUrl}${path}`;
|
||||
}
|
107
app/utils/stream.ts
Normal file
107
app/utils/stream.ts
Normal file
@@ -0,0 +1,107 @@
|
||||
// using tauri command to send request
|
||||
// see src-tauri/src/stream.rs, and src-tauri/src/main.rs
|
||||
// 1. invoke('stream_fetch', {url, method, headers, body}), get response with headers.
|
||||
// 2. listen event: `stream-response` multi times to get body
|
||||
|
||||
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>;
|
||||
};
|
||||
|
||||
export function fetch(url: string, options?: RequestInit): Promise<any> {
|
||||
if (window.__TAURI__) {
|
||||
const {
|
||||
signal,
|
||||
method = "GET",
|
||||
headers: _headers = {},
|
||||
body = [],
|
||||
} = options || {};
|
||||
let unlisten: Function | undefined;
|
||||
let setRequestId: Function | undefined;
|
||||
const requestIdPromise = new Promise((resolve) => (setRequestId = resolve));
|
||||
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));
|
||||
});
|
||||
};
|
||||
|
||||
if (signal) {
|
||||
signal.addEventListener("abort", () => close());
|
||||
}
|
||||
// @ts-ignore 2. listen response multi times, and write to Response.body
|
||||
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) {
|
||||
// end of body
|
||||
close();
|
||||
}
|
||||
}),
|
||||
)
|
||||
.then((u: Function) => (unlisten = u));
|
||||
|
||||
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];
|
||||
}
|
||||
return window.__TAURI__
|
||||
.invoke("stream_fetch", {
|
||||
method: method.toUpperCase(),
|
||||
url,
|
||||
headers,
|
||||
// TODO FormData
|
||||
body:
|
||||
typeof body === "string"
|
||||
? Array.from(new TextEncoder().encode(body))
|
||||
: [],
|
||||
})
|
||||
.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);
|
||||
throw e;
|
||||
});
|
||||
}
|
||||
return window.fetch(url, options);
|
||||
}
|
Reference in New Issue
Block a user