mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-01-07 11:08:52 +01:00
📜 refactor: Optimize Longer Message Thread Performance (#3610)
This commit is contained in:
parent
cf69b7ef85
commit
02847af580
8 changed files with 59 additions and 280 deletions
|
|
@ -6,14 +6,13 @@ import supersub from 'remark-supersub';
|
|||
import rehypeKatex from 'rehype-katex';
|
||||
import { useRecoilValue } from 'recoil';
|
||||
import ReactMarkdown from 'react-markdown';
|
||||
import rehypeHighlight from 'rehype-highlight';
|
||||
import type { TMessage } from 'librechat-data-provider';
|
||||
import type { PluggableList } from 'unified';
|
||||
import rehypeHighlight from 'rehype-highlight';
|
||||
import { cn, langSubset, validateIframe, processLaTeX } from '~/utils';
|
||||
import CodeBlock from '~/components/Messages/Content/CodeBlock';
|
||||
import { useChatContext, useToastContext } from '~/Providers';
|
||||
import { useFileDownload } from '~/data-provider';
|
||||
import useLocalize from '~/hooks/useLocalize';
|
||||
import { useToastContext } from '~/Providers';
|
||||
import store from '~/store';
|
||||
|
||||
type TCodeProps = {
|
||||
|
|
@ -22,20 +21,14 @@ type TCodeProps = {
|
|||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
type TContentProps = {
|
||||
content: string;
|
||||
message: TMessage;
|
||||
showCursor?: boolean;
|
||||
};
|
||||
|
||||
export const code = memo(({ inline, className, children }: TCodeProps) => {
|
||||
const match = /language-(\w+)/.exec(className || '');
|
||||
const match = /language-(\w+)/.exec(className ?? '');
|
||||
const lang = match && match[1];
|
||||
|
||||
if (inline) {
|
||||
return <code className={className}>{children}</code>;
|
||||
} else {
|
||||
return <CodeBlock lang={lang || 'text'} codeChildren={children} />;
|
||||
return <CodeBlock lang={lang ?? 'text'} codeChildren={children} />;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -110,18 +103,22 @@ export const p = memo(({ children }: { children: React.ReactNode }) => {
|
|||
});
|
||||
|
||||
const cursor = ' ';
|
||||
const Markdown = memo(({ content, message, showCursor }: TContentProps) => {
|
||||
const { isSubmitting, latestMessage } = useChatContext();
|
||||
|
||||
type TContentProps = {
|
||||
content: string;
|
||||
isEdited?: boolean;
|
||||
showCursor?: boolean;
|
||||
isLatestMessage: boolean;
|
||||
};
|
||||
|
||||
const Markdown = memo(({ content = '', isEdited, showCursor, isLatestMessage }: TContentProps) => {
|
||||
const LaTeXParsing = useRecoilValue<boolean>(store.LaTeXParsing);
|
||||
|
||||
const isInitializing = content === '';
|
||||
|
||||
const { isEdited, messageId } = message ?? {};
|
||||
const isLatestMessage = messageId === latestMessage?.messageId;
|
||||
|
||||
let currentContent = content;
|
||||
if (!isInitializing) {
|
||||
currentContent = currentContent?.replace('z-index: 1;', '') ?? '';
|
||||
currentContent = currentContent.replace('z-index: 1;', '') || '';
|
||||
currentContent = LaTeXParsing ? processLaTeX(currentContent) : currentContent;
|
||||
}
|
||||
|
||||
|
|
@ -143,18 +140,18 @@ const Markdown = memo(({ content, message, showCursor }: TContentProps) => {
|
|||
return (
|
||||
<div className="absolute">
|
||||
<p className="relative">
|
||||
<span className={cn(isSubmitting ? 'result-thinking' : '')} />
|
||||
<span className={cn(showCursor === true ? 'result-thinking' : '')} />
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
let isValidIframe: string | boolean | null = false;
|
||||
if (!isEdited) {
|
||||
if (isEdited !== true) {
|
||||
isValidIframe = validateIframe(currentContent);
|
||||
}
|
||||
|
||||
if (isEdited || ((!isInitializing || !isLatestMessage) && !isValidIframe)) {
|
||||
if (isEdited === true || (!isLatestMessage && !isValidIframe)) {
|
||||
rehypePlugins.pop();
|
||||
}
|
||||
|
||||
|
|
@ -173,9 +170,7 @@ const Markdown = memo(({ content, message, showCursor }: TContentProps) => {
|
|||
}
|
||||
}
|
||||
>
|
||||
{isLatestMessage && isSubmitting && !isInitializing && showCursor
|
||||
? currentContent + cursor
|
||||
: currentContent}
|
||||
{isLatestMessage && showCursor === true ? currentContent + cursor : currentContent}
|
||||
</ReactMarkdown>
|
||||
);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import { Fragment, Suspense } from 'react';
|
||||
import { Fragment, Suspense, useMemo } from 'react';
|
||||
import type { TMessage, TResPlugin } from 'librechat-data-provider';
|
||||
import type { TMessageContentProps, TDisplayProps } from '~/common';
|
||||
import Plugin from '~/components/Messages/Content/Plugin';
|
||||
import Error from '~/components/Messages/Content/Error';
|
||||
import { DelayedRender } from '~/components/ui';
|
||||
import { useChatContext } from '~/Providers';
|
||||
import EditMessage from './EditMessage';
|
||||
import { useLocalize } from '~/hooks';
|
||||
import Container from './Container';
|
||||
|
|
@ -63,17 +64,31 @@ export const ErrorMessage = ({
|
|||
|
||||
// Display Message Component
|
||||
const DisplayMessage = ({ text, isCreatedByUser, message, showCursor }: TDisplayProps) => {
|
||||
const { isSubmitting, latestMessage } = useChatContext();
|
||||
const showCursorState = useMemo(
|
||||
() => showCursor === true && isSubmitting,
|
||||
[showCursor, isSubmitting],
|
||||
);
|
||||
const isLatestMessage = useMemo(
|
||||
() => message.messageId === latestMessage?.messageId,
|
||||
[message.messageId, latestMessage?.messageId],
|
||||
);
|
||||
return (
|
||||
<Container message={message}>
|
||||
<div
|
||||
className={cn(
|
||||
showCursor && !!text.length ? 'result-streaming' : '',
|
||||
showCursorState && !!text.length ? 'result-streaming' : '',
|
||||
'markdown prose message-content dark:prose-invert light w-full break-words',
|
||||
isCreatedByUser ? 'whitespace-pre-wrap dark:text-gray-20' : 'dark:text-gray-100',
|
||||
)}
|
||||
>
|
||||
{!isCreatedByUser ? (
|
||||
<Markdown content={text} message={message} showCursor={showCursor} />
|
||||
<Markdown
|
||||
content={text}
|
||||
isEdited={message.isEdited}
|
||||
showCursor={showCursorState}
|
||||
isLatestMessage={isLatestMessage}
|
||||
/>
|
||||
) : (
|
||||
<>{text}</>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -4,9 +4,11 @@ import {
|
|||
imageGenTools,
|
||||
isImageVisionTool,
|
||||
} from 'librechat-data-provider';
|
||||
import { useMemo } from 'react';
|
||||
import type { TMessageContentParts, TMessage } from 'librechat-data-provider';
|
||||
import type { TDisplayProps } from '~/common';
|
||||
import { ErrorMessage } from './MessageContent';
|
||||
import { useChatContext } from '~/Providers';
|
||||
import RetrievalCall from './RetrievalCall';
|
||||
import CodeAnalyze from './CodeAnalyze';
|
||||
import Container from './Container';
|
||||
|
|
@ -20,16 +22,30 @@ import { cn } from '~/utils';
|
|||
|
||||
// Display Message Component
|
||||
const DisplayMessage = ({ text, isCreatedByUser = false, message, showCursor }: TDisplayProps) => {
|
||||
const { isSubmitting, latestMessage } = useChatContext();
|
||||
const showCursorState = useMemo(
|
||||
() => showCursor === true && isSubmitting,
|
||||
[showCursor, isSubmitting],
|
||||
);
|
||||
const isLatestMessage = useMemo(
|
||||
() => message.messageId === latestMessage?.messageId,
|
||||
[message.messageId, latestMessage?.messageId],
|
||||
);
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
showCursor && !!text.length ? 'result-streaming' : '',
|
||||
showCursorState && !!text.length ? 'result-streaming' : '',
|
||||
'markdown prose message-content dark:prose-invert light w-full break-words',
|
||||
isCreatedByUser ? 'whitespace-pre-wrap dark:text-gray-20' : 'dark:text-gray-70',
|
||||
)}
|
||||
>
|
||||
{!isCreatedByUser ? (
|
||||
<Markdown content={text} message={message} showCursor={showCursor} />
|
||||
<Markdown
|
||||
content={text}
|
||||
isEdited={message.isEdited}
|
||||
showCursor={showCursorState}
|
||||
isLatestMessage={isLatestMessage}
|
||||
/>
|
||||
) : (
|
||||
<>{text}</>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ const SearchContent = ({ message }: { message: TMessage }) => {
|
|||
)}
|
||||
dir="auto"
|
||||
>
|
||||
<MarkdownLite content={message.text ?? ''} />
|
||||
<MarkdownLite content={message.text || ''} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue