From bf8426952079e9a116ad0e273c73612f0fa00e77 Mon Sep 17 00:00:00 2001 From: akira-cn Date: Fri, 10 Nov 2023 20:38:53 +0800 Subject: [PATCH 1/9] fix: remove the content-encoding header --- app/api/common.ts | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/app/api/common.ts b/app/api/common.ts index adec611b2b3..e95bb483625 100644 --- a/app/api/common.ts +++ b/app/api/common.ts @@ -106,6 +106,12 @@ export async function requestOpenai(req: NextRequest) { // to disable nginx buffering newHeaders.set("X-Accel-Buffering", "no"); + // The latest version of the OpenAI API forced the content-encoding to be "br" in json response + // So if the streaming is disabled, we need to remove the content-encoding header + // But vercel uses gzip to compress the response + // So we need to remove the content-encoding header + newHeaders.delete("content-encoding"); + return new Response(res.body, { status: res.status, statusText: res.statusText, From dd6e79922a455862d6ae5c0a9469680d5c9e1d90 Mon Sep 17 00:00:00 2001 From: akira-cn Date: Fri, 10 Nov 2023 20:42:12 +0800 Subject: [PATCH 2/9] fix: remove the content-encoding header --- app/api/common.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/api/common.ts b/app/api/common.ts index e95bb483625..9f786c40300 100644 --- a/app/api/common.ts +++ b/app/api/common.ts @@ -108,8 +108,8 @@ export async function requestOpenai(req: NextRequest) { // The latest version of the OpenAI API forced the content-encoding to be "br" in json response // So if the streaming is disabled, we need to remove the content-encoding header - // But vercel uses gzip to compress the response - // So we need to remove the content-encoding header + // Because Vercel uses gzip to compress the response, if we don't remove the content-encoding header + // The browser will try to decode the response with brotli and fail newHeaders.delete("content-encoding"); return new Response(res.body, { From 24d7dc9bf91f1f0513dd831a2ea7e60fc2612515 Mon Sep 17 00:00:00 2001 From: Rocky <40670362@qq.com> Date: Mon, 18 Dec 2023 20:34:37 +0800 Subject: [PATCH 3/9] Update api.ts to set proper header "Accept" So it can work fine for some GPT forward service. --- app/client/api.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/app/client/api.ts b/app/client/api.ts index eedd2c9ab48..9f2a4b4e939 100644 --- a/app/client/api.ts +++ b/app/client/api.ts @@ -130,6 +130,7 @@ export function getHeaders() { const headers: Record = { "Content-Type": "application/json", "x-requested-with": "XMLHttpRequest", + "Accept": "application/json", }; const isAzure = accessStore.provider === ServiceProvider.Azure; From 64a8ba6212562bbe1335a9e436830f68afa04983 Mon Sep 17 00:00:00 2001 From: H0llyW00dzZ Date: Wed, 27 Dec 2023 22:43:48 +0700 Subject: [PATCH 4/9] Chore [Package] Downgrade Tauri Builder Version (#3656) - [+] chore(package.json): update @tauri-apps/cli devDependency to version 1.5.7 - [+] chore(yarn.lock): update @tauri-apps/cli versions to 1.5.7 --- package.json | 2 +- yarn.lock | 128 +++++++++++++++++++++++++-------------------------- 2 files changed, 65 insertions(+), 65 deletions(-) diff --git a/package.json b/package.json index 738e22ecc85..102461b314f 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "zustand": "^4.3.8" }, "devDependencies": { - "@tauri-apps/cli": "^1.5.8", + "@tauri-apps/cli": "1.5.7", "@types/node": "^20.9.0", "@types/react": "^18.2.14", "@types/react-dom": "^18.2.7", diff --git a/yarn.lock b/yarn.lock index e608eda15a7..5469672db2b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1431,71 +1431,71 @@ dependencies: tslib "^2.4.0" -"@tauri-apps/cli-darwin-arm64@1.5.8": - version "1.5.8" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.5.8.tgz#28ca810b910979260dd77c92951d16340fcaa711" - integrity sha512-/AksDWfAt3NUSt8Rq2a3gTLASChKzldPVUjmJhcbtsuzFg2nx5g+hhOHxfBYzss2Te1K5mzlu+73LAMy1Sb9Gw== - -"@tauri-apps/cli-darwin-x64@1.5.8": - version "1.5.8" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.5.8.tgz#4060fb0ffcc8312cf48701df51e0e9b665f18382" - integrity sha512-gcfSh+BFRDdbIGpggZ1+5R5SgToz2A9LthH8P4ak3OHagDzDvI6ov6zy2UQE3XDWJKdnlna2rSR1dIuRZ0T9bA== - -"@tauri-apps/cli-linux-arm-gnueabihf@1.5.8": - version "1.5.8" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.5.8.tgz#00256432520edf04004962caa92cd84fbcc8b63f" - integrity sha512-ZHQYuOBGvZubPnh5n8bNaN2VMxPBZWs26960FGQWamm9569UV/TNDHb6mD0Jjk9o0f9P+f98qNhuu5Y37P+vfQ== - -"@tauri-apps/cli-linux-arm64-gnu@1.5.8": - version "1.5.8" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.5.8.tgz#7869571b06e8b36a072f2e0e7bb49baab9d3c868" - integrity sha512-FFs28Ew3R2EFPYKuyAIouTbp6YnR+shAmJGFNnVy7ibKHL0wxamVKqv1N5N9gUUr+EhbZu2syMBRfG9XQ5mgng== - -"@tauri-apps/cli-linux-arm64-musl@1.5.8": - version "1.5.8" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.5.8.tgz#7cbe0395cbd09d4b49c945e36c2de99478c50a51" - integrity sha512-dEYvNyLMmWD0jb30FNfVPXmBq6OGg6is3km+4RlGg8tZU5Zvq78ClUZtaZuER+N/hv27+Uc6UHl9X3hin8cGGw== - -"@tauri-apps/cli-linux-x64-gnu@1.5.8": - version "1.5.8" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.5.8.tgz#d03ba73f1ac68bf6bace7bf45b50e6b12ce4468b" - integrity sha512-ut3TDbtLXmZhz6Q4wim57PV02wG+AfuLSWRPhTL9MsPsg/E7Y6sJhv0bIMAq6SwC59RCH52ZGft6RH7samV2NQ== - -"@tauri-apps/cli-linux-x64-musl@1.5.8": - version "1.5.8" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-1.5.8.tgz#4ce560aa102e9031d4c51c7bc853263cf3ab9616" - integrity sha512-k6ei7ETXVZlNpFOhl/8Cnj709UbEr+VuY9xKK/HgwvNfjA5f8HQ9TSKk/Um7oeT1Y61/eEcvcgF/hDURhFJDPQ== - -"@tauri-apps/cli-win32-arm64-msvc@1.5.8": - version "1.5.8" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-1.5.8.tgz#df83af81c6d89d4a505f2e96b3d443dd411c1a4a" - integrity sha512-l6zm31x1inkS2K5e7otUZ90XBoK+xr2KJObFCZbzmluBE+LM0fgIXCrj7xwH/f0RCUX3VY9HHx4EIo7eLGBXKQ== - -"@tauri-apps/cli-win32-ia32-msvc@1.5.8": - version "1.5.8" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.5.8.tgz#92e5acc4dcd44aec88099059a04bb5ad3b4e59ff" - integrity sha512-0k3YpWl6PKV4Qp2N52Sb45egXafSgQXcBaO7TIJG4EDfaEf5f6StN+hYSzdnrq9idrK5x9DDCPuebZTuJ+Q8EA== - -"@tauri-apps/cli-win32-x64-msvc@1.5.8": - version "1.5.8" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.5.8.tgz#a0c363969cf5a21c95c235e5bf6a94a410130761" - integrity sha512-XjBg8VMswmD9JAHKlb10NRPfBVAZoiOJBbPRte+GP1BUQtqDnbIYcOLSnUCmNZoy3fUBJuKJUBT9tDCbkMr5fQ== - -"@tauri-apps/cli@^1.5.8": - version "1.5.8" - resolved "https://registry.yarnpkg.com/@tauri-apps/cli/-/cli-1.5.8.tgz#feaf055af370cb192b24ea4c51edf0e577269fb2" - integrity sha512-c/mzk5vjjfxtH5uNXSc9h1eiprsolnoBcUwAa4/SZ3gxJ176CwrUKODz3cZBOnzs8omwagwgSN/j7K8NrdFL9g== +"@tauri-apps/cli-darwin-arm64@1.5.7": + version "1.5.7" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-darwin-arm64/-/cli-darwin-arm64-1.5.7.tgz#3435f1b6c4b431e0283f94c3a0bd486be66b24ee" + integrity sha512-eUpOUhs2IOpKaLa6RyGupP2owDLfd0q2FR/AILzryjtBtKJJRDQQvuotf+LcbEce2Nc2AHeYJIqYAsB4sw9K+g== + +"@tauri-apps/cli-darwin-x64@1.5.7": + version "1.5.7" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-darwin-x64/-/cli-darwin-x64-1.5.7.tgz#d3d646e790067158d14a1f631a50c67dc05e3360" + integrity sha512-zfumTv1xUuR+RB1pzhRy+51tB6cm8I76g0xUBaXOfEdOJ9FqW5GW2jdnEUbpNuU65qJ1lB8LVWHKGrSWWKazew== + +"@tauri-apps/cli-linux-arm-gnueabihf@1.5.7": + version "1.5.7" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm-gnueabihf/-/cli-linux-arm-gnueabihf-1.5.7.tgz#049c12980cdfd67fe9e5163762bf77f3c85f6956" + integrity sha512-JngWNqS06bMND9PhiPWp0e+yknJJuSozsSbo+iMzHoJNRauBZCUx+HnUcygUR66Cy6qM4eJvLXtsRG7ApxvWmg== + +"@tauri-apps/cli-linux-arm64-gnu@1.5.7": + version "1.5.7" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm64-gnu/-/cli-linux-arm64-gnu-1.5.7.tgz#d1c143da15cba74eebfaaf1662f0734e30f97562" + integrity sha512-WyIYP9BskgBGq+kf4cLAyru8ArrxGH2eMYGBJvuNEuSaqBhbV0i1uUxvyWdazllZLAEz1WvSocUmSwLknr1+sQ== + +"@tauri-apps/cli-linux-arm64-musl@1.5.7": + version "1.5.7" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-arm64-musl/-/cli-linux-arm64-musl-1.5.7.tgz#f79a17f5360a8ab25b90f3a8e9e6327d5378072f" + integrity sha512-OrDpihQP2MB0JY1a/wP9wsl9dDjFDpVEZOQxt4hU+UVGRCZQok7ghPBg4+Xpd1CkNkcCCuIeY8VxRvwLXpnIzg== + +"@tauri-apps/cli-linux-x64-gnu@1.5.7": + version "1.5.7" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-x64-gnu/-/cli-linux-x64-gnu-1.5.7.tgz#2cbd17998dcfc8a465d61f30ac9e99ae65e2c2e8" + integrity sha512-4T7FAYVk76rZi8VkuLpiKUAqaSxlva86C1fHm/RtmoTKwZEV+MI3vIMoVg+AwhyWIy9PS55C75nF7+OwbnFnvQ== + +"@tauri-apps/cli-linux-x64-musl@1.5.7": + version "1.5.7" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-linux-x64-musl/-/cli-linux-x64-musl-1.5.7.tgz#d5d4ddded945cc781568d72b7eba367121f28525" + integrity sha512-LL9aMK601BmQjAUDcKWtt5KvAM0xXi0iJpOjoUD3LPfr5dLvBMTflVHQDAEtuZexLQyqpU09+60781PrI/FCTw== + +"@tauri-apps/cli-win32-arm64-msvc@1.5.7": + version "1.5.7" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-arm64-msvc/-/cli-win32-arm64-msvc-1.5.7.tgz#05a1bd4e2bc692bad995edb9d07e616cc5682fd5" + integrity sha512-TmAdM6GVkfir3AUFsDV2gyc25kIbJeAnwT72OnmJGAECHs/t/GLP9IkFLLVcFKsiosRf8BXhVyQ84NYkSWo14w== + +"@tauri-apps/cli-win32-ia32-msvc@1.5.7": + version "1.5.7" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-ia32-msvc/-/cli-win32-ia32-msvc-1.5.7.tgz#8c832f4dc88374255ef1cda4d2d6a6d61a921388" + integrity sha512-bqWfxwCfLmrfZy69sEU19KHm5TFEaMb8KIekd4aRq/kyOlrjKLdZxN1PyNRP8zpJA1lTiRHzfUDfhpmnZH/skg== + +"@tauri-apps/cli-win32-x64-msvc@1.5.7": + version "1.5.7" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli-win32-x64-msvc/-/cli-win32-x64-msvc-1.5.7.tgz#adfcce46f796dd22ef69fb26ad8c6972a3263985" + integrity sha512-OxLHVBNdzyQ//xT3kwjQFnJTn/N5zta/9fofAkXfnL7vqmVn6s/RY1LDa3sxCHlRaKw0n3ShpygRbM9M8+sO9w== + +"@tauri-apps/cli@1.5.7": + version "1.5.7" + resolved "https://registry.yarnpkg.com/@tauri-apps/cli/-/cli-1.5.7.tgz#8f9a8bf577a39b7f7c0e5b125e7b5b3e149cfb5a" + integrity sha512-z7nXLpDAYfQqR5pYhQlWOr88DgPq1AfQyxHhGiakiVgWlaG0ikEfQxop2txrd52H0TRADG0JHR9vFrVFPv4hVQ== optionalDependencies: - "@tauri-apps/cli-darwin-arm64" "1.5.8" - "@tauri-apps/cli-darwin-x64" "1.5.8" - "@tauri-apps/cli-linux-arm-gnueabihf" "1.5.8" - "@tauri-apps/cli-linux-arm64-gnu" "1.5.8" - "@tauri-apps/cli-linux-arm64-musl" "1.5.8" - "@tauri-apps/cli-linux-x64-gnu" "1.5.8" - "@tauri-apps/cli-linux-x64-musl" "1.5.8" - "@tauri-apps/cli-win32-arm64-msvc" "1.5.8" - "@tauri-apps/cli-win32-ia32-msvc" "1.5.8" - "@tauri-apps/cli-win32-x64-msvc" "1.5.8" + "@tauri-apps/cli-darwin-arm64" "1.5.7" + "@tauri-apps/cli-darwin-x64" "1.5.7" + "@tauri-apps/cli-linux-arm-gnueabihf" "1.5.7" + "@tauri-apps/cli-linux-arm64-gnu" "1.5.7" + "@tauri-apps/cli-linux-arm64-musl" "1.5.7" + "@tauri-apps/cli-linux-x64-gnu" "1.5.7" + "@tauri-apps/cli-linux-x64-musl" "1.5.7" + "@tauri-apps/cli-win32-arm64-msvc" "1.5.7" + "@tauri-apps/cli-win32-ia32-msvc" "1.5.7" + "@tauri-apps/cli-win32-x64-msvc" "1.5.7" "@trysound/sax@0.2.0": version "0.2.0" From d17000975fe58c84e576f89be552c76b91bcb827 Mon Sep 17 00:00:00 2001 From: Fred Liang Date: Wed, 27 Dec 2023 23:45:40 +0800 Subject: [PATCH 5/9] Release 2.10.1: Support Google Gemini Pro model (#3668) * chore: update auth value logic * chore: bump version 2.10.1 --- src-tauri/tauri.conf.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 30546227d50..75d6a0d0afa 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -9,7 +9,7 @@ }, "package": { "productName": "NextChat", - "version": "2.9.13" + "version": "2.10.1" }, "tauri": { "allowlist": { From f8b963df6d3647272c28be36e9a1de85529b7696 Mon Sep 17 00:00:00 2001 From: Fred Liang Date: Thu, 28 Dec 2023 22:56:01 +0800 Subject: [PATCH 6/9] chore(docs): update readme for Gemini Pro (#3685) * chore: update auth value logic * chore: bump version 2.10.1 * Chore [Package] Downgrade Tauri Builder Version (#3656) - [+] chore(package.json): update @tauri-apps/cli devDependency to version 1.5.7 - [+] chore(yarn.lock): update @tauri-apps/cli versions to 1.5.7 * chore: update README.md --------- Co-authored-by: H0llyW00dzZ --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 69b649926b5..a42cbd1d4ef 100644 --- a/README.md +++ b/README.md @@ -61,10 +61,11 @@ One-Click to get a well-designed cross-platform ChatGPT web UI, with GPT3, GPT4 ## What's New -- πŸš€ v2.0 is released, now you can create prompt templates, turn your ideas into reality! Read this: [ChatGPT Prompt Engineering Tips: Zero, One and Few Shot Prompting](https://www.allabtai.com/prompt-engineering-tips-zero-one-and-few-shot-prompting/). -- πŸš€ v2.7 let's share conversations as image, or share to ShareGPT! -- πŸš€ v2.8 now we have a client that runs across all platforms! +- πŸš€ v2.10.1 support Google Gemini Pro model. - πŸš€ v2.9.11 you can use azure endpoint now. +- πŸš€ v2.8 now we have a client that runs across all platforms! +- πŸš€ v2.7 let's share conversations as image, or share to ShareGPT! +- πŸš€ v2.0 is released, now you can create prompt templates, turn your ideas into reality! Read this: [ChatGPT Prompt Engineering Tips: Zero, One and Few Shot Prompting](https://www.allabtai.com/prompt-engineering-tips-zero-one-and-few-shot-prompting/). ## δΈ»θ¦εŠŸθƒ½ From 406530ca69d9f6bd1159e1ff8bde98ec0a3306e2 Mon Sep 17 00:00:00 2001 From: Fred Liang Date: Thu, 28 Dec 2023 23:10:19 +0800 Subject: [PATCH 7/9] feat: support vercel speed insight (#3686) --- app/layout.tsx | 13 ++++++++++++- app/page.tsx | 6 +++++- package.json | 1 + yarn.lock | 5 +++++ 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/app/layout.tsx b/app/layout.tsx index b234051f943..be2162475d8 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -4,6 +4,10 @@ import "./styles/markdown.scss"; import "./styles/highlight.scss"; import { getClientConfig } from "./config/client"; import { type Metadata } from "next"; +import { SpeedInsights } from "@vercel/speed-insights/next"; +import { getServerSideConfig } from "./config/server"; + +const serverConfig = getServerSideConfig(); export const metadata: Metadata = { title: "NextChat", @@ -35,7 +39,14 @@ export default function RootLayout({ - {children} + + {children} + {serverConfig?.isVercel && ( + <> + + + )} + ); } diff --git a/app/page.tsx b/app/page.tsx index 20b503174d4..b3f169a9b74 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -10,7 +10,11 @@ export default async function App() { return ( <> - {serverConfig?.isVercel && } + {serverConfig?.isVercel && ( + <> + + + )} ); } diff --git a/package.json b/package.json index 102461b314f..a014c7bfe14 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "@hello-pangea/dnd": "^16.5.0", "@svgr/webpack": "^6.5.1", "@vercel/analytics": "^0.1.11", + "@vercel/speed-insights": "^1.0.2", "emoji-picker-react": "^4.5.15", "fuse.js": "^7.0.0", "html-to-image": "^1.11.11", diff --git a/yarn.lock b/yarn.lock index 5469672db2b..bf07c27eea1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1704,6 +1704,11 @@ resolved "https://registry.yarnpkg.com/@vercel/analytics/-/analytics-0.1.11.tgz#727a0ac655a4a89104cdea3e6925476470299428" integrity sha512-mj5CPR02y0BRs1tN3oZcBNAX9a8NxsIUl9vElDPcqxnMfP0RbRc9fI9Ud7+QDg/1Izvt5uMumsr+6YsmVHcyuw== +"@vercel/speed-insights@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@vercel/speed-insights/-/speed-insights-1.0.2.tgz#1bebf3e7c7046b6a911721233b263b69214ddb3e" + integrity sha512-y5HWeB6RmlyVYxJAMrjiDEz8qAIy2cit0fhBq+MD78WaUwQvuBnQlX4+5MuwVTWi46bV3klaRMq83u9zUy1KOg== + "@webassemblyjs/ast@1.11.6", "@webassemblyjs/ast@^1.11.5": version "1.11.6" resolved "https://registry.npmmirror.com/@webassemblyjs/ast/-/ast-1.11.6.tgz#db046555d3c413f8966ca50a95176a0e2c642e24" From 3ba598633c4f3b640ea2c8ecc0a604eed39b42e4 Mon Sep 17 00:00:00 2001 From: reece00 <37351410+reece00@users.noreply.github.com> Date: Thu, 28 Dec 2023 23:52:45 +0800 Subject: [PATCH 8/9] Non -GPT model disable system prompt (#3684) --- app/store/chat.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/store/chat.ts b/app/store/chat.ts index 4af5a52acf9..dff6b7bf1c6 100644 --- a/app/store/chat.ts +++ b/app/store/chat.ts @@ -386,7 +386,9 @@ export const useChatStore = createPersistStore( const contextPrompts = session.mask.context.slice(); // system prompts, to get close to OpenAI Web ChatGPT - const shouldInjectSystemPrompts = modelConfig.enableInjectSystemPrompts; + const shouldInjectSystemPrompts = + modelConfig.enableInjectSystemPrompts && + session.mask.modelConfig.model.startsWith("gpt-"); var systemPrompts: ChatMessage[] = []; systemPrompts = shouldInjectSystemPrompts From 5cf58d94466604cb53a6b026f477827baf12f012 Mon Sep 17 00:00:00 2001 From: Fred Liang Date: Fri, 29 Dec 2023 03:42:45 +0800 Subject: [PATCH 9/9] feat: support streaming for Gemini Pro (#3688) * feat: support streaming for Gemini Pro * feat: display texts smoothly * chore: remove comments --- app/client/platforms/google.ts | 128 +++++++++++++-------------------- 1 file changed, 48 insertions(+), 80 deletions(-) diff --git a/app/client/platforms/google.ts b/app/client/platforms/google.ts index c35e93cb396..6eaa3c97177 100644 --- a/app/client/platforms/google.ts +++ b/app/client/platforms/google.ts @@ -20,6 +20,7 @@ export class GeminiProApi implements LLMApi { ); } async chat(options: ChatOptions): Promise { + const apiClient = this; const messages = options.messages.map((v) => ({ role: v.role.replace("assistant", "model").replace("system", "user"), parts: [{ text: v.content }], @@ -61,8 +62,7 @@ export class GeminiProApi implements LLMApi { console.log("[Request] google payload: ", requestPayload); - // todo: support stream later - const shouldStream = false; + const shouldStream = !!options.config.stream; const controller = new AbortController(); options.onController?.(controller); try { @@ -82,13 +82,21 @@ export class GeminiProApi implements LLMApi { if (shouldStream) { let responseText = ""; let remainText = ""; + let streamChatPath = chatPath.replace( + "generateContent", + "streamGenerateContent", + ); let finished = false; + const finish = () => { + finished = true; + options.onFinish(responseText + remainText); + }; // animate response to make it looks smooth function animateResponseText() { if (finished || controller.signal.aborted) { responseText += remainText; - console.log("[Response Animation] finished"); + finish(); return; } @@ -105,88 +113,41 @@ export class GeminiProApi implements LLMApi { // start animaion animateResponseText(); + fetch(streamChatPath, chatPayload) + .then((response) => { + const reader = response?.body?.getReader(); + const decoder = new TextDecoder(); + let partialData = ""; + + return reader?.read().then(function processText({ + done, + value, + }): Promise { + if (done) { + console.log("Stream complete"); + // options.onFinish(responseText + remainText); + finished = true; + return Promise.resolve(); + } - const finish = () => { - if (!finished) { - finished = true; - options.onFinish(responseText + remainText); - } - }; + partialData += decoder.decode(value, { stream: true }); - controller.signal.onabort = finish; - - fetchEventSource(chatPath, { - ...chatPayload, - async onopen(res) { - clearTimeout(requestTimeoutId); - const contentType = res.headers.get("content-type"); - console.log( - "[OpenAI] request response content type: ", - contentType, - ); - - if (contentType?.startsWith("text/plain")) { - responseText = await res.clone().text(); - return finish(); - } - - if ( - !res.ok || - !res.headers - .get("content-type") - ?.startsWith(EventStreamContentType) || - res.status !== 200 - ) { - const responseTexts = [responseText]; - let extraInfo = await res.clone().text(); try { - const resJson = await res.clone().json(); - extraInfo = prettyObject(resJson); - } catch {} - - if (res.status === 401) { - responseTexts.push(Locale.Error.Unauthorized); + let data = JSON.parse(ensureProperEnding(partialData)); + console.log(data); + let fetchText = apiClient.extractMessage(data[data.length - 1]); + console.log("[Response Animation] fetchText: ", fetchText); + remainText += fetchText; + } catch (error) { + // skip error message when parsing json } - if (extraInfo) { - responseTexts.push(extraInfo); - } - - responseText = responseTexts.join("\n\n"); - - return finish(); - } - }, - onmessage(msg) { - if (msg.data === "[DONE]" || finished) { - return finish(); - } - const text = msg.data; - try { - const json = JSON.parse(text) as { - choices: Array<{ - delta: { - content: string; - }; - }>; - }; - const delta = json.choices[0]?.delta?.content; - if (delta) { - remainText += delta; - } - } catch (e) { - console.error("[Request] parse error", text); - } - }, - onclose() { - finish(); - }, - onerror(e) { - options.onError?.(e); - throw e; - }, - openWhenHidden: true, - }); + return reader.read().then(processText); + }); + }) + .catch((error) => { + console.error("Error:", error); + }); } else { const res = await fetch(chatPath, chatPayload); clearTimeout(requestTimeoutId); @@ -220,3 +181,10 @@ export class GeminiProApi implements LLMApi { return "/api/google/" + path; } } + +function ensureProperEnding(str: string) { + if (str.startsWith("[") && !str.endsWith("]")) { + return str + "]"; + } + return str; +}