Made optimization mode persist between page refreshes. Added mode switcher to chat so it can be changed while researching.
120 lines
3.2 KiB
TypeScript
120 lines
3.2 KiB
TypeScript
'use client';
|
|
|
|
import { Fragment, useEffect, useRef, useState } from 'react';
|
|
import MessageInput from './MessageInput';
|
|
import { File, Message } from './ChatWindow';
|
|
import MessageBox from './MessageBox';
|
|
import MessageBoxLoading from './MessageBoxLoading';
|
|
|
|
const Chat = ({
|
|
loading,
|
|
messages,
|
|
sendMessage,
|
|
messageAppeared,
|
|
rewrite,
|
|
fileIds,
|
|
setFileIds,
|
|
files,
|
|
setFiles,
|
|
isCompact,
|
|
setIsCompact,
|
|
optimizationMode,
|
|
setOptimizationMode,
|
|
}: {
|
|
messages: Message[];
|
|
sendMessage: (
|
|
message: string,
|
|
messageId?: string,
|
|
options?: { isCompact?: boolean },
|
|
) => void;
|
|
loading: boolean;
|
|
messageAppeared: boolean;
|
|
rewrite: (messageId: string) => void;
|
|
fileIds: string[];
|
|
setFileIds: (fileIds: string[]) => void;
|
|
files: File[];
|
|
setFiles: (files: File[]) => void;
|
|
isCompact: boolean;
|
|
setIsCompact: (isCompact: boolean) => void;
|
|
optimizationMode: string;
|
|
setOptimizationMode: (mode: string) => void;
|
|
}) => {
|
|
const [dividerWidth, setDividerWidth] = useState(0);
|
|
const dividerRef = useRef<HTMLDivElement | null>(null);
|
|
const messageEnd = useRef<HTMLDivElement | null>(null);
|
|
|
|
useEffect(() => {
|
|
const updateDividerWidth = () => {
|
|
if (dividerRef.current) {
|
|
setDividerWidth(dividerRef.current.scrollWidth);
|
|
}
|
|
};
|
|
|
|
updateDividerWidth();
|
|
|
|
window.addEventListener('resize', updateDividerWidth);
|
|
|
|
return () => {
|
|
window.removeEventListener('resize', updateDividerWidth);
|
|
};
|
|
});
|
|
|
|
useEffect(() => {
|
|
messageEnd.current?.scrollIntoView({ behavior: 'smooth' });
|
|
|
|
if (messages.length === 1) {
|
|
document.title = `${messages[0].content.substring(0, 30)} - Perplexica`;
|
|
}
|
|
}, [messages]);
|
|
|
|
return (
|
|
<div className="flex flex-col space-y-6 pt-8 pb-44 lg:pb-32 sm:mx-4 md:mx-8">
|
|
{messages.map((msg, i) => {
|
|
const isLast = i === messages.length - 1;
|
|
|
|
return (
|
|
<Fragment key={msg.messageId}>
|
|
<MessageBox
|
|
key={i}
|
|
message={msg}
|
|
messageIndex={i}
|
|
history={messages}
|
|
loading={loading}
|
|
dividerRef={isLast ? dividerRef : undefined}
|
|
isLast={isLast}
|
|
rewrite={rewrite}
|
|
isCompact={isCompact}
|
|
sendMessage={sendMessage}
|
|
/>
|
|
{!isLast && msg.role === 'assistant' && (
|
|
<div className="h-px w-full bg-light-secondary dark:bg-dark-secondary" />
|
|
)}
|
|
</Fragment>
|
|
);
|
|
})}
|
|
{loading && !messageAppeared && <MessageBoxLoading />}
|
|
<div ref={messageEnd} className="h-0" />
|
|
{dividerWidth > 0 && (
|
|
<div
|
|
className="bottom-24 lg:bottom-10 fixed"
|
|
style={{ width: dividerWidth }}
|
|
>
|
|
<MessageInput
|
|
loading={loading}
|
|
sendMessage={sendMessage}
|
|
fileIds={fileIds}
|
|
setFileIds={setFileIds}
|
|
files={files}
|
|
setFiles={setFiles}
|
|
isCompact={isCompact}
|
|
setIsCompact={setIsCompact}
|
|
optimizationMode={optimizationMode}
|
|
setOptimizationMode={setOptimizationMode}
|
|
/>
|
|
</div>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default Chat;
|