From 0209ace221c1f2ba4a0bda096b25bad15573c218 Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Mon, 1 May 2023 22:53:33 +0800 Subject: [PATCH 01/15] fix: #1154 wrong date range when query usage --- app/requests.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/requests.ts b/app/requests.ts index 7e92cc45..9c069ccb 100644 --- a/app/requests.ts +++ b/app/requests.ts @@ -102,11 +102,11 @@ export async function requestUsage() { .getDate() .toString() .padStart(2, "0")}`; - const ONE_DAY = 2 * 24 * 60 * 60 * 1000; - const now = new Date(Date.now() + ONE_DAY); + const ONE_DAY = 1 * 24 * 60 * 60 * 1000; + const now = new Date(); const startOfMonth = new Date(now.getFullYear(), now.getMonth(), 1); const startDate = formatDate(startOfMonth); - const endDate = formatDate(now); + const endDate = formatDate(new Date(Date.now() + ONE_DAY)); const [used, subs] = await Promise.all([ requestOpenaiClient( From c37885e743f02f7102816f0c96f86c124f3d8b1e Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Mon, 1 May 2023 23:21:28 +0800 Subject: [PATCH 02/15] fix: #1130 #1131 delete right session --- app/components/chat-list.tsx | 13 ++++-- app/components/sidebar.tsx | 6 ++- app/components/ui-lib.tsx | 8 +++- app/store/chat.ts | 89 ++++++++++++++++-------------------- 4 files changed, 58 insertions(+), 58 deletions(-) diff --git a/app/components/chat-list.tsx b/app/components/chat-list.tsx index 2c7b95aa..02ea086b 100644 --- a/app/components/chat-list.tsx +++ b/app/components/chat-list.tsx @@ -67,7 +67,10 @@ export function ChatItem(props: { )} -
+
@@ -77,14 +80,14 @@ export function ChatItem(props: { } export function ChatList(props: { narrow?: boolean }) { - const [sessions, selectedIndex, selectSession, removeSession, moveSession] = - useChatStore((state) => [ + const [sessions, selectedIndex, selectSession, moveSession] = useChatStore( + (state) => [ state.sessions, state.currentSessionIndex, state.selectSession, - state.removeSession, state.moveSession, - ]); + ], + ); const chatStore = useChatStore(); const navigate = useNavigate(); diff --git a/app/components/sidebar.tsx b/app/components/sidebar.tsx index 47a31172..77621964 100644 --- a/app/components/sidebar.tsx +++ b/app/components/sidebar.tsx @@ -138,7 +138,11 @@ export function SideBar(props: { className?: string }) {
} - onClick={chatStore.deleteSession} + onClick={() => { + if (confirm(Locale.Home.DeleteChat)) { + chatStore.deleteSession(chatStore.currentSessionIndex); + } + }} />
diff --git a/app/components/ui-lib.tsx b/app/components/ui-lib.tsx index 5b6ed959..c16f94a4 100644 --- a/app/components/ui-lib.tsx +++ b/app/components/ui-lib.tsx @@ -158,6 +158,7 @@ export type ToastProps = { text: string; onClick: () => void; }; + onClose?: () => void; }; export function Toast(props: ToastProps) { @@ -167,7 +168,10 @@ export function Toast(props: ToastProps) { {props.content} {props.action && (
From 9f3188fe45d9d5c14abcb4d0a98b3b7a0718f1fe Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Mon, 1 May 2023 23:37:02 +0800 Subject: [PATCH 04/15] fix: #1124 mask model config does not works --- app/requests.ts | 20 ++++++-------------- app/store/chat.ts | 38 ++++++++++++++++++++------------------ app/store/config.ts | 1 - 3 files changed, 26 insertions(+), 33 deletions(-) diff --git a/app/requests.ts b/app/requests.ts index 9c069ccb..582ab486 100644 --- a/app/requests.ts +++ b/app/requests.ts @@ -14,9 +14,8 @@ const TIME_OUT_MS = 60000; const makeRequestParam = ( messages: Message[], options?: { - filterBot?: boolean; stream?: boolean; - model?: ModelType; + overrideModel?: ModelType; }, ): ChatRequest => { let sendMessages = messages.map((v) => ({ @@ -24,18 +23,14 @@ const makeRequestParam = ( content: v.content, })); - if (options?.filterBot) { - sendMessages = sendMessages.filter((m) => m.role !== "assistant"); - } - const modelConfig = { ...useAppConfig.getState().modelConfig, ...useChatStore.getState().currentSession().mask.modelConfig, }; // override model config - if (options?.model) { - modelConfig.model = options.model; + if (options?.overrideModel) { + modelConfig.model = options.overrideModel; } return { @@ -82,8 +77,7 @@ export async function requestChat( }, ) { const req: ChatRequest = makeRequestParam(messages, { - filterBot: true, - model: options?.model, + overrideModel: options?.model, }); const res = await requestOpenaiClient("v1/chat/completions")(req); @@ -149,9 +143,8 @@ export async function requestUsage() { export async function requestChatStream( messages: Message[], options?: { - filterBot?: boolean; modelConfig?: ModelConfig; - model?: ModelType; + overrideModel?: ModelType; onMessage: (message: string, done: boolean) => void; onError: (error: Error, statusCode?: number) => void; onController?: (controller: AbortController) => void; @@ -159,8 +152,7 @@ export async function requestChatStream( ) { const req = makeRequestParam(messages, { stream: true, - filterBot: options?.filterBot, - model: options?.model, + overrideModel: options?.overrideModel, }); console.log("[Request] ", req); diff --git a/app/store/chat.ts b/app/store/chat.ts index d1aeabf7..5abd8129 100644 --- a/app/store/chat.ts +++ b/app/store/chat.ts @@ -236,6 +236,9 @@ export const useChatStore = create()( }, async onUserInput(content) { + const session = get().currentSession(); + const modelConfig = session.mask.modelConfig; + const userMessage: Message = createMessage({ role: "user", content, @@ -245,7 +248,7 @@ export const useChatStore = create()( role: "assistant", streaming: true, id: userMessage.id! + 1, - model: useAppConfig.getState().modelConfig.model, + model: modelConfig.model, }); // get recent messages @@ -279,14 +282,16 @@ export const useChatStore = create()( } }, onError(error, statusCode) { + const isAborted = error.message.includes("aborted"); if (statusCode === 401) { botMessage.content = Locale.Error.Unauthorized; - } else if (!error.message.includes("aborted")) { + } else if (!isAborted) { botMessage.content += "\n\n" + Locale.Store.Error; } botMessage.streaming = false; - userMessage.isError = true; - botMessage.isError = true; + userMessage.isError = !isAborted; + botMessage.isError = !isAborted; + set(() => ({})); ControllerPool.remove(sessionIndex, botMessage.id ?? messageIndex); }, @@ -298,8 +303,7 @@ export const useChatStore = create()( controller, ); }, - filterBot: !useAppConfig.getState().sendBotMessages, - modelConfig: useAppConfig.getState().modelConfig, + modelConfig: { ...modelConfig }, }); }, @@ -318,7 +322,7 @@ export const useChatStore = create()( getMessagesWithMemory() { const session = get().currentSession(); - const config = useAppConfig.getState(); + const modelConfig = session.mask.modelConfig; const messages = session.messages.filter((msg) => !msg.isError); const n = messages.length; @@ -326,7 +330,7 @@ export const useChatStore = create()( // long term memory if ( - session.mask.modelConfig.sendMemory && + modelConfig.sendMemory && session.memoryPrompt && session.memoryPrompt.length > 0 ) { @@ -337,14 +341,14 @@ export const useChatStore = create()( // get short term and unmemoried long term memory const shortTermMemoryMessageIndex = Math.max( 0, - n - config.modelConfig.historyMessageCount, + n - modelConfig.historyMessageCount, ); const longTermMemoryMessageIndex = session.lastSummarizeIndex; const oldestIndex = Math.max( shortTermMemoryMessageIndex, longTermMemoryMessageIndex, ); - const threshold = config.modelConfig.compressMessageLengthThreshold; + const threshold = modelConfig.compressMessageLengthThreshold; // get recent messages as many as possible const reversedRecentMessages = []; @@ -403,17 +407,17 @@ export const useChatStore = create()( }); } - const config = useAppConfig.getState(); + const modelConfig = session.mask.modelConfig; let toBeSummarizedMsgs = session.messages.slice( session.lastSummarizeIndex, ); const historyMsgLength = countMessages(toBeSummarizedMsgs); - if (historyMsgLength > config?.modelConfig?.max_tokens ?? 4000) { + if (historyMsgLength > modelConfig?.max_tokens ?? 4000) { const n = toBeSummarizedMsgs.length; toBeSummarizedMsgs = toBeSummarizedMsgs.slice( - Math.max(0, n - config.modelConfig.historyMessageCount), + Math.max(0, n - modelConfig.historyMessageCount), ); } @@ -426,12 +430,11 @@ export const useChatStore = create()( "[Chat History] ", toBeSummarizedMsgs, historyMsgLength, - config.modelConfig.compressMessageLengthThreshold, + modelConfig.compressMessageLengthThreshold, ); if ( - historyMsgLength > - config.modelConfig.compressMessageLengthThreshold && + historyMsgLength > modelConfig.compressMessageLengthThreshold && session.mask.modelConfig.sendMemory ) { requestChatStream( @@ -441,8 +444,7 @@ export const useChatStore = create()( date: "", }), { - filterBot: false, - model: "gpt-3.5-turbo", + overrideModel: "gpt-3.5-turbo", onMessage(message, done) { session.memoryPrompt = message; if (done) { diff --git a/app/store/config.ts b/app/store/config.ts index 4bd68b73..da77c7b3 100644 --- a/app/store/config.ts +++ b/app/store/config.ts @@ -17,7 +17,6 @@ export enum Theme { } export const DEFAULT_CONFIG = { - sendBotMessages: true as boolean, submitKey: SubmitKey.CtrlEnter as SubmitKey, avatar: "1f603", fontSize: 14, From 1aaf4ae5bc30309de7e1d8aea1df0fe413e11c45 Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Mon, 1 May 2023 23:39:54 +0800 Subject: [PATCH 05/15] fix: #1126 can not select prompt --- app/components/chat.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/components/chat.tsx b/app/components/chat.tsx index 8fc39e31..4c168669 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -391,7 +391,7 @@ export function Chat() { const onPromptSelect = (prompt: Prompt) => { setPromptHints([]); inputRef.current?.focus(); - setUserInput(prompt.content); + setTimeout(() => setUserInput(prompt.content), 60); }; // auto grow input From 8f5c28981877c3428b29fb08c36a3c15117c873d Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Mon, 1 May 2023 23:48:23 +0800 Subject: [PATCH 06/15] fix: #751 do not cache request --- app/api/common.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/api/common.ts b/app/api/common.ts index 22e71884..a86d6861 100644 --- a/app/api/common.ts +++ b/app/api/common.ts @@ -26,8 +26,11 @@ export async function requestOpenai(req: NextRequest) { headers: { "Content-Type": "application/json", Authorization: `Bearer ${apiKey}`, - ...(process.env.OPENAI_ORG_ID && { "OpenAI-Organization": process.env.OPENAI_ORG_ID }), + ...(process.env.OPENAI_ORG_ID && { + "OpenAI-Organization": process.env.OPENAI_ORG_ID, + }), }, + cache: "no-store", method: req.method, body: req.body, }); From a69cec89fb3b4264abaaa9537c5351bbe7860882 Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Tue, 2 May 2023 00:31:44 +0800 Subject: [PATCH 07/15] perf: close #909 reduce message items render time --- app/components/chat.tsx | 11 ++-- app/components/markdown.tsx | 107 +++++++++++++++++++----------------- 2 files changed, 61 insertions(+), 57 deletions(-) diff --git a/app/components/chat.tsx b/app/components/chat.tsx index 4c168669..bd2c913d 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -1,5 +1,5 @@ import { useDebouncedCallback } from "use-debounce"; -import { memo, useState, useRef, useEffect, useLayoutEffect } from "react"; +import { useState, useRef, useEffect, useLayoutEffect } from "react"; import SendWhiteIcon from "../icons/send-white.svg"; import BrainIcon from "../icons/brain.svg"; @@ -64,12 +64,9 @@ import { useMaskStore, } from "../store/mask"; -const Markdown = dynamic( - async () => memo((await import("./markdown")).Markdown), - { - loading: () => , - }, -); +const Markdown = dynamic(async () => (await import("./markdown")).Markdown, { + loading: () => , +}); function exportMessages(messages: Message[], topic: string) { const mdText = diff --git a/app/components/markdown.tsx b/app/components/markdown.tsx index 25d0584f..2909293c 100644 --- a/app/components/markdown.tsx +++ b/app/components/markdown.tsx @@ -9,6 +9,7 @@ import { useRef, useState, RefObject, useEffect } from "react"; import { copyToClipboard } from "../utils"; import LoadingIcon from "../icons/three-dots.svg"; +import React from "react"; export function PreCode(props: { children: any }) { const ref = useRef(null); @@ -29,6 +30,32 @@ export function PreCode(props: { children: any }) { ); } +function _MarkDownContent(props: { content: string }) { + return ( + + {props.content} + + ); +} + +export const MarkdownContent = React.memo(_MarkDownContent); + export function Markdown( props: { content: string; @@ -38,69 +65,49 @@ export function Markdown( } & React.DOMAttributes, ) { const mdRef = useRef(null); + const renderedHeight = useRef(0); + const inView = useRef(false); const parent = props.parentRef.current; const md = mdRef.current; - const rendered = useRef(true); // disable lazy loading for bad ux - const [counter, setCounter] = useState(0); - useEffect(() => { - // to triggr rerender - setCounter(counter + 1); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [props.loading]); + if (parent && md) { + const parentBounds = parent.getBoundingClientRect(); + const twoScreenHeight = Math.max(500, parentBounds.height * 2); + const mdBounds = md.getBoundingClientRect(); + const isInRange = (x: number) => + x <= parentBounds.bottom + twoScreenHeight && + x >= parentBounds.top - twoScreenHeight; + inView.current = isInRange(mdBounds.top) || isInRange(mdBounds.bottom); + } - const inView = - rendered.current || - (() => { - if (parent && md) { - const parentBounds = parent.getBoundingClientRect(); - const mdBounds = md.getBoundingClientRect(); - const isInRange = (x: number) => - x <= parentBounds.bottom && x >= parentBounds.top; - const inView = isInRange(mdBounds.top) || isInRange(mdBounds.bottom); - - if (inView) { - rendered.current = true; - } - - return inView; - } - })(); - - const shouldLoading = props.loading || !inView; + if (inView.current && md) { + renderedHeight.current = Math.max( + renderedHeight.current, + md.getBoundingClientRect().height, + ); + } return (
0 + ? renderedHeight.current + : "auto", + }} ref={mdRef} onContextMenu={props.onContextMenu} onDoubleClickCapture={props.onDoubleClickCapture} > - {shouldLoading ? ( - - ) : ( - - {props.content} - - )} + {inView.current && + (props.loading ? ( + + ) : ( + + ))}
); } From e509749421dc7d81180bc3f4255dae27712defc6 Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Tue, 2 May 2023 02:26:43 +0800 Subject: [PATCH 08/15] perf: improve prompt list performance --- app/components/settings.module.scss | 71 ++++++++------ app/components/settings.tsx | 144 +++++++++++++++++++--------- app/locales/cn.ts | 13 ++- app/locales/de.ts | 11 +++ app/locales/en.ts | 11 +++ app/locales/es.ts | 11 +++ app/locales/it.ts | 11 +++ app/locales/jp.ts | 11 +++ app/locales/tr.ts | 11 +++ app/locales/tw.ts | 10 ++ app/store/prompt.ts | 15 ++- scripts/init-proxy.sh | 1 + 12 files changed, 240 insertions(+), 80 deletions(-) diff --git a/app/components/settings.module.scss b/app/components/settings.module.scss index 30abc36d..f257a3ca 100644 --- a/app/components/settings.module.scss +++ b/app/components/settings.module.scss @@ -7,6 +7,20 @@ cursor: pointer; } +.edit-prompt-modal { + display: flex; + flex-direction: column; + + .edit-prompt-title { + max-width: unset; + margin-bottom: 20px; + text-align: left; + } + .edit-prompt-content { + max-width: unset; + } +} + .user-prompt-modal { min-height: 40vh; @@ -18,47 +32,42 @@ } .user-prompt-list { - padding: 10px 0; + border: var(--border-in-light); + border-radius: 10px; .user-prompt-item { - margin-bottom: 10px; - widows: 100%; + display: flex; + justify-content: space-between; + padding: 10px; + + &:not(:last-child) { + border-bottom: var(--border-in-light); + } .user-prompt-header { - display: flex; - widows: 100%; - margin-bottom: 5px; + max-width: calc(100% - 100px); .user-prompt-title { - flex-grow: 1; - max-width: 100%; - margin-right: 5px; - padding: 5px; - font-size: 12px; - text-align: left; + font-size: 14px; + line-height: 2; + font-weight: bold; } - - .user-prompt-buttons { - display: flex; - align-items: center; - - .user-prompt-button { - height: 100%; - - &:not(:last-child) { - margin-right: 5px; - } - } + .user-prompt-content { + font-size: 12px; } } - .user-prompt-content { - width: 100%; - box-sizing: border-box; - padding: 5px; - margin-right: 10px; - font-size: 12px; - flex-grow: 1; + .user-prompt-buttons { + display: flex; + align-items: center; + + .user-prompt-button { + height: 100%; + + &:not(:last-child) { + margin-right: 5px; + } + } } } } diff --git a/app/components/settings.tsx b/app/components/settings.tsx index 385fc323..5d0a663f 100644 --- a/app/components/settings.tsx +++ b/app/components/settings.tsx @@ -3,10 +3,12 @@ import { useState, useEffect, useMemo, HTMLProps, useRef } from "react"; import styles from "./settings.module.scss"; import ResetIcon from "../icons/reload.svg"; +import AddIcon from "../icons/add.svg"; import CloseIcon from "../icons/close.svg"; import CopyIcon from "../icons/copy.svg"; import ClearIcon from "../icons/clear.svg"; import EditIcon from "../icons/edit.svg"; +import EyeIcon from "../icons/eye.svg"; import { Input, List, ListItem, Modal, PasswordInput, Popover } from "./ui-lib"; import { ModelConfigList } from "./model-config"; @@ -30,6 +32,55 @@ import { InputRange } from "./input-range"; import { useNavigate } from "react-router-dom"; import { Avatar, AvatarPicker } from "./emoji"; +function EditPromptModal(props: { id: number; onClose: () => void }) { + const promptStore = usePromptStore(); + const prompt = promptStore.get(props.id); + + return prompt ? ( +
+ , + ]} + > +
+ + promptStore.update( + props.id, + (prompt) => (prompt.title = e.currentTarget.value), + ) + } + > + + promptStore.update( + props.id, + (prompt) => (prompt.content = e.currentTarget.value), + ) + } + > +
+
+
+ ) : null; +} + function UserPromptModal(props: { onClose?: () => void }) { const promptStore = usePromptStore(); const userPrompts = promptStore.getUserPrompts(); @@ -39,6 +90,8 @@ function UserPromptModal(props: { onClose?: () => void }) { const [searchPrompts, setSearchPrompts] = useState([]); const prompts = searchInput.length > 0 ? searchPrompts : allPrompts; + const [editingPromptId, setEditingPromptId] = useState(); + useEffect(() => { if (searchInput.length > 0) { const searchResult = SearchService.search(searchInput); @@ -56,8 +109,13 @@ function UserPromptModal(props: { onClose?: () => void }) { actions={[ promptStore.add({ title: "", content: "" })} - icon={} + onClick={() => + promptStore.add({ + title: "Empty Prompt", + content: "Empty Prompt Content", + }) + } + icon={} bordered text={Locale.Settings.Prompt.Modal.Add} />, @@ -76,57 +134,51 @@ function UserPromptModal(props: { onClose?: () => void }) { {prompts.map((v, _) => (
- { - if (v.isUser) { - promptStore.updateUserPrompts( - v.id!, - (prompt) => (prompt.title = e.currentTarget.value), - ); - } - }} - > - -
- {v.isUser && ( - } - bordered - className={styles["user-prompt-button"]} - onClick={() => promptStore.remove(v.id!)} - /> - )} - } - bordered - className={styles["user-prompt-button"]} - onClick={() => copyToClipboard(v.content)} - /> +
{v.title}
+
+ {v.content}
- { - if (v.isUser) { - promptStore.updateUserPrompts( - v.id!, - (prompt) => (prompt.content = e.currentTarget.value), - ); - } - }} - /> + +
+ {v.isUser && ( + } + className={styles["user-prompt-button"]} + onClick={() => promptStore.remove(v.id!)} + /> + )} + {v.isUser ? ( + } + className={styles["user-prompt-button"]} + onClick={() => setEditingPromptId(v.id)} + /> + ) : ( + } + className={styles["user-prompt-button"]} + onClick={() => setEditingPromptId(v.id)} + /> + )} + } + className={styles["user-prompt-button"]} + onClick={() => copyToClipboard(v.content)} + /> +
))}
+ + {editingPromptId !== undefined && ( + setEditingPromptId(undefined)} + /> + )} ); } diff --git a/app/locales/cn.ts b/app/locales/cn.ts index 208752c1..45dc10a9 100644 --- a/app/locales/cn.ts +++ b/app/locales/cn.ts @@ -116,9 +116,12 @@ const cn = { Edit: "编辑", Modal: { Title: "提示词列表", - Add: "增加一条", + Add: "新建", Search: "搜索提示词", }, + EditModal: { + Title: "编辑提示词", + }, }, HistoryCount: { Title: "附带历史消息数", @@ -223,6 +226,14 @@ const cn = { SubTitle: "现在开始,与面具背后的灵魂思维碰撞", More: "搜索更多", }, + + UI: { + Confirm: "确认", + Cancel: "取消", + Close: "关闭", + Create: "新建", + Edit: "编辑", + }, }; export type LocaleType = typeof cn; diff --git a/app/locales/de.ts b/app/locales/de.ts index 1981944f..048e575c 100644 --- a/app/locales/de.ts +++ b/app/locales/de.ts @@ -121,6 +121,9 @@ const de: LocaleType = { Add: "Add One", Search: "Search Prompts", }, + EditModal: { + Title: "Edit Prompt", + }, }, HistoryCount: { Title: "Anzahl der angehängten Nachrichten", @@ -230,6 +233,14 @@ const de: LocaleType = { NotShow: "Not Show Again", ConfirmNoShow: "Confirm to disable?You can enable it in settings later.", }, + + UI: { + Confirm: "Confirm", + Cancel: "Cancel", + Close: "Close", + Create: "Create", + Edit: "Edit", + }, }; export default de; diff --git a/app/locales/en.ts b/app/locales/en.ts index d7357731..e424d9b4 100644 --- a/app/locales/en.ts +++ b/app/locales/en.ts @@ -120,6 +120,9 @@ const en: LocaleType = { Add: "Add One", Search: "Search Prompts", }, + EditModal: { + Title: "Edit Prompt", + }, }, HistoryCount: { Title: "Attached Messages Count", @@ -226,6 +229,14 @@ const en: LocaleType = { NotShow: "Not Show Again", ConfirmNoShow: "Confirm to disable?You can enable it in settings later.", }, + + UI: { + Confirm: "Confirm", + Cancel: "Cancel", + Close: "Close", + Create: "Create", + Edit: "Edit", + }, }; export default en; diff --git a/app/locales/es.ts b/app/locales/es.ts index 783cd6e9..46d18a54 100644 --- a/app/locales/es.ts +++ b/app/locales/es.ts @@ -120,6 +120,9 @@ const es: LocaleType = { Add: "Add One", Search: "Search Prompts", }, + EditModal: { + Title: "Edit Prompt", + }, }, HistoryCount: { Title: "Cantidad de mensajes adjuntos", @@ -227,6 +230,14 @@ const es: LocaleType = { NotShow: "Not Show Again", ConfirmNoShow: "Confirm to disable?You can enable it in settings later.", }, + + UI: { + Confirm: "Confirm", + Cancel: "Cancel", + Close: "Close", + Create: "Create", + Edit: "Edit", + }, }; export default es; diff --git a/app/locales/it.ts b/app/locales/it.ts index 3fcc80ec..ee9a2c2b 100644 --- a/app/locales/it.ts +++ b/app/locales/it.ts @@ -120,6 +120,9 @@ const it: LocaleType = { Add: "Add One", Search: "Search Prompts", }, + EditModal: { + Title: "Edit Prompt", + }, }, HistoryCount: { Title: "Conteggio dei messaggi allegati", @@ -228,6 +231,14 @@ const it: LocaleType = { NotShow: "Not Show Again", ConfirmNoShow: "Confirm to disable?You can enable it in settings later.", }, + + UI: { + Confirm: "Confirm", + Cancel: "Cancel", + Close: "Close", + Create: "Create", + Edit: "Edit", + }, }; export default it; diff --git a/app/locales/jp.ts b/app/locales/jp.ts index 4bbe0512..fb693cf5 100644 --- a/app/locales/jp.ts +++ b/app/locales/jp.ts @@ -122,6 +122,9 @@ const jp: LocaleType = { Add: "新規追加", Search: "プロンプトワード検索", }, + EditModal: { + Title: "编辑提示词", + }, }, HistoryCount: { Title: "履歴メッセージ数を添付", @@ -226,6 +229,14 @@ const jp: LocaleType = { NotShow: "不再展示", ConfirmNoShow: "确认禁用?禁用后可以随时在设置中重新启用。", }, + + UI: { + Confirm: "确认", + Cancel: "取消", + Close: "关闭", + Create: "新建", + Edit: "编辑", + }, }; export default jp; diff --git a/app/locales/tr.ts b/app/locales/tr.ts index a658fcc4..5eb4fe3e 100644 --- a/app/locales/tr.ts +++ b/app/locales/tr.ts @@ -120,6 +120,9 @@ const tr: LocaleType = { Add: "Add One", Search: "Search Prompts", }, + EditModal: { + Title: "Edit Prompt", + }, }, HistoryCount: { Title: "Ekli Mesaj Sayısı", @@ -228,6 +231,14 @@ const tr: LocaleType = { NotShow: "Not Show Again", ConfirmNoShow: "Confirm to disable?You can enable it in settings later.", }, + + UI: { + Confirm: "Confirm", + Cancel: "Cancel", + Close: "Close", + Create: "Create", + Edit: "Edit", + }, }; export default tr; diff --git a/app/locales/tw.ts b/app/locales/tw.ts index 9a0e9eac..de964fc3 100644 --- a/app/locales/tw.ts +++ b/app/locales/tw.ts @@ -118,6 +118,9 @@ const tw: LocaleType = { Add: "新增一條", Search: "搜尋提示詞", }, + EditModal: { + Title: "编辑提示词", + }, }, HistoryCount: { Title: "附帶歷史訊息數", @@ -219,6 +222,13 @@ const tw: LocaleType = { NotShow: "不再展示", ConfirmNoShow: "确认禁用?禁用后可以随时在设置中重新启用。", }, + UI: { + Confirm: "确认", + Cancel: "取消", + Close: "关闭", + Create: "新建", + Edit: "编辑", + }, }; export default tw; diff --git a/app/store/prompt.ts b/app/store/prompt.ts index e3a2eedd..98d4193b 100644 --- a/app/store/prompt.ts +++ b/app/store/prompt.ts @@ -17,11 +17,12 @@ export interface PromptStore { prompts: Record; add: (prompt: Prompt) => number; + get: (id: number) => Prompt | undefined; remove: (id: number) => void; search: (text: string) => Prompt[]; + update: (id: number, updater: (prompt: Prompt) => void) => void; getUserPrompts: () => Prompt[]; - updateUserPrompts: (id: number, updater: (prompt: Prompt) => void) => void; } export const SearchService = { @@ -81,6 +82,16 @@ export const usePromptStore = create()( return prompt.id!; }, + get(id) { + const targetPrompt = get().prompts[id]; + + if (!targetPrompt) { + return SearchService.builtinPrompts.find((v) => v.id === id); + } + + return targetPrompt; + }, + remove(id) { const prompts = get().prompts; delete prompts[id]; @@ -98,7 +109,7 @@ export const usePromptStore = create()( return userPrompts; }, - updateUserPrompts(id: number, updater) { + update(id: number, updater) { const prompt = get().prompts[id] ?? { title: "", content: "", diff --git a/scripts/init-proxy.sh b/scripts/init-proxy.sh index acba064f..32e55921 100644 --- a/scripts/init-proxy.sh +++ b/scripts/init-proxy.sh @@ -1,5 +1,6 @@ dir="$(dirname "$0")" config=$dir/proxychains.conf host_ip=$(grep nameserver /etc/resolv.conf | sed 's/nameserver //') +echo "proxying to $host_ip" cp $dir/proxychains.template.conf $config sed -i "\$s/.*/http $host_ip 7890/" $config From 220c622f8f472311f4d3787e1293998c475ad0e3 Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Tue, 2 May 2023 02:37:15 +0800 Subject: [PATCH 09/15] fixup --- app/components/markdown.tsx | 43 ++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/app/components/markdown.tsx b/app/components/markdown.tsx index 2909293c..11fc249d 100644 --- a/app/components/markdown.tsx +++ b/app/components/markdown.tsx @@ -71,22 +71,35 @@ export function Markdown( const parent = props.parentRef.current; const md = mdRef.current; - if (parent && md) { - const parentBounds = parent.getBoundingClientRect(); - const twoScreenHeight = Math.max(500, parentBounds.height * 2); - const mdBounds = md.getBoundingClientRect(); - const isInRange = (x: number) => - x <= parentBounds.bottom + twoScreenHeight && - x >= parentBounds.top - twoScreenHeight; - inView.current = isInRange(mdBounds.top) || isInRange(mdBounds.bottom); - } + const checkInView = () => { + if (parent && md) { + const parentBounds = parent.getBoundingClientRect(); + const twoScreenHeight = Math.max(500, parentBounds.height * 2); + const mdBounds = md.getBoundingClientRect(); + const isInRange = (x: number) => + x <= parentBounds.bottom + twoScreenHeight && + x >= parentBounds.top - twoScreenHeight; + inView.current = isInRange(mdBounds.top) || isInRange(mdBounds.bottom); + } - if (inView.current && md) { - renderedHeight.current = Math.max( - renderedHeight.current, - md.getBoundingClientRect().height, - ); - } + if (inView.current && md) { + renderedHeight.current = Math.max( + renderedHeight.current, + md.getBoundingClientRect().height, + ); + } + }; + + useEffect(() => { + setTimeout(() => { + if (!inView.current) { + checkInView(); + } + }, 10); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + checkInView(); return (
Date: Tue, 2 May 2023 02:38:30 +0800 Subject: [PATCH 10/15] fixup --- app/components/markdown.tsx | 9 --------- 1 file changed, 9 deletions(-) diff --git a/app/components/markdown.tsx b/app/components/markdown.tsx index 11fc249d..69bc3517 100644 --- a/app/components/markdown.tsx +++ b/app/components/markdown.tsx @@ -90,15 +90,6 @@ export function Markdown( } }; - useEffect(() => { - setTimeout(() => { - if (!inView.current) { - checkInView(); - } - }, 10); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - checkInView(); return ( From ae8050a3f72e370cdec0c64b645ef57e4df650cf Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Tue, 2 May 2023 02:45:15 +0800 Subject: [PATCH 11/15] fixup --- app/components/markdown.tsx | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/app/components/markdown.tsx b/app/components/markdown.tsx index 69bc3517..eefb31f3 100644 --- a/app/components/markdown.tsx +++ b/app/components/markdown.tsx @@ -90,6 +90,15 @@ export function Markdown( } }; + useEffect(() => { + setTimeout(() => { + if (!inView.current) { + checkInView(); + } + }, 30); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + checkInView(); return ( From 116e16e30dfda4ffd9aea5e006d78db525a323d3 Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Tue, 2 May 2023 02:52:25 +0800 Subject: [PATCH 12/15] fixup --- app/components/chat.tsx | 1 + app/components/markdown.tsx | 12 ++---------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/app/components/chat.tsx b/app/components/chat.tsx index bd2c913d..4aaa8437 100644 --- a/app/components/chat.tsx +++ b/app/components/chat.tsx @@ -725,6 +725,7 @@ export function Chat() { }} fontSize={fontSize} parentRef={scrollRef} + defaultShow={i >= messages.length - 10} />
{!isUser && !message.preview && ( diff --git a/app/components/markdown.tsx b/app/components/markdown.tsx index eefb31f3..b5805e50 100644 --- a/app/components/markdown.tsx +++ b/app/components/markdown.tsx @@ -62,11 +62,12 @@ export function Markdown( loading?: boolean; fontSize?: number; parentRef: RefObject; + defaultShow?: boolean; } & React.DOMAttributes, ) { const mdRef = useRef(null); const renderedHeight = useRef(0); - const inView = useRef(false); + const inView = useRef(!!props.defaultShow); const parent = props.parentRef.current; const md = mdRef.current; @@ -90,15 +91,6 @@ export function Markdown( } }; - useEffect(() => { - setTimeout(() => { - if (!inView.current) { - checkInView(); - } - }, 30); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - checkInView(); return ( From 132f6c842073d354f7c88fc06fa18d705a978717 Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Tue, 2 May 2023 03:01:42 +0800 Subject: [PATCH 13/15] feat: improve mask ui --- app/components/mask.module.scss | 9 +++------ app/components/mask.tsx | 21 ++++++++++----------- 2 files changed, 13 insertions(+), 17 deletions(-) diff --git a/app/components/mask.module.scss b/app/components/mask.module.scss index 0618cc06..c1778d45 100644 --- a/app/components/mask.module.scss +++ b/app/components/mask.module.scss @@ -23,8 +23,9 @@ .mask-filter { width: 100%; max-width: 100%; - margin-bottom: 10px; + margin-bottom: 20px; animation: search-in ease 0.3s; + height: 40px; display: flex; @@ -32,7 +33,6 @@ flex-grow: 1; max-width: 100%; min-width: 0; - margin-bottom: 20px; animation: search-in ease 0.3s; } @@ -45,10 +45,7 @@ height: 100%; margin-left: 10px; box-sizing: border-box; - - button { - padding: 10px; - } + min-width: 80px; } } diff --git a/app/components/mask.tsx b/app/components/mask.tsx index 3f239aca..c980c48c 100644 --- a/app/components/mask.tsx +++ b/app/components/mask.tsx @@ -291,17 +291,16 @@ export function MaskPage() { ))} -
- } - text={Locale.Mask.Page.Create} - bordered - onClick={() => { - const createdMask = maskStore.create(); - setEditingMaskId(createdMask.id); - }} - /> -
+ } + text={Locale.Mask.Page.Create} + bordered + onClick={() => { + const createdMask = maskStore.create(); + setEditingMaskId(createdMask.id); + }} + />
From 717c123b82e5b20e27b1bd29849ba4f64bbd9b6b Mon Sep 17 00:00:00 2001 From: Yidadaa Date: Tue, 2 May 2023 03:10:13 +0800 Subject: [PATCH 14/15] feat: improve mask ui --- app/components/mask.module.scss | 15 +-------------- app/components/new-chat.module.scss | 5 ++--- app/components/new-chat.tsx | 23 +++++++++++++---------- app/locales/cn.ts | 2 +- 4 files changed, 17 insertions(+), 28 deletions(-) diff --git a/app/components/mask.module.scss b/app/components/mask.module.scss index c1778d45..d66d9886 100644 --- a/app/components/mask.module.scss +++ b/app/components/mask.module.scss @@ -1,16 +1,4 @@ @import "../styles/animation.scss"; - -@keyframes search-in { - from { - opacity: 0; - transform: translateY(5vh) scaleX(0.5); - } - to { - opacity: 1; - transform: translateY(0) scaleX(1); - } -} - .mask-page { height: 100%; display: flex; @@ -24,7 +12,7 @@ width: 100%; max-width: 100%; margin-bottom: 20px; - animation: search-in ease 0.3s; + animation: slide-in ease 0.3s; height: 40px; display: flex; @@ -33,7 +21,6 @@ flex-grow: 1; max-width: 100%; min-width: 0; - animation: search-in ease 0.3s; } .mask-filter-lang { diff --git a/app/components/new-chat.module.scss b/app/components/new-chat.module.scss index 36f447bb..b0e472ea 100644 --- a/app/components/new-chat.module.scss +++ b/app/components/new-chat.module.scss @@ -59,10 +59,9 @@ display: flex; justify-content: center; - .search-bar { + .more { font-size: 12px; - margin-right: 10px; - width: 40vw; + margin-left: 10px; } } diff --git a/app/components/new-chat.tsx b/app/components/new-chat.tsx index 8cb4d35e..42612e0a 100644 --- a/app/components/new-chat.tsx +++ b/app/components/new-chat.tsx @@ -5,10 +5,11 @@ import { EmojiAvatar } from "./emoji"; import styles from "./new-chat.module.scss"; import LeftIcon from "../icons/left.svg"; -import AddIcon from "../icons/lightning.svg"; +import LightningIcon from "../icons/lightning.svg"; +import EyeIcon from "../icons/eye.svg"; import { useLocation, useNavigate } from "react-router-dom"; -import { createEmptyMask, Mask, useMaskStore } from "../store/mask"; +import { Mask, useMaskStore } from "../store/mask"; import Locale from "../locales"; import { useAppConfig, useChatStore } from "../store"; import { MaskAvatar } from "./mask"; @@ -148,20 +149,22 @@ export function NewChat() {
{Locale.NewChat.SubTitle}
- navigate(Path.Masks)} - /> - startChat()} - icon={} + icon={} type="primary" shadow /> + + navigate(Path.Masks)} + icon={} + bordered + shadow + />
diff --git a/app/locales/cn.ts b/app/locales/cn.ts index 45dc10a9..f973dfbc 100644 --- a/app/locales/cn.ts +++ b/app/locales/cn.ts @@ -224,7 +224,7 @@ const cn = { ConfirmNoShow: "确认禁用?禁用后可以随时在设置中重新启用。", Title: "挑选一个面具", SubTitle: "现在开始,与面具背后的灵魂思维碰撞", - More: "搜索更多", + More: "查看全部", }, UI: { From aeda7520fea361474c2177539d203a75226af358 Mon Sep 17 00:00:00 2001 From: Clarence Dan <48417261+ClarenceDan@users.noreply.github.com> Date: Tue, 2 May 2023 11:18:18 +0800 Subject: [PATCH 15/15] fix: Resolve markdown link issue Resolved Markdown Issue This pull request also resolves an issue where internal links were not redirecting properly in markdown, and optimizes the behavior for external links to open in a new window. --- app/components/markdown.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/components/markdown.tsx b/app/components/markdown.tsx index b5805e50..49bb581d 100644 --- a/app/components/markdown.tsx +++ b/app/components/markdown.tsx @@ -46,8 +46,13 @@ function _MarkDownContent(props: { content: string }) { ]} components={{ pre: PreCode, + a: (aProps) => { + const href = aProps.href || ""; + const isInternal = /^\/#/i.test(href); + const target = isInternal ? "_self" : aProps.target ?? "_blank"; + return ; + }, }} - linkTarget={"_blank"} > {props.content}