'use client' import React from 'react' import { useChat } from 'ai/react' import { cn, nanoid, truncateText } from '@/lib/utils' import { ChatList } from '@/components/chat-list' import { ChatPanel } from '@/components/chat-panel' import { EmptyScreen } from '@/components/empty-screen' import { ChatScrollAnchor } from '@/components/chat-scroll-anchor' import { toast } from 'react-hot-toast' import { usePatchFetch } from '@/lib/hooks/use-patch-fetch' import { addChat, updateMessages } from '@/lib/stores/chat-actions' import { find, findIndex } from 'lodash-es' import { useStore } from '@/lib/hooks/use-store' import { useChatStore } from '@/lib/stores/chat-store' import { ListSkeleton } from '@/components/skeleton' import type { MessageActionType } from '@/lib/types' import type { Message } from 'ai/react' export interface ChatProps extends React.ComponentProps<'div'> { initialMessages?: Message[] id?: string loading?: boolean } export function Chat({ id, initialMessages, loading, className }: ChatProps) { usePatchFetch() const chats = useStore(useChatStore, state => state.chats) const { messages, append, reload, stop, isLoading, input, setInput, setMessages } = useChat({ initialMessages, id, body: { id }, onResponse(response) { if (response.status === 401) { toast.error(response.statusText) } } }) const [selectedMessageId, setSelectedMessageId] = React.useState() const onRegenerateResponse = (messageId: string) => { const messageIndex = findIndex(messages, { id: messageId }) const prevMessage = messages?.[messageIndex - 1] if (prevMessage?.role === 'user') { setMessages(messages.slice(0, messageIndex - 1)) append(prevMessage) } } const onDeleteMessage = (messageId: string) => { const message = find(messages, { id: messageId }) if (message) { setMessages(messages.filter(m => m.id !== messageId)) } } const onEditMessage = (messageId: string) => { const message = find(messages, { id: messageId }) if (message) { setInput(message.content) setSelectedMessageId(messageId) } } const handleMessageAction = ( messageId: string, actionType: MessageActionType ) => { switch (actionType) { case 'edit': onEditMessage(messageId) break case 'delete': onDeleteMessage(messageId) break case 'regenerate': onRegenerateResponse(messageId) break default: break } } const handleSubmit = async (value: string) => { if (findIndex(chats, { id }) === -1) { addChat(id, truncateText(value)) } else if (selectedMessageId) { let messageIdx = findIndex(messages, { id: selectedMessageId }) setMessages(messages.slice(0, messageIdx)) setSelectedMessageId(undefined) } await append({ id: nanoid(), content: value, role: 'user' }) } React.useEffect(() => { if (id) { updateMessages(id, messages) } }, [messages]) React.useEffect(() => { const scrollHeight = document.documentElement.scrollHeight window.scrollTo(0, scrollHeight) return () => stop() }, []) return (
{loading ? (
) : messages.length ? ( <> ) : ( )}
) }