chatbot-template/components/messages.tsx
2024-12-05 15:29:33 +03:00

85 lines
2.1 KiB
TypeScript

import { ChatRequestOptions, Message } from 'ai';
import { PreviewMessage, ThinkingMessage } from './message';
import { useScrollToBottom } from './use-scroll-to-bottom';
import { Overview } from './overview';
import { UIBlock } from './block';
import { Dispatch, memo, SetStateAction } from 'react';
import { Vote } from '@/lib/db/schema';
interface MessagesProps {
chatId: string;
block: UIBlock;
setBlock: Dispatch<SetStateAction<UIBlock>>;
isLoading: boolean;
votes: Array<Vote> | undefined;
messages: Array<Message>;
setMessages: (
messages: Message[] | ((messages: Message[]) => Message[]),
) => void;
reload: (
chatRequestOptions?: ChatRequestOptions,
) => Promise<string | null | undefined>;
}
function PureMessages({
chatId,
block,
setBlock,
isLoading,
votes,
messages,
setMessages,
reload,
}: MessagesProps) {
const [messagesContainerRef, messagesEndRef] =
useScrollToBottom<HTMLDivElement>();
return (
<div
ref={messagesContainerRef}
className="flex flex-col min-w-0 gap-6 flex-1 overflow-y-scroll pt-4"
>
{messages.length === 0 && <Overview />}
{messages.map((message, index) => (
<PreviewMessage
key={message.id}
chatId={chatId}
message={message}
block={block}
setBlock={setBlock}
isLoading={isLoading && messages.length - 1 === index}
vote={
votes
? votes.find((vote) => vote.messageId === message.id)
: undefined
}
setMessages={setMessages}
reload={reload}
/>
))}
{isLoading &&
messages.length > 0 &&
messages[messages.length - 1].role === 'user' && <ThinkingMessage />}
<div
ref={messagesEndRef}
className="shrink-0 min-w-[24px] min-h-[24px]"
/>
</div>
);
}
function areEqual(prevProps: MessagesProps, nextProps: MessagesProps) {
if (
prevProps.block.status === 'streaming' &&
nextProps.block.status === 'streaming'
) {
return true;
}
return false;
}
export const Messages = memo(PureMessages, areEqual);