import { XMarkIcon } from "@heroicons/react/24/outline"; import Markdown from "preact-markdown"; import { useState, useEffect, StateUpdater } from "preact/hooks"; import { Tr, langCodeContext, LANG_OPTIONS } from "@/translate"; import { ChatStore, ChatStoreMessage } from "@/types/chatstore"; import { calculate_token_length, getMessageText } from "@/chatgpt"; 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 logprobToColor from "@/logprob"; import { ChatBubble, ChatBubbleAvatar, ChatBubbleMessage, ChatBubbleAction, ChatBubbleActionWrapper, } from "@/components/ui/chat/chat-bubble"; import { useToast } from "@/hooks/use-toast"; import { ClipboardIcon, PencilIcon, MessageSquareOffIcon, MessageSquarePlusIcon, } from "lucide-react"; export const isVailedJSON = (str: string): boolean => { try { JSON.parse(str); } catch (e) { return false; } return true; }; interface Props { messageIndex: number; chatStore: ChatStore; setChatStore: (cs: ChatStore) => void; } export default function Message(props: Props) { const { chatStore, messageIndex, setChatStore } = props; const chat = chatStore.history[messageIndex]; const [showEdit, setShowEdit] = useState(false); const [showCopiedHint, setShowCopiedHint] = useState(false); const [renderMarkdown, setRenderWorkdown] = useState(false); const [renderColor, setRenderColor] = useState(false); const DeleteIcon = () => ( ); const CopiedHint = () => (
{Tr("Message copied to clipboard!")}
); const { toast } = useToast(); const copyToClipboard = async (text: string) => { try { await navigator.clipboard.writeText(text); toast({ description: Tr("Message copied to clipboard!"), }); } catch (err) { const textArea = document.createElement("textarea"); textArea.value = text; document.body.appendChild(textArea); textArea.select(); try { document.execCommand("copy"); toast({ description: Tr("Message copied to clipboard!"), }); } catch (err) { toast({ description: Tr("Failed to copy to clipboard"), }); } document.body.removeChild(textArea); } }; const CopyIcon = ({ textToCopy }: { textToCopy: string }) => { return ( <> ); }; return ( <> {chatStore.postBeginIndex !== 0 && !chatStore.history[messageIndex].hide && chatStore.postBeginIndex === chatStore.history.slice(0, messageIndex).filter(({ hide }) => !hide) .length && (

Above messages are "forgotten"
)} {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))}
)}
) : ( ) } 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 && ( )}
{chatStore.develop_mode && (
token
{chat.response_model_name && ( <> {chat.response_model_name} )}
)} ); }