From 368d9810c24b9fb251877a3d425d57e3495059f4 Mon Sep 17 00:00:00 2001 From: ecwu Date: Fri, 20 Dec 2024 18:21:28 +0800 Subject: [PATCH] refactor message layout for improved UI consistency --- src/message.tsx | 288 +++++++++++++++++++++-------------------- src/pages/App.tsx | 168 ++++++++++++------------ src/pages/Chatbox.tsx | 291 ++++++++++++++++++++++-------------------- 3 files changed, 391 insertions(+), 356 deletions(-) diff --git a/src/message.tsx b/src/message.tsx index 1e95ac8..3ed507e 100644 --- a/src/message.tsx +++ b/src/message.tsx @@ -12,6 +12,15 @@ import { MessageToolCall } from "@/messageToolCall"; import { MessageToolResp } from "@/messageToolResp"; import { EditMessage } from "@/editMessage"; import logprobToColor from "@/logprob"; +import { + ChatBubble, + ChatBubbleAvatar, + ChatBubbleMessage, + ChatBubbleAction, + ChatBubbleActionWrapper, +} from "@/components/ui/chat/chat-bubble"; +import { useToast } from "@/hooks/use-toast"; +import { ClipboardIcon, PencilIcon, TrashIcon } from "lucide-react"; export const isVailedJSON = (str: string): boolean => { try { @@ -74,10 +83,13 @@ export default function Message(props: Props) { ); + const { toast } = useToast(); const copyToClipboard = (text: string) => { navigator.clipboard.writeText(text); - setShowCopiedHint(true); - setTimeout(() => setShowCopiedHint(false), 1000); + // TODO: Remove show copied hint + toast({ + description: Tr("Message copied to clipboard!"), + }); }; const CopyIcon = ({ textToCopy }: { textToCopy: string }) => { @@ -108,154 +120,154 @@ export default function Message(props: Props) { )} -
-
-
-
- {chat.hide ? ( - - ) : typeof chat.content !== "string" ? ( - - ) : chat.tool_calls ? ( - - ) : chat.role === "tool" ? ( - - ) : renderMarkdown ? ( - // @ts-ignore - - ) : ( -
- { - // only show when content is string or list of message - // this check is used to avoid rendering tool call - chat.content && - (chat.logprobs && renderColor - ? chat.logprobs.content - .filter((c) => c.token) - .map((c) => ( -
- {c.token} -
- )) - : getMessageText(chat)) - } -
- )} + + + {chat.hide ? ( + + ) : typeof chat.content !== "string" ? ( + + ) : chat.tool_calls ? ( + + ) : chat.role === "tool" ? ( + + ) : renderMarkdown ? ( + + ) : ( +
+ {chat.content && + (chat.logprobs && renderColor + ? chat.logprobs.content + .filter((c) => c.token) + .map((c) => ( +
+ {c.token} +
+ )) + : getMessageText(chat))}
-
- - - - {chatStore.tts_api && chatStore.tts_key && ( - - )} - - {chat.response_model_name && ( - <> - {chat.response_model_name} -
- - )} -
-
- {showEdit && ( - + + } + onClick={() => { + chatStore.history[messageIndex].hide = + !chatStore.history[messageIndex].hide; + chatStore.totalTokens = 0; + for (const i of chatStore.history + .filter(({ hide }) => !hide) + .slice(chatStore.postBeginIndex) + .map(({ token }) => token)) { + chatStore.totalTokens += i; + } + setChatStore({ ...chatStore }); + }} + /> + } + onClick={() => setShowEdit(true)} + /> + } + onClick={() => copyToClipboard(getMessageText(chat))} + /> + {chatStore.tts_api && chatStore.tts_key && ( + )} - {showCopiedHint && } - {chatStore.develop_mode && ( -
+ + + {showEdit && ( + + )} + {showCopiedHint && } + {chatStore.develop_mode && ( +
+
+ token + + +
+
+
- )} + /> + {Tr("example")} + + + +
-
+ )} ); } diff --git a/src/pages/App.tsx b/src/pages/App.tsx index 4cb1ca9..00fb6da 100644 --- a/src/pages/App.tsx +++ b/src/pages/App.tsx @@ -68,6 +68,7 @@ import { ScissorsIcon, WholeWordIcon, EllipsisIcon, + CogIcon, } from "lucide-react"; import { Badge } from "@/components/ui/badge"; @@ -307,90 +308,95 @@ export function App() { -
+
-
-

{chatStore.model}

{" "} - - {chatStore.totalTokens.toString()} - - - - - - -

- Tokens: {chatStore.totalTokens}/{chatStore.maxTokens} -

-

- Cut(s): {chatStore.postBeginIndex}/ - {chatStore.history.filter(({ hide }) => !hide).length} -

-

- Cost: ${chatStore.cost.toFixed(4)} / $ - {getTotalCost().toFixed(2)} -

-
-
-
-
- - - - - {chatStore.model} - - - - {models[chatStore.model]?.price?.prompt * 1000 * 1000}$ / - 1M input tokens - - - - - - - {chatStore.streamMode ? Tr("STREAM") : Tr("FETCH")} - - - STREAM/FETCH - - - - - {" "} - {chatStore.totalTokens} - - - Max: {chatStore.maxTokens} - - - - - - {chatStore.postBeginIndex} - - - - Max:{" "} - {chatStore.history.filter(({ hide }) => !hide).length} - - - - - - - {chatStore.cost.toFixed(4)} - - - - Accumulated: ${getTotalCost().toFixed(2)} - - - - +
+
+
+

{chatStore.model}

{" "} + + {chatStore.totalTokens.toString()} + + + + + + +

+ Tokens: {chatStore.totalTokens}/{chatStore.maxTokens} +

+

+ Cut(s): {chatStore.postBeginIndex}/ + {chatStore.history.filter(({ hide }) => !hide).length} +

+

+ Cost: ${chatStore.cost.toFixed(4)} / $ + {getTotalCost().toFixed(2)} +

+
+
+
+
+ + + + + {chatStore.model} + + + + {models[chatStore.model]?.price?.prompt * 1000 * 1000} + $ / 1M input tokens + + + + + + + {chatStore.streamMode ? Tr("STREAM") : Tr("FETCH")} + + + STREAM/FETCH + + + + + {" "} + {chatStore.totalTokens} + + + Max: {chatStore.maxTokens} + + + + + + {chatStore.postBeginIndex} + + + + Max:{" "} + {chatStore.history.filter(({ hide }) => !hide).length} + + + + + + + {chatStore.cost.toFixed(4)} + + + + Accumulated: ${getTotalCost().toFixed(2)} + + + + +
+
+
diff --git a/src/pages/Chatbox.tsx b/src/pages/Chatbox.tsx index 61b38e2..67faca1 100644 --- a/src/pages/Chatbox.tsx +++ b/src/pages/Chatbox.tsx @@ -40,6 +40,16 @@ import VersionHint from "@/components/VersionHint"; import StatusBar from "@/components/StatusBar"; import WhisperButton from "@/components/WhisperButton"; import AddToolMsg from "./AddToolMsg"; +import { Textarea } from "@/components/ui/textarea"; +import { Button } from "@/components/ui/button"; +import { + ChatBubble, + ChatBubbleAvatar, + ChatBubbleMessage, + ChatBubbleAction, + ChatBubbleActionWrapper, +} from "@/components/ui/chat/chat-bubble"; +import { ChatMessageList } from "@/components/ui/chat/chat-message-list"; export default function ChatBOX(props: { db: Promise>; @@ -436,7 +446,7 @@ export default function ChatBOX(props: { return (
- {showSettings && ( + {true && ( )} + + {chatStore.history.filter((msg) => !msg.example).length == 0 && ( +
+

+ {Tr("Saved prompt templates")} + +

+
+
+ +
+
+ )} + {chatStore.history.length === 0 && ( +

+ {Tr("No chat history here")} +
⚙{Tr("Model")}: {chatStore.model} +
⬆{Tr("Click above to change the settings of this chat")} +
↖{Tr("Click the conor to create a new chat")} +
⚠ + {Tr( + "All chat history and settings are stored in the local browser" + )} +
+

+ )} + {chatStore.systemMessageContent.trim() && ( +
+
Prompt
+
setShowSettings(true)} + > + {chatStore.systemMessageContent} +
+
+ )} + + {chatStore.history.map((_, messageIndex) => ( + + ))} + {showGenerating && ( +

+ {generatingMessage || Tr("Generating...")} + ... +

+ )} +

+ {chatStore.history.length > 0 && ( + - -

-
- -
-
- )} - {chatStore.history.length === 0 && ( -

- {Tr("No chat history here")} -
⚙{Tr("Model")}: {chatStore.model} -
⬆{Tr("Click above to change the settings of this chat")} -
↖{Tr("Click the conor to create a new chat")} -
⚠ - {Tr( - "All chat history and settings are stored in the local browser" + {Tr("Re-Generate")} + + )} + {chatStore.develop_mode && chatStore.history.length > 0 && ( + )} -

- )} - {chatStore.systemMessageContent.trim() && ( -
-
Prompt
-
setShowSettings(true)} - > - {chatStore.systemMessageContent} -
-
- )} - - {chatStore.history.map((_, messageIndex) => ( - - ))} - {showGenerating && ( -

- {generatingMessage || Tr("Generating...")} - ... +

+ {chatStore.postBeginIndex !== 0 && ( + <> +
+ {Tr("Info: chat history is too long, forget messages")}:{" "} + {chatStore.postBeginIndex} + + )}

- )} -

- {chatStore.history.length > 0 && ( - + + {showRetry && ( +

+ +

)} - {chatStore.develop_mode && chatStore.history.length > 0 && ( - - )} -

-

- {chatStore.postBeginIndex !== 0 && ( - <> -
- {Tr("Info: chat history is too long, forget messages")}:{" "} - {chatStore.postBeginIndex} - - )} -

- - {showRetry && ( -

- -

- )} -
+
+
{images.length > 0 && (
@@ -683,16 +696,17 @@ export default function ChatBOX(props: { )} -
- + {showAddImage && ( )} - - + {chatStore.whisper_api && chatStore.whisper_key && ( )} {chatStore.develop_mode && ( - + )} {chatStore.develop_mode && ( - + )} {chatStore.develop_mode && ( - + )} {showAddToolMsg && (