import * as React from 'react'; import { useState, useEffect, useRef } from 'react'; import { Alert, Center, Container, Stack, px } from '@mantine/core'; import { ScrollArea } from '@mantine/core'; import { Button } from '@mantine/core'; import { useListState, useResizeObserver, useTimeout, useViewportSize } from '@mantine/hooks'; import { IconPlayerStop, IconRotateDot } from '@tabler/icons-react'; import messageUtil from '@/util/MessageUtil'; import { useAppDispatch, useAppSelector } from '@/views/hooks'; import { setValue } from './inputSlice'; import { reGenerating, stopGenerating, startResponsing, happendError, newMessage, updateMessage, shiftMessage, selectGenerating, selectCurrentMessage, selectErrorMessage, selectMessages, selectMessageCount, selectIsBottom, selectIsTop, selectIsMiddle, onMessagesBottom, onMessagesTop, onMessagesMiddle, fetchHistoryMessages, } from './chatSlice'; import InputMessage from './InputMessage'; import MessageContainer from './MessageContainer'; const RegenerationButton = () => { const dispatch = useAppDispatch(); return (); }; const StopButton = () => { const dispatch = useAppDispatch(); return ( ); }; const chatPanel = () => { const dispatch = useAppDispatch(); const generating = useAppSelector(selectGenerating); const currentMessage = useAppSelector(selectCurrentMessage); const errorMessage = useAppSelector(selectErrorMessage); const messages = useAppSelector(selectMessages); const messageCount = useAppSelector(selectMessageCount); const isTop = useAppSelector(selectIsTop); const isBottom = useAppSelector(selectIsBottom); const isMiddle = useAppSelector(selectIsMiddle); const [chatContainerRef, chatContainerRect] = useResizeObserver(); const scrollViewport = useRef(null); const { height, width } = useViewportSize(); const scrollToBottom = () => scrollViewport?.current?.scrollTo({ top: scrollViewport.current.scrollHeight, behavior: 'smooth' }); const timer = useTimeout(() => { if (isBottom) { scrollToBottom(); } }, 1000); const onScrollPositionChange = ({ x, y }) => { const sh = scrollViewport.current?.scrollHeight || 0; const vh = scrollViewport.current?.clientHeight || 0; const gap = sh - vh - y; const isBottom = sh < vh ? true : gap < 100; const isTop = y === 0; // console.log(`sh:${sh},vh:${vh},x:${x},y:${y},gap:${gap}`); if (isBottom) { dispatch(onMessagesBottom()); } else if (isTop) { dispatch(onMessagesTop()); } else { dispatch(onMessagesMiddle()); } }; useEffect(() => { dispatch(fetchHistoryMessages()); messageUtil.registerHandler('receiveMessagePartial', (message: { text: string; }) => { dispatch(startResponsing(message.text)); }); messageUtil.registerHandler('receiveMessage', (message: { text: string; isError: boolean }) => { dispatch(stopGenerating()); if (message.isError) { dispatch(happendError(message.text)); } }); timer.start(); return () => { timer.clear(); }; }, []); useEffect(() => { if (generating) { // new a bot message dispatch(newMessage({ type: 'bot', message: currentMessage })); } }, [generating]); // Add the received message to the chat UI as a bot message useEffect(() => { const lastIndex = messages?.length - 1; const lastMessage = messages[lastIndex]; if (currentMessage && lastMessage?.type === 'bot') { // update the last one bot message // messageHandlers.setItem(); dispatch(updateMessage({ index: lastIndex, newMessage: { type: 'bot', message: currentMessage } })); } timer.start(); }, [currentMessage]); useEffect(() => { if (messages.length > messageCount * 2) { dispatch(shiftMessage()); } timer.start(); }, [messages]); return ( {errorMessage && {errorMessage} } {generating &&
} {errorMessage &&
}
); }; export default chatPanel;