From fcb1a657e333980495b691dc1f61b5bc08f55097 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=91=E4=BA=91=E7=99=BD=E5=9C=9F?= Date: Wed, 17 Apr 2024 16:24:11 +0800 Subject: [PATCH 01/28] Update constant.ts --- app/constant.ts | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/app/constant.ts b/app/constant.ts index aaa33bdcf..8b6549566 100644 --- a/app/constant.ts +++ b/app/constant.ts @@ -99,7 +99,6 @@ export const Azure = { export const Google = { ExampleEndpoint: "https://generativelanguage.googleapis.com/", ChatPath: (modelName: string) => `v1beta/models/${modelName}:generateContent`, - VisionChatPath: (modelName: string) => `v1beta/models/${modelName}:generateContent`, }; export const DEFAULT_INPUT_TEMPLATE = `{{input}}`; // input / time / model / lang @@ -128,8 +127,6 @@ export const KnowledgeCutOffDate: Record = { "gpt-4-turbo": "2023-12", "gpt-4-turbo-2024-04-09": "2023-12", "gpt-4-turbo-preview": "2023-12", - "gpt-4-1106-preview": "2023-04", - "gpt-4-0125-preview": "2023-12", "gpt-4-vision-preview": "2023-04", // After improvements, // it's now easier to add "KnowledgeCutOffDate" instead of stupid hardcoding it, as was done previously. @@ -139,19 +136,11 @@ export const KnowledgeCutOffDate: Record = { const openaiModels = [ "gpt-3.5-turbo", - "gpt-3.5-turbo-0301", - "gpt-3.5-turbo-0613", "gpt-3.5-turbo-1106", "gpt-3.5-turbo-0125", - "gpt-3.5-turbo-16k", - "gpt-3.5-turbo-16k-0613", "gpt-4", - "gpt-4-0314", "gpt-4-0613", - "gpt-4-1106-preview", - "gpt-4-0125-preview", "gpt-4-32k", - "gpt-4-32k-0314", "gpt-4-32k-0613", "gpt-4-turbo", "gpt-4-turbo-preview", From b7aab3c10272e076bd84b7a871de02f528283abc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=BB=91=E4=BA=91=E7=99=BD=E5=9C=9F?= Date: Wed, 17 Apr 2024 17:16:31 +0800 Subject: [PATCH 02/28] Update google.ts --- app/client/platforms/google.ts | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/app/client/platforms/google.ts b/app/client/platforms/google.ts index 1ab36db25..a786f5275 100644 --- a/app/client/platforms/google.ts +++ b/app/client/platforms/google.ts @@ -21,11 +21,10 @@ export class GeminiProApi implements LLMApi { } async chat(options: ChatOptions): Promise { // const apiClient = this; - const visionModel = isVisionModel(options.config.model); let multimodal = false; const messages = options.messages.map((v) => { let parts: any[] = [{ text: getMessageTextContent(v) }]; - if (visionModel) { + if (isVisionModel(options.config.model)) { const images = getMessageImages(v); if (images.length > 0) { multimodal = true; @@ -117,17 +116,12 @@ export class GeminiProApi implements LLMApi { const controller = new AbortController(); options.onController?.(controller); try { - let googleChatPath = visionModel - ? Google.VisionChatPath(modelConfig.model) - : Google.ChatPath(modelConfig.model); - let chatPath = this.path(googleChatPath); - // let baseUrl = accessStore.googleUrl; if (!baseUrl) { baseUrl = isApp - ? DEFAULT_API_HOST + "/api/proxy/google/" + googleChatPath - : chatPath; + ? DEFAULT_API_HOST + "/api/proxy/google/" + Google.ChatPath(modelConfig.model) + : this.path(Google.ChatPath(modelConfig.model)); } if (isApp) { @@ -145,6 +139,7 @@ export class GeminiProApi implements LLMApi { () => controller.abort(), REQUEST_TIMEOUT_MS, ); + if (shouldStream) { let responseText = ""; let remainText = ""; From 1cd0beb231d98bc14ff660d98bc78b1ba2df43b3 Mon Sep 17 00:00:00 2001 From: Roy Date: Tue, 23 Apr 2024 11:48:54 +0800 Subject: [PATCH 03/28] chore: No outline when element is in `:focus-visible` state --- app/styles/globals.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/styles/globals.scss b/app/styles/globals.scss index aa22b7d4f..20792cda5 100644 --- a/app/styles/globals.scss +++ b/app/styles/globals.scss @@ -86,6 +86,7 @@ @include dark; } } + html { height: var(--full-height); @@ -110,6 +111,10 @@ body { @media only screen and (max-width: 600px) { background-color: var(--second); } + + *:focus-visible { + outline: none; + } } ::-webkit-scrollbar { From dd4648ed9a803568b839e2510ca01cf7f1c6f740 Mon Sep 17 00:00:00 2001 From: "l.tingting" Date: Wed, 24 Apr 2024 22:59:14 +0800 Subject: [PATCH 04/28] remove max_tokens from the official version of gpt4-turbo --- app/client/platforms/openai.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/client/platforms/openai.ts b/app/client/platforms/openai.ts index ca8bc2ebe..f35992630 100644 --- a/app/client/platforms/openai.ts +++ b/app/client/platforms/openai.ts @@ -129,7 +129,7 @@ export class ChatGPTApi implements LLMApi { }; // add max_tokens to vision model - if (visionModel) { + if (visionModel && modelConfig.model.includes("preview")) { requestPayload["max_tokens"] = Math.max(modelConfig.max_tokens, 4000); } From b2e8a1eaa202c29378a83ef4d48ca5c39efc3689 Mon Sep 17 00:00:00 2001 From: Fred Date: Tue, 30 Apr 2024 13:27:07 +0800 Subject: [PATCH 05/28] feat: bump version code --- 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 f03efb0fe..7b00ac17c 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -9,7 +9,7 @@ }, "package": { "productName": "NextChat", - "version": "2.11.3" + "version": "2.12.2" }, "tauri": { "allowlist": { From 4cd94370e8f87b1fc70200e9383a7c90f6aff03c Mon Sep 17 00:00:00 2001 From: ruban <51721541+rooben-me@users.noreply.github.com> Date: Fri, 3 May 2024 05:25:11 +0000 Subject: [PATCH 06/28] fix i think --- app/store/sync.ts | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/app/store/sync.ts b/app/store/sync.ts index 8ee6c1819..d5a7f7b6f 100644 --- a/app/store/sync.ts +++ b/app/store/sync.ts @@ -95,22 +95,29 @@ export const useSyncStore = createPersistStore( const provider = get().provider; const config = get()[provider]; const client = this.getClient(); - + try { - const remoteState = JSON.parse( - await client.get(config.username), - ) as AppState; - mergeAppState(localState, remoteState); - setLocalAppState(localState); + const remoteState = await client.get(config.username); + if (!remoteState || remoteState === "") { + console.log("[Sync] Remote state is empty, using local state instead."); + return + } else { + const parsedRemoteState = JSON.parse( + await client.get(config.username), + ) as AppState; + + mergeAppState(localState, parsedRemoteState); + setLocalAppState(localState); + } + } catch (e) { console.log("[Sync] failed to get remote state", e); throw e; } - + await client.set(config.username, JSON.stringify(localState)); - this.markSyncTime(); - }, + }, async check() { const client = this.getClient(); From 9cd3358e4e08e207dacc7d6b032283e351d8a58d Mon Sep 17 00:00:00 2001 From: ruban <51721541+rooben-me@users.noreply.github.com> Date: Thu, 2 May 2024 22:40:52 -0700 Subject: [PATCH 07/28] this is the fix --- app/store/sync.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/app/store/sync.ts b/app/store/sync.ts index d5a7f7b6f..aa516057a 100644 --- a/app/store/sync.ts +++ b/app/store/sync.ts @@ -116,6 +116,7 @@ export const useSyncStore = createPersistStore( } await client.set(config.username, JSON.stringify(localState)); + console.log("client set", localState); this.markSyncTime(); }, From 9d728ec3c560d69282e0d867fe9c490bbb26bc3a Mon Sep 17 00:00:00 2001 From: ruban <51721541+rooben-me@users.noreply.github.com> Date: Thu, 2 May 2024 22:50:35 -0700 Subject: [PATCH 08/28] this is ti --- app/store/sync.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/store/sync.ts b/app/store/sync.ts index aa516057a..9d01a7871 100644 --- a/app/store/sync.ts +++ b/app/store/sync.ts @@ -95,6 +95,9 @@ export const useSyncStore = createPersistStore( const provider = get().provider; const config = get()[provider]; const client = this.getClient(); + + console.log("client set", localState); + await client.set(config.username, JSON.stringify(localState)); try { const remoteState = await client.get(config.username); From 6fc7c50f193a7be50a00233d4ea1bf0668f182da Mon Sep 17 00:00:00 2001 From: ruban <51721541+rooben-me@users.noreply.github.com> Date: Thu, 2 May 2024 22:55:41 -0700 Subject: [PATCH 09/28] this --- app/store/sync.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/store/sync.ts b/app/store/sync.ts index 9d01a7871..aa516057a 100644 --- a/app/store/sync.ts +++ b/app/store/sync.ts @@ -95,9 +95,6 @@ export const useSyncStore = createPersistStore( const provider = get().provider; const config = get()[provider]; const client = this.getClient(); - - console.log("client set", localState); - await client.set(config.username, JSON.stringify(localState)); try { const remoteState = await client.get(config.username); From 7b61d05e880c36f5ba3643fdf65a077f90b8ddc3 Mon Sep 17 00:00:00 2001 From: ruban <51721541+rooben-me@users.noreply.github.com> Date: Thu, 2 May 2024 23:08:17 -0700 Subject: [PATCH 10/28] new fix --- app/store/sync.ts | 164 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 160 insertions(+), 4 deletions(-) diff --git a/app/store/sync.ts b/app/store/sync.ts index aa516057a..af7888d57 100644 --- a/app/store/sync.ts +++ b/app/store/sync.ts @@ -99,24 +99,22 @@ export const useSyncStore = createPersistStore( try { const remoteState = await client.get(config.username); if (!remoteState || remoteState === "") { + await client.set(config.username, JSON.stringify(localState)); console.log("[Sync] Remote state is empty, using local state instead."); return } else { const parsedRemoteState = JSON.parse( await client.get(config.username), ) as AppState; - mergeAppState(localState, parsedRemoteState); setLocalAppState(localState); - } - + } } catch (e) { console.log("[Sync] failed to get remote state", e); throw e; } await client.set(config.username, JSON.stringify(localState)); - console.log("client set", localState); this.markSyncTime(); }, @@ -149,3 +147,161 @@ export const useSyncStore = createPersistStore( }, }, ); + +``` + +**Output:** + +```tsx +import { getClientConfig } from "../config/client"; +import { Updater } from "../typing"; +import { ApiPath, STORAGE_KEY, StoreKey } from "../constant"; +import { createPersistStore } from "../utils/store"; +import { + AppState, + getLocalAppState, + GetStoreState, + mergeAppState, + setLocalAppState, +} from "../utils/sync"; +import { downloadAs, readFromFile } from "../utils"; +import { showToast } from "../components/ui-lib"; +import Locale from "../locales"; +import { createSyncClient, ProviderType } from "../utils/cloud"; +import { corsPath } from "../utils/cors"; + +export interface WebDavConfig { + server: string; + username: string; + password: string; +} + +const isApp = !!getClientConfig()?.isApp; +export type SyncStore = GetStoreState; + +const DEFAULT_SYNC_STATE = { + provider: ProviderType.WebDAV, + useProxy: true, + proxyUrl: corsPath(ApiPath.Cors), + + webdav: { + endpoint: "", + username: "", + password: "", + }, + + upstash: { + endpoint: "", + username: STORAGE_KEY, + apiKey: "", + }, + + lastSyncTime: 0, + lastProvider: "", +}; + +export const useSyncStore = createPersistStore( + DEFAULT_SYNC_STATE, + (set, get) => ({ + cloudSync() { + const config = get()[get().provider]; + return Object.values(config).every((c) => c.toString().length > 0); + }, + + markSyncTime() { + set({ lastSyncTime: Date.now(), lastProvider: get().provider }); + }, + + export() { + const state = getLocalAppState(); + const datePart = isApp + ? `${new Date().toLocaleDateString().replace(/\//g, "_")} ${new Date() + .toLocaleTimeString() + .replace(/:/g, "_")}` + : new Date().toLocaleString(); + + const fileName = `Backup-${datePart}.json`; + downloadAs(JSON.stringify(state), fileName); + }, + + async import() { + const rawContent = await readFromFile(); + + try { + const remoteState = JSON.parse(rawContent) as AppState; + const localState = getLocalAppState(); + mergeAppState(localState, remoteState); + setLocalAppState(localState); + location.reload(); + } catch (e) { + console.error("[Import]", e); + showToast(Locale.Settings.Sync.ImportFailed); + } + }, + + getClient() { + const provider = get().provider; + const client = createSyncClient(provider, get()); + return client; + }, + + async sync() { + const localState = getLocalAppState(); + const provider = get().provider; + const config = get()[provider]; + const client = this.getClient(); + + try { + const remoteState = await client.get(config.username); + if (!remoteState || remoteState === "") { + console.log( + "[Sync] Remote state is empty, using local state instead.", + ); + return; + } else { + const parsedRemoteState = JSON.parse( + await client.get(config.username), + ) as AppState; + + mergeAppState(localState, parsedRemoteState); + setLocalAppState(localState); + } + } catch (e) { + console.log("[Sync] failed to get remote state", e); + throw e; + } + + await client.set(config.username, JSON.stringify(localState)); + console.log("client set", localState); + this.markSyncTime(); + }, + + async check() { + const client = this.getClient(); + return await client.check(); + }, + }), + { + name: StoreKey.Sync, + version: 1.2, + + migrate(persistedState, version) { + const newState = persistedState as typeof DEFAULT_SYNC_STATE; + + if (version < 1.1) { + newState.upstash.username = STORAGE_KEY; + } + + if (version < 1.2) { + if ( + (persistedState as typeof DEFAULT_SYNC_STATE).proxyUrl === + "/api/cors/" + ) { + newState.proxyUrl = ""; + } + } + + return newState as any; + }, + }, +); \ No newline at end of file From a10358234641dd209488d68e3fbf587b3dd61d91 Mon Sep 17 00:00:00 2001 From: ruban <51721541+rooben-me@users.noreply.github.com> Date: Thu, 2 May 2024 23:10:10 -0700 Subject: [PATCH 11/28] fix --- app/store/sync.ts | 158 ---------------------------------------------- 1 file changed, 158 deletions(-) diff --git a/app/store/sync.ts b/app/store/sync.ts index af7888d57..d22d6baf8 100644 --- a/app/store/sync.ts +++ b/app/store/sync.ts @@ -127,164 +127,6 @@ export const useSyncStore = createPersistStore( name: StoreKey.Sync, version: 1.2, - migrate(persistedState, version) { - const newState = persistedState as typeof DEFAULT_SYNC_STATE; - - if (version < 1.1) { - newState.upstash.username = STORAGE_KEY; - } - - if (version < 1.2) { - if ( - (persistedState as typeof DEFAULT_SYNC_STATE).proxyUrl === - "/api/cors/" - ) { - newState.proxyUrl = ""; - } - } - - return newState as any; - }, - }, -); - -``` - -**Output:** - -```tsx -import { getClientConfig } from "../config/client"; -import { Updater } from "../typing"; -import { ApiPath, STORAGE_KEY, StoreKey } from "../constant"; -import { createPersistStore } from "../utils/store"; -import { - AppState, - getLocalAppState, - GetStoreState, - mergeAppState, - setLocalAppState, -} from "../utils/sync"; -import { downloadAs, readFromFile } from "../utils"; -import { showToast } from "../components/ui-lib"; -import Locale from "../locales"; -import { createSyncClient, ProviderType } from "../utils/cloud"; -import { corsPath } from "../utils/cors"; - -export interface WebDavConfig { - server: string; - username: string; - password: string; -} - -const isApp = !!getClientConfig()?.isApp; -export type SyncStore = GetStoreState; - -const DEFAULT_SYNC_STATE = { - provider: ProviderType.WebDAV, - useProxy: true, - proxyUrl: corsPath(ApiPath.Cors), - - webdav: { - endpoint: "", - username: "", - password: "", - }, - - upstash: { - endpoint: "", - username: STORAGE_KEY, - apiKey: "", - }, - - lastSyncTime: 0, - lastProvider: "", -}; - -export const useSyncStore = createPersistStore( - DEFAULT_SYNC_STATE, - (set, get) => ({ - cloudSync() { - const config = get()[get().provider]; - return Object.values(config).every((c) => c.toString().length > 0); - }, - - markSyncTime() { - set({ lastSyncTime: Date.now(), lastProvider: get().provider }); - }, - - export() { - const state = getLocalAppState(); - const datePart = isApp - ? `${new Date().toLocaleDateString().replace(/\//g, "_")} ${new Date() - .toLocaleTimeString() - .replace(/:/g, "_")}` - : new Date().toLocaleString(); - - const fileName = `Backup-${datePart}.json`; - downloadAs(JSON.stringify(state), fileName); - }, - - async import() { - const rawContent = await readFromFile(); - - try { - const remoteState = JSON.parse(rawContent) as AppState; - const localState = getLocalAppState(); - mergeAppState(localState, remoteState); - setLocalAppState(localState); - location.reload(); - } catch (e) { - console.error("[Import]", e); - showToast(Locale.Settings.Sync.ImportFailed); - } - }, - - getClient() { - const provider = get().provider; - const client = createSyncClient(provider, get()); - return client; - }, - - async sync() { - const localState = getLocalAppState(); - const provider = get().provider; - const config = get()[provider]; - const client = this.getClient(); - - try { - const remoteState = await client.get(config.username); - if (!remoteState || remoteState === "") { - console.log( - "[Sync] Remote state is empty, using local state instead.", - ); - return; - } else { - const parsedRemoteState = JSON.parse( - await client.get(config.username), - ) as AppState; - - mergeAppState(localState, parsedRemoteState); - setLocalAppState(localState); - } - } catch (e) { - console.log("[Sync] failed to get remote state", e); - throw e; - } - - await client.set(config.username, JSON.stringify(localState)); - console.log("client set", localState); - this.markSyncTime(); - }, - - async check() { - const client = this.getClient(); - return await client.check(); - }, - }), - { - name: StoreKey.Sync, - version: 1.2, - migrate(persistedState, version) { const newState = persistedState as typeof DEFAULT_SYNC_STATE; From 1da7d81122905362e1e6d76c1b8aba47f1a90a67 Mon Sep 17 00:00:00 2001 From: ruban <51721541+rooben-me@users.noreply.github.com> Date: Thu, 2 May 2024 23:22:32 -0700 Subject: [PATCH 12/28] Fix cloud data sync issue with Upstash (#4563) --- app/store/sync.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/store/sync.ts b/app/store/sync.ts index d22d6baf8..ce31ebd8f 100644 --- a/app/store/sync.ts +++ b/app/store/sync.ts @@ -115,6 +115,7 @@ export const useSyncStore = createPersistStore( } await client.set(config.username, JSON.stringify(localState)); + this.markSyncTime(); }, @@ -146,4 +147,4 @@ export const useSyncStore = createPersistStore( return newState as any; }, }, -); \ No newline at end of file +); From 8ef2617eec823ea5a6f647be762a3345f52cae0c Mon Sep 17 00:00:00 2001 From: ruban <51721541+rooben-me@users.noreply.github.com> Date: Thu, 2 May 2024 23:24:41 -0700 Subject: [PATCH 13/28] Removed spaces --- app/store/sync.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/store/sync.ts b/app/store/sync.ts index ce31ebd8f..d3582e3c9 100644 --- a/app/store/sync.ts +++ b/app/store/sync.ts @@ -95,7 +95,7 @@ export const useSyncStore = createPersistStore( const provider = get().provider; const config = get()[provider]; const client = this.getClient(); - + try { const remoteState = await client.get(config.username); if (!remoteState || remoteState === "") { @@ -113,11 +113,11 @@ export const useSyncStore = createPersistStore( console.log("[Sync] failed to get remote state", e); throw e; } - + await client.set(config.username, JSON.stringify(localState)); this.markSyncTime(); - }, + }, async check() { const client = this.getClient(); From b3e856df1d0aa00038f0e4048c209ce0c7def444 Mon Sep 17 00:00:00 2001 From: butterfly Date: Mon, 6 May 2024 19:26:39 +0800 Subject: [PATCH 14/28] feat: fix 1)the property named 'role' of the first message must be 'user' 2)if default summarize model 'gpt-3.5-turbo' is blocked, use currentModel instead 3)if apiurl&apikey set by location, useCustomConfig would be opened --- app/api/webdav/[...path]/route.ts | 12 +++++++----- app/client/platforms/anthropic.ts | 7 +++++++ app/components/chat.tsx | 1 + app/config/server.ts | 8 ++++---- app/constant.ts | 2 +- app/store/chat.ts | 16 ++++++++++++++-- app/utils/model.ts | 5 +---- 7 files changed, 35 insertions(+), 16 deletions(-) diff --git a/app/api/webdav/[...path]/route.ts b/app/api/webdav/[...path]/route.ts index 3dd9ca3cd..816c2046b 100644 --- a/app/api/webdav/[...path]/route.ts +++ b/app/api/webdav/[...path]/route.ts @@ -1,12 +1,12 @@ import { NextRequest, NextResponse } from "next/server"; -import { STORAGE_KEY, internalWhiteWebDavEndpoints } from "../../../constant"; +import { STORAGE_KEY, internalAllowedWebDavEndpoints } from "../../../constant"; import { getServerSideConfig } from "@/app/config/server"; const config = getServerSideConfig(); -const mergedWhiteWebDavEndpoints = [ - ...internalWhiteWebDavEndpoints, - ...config.whiteWebDevEndpoints, +const mergedAllowedWebDavEndpoints = [ + ...internalAllowedWebDavEndpoints, + ...config.allowedWebDevEndpoints, ].filter((domain) => Boolean(domain.trim())); async function handle( @@ -24,7 +24,9 @@ async function handle( // Validate the endpoint to prevent potential SSRF attacks if ( - !mergedWhiteWebDavEndpoints.some((white) => endpoint?.startsWith(white)) + !mergedAllowedWebDavEndpoints.some( + (allowedEndpoint) => endpoint?.startsWith(allowedEndpoint), + ) ) { return NextResponse.json( { diff --git a/app/client/platforms/anthropic.ts b/app/client/platforms/anthropic.ts index ba07dcc76..54a171cda 100644 --- a/app/client/platforms/anthropic.ts +++ b/app/client/platforms/anthropic.ts @@ -161,6 +161,13 @@ export class ClaudeApi implements LLMApi { }; }); + if (prompt[0]?.role === "assistant") { + prompt.unshift({ + role: "user", + content: "", + }); + } + const requestBody: AnthropicChatRequest = { messages: prompt, stream: shouldStream, diff --git a/app/components/chat.tsx b/app/components/chat.tsx index 85df5b9a8..c1400edc6 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -1088,6 +1088,7 @@ function _Chat() { if (payload.url) { accessStore.update((access) => (access.openaiUrl = payload.url!)); } + accessStore.useCustomConfig = true; }); } } catch { diff --git a/app/config/server.ts b/app/config/server.ts index 618112172..edf58aaff 100644 --- a/app/config/server.ts +++ b/app/config/server.ts @@ -82,9 +82,9 @@ export const getServerSideConfig = () => { `[Server Config] using ${randomIndex + 1} of ${apiKeys.length} api key`, ); - const whiteWebDevEndpoints = (process.env.WHITE_WEBDEV_ENDPOINTS ?? "").split( - ",", - ); + const allowedWebDevEndpoints = ( + process.env.WHITE_WEBDEV_ENDPOINTS ?? "" + ).split(","); return { baseUrl: process.env.BASE_URL, @@ -120,6 +120,6 @@ export const getServerSideConfig = () => { disableFastLink: !!process.env.DISABLE_FAST_LINK, customModels, defaultModel, - whiteWebDevEndpoints, + allowedWebDevEndpoints, }; }; diff --git a/app/constant.ts b/app/constant.ts index 8b6549566..a3d9c206f 100644 --- a/app/constant.ts +++ b/app/constant.ts @@ -197,7 +197,7 @@ export const CHAT_PAGE_SIZE = 15; export const MAX_RENDER_MSG_COUNT = 45; // some famous webdav endpoints -export const internalWhiteWebDavEndpoints = [ +export const internalAllowedWebDavEndpoints = [ "https://dav.jianguoyun.com/dav/", "https://dav.dropdav.com/", "https://dav.box.com/dav", diff --git a/app/store/chat.ts b/app/store/chat.ts index b305264b6..a5412eaa9 100644 --- a/app/store/chat.ts +++ b/app/store/chat.ts @@ -21,6 +21,8 @@ import { estimateTokenLength } from "../utils/token"; import { nanoid } from "nanoid"; import { createPersistStore } from "../utils/store"; import { identifyDefaultClaudeModel } from "../utils/checkers"; +import { collectModelsWithDefaultModel } from "../utils/model"; +import { useAccessStore } from "./access"; export type ChatMessage = RequestMessage & { date: string; @@ -87,9 +89,19 @@ function createEmptySession(): ChatSession { function getSummarizeModel(currentModel: string) { // if it is using gpt-* models, force to use 3.5 to summarize if (currentModel.startsWith("gpt")) { - return SUMMARIZE_MODEL; + const configStore = useAppConfig.getState(); + const accessStore = useAccessStore.getState(); + const allModel = collectModelsWithDefaultModel( + configStore.models, + [configStore.customModels, accessStore.customModels].join(","), + accessStore.defaultModel, + ); + const summarizeModel = allModel.find( + (m) => m.name === SUMMARIZE_MODEL && m.available, + ); + return summarizeModel?.name ?? currentModel; } - if (currentModel.startsWith("gemini-pro")) { + if (currentModel.startsWith("gemini")) { return GEMINI_SUMMARIZE_MODEL; } return currentModel; diff --git a/app/utils/model.ts b/app/utils/model.ts index 6477640aa..056fff2e9 100644 --- a/app/utils/model.ts +++ b/app/utils/model.ts @@ -64,13 +64,10 @@ export function collectModelTableWithDefaultModel( ) { let modelTable = collectModelTable(models, customModels); if (defaultModel && defaultModel !== "") { - delete modelTable[defaultModel]; modelTable[defaultModel] = { + ...modelTable[defaultModel], name: defaultModel, - displayName: defaultModel, available: true, - provider: - modelTable[defaultModel]?.provider ?? customProvider(defaultModel), isDefault: true, }; } From a1493bfb4e9efe0a2e12917ab861bbf2321dbd7d Mon Sep 17 00:00:00 2001 From: Dean-YZG Date: Mon, 6 May 2024 20:46:53 +0800 Subject: [PATCH 15/28] feat: bugfix --- app/client/platforms/anthropic.ts | 2 +- app/components/chat.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/client/platforms/anthropic.ts b/app/client/platforms/anthropic.ts index 54a171cda..e90c8f057 100644 --- a/app/client/platforms/anthropic.ts +++ b/app/client/platforms/anthropic.ts @@ -164,7 +164,7 @@ export class ClaudeApi implements LLMApi { if (prompt[0]?.role === "assistant") { prompt.unshift({ role: "user", - content: "", + content: ";", }); } diff --git a/app/components/chat.tsx b/app/components/chat.tsx index c1400edc6..c8a79870c 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -1088,7 +1088,7 @@ function _Chat() { if (payload.url) { accessStore.update((access) => (access.openaiUrl = payload.url!)); } - accessStore.useCustomConfig = true; + accessStore.update((access) => (access.useCustomConfig = true)); }); } } catch { From 864529cbf61925f3b85cfa698613c766efd93436 Mon Sep 17 00:00:00 2001 From: Dean-YZG Date: Mon, 6 May 2024 21:14:53 +0800 Subject: [PATCH 16/28] feat: googleApiKey & anthropicApiKey support setting multi-key --- app/config/server.ts | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/app/config/server.ts b/app/config/server.ts index edf58aaff..b5d754dde 100644 --- a/app/config/server.ts +++ b/app/config/server.ts @@ -51,6 +51,22 @@ const ACCESS_CODES = (function getAccessCodes(): Set { } })(); +function getApiKey(keys?: string) { + const apiKeyEnvVar = keys ?? ""; + const apiKeys = apiKeyEnvVar.split(",").map((v) => v.trim()); + const randomIndex = Math.floor(Math.random() * apiKeys.length); + const apiKey = apiKeys[randomIndex]; + if (apiKey) { + console.log( + `[Server Config] using ${randomIndex + 1} of ${ + apiKeys.length + } api key - ${apiKey}`, + ); + } + + return apiKey; +} + export const getServerSideConfig = () => { if (typeof process === "undefined") { throw Error( @@ -74,13 +90,13 @@ export const getServerSideConfig = () => { const isGoogle = !!process.env.GOOGLE_API_KEY; const isAnthropic = !!process.env.ANTHROPIC_API_KEY; - const apiKeyEnvVar = process.env.OPENAI_API_KEY ?? ""; - const apiKeys = apiKeyEnvVar.split(",").map((v) => v.trim()); - const randomIndex = Math.floor(Math.random() * apiKeys.length); - const apiKey = apiKeys[randomIndex]; - console.log( - `[Server Config] using ${randomIndex + 1} of ${apiKeys.length} api key`, - ); + // const apiKeyEnvVar = process.env.OPENAI_API_KEY ?? ""; + // const apiKeys = apiKeyEnvVar.split(",").map((v) => v.trim()); + // const randomIndex = Math.floor(Math.random() * apiKeys.length); + // const apiKey = apiKeys[randomIndex]; + // console.log( + // `[Server Config] using ${randomIndex + 1} of ${apiKeys.length} api key`, + // ); const allowedWebDevEndpoints = ( process.env.WHITE_WEBDEV_ENDPOINTS ?? "" @@ -88,20 +104,20 @@ export const getServerSideConfig = () => { return { baseUrl: process.env.BASE_URL, - apiKey, + apiKey: getApiKey(process.env.OPENAI_API_KEY), openaiOrgId: process.env.OPENAI_ORG_ID, isAzure, azureUrl: process.env.AZURE_URL, - azureApiKey: process.env.AZURE_API_KEY, + azureApiKey: getApiKey(process.env.AZURE_API_KEY), azureApiVersion: process.env.AZURE_API_VERSION, isGoogle, - googleApiKey: process.env.GOOGLE_API_KEY, + googleApiKey: getApiKey(process.env.GOOGLE_API_KEY), googleUrl: process.env.GOOGLE_URL, isAnthropic, - anthropicApiKey: process.env.ANTHROPIC_API_KEY, + anthropicApiKey: getApiKey(process.env.ANTHROPIC_API_KEY), anthropicApiVersion: process.env.ANTHROPIC_API_VERSION, anthropicUrl: process.env.ANTHROPIC_URL, From cd48f7eff4f811515eabbc99e219dd0dbbcabe19 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 May 2024 00:27:02 +0000 Subject: [PATCH 17/28] chore(deps): bump next from 13.4.9 to 14.1.1 Bumps [next](https://github.com/vercel/next.js) from 13.4.9 to 14.1.1. - [Release notes](https://github.com/vercel/next.js/releases) - [Changelog](https://github.com/vercel/next.js/blob/canary/release.js) - [Commits](https://github.com/vercel/next.js/compare/v13.4.9...v14.1.1) --- updated-dependencies: - dependency-name: next dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- package.json | 2 +- yarn.lock | 160 +++++++++++++++++++++++++-------------------------- 2 files changed, 78 insertions(+), 84 deletions(-) diff --git a/package.json b/package.json index 9dbae8208..e64730eac 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "html-to-image": "^1.11.11", "mermaid": "^10.6.1", "nanoid": "^5.0.3", - "next": "^13.4.9", + "next": "^14.1.1", "node-fetch": "^3.3.1", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/yarn.lock b/yarn.lock index 66924bf41..09270d14f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1218,10 +1218,10 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" -"@next/env@13.4.9": - version "13.4.9" - resolved "https://registry.yarnpkg.com/@next/env/-/env-13.4.9.tgz#b77759514dd56bfa9791770755a2482f4d6ca93e" - integrity sha512-vuDRK05BOKfmoBYLNi2cujG2jrYbEod/ubSSyqgmEx9n/W3eZaJQdRNhTfumO+qmq/QTzLurW487n/PM/fHOkw== +"@next/env@14.1.1": + version "14.1.1" + resolved "https://registry.yarnpkg.com/@next/env/-/env-14.1.1.tgz#80150a8440eb0022a73ba353c6088d419b908bac" + integrity sha512-7CnQyD5G8shHxQIIg3c7/pSeYFeMhsNbpU/bmvH7ZnDql7mNRgg8O2JZrhrc/soFnfBnKP4/xXNiiSIPn2w8gA== "@next/eslint-plugin-next@13.4.19": version "13.4.19" @@ -1230,50 +1230,50 @@ dependencies: glob "7.1.7" -"@next/swc-darwin-arm64@13.4.9": - version "13.4.9" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.9.tgz#0ed408d444bbc6b0a20f3506a9b4222684585677" - integrity sha512-TVzGHpZoVBk3iDsTOQA/R6MGmFp0+17SWXMEWd6zG30AfuELmSSMe2SdPqxwXU0gbpWkJL1KgfLzy5ReN0crqQ== +"@next/swc-darwin-arm64@14.1.1": + version "14.1.1" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.1.1.tgz#b74ba7c14af7d05fa2848bdeb8ee87716c939b64" + integrity sha512-yDjSFKQKTIjyT7cFv+DqQfW5jsD+tVxXTckSe1KIouKk75t1qZmj/mV3wzdmFb0XHVGtyRjDMulfVG8uCKemOQ== -"@next/swc-darwin-x64@13.4.9": - version "13.4.9" - resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.9.tgz#a08fccdee68201522fe6618ec81f832084b222f8" - integrity sha512-aSfF1fhv28N2e7vrDZ6zOQ+IIthocfaxuMWGReB5GDriF0caTqtHttAvzOMgJgXQtQx6XhyaJMozLTSEXeNN+A== +"@next/swc-darwin-x64@14.1.1": + version "14.1.1" + resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-14.1.1.tgz#82c3e67775e40094c66e76845d1a36cc29c9e78b" + integrity sha512-KCQmBL0CmFmN8D64FHIZVD9I4ugQsDBBEJKiblXGgwn7wBCSe8N4Dx47sdzl4JAg39IkSN5NNrr8AniXLMb3aw== -"@next/swc-linux-arm64-gnu@13.4.9": - version "13.4.9" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.9.tgz#1798c2341bb841e96521433eed00892fb24abbd1" - integrity sha512-JhKoX5ECzYoTVyIy/7KykeO4Z2lVKq7HGQqvAH+Ip9UFn1MOJkOnkPRB7v4nmzqAoY+Je05Aj5wNABR1N18DMg== +"@next/swc-linux-arm64-gnu@14.1.1": + version "14.1.1" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.1.1.tgz#4f4134457b90adc5c3d167d07dfb713c632c0caa" + integrity sha512-YDQfbWyW0JMKhJf/T4eyFr4b3tceTorQ5w2n7I0mNVTFOvu6CGEzfwT3RSAQGTi/FFMTFcuspPec/7dFHuP7Eg== -"@next/swc-linux-arm64-musl@13.4.9": - version "13.4.9" - resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.9.tgz#cee04c51610eddd3638ce2499205083656531ea0" - integrity sha512-OOn6zZBIVkm/4j5gkPdGn4yqQt+gmXaLaSjRSO434WplV8vo2YaBNbSHaTM9wJpZTHVDYyjzuIYVEzy9/5RVZw== +"@next/swc-linux-arm64-musl@14.1.1": + version "14.1.1" + resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.1.1.tgz#594bedafaeba4a56db23a48ffed2cef7cd09c31a" + integrity sha512-fiuN/OG6sNGRN/bRFxRvV5LyzLB8gaL8cbDH5o3mEiVwfcMzyE5T//ilMmaTrnA8HLMS6hoz4cHOu6Qcp9vxgQ== -"@next/swc-linux-x64-gnu@13.4.9": - version "13.4.9" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.9.tgz#1932d0367916adbc6844b244cda1d4182bd11f7a" - integrity sha512-iA+fJXFPpW0SwGmx/pivVU+2t4zQHNOOAr5T378PfxPHY6JtjV6/0s1vlAJUdIHeVpX98CLp9k5VuKgxiRHUpg== +"@next/swc-linux-x64-gnu@14.1.1": + version "14.1.1" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.1.1.tgz#cb4e75f1ff2b9bcadf2a50684605928ddfc58528" + integrity sha512-rv6AAdEXoezjbdfp3ouMuVqeLjE1Bin0AuE6qxE6V9g3Giz5/R3xpocHoAi7CufRR+lnkuUjRBn05SYJ83oKNQ== -"@next/swc-linux-x64-musl@13.4.9": - version "13.4.9" - resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.9.tgz#a66aa8c1383b16299b72482f6360facd5cde3c7a" - integrity sha512-rlNf2WUtMM+GAQrZ9gMNdSapkVi3koSW3a+dmBVp42lfugWVvnyzca/xJlN48/7AGx8qu62WyO0ya1ikgOxh6A== +"@next/swc-linux-x64-musl@14.1.1": + version "14.1.1" + resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.1.1.tgz#15f26800df941b94d06327f674819ab64b272e25" + integrity sha512-YAZLGsaNeChSrpz/G7MxO3TIBLaMN8QWMr3X8bt6rCvKovwU7GqQlDu99WdvF33kI8ZahvcdbFsy4jAFzFX7og== -"@next/swc-win32-arm64-msvc@13.4.9": - version "13.4.9" - resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.9.tgz#39482ee856c867177a612a30b6861c75e0736a4a" - integrity sha512-5T9ybSugXP77nw03vlgKZxD99AFTHaX8eT1ayKYYnGO9nmYhJjRPxcjU5FyYI+TdkQgEpIcH7p/guPLPR0EbKA== +"@next/swc-win32-arm64-msvc@14.1.1": + version "14.1.1" + resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.1.1.tgz#060c134fa7fa843666e3e8574972b2b723773dd9" + integrity sha512-1L4mUYPBMvVDMZg1inUYyPvFSduot0g73hgfD9CODgbr4xiTYe0VOMTZzaRqYJYBA9mana0x4eaAaypmWo1r5A== -"@next/swc-win32-ia32-msvc@13.4.9": - version "13.4.9" - resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.9.tgz#29db85e34b597ade1a918235d16a760a9213c190" - integrity sha512-ojZTCt1lP2ucgpoiFgrFj07uq4CZsq4crVXpLGgQfoFq00jPKRPgesuGPaz8lg1yLfvafkU3Jd1i8snKwYR3LA== +"@next/swc-win32-ia32-msvc@14.1.1": + version "14.1.1" + resolved "https://registry.yarnpkg.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.1.1.tgz#5c06889352b1f77e3807834a0d0afd7e2d2d1da2" + integrity sha512-jvIE9tsuj9vpbbXlR5YxrghRfMuG0Qm/nZ/1KDHc+y6FpnZ/apsgh+G6t15vefU0zp3WSpTMIdXRUsNl/7RSuw== -"@next/swc-win32-x64-msvc@13.4.9": - version "13.4.9" - resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.9.tgz#0c2758164cccd61bc5a1c6cd8284fe66173e4a2b" - integrity sha512-QbT03FXRNdpuL+e9pLnu+XajZdm/TtIXVYY4lA9t+9l0fLZbHXDYEKitAqxrOj37o3Vx5ufxiRAniaIebYDCgw== +"@next/swc-win32-x64-msvc@14.1.1": + version "14.1.1" + resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.1.1.tgz#d38c63a8f9b7f36c1470872797d3735b4a9c5c52" + integrity sha512-S6K6EHDU5+1KrBDLko7/c1MNy/Ya73pIAmvKeFwsF4RmBFJSO7/7YeD4FnZ4iBdzE69PpQ4sOMU9ORKeNuxe8A== "@next/third-parties@^14.1.0": version "14.1.0" @@ -1424,10 +1424,10 @@ "@svgr/plugin-jsx" "^6.5.1" "@svgr/plugin-svgo" "^6.5.1" -"@swc/helpers@0.5.1": - version "0.5.1" - resolved "https://registry.npmmirror.com/@swc/helpers/-/helpers-0.5.1.tgz#e9031491aa3f26bfcc974a67f48bd456c8a5357a" - integrity sha512-sJ902EfIzn1Fa+qYmjdQqh8tPsoxyBz+8yBKC2HKUxyezKJFwPGOn7pv4WY6QuQW//ySQi5lJjA/ZT9sNWWNTg== +"@swc/helpers@0.5.2": + version "0.5.2" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.2.tgz#85ea0c76450b61ad7d10a37050289eded783c27d" + integrity sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw== dependencies: tslib "^2.4.0" @@ -2130,10 +2130,10 @@ camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001449, caniuse-lite@^1.0.30001503: - version "1.0.30001509" - resolved "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001509.tgz#2b7ad5265392d6d2de25cd8776d1ab3899570d14" - integrity sha512-2uDDk+TRiTX5hMcUYT/7CSyzMZxjfGu0vAUjS2g0LSD8UoXOv0LtpH4LxGMemsiPq6LCVIUjNwVM0erkOkGCDA== +caniuse-lite@^1.0.30001449, caniuse-lite@^1.0.30001503, caniuse-lite@^1.0.30001579: + version "1.0.30001617" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001617.tgz#809bc25f3f5027ceb33142a7d6c40759d7a901eb" + integrity sha512-mLyjzNI9I+Pix8zwcrpxEbGlfqOkF9kM3ptzmKNw5tizSyYwMe+nGLTqMK9cO+0E+Bh6TsBxNAaHWEM8xwSsmA== ccount@^2.0.0: version "2.0.1" @@ -3525,7 +3525,7 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" -graceful-fs@^4.1.2, graceful-fs@^4.2.4, graceful-fs@^4.2.9: +graceful-fs@^4.1.2, graceful-fs@^4.2.11, graceful-fs@^4.2.4, graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -4753,10 +4753,10 @@ ms@^2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -nanoid@^3.3.4: - version "3.3.6" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" - integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== +nanoid@^3.3.6: + version "3.3.7" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" + integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== nanoid@^5.0.3: version "5.0.3" @@ -4773,29 +4773,28 @@ neo-async@^2.6.2: resolved "https://registry.npmmirror.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== -next@^13.4.9: - version "13.4.9" - resolved "https://registry.yarnpkg.com/next/-/next-13.4.9.tgz#473de5997cb4c5d7a4fb195f566952a1cbffbeba" - integrity sha512-vtefFm/BWIi/eWOqf1GsmKG3cjKw1k3LjuefKRcL3iiLl3zWzFdPG3as6xtxrGO6gwTzzaO1ktL4oiHt/uvTjA== +next@^14.1.1: + version "14.1.1" + resolved "https://registry.yarnpkg.com/next/-/next-14.1.1.tgz#92bd603996c050422a738e90362dff758459a171" + integrity sha512-McrGJqlGSHeaz2yTRPkEucxQKe5Zq7uPwyeHNmJaZNY4wx9E9QdxmTp310agFRoMuIYgQrCrT3petg13fSVOww== dependencies: - "@next/env" "13.4.9" - "@swc/helpers" "0.5.1" + "@next/env" "14.1.1" + "@swc/helpers" "0.5.2" busboy "1.6.0" - caniuse-lite "^1.0.30001406" - postcss "8.4.14" + caniuse-lite "^1.0.30001579" + graceful-fs "^4.2.11" + postcss "8.4.31" styled-jsx "5.1.1" - watchpack "2.4.0" - zod "3.21.4" optionalDependencies: - "@next/swc-darwin-arm64" "13.4.9" - "@next/swc-darwin-x64" "13.4.9" - "@next/swc-linux-arm64-gnu" "13.4.9" - "@next/swc-linux-arm64-musl" "13.4.9" - "@next/swc-linux-x64-gnu" "13.4.9" - "@next/swc-linux-x64-musl" "13.4.9" - "@next/swc-win32-arm64-msvc" "13.4.9" - "@next/swc-win32-ia32-msvc" "13.4.9" - "@next/swc-win32-x64-msvc" "13.4.9" + "@next/swc-darwin-arm64" "14.1.1" + "@next/swc-darwin-x64" "14.1.1" + "@next/swc-linux-arm64-gnu" "14.1.1" + "@next/swc-linux-arm64-musl" "14.1.1" + "@next/swc-linux-x64-gnu" "14.1.1" + "@next/swc-linux-x64-musl" "14.1.1" + "@next/swc-win32-arm64-msvc" "14.1.1" + "@next/swc-win32-ia32-msvc" "14.1.1" + "@next/swc-win32-x64-msvc" "14.1.1" node-domexception@^1.0.0: version "1.0.0" @@ -5036,12 +5035,12 @@ pidtree@^0.6.0: resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c" integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g== -postcss@8.4.14: - version "8.4.14" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf" - integrity sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig== +postcss@8.4.31: + version "8.4.31" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.31.tgz#92b451050a9f914da6755af352bdc0192508656d" + integrity sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ== dependencies: - nanoid "^3.3.4" + nanoid "^3.3.6" picocolors "^1.0.0" source-map-js "^1.0.2" @@ -6039,7 +6038,7 @@ vfile@^5.0.0: unist-util-stringify-position "^3.0.0" vfile-message "^3.0.0" -watchpack@2.4.0, watchpack@^2.4.0: +watchpack@^2.4.0: version "2.4.0" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== @@ -6185,11 +6184,6 @@ yocto-queue@^0.1.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== -zod@3.21.4: - version "3.21.4" - resolved "https://registry.npmmirror.com/zod/-/zod-3.21.4.tgz#10882231d992519f0a10b5dd58a38c9dabbb64db" - integrity sha512-m46AKbrzKVzOzs/DZgVnG5H55N1sv1M8qZU3A8RIKbs3mrACDNeIOeilDymVb2HdmP8uwshOCF4uJ8uM9rCqJw== - zustand@^4.3.8: version "4.3.8" resolved "https://registry.yarnpkg.com/zustand/-/zustand-4.3.8.tgz#37113df8e9e1421b0be1b2dca02b49b76210e7c4" From c10447df79b6e3300f65885f94472e435f53c03f Mon Sep 17 00:00:00 2001 From: Dean-YZG Date: Mon, 13 May 2024 16:24:15 +0800 Subject: [PATCH 18/28] feat: 1)upload image with type 'heic' 2)change the empty message to ';' for models 3) --- app/components/chat.tsx | 3 +- app/store/chat.ts | 2 +- app/utils.ts | 56 ++++---------------------------------- app/utils/chat.ts | 54 ++++++++++++++++++++++++++++++++++++ app/utils/cloud/upstash.ts | 11 +++++--- package.json | 1 + yarn.lock | 5 ++++ 7 files changed, 76 insertions(+), 56 deletions(-) create mode 100644 app/utils/chat.ts diff --git a/app/components/chat.tsx b/app/components/chat.tsx index c8a79870c..061192504 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -59,9 +59,10 @@ import { getMessageTextContent, getMessageImages, isVisionModel, - compressImage, } from "../utils"; +import { compressImage } from "@/app/utils/chat"; + import dynamic from "next/dynamic"; import { ChatControllerPool } from "../client/controller"; diff --git a/app/store/chat.ts b/app/store/chat.ts index a5412eaa9..a97c67e9d 100644 --- a/app/store/chat.ts +++ b/app/store/chat.ts @@ -433,7 +433,7 @@ export const useChatStore = createPersistStore( content: session.memoryPrompt.length > 0 ? Locale.Store.Prompt.History(session.memoryPrompt) - : "", + : ";", date: "", } as ChatMessage; }, diff --git a/app/utils.ts b/app/utils.ts index 07d0dcb13..dbb0e4a0b 100644 --- a/app/utils.ts +++ b/app/utils.ts @@ -83,48 +83,6 @@ export async function downloadAs(text: string, filename: string) { } } -export function compressImage(file: File, maxSize: number): Promise { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - reader.onload = (readerEvent: any) => { - const image = new Image(); - image.onload = () => { - let canvas = document.createElement("canvas"); - let ctx = canvas.getContext("2d"); - let width = image.width; - let height = image.height; - let quality = 0.9; - let dataUrl; - - do { - canvas.width = width; - canvas.height = height; - ctx?.clearRect(0, 0, canvas.width, canvas.height); - ctx?.drawImage(image, 0, 0, width, height); - dataUrl = canvas.toDataURL("image/jpeg", quality); - - if (dataUrl.length < maxSize) break; - - if (quality > 0.5) { - // Prioritize quality reduction - quality -= 0.1; - } else { - // Then reduce the size - width *= 0.9; - height *= 0.9; - } - } while (dataUrl.length > maxSize); - - resolve(dataUrl); - }; - image.onerror = reject; - image.src = readerEvent.target.result; - }; - reader.onerror = reject; - reader.readAsDataURL(file); - }); -} - export function readFromFile() { return new Promise((res, rej) => { const fileInput = document.createElement("input"); @@ -290,16 +248,14 @@ export function getMessageImages(message: RequestMessage): string[] { } export function isVisionModel(model: string) { - // Note: This is a better way using the TypeScript feature instead of `&&` or `||` (ts v5.5.0-dev.20240314 I've been using) - const visionKeywords = [ - "vision", - "claude-3", - "gemini-1.5-pro", - ]; + const visionKeywords = ["vision", "claude-3", "gemini-1.5-pro"]; - const isGpt4Turbo = model.includes("gpt-4-turbo") && !model.includes("preview"); + const isGpt4Turbo = + model.includes("gpt-4-turbo") && !model.includes("preview"); - return visionKeywords.some((keyword) => model.includes(keyword)) || isGpt4Turbo; + return ( + visionKeywords.some((keyword) => model.includes(keyword)) || isGpt4Turbo + ); } diff --git a/app/utils/chat.ts b/app/utils/chat.ts new file mode 100644 index 000000000..991d06b73 --- /dev/null +++ b/app/utils/chat.ts @@ -0,0 +1,54 @@ +import heic2any from "heic2any"; + +export function compressImage(file: File, maxSize: number): Promise { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = (readerEvent: any) => { + const image = new Image(); + image.onload = () => { + let canvas = document.createElement("canvas"); + let ctx = canvas.getContext("2d"); + let width = image.width; + let height = image.height; + let quality = 0.9; + let dataUrl; + + do { + canvas.width = width; + canvas.height = height; + ctx?.clearRect(0, 0, canvas.width, canvas.height); + ctx?.drawImage(image, 0, 0, width, height); + dataUrl = canvas.toDataURL("image/jpeg", quality); + + if (dataUrl.length < maxSize) break; + + if (quality > 0.5) { + // Prioritize quality reduction + quality -= 0.1; + } else { + // Then reduce the size + width *= 0.9; + height *= 0.9; + } + } while (dataUrl.length > maxSize); + + resolve(dataUrl); + }; + image.onerror = reject; + image.src = readerEvent.target.result; + }; + reader.onerror = reject; + + if (file.type.includes("heic")) { + heic2any({ blob: file, toType: "image/jpeg" }) + .then((blob) => { + reader.readAsDataURL(blob as Blob); + }) + .catch((e) => { + reject(e); + }); + } + + reader.readAsDataURL(file); + }); +} diff --git a/app/utils/cloud/upstash.ts b/app/utils/cloud/upstash.ts index bf6147bd4..8d84adbde 100644 --- a/app/utils/cloud/upstash.ts +++ b/app/utils/cloud/upstash.ts @@ -93,14 +93,17 @@ export function createUpstashClient(store: SyncStore) { } let url; - if (proxyUrl.length > 0 || proxyUrl === "/") { - let u = new URL(proxyUrl + "/api/upstash/" + path); + const pathPrefix = "/api/upstash/"; + + try { + let u = new URL(proxyUrl + pathPrefix + path); // add query params u.searchParams.append("endpoint", config.endpoint); url = u.toString(); - } else { - url = "/api/upstash/" + path + "?endpoint=" + config.endpoint; + } catch (e) { + url = pathPrefix + path + "?endpoint=" + config.endpoint; } + return url; }, }; diff --git a/package.json b/package.json index 9dbae8208..6fd3b0ec6 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "@vercel/speed-insights": "^1.0.2", "emoji-picker-react": "^4.9.2", "fuse.js": "^7.0.0", + "heic2any": "^0.0.4", "html-to-image": "^1.11.11", "mermaid": "^10.6.1", "nanoid": "^5.0.3", diff --git a/yarn.lock b/yarn.lock index 66924bf41..933dcae52 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3669,6 +3669,11 @@ heap@^0.2.6: resolved "https://registry.npmmirror.com/heap/-/heap-0.2.7.tgz#1e6adf711d3f27ce35a81fe3b7bd576c2260a8fc" integrity sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg== +heic2any@^0.0.4: + version "0.0.4" + resolved "https://registry.npmmirror.com/heic2any/-/heic2any-0.0.4.tgz#eddb8e6fec53c8583a6e18b65069bb5e8d19028a" + integrity sha512-3lLnZiDELfabVH87htnRolZ2iehX9zwpRyGNz22GKXIu0fznlblf0/ftppXKNqS26dqFSeqfIBhAmAj/uSp0cA== + highlight.js@~11.7.0: version "11.7.0" resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-11.7.0.tgz#3ff0165bc843f8c9bce1fd89e2fda9143d24b11e" From d3131d2f55b10c425d2fe36cdb459862cde65fd4 Mon Sep 17 00:00:00 2001 From: Dmitry Sandalov Date: Mon, 13 May 2024 10:39:49 +0200 Subject: [PATCH 19/28] Fix typo for "OpenAI Endpoint" in the en locale --- app/locales/en.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/locales/en.ts b/app/locales/en.ts index 59636db7b..aa153f523 100644 --- a/app/locales/en.ts +++ b/app/locales/en.ts @@ -296,7 +296,7 @@ const en: LocaleType = { Endpoint: { Title: "OpenAI Endpoint", - SubTitle: "Must starts with http(s):// or use /api/openai as default", + SubTitle: "Must start with http(s):// or use /api/openai as default", }, }, Azure: { From 2d1f0c9f5760b726153c347ef3f6b6bffcd439a5 Mon Sep 17 00:00:00 2001 From: Dean-YZG Date: Mon, 13 May 2024 17:11:11 +0800 Subject: [PATCH 20/28] feat: support env var DEFAULT_INPUT_TEMPLATE to custom default template for preprocessing user inputs --- README.md | 6 +++++- README_CN.md | 3 +++ app/config/build.ts | 2 ++ app/config/server.ts | 3 +++ app/store/config.ts | 9 +++++---- 5 files changed, 18 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 633124ec7..d496d68ed 100644 --- a/README.md +++ b/README.md @@ -245,13 +245,17 @@ To control custom models, use `+` to add a custom model, use `-` to hide a model User `-all` to disable all default models, `+all` to enable all default models. -### `WHITE_WEBDEV_ENDPOINTS` (可选) +### `WHITE_WEBDEV_ENDPOINTS` (optional) You can use this option if you want to increase the number of webdav service addresses you are allowed to access, as required by the format: - Each address must be a complete endpoint > `https://xxxx/yyy` - Multiple addresses are connected by ', ' +### `DEFAULT_INPUT_TEMPLATE` (optional) + +Customize the default template used to initialize the User Input Preprocessing configuration item in Settings. + ## Requirements NodeJS >= 18, Docker >= 20 diff --git a/README_CN.md b/README_CN.md index 10b5fd035..6811102b6 100644 --- a/README_CN.md +++ b/README_CN.md @@ -156,6 +156,9 @@ anthropic claude Api Url. 用来控制模型列表,使用 `+` 增加一个模型,使用 `-` 来隐藏一个模型,使用 `模型名=展示名` 来自定义模型的展示名,用英文逗号隔开。 +### `DEFAULT_INPUT_TEMPLATE` (可选) +自定义默认的 template,用于初始化『设置』中的『用户输入预处理』配置项 + ## 开发 点击下方按钮,开始二次开发: diff --git a/app/config/build.ts b/app/config/build.ts index 7a93ad02c..b2b1ad49d 100644 --- a/app/config/build.ts +++ b/app/config/build.ts @@ -1,4 +1,5 @@ import tauriConfig from "../../src-tauri/tauri.conf.json"; +import { DEFAULT_INPUT_TEMPLATE } from "../constant"; export const getBuildConfig = () => { if (typeof process === "undefined") { @@ -38,6 +39,7 @@ export const getBuildConfig = () => { ...commitInfo, buildMode, isApp, + template: process.env.DEFAULT_INPUT_TEMPLATE ?? DEFAULT_INPUT_TEMPLATE, }; }; diff --git a/app/config/server.ts b/app/config/server.ts index b5d754dde..b7c85ce6a 100644 --- a/app/config/server.ts +++ b/app/config/server.ts @@ -34,6 +34,9 @@ declare global { // google tag manager GTM_ID?: string; + + // custom template for preprocessing user input + DEFAULT_INPUT_TEMPLATE?: string; } } } diff --git a/app/store/config.ts b/app/store/config.ts index 6f2f558a0..0f9f78ed7 100644 --- a/app/store/config.ts +++ b/app/store/config.ts @@ -1,5 +1,4 @@ import { LLMModel } from "../client/api"; -import { isMacOS } from "../utils"; import { getClientConfig } from "../config/client"; import { DEFAULT_INPUT_TEMPLATE, @@ -25,6 +24,8 @@ export enum Theme { Light = "light", } +const config = getClientConfig(); + export const DEFAULT_CONFIG = { lastUpdate: Date.now(), // timestamp, to merge state @@ -32,7 +33,7 @@ export const DEFAULT_CONFIG = { avatar: "1f603", fontSize: 14, theme: Theme.Auto as Theme, - tightBorder: !!getClientConfig()?.isApp, + tightBorder: !!config?.isApp, sendPreviewBubble: true, enableAutoGenerateTitle: true, sidebarWidth: DEFAULT_SIDEBAR_WIDTH, @@ -56,7 +57,7 @@ export const DEFAULT_CONFIG = { historyMessageCount: 4, compressMessageLengthThreshold: 1000, enableInjectSystemPrompts: true, - template: DEFAULT_INPUT_TEMPLATE, + template: config?.template ?? DEFAULT_INPUT_TEMPLATE, }, }; @@ -132,7 +133,7 @@ export const useAppConfig = createPersistStore( }), { name: StoreKey.Config, - version: 3.8, + version: 3.9, migrate(persistedState, version) { const state = persistedState as ChatConfig; From 9d7ce207b689d2636465da8088a1d96c1275d27a Mon Sep 17 00:00:00 2001 From: Dean-YZG Date: Mon, 13 May 2024 17:11:35 +0800 Subject: [PATCH 21/28] feat: support env var DEFAULT_INPUT_TEMPLATE to custom default template for preprocessing user inputs --- app/store/config.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/app/store/config.ts b/app/store/config.ts index 0f9f78ed7..94cfcd8ec 100644 --- a/app/store/config.ts +++ b/app/store/config.ts @@ -164,6 +164,13 @@ export const useAppConfig = createPersistStore( state.lastUpdate = Date.now(); } + if (version < 3.9) { + state.modelConfig.template = + state.modelConfig.template !== DEFAULT_INPUT_TEMPLATE + ? state.modelConfig.template + : config?.template ?? DEFAULT_INPUT_TEMPLATE; + } + return state as any; }, }, From ef5f910f196fb534a8e7ff75a8c510cafb8c5713 Mon Sep 17 00:00:00 2001 From: Leo Li Date: Mon, 13 May 2024 17:28:13 -0400 Subject: [PATCH 22/28] support gpt-4o --- app/constant.ts | 6 +++++- app/utils.ts | 11 ++++------- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/app/constant.ts b/app/constant.ts index a3d9c206f..0d37a420b 100644 --- a/app/constant.ts +++ b/app/constant.ts @@ -127,6 +127,8 @@ export const KnowledgeCutOffDate: Record = { "gpt-4-turbo": "2023-12", "gpt-4-turbo-2024-04-09": "2023-12", "gpt-4-turbo-preview": "2023-12", + "gpt-4o": "2023-10", + "gpt-4o-2024-05-13": "2023-10", "gpt-4-vision-preview": "2023-04", // After improvements, // it's now easier to add "KnowledgeCutOffDate" instead of stupid hardcoding it, as was done previously. @@ -144,8 +146,10 @@ const openaiModels = [ "gpt-4-32k-0613", "gpt-4-turbo", "gpt-4-turbo-preview", + "gpt-4o", + "gpt-4o-2024-05-13", "gpt-4-vision-preview", - "gpt-4-turbo-2024-04-09", + "gpt-4-turbo-2024-04-09" ]; const googleModels = [ diff --git a/app/utils.ts b/app/utils.ts index 07d0dcb13..efcc8c197 100644 --- a/app/utils.ts +++ b/app/utils.ts @@ -290,16 +290,13 @@ export function getMessageImages(message: RequestMessage): string[] { } export function isVisionModel(model: string) { - - // Note: This is a better way using the TypeScript feature instead of `&&` or `||` (ts v5.5.0-dev.20240314 I've been using) - const visionKeywords = [ "vision", "claude-3", "gemini-1.5-pro", + "gpt-4-turbo", + "gpt-4o", ]; - const isGpt4Turbo = model.includes("gpt-4-turbo") && !model.includes("preview"); - - return visionKeywords.some((keyword) => model.includes(keyword)) || isGpt4Turbo; -} + return visionKeywords.some((keyword) => model.includes(keyword)); +} \ No newline at end of file From 5df8b1d183ffc657b44f51d280d994da672f1103 Mon Sep 17 00:00:00 2001 From: fred-bf <157469842+fred-bf@users.noreply.github.com> Date: Tue, 14 May 2024 14:32:34 +0800 Subject: [PATCH 23/28] fix: revert gpt-4-turbo-preview detection --- app/utils.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/app/utils.ts b/app/utils.ts index efcc8c197..d67346a23 100644 --- a/app/utils.ts +++ b/app/utils.ts @@ -297,6 +297,10 @@ export function isVisionModel(model: string) { "gpt-4-turbo", "gpt-4o", ]; + const isGpt4TurboPreview = model === "gpt-4-turbo-preview"; - return visionKeywords.some((keyword) => model.includes(keyword)); -} \ No newline at end of file + return ( + visionKeywords.some((keyword) => model.includes(keyword)) && + !isGpt4TurboPreview + ); +} From 3a007e4f3d8d0ac7be8a8bf08f962101589b1e3c Mon Sep 17 00:00:00 2001 From: fred-bf <157469842+fred-bf@users.noreply.github.com> Date: Tue, 14 May 2024 17:35:58 +0800 Subject: [PATCH 24/28] feat: bump version --- src-tauri/tauri.conf.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index 7b00ac17c..ee87d8d15 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -9,7 +9,7 @@ }, "package": { "productName": "NextChat", - "version": "2.12.2" + "version": "2.12.3" }, "tauri": { "allowlist": { @@ -112,4 +112,4 @@ } ] } -} \ No newline at end of file +} From 6612550c064a68dbc8772c182228d7428b562fd7 Mon Sep 17 00:00:00 2001 From: Fred Date: Wed, 15 May 2024 15:29:38 +0800 Subject: [PATCH 25/28] feat: support gemini flash --- app/constant.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/app/constant.ts b/app/constant.ts index a3d9c206f..5047ad1d1 100644 --- a/app/constant.ts +++ b/app/constant.ts @@ -151,6 +151,7 @@ const openaiModels = [ const googleModels = [ "gemini-1.0-pro", "gemini-1.5-pro-latest", + "gemini-1.5-flash-latest", "gemini-pro-vision", ]; From 4789a7f6a93cb7c271755a201d04523de246bbec Mon Sep 17 00:00:00 2001 From: Fred Date: Wed, 15 May 2024 15:42:06 +0800 Subject: [PATCH 26/28] feat: add gemini flash into vision model list --- app/utils.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/utils.ts b/app/utils.ts index 07d0dcb13..0007e2b61 100644 --- a/app/utils.ts +++ b/app/utils.ts @@ -290,16 +290,19 @@ export function getMessageImages(message: RequestMessage): string[] { } export function isVisionModel(model: string) { - // Note: This is a better way using the TypeScript feature instead of `&&` or `||` (ts v5.5.0-dev.20240314 I've been using) const visionKeywords = [ "vision", "claude-3", "gemini-1.5-pro", + "gemini-1.5-flash", ]; - const isGpt4Turbo = model.includes("gpt-4-turbo") && !model.includes("preview"); + const isGpt4Turbo = + model.includes("gpt-4-turbo") && !model.includes("preview"); - return visionKeywords.some((keyword) => model.includes(keyword)) || isGpt4Turbo; + return ( + visionKeywords.some((keyword) => model.includes(keyword)) || isGpt4Turbo + ); } From 8688842984370479b588bc87b7e3956ae56cd759 Mon Sep 17 00:00:00 2001 From: Leo Li Date: Wed, 15 May 2024 17:53:27 -0400 Subject: [PATCH 27/28] gpt-4o as vision model https://platform.openai.com/docs/guides/vision --- app/utils.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/app/utils.ts b/app/utils.ts index 0b01b91f1..64e3c5406 100644 --- a/app/utils.ts +++ b/app/utils.ts @@ -297,6 +297,7 @@ export function isVisionModel(model: string) { "claude-3", "gemini-1.5-pro", "gemini-1.5-flash", + "gpt-4o", ]; const isGpt4Turbo = model.includes("gpt-4-turbo") && !model.includes("preview"); From 0aa807df190e1d08fc368a337e6d3651410c1993 Mon Sep 17 00:00:00 2001 From: Dean-YZG Date: Thu, 16 May 2024 14:41:18 +0800 Subject: [PATCH 28/28] feat: remove empty memoryPrompt in ChatMessages --- app/store/chat.ts | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/app/store/chat.ts b/app/store/chat.ts index a97c67e9d..27a7114a3 100644 --- a/app/store/chat.ts +++ b/app/store/chat.ts @@ -428,14 +428,13 @@ export const useChatStore = createPersistStore( getMemoryPrompt() { const session = get().currentSession(); - return { - role: "system", - content: - session.memoryPrompt.length > 0 - ? Locale.Store.Prompt.History(session.memoryPrompt) - : ";", - date: "", - } as ChatMessage; + if (session.memoryPrompt.length) { + return { + role: "system", + content: Locale.Store.Prompt.History(session.memoryPrompt), + date: "", + } as ChatMessage; + } }, getMessagesWithMemory() { @@ -471,16 +470,15 @@ export const useChatStore = createPersistStore( systemPrompts.at(0)?.content ?? "empty", ); } - + const memoryPrompt = get().getMemoryPrompt(); // long term memory const shouldSendLongTermMemory = modelConfig.sendMemory && session.memoryPrompt && session.memoryPrompt.length > 0 && session.lastSummarizeIndex > clearContextIndex; - const longTermMemoryPrompts = shouldSendLongTermMemory - ? [get().getMemoryPrompt()] - : []; + const longTermMemoryPrompts = + shouldSendLongTermMemory && memoryPrompt ? [memoryPrompt] : []; const longTermMemoryStartIndex = session.lastSummarizeIndex; // short term memory @@ -605,9 +603,11 @@ export const useChatStore = createPersistStore( Math.max(0, n - modelConfig.historyMessageCount), ); } - - // add memory prompt - toBeSummarizedMsgs.unshift(get().getMemoryPrompt()); + const memoryPrompt = get().getMemoryPrompt(); + if (memoryPrompt) { + // add memory prompt + toBeSummarizedMsgs.unshift(memoryPrompt); + } const lastSummarizeIndex = session.messages.length;