From 7bddf323e138781abf560081d48ffedb1b088a42 Mon Sep 17 00:00:00 2001 From: zxhlyh Date: Tue, 19 Aug 2025 16:42:07 +0800 Subject: [PATCH] fix: load balancing --- .../model-provider-page/declarations.ts | 5 ++ .../model-auth/authorized/credential-item.tsx | 12 +++- .../model-auth/config-model.tsx | 26 +++++--- .../switch-credential-in-load-balancing.tsx | 59 ++++++++++--------- .../provider-added-card/model-list-item.tsx | 15 +++-- .../model-load-balancing-configs.tsx | 28 +++++---- .../model-load-balancing-modal.tsx | 43 +++++++++++--- .../components/plugins/plugin-auth/types.ts | 1 + web/i18n/en-US/common.ts | 6 +- web/i18n/zh-Hans/common.ts | 6 +- web/service/use-models.ts | 1 + 11 files changed, 135 insertions(+), 67 deletions(-) diff --git a/web/app/components/header/account-setting/model-provider-page/declarations.ts b/web/app/components/header/account-setting/model-provider-page/declarations.ts index afb1cbce48..945806928a 100644 --- a/web/app/components/header/account-setting/model-provider-page/declarations.ts +++ b/web/app/components/header/account-setting/model-provider-page/declarations.ts @@ -86,6 +86,7 @@ export enum ModelStatusEnum { quotaExceeded = 'quota-exceeded', noPermission = 'no-permission', disabled = 'disabled', + credentialRemoved = 'credential-removed', } export const MODEL_STATUS_TEXT: { [k: string]: TypeWithI18N } = { @@ -185,6 +186,8 @@ export type QuotaConfiguration = { export type Credential = { credential_id: string credential_name?: string + from_enterprise?: boolean + allowed_to_use?: boolean } export type CustomModel = { @@ -316,4 +319,6 @@ export type ModelCredential = { credentials: Record load_balancing: ModelLoadBalancingConfig available_credentials: Credential[] + current_credential_id?: string + current_credential_name?: string } diff --git a/web/app/components/header/account-setting/model-provider-page/model-auth/authorized/credential-item.tsx b/web/app/components/header/account-setting/model-provider-page/model-auth/authorized/credential-item.tsx index c7dc37031f..4329adba4c 100644 --- a/web/app/components/header/account-setting/model-provider-page/model-auth/authorized/credential-item.tsx +++ b/web/app/components/header/account-setting/model-provider-page/model-auth/authorized/credential-item.tsx @@ -13,6 +13,7 @@ import ActionButton from '@/app/components/base/action-button' import Tooltip from '@/app/components/base/tooltip' import cn from '@/utils/classnames' import type { Credential } from '../../declarations' +import Badge from '@/app/components/base/badge' type CredentialItemProps = { credential: Credential @@ -49,7 +50,9 @@ const CredentialItem = ({ className={cn( 'group flex h-8 items-center rounded-lg p-1 hover:bg-state-base-hover', )} - onClick={() => onItemClick?.(credential)} + onClick={() => { + onItemClick?.(credential) + }} >
{ @@ -71,6 +74,13 @@ const CredentialItem = ({ {credential.credential_name}
+ { + credential.from_enterprise && ( + + Enterprise + + ) + } { showAction && (
diff --git a/web/app/components/header/account-setting/model-provider-page/model-auth/config-model.tsx b/web/app/components/header/account-setting/model-provider-page/model-auth/config-model.tsx index c9f1744cdb..083a3e238c 100644 --- a/web/app/components/header/account-setting/model-provider-page/model-auth/config-model.tsx +++ b/web/app/components/header/account-setting/model-provider-page/model-auth/config-model.tsx @@ -5,30 +5,32 @@ import { } from '@remixicon/react' import { useTranslation } from 'react-i18next' import Button from '@/app/components/base/button' +import Indicator from '@/app/components/header/indicator' import cn from '@/utils/classnames' type ConfigModelProps = { - className?: string onClick?: () => void loadBalancingEnabled?: boolean loadBalancingInvalid?: boolean + credentialRemoved?: boolean } const ConfigModel = ({ - className, onClick, loadBalancingEnabled, loadBalancingInvalid, + credentialRemoved, }: ConfigModelProps) => { const { t } = useTranslation() - if (loadBalancingEnabled && loadBalancingInvalid) { + if (loadBalancingEnabled && loadBalancingInvalid && !credentialRemoved) { return (
{t('common.modelProvider.auth.authorizationError')} +
) } @@ -38,13 +40,21 @@ const ConfigModel = ({ variant='secondary' size='small' className={cn( - 'shrink-0', - className, + 'hidden shrink-0 group-hover:flex', + credentialRemoved && 'flex', )} onClick={onClick} > { - !loadBalancingEnabled && ( + credentialRemoved && ( + <> + {t('common.modelProvider.auth.credentialRemoved')} + + + ) + } + { + !loadBalancingEnabled && !credentialRemoved && ( <> {t('common.operation.config')} @@ -52,7 +62,7 @@ const ConfigModel = ({ ) } { - loadBalancingEnabled && !loadBalancingInvalid && ( + loadBalancingEnabled && !loadBalancingInvalid && !credentialRemoved && ( <> {t('common.modelProvider.auth.configLoadBalancing')} diff --git a/web/app/components/header/account-setting/model-provider-page/model-auth/switch-credential-in-load-balancing.tsx b/web/app/components/header/account-setting/model-provider-page/model-auth/switch-credential-in-load-balancing.tsx index fca3e76d1f..4a45cd761f 100644 --- a/web/app/components/header/account-setting/model-provider-page/model-auth/switch-credential-in-load-balancing.tsx +++ b/web/app/components/header/account-setting/model-provider-page/model-auth/switch-credential-in-load-balancing.tsx @@ -7,40 +7,38 @@ import { useTranslation } from 'react-i18next' import { RiArrowDownSLine } from '@remixicon/react' import Button from '@/app/components/base/button' import Indicator from '@/app/components/header/indicator' -import Badge from '@/app/components/base/badge' import Authorized from './authorized' import type { - ModelLoadBalancingConfig, + Credential, + CustomModel, ModelProvider, } from '../declarations' import { ConfigurationMethodEnum } from '@/app/components/header/account-setting/model-provider-page/declarations' -import { useCredentialStatus } from './hooks' import cn from '@/utils/classnames' type SwitchCredentialInLoadBalancingProps = { provider: ModelProvider - draftConfig?: ModelLoadBalancingConfig - setDraftConfig: Dispatch> + model: CustomModel + credentials?: Credential[] + customModelCredential?: Credential + setCustomModelCredential: Dispatch> } const SwitchCredentialInLoadBalancing = ({ provider, - draftConfig, + model, + customModelCredential, + setCustomModelCredential, + credentials, }: SwitchCredentialInLoadBalancingProps) => { const { t } = useTranslation() - const { - available_credentials, - current_credential_name, - } = useCredentialStatus(provider) - const handleItemClick = useCallback(() => { - console.log('handleItemClick', draftConfig) - }, []) + const handleItemClick = useCallback((credential: Credential) => { + setCustomModelCredential(credential) + }, [setCustomModelCredential]) const renderTrigger = useCallback(() => { - const selectedCredentialId = draftConfig?.configs.find(config => config.name === '__inherit__')?.credential_id - const selectedCredential = available_credentials?.find(credential => credential.credential_id === selectedCredentialId) - const name = selectedCredential?.credential_name || current_credential_name - const authRemoved = !!selectedCredentialId && !selectedCredential + const selectedCredentialId = customModelCredential?.credential_id + const authRemoved = !selectedCredentialId && !!credentials?.length return ( ) - }, [current_credential_name, t, draftConfig, available_credentials]) + }, [customModelCredential, t, credentials]) return ( ) } diff --git a/web/app/components/header/account-setting/model-provider-page/provider-added-card/model-list-item.tsx b/web/app/components/header/account-setting/model-provider-page/provider-added-card/model-list-item.tsx index 5093904b2f..020cf83e43 100644 --- a/web/app/components/header/account-setting/model-provider-page/provider-added-card/model-list-item.tsx +++ b/web/app/components/header/account-setting/model-provider-page/provider-added-card/model-list-item.tsx @@ -3,7 +3,6 @@ import { useTranslation } from 'react-i18next' import { useDebounceFn } from 'ahooks' import type { ModelItem, ModelProvider } from '../declarations' import { ModelStatusEnum } from '../declarations' -import ModelBadge from '../model-badge' import ModelIcon from '../model-icon' import ModelName from '../model-name' import classNames from '@/utils/classnames' @@ -15,6 +14,7 @@ import { disableModel, enableModel } from '@/service/common' import { Plan } from '@/app/components/billing/type' import { useAppContext } from '@/context/app-context' import { ConfigModel } from '../model-auth' +import Badge from '@/app/components/base/badge' export type ModelListItemProps = { model: ModelItem @@ -63,21 +63,20 @@ const ModelListItem = ({ model, provider, isConfigurable, onModifyLoadBalancing showMode showContextSize > - {modelLoadBalancingEnabled && !model.deprecated && model.load_balancing_enabled && ( - - - {t('common.modelProvider.loadBalancingHeadline')} - - )}
+ {modelLoadBalancingEnabled && !model.deprecated && model.load_balancing_enabled && ( + + + + )} { (isCurrentWorkspaceManager && (modelLoadBalancingEnabled || plan.type === Plan.sandbox) && !model.deprecated && [ModelStatusEnum.active, ModelStatusEnum.disabled].includes(model.status)) && ( onModifyLoadBalancing?.(model)} loadBalancingEnabled={model.load_balancing_enabled} loadBalancingInvalid={model.has_invalid_load_balancing_configs} + credentialRemoved={model.status === ModelStatusEnum.credentialRemoved} /> ) } diff --git a/web/app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-configs.tsx b/web/app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-configs.tsx index 28fc5d39b7..5402ba4d73 100644 --- a/web/app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-configs.tsx +++ b/web/app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-configs.tsx @@ -1,5 +1,5 @@ import type { Dispatch, SetStateAction } from 'react' -import { useCallback } from 'react' +import { useCallback, useMemo } from 'react' import { useTranslation } from 'react-i18next' import { RiDeleteBinLine, @@ -122,6 +122,20 @@ const ModelLoadBalancingConfigs = ({ }) }, [updateConfigEntry]) + const validDraftConfigList = useMemo(() => { + if (!draftConfig) + return [] + return draftConfig.configs.filter((config) => { + if (config.name === '__inherit__') + return true + + if (config.credential_id) + return true + + return false + }) + }, [draftConfig]) + if (!draftConfig) return null @@ -165,15 +179,7 @@ const ModelLoadBalancingConfigs = ({
{draftConfig.enabled && (
- {draftConfig.configs.filter((config) => { - if (config.name === '__inherit__') - return true - - if (config.credential_id) - return true - - return false - }).map((config, index) => { + {validDraftConfigList.map((config, index) => { const isProviderManaged = config.name === '__inherit__' return (
@@ -249,7 +255,7 @@ const ModelLoadBalancingConfigs = ({
)} { - draftConfig.enabled && draftConfig.configs.length < 2 && ( + draftConfig.enabled && validDraftConfigList.length < 2 && (
{t('common.modelProvider.loadBalancingLeastKeyWarning')} diff --git a/web/app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-modal.tsx b/web/app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-modal.tsx index 7f2b88a186..9228fa5c93 100644 --- a/web/app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-modal.tsx +++ b/web/app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-modal.tsx @@ -19,7 +19,7 @@ import Modal from '@/app/components/base/modal' import Button from '@/app/components/base/button' import Loading from '@/app/components/base/loading' import { useToastContext } from '@/app/components/base/toast' -// import { SwitchCredentialInLoadBalancing } from '@/app/components/header/account-setting/model-provider-page/model-auth' +import { SwitchCredentialInLoadBalancing } from '@/app/components/header/account-setting/model-provider-page/model-auth' import { useGetModelCredential, useUpdateModelLoadBalancingConfig, @@ -59,6 +59,9 @@ const ModelLoadBalancingModal = ({ const modelCredential = data const { load_balancing, + current_credential_id, + available_credentials, + current_credential_name, } = modelCredential ?? {} const originalConfig = load_balancing const [draftConfig, setDraftConfig] = useState() @@ -102,11 +105,21 @@ const ModelLoadBalancingModal = ({ }, [extendedSecretFormSchemas, originalConfigMap]) const { mutateAsync: updateModelLoadBalancingConfig } = useUpdateModelLoadBalancingConfig(provider.provider) + const initialCustomModelCredential = useMemo(() => { + if (!current_credential_id) + return undefined + return { + credential_id: current_credential_id, + credential_name: current_credential_name, + } + }, [current_credential_id, current_credential_name]) + const [customModelCredential, setCustomModelCredential] = useState(initialCustomModelCredential) const handleSave = async () => { try { setLoading(true) const res = await updateModelLoadBalancingConfig( { + credential_id: customModelCredential?.credential_id || current_credential_id, config_from: configFrom, model: model.model, model_type: model.model_type, @@ -178,14 +191,28 @@ const ModelLoadBalancingModal = ({ )}
-
{t('common.modelProvider.providerManaged')}
-
{t('common.modelProvider.providerManagedDescription')}
+
{ + providerFormSchemaPredefined + ? t('common.modelProvider.auth.providerManaged') + : t('common.modelProvider.auth.specifyModelCredential') + }
+
{ + providerFormSchemaPredefined + ? t('common.modelProvider.auth.providerManagedTip') + : t('common.modelProvider.auth.specifyModelCredentialTip') + }
- {/* */} + { + !providerFormSchemaPredefined && ( + + ) + }
{ diff --git a/web/app/components/plugins/plugin-auth/types.ts b/web/app/components/plugins/plugin-auth/types.ts index df774d5d25..93ec4c8c1a 100644 --- a/web/app/components/plugins/plugin-auth/types.ts +++ b/web/app/components/plugins/plugin-auth/types.ts @@ -23,4 +23,5 @@ export type Credential = { credentials?: Record isWorkspaceDefault?: boolean from_enterprise?: boolean + allowed_to_use?: boolean } diff --git a/web/i18n/en-US/common.ts b/web/i18n/en-US/common.ts index 7226c9850f..f4622c3068 100644 --- a/web/i18n/en-US/common.ts +++ b/web/i18n/en-US/common.ts @@ -467,7 +467,7 @@ const translation = { loadPresets: 'Load Presets', parameters: 'PARAMETERS', loadBalancing: 'Load balancing', - loadBalancingDescription: 'Reduce pressure with multiple sets of credentials.', + loadBalancingDescription: 'Configure multiple credentials for the model and invoke them automatically. ', loadBalancingHeadline: 'Load Balancing', configLoadBalancing: 'Config Load Balancing', modelHasBeenDeprecated: 'This model has been deprecated', @@ -499,6 +499,10 @@ const translation = { configModel: 'Config model', configLoadBalancing: 'Config Load Balancing', authorizationError: 'Authorization error', + specifyModelCredential: 'Specify model credential', + specifyModelCredentialTip: 'Use a configured model credential.', + providerManaged: 'Provider managed', + providerManagedTip: 'The current configuration is hosted by the provider.', }, }, dataSource: { diff --git a/web/i18n/zh-Hans/common.ts b/web/i18n/zh-Hans/common.ts index e91407872a..fcbf825bbc 100644 --- a/web/i18n/zh-Hans/common.ts +++ b/web/i18n/zh-Hans/common.ts @@ -466,7 +466,7 @@ const translation = { loadPresets: '加载预设', parameters: '参数', loadBalancing: '负载均衡', - loadBalancingDescription: '为了减轻单组凭据的压力,您可以为模型调用配置多组凭据。', + loadBalancingDescription: '为模型配置多组凭据,并自动调用。', loadBalancingHeadline: '负载均衡', configLoadBalancing: '设置负载均衡', modelHasBeenDeprecated: '该模型已废弃', @@ -499,6 +499,10 @@ const translation = { configModel: '配置模型', configLoadBalancing: '配置负载均衡', authorizationError: '授权错误', + specifyModelCredential: '指定模型凭据', + specifyModelCredentialTip: '使用已配置的模型凭据。', + providerManaged: '由模型供应商管理', + providerManagedTip: '使用模型供应商提供的单组凭据。', }, }, dataSource: { diff --git a/web/service/use-models.ts b/web/service/use-models.ts index 75321d2706..f3336dd03b 100644 --- a/web/service/use-models.ts +++ b/web/service/use-models.ts @@ -147,6 +147,7 @@ export const useUpdateModelLoadBalancingConfig = (provider: string) => { model: string model_type: ModelTypeEnum load_balancing: ModelLoadBalancingConfig + credential_id?: string }) => post<{ result: string }>(`/workspaces/current/model-providers/${provider}/models`, { body: data, }),