import { XMarkIcon } from "@heroicons/react/24/outline";
import Markdown from "react-markdown";
import { useContext, useState } from "react";
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";
import { AppContext } from "./pages/App";
export const isVailedJSON = (str: string): boolean => {
try {
JSON.parse(str);
} catch (e) {
return false;
}
return true;
};
export default function Message(props: { messageIndex: number }) {
const ctx = useContext(AppContext);
if (ctx === null) return <>>;
const { messageIndex } = props;
const { chatStore, setChatStore } = ctx;
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 ? (
// [TODO] It is happening https://github.com/remarkjs/react-markdown/pull/879
// {getMessageText(chat)}
<>>
) : (
{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 && (
)}
>
);
}