perf: improve modellist search bar responsiveness (and memorization) (#4221)
This commit is contained in:
parent
3dc4947e26
commit
b43ecb75f5
@ -16,11 +16,11 @@ import { useProvider } from '@renderer/hooks/useProvider'
|
||||
import { ModelCheckStatus } from '@renderer/services/HealthCheckService'
|
||||
import { useAppDispatch } from '@renderer/store'
|
||||
import { setModel } from '@renderer/store/assistants'
|
||||
import { Model, Provider } from '@renderer/types'
|
||||
import { Model } from '@renderer/types'
|
||||
import { maskApiKey } from '@renderer/utils/api'
|
||||
import { Avatar, Button, Card, Flex, Space, Tooltip, Typography } from 'antd'
|
||||
import { groupBy, sortBy, toPairs } from 'lodash'
|
||||
import React, { useCallback, useEffect, useState } from 'react'
|
||||
import React, { memo, useCallback, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
|
||||
@ -36,7 +36,7 @@ const STATUS_COLORS = {
|
||||
}
|
||||
|
||||
interface ModelListProps {
|
||||
provider: Provider
|
||||
providerId: string
|
||||
modelStatuses?: ModelStatus[]
|
||||
searchText?: string
|
||||
}
|
||||
@ -166,10 +166,9 @@ function useModelStatusRendering() {
|
||||
return { renderStatusIndicator, renderLatencyText }
|
||||
}
|
||||
|
||||
const ModelList: React.FC<ModelListProps> = ({ provider: _provider, modelStatuses = [], searchText = '' }) => {
|
||||
const ModelList: React.FC<ModelListProps> = ({ providerId, modelStatuses = [], searchText = '' }) => {
|
||||
const { t } = useTranslation()
|
||||
const { provider } = useProvider(_provider.id)
|
||||
const { updateProvider, models, removeModel } = useProvider(_provider.id)
|
||||
const { provider, updateProvider, models, removeModel } = useProvider(providerId)
|
||||
const { assistants } = useAssistants()
|
||||
const dispatch = useAppDispatch()
|
||||
const { defaultModel, setDefaultModel } = useDefaultModel()
|
||||
@ -180,33 +179,36 @@ const ModelList: React.FC<ModelListProps> = ({ provider: _provider, modelStatuse
|
||||
const modelsWebsite = providerConfig?.websites?.models
|
||||
|
||||
const [editingModel, setEditingModel] = useState<Model | null>(null)
|
||||
const [debouncedSearchText, setDebouncedSearchText] = useState(searchText)
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setTimeout(() => {
|
||||
setDebouncedSearchText(searchText)
|
||||
}, 50)
|
||||
|
||||
return () => clearTimeout(timer)
|
||||
}, [searchText])
|
||||
|
||||
const filteredModels = debouncedSearchText
|
||||
? models.filter((model) => model.name.toLowerCase().includes(debouncedSearchText.toLowerCase()))
|
||||
const modelGroups = useMemo(() => {
|
||||
const filteredModels = searchText
|
||||
? models.filter((model) => model.name.toLowerCase().includes(searchText.toLowerCase()))
|
||||
: models
|
||||
return groupBy(filteredModels, 'group')
|
||||
}, [searchText, models])
|
||||
|
||||
const modelGroups = groupBy(filteredModels, 'group')
|
||||
const sortedModelGroups = sortBy(toPairs(modelGroups), [0]).reduce((acc, [key, value]) => {
|
||||
const sortedModelGroups = useMemo(() => {
|
||||
return sortBy(toPairs(modelGroups), [0]).reduce((acc, [key, value]) => {
|
||||
acc[key] = value
|
||||
return acc
|
||||
}, {})
|
||||
}, [modelGroups])
|
||||
|
||||
const onManageModel = () => EditModelsPopup.show({ provider })
|
||||
const onAddModel = () => AddModelPopup.show({ title: t('settings.models.add.add_model'), provider })
|
||||
const onEditModel = (model: Model) => {
|
||||
const onManageModel = useCallback(() => {
|
||||
EditModelsPopup.show({ provider })
|
||||
}, [provider])
|
||||
|
||||
const onAddModel = useCallback(
|
||||
() => AddModelPopup.show({ title: t('settings.models.add.add_model'), provider }),
|
||||
[provider, t]
|
||||
)
|
||||
|
||||
const onEditModel = useCallback((model: Model) => {
|
||||
setEditingModel(model)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const onUpdateModel = (updatedModel: Model) => {
|
||||
const onUpdateModel = useCallback(
|
||||
(updatedModel: Model) => {
|
||||
const updatedModels = models.map((m) => {
|
||||
if (m.id === updatedModel.id) {
|
||||
return updatedModel
|
||||
@ -232,7 +234,9 @@ const ModelList: React.FC<ModelListProps> = ({ provider: _provider, modelStatuse
|
||||
if (defaultModel?.id === updatedModel.id && defaultModel?.provider === provider.id) {
|
||||
setDefaultModel(updatedModel)
|
||||
}
|
||||
}
|
||||
},
|
||||
[models, updateProvider, provider, assistants, defaultModel?.id, defaultModel?.provider, dispatch, setDefaultModel]
|
||||
)
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -396,4 +400,4 @@ const ModelLatencyText = styled(Typography.Text)`
|
||||
color: var(--color-text-secondary);
|
||||
`
|
||||
|
||||
export default ModelList
|
||||
export default memo(ModelList)
|
||||
|
||||
@ -16,7 +16,7 @@ import { providerCharge } from '@renderer/utils/oauth'
|
||||
import { Button, Divider, Flex, Input, Space, Switch, Tooltip } from 'antd'
|
||||
import Link from 'antd/es/typography/Link'
|
||||
import { debounce, isEmpty } from 'lodash'
|
||||
import { FC, useCallback, useEffect, useState } from 'react'
|
||||
import { FC, useCallback, useDeferredValue, useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
|
||||
@ -51,7 +51,8 @@ const ProviderSetting: FC<Props> = ({ provider: _provider }) => {
|
||||
const [apiVersion, setApiVersion] = useState(provider.apiVersion)
|
||||
const [apiValid, setApiValid] = useState(false)
|
||||
const [apiChecking, setApiChecking] = useState(false)
|
||||
const [searchText, setSearchText] = useState('')
|
||||
const [modelSearchText, setModelSearchText] = useState('')
|
||||
const deferredModelSearchText = useDeferredValue(modelSearchText)
|
||||
const { updateProvider, models } = useProvider(provider.id)
|
||||
const { t } = useTranslation()
|
||||
const { theme } = useTheme()
|
||||
@ -387,7 +388,7 @@ const ProviderSetting: FC<Props> = ({ provider: _provider }) => {
|
||||
<Space align="center" style={{ width: '100%', justifyContent: 'space-between' }}>
|
||||
<Space>
|
||||
<span>{t('common.models')}</span>
|
||||
{!isEmpty(models) && <ModelListSearchBar onSearch={setSearchText} />}
|
||||
{!isEmpty(models) && <ModelListSearchBar onSearch={setModelSearchText} />}
|
||||
</Space>
|
||||
{!isEmpty(models) && (
|
||||
<Tooltip title={t('settings.models.check.button_caption')} mouseEnterDelay={0.5}>
|
||||
@ -402,7 +403,7 @@ const ProviderSetting: FC<Props> = ({ provider: _provider }) => {
|
||||
)}
|
||||
</Space>
|
||||
</SettingSubtitle>
|
||||
<ModelList provider={provider} modelStatuses={modelStatuses} searchText={searchText} />
|
||||
<ModelList providerId={provider.id} modelStatuses={modelStatuses} searchText={deferredModelSearchText} />
|
||||
</SettingContainer>
|
||||
)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user