From 8b0cf7d248bd3582c619f9337f711076caa75532 Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Tue, 16 May 2023 00:22:11 +0800 Subject: [PATCH 1/3] fix: #1509 openai url split --- app/client/platforms/openai.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/client/platforms/openai.ts b/app/client/platforms/openai.ts index 4bdf9e056..a69e8e3ce 100644 --- a/app/client/platforms/openai.ts +++ b/app/client/platforms/openai.ts @@ -10,8 +10,10 @@ export class ChatGPTApi implements LLMApi { public SubsPath = "dashboard/billing/subscription"; path(path: string): string { - const openaiUrl = useAccessStore.getState().openaiUrl; - if (openaiUrl.endsWith("/")) openaiUrl.slice(0, openaiUrl.length - 1); + let openaiUrl = useAccessStore.getState().openaiUrl; + if (openaiUrl.endsWith("/")) { + openaiUrl = openaiUrl.slice(0, openaiUrl.length - 1); + } return [openaiUrl, path].join("/"); } From aed6b349507dce2bdca77756db52bca88db268a9 Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Tue, 16 May 2023 01:25:16 +0800 Subject: [PATCH 2/3] fix: #1498 missing text caused by streaming --- app/client/platforms/openai.ts | 57 +++++++++++++--------------------- package.json | 1 + yarn.lock | 5 +++ 3 files changed, 28 insertions(+), 35 deletions(-) diff --git a/app/client/platforms/openai.ts b/app/client/platforms/openai.ts index a69e8e3ce..cc1ecb919 100644 --- a/app/client/platforms/openai.ts +++ b/app/client/platforms/openai.ts @@ -3,6 +3,7 @@ import { useAccessStore, useAppConfig, useChatStore } from "@/app/store"; import { ChatOptions, getHeaders, LLMApi, LLMUsage } from "../api"; import Locale from "../../locales"; +import { fetchEventSource } from "@microsoft/fetch-event-source"; export class ChatGPTApi implements LLMApi { public ChatPath = "v1/chat/completions"; @@ -71,40 +72,20 @@ export class ChatGPTApi implements LLMApi { options.onFinish(responseText); }; - const res = await fetch(chatPath, chatPayload); - clearTimeout(reqestTimeoutId); - - if (res.status === 401) { - responseText += "\n\n" + Locale.Error.Unauthorized; - return finish(); - } - - if ( - !res.ok || - !res.headers.get("Content-Type")?.includes("stream") || - !res.body - ) { - return options.onError?.(new Error()); - } - - const reader = res.body.getReader(); - const decoder = new TextDecoder("utf-8"); - - while (true) { - const { done, value } = await reader.read(); - if (done) { - return finish(); - } - - const chunk = decoder.decode(value, { stream: true }); - const lines = chunk.split("data: "); - - for (const line of lines) { - const text = line.trim(); - if (line.startsWith("[DONE]")) { + fetchEventSource(chatPath, { + ...chatPayload, + async onopen(res) { + clearTimeout(reqestTimeoutId); + if (res.status === 401) { + responseText += "\n\n" + Locale.Error.Unauthorized; return finish(); } - if (text.length === 0) continue; + }, + onmessage(msg) { + if (msg.data === "[DONE]") { + return finish(); + } + const text = msg.data; try { const json = JSON.parse(text); const delta = json.choices[0].delta.content; @@ -113,10 +94,16 @@ export class ChatGPTApi implements LLMApi { options.onUpdate?.(responseText, delta); } } catch (e) { - console.error("[Request] parse error", text, chunk); + console.error("[Request] parse error", text, msg); } - } - } + }, + onclose() { + finish(); + }, + onerror(e) { + options.onError?.(e); + }, + }); } else { const res = await fetch(chatPath, chatPayload); clearTimeout(reqestTimeoutId); diff --git a/package.json b/package.json index 07ba977ea..f9d3c3c72 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ }, "dependencies": { "@hello-pangea/dnd": "^16.2.0", + "@microsoft/fetch-event-source": "^2.0.1", "@svgr/webpack": "^6.5.1", "@vercel/analytics": "^0.1.11", "emoji-picker-react": "^4.4.7", diff --git a/yarn.lock b/yarn.lock index 5240d7e77..e54a69e48 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1111,6 +1111,11 @@ dependencies: "@types/react" ">=16.0.0" +"@microsoft/fetch-event-source@^2.0.1": + version "2.0.1" + resolved "https://registry.npmmirror.com/@microsoft/fetch-event-source/-/fetch-event-source-2.0.1.tgz#9ceecc94b49fbaa15666e38ae8587f64acce007d" + integrity sha512-W6CLUJ2eBMw3Rec70qrsEW0jOm/3twwJv21mrmj2yORiaVmVYGS4sSS5yUwvQc1ZlDLYGPnClVWmUUMagKNsfA== + "@next/env@13.4.2": version "13.4.2" resolved "https://registry.npmmirror.com/@next/env/-/env-13.4.2.tgz#cf3ebfd523a33d8404c1216e02ac8d856a73170e" From 71cbf86b2c8e21407045ba848ba38237134b837d Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Tue, 16 May 2023 01:58:58 +0800 Subject: [PATCH 3/3] fixup: add more error info --- app/api/auth.ts | 5 ++--- app/client/platforms/openai.ts | 13 +++++++++++++ app/store/chat.ts | 4 +--- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/app/api/auth.ts b/app/api/auth.ts index 1005c5fff..62fcd2262 100644 --- a/app/api/auth.ts +++ b/app/api/auth.ts @@ -43,8 +43,7 @@ export function auth(req: NextRequest) { if (serverConfig.needCode && !serverConfig.codes.has(hashedCode) && !token) { return { error: true, - needAccessCode: true, - msg: "Please go settings page and fill your access code.", + msg: !accessCode ? "empty access code" : "wrong access code", }; } @@ -58,7 +57,7 @@ export function auth(req: NextRequest) { console.log("[Auth] admin did not provide an api key"); return { error: true, - msg: "Empty Api Key", + msg: "admin did not provide an api key", }; } } else { diff --git a/app/client/platforms/openai.ts b/app/client/platforms/openai.ts index cc1ecb919..99f365202 100644 --- a/app/client/platforms/openai.ts +++ b/app/client/platforms/openai.ts @@ -4,6 +4,7 @@ import { useAccessStore, useAppConfig, useChatStore } from "@/app/store"; import { ChatOptions, getHeaders, LLMApi, LLMUsage } from "../api"; import Locale from "../../locales"; import { fetchEventSource } from "@microsoft/fetch-event-source"; +import { prettyObject } from "@/app/utils/format"; export class ChatGPTApi implements LLMApi { public ChatPath = "v1/chat/completions"; @@ -72,12 +73,24 @@ export class ChatGPTApi implements LLMApi { options.onFinish(responseText); }; + controller.signal.onabort = finish; + fetchEventSource(chatPath, { ...chatPayload, async onopen(res) { clearTimeout(reqestTimeoutId); if (res.status === 401) { + let extraInfo = { error: undefined }; + try { + extraInfo = await res.clone().json(); + } catch {} + responseText += "\n\n" + Locale.Error.Unauthorized; + + if (extraInfo.error) { + responseText += "\n\n" + prettyObject(extraInfo); + } + return finish(); } }, diff --git a/app/store/chat.ts b/app/store/chat.ts index 9257d2633..9bb9a8039 100644 --- a/app/store/chat.ts +++ b/app/store/chat.ts @@ -296,9 +296,7 @@ export const useChatStore = create()( botMessage.content !== Locale.Error.Unauthorized && !isAborted ) { - botMessage.content += "\n\n" + Locale.Store.Error; - } else if (botMessage.content.length === 0) { - botMessage.content = prettyObject(error); + botMessage.content += "\n\n" + prettyObject(error); } botMessage.streaming = false; userMessage.isError = !isAborted;