diff --git a/app/components/home.tsx b/app/components/home.tsx index 909e5406..341054b8 100644 --- a/app/components/home.tsx +++ b/app/components/home.tsx @@ -102,7 +102,7 @@ export function ChatList() { state.currentSessionIndex, state.selectSession, state.removeSession, - ] + ], ); return ( @@ -128,7 +128,7 @@ function useSubmitHandler() { const shouldSubmit = (e: KeyboardEvent) => { if (e.key !== "Enter") return false; - + return ( (config.submitKey === SubmitKey.AltEnter && e.altKey) || (config.submitKey === SubmitKey.CtrlEnter && e.ctrlKey) || @@ -170,7 +170,10 @@ export function PromptHints(props: { ); } -export function Chat(props: { showSideBar?: () => void, sideBarShowing?: boolean }) { +export function Chat(props: { + showSideBar?: () => void; + sideBarShowing?: boolean; +}) { type RenderMessage = Message & { preview?: boolean }; const chatStore = useChatStore(); @@ -190,11 +193,10 @@ export function Chat(props: { showSideBar?: () => void, sideBarShowing?: boolean const [promptHints, setPromptHints] = useState([]); const onSearch = useDebouncedCallback( (text: string) => { - if (chatStore.config.disablePromptHint) return; setPromptHints(promptStore.search(text)); }, 100, - { leading: true, trailing: true } + { leading: true, trailing: true }, ); const onPromptSelect = (prompt: Prompt) => { @@ -203,20 +205,31 @@ export function Chat(props: { showSideBar?: () => void, sideBarShowing?: boolean inputRef.current?.focus(); }; + const scrollInput = () => { + const dom = inputRef.current; + if (!dom) return; + const paddingBottomNum: number = parseInt( + window.getComputedStyle(dom).paddingBottom, + 10, + ); + dom.scrollTop = dom.scrollHeight - dom.offsetHeight + paddingBottomNum; + }; + // only search prompts when user input is short const SEARCH_TEXT_LIMIT = 30; const onInput = (text: string) => { - const textareaDom = inputRef.current - if (textareaDom) { - const paddingBottomNum: number = parseInt(window.getComputedStyle(textareaDom).paddingBottom, 10); - textareaDom.scrollTop = textareaDom.scrollHeight - textareaDom.offsetHeight + paddingBottomNum; - } + scrollInput(); setUserInput(text); const n = text.trim().length; - if (n === 0 || n > SEARCH_TEXT_LIMIT) { + + // clear search results + if (n === 0) { setPromptHints([]); - } else { - onSearch(text); + } else if (!chatStore.config.disablePromptHint && n < SEARCH_TEXT_LIMIT) { + // check if need to trigger auto completion + if (text.startsWith("/") && text.length > 1) { + onSearch(text.slice(1)); + } } }; @@ -285,7 +298,7 @@ export function Chat(props: { showSideBar?: () => void, sideBarShowing?: boolean preview: true, }, ] - : [] + : [], ) .concat( userInput.length > 0 @@ -297,7 +310,7 @@ export function Chat(props: { showSideBar?: () => void, sideBarShowing?: boolean preview: true, }, ] - : [] + : [], ); // auto scroll @@ -380,32 +393,33 @@ export function Chat(props: { showSideBar?: () => void, sideBarShowing?: boolean )}
- {(!isUser && !(message.preview || message.content.length === 0)) && ( -
- {message.streaming ? ( -
onUserStop(i)} - > - {Locale.Chat.Actions.Stop} -
- ) : ( -
onResend(i)} - > - {Locale.Chat.Actions.Retry} -
- )} + {!isUser && + !(message.preview || message.content.length === 0) && ( +
+ {message.streaming ? ( +
onUserStop(i)} + > + {Locale.Chat.Actions.Stop} +
+ ) : ( +
onResend(i)} + > + {Locale.Chat.Actions.Retry} +
+ )} -
copyToClipboard(message.content)} - > - {Locale.Chat.Actions.Copy} +
copyToClipboard(message.content)} + > + {Locale.Chat.Actions.Copy} +
-
- )} + )} {(message.preview || message.content.length === 0) && !isUser ? ( @@ -560,7 +574,7 @@ export function Home() { state.newSession, state.currentSessionIndex, state.removeSession, - ] + ], ); const loading = !useHasHydrated(); const [showSideBar, setShowSideBar] = useState(true); @@ -653,7 +667,11 @@ export function Home() { }} /> ) : ( - setShowSideBar(true)} sideBarShowing={showSideBar} /> + setShowSideBar(true)} + sideBarShowing={showSideBar} + /> )}
diff --git a/app/locales/cn.ts b/app/locales/cn.ts index b93ec859..76f6a770 100644 --- a/app/locales/cn.ts +++ b/app/locales/cn.ts @@ -77,7 +77,7 @@ const cn = { Prompt: { Disable: { Title: "禁用提示词自动补全", - SubTitle: "禁用后将无法自动根据输入补全", + SubTitle: "在输入框开头输入 / 即可触发自动补全", }, List: "自定义提示词列表", ListCount: (builtin: number, custom: number) => diff --git a/app/locales/en.ts b/app/locales/en.ts index d1689372..d21679ab 100644 --- a/app/locales/en.ts +++ b/app/locales/en.ts @@ -79,7 +79,7 @@ const en: LocaleType = { Prompt: { Disable: { Title: "Disable auto-completion", - SubTitle: "After disabling, auto-completion will not be available", + SubTitle: "Input / to trigger auto-completion", }, List: "Prompt List", ListCount: (builtin: number, custom: number) => diff --git a/app/locales/tw.ts b/app/locales/tw.ts index 29f5ec22..63312eb4 100644 --- a/app/locales/tw.ts +++ b/app/locales/tw.ts @@ -20,7 +20,7 @@ const tw: LocaleType = { Retry: "重試", }, Typing: "正在輸入…", - Input: (submitKey: string) => { + Input: (submitKey: string) => { var inputHints = `輸入訊息後,按下 ${submitKey} 鍵即可發送`; if (submitKey === String(SubmitKey.Enter)) { inputHints += ",Shift + Enter 鍵換行"; @@ -78,7 +78,7 @@ const tw: LocaleType = { Prompt: { Disable: { Title: "停用提示詞自動補全", - SubTitle: "若停用後,將無法自動根據輸入進行補全", + SubTitle: "在輸入框開頭輸入 / 即可觸發自動補全", }, List: "自定義提示詞列表", ListCount: (builtin: number, custom: number) => @@ -124,8 +124,7 @@ const tw: LocaleType = { Prompt: { History: (content: string) => "這是 AI 與用戶的歷史聊天總結,作為前情提要:" + content, - Topic: - "直接返回這句話的簡要主題,無須解釋,若無主題,請直接返回「閒聊」", + Topic: "直接返回這句話的簡要主題,無須解釋,若無主題,請直接返回「閒聊」", Summarize: "簡要總結一下你和用戶的對話,作為後續的上下文提示 prompt,且字數控制在 50 字以內", },