From 83cea0750dcae81fd7d5749c2ba336b1f1e2eda1 Mon Sep 17 00:00:00 2001 From: one Date: Thu, 8 May 2025 23:20:29 +0800 Subject: [PATCH] refactor(ModelList): improve model list style and grouping (#5674) * refactor(ModelList): make the group removing button consistent with model removing button * refactor(ModelList): improve auto-grouping, reduce the number of groups * refactor(EditModelsPopup): extract model group tools * refactor(naming): add special grouping rules for some providers * feat(ModelList): add a button to add/remove all the listed models * refactor(naming): update auto grouping * refactor: update auto grouping for dmxapi * revert: remove ungrouped --- src/renderer/src/i18n/locales/en-us.json | 2 + src/renderer/src/i18n/locales/ja-jp.json | 2 + src/renderer/src/i18n/locales/ru-ru.json | 2 + src/renderer/src/i18n/locales/zh-cn.json | 2 + src/renderer/src/i18n/locales/zh-tw.json | 2 + .../ProviderSettings/AddModelPopup.tsx | 2 +- .../ProviderSettings/EditModelsPopup.tsx | 166 ++++++++++------- .../settings/ProviderSettings/ModelList.tsx | 174 +++++++++--------- .../src/utils/__tests__/naming.test.ts | 37 +++- src/renderer/src/utils/naming.ts | 45 +++-- 10 files changed, 267 insertions(+), 167 deletions(-) diff --git a/src/renderer/src/i18n/locales/en-us.json b/src/renderer/src/i18n/locales/en-us.json index 5d51d0d83c..298e65b2fc 100644 --- a/src/renderer/src/i18n/locales/en-us.json +++ b/src/renderer/src/i18n/locales/en-us.json @@ -1389,6 +1389,8 @@ "models.default_assistant_model_description": "Model used when creating a new assistant, if the assistant is not set, this model will be used", "models.empty": "No models found", "models.enable_topic_naming": "Topic Auto Naming", + "models.manage.add_listed": "Add models to the list", + "models.manage.remove_listed": "Remove models from the list", "models.manage.add_whole_group": "Add the whole group", "models.manage.remove_whole_group": "Remove the whole group", "models.topic_naming_model": "Topic Naming Model", diff --git a/src/renderer/src/i18n/locales/ja-jp.json b/src/renderer/src/i18n/locales/ja-jp.json index 93c1ac3c45..a881ba0f0b 100644 --- a/src/renderer/src/i18n/locales/ja-jp.json +++ b/src/renderer/src/i18n/locales/ja-jp.json @@ -1387,6 +1387,8 @@ "models.default_assistant_model_description": "新しいアシスタントを作成する際に使用されるモデル。アシスタントがモデルを設定していない場合、このモデルが使用されます", "models.empty": "モデルが見つかりません", "models.enable_topic_naming": "トピックの自動命名", + "models.manage.add_listed": "リストにモデルを追加", + "models.manage.remove_listed": "リストからモデルを削除", "models.manage.add_whole_group": "グループ全体を追加", "models.manage.remove_whole_group": "グループ全体を削除", "models.topic_naming_model": "トピック命名モデル", diff --git a/src/renderer/src/i18n/locales/ru-ru.json b/src/renderer/src/i18n/locales/ru-ru.json index 1fd1a31ed6..b9244b6de3 100644 --- a/src/renderer/src/i18n/locales/ru-ru.json +++ b/src/renderer/src/i18n/locales/ru-ru.json @@ -1387,6 +1387,8 @@ "models.default_assistant_model_description": "Модель, используемая при создании нового ассистента, если ассистент не имеет настроенной модели, будет использоваться эта модель", "models.empty": "Модели не найдены", "models.enable_topic_naming": "Автоматическое переименование топика", + "models.manage.add_listed": "Добавить в список", + "models.manage.remove_listed": "Удалить из списка", "models.manage.add_whole_group": "Добавить всю группу", "models.manage.remove_whole_group": "Удалить всю группу", "models.topic_naming_model": "Модель именования топика", diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json index 4e73f16411..950c1d5145 100644 --- a/src/renderer/src/i18n/locales/zh-cn.json +++ b/src/renderer/src/i18n/locales/zh-cn.json @@ -1389,6 +1389,8 @@ "models.default_assistant_model_description": "创建新助手时使用的模型,如果助手未设置模型,则使用此模型", "models.empty": "没有模型", "models.enable_topic_naming": "话题自动重命名", + "models.manage.add_listed": "添加列表中的模型", + "models.manage.remove_listed": "移除列表中的模型", "models.manage.add_whole_group": "添加整个分组", "models.manage.remove_whole_group": "移除整个分组", "models.topic_naming_model": "话题命名模型", diff --git a/src/renderer/src/i18n/locales/zh-tw.json b/src/renderer/src/i18n/locales/zh-tw.json index 440953a5a7..6d782435f6 100644 --- a/src/renderer/src/i18n/locales/zh-tw.json +++ b/src/renderer/src/i18n/locales/zh-tw.json @@ -1388,6 +1388,8 @@ "models.default_assistant_model_description": "建立新助手時使用的模型,如果助手未設定模型,則使用此模型", "models.empty": "找不到模型", "models.enable_topic_naming": "話題自動重新命名", + "models.manage.add_listed": "添加列表中的模型", + "models.manage.remove_listed": "移除列表中的模型", "models.manage.add_whole_group": "新增整個分組", "models.manage.remove_whole_group": "移除整個分組", "models.topic_naming_model": "話題命名模型", diff --git a/src/renderer/src/pages/settings/ProviderSettings/AddModelPopup.tsx b/src/renderer/src/pages/settings/ProviderSettings/AddModelPopup.tsx index 6b45ac78f9..7f9a2d7b29 100644 --- a/src/renderer/src/pages/settings/ProviderSettings/AddModelPopup.tsx +++ b/src/renderer/src/pages/settings/ProviderSettings/AddModelPopup.tsx @@ -104,7 +104,7 @@ const PopupContainer: React.FC = ({ title, provider, resolve }) => { maxLength={200} onChange={(e) => { form.setFieldValue('name', e.target.value) - form.setFieldValue('group', getDefaultGroupName(e.target.value)) + form.setFieldValue('group', getDefaultGroupName(e.target.value, provider.id)) }} /> diff --git a/src/renderer/src/pages/settings/ProviderSettings/EditModelsPopup.tsx b/src/renderer/src/pages/settings/ProviderSettings/EditModelsPopup.tsx index c7c1815dfb..b2af375c8d 100644 --- a/src/renderer/src/pages/settings/ProviderSettings/EditModelsPopup.tsx +++ b/src/renderer/src/pages/settings/ProviderSettings/EditModelsPopup.tsx @@ -22,7 +22,7 @@ import { Avatar, Button, Empty, Flex, Modal, Tabs, Tooltip, Typography } from 'a import Input from 'antd/es/input/Input' import { groupBy, isEmpty, uniqBy } from 'lodash' import { Search } from 'lucide-react' -import { useEffect, useRef, useState } from 'react' +import { useCallback, useEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import styled from 'styled-components' @@ -83,39 +83,36 @@ const PopupContainer: React.FC = ({ provider: _provider, resolve }) => { } }) - const modelGroups = - provider.id === 'dashscope' - ? { - ...groupBy( - list.filter((model) => !model.id.startsWith('qwen')), - 'group' - ), - ...groupQwenModels(list.filter((model) => model.id.startsWith('qwen'))) - } - : groupBy(list, 'group') + const modelGroups = useMemo( + () => + provider.id === 'dashscope' + ? { + ...groupBy( + list.filter((model) => !model.id.startsWith('qwen')), + 'group' + ), + ...groupQwenModels(list.filter((model) => model.id.startsWith('qwen'))) + } + : groupBy(list, 'group'), + [list, provider.id] + ) - const onOk = () => { - setOpen(false) - } + const onOk = useCallback(() => setOpen(false), []) - const onCancel = () => { - setOpen(false) - } + const onCancel = useCallback(() => setOpen(false), []) - const onClose = () => { - resolve({}) - } + const onClose = useCallback(() => resolve({}), [resolve]) - const onAddModel = (model: Model) => { - if (isEmpty(model.name)) { - return - } - addModel(model) - } + const onAddModel = useCallback( + (model: Model) => { + if (!isEmpty(model.name)) { + addModel(model) + } + }, + [addModel] + ) - const onRemoveModel = (model: Model) => { - removeModel(model) - } + const onRemoveModel = useCallback((model: Model) => removeModel(model), [removeModel]) useEffect(() => { runAsyncFunction(async () => { @@ -129,7 +126,7 @@ const PopupContainer: React.FC = ({ provider: _provider, resolve }) => { // @ts-ignore name name: model.name || model.id, provider: _provider.id, - group: getDefaultGroupName(model.id), + group: getDefaultGroupName(model.id, _provider.id), // @ts-ignore name description: model?.description, owned_by: model?.owned_by @@ -165,6 +162,63 @@ const PopupContainer: React.FC = ({ provider: _provider, resolve }) => { ) } + const renderTopTools = useCallback(() => { + const isAllFilteredInProvider = list.length > 0 && list.every((model) => isModelInProvider(provider, model.id)) + return ( + +