diff --git a/src/renderer/src/components/CustomCollapse.tsx b/src/renderer/src/components/CustomCollapse.tsx index d41a9ffd60..8362d8a479 100644 --- a/src/renderer/src/components/CustomCollapse.tsx +++ b/src/renderer/src/components/CustomCollapse.tsx @@ -78,7 +78,7 @@ const CustomCollapse: FC = ({ style={collapseStyle} defaultActiveKey={defaultActiveKey} activeKey={activeKey} - destroyInactivePanel={destroyInactivePanel} + destroyOnHidden={destroyInactivePanel} collapsible={collapsible} onChange={(keys) => { setActiveKeys(keys) diff --git a/src/renderer/src/components/ModelIdWithTags.tsx b/src/renderer/src/components/ModelIdWithTags.tsx index 4b8ca86123..bf902ae1c4 100644 --- a/src/renderer/src/components/ModelIdWithTags.tsx +++ b/src/renderer/src/components/ModelIdWithTags.tsx @@ -26,7 +26,7 @@ const ModelIdWithTags = ({ maxWidth: '500px' } }} - destroyTooltipOnHide + destroyOnHidden title={ {model.id} diff --git a/src/renderer/src/components/ModelTagsWithLabel.tsx b/src/renderer/src/components/ModelTagsWithLabel.tsx index 86a04dd454..3da6ccfc8d 100644 --- a/src/renderer/src/components/ModelTagsWithLabel.tsx +++ b/src/renderer/src/components/ModelTagsWithLabel.tsx @@ -1,4 +1,3 @@ -import { EyeOutlined, GlobalOutlined, ToolOutlined } from '@ant-design/icons' import { isEmbeddingModel, isFunctionCallingModel, @@ -14,7 +13,15 @@ import { FC, memo, useLayoutEffect, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' import styled from 'styled-components' -import CustomTag from './CustomTag' +import CustomTag from './Tags/CustomTag' +import { + EmbeddingTag, + ReasoningTag, + RerankerTag, + ToolsCallingTag, + VisionTag, + WebSearchTag +} from './Tags/ModelCapabilities' interface ModelTagsProps { model: Model @@ -70,45 +77,17 @@ const ModelTagsWithLabel: FC = ({ return ( - {isVisionModel(model) && ( - } - tooltip={showTooltip ? t('models.type.vision') : undefined}> - {shouldShowLabel ? t('models.type.vision') : ''} - - )} - {isWebSearchModel(model) && ( - } - tooltip={showTooltip ? t('models.type.websearch') : undefined}> - {shouldShowLabel ? t('models.type.websearch') : ''} - - )} + {isVisionModel(model) && } + {isWebSearchModel(model) && } {showReasoning && isReasoningModel(model) && ( - } - tooltip={showTooltip ? t('models.type.reasoning') : undefined}> - {shouldShowLabel ? t('models.type.reasoning') : ''} - + )} {showToolsCalling && isFunctionCallingModel(model) && ( - } - tooltip={showTooltip ? t('models.type.function_calling') : undefined}> - {shouldShowLabel ? t('models.type.function_calling') : ''} - + )} - {isEmbeddingModel(model) && } + {isEmbeddingModel(model) && } {showFree && isFreeModel(model) && } - {isRerankModel(model) && } + {isRerankModel(model) && } ) } diff --git a/src/renderer/src/components/Popups/SaveToKnowledgePopup.tsx b/src/renderer/src/components/Popups/SaveToKnowledgePopup.tsx index 3997135f72..1b92b97828 100644 --- a/src/renderer/src/components/Popups/SaveToKnowledgePopup.tsx +++ b/src/renderer/src/components/Popups/SaveToKnowledgePopup.tsx @@ -1,5 +1,5 @@ import { loggerService } from '@logger' -import CustomTag from '@renderer/components/CustomTag' +import CustomTag from '@renderer/components/Tags/CustomTag' import { TopView } from '@renderer/components/TopView' import { useKnowledge, useKnowledgeBases } from '@renderer/hooks/useKnowledge' import { Message } from '@renderer/types/newMessage' diff --git a/src/renderer/src/components/CustomTag.tsx b/src/renderer/src/components/Tags/CustomTag.tsx similarity index 64% rename from src/renderer/src/components/CustomTag.tsx rename to src/renderer/src/components/Tags/CustomTag.tsx index c875ba01a4..c7abd15a62 100644 --- a/src/renderer/src/components/CustomTag.tsx +++ b/src/renderer/src/components/Tags/CustomTag.tsx @@ -1,27 +1,58 @@ import { CloseOutlined } from '@ant-design/icons' import { Tooltip } from 'antd' -import { FC, memo, useMemo } from 'react' +import { CSSProperties, FC, memo, useMemo } from 'react' import styled from 'styled-components' -interface CustomTagProps { +export interface CustomTagProps { icon?: React.ReactNode children?: React.ReactNode | string color: string size?: number + style?: CSSProperties tooltip?: string closable?: boolean onClose?: () => void + onClick?: () => void + disabled?: boolean + inactive?: boolean } -const CustomTag: FC = ({ children, icon, color, size = 12, tooltip, closable = false, onClose }) => { +const CustomTag: FC = ({ + children, + icon, + color, + size = 12, + style, + tooltip, + closable = false, + onClose, + onClick, + disabled, + inactive +}) => { + const actualColor = inactive ? '#aaaaaa' : color const tagContent = useMemo( () => ( - + {icon && icon} {children} - {closable && } + {closable && ( + { + e.stopPropagation() + onClose?.() + }} + /> + )} ), - [children, closable, color, icon, onClose, size] + [actualColor, children, closable, disabled, icon, onClick, onClose, size, style] ) return tooltip ? ( diff --git a/src/renderer/src/components/Tags/ModelCapabilities/EmbeddingTag.tsx b/src/renderer/src/components/Tags/ModelCapabilities/EmbeddingTag.tsx new file mode 100644 index 0000000000..8a2e5e2a33 --- /dev/null +++ b/src/renderer/src/components/Tags/ModelCapabilities/EmbeddingTag.tsx @@ -0,0 +1,12 @@ +import { useTranslation } from 'react-i18next' + +import CustomTag, { CustomTagProps } from '../CustomTag' + +type Props = { + size?: number +} & Omit + +export const EmbeddingTag = ({ size, ...restProps }: Props) => { + const { t } = useTranslation() + return +} diff --git a/src/renderer/src/components/Tags/ModelCapabilities/ReasoningTag.tsx b/src/renderer/src/components/Tags/ModelCapabilities/ReasoningTag.tsx new file mode 100644 index 0000000000..8e6d94bea7 --- /dev/null +++ b/src/renderer/src/components/Tags/ModelCapabilities/ReasoningTag.tsx @@ -0,0 +1,23 @@ +import { useTranslation } from 'react-i18next' + +import CustomTag, { CustomTagProps } from '../CustomTag' + +type Props = { + size?: number + showTooltip?: boolean + showLabel?: boolean +} & Omit + +export const ReasoningTag = ({ size, showTooltip, showLabel, ...restProps }: Props) => { + const { t } = useTranslation() + return ( + } + tooltip={showTooltip ? t('models.type.reasoning') : undefined} + {...restProps}> + {showLabel ? t('models.type.reasoning') : ''} + + ) +} diff --git a/src/renderer/src/components/Tags/ModelCapabilities/RerankerTag.tsx b/src/renderer/src/components/Tags/ModelCapabilities/RerankerTag.tsx new file mode 100644 index 0000000000..6d6811f77f --- /dev/null +++ b/src/renderer/src/components/Tags/ModelCapabilities/RerankerTag.tsx @@ -0,0 +1,12 @@ +import { useTranslation } from 'react-i18next' + +import CustomTag, { CustomTagProps } from '../CustomTag' + +type Props = { + size?: number +} & Omit + +export const RerankerTag = ({ size, ...restProps }: Props) => { + const { t } = useTranslation() + return +} diff --git a/src/renderer/src/components/Tags/ModelCapabilities/ToolsCallingTag.tsx b/src/renderer/src/components/Tags/ModelCapabilities/ToolsCallingTag.tsx new file mode 100644 index 0000000000..1532564be1 --- /dev/null +++ b/src/renderer/src/components/Tags/ModelCapabilities/ToolsCallingTag.tsx @@ -0,0 +1,24 @@ +import { ToolOutlined } from '@ant-design/icons' +import { useTranslation } from 'react-i18next' + +import CustomTag, { CustomTagProps } from '../CustomTag' + +type Props = { + size?: number + showTooltip?: boolean + showLabel?: boolean +} & Omit + +export const ToolsCallingTag = ({ size, showTooltip, showLabel, ...restProps }: Props) => { + const { t } = useTranslation() + return ( + } + tooltip={showTooltip ? t('models.type.function_calling') : undefined} + {...restProps}> + {showLabel ? t('models.type.function_calling') : ''} + + ) +} diff --git a/src/renderer/src/components/Tags/ModelCapabilities/VisionTag.tsx b/src/renderer/src/components/Tags/ModelCapabilities/VisionTag.tsx new file mode 100644 index 0000000000..4ff219cfc5 --- /dev/null +++ b/src/renderer/src/components/Tags/ModelCapabilities/VisionTag.tsx @@ -0,0 +1,25 @@ +import { EyeOutlined } from '@ant-design/icons' +import { useTranslation } from 'react-i18next' + +import CustomTag, { CustomTagProps } from '../CustomTag' + +type Props = { + size?: number + showTooltip?: boolean + showLabel?: boolean +} & Omit + +export const VisionTag = ({ size, showTooltip, showLabel, ...restProps }: Props) => { + const { t } = useTranslation() + + return ( + } + tooltip={showTooltip ? t('models.type.vision') : undefined} + {...restProps}> + {showLabel ? t('models.type.vision') : ''} + + ) +} diff --git a/src/renderer/src/components/Tags/ModelCapabilities/WebSearchTag.tsx b/src/renderer/src/components/Tags/ModelCapabilities/WebSearchTag.tsx new file mode 100644 index 0000000000..099c9b3839 --- /dev/null +++ b/src/renderer/src/components/Tags/ModelCapabilities/WebSearchTag.tsx @@ -0,0 +1,25 @@ +import { GlobalOutlined } from '@ant-design/icons' +import { useTranslation } from 'react-i18next' + +import CustomTag, { CustomTagProps } from '../CustomTag' + +type Props = { + size?: number + showTooltip?: boolean + showLabel?: boolean +} & Omit + +export const WebSearchTag = ({ size, showTooltip, showLabel, ...restProps }: Props) => { + const { t } = useTranslation() + + return ( + } + tooltip={showTooltip ? t('models.type.websearch') : undefined} + {...restProps}> + {showLabel ? t('models.type.websearch') : ''} + + ) +} diff --git a/src/renderer/src/components/Tags/ModelCapabilities/index.ts b/src/renderer/src/components/Tags/ModelCapabilities/index.ts new file mode 100644 index 0000000000..990f66c580 --- /dev/null +++ b/src/renderer/src/components/Tags/ModelCapabilities/index.ts @@ -0,0 +1,8 @@ +import { EmbeddingTag } from './EmbeddingTag' +import { ReasoningTag } from './ReasoningTag' +import { RerankerTag } from './RerankerTag' +import { ToolsCallingTag } from './ToolsCallingTag' +import { VisionTag } from './VisionTag' +import { WebSearchTag } from './WebSearchTag' + +export { EmbeddingTag, ReasoningTag, RerankerTag, ToolsCallingTag, VisionTag, WebSearchTag } diff --git a/src/renderer/src/components/WarnTooltip.tsx b/src/renderer/src/components/WarnTooltip.tsx new file mode 100644 index 0000000000..b5292365db --- /dev/null +++ b/src/renderer/src/components/WarnTooltip.tsx @@ -0,0 +1,25 @@ +import { Tooltip, TooltipProps } from 'antd' +import { AlertTriangle } from 'lucide-react' + +type InheritedTooltipProps = Omit + +interface WarnTooltipProps extends InheritedTooltipProps { + iconColor?: string + iconSize?: string | number + iconStyle?: React.CSSProperties +} + +const WarnTooltip = ({ + iconColor = 'var(--color-status-warning)', + iconSize = 14, + iconStyle, + ...rest +}: WarnTooltipProps) => { + return ( + + + + ) +} + +export default WarnTooltip diff --git a/src/renderer/src/components/__tests__/CustomTag.test.tsx b/src/renderer/src/components/__tests__/CustomTag.test.tsx index a306fa6494..12a4620b3d 100644 --- a/src/renderer/src/components/__tests__/CustomTag.test.tsx +++ b/src/renderer/src/components/__tests__/CustomTag.test.tsx @@ -2,7 +2,7 @@ import { render, screen } from '@testing-library/react' import userEvent from '@testing-library/user-event' import { describe, expect, it } from 'vitest' -import CustomTag from '../CustomTag' +import CustomTag from '../Tags/CustomTag' const COLOR = '#ff0000' diff --git a/src/renderer/src/i18n/locales/zh-cn.json b/src/renderer/src/i18n/locales/zh-cn.json index 0e432c84c6..49bed6aff4 100644 --- a/src/renderer/src/i18n/locales/zh-cn.json +++ b/src/renderer/src/i18n/locales/zh-cn.json @@ -3052,7 +3052,7 @@ "moresetting": { "check": { "confirm": "确认勾选", - "warn": "请慎重勾选此选项,勾选错误会导致模型无法正常使用!!!" + "warn": "请慎重更改模型类型,选择错误的类型会导致模型无法正常使用!" }, "label": "更多设置", "warn": "风险警告" diff --git a/src/renderer/src/pages/agents/AgentsPage.tsx b/src/renderer/src/pages/agents/AgentsPage.tsx index 727e065662..c0c9093e7c 100644 --- a/src/renderer/src/pages/agents/AgentsPage.tsx +++ b/src/renderer/src/pages/agents/AgentsPage.tsx @@ -1,9 +1,9 @@ import { ImportOutlined, PlusOutlined } from '@ant-design/icons' import { Navbar, NavbarCenter } from '@renderer/components/app/Navbar' -import CustomTag from '@renderer/components/CustomTag' import { HStack } from '@renderer/components/Layout' import ListItem from '@renderer/components/ListItem' import Scrollbar from '@renderer/components/Scrollbar' +import CustomTag from '@renderer/components/Tags/CustomTag' import { useAgents } from '@renderer/hooks/useAgents' import { useNavbarPosition } from '@renderer/hooks/useSettings' import { createAssistantFromAgent } from '@renderer/services/AssistantService' diff --git a/src/renderer/src/pages/agents/components/AgentCard.tsx b/src/renderer/src/pages/agents/components/AgentCard.tsx index 223987a06c..020bd35c73 100644 --- a/src/renderer/src/pages/agents/components/AgentCard.tsx +++ b/src/renderer/src/pages/agents/components/AgentCard.tsx @@ -1,5 +1,5 @@ -import CustomTag from '@renderer/components/CustomTag' import { DeleteIcon, EditIcon } from '@renderer/components/Icons' +import CustomTag from '@renderer/components/Tags/CustomTag' import { useAgents } from '@renderer/hooks/useAgents' import AssistantSettingsPopup from '@renderer/pages/settings/AssistantSettings' import { createAssistantFromAgent } from '@renderer/services/AssistantService' diff --git a/src/renderer/src/pages/home/Inputbar/AttachmentPreview.tsx b/src/renderer/src/pages/home/Inputbar/AttachmentPreview.tsx index 678140c78f..fcf9b083fb 100644 --- a/src/renderer/src/pages/home/Inputbar/AttachmentPreview.tsx +++ b/src/renderer/src/pages/home/Inputbar/AttachmentPreview.tsx @@ -12,7 +12,7 @@ import { GlobalOutlined, LinkOutlined } from '@ant-design/icons' -import CustomTag from '@renderer/components/CustomTag' +import CustomTag from '@renderer/components/Tags/CustomTag' import FileManager from '@renderer/services/FileManager' import { FileMetadata } from '@renderer/types' import { formatFileSize } from '@renderer/utils' diff --git a/src/renderer/src/pages/home/Inputbar/KnowledgeBaseInput.tsx b/src/renderer/src/pages/home/Inputbar/KnowledgeBaseInput.tsx index 9918290e51..fdcde05aa3 100644 --- a/src/renderer/src/pages/home/Inputbar/KnowledgeBaseInput.tsx +++ b/src/renderer/src/pages/home/Inputbar/KnowledgeBaseInput.tsx @@ -1,5 +1,5 @@ import { FileSearchOutlined } from '@ant-design/icons' -import CustomTag from '@renderer/components/CustomTag' +import CustomTag from '@renderer/components/Tags/CustomTag' import { KnowledgeBase } from '@renderer/types' import { FC } from 'react' import styled from 'styled-components' diff --git a/src/renderer/src/pages/home/Inputbar/MentionModelsInput.tsx b/src/renderer/src/pages/home/Inputbar/MentionModelsInput.tsx index 1e62b15f85..025c0bb2b3 100644 --- a/src/renderer/src/pages/home/Inputbar/MentionModelsInput.tsx +++ b/src/renderer/src/pages/home/Inputbar/MentionModelsInput.tsx @@ -1,4 +1,4 @@ -import CustomTag from '@renderer/components/CustomTag' +import CustomTag from '@renderer/components/Tags/CustomTag' import { useProviders } from '@renderer/hooks/useProvider' import { getModelUniqId } from '@renderer/services/ModelService' import { Model } from '@renderer/types' diff --git a/src/renderer/src/pages/home/Messages/MessageEditor.tsx b/src/renderer/src/pages/home/Messages/MessageEditor.tsx index 2b6dd59d1e..09f52a1a3d 100644 --- a/src/renderer/src/pages/home/Messages/MessageEditor.tsx +++ b/src/renderer/src/pages/home/Messages/MessageEditor.tsx @@ -1,5 +1,5 @@ import { loggerService } from '@logger' -import CustomTag from '@renderer/components/CustomTag' +import CustomTag from '@renderer/components/Tags/CustomTag' import TranslateButton from '@renderer/components/TranslateButton' import { isGenerateImageModel, isVisionModel } from '@renderer/config/models' import { useAssistant } from '@renderer/hooks/useAssistant' diff --git a/src/renderer/src/pages/knowledge/KnowledgeContent.tsx b/src/renderer/src/pages/knowledge/KnowledgeContent.tsx index cba5513082..6d0e350ac0 100644 --- a/src/renderer/src/pages/knowledge/KnowledgeContent.tsx +++ b/src/renderer/src/pages/knowledge/KnowledgeContent.tsx @@ -1,7 +1,7 @@ import { RedoOutlined } from '@ant-design/icons' import { loggerService } from '@logger' -import CustomTag from '@renderer/components/CustomTag' import { HStack } from '@renderer/components/Layout' +import CustomTag from '@renderer/components/Tags/CustomTag' import { useKnowledge } from '@renderer/hooks/useKnowledge' import { NavbarIcon } from '@renderer/pages/home/ChatNavbar' import { getProviderName } from '@renderer/services/ProviderService' diff --git a/src/renderer/src/pages/settings/ProviderSettings/EditModelPopup/ModelEditContent.tsx b/src/renderer/src/pages/settings/ProviderSettings/EditModelPopup/ModelEditContent.tsx index 8f0053ecab..7dfa6070e1 100644 --- a/src/renderer/src/pages/settings/ProviderSettings/EditModelPopup/ModelEditContent.tsx +++ b/src/renderer/src/pages/settings/ProviderSettings/EditModelPopup/ModelEditContent.tsx @@ -1,4 +1,13 @@ import CopyIcon from '@renderer/components/Icons/CopyIcon' +import { + EmbeddingTag, + ReasoningTag, + RerankerTag, + ToolsCallingTag, + VisionTag, + WebSearchTag +} from '@renderer/components/Tags/ModelCapabilities' +import WarnTooltip from '@renderer/components/WarnTooltip' import { endpointTypeOptions } from '@renderer/config/endpointTypes' import { isEmbeddingModel, @@ -13,7 +22,6 @@ import { Model, ModelCapability, ModelType, Provider } from '@renderer/types' import { getDefaultGroupName, getDifference, getUnion, uniqueObjectArray } from '@renderer/utils' import { Button, - Checkbox, Divider, Flex, Form, @@ -23,11 +31,12 @@ import { Modal, ModalProps, Select, - Switch + Switch, + Tooltip } from 'antd' import { cloneDeep } from 'lodash' -import { ChevronDown, ChevronUp, SaveIcon } from 'lucide-react' -import { FC, useEffect, useRef, useState } from 'react' +import { ChevronDown, ChevronUp, RotateCcw, SaveIcon } from 'lucide-react' +import { FC, useCallback, useEffect, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' import styled from 'styled-components' @@ -107,22 +116,32 @@ const ModelEditContent: FC = ({ provider, mo { label: t('models.price.custom'), value: 'custom' } ] - const defaultTypes = [ - ...(isVisionModel(model) ? ['vision'] : []), - ...(isReasoningModel(model) ? ['reasoning'] : []), - ...(isFunctionCallingModel(model) ? ['function_calling'] : []), - ...(isWebSearchModel(model) ? ['web_search'] : []), - ...(isEmbeddingModel(model) ? ['embedding'] : []), - ...(isRerankModel(model) ? ['rerank'] : []) - ] + const defaultTypes: ModelType[] = useMemo( + () => [ + ...(isVisionModel(model) ? (['vision'] as const) : []), + ...(isReasoningModel(model) ? (['reasoning'] as const) : []), + ...(isFunctionCallingModel(model) ? (['function_calling'] as const) : []), + ...(isWebSearchModel(model) ? (['web_search'] as const) : []), + ...(isEmbeddingModel(model) ? (['embedding'] as const) : []), + ...(isRerankModel(model) ? (['rerank'] as const) : []) + ], + [model] + ) - const selectedTypes: string[] = getUnion( - modelCapabilities?.filter((t) => t.isUserSelected).map((t) => t.type) || [], - getDifference(defaultTypes, modelCapabilities?.filter((t) => t.isUserSelected === false).map((t) => t.type) || []) + const selectedTypes: ModelType[] = useMemo( + () => + getUnion( + modelCapabilities?.filter((t) => t.isUserSelected).map((t) => t.type) || [], + getDifference( + defaultTypes, + modelCapabilities?.filter((t) => t.isUserSelected === false).map((t) => t.type) || [] + ) + ), + [defaultTypes, modelCapabilities] ) // 被rerank/embedding改变的类型 - const changedTypesRef = useRef([]) + // const changedTypesRef = useRef([]) useEffect(() => { if (showMoreSettings) { @@ -151,157 +170,76 @@ const ModelEditContent: FC = ({ provider, mo }, [modelCapabilities]) const ModelCapability = () => { - const isDisabled = selectedTypes.includes('rerank') || selectedTypes.includes('embedding') - const isRerankDisabled = selectedTypes.includes('embedding') const isEmbeddingDisabled = selectedTypes.includes('rerank') - const showTypeConfirmModal = (newCapability: ModelCapability) => { - const onUpdateType = selectedTypes?.find((t) => t === newCapability.type) - window.modal.confirm({ - title: t('settings.moresetting.warn'), - content: t('settings.moresetting.check.warn'), - okText: t('settings.moresetting.check.confirm'), - cancelText: t('common.cancel'), - okButtonProps: { danger: true }, - cancelButtonProps: { type: 'primary' }, - onOk: () => { - if (onUpdateType) { - const updatedModelCapabilities = modelCapabilities?.map((t) => { - if (t.type === newCapability.type) { - return { ...t, isUserSelected: true } - } - if ( - ((onUpdateType !== t.type && onUpdateType === 'rerank') || - (onUpdateType === 'embedding' && onUpdateType !== t.type)) && - t.isUserSelected !== false - ) { - changedTypesRef.current.push(t.type) - return { ...t, isUserSelected: false } - } - return t - }) - setModelCapabilities(uniqueObjectArray(updatedModelCapabilities as ModelCapability[])) - } else { - const updatedModelCapabilities = modelCapabilities?.map((t) => { - if ( - ((newCapability.type !== t.type && newCapability.type === 'rerank') || - (newCapability.type === 'embedding' && newCapability.type !== t.type)) && - t.isUserSelected !== false - ) { - changedTypesRef.current.push(t.type) - return { ...t, isUserSelected: false } - } - if (newCapability.type === t.type) { - return { ...t, isUserSelected: true } - } - return t - }) - updatedModelCapabilities.push(newCapability as any) - setModelCapabilities(uniqueObjectArray(updatedModelCapabilities as ModelCapability[])) - } - }, - onCancel: () => {}, - centered: true - }) - } - - const handleTypeChange = (types: string[]) => { - setHasUserModified(true) // 标记用户已进行修改 - const diff = types.length > selectedTypes.length - if (diff) { - const newCapability = getDifference(types, selectedTypes) // checkbox的特性,确保了newCapability只有一个元素 - showTypeConfirmModal({ - type: newCapability[0] as ModelType, - isUserSelected: true - }) - } else { - const disabledTypes = getDifference(selectedTypes, types) - const onUpdateType = modelCapabilities?.find((t) => t.type === disabledTypes[0]) - if (onUpdateType) { - const updatedTypes = modelCapabilities?.map((t) => { - if (t.type === disabledTypes[0]) { - return { ...t, isUserSelected: false } - } - if ( - ((onUpdateType !== t && onUpdateType.type === 'rerank') || - (onUpdateType.type === 'embedding' && onUpdateType !== t)) && - t.isUserSelected === false - ) { - if (changedTypesRef.current.includes(t.type)) { - return { ...t, isUserSelected: true } - } - } - return t - }) - setModelCapabilities(uniqueObjectArray(updatedTypes as ModelCapability[])) - } else { - const updatedModelCapabilities = modelCapabilities?.map((t) => { - if ( - (disabledTypes[0] === 'rerank' && t.type !== 'rerank') || - (disabledTypes[0] === 'embedding' && t.type !== 'embedding' && t.isUserSelected === false) - ) { - return { ...t, isUserSelected: true } - } - return t - }) - updatedModelCapabilities.push({ type: disabledTypes[0] as ModelType, isUserSelected: false }) - setModelCapabilities(uniqueObjectArray(updatedModelCapabilities as ModelCapability[])) - } - changedTypesRef.current.length = 0 - } - } + const isOtherDisabled = selectedTypes.includes('rerank') || selectedTypes.includes('embedding') const handleResetTypes = () => { setModelCapabilities(originalModelCapabilities) setHasUserModified(false) // 重置后清除修改标志 } + const updateType = useCallback((type: ModelType) => { + setHasUserModified(true) + setModelCapabilities((prev) => + uniqueObjectArray([ + ...prev.filter((t) => t.type !== type), + { type, isUserSelected: !selectedTypes.includes(type) } + ]) + ) + }, []) + return ( -
- - + <> + + + {t('models.type.select')} + + + {hasUserModified && ( - + +
+ ) } @@ -405,7 +343,6 @@ const ModelEditContent: FC = ({ provider, mo {showMoreSettings && (
- {t('models.type.select')} = ({ provider, mo } const TypeTitle = styled.div` + display: flex; + justify-content: space-between; + align-items: center; margin: 12px 0; font-size: 14px; font-weight: 600; diff --git a/src/renderer/src/pages/settings/ProviderSettings/ModelList/ManageModelsList.tsx b/src/renderer/src/pages/settings/ProviderSettings/ModelList/ManageModelsList.tsx index a76918e17c..a6d7020511 100644 --- a/src/renderer/src/pages/settings/ProviderSettings/ModelList/ManageModelsList.tsx +++ b/src/renderer/src/pages/settings/ProviderSettings/ModelList/ManageModelsList.tsx @@ -1,6 +1,6 @@ -import CustomTag from '@renderer/components/CustomTag' import ExpandableText from '@renderer/components/ExpandableText' import ModelIdWithTags from '@renderer/components/ModelIdWithTags' +import CustomTag from '@renderer/components/Tags/CustomTag' import { DynamicVirtualList } from '@renderer/components/VirtualList' import { getModelLogo } from '@renderer/config/models' import FileItem from '@renderer/pages/files/FileItem' diff --git a/src/renderer/src/pages/settings/ProviderSettings/ModelList/ModelList.tsx b/src/renderer/src/pages/settings/ProviderSettings/ModelList/ModelList.tsx index 0a29e60f03..4551f839e9 100644 --- a/src/renderer/src/pages/settings/ProviderSettings/ModelList/ModelList.tsx +++ b/src/renderer/src/pages/settings/ProviderSettings/ModelList/ModelList.tsx @@ -1,7 +1,7 @@ import CollapsibleSearchBar from '@renderer/components/CollapsibleSearchBar' -import CustomTag from '@renderer/components/CustomTag' import { LoadingIcon, StreamlineGoodHealthAndWellBeing } from '@renderer/components/Icons' import { HStack } from '@renderer/components/Layout' +import CustomTag from '@renderer/components/Tags/CustomTag' import { PROVIDER_URLS } from '@renderer/config/providers' import { useProvider } from '@renderer/hooks/useProvider' import { getProviderLabel } from '@renderer/i18n/label'