From 3f5a189591319a90cebfb835c533a3538a99c507 Mon Sep 17 00:00:00 2001 From: Jingguo Yao Date: Sat, 20 May 2023 11:06:54 +0800 Subject: [PATCH 01/11] Not to detect user lang when running in Node Use DEFAULT_LANG with Node. Remove the logging on the server side: [Lang] failed to detect user lang. --- app/locales/index.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/locales/index.ts b/app/locales/index.ts index 22c417da5..7c88c0d22 100644 --- a/app/locales/index.ts +++ b/app/locales/index.ts @@ -66,6 +66,9 @@ function setItem(key: string, value: string) { } function getLanguage() { + if (typeof process === "object") { + return DEFAULT_LANG; + } try { return navigator.language.toLowerCase(); } catch { From af497c96ec066abe93ac05433382283acc3ccf93 Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Sat, 20 May 2023 19:58:12 +0800 Subject: [PATCH 02/11] fix: #1612 infinite loading --- app/api/auth.ts | 4 -- app/client/controller.ts | 1 + app/client/platforms/openai.ts | 3 +- app/components/chat.tsx | 9 ++- app/store/chat.ts | 26 +++++--- app/utils/format.ts | 9 ++- package.json | 4 +- yarn.lock | 118 ++++++++++++++++----------------- 8 files changed, 90 insertions(+), 84 deletions(-) diff --git a/app/api/auth.ts b/app/api/auth.ts index fa9f9f4c0..fffb63c1f 100644 --- a/app/api/auth.ts +++ b/app/api/auth.ts @@ -55,10 +55,6 @@ export function auth(req: NextRequest) { req.headers.set("Authorization", `Bearer ${apiKey}`); } else { console.log("[Auth] admin did not provide an api key"); - return { - error: serverConfig.baseUrl?.includes(OPENAI_URL), - msg: "admin did not provide an api key", - }; } } else { console.log("[Auth] use user api key"); diff --git a/app/client/controller.ts b/app/client/controller.ts index 86cb99e7f..d28e72b0e 100644 --- a/app/client/controller.ts +++ b/app/client/controller.ts @@ -28,6 +28,7 @@ export const ChatControllerPool = { remove(sessionIndex: number, messageId: number) { const key = this.key(sessionIndex, messageId); + this.controllers[key]?.abort(); delete this.controllers[key]; }, diff --git a/app/client/platforms/openai.ts b/app/client/platforms/openai.ts index c9197f1e0..84c4a2df0 100644 --- a/app/client/platforms/openai.ts +++ b/app/client/platforms/openai.ts @@ -6,7 +6,7 @@ import Locale from "../../locales"; import { EventStreamContentType, fetchEventSource, -} from "@microsoft/fetch-event-source"; +} from "@fortaine/fetch-event-source"; import { prettyObject } from "@/app/utils/format"; export class ChatGPTApi implements LLMApi { @@ -145,6 +145,7 @@ export class ChatGPTApi implements LLMApi { }, onerror(e) { options.onError?.(e); + throw e; }, openWhenHidden: true, }); diff --git a/app/components/chat.tsx b/app/components/chat.tsx index fffa8b889..755901f2d 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -58,6 +58,7 @@ import { Avatar } from "./emoji"; import { MaskAvatar, MaskConfig } from "./mask"; import { useMaskStore } from "../store/mask"; import { useCommand } from "../command"; +import { prettyObject } from "../utils/format"; const Markdown = dynamic(async () => (await import("./markdown")).Markdown, { loading: () => , @@ -496,13 +497,17 @@ export function Chat() { const stopTiming = Date.now() - REQUEST_TIMEOUT_MS; session.messages.forEach((m) => { // check if should stop all stale messages - if (new Date(m.date).getTime() < stopTiming) { + if (m.isError || new Date(m.date).getTime() < stopTiming) { if (m.streaming) { m.streaming = false; } if (m.content.length === 0) { - m.content = "No content in this message."; + m.isError = true; + m.content = prettyObject({ + error: true, + message: "empty response", + }); } } }); diff --git a/app/store/chat.ts b/app/store/chat.ts index e063a12ce..888ac3a0c 100644 --- a/app/store/chat.ts +++ b/app/store/chat.ts @@ -5,7 +5,7 @@ import { trimTopic } from "../utils"; import Locale from "../locales"; import { showToast } from "../components/ui-lib"; -import { ModelType, useAppConfig } from "./config"; +import { ModelType } from "./config"; import { createEmptyMask, Mask } from "./mask"; import { StoreKey } from "../constant"; import { api, RequestMessage } from "../client/api"; @@ -277,13 +277,17 @@ export const useChatStore = create()( config: { ...modelConfig, stream: true }, onUpdate(message) { botMessage.streaming = true; - botMessage.content = message; + if (message) { + botMessage.content = message; + } set(() => ({})); }, onFinish(message) { botMessage.streaming = false; - botMessage.content = message; - get().onNewMessage(botMessage); + if (message) { + botMessage.content = message; + get().onNewMessage(botMessage); + } ChatControllerPool.remove( sessionIndex, botMessage.id ?? messageIndex, @@ -292,12 +296,12 @@ export const useChatStore = create()( }, onError(error) { const isAborted = error.message.includes("aborted"); - if ( - botMessage.content !== Locale.Error.Unauthorized && - !isAborted - ) { - botMessage.content += "\n\n" + prettyObject(error); - } + botMessage.content = + "\n\n" + + prettyObject({ + error: true, + message: error.message, + }); botMessage.streaming = false; userMessage.isError = !isAborted; botMessage.isError = !isAborted; @@ -308,7 +312,7 @@ export const useChatStore = create()( botMessage.id ?? messageIndex, ); - console.error("[Chat] error ", error); + console.error("[Chat] failed ", error); }, onController(controller) { // collect controller for stop/retry diff --git a/app/utils/format.ts b/app/utils/format.ts index 1f71f4f00..d2912d20b 100644 --- a/app/utils/format.ts +++ b/app/utils/format.ts @@ -1,8 +1,7 @@ export function prettyObject(msg: any) { - const prettyMsg = [ - "```json\n", - JSON.stringify(msg, null, " "), - "\n```", - ].join(""); + if (typeof msg !== "string") { + msg = JSON.stringify(msg, null, " "); + } + const prettyMsg = ["```json", msg, "```"].join("\n"); return prettyMsg; } diff --git a/package.json b/package.json index 792930f14..7acc6aad3 100644 --- a/package.json +++ b/package.json @@ -14,13 +14,13 @@ }, "dependencies": { "@hello-pangea/dnd": "^16.2.0", - "@microsoft/fetch-event-source": "^2.0.1", + "@fortaine/fetch-event-source": "^3.0.6", "@svgr/webpack": "^6.5.1", "@vercel/analytics": "^0.1.11", "emoji-picker-react": "^4.4.7", "fuse.js": "^6.6.2", "mermaid": "^10.1.0", - "next": "^13.4.2", + "next": "^13.4.3", "node-fetch": "^3.3.1", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/yarn.lock b/yarn.lock index e54a69e48..584db6dcd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1032,6 +1032,11 @@ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.37.0.tgz#cf1b5fa24217fe007f6487a26d765274925efa7d" integrity sha512-x5vzdtOOGgFVDCUs81QRB2+liax8rFg3+7hqM+QhBG0/G3F1ZsoYl97UrqgHgQ9KKT7G6c4V+aTUCgu/n22v1A== +"@fortaine/fetch-event-source@^3.0.6": + version "3.0.6" + resolved "https://registry.npmmirror.com/@fortaine/fetch-event-source/-/fetch-event-source-3.0.6.tgz#b8552a2ca2c5202f5699b93a92be0188d422b06e" + integrity sha512-621GAuLMvKtyZQ3IA6nlDWhV1V/7PGOTNIGLUifxt0KzM+dZIweJ6F3XvQF3QnqeNfS1N7WQ0Kil1Di/lhChEw== + "@hello-pangea/dnd@^16.2.0": version "16.2.0" resolved "https://registry.npmmirror.com/@hello-pangea/dnd/-/dnd-16.2.0.tgz#58cbadeb56f8c7a381da696bb7aa3bfbb87876ec" @@ -1111,15 +1116,10 @@ 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" - integrity sha512-Wqvo7lDeS0KGwtwg9TT9wKQ8raelmUxt+TQKWvG/xKfcmDXNOtCuaszcfCF8JzlBG1q0VhpI6CKaRMbVPMDWgw== +"@next/env@13.4.3": + version "13.4.3" + resolved "https://registry.npmmirror.com/@next/env/-/env-13.4.3.tgz#cb00bdd43a0619a79a52c9336df8a0aa84f8f4bf" + integrity sha512-pa1ErjyFensznttAk3EIv77vFbfSYT6cLzVRK5jx4uiRuCQo+m2wCFAREaHKIy63dlgvOyMlzh6R8Inu8H3KrQ== "@next/eslint-plugin-next@13.2.3": version "13.2.3" @@ -1128,50 +1128,50 @@ dependencies: glob "7.1.7" -"@next/swc-darwin-arm64@13.4.2": - version "13.4.2" - resolved "https://registry.npmmirror.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.2.tgz#d0b497df972bd02eee3bc823d6a76c2cc8b733ef" - integrity sha512-6BBlqGu3ewgJflv9iLCwO1v1hqlecaIH2AotpKfVUEzUxuuDNJQZ2a4KLb4MBl8T9/vca1YuWhSqtbF6ZuUJJw== +"@next/swc-darwin-arm64@13.4.3": + version "13.4.3" + resolved "https://registry.npmmirror.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.3.tgz#2d6c99dd5afbcce37e4ba0f64196317a1259034d" + integrity sha512-yx18udH/ZmR4Bw4M6lIIPE3JxsAZwo04iaucEfA2GMt1unXr2iodHUX/LAKNyi6xoLP2ghi0E+Xi1f4Qb8f1LQ== -"@next/swc-darwin-x64@13.4.2": - version "13.4.2" - resolved "https://registry.npmmirror.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.2.tgz#09a800bed8dfe4beec4cbf14092f9c22db24470b" - integrity sha512-iZuYr7ZvGLPjPmfhhMl0ISm+z8EiyLBC1bLyFwGBxkWmPXqdJ60mzuTaDSr5WezDwv0fz32HB7JHmRC6JVHSZg== +"@next/swc-darwin-x64@13.4.3": + version "13.4.3" + resolved "https://registry.npmmirror.com/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.3.tgz#162b15fb8a54d9f64e69c898ebeb55b7dac9bddd" + integrity sha512-Mi8xJWh2IOjryAM1mx18vwmal9eokJ2njY4nDh04scy37F0LEGJ/diL6JL6kTXi0UfUCGbMsOItf7vpReNiD2A== -"@next/swc-linux-arm64-gnu@13.4.2": - version "13.4.2" - resolved "https://registry.npmmirror.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.2.tgz#b7ade28834564120b0b25ffa0b79d75982d290bc" - integrity sha512-2xVabFtIge6BJTcJrW8YuUnYTuQjh4jEuRuS2mscyNVOj6zUZkom3CQg+egKOoS+zh2rrro66ffSKIS+ztFJTg== +"@next/swc-linux-arm64-gnu@13.4.3": + version "13.4.3" + resolved "https://registry.npmmirror.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.3.tgz#aee57422f11183d6a2e4a2e8aa23b9285873e18f" + integrity sha512-aBvtry4bxJ1xwKZ/LVPeBGBwWVwxa4bTnNkRRw6YffJnn/f4Tv4EGDPaVeYHZGQVA56wsGbtA6nZMuWs/EIk4Q== -"@next/swc-linux-arm64-musl@13.4.2": - version "13.4.2" - resolved "https://registry.npmmirror.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.2.tgz#f5420548234d35251630ddaa2e9a7dc32337a887" - integrity sha512-wKRCQ27xCUJx5d6IivfjYGq8oVngqIhlhSAJntgXLt7Uo9sRT/3EppMHqUZRfyuNBTbykEre1s5166z+pvRB5A== +"@next/swc-linux-arm64-musl@13.4.3": + version "13.4.3" + resolved "https://registry.npmmirror.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.3.tgz#c10b6aaaa47b341c6c9ea15f8b0ddb37e255d035" + integrity sha512-krT+2G3kEsEUvZoYte3/2IscscDraYPc2B+fDJFipPktJmrv088Pei/RjrhWm5TMIy5URYjZUoDZdh5k940Dyw== -"@next/swc-linux-x64-gnu@13.4.2": - version "13.4.2" - resolved "https://registry.npmmirror.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.2.tgz#0241dc011d73f08df9d9998cffdfcf08d1971520" - integrity sha512-NpCa+UVhhuNeaFVUP1Bftm0uqtvLWq2JTm7+Ta48+2Uqj2mNXrDIvyn1DY/ZEfmW/1yvGBRaUAv9zkMkMRixQA== +"@next/swc-linux-x64-gnu@13.4.3": + version "13.4.3" + resolved "https://registry.npmmirror.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.3.tgz#3f85bc5591c6a0d4908404f7e88e3c04f4462039" + integrity sha512-AMdFX6EKJjC0G/CM6hJvkY8wUjCcbdj3Qg7uAQJ7PVejRWaVt0sDTMavbRfgMchx8h8KsAudUCtdFkG9hlEClw== -"@next/swc-linux-x64-musl@13.4.2": - version "13.4.2" - resolved "https://registry.npmmirror.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.2.tgz#fd35919e2b64b1c739583145799fefd594ef5d63" - integrity sha512-ZWVC72x0lW4aj44e3khvBrj2oSYj1bD0jESmyah3zG/3DplEy/FOtYkMzbMjHTdDSheso7zH8GIlW6CDQnKhmQ== +"@next/swc-linux-x64-musl@13.4.3": + version "13.4.3" + resolved "https://registry.npmmirror.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.3.tgz#f4535adc2374a86bc8e43af149b551567df065de" + integrity sha512-jySgSXE48shaLtcQbiFO9ajE9mqz7pcAVLnVLvRIlUHyQYR/WyZdK8ehLs65Mz6j9cLrJM+YdmdJPyV4WDaz2g== -"@next/swc-win32-arm64-msvc@13.4.2": - version "13.4.2" - resolved "https://registry.npmmirror.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.2.tgz#fa95d2dbb97707c130a868a1bd7e83e64bedf4c6" - integrity sha512-pLT+OWYpzJig5K4VKhLttlIfBcVZfr2+Xbjra0Tjs83NQSkFS+y7xx+YhCwvpEmXYLIvaggj2ONPyjbiigOvHQ== +"@next/swc-win32-arm64-msvc@13.4.3": + version "13.4.3" + resolved "https://registry.npmmirror.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.3.tgz#e76106d85391c308c5ed70cda2bca2c582d65536" + integrity sha512-5DxHo8uYcaADiE9pHrg8o28VMt/1kR8voDehmfs9AqS0qSClxAAl+CchjdboUvbCjdNWL1MISCvEfKY2InJ3JA== -"@next/swc-win32-ia32-msvc@13.4.2": - version "13.4.2" - resolved "https://registry.npmmirror.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.2.tgz#31a98e61d3cda92ec2293c50df7cb5280fc63697" - integrity sha512-dhpiksQCyGca4WY0fJyzK3FxMDFoqMb0Cn+uDB+9GYjpU2K5//UGPQlCwiK4JHxuhg8oLMag5Nf3/IPSJNG8jw== +"@next/swc-win32-ia32-msvc@13.4.3": + version "13.4.3" + resolved "https://registry.npmmirror.com/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.3.tgz#8eb5d9dd71ed7a971671291605ad64ad522fb3bc" + integrity sha512-LaqkF3d+GXRA5X6zrUjQUrXm2MN/3E2arXBtn5C7avBCNYfm9G3Xc646AmmmpN3DJZVaMYliMyCIQCMDEzk80w== -"@next/swc-win32-x64-msvc@13.4.2": - version "13.4.2" - resolved "https://registry.npmmirror.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.2.tgz#8435ab6087046355f5de07122d3097949e8fab10" - integrity sha512-O7bort1Vld00cu8g0jHZq3cbSTUNMohOEvYqsqE10+yfohhdPHzvzO+ziJRz4Dyyr/fYKREwS7gR4JC0soSOMw== +"@next/swc-win32-x64-msvc@13.4.3": + version "13.4.3" + resolved "https://registry.npmmirror.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.3.tgz#c7b2b1b9e158fd7749f8209e68ee8e43a997eb4c" + integrity sha512-jglUk/x7ZWeOJWlVoKyIAkHLTI+qEkOriOOV+3hr1GyiywzcqfI7TpFSiwC7kk1scOiH7NTFKp8mA3XPNO9bDw== "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -4275,12 +4275,12 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -next@^13.4.2: - version "13.4.2" - resolved "https://registry.npmmirror.com/next/-/next-13.4.2.tgz#972f73a794f2c61729facedc79c49b22bdc89f0c" - integrity sha512-aNFqLs3a3nTGvLWlO9SUhCuMUHVPSFQC0+tDNGAsDXqx+WJDFSbvc233gOJ5H19SBc7nw36A9LwQepOJ2u/8Kg== +next@^13.4.3: + version "13.4.3" + resolved "https://registry.npmmirror.com/next/-/next-13.4.3.tgz#7f417dec9fa2731d8c1d1819a1c7d0919ad6fc75" + integrity sha512-FV3pBrAAnAIfOclTvncw9dDohyeuEEXPe5KNcva91anT/rdycWbgtu3IjUj4n5yHnWK8YEPo0vrUecHmnmUNbA== dependencies: - "@next/env" "13.4.2" + "@next/env" "13.4.3" "@swc/helpers" "0.5.1" busboy "1.6.0" caniuse-lite "^1.0.30001406" @@ -4288,15 +4288,15 @@ next@^13.4.2: styled-jsx "5.1.1" zod "3.21.4" optionalDependencies: - "@next/swc-darwin-arm64" "13.4.2" - "@next/swc-darwin-x64" "13.4.2" - "@next/swc-linux-arm64-gnu" "13.4.2" - "@next/swc-linux-arm64-musl" "13.4.2" - "@next/swc-linux-x64-gnu" "13.4.2" - "@next/swc-linux-x64-musl" "13.4.2" - "@next/swc-win32-arm64-msvc" "13.4.2" - "@next/swc-win32-ia32-msvc" "13.4.2" - "@next/swc-win32-x64-msvc" "13.4.2" + "@next/swc-darwin-arm64" "13.4.3" + "@next/swc-darwin-x64" "13.4.3" + "@next/swc-linux-arm64-gnu" "13.4.3" + "@next/swc-linux-arm64-musl" "13.4.3" + "@next/swc-linux-x64-gnu" "13.4.3" + "@next/swc-linux-x64-musl" "13.4.3" + "@next/swc-win32-arm64-msvc" "13.4.3" + "@next/swc-win32-ia32-msvc" "13.4.3" + "@next/swc-win32-x64-msvc" "13.4.3" node-domexception@^1.0.0: version "1.0.0" From 6d8c7ba1403248e1d3c01515d58824bff74bc826 Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Sat, 20 May 2023 20:08:17 +0800 Subject: [PATCH 03/11] feat: close #1626 hide context prompts in mask config --- app/components/chat.tsx | 4 +++- app/components/mask.tsx | 40 ++++++++++++++++++++++++++++------------ app/locales/cn.ts | 4 ++++ app/locales/en.ts | 6 +++++- app/store/mask.ts | 1 + 5 files changed, 41 insertions(+), 14 deletions(-) diff --git a/app/components/chat.tsx b/app/components/chat.tsx index 755901f2d..e1cb78de6 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -585,7 +585,9 @@ export function Chat() { inputRef.current?.focus(); }; - const context: RenderMessage[] = session.mask.context.slice(); + const context: RenderMessage[] = session.mask.hideContext + ? [] + : session.mask.context.slice(); const accessStore = useAccessStore(); diff --git a/app/components/mask.tsx b/app/components/mask.tsx index 09acaeefc..de724e26d 100644 --- a/app/components/mask.tsx +++ b/app/components/mask.tsx @@ -104,25 +104,41 @@ export function MaskConfig(props: { > { - if ( - e.currentTarget.checked && - confirm(Locale.Mask.Config.Sync.Confirm) - ) { - props.updateMask((mask) => { - mask.syncGlobalConfig = e.currentTarget.checked; - mask.modelConfig = { ...globalConfig.modelConfig }; - }); - } + props.updateMask((mask) => { + mask.hideContext = e.currentTarget.checked; + }); }} > + {props.shouldSyncFromGlobal ? ( + + { + if ( + e.currentTarget.checked && + confirm(Locale.Mask.Config.Sync.Confirm) + ) { + props.updateMask((mask) => { + mask.syncGlobalConfig = e.currentTarget.checked; + mask.modelConfig = { ...globalConfig.modelConfig }; + }); + } + }} + > + + ) : null} diff --git a/app/locales/cn.ts b/app/locales/cn.ts index 9f0ea0441..4250178c6 100644 --- a/app/locales/cn.ts +++ b/app/locales/cn.ts @@ -210,6 +210,10 @@ const cn = { SubTitle: "当前对话是否使用全局模型设置", Confirm: "当前对话的自定义设置将会被自动覆盖,确认启用全局设置?", }, + HideContext: { + Title: "隐藏预设对话", + SubTitle: "隐藏后预设对话不会出现在聊天界面", + }, }, }, NewChat: { diff --git a/app/locales/en.ts b/app/locales/en.ts index dc02aa66f..cd7e7c717 100644 --- a/app/locales/en.ts +++ b/app/locales/en.ts @@ -213,6 +213,10 @@ const en: RequiredLocaleType = { SubTitle: "Use global config in this chat", Confirm: "Confirm to override custom config with global config?", }, + HideContext: { + Title: "Hide Context Prompts", + SubTitle: "Do not show in-context prompts in chat", + }, }, }, NewChat: { @@ -221,7 +225,7 @@ const en: RequiredLocaleType = { Title: "Pick a Mask", SubTitle: "Chat with the Soul behind the Mask", More: "Find More", - NotShow: "Not Show Again", + NotShow: "Dont Show Again", ConfirmNoShow: "Confirm to disable?You can enable it in settings later.", }, diff --git a/app/store/mask.ts b/app/store/mask.ts index a691a7cfa..ed45241f8 100644 --- a/app/store/mask.ts +++ b/app/store/mask.ts @@ -10,6 +10,7 @@ export type Mask = { id: number; avatar: string; name: string; + hideContext?: boolean; context: ChatMessage[]; syncGlobalConfig?: boolean; modelConfig: ModelConfig; From d0e73bd6b2453f2ce13afa164aa94793e83449a1 Mon Sep 17 00:00:00 2001 From: Yifei Zhang Date: Sat, 20 May 2023 23:44:35 +0800 Subject: [PATCH 04/11] Revert "Not to detect user lang when running in Node" --- app/locales/index.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/app/locales/index.ts b/app/locales/index.ts index 7c88c0d22..22c417da5 100644 --- a/app/locales/index.ts +++ b/app/locales/index.ts @@ -66,9 +66,6 @@ function setItem(key: string, value: string) { } function getLanguage() { - if (typeof process === "object") { - return DEFAULT_LANG; - } try { return navigator.language.toLowerCase(); } catch { From f14b413b7c94a477ce3644953a3df2b4ace666bf Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Sat, 20 May 2023 23:49:10 +0800 Subject: [PATCH 05/11] feat: scrollable mask lists in new-chat page --- app/components/new-chat.module.scss | 22 +++++-- app/components/new-chat.tsx | 99 +++++++++++++---------------- app/locales/en.ts | 4 +- app/store/config.ts | 10 +-- 4 files changed, 67 insertions(+), 68 deletions(-) diff --git a/app/components/new-chat.module.scss b/app/components/new-chat.module.scss index b0e472ea5..b291a2366 100644 --- a/app/components/new-chat.module.scss +++ b/app/components/new-chat.module.scss @@ -54,13 +54,13 @@ .actions { margin-top: 5vh; - margin-bottom: 5vh; + margin-bottom: 2vh; animation: slide-in ease 0.45s; display: flex; justify-content: center; + font-size: 12px; - .more { - font-size: 12px; + .skip { margin-left: 10px; } } @@ -68,16 +68,26 @@ .masks { flex-grow: 1; width: 100%; - overflow: hidden; + overflow: auto; align-items: center; padding-top: 20px; + $linear: linear-gradient( + to bottom, + rgba(0, 0, 0, 0), + rgba(0, 0, 0, 1), + rgba(0, 0, 0, 0) + ); + + -webkit-mask-image: $linear; + mask-image: $linear; + animation: slide-in ease 0.5s; .mask-row { - margin-bottom: 10px; display: flex; - justify-content: center; + // justify-content: center; + margin-bottom: 10px; @for $i from 1 to 10 { &:nth-child(#{$i * 2}) { diff --git a/app/components/new-chat.tsx b/app/components/new-chat.tsx index 81858fb02..5fc42bb76 100644 --- a/app/components/new-chat.tsx +++ b/app/components/new-chat.tsx @@ -27,32 +27,8 @@ function getIntersectionArea(aRect: DOMRect, bRect: DOMRect) { } function MaskItem(props: { mask: Mask; onClick?: () => void }) { - const domRef = useRef(null); - - useEffect(() => { - const changeOpacity = () => { - const dom = domRef.current; - const parent = document.getElementById(SlotID.AppBody); - if (!parent || !dom) return; - - const domRect = dom.getBoundingClientRect(); - const parentRect = parent.getBoundingClientRect(); - const intersectionArea = getIntersectionArea(domRect, parentRect); - const domArea = domRect.width * domRect.height; - const ratio = intersectionArea / domArea; - const opacity = ratio > 0.9 ? 1 : 0.4; - dom.style.opacity = opacity.toString(); - }; - - setTimeout(changeOpacity, 30); - - window.addEventListener("resize", changeOpacity); - - return () => window.removeEventListener("resize", changeOpacity); - }, [domRef]); - return ( -
+
{props.mask.name}
@@ -63,32 +39,36 @@ function useMaskGroup(masks: Mask[]) { const [groups, setGroups] = useState([]); useEffect(() => { - const appBody = document.getElementById(SlotID.AppBody); - if (!appBody || masks.length === 0) return; + const computeGroup = () => { + const appBody = document.getElementById(SlotID.AppBody); + if (!appBody || masks.length === 0) return; - const rect = appBody.getBoundingClientRect(); - const maxWidth = rect.width; - const maxHeight = rect.height * 0.6; - const maskItemWidth = 120; - const maskItemHeight = 50; + const rect = appBody.getBoundingClientRect(); + const maxWidth = rect.width; + const maxHeight = rect.height * 0.6; + const maskItemWidth = 120; + const maskItemHeight = 50; - const randomMask = () => masks[Math.floor(Math.random() * masks.length)]; - let maskIndex = 0; - const nextMask = () => masks[maskIndex++ % masks.length]; + const randomMask = () => masks[Math.floor(Math.random() * masks.length)]; + let maskIndex = 0; + const nextMask = () => masks[maskIndex++ % masks.length]; - const rows = Math.ceil(maxHeight / maskItemHeight); - const cols = Math.ceil(maxWidth / maskItemWidth); + const rows = Math.ceil(maxHeight / maskItemHeight); + const cols = Math.ceil(maxWidth / maskItemWidth); - const newGroups = new Array(rows) - .fill(0) - .map((_, _i) => - new Array(cols) - .fill(0) - .map((_, j) => (j < 1 || j > cols - 2 ? randomMask() : nextMask())), - ); + const newGroups = new Array(rows) + .fill(0) + .map((_, _i) => + new Array(cols) + .fill(0) + .map((_, j) => (j < 1 || j > cols - 2 ? randomMask() : nextMask())), + ); - setGroups(newGroups); + setGroups(newGroups); + }; + window.addEventListener("resize", computeGroup); + return () => window.removeEventListener("resize", computeGroup); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); @@ -105,6 +85,8 @@ export function NewChat() { const navigate = useNavigate(); const config = useAppConfig(); + const maskRef = useRef(null); + const { state } = useLocation(); const startChat = (mask?: Mask) => { @@ -123,6 +105,13 @@ export function NewChat() { }, }); + useEffect(() => { + if (maskRef.current) { + maskRef.current.scrollLeft = + (maskRef.current.scrollWidth - maskRef.current.clientWidth) / 2; + } + }, [groups]); + return (
@@ -162,24 +151,24 @@ export function NewChat() {
startChat()} - icon={} - type="primary" - shadow - /> - - navigate(Path.Masks)} icon={} bordered shadow /> + + startChat()} + icon={} + type="primary" + shadow + className={styles["skip"]} + />
-
+
{groups.map((masks, i) => (
{masks.map((mask, index) => ( diff --git a/app/locales/en.ts b/app/locales/en.ts index cd7e7c717..1f136f003 100644 --- a/app/locales/en.ts +++ b/app/locales/en.ts @@ -221,11 +221,11 @@ const en: RequiredLocaleType = { }, NewChat: { Return: "Return", - Skip: "Skip", + Skip: "Just Start", Title: "Pick a Mask", SubTitle: "Chat with the Soul behind the Mask", More: "Find More", - NotShow: "Dont Show Again", + NotShow: "Never Show Again", ConfirmNoShow: "Confirm to disable?You can enable it in settings later.", }, diff --git a/app/store/config.ts b/app/store/config.ts index 5fc9cd546..6802a402b 100644 --- a/app/store/config.ts +++ b/app/store/config.ts @@ -73,7 +73,7 @@ export const ALL_MODELS = [ available: ENABLE_GPT4, }, { - name: "ext-davinci-002-render-sha-mobile", + name: "text-davinci-002-render-sha-mobile", available: true, }, { @@ -106,13 +106,13 @@ export const ALL_MODELS = [ }, ] as const; -export type ModelType = typeof ALL_MODELS[number]["name"]; +export type ModelType = (typeof ALL_MODELS)[number]["name"]; export function limitNumber( x: number, min: number, max: number, - defaultValue: number + defaultValue: number, ) { if (typeof x !== "number" || isNaN(x)) { return defaultValue; @@ -171,6 +171,6 @@ export const useAppConfig = create()( return state; }, - } - ) + }, + ), ); From 76e6957a8acc8528217a016b53260cc1e62b9752 Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Sat, 20 May 2023 23:53:39 +0800 Subject: [PATCH 06/11] fixup --- app/components/new-chat.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/components/new-chat.tsx b/app/components/new-chat.tsx index 5fc42bb76..30041c5c1 100644 --- a/app/components/new-chat.tsx +++ b/app/components/new-chat.tsx @@ -67,6 +67,8 @@ function useMaskGroup(masks: Mask[]) { setGroups(newGroups); }; + computeGroup(); + window.addEventListener("resize", computeGroup); return () => window.removeEventListener("resize", computeGroup); // eslint-disable-next-line react-hooks/exhaustive-deps From 600b1814a1b982e6faca151afff0518b15884c79 Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Sat, 20 May 2023 23:58:36 +0800 Subject: [PATCH 07/11] fix: wont show auth popup when receiving a 401 http code --- app/client/api.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/app/client/api.ts b/app/client/api.ts index c76fab57f..a966d7334 100644 --- a/app/client/api.ts +++ b/app/client/api.ts @@ -62,6 +62,7 @@ export function getHeaders() { const accessStore = useAccessStore.getState(); let headers: Record = { "Content-Type": "application/json", + "x-requested-with": "XMLHttpRequest", }; const makeBearer = (token: string) => `Bearer ${token.trim()}`; From c2b36cdffaa0b418bc22588c637f5fcde6fc9ef5 Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Sun, 21 May 2023 00:06:28 +0800 Subject: [PATCH 08/11] feat: prevent browser to invoke basic auth popup --- app/api/common.ts | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/app/api/common.ts b/app/api/common.ts index eb0739224..b606d8ca2 100644 --- a/app/api/common.ts +++ b/app/api/common.ts @@ -30,26 +30,30 @@ export async function requestOpenai(req: NextRequest) { controller.abort(); }, 10 * 60 * 1000); + const fetchUrl = `${baseUrl}/${openaiPath}`; + const fetchOptions: RequestInit = { + headers: { + "Content-Type": "application/json", + Authorization: authValue, + ...(process.env.OPENAI_ORG_ID && { + "OpenAI-Organization": process.env.OPENAI_ORG_ID, + }), + }, + cache: "no-store", + method: req.method, + body: req.body, + signal: controller.signal, + }; + try { - return await fetch(`${baseUrl}/${openaiPath}`, { - headers: { - "Content-Type": "application/json", - Authorization: authValue, - ...(process.env.OPENAI_ORG_ID && { - "OpenAI-Organization": process.env.OPENAI_ORG_ID, - }), - }, - cache: "no-store", - method: req.method, - body: req.body, - signal: controller.signal, - }); - } catch (err: unknown) { - if (err instanceof Error && err.name === "AbortError") { - console.log("Fetch aborted"); - } else { - throw err; + const res = await fetch(fetchUrl, fetchOptions); + + if (res.status === 401) { + // to prevent browser prompt for credentials + res.headers.delete("www-authenticate"); } + + return res; } finally { clearTimeout(timeoutId); } From a19d23848314e8539b40d9fb26544777d53d17df Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Sun, 21 May 2023 01:28:09 +0800 Subject: [PATCH 09/11] feat: close #1415 clear context button --- app/components/chat.module.scss | 65 +++++++++++ app/components/chat.tsx | 190 ++++++++++++++++++++------------ app/icons/break.svg | 1 + app/icons/chat-settings.svg | 1 + app/locales/cn.ts | 7 +- app/locales/en.ts | 5 +- app/store/chat.ts | 26 +++-- 7 files changed, 209 insertions(+), 86 deletions(-) create mode 100644 app/icons/break.svg create mode 100644 app/icons/chat-settings.svg diff --git a/app/components/chat.module.scss b/app/components/chat.module.scss index 3a1be3910..3649dfe0f 100644 --- a/app/components/chat.module.scss +++ b/app/components/chat.module.scss @@ -107,3 +107,68 @@ user-select: text; } } + +.clear-context { + margin: 20px 0 0 0; + padding: 4px 0; + + border-top: var(--border-in-light); + border-bottom: var(--border-in-light); + box-shadow: var(--card-shadow) inset; + + display: flex; + justify-content: center; + align-items: center; + + opacity: 0.5; + color: var(--black); + transition: all ease 0.3s; + cursor: pointer; + overflow: hidden; + position: relative; + font-size: 12px; + + $linear: linear-gradient( + to right, + rgba(0, 0, 0, 0), + rgba(0, 0, 0, 1), + rgba(0, 0, 0, 0) + ); + mask-image: $linear; + + @mixin show { + transform: translateY(0); + position: relative; + transition: all ease 0.3s; + opacity: 1; + } + + @mixin hide { + transform: translateY(-50%); + position: absolute; + transition: all ease 0.1s; + opacity: 0; + } + + &-tips { + @include show; + } + + &-revert-btn { + color: var(--primary); + @include hide; + } + + &:hover { + opacity: 1; + border-color: var(--primary); + + .clear-context-tips { + @include hide; + } + + .clear-context-revert-btn { + @include show; + } + } +} diff --git a/app/components/chat.tsx b/app/components/chat.tsx index e1cb78de6..f2ee89431 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -14,6 +14,8 @@ import MaskIcon from "../icons/mask.svg"; import MaxIcon from "../icons/max.svg"; import MinIcon from "../icons/min.svg"; import ResetIcon from "../icons/reload.svg"; +import BreakIcon from "../icons/break.svg"; +import SettingsIcon from "../icons/chat-settings.svg"; import LightIcon from "../icons/light.svg"; import DarkIcon from "../icons/dark.svg"; @@ -51,7 +53,7 @@ import { IconButton } from "./button"; import styles from "./home.module.scss"; import chatStyle from "./chat.module.scss"; -import { ListItem, Modal, showModal } from "./ui-lib"; +import { ListItem, Modal, showModal, showToast } from "./ui-lib"; import { useLocation, useNavigate } from "react-router-dom"; import { LAST_INPUT_KEY, Path, REQUEST_TIMEOUT_MS } from "../constant"; import { Avatar } from "./emoji"; @@ -289,6 +291,24 @@ export function PromptHints(props: { ); } +function ClearContextDivider() { + const chatStore = useChatStore(); + + return ( +
+ chatStore.updateCurrentSession( + (session) => (session.clearContextIndex = -1), + ) + } + > +
上下文已清除
+
取消清除
+
+ ); +} + function useScrollToBottom() { // for auto-scroll const scrollRef = useRef(null); @@ -321,6 +341,7 @@ export function ChatActions(props: { }) { const config = useAppConfig(); const navigate = useNavigate(); + const chatStore = useChatStore(); // switch themes const theme = config.theme; @@ -359,7 +380,7 @@ export function ChatActions(props: { className={`${chatStyle["chat-input-action"]} clickable`} onClick={props.showPromptModal} > - +
)} @@ -391,6 +412,22 @@ export function ChatActions(props: { >
+ +
{ + chatStore.updateCurrentSession((session) => { + if ((session.clearContextIndex ?? -1) > 0) { + session.clearContextIndex = -1; + } else { + session.clearContextIndex = session.messages.length; + session.memoryPrompt = ""; // will clear memory + } + }); + }} + > + +
); } @@ -602,6 +639,12 @@ export function Chat() { context.push(copiedHello); } + // clear context index = context length + index in messages + const clearContextIndex = + (session.clearContextIndex ?? -1) >= 0 + ? session.clearContextIndex! + context.length + : -1; + // preview messages const messages = context .concat(session.messages as RenderMessage[]) @@ -736,86 +779,91 @@ export function Chat() { !(message.preview || message.content.length === 0); const showTyping = message.preview || message.streaming; + const shouldShowClearContextDivider = i === clearContextIndex - 1; + return ( -
-
-
- {message.role === "user" ? ( - - ) : ( - - )} -
- {showTyping && ( -
- {Locale.Chat.Typing} + <> +
+
+
+ {message.role === "user" ? ( + + ) : ( + + )}
- )} -
- {showActions && ( -
- {message.streaming ? ( + {showTyping && ( +
+ {Locale.Chat.Typing} +
+ )} +
+ {showActions && ( +
+ {message.streaming ? ( +
onUserStop(message.id ?? i)} + > + {Locale.Chat.Actions.Stop} +
+ ) : ( + <> +
onDelete(message.id ?? i)} + > + {Locale.Chat.Actions.Delete} +
+
onResend(message.id ?? i)} + > + {Locale.Chat.Actions.Retry} +
+ + )} +
onUserStop(message.id ?? i)} + onClick={() => copyToClipboard(message.content)} > - {Locale.Chat.Actions.Stop} + {Locale.Chat.Actions.Copy}
- ) : ( - <> -
onDelete(message.id ?? i)} - > - {Locale.Chat.Actions.Delete} -
-
onResend(message.id ?? i)} - > - {Locale.Chat.Actions.Retry} -
- - )} - -
copyToClipboard(message.content)} - > - {Locale.Chat.Actions.Copy} +
+ )} + onRightClick(e, message)} + onDoubleClickCapture={() => { + if (!isMobileScreen) return; + setUserInput(message.content); + }} + fontSize={fontSize} + parentRef={scrollRef} + defaultShow={i >= messages.length - 10} + /> +
+ {!isUser && !message.preview && ( +
+
+ {message.date.toLocaleString()}
)} - onRightClick(e, message)} - onDoubleClickCapture={() => { - if (!isMobileScreen) return; - setUserInput(message.content); - }} - fontSize={fontSize} - parentRef={scrollRef} - defaultShow={i >= messages.length - 10} - />
- {!isUser && !message.preview && ( -
-
- {message.date.toLocaleString()} -
-
- )}
-
+ {shouldShowClearContextDivider && } + ); })}
diff --git a/app/icons/break.svg b/app/icons/break.svg new file mode 100644 index 000000000..64e617095 --- /dev/null +++ b/app/icons/break.svg @@ -0,0 +1 @@ + diff --git a/app/icons/chat-settings.svg b/app/icons/chat-settings.svg new file mode 100644 index 000000000..0a37b294c --- /dev/null +++ b/app/icons/chat-settings.svg @@ -0,0 +1 @@ + diff --git a/app/locales/cn.ts b/app/locales/cn.ts index 4250178c6..9a29ecf84 100644 --- a/app/locales/cn.ts +++ b/app/locales/cn.ts @@ -160,12 +160,11 @@ const cn = { BotHello: "有什么可以帮你的吗", Error: "出错了,稍后重试吧", Prompt: { - History: (content: string) => - "这是 ai 和用户的历史聊天总结作为前情提要:" + content, + History: (content: string) => "这是历史聊天总结作为前情提要:" + content, Topic: "使用四到五个字直接返回这句话的简要主题,不要解释、不要标点、不要语气词、不要多余文本,如果没有主题,请直接返回“闲聊”", Summarize: - "简要总结一下你和用户的对话,用作后续的上下文提示 prompt,控制在 200 字以内", + "简要总结一下对话内容,用作后续的上下文提示 prompt,控制在 200 字以内", }, }, Copy: { @@ -173,7 +172,7 @@ const cn = { Failed: "复制失败,请赋予剪切板权限", }, Context: { - Toast: (x: any) => `已设置 ${x} 条前置上下文`, + Toast: (x: any) => `包含 ${x} 条预设提示词`, Edit: "当前对话设置", Add: "新增预设对话", }, diff --git a/app/locales/en.ts b/app/locales/en.ts index 1f136f003..0dd3308c1 100644 --- a/app/locales/en.ts +++ b/app/locales/en.ts @@ -163,12 +163,11 @@ const en: RequiredLocaleType = { Error: "Something went wrong, please try again later.", Prompt: { History: (content: string) => - "This is a summary of the chat history between the AI and the user as a recap: " + - content, + "This is a summary of the chat history as a recap: " + content, Topic: "Please generate a four to five word title summarizing our conversation without any lead-in, punctuation, quotation marks, periods, symbols, or additional text. Remove enclosing quotation marks.", Summarize: - "Summarize our discussion briefly in 200 words or less to use as a prompt for future context.", + "Summarize the discussion briefly in 200 words or less to use as a prompt for future context.", }, }, Copy: { diff --git a/app/store/chat.ts b/app/store/chat.ts index 888ac3a0c..4abba0cf5 100644 --- a/app/store/chat.ts +++ b/app/store/chat.ts @@ -45,6 +45,7 @@ export interface ChatSession { stat: ChatStat; lastUpdate: number; lastSummarizeIndex: number; + clearContextIndex?: number; mask: Mask; } @@ -341,7 +342,12 @@ export const useChatStore = create()( getMessagesWithMemory() { const session = get().currentSession(); const modelConfig = session.mask.modelConfig; - const messages = session.messages.filter((msg) => !msg.isError); + + // wont send cleared context messages + const clearedContextMessages = session.messages.slice( + (session.clearContextIndex ?? -1) + 1, + ); + const messages = clearedContextMessages.filter((msg) => !msg.isError); const n = messages.length; const context = session.mask.context.slice(); @@ -362,17 +368,17 @@ export const useChatStore = create()( n - modelConfig.historyMessageCount, ); const longTermMemoryMessageIndex = session.lastSummarizeIndex; - const oldestIndex = Math.max( + const mostRecentIndex = Math.max( shortTermMemoryMessageIndex, longTermMemoryMessageIndex, ); - const threshold = modelConfig.compressMessageLengthThreshold; + const threshold = modelConfig.compressMessageLengthThreshold * 2; // get recent messages as many as possible const reversedRecentMessages = []; for ( let i = n - 1, count = 0; - i >= oldestIndex && count < threshold; + i >= mostRecentIndex && count < threshold; i -= 1 ) { const msg = messages[i]; @@ -410,15 +416,15 @@ export const useChatStore = create()( const session = get().currentSession(); // remove error messages if any - const cleanMessages = session.messages.filter((msg) => !msg.isError); + const messages = session.messages; // should summarize topic after chating more than 50 words const SUMMARIZE_MIN_LEN = 50; if ( session.topic === DEFAULT_TOPIC && - countMessages(cleanMessages) >= SUMMARIZE_MIN_LEN + countMessages(messages) >= SUMMARIZE_MIN_LEN ) { - const topicMessages = cleanMessages.concat( + const topicMessages = messages.concat( createMessage({ role: "user", content: Locale.Store.Prompt.Topic, @@ -440,9 +446,13 @@ export const useChatStore = create()( } const modelConfig = session.mask.modelConfig; - let toBeSummarizedMsgs = cleanMessages.slice( + const summarizeIndex = Math.max( session.lastSummarizeIndex, + session.clearContextIndex ?? 0, ); + let toBeSummarizedMsgs = messages + .filter((msg) => !msg.isError) + .slice(summarizeIndex); const historyMsgLength = countMessages(toBeSummarizedMsgs); From 35cec0f1dff0c6a940efb0d5055bdf1857fa325e Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Sun, 21 May 2023 01:44:59 +0800 Subject: [PATCH 10/11] fixup: i18n and icon minor changes --- app/components/chat.module.scss | 4 +++- app/components/chat.tsx | 10 +++++++--- app/icons/break.svg | 2 +- app/locales/cn.ts | 2 ++ app/locales/en.ts | 2 ++ 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/app/components/chat.module.scss b/app/components/chat.module.scss index 3649dfe0f..0e2741e70 100644 --- a/app/components/chat.module.scss +++ b/app/components/chat.module.scss @@ -120,7 +120,6 @@ justify-content: center; align-items: center; - opacity: 0.5; color: var(--black); transition: all ease 0.3s; cursor: pointer; @@ -128,6 +127,8 @@ position: relative; font-size: 12px; + animation: slide-in ease 0.3s; + $linear: linear-gradient( to right, rgba(0, 0, 0, 0), @@ -152,6 +153,7 @@ &-tips { @include show; + opacity: 0.5; } &-revert-btn { diff --git a/app/components/chat.tsx b/app/components/chat.tsx index f2ee89431..d736d18d5 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -303,8 +303,12 @@ function ClearContextDivider() { ) } > -
上下文已清除
-
取消清除
+
+ {Locale.Context.Clear} +
+
+ {Locale.Context.Revert} +
); } @@ -417,7 +421,7 @@ export function ChatActions(props: { className={`${chatStyle["chat-input-action"]} clickable`} onClick={() => { chatStore.updateCurrentSession((session) => { - if ((session.clearContextIndex ?? -1) > 0) { + if (session.clearContextIndex === session.messages.length) { session.clearContextIndex = -1; } else { session.clearContextIndex = session.messages.length; diff --git a/app/icons/break.svg b/app/icons/break.svg index 64e617095..fbfe04f46 100644 --- a/app/icons/break.svg +++ b/app/icons/break.svg @@ -1 +1 @@ - + diff --git a/app/locales/cn.ts b/app/locales/cn.ts index 9a29ecf84..ce0108f2f 100644 --- a/app/locales/cn.ts +++ b/app/locales/cn.ts @@ -175,6 +175,8 @@ const cn = { Toast: (x: any) => `包含 ${x} 条预设提示词`, Edit: "当前对话设置", Add: "新增预设对话", + Clear: "上下文已清除", + Revert: "恢复上下文", }, Plugin: { Name: "插件", diff --git a/app/locales/en.ts b/app/locales/en.ts index 0dd3308c1..12ad101a3 100644 --- a/app/locales/en.ts +++ b/app/locales/en.ts @@ -178,6 +178,8 @@ const en: RequiredLocaleType = { Toast: (x: any) => `With ${x} contextual prompts`, Edit: "Contextual and Memory Prompts", Add: "Add a Prompt", + Clear: "Context Cleared", + Revert: "Revert", }, Plugin: { Name: "Plugin", From 05b1b8b2407b41f3c4ee3dc75bee030b603a4489 Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Sun, 21 May 2023 02:04:30 +0800 Subject: [PATCH 11/11] feat: close #1382 only clear memory btn in chat config --- app/components/chat.tsx | 10 +++++++--- app/locales/cn.ts | 8 ++++---- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/app/components/chat.tsx b/app/components/chat.tsx index d736d18d5..80c6655d7 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -121,9 +121,13 @@ export function SessionConfigModel(props: { onClose: () => void }) { icon={} bordered text={Locale.Chat.Config.Reset} - onClick={() => - confirm(Locale.Memory.ResetConfirm) && chatStore.resetSession() - } + onClick={() => { + if (confirm(Locale.Memory.ResetConfirm)) { + chatStore.updateCurrentSession( + (session) => (session.memoryPrompt = ""), + ); + } + }} />,