refactor: rename message.tsx to MessageBubble.tsx and consolidate message-related components for better organization
This commit is contained in:
@@ -1,15 +1,11 @@
|
|||||||
import { XMarkIcon } from "@heroicons/react/24/outline";
|
import { XMarkIcon } from "@heroicons/react/24/outline";
|
||||||
import Markdown from "react-markdown";
|
import Markdown from "react-markdown";
|
||||||
import { useContext, useState } from "react";
|
import { useContext, useState } from "react";
|
||||||
|
import { ChatStoreMessage } from "@/types/chatstore";
|
||||||
|
|
||||||
import { Tr, langCodeContext, LANG_OPTIONS } from "@/translate";
|
import { Tr } from "@/translate";
|
||||||
import { ChatStore, ChatStoreMessage } from "@/types/chatstore";
|
import { getMessageText } from "@/chatgpt";
|
||||||
import { calculate_token_length, getMessageText } from "@/chatgpt";
|
|
||||||
import TTSButton, { TTSPlay } from "@/tts";
|
import TTSButton, { TTSPlay } from "@/tts";
|
||||||
import { MessageHide } from "@/messageHide";
|
|
||||||
import { MessageDetail } from "@/messageDetail";
|
|
||||||
import { MessageToolCall } from "@/messageToolCall";
|
|
||||||
import { MessageToolResp } from "@/messageToolResp";
|
|
||||||
import { EditMessage } from "@/editMessage";
|
import { EditMessage } from "@/editMessage";
|
||||||
import logprobToColor from "@/utils/logprob";
|
import logprobToColor from "@/utils/logprob";
|
||||||
import {
|
import {
|
||||||
@@ -18,6 +14,7 @@ import {
|
|||||||
ChatBubbleAction,
|
ChatBubbleAction,
|
||||||
ChatBubbleActionWrapper,
|
ChatBubbleActionWrapper,
|
||||||
} from "@/components/ui/chat/chat-bubble";
|
} from "@/components/ui/chat/chat-bubble";
|
||||||
|
import { Badge } from "@/components/ui/badge";
|
||||||
import { useToast } from "@/hooks/use-toast";
|
import { useToast } from "@/hooks/use-toast";
|
||||||
import {
|
import {
|
||||||
ClipboardIcon,
|
ClipboardIcon,
|
||||||
@@ -25,16 +22,126 @@ import {
|
|||||||
MessageSquareOffIcon,
|
MessageSquareOffIcon,
|
||||||
MessageSquarePlusIcon,
|
MessageSquarePlusIcon,
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { AppContext } from "./pages/App";
|
import { AppContext } from "@/pages/App";
|
||||||
|
|
||||||
export const isVailedJSON = (str: string): boolean => {
|
interface HideMessageProps {
|
||||||
try {
|
chat: ChatStoreMessage;
|
||||||
JSON.parse(str);
|
}
|
||||||
} catch (e) {
|
|
||||||
return false;
|
function MessageHide({ chat }: HideMessageProps) {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
||||||
|
<span>{getMessageText(chat).split("\n")[0].slice(0, 28)} ...</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex mt-2 justify-center">
|
||||||
|
<Badge variant="destructive">Removed from context</Badge>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MessageDetailProps {
|
||||||
|
chat: ChatStoreMessage;
|
||||||
|
renderMarkdown: boolean;
|
||||||
|
}
|
||||||
|
function MessageDetail({ chat, renderMarkdown }: MessageDetailProps) {
|
||||||
|
if (typeof chat.content === "string") {
|
||||||
|
return <div></div>;
|
||||||
}
|
}
|
||||||
return true;
|
return (
|
||||||
};
|
<div>
|
||||||
|
{chat.content.map((mdt) =>
|
||||||
|
mdt.type === "text" ? (
|
||||||
|
chat.hide ? (
|
||||||
|
mdt.text?.split("\n")[0].slice(0, 16) + " ..."
|
||||||
|
) : renderMarkdown ? (
|
||||||
|
<Markdown>{mdt.text}</Markdown>
|
||||||
|
) : (
|
||||||
|
mdt.text
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
<img
|
||||||
|
className="my-2 rounded-md max-w-64 max-h-64"
|
||||||
|
src={mdt.image_url?.url}
|
||||||
|
onClick={() => {
|
||||||
|
window.open(mdt.image_url?.url, "_blank");
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ToolCallMessageProps {
|
||||||
|
chat: ChatStoreMessage;
|
||||||
|
copyToClipboard: (text: string) => void;
|
||||||
|
}
|
||||||
|
function MessageToolCall({ chat, copyToClipboard }: ToolCallMessageProps) {
|
||||||
|
return (
|
||||||
|
<div className="message-content">
|
||||||
|
{chat.tool_calls?.map((tool_call) => (
|
||||||
|
<div className="bg-blue-300 dark:bg-blue-800 p-1 rounded my-1">
|
||||||
|
<strong>
|
||||||
|
Tool Call ID:{" "}
|
||||||
|
<span
|
||||||
|
className="p-1 m-1 rounded cursor-pointer hover:opacity-50 hover:underline"
|
||||||
|
onClick={() => copyToClipboard(String(tool_call.id))}
|
||||||
|
>
|
||||||
|
{tool_call?.id}
|
||||||
|
</span>
|
||||||
|
</strong>
|
||||||
|
<p>Type: {tool_call?.type}</p>
|
||||||
|
<p>
|
||||||
|
Function:
|
||||||
|
<span
|
||||||
|
className="p-1 m-1 rounded cursor-pointer hover:opacity-50 hover:underline"
|
||||||
|
onClick={() => copyToClipboard(tool_call.function.name)}
|
||||||
|
>
|
||||||
|
{tool_call.function.name}
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Arguments:
|
||||||
|
<span
|
||||||
|
className="p-1 m-1 rounded cursor-pointer hover:opacity-50 hover:underline"
|
||||||
|
onClick={() => copyToClipboard(tool_call.function.arguments)}
|
||||||
|
>
|
||||||
|
{tool_call.function.arguments}
|
||||||
|
</span>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
{/* [TODO] */}
|
||||||
|
{chat.content as string}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ToolRespondMessageProps {
|
||||||
|
chat: ChatStoreMessage;
|
||||||
|
copyToClipboard: (text: string) => void;
|
||||||
|
}
|
||||||
|
function MessageToolResp({ chat, copyToClipboard }: ToolRespondMessageProps) {
|
||||||
|
return (
|
||||||
|
<div className="message-content">
|
||||||
|
<div className="bg-blue-300 dark:bg-blue-800 p-1 rounded my-1">
|
||||||
|
<strong>
|
||||||
|
Tool Response ID:{" "}
|
||||||
|
<span
|
||||||
|
className="p-1 m-1 rounded cursor-pointer hover:opacity-50 hover:underline"
|
||||||
|
onClick={() => copyToClipboard(String(chat.tool_call_id))}
|
||||||
|
>
|
||||||
|
{chat.tool_call_id}
|
||||||
|
</span>
|
||||||
|
</strong>
|
||||||
|
{/* [TODO] */}
|
||||||
|
<p>{chat.content as string}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default function Message(props: { messageIndex: number }) {
|
export default function Message(props: { messageIndex: number }) {
|
||||||
const ctx = useContext(AppContext);
|
const ctx = useContext(AppContext);
|
||||||
@@ -44,7 +151,6 @@ export default function Message(props: { messageIndex: number }) {
|
|||||||
|
|
||||||
const chat = chatStore.history[messageIndex];
|
const chat = chatStore.history[messageIndex];
|
||||||
const [showEdit, setShowEdit] = useState(false);
|
const [showEdit, setShowEdit] = useState(false);
|
||||||
const [showCopiedHint, setShowCopiedHint] = useState(false);
|
|
||||||
const [renderMarkdown, setRenderWorkdown] = useState(false);
|
const [renderMarkdown, setRenderWorkdown] = useState(false);
|
||||||
const [renderColor, setRenderColor] = useState(false);
|
const [renderColor, setRenderColor] = useState(false);
|
||||||
const DeleteIcon = () => (
|
const DeleteIcon = () => (
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
import { ChatStoreMessage } from "@/types/chatstore";
|
|
||||||
import Markdown from "react-markdown";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
chat: ChatStoreMessage;
|
|
||||||
renderMarkdown: boolean;
|
|
||||||
}
|
|
||||||
export function MessageDetail({ chat, renderMarkdown }: Props) {
|
|
||||||
if (typeof chat.content === "string") {
|
|
||||||
return <div></div>;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{chat.content.map((mdt) =>
|
|
||||||
mdt.type === "text" ? (
|
|
||||||
chat.hide ? (
|
|
||||||
mdt.text?.split("\n")[0].slice(0, 16) + " ..."
|
|
||||||
) : renderMarkdown ? (
|
|
||||||
<Markdown>{mdt.text}</Markdown>
|
|
||||||
) : (
|
|
||||||
mdt.text
|
|
||||||
)
|
|
||||||
) : (
|
|
||||||
<img
|
|
||||||
className="my-2 rounded-md max-w-64 max-h-64"
|
|
||||||
src={mdt.image_url?.url}
|
|
||||||
onClick={() => {
|
|
||||||
window.open(mdt.image_url?.url, "_blank");
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
import { ChatStoreMessage } from "@/types/chatstore";
|
|
||||||
import { getMessageText } from "@/chatgpt";
|
|
||||||
import { Badge } from "./components/ui/badge";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
chat: ChatStoreMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function MessageHide({ chat }: Props) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
|
||||||
<span>{getMessageText(chat).split("\n")[0].slice(0, 28)} ...</span>
|
|
||||||
</div>
|
|
||||||
<div className="flex mt-2 justify-center">
|
|
||||||
<Badge variant="destructive">Removed from context</Badge>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
import { ChatStoreMessage } from "@/types/chatstore";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
chat: ChatStoreMessage;
|
|
||||||
copyToClipboard: (text: string) => void;
|
|
||||||
}
|
|
||||||
export function MessageToolCall({ chat, copyToClipboard }: Props) {
|
|
||||||
return (
|
|
||||||
<div className="message-content">
|
|
||||||
{chat.tool_calls?.map((tool_call) => (
|
|
||||||
<div className="bg-blue-300 dark:bg-blue-800 p-1 rounded my-1">
|
|
||||||
<strong>
|
|
||||||
Tool Call ID:{" "}
|
|
||||||
<span
|
|
||||||
className="p-1 m-1 rounded cursor-pointer hover:opacity-50 hover:underline"
|
|
||||||
onClick={() => copyToClipboard(String(tool_call.id))}
|
|
||||||
>
|
|
||||||
{tool_call?.id}
|
|
||||||
</span>
|
|
||||||
</strong>
|
|
||||||
<p>Type: {tool_call?.type}</p>
|
|
||||||
<p>
|
|
||||||
Function:
|
|
||||||
<span
|
|
||||||
className="p-1 m-1 rounded cursor-pointer hover:opacity-50 hover:underline"
|
|
||||||
onClick={() => copyToClipboard(tool_call.function.name)}
|
|
||||||
>
|
|
||||||
{tool_call.function.name}
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Arguments:
|
|
||||||
<span
|
|
||||||
className="p-1 m-1 rounded cursor-pointer hover:opacity-50 hover:underline"
|
|
||||||
onClick={() => copyToClipboard(tool_call.function.arguments)}
|
|
||||||
>
|
|
||||||
{tool_call.function.arguments}
|
|
||||||
</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
{/* [TODO] */}
|
|
||||||
{chat.content as string}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import { ChatStoreMessage } from "@/types/chatstore";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
chat: ChatStoreMessage;
|
|
||||||
copyToClipboard: (text: string) => void;
|
|
||||||
}
|
|
||||||
export function MessageToolResp({ chat, copyToClipboard }: Props) {
|
|
||||||
return (
|
|
||||||
<div className="message-content">
|
|
||||||
<div className="bg-blue-300 dark:bg-blue-800 p-1 rounded my-1">
|
|
||||||
<strong>
|
|
||||||
Tool Response ID:{" "}
|
|
||||||
<span
|
|
||||||
className="p-1 m-1 rounded cursor-pointer hover:opacity-50 hover:underline"
|
|
||||||
onClick={() => copyToClipboard(String(chat.tool_call_id))}
|
|
||||||
>
|
|
||||||
{chat.tool_call_id}
|
|
||||||
</span>
|
|
||||||
</strong>
|
|
||||||
{/* [TODO] */}
|
|
||||||
<p>{chat.content as string}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -215,6 +215,10 @@ export function App() {
|
|||||||
const newKey = await (await db).add(STORAGE_NAME, newChatStore(chatStore));
|
const newKey = await (await db).add(STORAGE_NAME, newChatStore(chatStore));
|
||||||
setSelectedChatIndex(newKey as number);
|
setSelectedChatIndex(newKey as number);
|
||||||
setAllChatStoreIndexes(await (await db).getAllKeys(STORAGE_NAME));
|
setAllChatStoreIndexes(await (await db).getAllKeys(STORAGE_NAME));
|
||||||
|
toast({
|
||||||
|
title: "New chat session created",
|
||||||
|
description: `A new chat session (ID. ${newKey}) has been created.`,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
const handleNewChatStore = async () => {
|
const handleNewChatStore = async () => {
|
||||||
return handleNewChatStoreWithOldOne(chatStore);
|
return handleNewChatStoreWithOldOne(chatStore);
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ import ChatGPT, {
|
|||||||
Usage,
|
Usage,
|
||||||
} from "@/chatgpt";
|
} from "@/chatgpt";
|
||||||
import { ChatStoreMessage } from "../types/chatstore";
|
import { ChatStoreMessage } from "../types/chatstore";
|
||||||
import Message from "@/message";
|
import Message from "@/components/MessageBubble";
|
||||||
import { models } from "@/types/models";
|
import { models } from "@/types/models";
|
||||||
import { AddImage } from "@/addImage";
|
import { AddImage } from "@/addImage";
|
||||||
import { ListAPIs } from "@/listAPIs";
|
import { ListAPIs } from "@/listAPIs";
|
||||||
|
|||||||
Reference in New Issue
Block a user