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 } 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 = (text: string) => {
navigator.clipboard.writeText(text);
// TODO: Remove show copied hint
toast({
description: Tr("Message copied to clipboard!"),
});
};
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 && (
)}
{showEdit && (
)}
{showCopiedHint && }
{chatStore.develop_mode && (
)}
>
);
}