Skip to content

Commit

Permalink
⚡️ refactor: Optimize Rendering Performance for Icons, Conversations (#…
Browse files Browse the repository at this point in the history
…5234)

* refactor: HoverButtons and Fork components to use explicit props

* refactor: improve typing for Fork Component

* fix: memoize SpecIcon to avoid unnecessary re-renders

* feat: introduce URLIcon component and update SpecIcon for improved icon handling

* WIP: optimizing icons

* refactor: simplify modelLabel assignment in Message components

* refactor: memoize ConvoOptions component to optimize rendering performance
  • Loading branch information
danny-avila authored Jan 9, 2025
1 parent 687ab32 commit 0f95604
Show file tree
Hide file tree
Showing 19 changed files with 206 additions and 171 deletions.
6 changes: 6 additions & 0 deletions client/src/common/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,12 @@ export type TMessageProps = {
setSiblingIdx?: ((value: number) => void | React.Dispatch<React.SetStateAction<number>>) | null;
};

export type TMessageIcon = { endpoint?: string | null; isCreatedByUser?: boolean } & Pick<
t.TConversation,
'modelLabel'
> &
Pick<t.TMessage, 'model' | 'iconURL'>;

export type TInitialProps = {
text: string;
edit: boolean;
Expand Down
5 changes: 4 additions & 1 deletion client/src/components/Chat/Menus/Endpoints/UnknownIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { memo } from 'react';
import { EModelEndpoint, KnownEndpoints } from 'librechat-data-provider';
import { CustomMinimalIcon } from '~/components/svg';
import { IconContext } from '~/common';
Expand Down Expand Up @@ -53,7 +54,7 @@ const getKnownClass = ({
return cn(match, defaultClass);
};

export default function UnknownIcon({
function UnknownIcon({
className = '',
endpoint: _endpoint,
iconURL = '',
Expand Down Expand Up @@ -93,3 +94,5 @@ export default function UnknownIcon({
/>
);
}

export default memo(UnknownIcon);
27 changes: 8 additions & 19 deletions client/src/components/Chat/Menus/Models/SpecIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React from 'react';
import React, { memo } from 'react';
import type { TModelSpec, TEndpointsConfig } from 'librechat-data-provider';
import type { IconMapProps } from '~/common';
import { getModelSpecIconURL, getIconKey, getEndpointField } from '~/utils';
import { icons } from '~/components/Chat/Menus/Endpoints/Icons';
import { URLIcon } from '~/components/Endpoints/URLIcon';

interface SpecIconProps {
currentSpec: TModelSpec;
Expand All @@ -16,24 +17,12 @@ const SpecIcon: React.FC<SpecIconProps> = ({ currentSpec, endpointsConfig }) =>
const iconKey = getIconKey({ endpoint, endpointsConfig, endpointIconURL });
let Icon: (props: IconMapProps) => React.JSX.Element;

if (!iconURL?.includes('http')) {
if (!iconURL.includes('http')) {
Icon = icons[iconKey] ?? icons.unknown;
} else if (iconURL) {
return <URLIcon iconURL={iconURL} altName={currentSpec.name} />;
} else {
Icon = iconURL
? () => (
<div
className="icon-xl mr-1 shrink-0 overflow-hidden rounded-full "
style={{ width: '20', height: '20' }}
>
<img
src={iconURL}
alt={currentSpec.name}
style={{ width: '100%', height: '100%' }}
className="object-cover"
/>
</div>
)
: icons[endpoint ?? ''] ?? icons.unknown;
Icon = icons[endpoint ?? ''] ?? icons.unknown;
}

return (
Expand All @@ -42,9 +31,9 @@ const SpecIcon: React.FC<SpecIconProps> = ({ currentSpec, endpointsConfig }) =>
endpoint={endpoint}
context="menu-item"
iconURL={endpointIconURL}
className="icon-lg mr-1 shrink-0 dark:text-white"
className="icon-lg mr-1 shrink-0 text-text-primary"
/>
);
};

export default SpecIcon;
export default memo(SpecIcon);
10 changes: 7 additions & 3 deletions client/src/components/Chat/Messages/HoverButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,13 @@ export default function HoverButtons({
} = useGenerationsByLatest({
isEditing,
isSubmitting,
message,
error: message.error,
endpoint: endpoint ?? '',
latestMessage,
messageId: message.messageId,
searchResult: message.searchResult,
finish_reason: message.finish_reason,
isCreatedByUser: message.isCreatedByUser,
latestMessageId: latestMessage?.messageId,
});
if (!conversation) {
return null;
Expand Down Expand Up @@ -146,7 +150,7 @@ export default function HoverButtons({
messageId={message.messageId}
conversationId={conversation.conversationId}
forkingSupported={forkingSupported}
latestMessage={latestMessage}
latestMessageId={latestMessage?.messageId}
/>
{continueSupported === true ? (
<button
Expand Down
35 changes: 21 additions & 14 deletions client/src/components/Chat/Messages/MessageIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,38 @@
import React, { useMemo, memo } from 'react';
import { useGetEndpointsQuery } from 'librechat-data-provider/react-query';
import type { Assistant, Agent, TMessage } from 'librechat-data-provider';
import type { Assistant, Agent } from 'librechat-data-provider';
import type { TMessageIcon } from '~/common';
import { getEndpointField, getIconEndpoint, logger } from '~/utils';
import ConvoIconURL from '~/components/Endpoints/ConvoIconURL';
import { getEndpointField, getIconEndpoint } from '~/utils';
import Icon from '~/components/Endpoints/Icon';

const MessageIcon = memo(
(props: {
iconData?: TMessage & { modelLabel?: string };
({
iconData,
assistant,
agent,
}: {
iconData?: TMessageIcon;
assistant?: Assistant;
agent?: Agent;
}) => {
logger.log('icon_data', iconData, assistant, agent);
const { data: endpointsConfig } = useGetEndpointsQuery();
const { iconData, assistant, agent } = props;

const agentName = useMemo(() => agent?.name ?? '', [agent]);
const agentAvatar = useMemo(() => agent?.avatar?.filepath ?? '', [agent]);
const assistantName = useMemo(() => assistant?.name ?? '', [assistant]);
const assistantAvatar = useMemo(() => assistant?.metadata?.avatar ?? '', [assistant]);
const agentName = useMemo(() => props.agent?.name ?? '', [props.agent]);
const agentAvatar = useMemo(() => props.agent?.avatar?.filepath ?? '', [props.agent]);

let avatarURL = '';

if (assistant) {
avatarURL = assistantAvatar;
} else if (agent) {
avatarURL = agentAvatar;
}
const avatarURL = useMemo(() => {
let result = '';
if (assistant) {
result = assistantAvatar;
} else if (agent) {
result = agentAvatar;
}
return result;
}, [assistant, agent, assistantAvatar, agentAvatar]);

const iconURL = iconData?.iconURL;
const endpoint = useMemo(
Expand Down
46 changes: 23 additions & 23 deletions client/src/components/Chat/Messages/MessageParts.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useMemo } from 'react';
import { useRecoilValue } from 'recoil';
import type { TMessage, TMessageContentParts } from 'librechat-data-provider';
import type { TMessageProps } from '~/common';
import type { TMessageContentParts } from 'librechat-data-provider';
import type { TMessageProps, TMessageIcon } from '~/common';
import MessageIcon from '~/components/Chat/Messages/MessageIcon';
import { useMessageHelpers, useLocalize } from '~/hooks';
import ContentParts from './Content/ContentParts';
Expand Down Expand Up @@ -35,19 +35,29 @@ export default function Message(props: TMessageProps) {
} = useMessageHelpers(props);
const fontSize = useRecoilValue(store.fontSize);
const { children, messageId = null, isCreatedByUser } = message ?? {};
const name = useMemo(() => {
let result = '';
if (isCreatedByUser === true) {
result = localize('com_user_message');
} else if (assistant) {
result = assistant.name ?? localize('com_ui_assistant');
} else if (agent) {
result = agent.name ?? localize('com_ui_agent');
}

const iconData = useMemo(
() =>
({
endpoint: message?.endpoint ?? conversation?.endpoint,
model: message?.model ?? conversation?.model,
iconURL: message?.iconURL ?? conversation?.iconURL,
modelLabel: conversation?.chatGptLabel ?? conversation?.modelLabel,
isCreatedByUser: message?.isCreatedByUser,
} as TMessage & { modelLabel?: string }),
return result;
}, [assistant, agent, isCreatedByUser, localize]);

const iconData: TMessageIcon = useMemo(
() => ({
endpoint: message?.endpoint ?? conversation?.endpoint,
model: message?.model ?? conversation?.model,
iconURL: message?.iconURL ?? conversation?.iconURL,
modelLabel: name,
isCreatedByUser: message?.isCreatedByUser,
}),
[
conversation?.chatGptLabel,
conversation?.modelLabel,
name,
conversation?.endpoint,
conversation?.iconURL,
conversation?.model,
Expand All @@ -61,16 +71,6 @@ export default function Message(props: TMessageProps) {
return null;
}

let name = '';

if (isCreatedByUser === true) {
name = localize('com_user_message');
} else if (assistant) {
name = assistant.name ?? localize('com_ui_assistant');
} else if (agent) {
name = agent.name ?? localize('com_ui_agent');
}

return (
<>
<div
Expand Down
18 changes: 8 additions & 10 deletions client/src/components/Chat/Messages/SearchMessage.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { useMemo } from 'react';
import { useRecoilValue } from 'recoil';
import { useAuthContext, useLocalize } from '~/hooks';
import type { TMessage } from 'librechat-data-provider';
import type { TMessageProps } from '~/common';
import type { TMessageProps, TMessageIcon } from '~/common';
import MinimalHoverButtons from '~/components/Chat/Messages/MinimalHoverButtons';
import Icon from '~/components/Chat/Messages/MessageIcon';
import SearchContent from './Content/SearchContent';
Expand All @@ -17,14 +16,13 @@ export default function Message({ message }: Pick<TMessageProps, 'message'>) {
const { user } = useAuthContext();
const localize = useLocalize();

const iconData = useMemo(
() =>
({
endpoint: message?.endpoint,
model: message?.model,
iconURL: message?.iconURL ?? '',
isCreatedByUser: message?.isCreatedByUser,
} as TMessage & { modelLabel?: string }),
const iconData: TMessageIcon = useMemo(
() => ({
endpoint: message?.endpoint,
model: message?.model,
iconURL: message?.iconURL ?? '',
isCreatedByUser: message?.isCreatedByUser,
}),
[message?.model, message?.iconURL, message?.endpoint, message?.isCreatedByUser],
);

Expand Down
22 changes: 10 additions & 12 deletions client/src/components/Chat/Messages/ui/MessageRender.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useRecoilValue } from 'recoil';
import { useCallback, useMemo, memo } from 'react';
import type { TMessage } from 'librechat-data-provider';
import type { TMessageProps } from '~/common';
import type { TMessageProps, TMessageIcon } 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';
Expand Down Expand Up @@ -66,18 +66,16 @@ const MessageRender = memo(
[hasNoChildren, msg?.depth, latestMessage?.depth],
);

const iconData = useMemo(
() =>
({
endpoint: msg?.endpoint ?? conversation?.endpoint,
model: msg?.model ?? conversation?.model,
iconURL: msg?.iconURL ?? conversation?.iconURL,
modelLabel: conversation?.chatGptLabel ?? conversation?.modelLabel,
isCreatedByUser: msg?.isCreatedByUser,
} as TMessage & { modelLabel?: string }),
const iconData: TMessageIcon = useMemo(
() => ({
endpoint: msg?.endpoint ?? conversation?.endpoint,
model: msg?.model ?? conversation?.model,
iconURL: msg?.iconURL ?? conversation?.iconURL,
modelLabel: messageLabel,
isCreatedByUser: msg?.isCreatedByUser,
}),
[
conversation?.chatGptLabel,
conversation?.modelLabel,
messageLabel,
conversation?.endpoint,
conversation?.iconURL,
conversation?.model,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useState, useId, useRef } from 'react';
import { useState, useId, useRef, memo } from 'react';
import * as Menu from '@ariakit/react/menu';
import { Ellipsis, Share2, Copy, Archive, Pen, Trash } from 'lucide-react';
import { useGetStartupConfig } from 'librechat-data-provider/react-query';
Expand All @@ -12,7 +12,7 @@ import DeleteButton from './DeleteButton';
import ShareButton from './ShareButton';
import { cn } from '~/utils';

export default function ConvoOptions({
function ConvoOptions({
conversationId,
title,
retainView,
Expand Down Expand Up @@ -161,3 +161,5 @@ export default function ConvoOptions({
</>
);
}

export default memo(ConvoOptions);
Loading

0 comments on commit 0f95604

Please sign in to comment.