mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-20 10:20:15 +01:00
155 lines
5.2 KiB
TypeScript
155 lines
5.2 KiB
TypeScript
|
|
import React, { useCallback, useMemo } from 'react';
|
||
|
|
import { useMessageActions } from '~/hooks';
|
||
|
|
import type { TMessage } from 'librechat-data-provider';
|
||
|
|
import type { TMessageProps } from '~/common';
|
||
|
|
import MessageContent from '~/components/Chat/Messages/Content/MessageContent';
|
||
|
|
import PlaceholderRow from '~/components/Chat/Messages/ui/PlaceholderRow';
|
||
|
|
import SiblingSwitch from '~/components/Chat/Messages/SiblingSwitch';
|
||
|
|
import HoverButtons from '~/components/Chat/Messages/HoverButtons';
|
||
|
|
import Icon from '~/components/Chat/Messages/MessageIcon';
|
||
|
|
import { Plugin } from '~/components/Messages/Content';
|
||
|
|
import SubRow from '~/components/Chat/Messages/SubRow';
|
||
|
|
import { cn } from '~/utils';
|
||
|
|
|
||
|
|
type MessageRenderProps = {
|
||
|
|
message?: TMessage;
|
||
|
|
isCard?: boolean;
|
||
|
|
isMultiMessage?: boolean;
|
||
|
|
isSubmittingFamily?: boolean;
|
||
|
|
} & Pick<
|
||
|
|
TMessageProps,
|
||
|
|
'currentEditId' | 'setCurrentEditId' | 'siblingIdx' | 'setSiblingIdx' | 'siblingCount'
|
||
|
|
>;
|
||
|
|
|
||
|
|
const MessageRender = React.memo(
|
||
|
|
({
|
||
|
|
isCard,
|
||
|
|
siblingIdx,
|
||
|
|
siblingCount,
|
||
|
|
message: msg,
|
||
|
|
setSiblingIdx,
|
||
|
|
currentEditId,
|
||
|
|
isMultiMessage,
|
||
|
|
setCurrentEditId,
|
||
|
|
isSubmittingFamily,
|
||
|
|
}: MessageRenderProps) => {
|
||
|
|
const {
|
||
|
|
ask,
|
||
|
|
edit,
|
||
|
|
index,
|
||
|
|
assistant,
|
||
|
|
enterEdit,
|
||
|
|
conversation,
|
||
|
|
messageLabel,
|
||
|
|
isSubmitting,
|
||
|
|
latestMessage,
|
||
|
|
handleContinue,
|
||
|
|
copyToClipboard,
|
||
|
|
setLatestMessage,
|
||
|
|
regenerateMessage,
|
||
|
|
} = useMessageActions({
|
||
|
|
message: msg,
|
||
|
|
currentEditId,
|
||
|
|
isMultiMessage,
|
||
|
|
setCurrentEditId,
|
||
|
|
});
|
||
|
|
|
||
|
|
const handleRegenerateMessage = useCallback(() => regenerateMessage(), [regenerateMessage]);
|
||
|
|
const { isCreatedByUser, error, unfinished } = msg ?? {};
|
||
|
|
const isLast = useMemo(
|
||
|
|
() => !msg?.children?.length && (msg?.depth === latestMessage?.depth || msg?.depth === -1),
|
||
|
|
[msg?.children, msg?.depth, latestMessage?.depth],
|
||
|
|
);
|
||
|
|
|
||
|
|
if (!msg) {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
const isLatestCard =
|
||
|
|
isCard && !isSubmittingFamily && msg.messageId === latestMessage?.messageId;
|
||
|
|
const clickHandler =
|
||
|
|
isLast && isCard && !isSubmittingFamily && msg.messageId !== latestMessage?.messageId
|
||
|
|
? () => setLatestMessage(msg)
|
||
|
|
: undefined;
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div
|
||
|
|
className={cn(
|
||
|
|
'final-completion group mx-auto flex flex-1 gap-3 text-base',
|
||
|
|
isCard
|
||
|
|
? 'relative w-full gap-1 rounded-lg border border-border-medium bg-surface-primary-alt p-2 md:w-1/2 md:gap-3 md:p-4'
|
||
|
|
: 'md:max-w-3xl md:px-5 lg:max-w-[40rem] lg:px-1 xl:max-w-[48rem] xl:px-5',
|
||
|
|
isLatestCard ? 'bg-surface-secondary' : '',
|
||
|
|
isLast && !isSubmittingFamily && isCard
|
||
|
|
? 'cursor-pointer transition-colors duration-300'
|
||
|
|
: '',
|
||
|
|
)}
|
||
|
|
onClick={clickHandler}
|
||
|
|
>
|
||
|
|
{isLatestCard && (
|
||
|
|
<div className="absolute right-0 top-0 m-2 h-3 w-3 rounded-full bg-text-primary"></div>
|
||
|
|
)}
|
||
|
|
<div className="relative flex flex-shrink-0 flex-col items-end">
|
||
|
|
<div>
|
||
|
|
<div className="pt-0.5">
|
||
|
|
<div className="flex h-6 w-6 items-center justify-center overflow-hidden rounded-full">
|
||
|
|
<Icon message={msg} conversation={conversation} assistant={assistant} />
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
<div
|
||
|
|
className={cn('relative flex w-11/12 flex-col', msg?.isCreatedByUser ? '' : 'agent-turn')}
|
||
|
|
>
|
||
|
|
<div className="select-none font-semibold">{messageLabel}</div>
|
||
|
|
<div className="flex-col gap-1 md:gap-3">
|
||
|
|
<div className="flex max-w-full flex-grow flex-col gap-0">
|
||
|
|
{msg?.plugin && <Plugin plugin={msg?.plugin} />}
|
||
|
|
<MessageContent
|
||
|
|
ask={ask}
|
||
|
|
edit={edit}
|
||
|
|
isLast={isLast}
|
||
|
|
text={msg.text ?? ''}
|
||
|
|
message={msg}
|
||
|
|
enterEdit={enterEdit}
|
||
|
|
error={!!error}
|
||
|
|
isSubmitting={isSubmitting}
|
||
|
|
unfinished={unfinished ?? false}
|
||
|
|
isCreatedByUser={isCreatedByUser ?? true}
|
||
|
|
siblingIdx={siblingIdx ?? 0}
|
||
|
|
setSiblingIdx={setSiblingIdx ?? (() => ({}))}
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
{!msg?.children?.length && (isSubmittingFamily || isSubmitting) ? (
|
||
|
|
<PlaceholderRow isLast={isLast} isCard={isCard} />
|
||
|
|
) : (
|
||
|
|
<SubRow classes="text-xs">
|
||
|
|
<SiblingSwitch
|
||
|
|
siblingIdx={siblingIdx}
|
||
|
|
siblingCount={siblingCount}
|
||
|
|
setSiblingIdx={setSiblingIdx}
|
||
|
|
/>
|
||
|
|
<HoverButtons
|
||
|
|
index={index}
|
||
|
|
isEditing={edit}
|
||
|
|
message={msg}
|
||
|
|
enterEdit={enterEdit}
|
||
|
|
isSubmitting={isSubmitting}
|
||
|
|
conversation={conversation ?? null}
|
||
|
|
regenerate={handleRegenerateMessage}
|
||
|
|
copyToClipboard={copyToClipboard}
|
||
|
|
handleContinue={handleContinue}
|
||
|
|
latestMessage={latestMessage}
|
||
|
|
isLast={isLast}
|
||
|
|
/>
|
||
|
|
</SubRow>
|
||
|
|
)}
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
},
|
||
|
|
);
|
||
|
|
|
||
|
|
export default MessageRender;
|