import { Fragment, Suspense } from 'react'; import type { TResPlugin, TFile } from 'librechat-data-provider'; import type { TMessageContentProps, TText, TDisplayProps } from '~/common'; import FileContainer from '~/components/Chat/Input/Files/FileContainer'; import Plugin from '~/components/Messages/Content/Plugin'; import Error from '~/components/Messages/Content/Error'; import { DelayedRender } from '~/components/ui'; import { useAuthContext } from '~/hooks'; import EditMessage from './EditMessage'; import Container from './Container'; import Markdown from './Markdown'; import { cn } from '~/utils'; import Image from './Image'; export const ErrorMessage = ({ text }: TText) => { const { logout } = useAuthContext(); if (text.includes('ban')) { logout(); return null; } return (
); }; // Display Message Component const DisplayMessage = ({ text, isCreatedByUser, message, showCursor }: TDisplayProps) => { const files: TFile[] = []; const imageFiles = message?.files ? message.files.filter((file) => { if (file.type && file.type.startsWith('image/')) { return true; } files.push(file); }) : null; return ( {files.length > 0 && files.map((file) => )} {imageFiles && imageFiles.map((file) => ( ))}
{!isCreatedByUser ? ( ) : ( <>{text} )}
); }; // Unfinished Message Component export const UnfinishedMessage = () => ( ); // Content Component const MessageContent = ({ text, edit, error, unfinished, isSubmitting, isLast, ...props }: TMessageContentProps) => { if (error) { return ; } else if (edit) { return ; } else { const marker = ':::plugin:::\n'; const splitText = text.split(marker); const { message } = props; const { plugins, messageId } = message; const displayedIndices = new Set(); // Function to get the next non-empty text index const getNextNonEmptyTextIndex = (currentIndex: number) => { for (let i = currentIndex + 1; i < splitText.length; i++) { // Allow the last index to be last in case it has text // this may need to change if I add back streaming if (i === splitText.length - 1) { return currentIndex; } if (splitText[i].trim() !== '' && !displayedIndices.has(i)) { return i; } } return currentIndex; // If no non-empty text is found, return the current index }; return splitText.map((text, idx) => { let currentText = text.trim(); let plugin: TResPlugin | null = null; if (plugins) { plugin = plugins[idx]; } // If the current text is empty, get the next non-empty text index const displayTextIndex = currentText === '' ? getNextNonEmptyTextIndex(idx) : idx; currentText = splitText[displayTextIndex]; const isLastIndex = displayTextIndex === splitText.length - 1; const isEmpty = currentText.trim() === ''; const showText = (currentText && !isEmpty && !displayedIndices.has(displayTextIndex)) || (isEmpty && isLastIndex); displayedIndices.add(displayTextIndex); return ( {plugin && } {showText ? ( ) : null} {!isSubmitting && unfinished && ( )} ); }); } }; export default MessageContent;