import React, { useState, useEffect, useRef, useCallback } from 'react'; import TextWrapper from './TextWrapper'; import MultiMessage from './MultiMessage'; import { useSelector, useDispatch } from 'react-redux'; import HoverButtons from './HoverButtons'; import SiblingSwitch from './SiblingSwitch'; import { setError } from '~/store/convoSlice'; import { setMessages } from '~/store/messageSlice'; import { setSubmitState, setSubmission } from '~/store/submitSlice'; import { setText } from '~/store/textSlice'; import { setConversation } from '../../store/convoSlice'; import { getIconOfModel } from '../../utils'; export default function Message({ message, messages, scrollToBottom, currentEditId, setCurrentEditId, siblingIdx, siblingCount, setSiblingIdx }) { const { isSubmitting, model, chatGptLabel, promptPrefix } = useSelector( (state) => state.submit ); const [abortScroll, setAbort] = useState(false); const { sender, text, isCreatedByUser, error, submitting } = message; const textEditor = useRef(null); const convo = useSelector((state) => state.convo); const { initial } = useSelector((state) => state.models); const { error: convoError } = convo; const last = !message?.children?.length; const edit = message.messageId == currentEditId; const dispatch = useDispatch(); // const notUser = !isCreatedByUser; // sender.toLowerCase() !== 'user'; const blinker = submitting && isSubmitting && last && !isCreatedByUser; const generateCursor = useCallback(() => { if (!blinker) { return ''; } return █; }, [blinker]); useEffect(() => { if (blinker && !abortScroll) { scrollToBottom(); } }, [isSubmitting, text, blinker, scrollToBottom, abortScroll]); useEffect(() => { if (last) dispatch(setConversation({ parentMessageId: message?.messageId })); }, [last]); const enterEdit = (cancel) => setCurrentEditId(cancel ? -1 : message.messageId); const handleWheel = () => { if (blinker) { setAbort(true); } else { setAbort(false); } }; const props = { className: 'w-full border-b border-black/10 dark:border-gray-900/50 text-gray-800 bg-white dark:text-gray-100 group dark:bg-gray-800' }; const icon = getIconOfModel({ sender, isCreatedByUser, model, chatGptLabel, promptPrefix, error }); if (!isCreatedByUser) props.className = 'w-full border-b border-black/10 bg-gray-50 dark:border-gray-900/50 text-gray-800 dark:text-gray-100 group bg-gray-100 dark:bg-[#444654]'; // const wrapText = (text) => ; const resubmitMessage = () => { const text = textEditor.current.innerText; if (convoError) { dispatch(setError(false)); } if (!!isSubmitting || text.trim() === '') { return; } // this is not a real messageId, it is used as placeholder before real messageId returned const fakeMessageId = crypto.randomUUID(); const isCustomModel = model === 'chatgptCustom' || !initial[model]; const currentMsg = { sender: 'User', text: text.trim(), current: true, isCreatedByUser: true, parentMessageId: message?.parentMessageId, conversationId: message?.conversationId, messageId: fakeMessageId }; const sender = model === 'chatgptCustom' ? chatGptLabel : model; const initialResponse = { sender, text: '', parentMessageId: fakeMessageId, submitting: true }; dispatch(setSubmitState(true)); dispatch(setMessages([...messages, currentMsg, initialResponse])); dispatch(setText('')); const submission = { isCustomModel, message: { ...currentMsg, model, chatGptLabel, promptPrefix }, messages: messages, currentMsg, initialResponse, sender }; console.log('User Input:', currentMsg?.text); // handleSubmit(submission); dispatch(setSubmission(submission)); setSiblingIdx(siblingCount - 1); enterEdit(true); }; return ( <> {typeof icon === 'string' && icon.match(/[^\u0000-\u007F]+/) ? ( {icon} ) : ( icon )} {error ? ( {`An error occurred. Please try again in a few moments.\n\nError message: ${text}`} ) : edit ? ( {/* */} {text} Save & Submit enterEdit(true)} > Cancel ) : ( {/* */} {!isCreatedByUser ? ( ) : ( text )} )} enterEdit()} /> > ); }