import React, { useEffect, useLayoutEffect, useRef, useState } from "react"; import { useStore } from "@/_models/RootStore"; import { observer } from "mobx-react-lite"; import { ChatMessage, MessageStatus, MessageType } from "@/_models/ChatMessage"; import SimpleImageMessage from "../SimpleImageMessage"; import SimpleTextMessage from "../SimpleTextMessage"; import { Instance } from "mobx-state-tree"; import { GenerativeSampleContainer } from "../GenerativeSampleContainer"; import { AiModelType } from "@/_models/Product"; import SampleLlmContainer from "@/_components/SampleLlmContainer"; import SimpleControlNetMessage from "../SimpleControlNetMessage"; import { GetConversationMessagesQuery, GetConversationMessagesDocument, } from "@/graphql"; import { useLazyQuery } from "@apollo/client"; import LoadingIndicator from "../LoadingIndicator"; import StreamTextMessage from "../StreamTextMessage"; type Props = { onPromptSelected: (prompt: string) => void; }; export const ChatBody: React.FC = observer(({ onPromptSelected }) => { const ref = useRef(null); const scrollRef = useRef(null); const [height, setHeight] = useState(0); const { historyStore } = useStore(); const refSmooth = useRef(null); const [heightContent, setHeightContent] = useState(0); const refContent = useRef(null); const convo = historyStore.getActiveConversation(); const [getConversationMessages] = useLazyQuery( GetConversationMessagesDocument ); useEffect(() => { refSmooth.current?.scrollIntoView({ behavior: "instant" }); }, [heightContent]); useLayoutEffect(() => { if (refContent.current) { setHeightContent(refContent.current?.offsetHeight); } }); useLayoutEffect(() => { if (!ref.current) return; setHeight(ref.current?.offsetHeight); }, []); const loadFunc = () => { historyStore.fetchMoreMessages(getConversationMessages); }; const messages = historyStore.getActiveMessages(); const shouldShowSampleContainer = messages.length === 0; const shouldShowImageSampleContainer = shouldShowSampleContainer && convo && convo.product.type === AiModelType.GenerativeArt; const model = convo?.product; const handleScroll = () => { if (!scrollRef.current) return; if ( scrollRef.current?.clientHeight - scrollRef.current?.scrollTop + 1 >= scrollRef.current?.scrollHeight ) { loadFunc(); } }; useEffect(() => { loadFunc(); scrollRef.current?.addEventListener("scroll", handleScroll); return () => { scrollRef.current?.removeEventListener("scroll", handleScroll); }; }, [scrollRef.current]); return (
{shouldShowSampleContainer && model ? ( shouldShowImageSampleContainer ? ( ) : ( ) ) : (
{messages.map((message, index) => renderItem(index, message))}
{convo?.isWaitingForModelResponse && (
)}
)}
); }); const renderItem = ( index: number, { messageType, senderAvatarUrl, senderName, createdAt, imageUrls, text, status, }: Instance ) => { switch (messageType) { case MessageType.ImageWithText: return ( ); case MessageType.Image: return ( ); case MessageType.Text: return status === MessageStatus.Ready ? ( ) : ( ); default: return null; } };