From e2b13ade95dae57cbc7563ca1e6c95b8ec631218 Mon Sep 17 00:00:00 2001 From: one Date: Fri, 1 Aug 2025 14:57:27 +0800 Subject: [PATCH] perf: improve model list loading (#8751) * refactor(ModelList): use spin as a wrapper * perf: improve SvgSpinners180Ring --- .../components/Icons/SvgSpinners180Ring.tsx | 47 +++++--- .../src/components/ModelList/ModelList.tsx | 106 ++++++++++-------- 2 files changed, 91 insertions(+), 62 deletions(-) diff --git a/src/renderer/src/components/Icons/SvgSpinners180Ring.tsx b/src/renderer/src/components/Icons/SvgSpinners180Ring.tsx index 9e39d6a770..11a25a48e6 100644 --- a/src/renderer/src/components/Icons/SvgSpinners180Ring.tsx +++ b/src/renderer/src/components/Icons/SvgSpinners180Ring.tsx @@ -1,20 +1,41 @@ import { SVGProps } from 'react' export function SvgSpinners180Ring(props: SVGProps) { + // 避免与全局样式冲突 + const animationClassName = 'svg-spinner-anim-180-ring' + return ( - - {/* Icon from SVG Spinners by Utkarsh Verma - https://github.com/n3r4zzurr0/svg-spinners/blob/main/LICENSE */} - - - - + <> + {/* CSS transform 硬件加速 */} + + + {/* Icon from SVG Spinners by Utkarsh Verma - https://github.com/n3r4zzurr0/svg-spinners/blob/main/LICENSE */} + + + ) } export default SvgSpinners180Ring diff --git a/src/renderer/src/components/ModelList/ModelList.tsx b/src/renderer/src/components/ModelList/ModelList.tsx index 8f105a88b7..b0ad8e3c99 100644 --- a/src/renderer/src/components/ModelList/ModelList.tsx +++ b/src/renderer/src/components/ModelList/ModelList.tsx @@ -16,8 +16,8 @@ import { useAppDispatch } from '@renderer/store' import { setModel } from '@renderer/store/assistants' import { Model } from '@renderer/types' import { filterModelsByKeywords } from '@renderer/utils' -import { Button, Flex, Spin, Tooltip } from 'antd' -import { groupBy, sortBy, toPairs } from 'lodash' +import { Button, Empty, Flex, Spin, Tooltip } from 'antd' +import { groupBy, isEmpty, sortBy, toPairs } from 'lodash' import { ListCheck, Plus } from 'lucide-react' import React, { memo, startTransition, useCallback, useEffect, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' @@ -134,6 +134,8 @@ const ModelList: React.FC = ({ providerId }) => { [provider, onUpdateModel] ) + const isLoading = useMemo(() => displayedModelGroups === null, [displayedModelGroups]) + return ( <> @@ -158,54 +160,60 @@ const ModelList: React.FC = ({ providerId }) => { - {displayedModelGroups === null ? ( - - } /> + }> + {displayedModelGroups && !isEmpty(displayedModelGroups) ? ( + + {Object.keys(displayedModelGroups).map((group, i) => ( + displayedModelGroups[group].forEach((model) => removeModel(model))} + /> + ))} + + ) : ( + + )} + + + {docsWebsite || modelsWebsite ? ( + + {t('settings.provider.docs_check')} + {docsWebsite && ( + + {getProviderLabel(provider.id) + ' '} + {t('common.docs')} + + )} + {docsWebsite && modelsWebsite && {t('common.and')}} + {modelsWebsite && ( + + {t('common.models')} + + )} + {t('settings.provider.docs_more_details')} + + ) : ( +
+ )} + + + - ) : ( - - {Object.keys(displayedModelGroups).map((group, i) => ( - displayedModelGroups[group].forEach((model) => removeModel(model))} - /> - ))} - {docsWebsite || modelsWebsite ? ( - - {t('settings.provider.docs_check')} - {docsWebsite && ( - - {getProviderLabel(provider.id) + ' '} - {t('common.docs')} - - )} - {docsWebsite && modelsWebsite && {t('common.and')}} - {modelsWebsite && ( - - {t('common.models')} - - )} - {t('settings.provider.docs_more_details')} - - ) : ( -
- )} - - )} - - - )