mirror of https://github.com/langgenius/dify.git
model auth
This commit is contained in:
parent
2e28a64d38
commit
473b465efb
|
|
@ -30,7 +30,7 @@ const BaseField = ({
|
|||
inputClassName,
|
||||
formSchema,
|
||||
field,
|
||||
disabled,
|
||||
disabled: propsDisabled,
|
||||
}: BaseFieldProps) => {
|
||||
const renderI18nObject = useRenderI18nObject()
|
||||
const {
|
||||
|
|
@ -40,7 +40,9 @@ const BaseField = ({
|
|||
options,
|
||||
labelClassName: formLabelClassName,
|
||||
show_on = [],
|
||||
disabled: formSchemaDisabled,
|
||||
} = formSchema
|
||||
const disabled = propsDisabled || formSchemaDisabled
|
||||
|
||||
const memorizedLabel = useMemo(() => {
|
||||
if (isValidElement(label))
|
||||
|
|
@ -182,9 +184,10 @@ const BaseField = ({
|
|||
className={cn(
|
||||
'system-sm-regular hover:bg-components-option-card-option-hover-bg hover:border-components-option-card-option-hover-border flex h-8 flex-[1] grow cursor-pointer items-center justify-center rounded-lg border border-components-option-card-option-border bg-components-option-card-option-bg p-2 text-text-secondary',
|
||||
value === option.value && 'border-components-option-card-option-selected-border bg-components-option-card-option-selected-bg text-text-primary shadow-xs',
|
||||
disabled && 'cursor-not-allowed opacity-50',
|
||||
inputClassName,
|
||||
)}
|
||||
onClick={() => field.handleChange(option.value)}
|
||||
onClick={() => !disabled && field.handleChange(option.value)}
|
||||
>
|
||||
{
|
||||
formSchema.showRadioUI && (
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ export type FormSchema = {
|
|||
labelClassName?: string
|
||||
validators?: AnyValidators
|
||||
showRadioUI?: boolean
|
||||
disabled?: boolean
|
||||
}
|
||||
|
||||
export type FormValues = Record<string, any>
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ export type QuotaConfiguration = {
|
|||
|
||||
export type Credential = {
|
||||
credential_id: string
|
||||
credential_name: string
|
||||
credential_name?: string
|
||||
}
|
||||
|
||||
export type CustomModel = {
|
||||
|
|
|
|||
|
|
@ -354,6 +354,7 @@ export const useModelModalHandler = () => {
|
|||
provider: ModelProvider,
|
||||
configurationMethod: ConfigurationMethodEnum,
|
||||
CustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields,
|
||||
isModelCredential?: boolean,
|
||||
credential?: Credential,
|
||||
model?: CustomModel,
|
||||
) => {
|
||||
|
|
@ -362,6 +363,7 @@ export const useModelModalHandler = () => {
|
|||
currentProvider: provider,
|
||||
currentConfigurationMethod: configurationMethod,
|
||||
currentCustomConfigurationModelFixedFields: CustomConfigurationModelFixedFields,
|
||||
isModelCredential,
|
||||
credential,
|
||||
model,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -8,9 +8,6 @@ import {
|
|||
import SystemModelSelector from './system-model-selector'
|
||||
import ProviderAddedCard from './provider-added-card'
|
||||
import type {
|
||||
ConfigurationMethodEnum,
|
||||
Credential,
|
||||
CustomConfigurationModelFixedFields,
|
||||
ModelProvider,
|
||||
} from './declarations'
|
||||
import {
|
||||
|
|
@ -19,7 +16,6 @@ import {
|
|||
} from './declarations'
|
||||
import {
|
||||
useDefaultModel,
|
||||
useModelModalHandler,
|
||||
} from './hooks'
|
||||
import InstallFromMarketplace from './install-from-marketplace'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
|
|
@ -85,8 +81,6 @@ const ModelProviderPage = ({ searchText }: Props) => {
|
|||
return [filteredConfiguredProviders, filteredNotConfiguredProviders]
|
||||
}, [configuredProviders, debouncedSearchText, notConfiguredProviders])
|
||||
|
||||
const handleOpenModal = useModelModalHandler()
|
||||
|
||||
return (
|
||||
<div className='relative -mt-2 pt-1'>
|
||||
<div className={cn('mb-2 flex items-center')}>
|
||||
|
|
@ -127,7 +121,6 @@ const ModelProviderPage = ({ searchText }: Props) => {
|
|||
<ProviderAddedCard
|
||||
key={provider.provider}
|
||||
provider={provider}
|
||||
onOpenModal={(configurationMethod: ConfigurationMethodEnum, currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields, credential?: Credential) => handleOpenModal(provider, configurationMethod, currentCustomConfigurationModelFixedFields, credential)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
|
@ -141,7 +134,6 @@ const ModelProviderPage = ({ searchText }: Props) => {
|
|||
notConfigured
|
||||
key={provider.provider}
|
||||
provider={provider}
|
||||
onOpenModal={(configurationMethod: ConfigurationMethodEnum, currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields, credential?: Credential) => handleOpenModal(provider, configurationMethod, currentCustomConfigurationModelFixedFields, credential)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,39 +3,70 @@ import {
|
|||
useCallback,
|
||||
} from 'react'
|
||||
import { RiAddLine } from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Authorized } from '@/app/components/header/account-setting/model-provider-page/model-auth'
|
||||
import cn from '@/utils/classnames'
|
||||
import type {
|
||||
Credential,
|
||||
CustomModelCredential,
|
||||
ModelCredential,
|
||||
ModelProvider,
|
||||
} from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import { ConfigurationMethodEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
|
||||
type AddCredentialInLoadBalancingProps = {
|
||||
provider: ModelProvider
|
||||
onSetup: (credential?: Credential) => void
|
||||
model: CustomModelCredential
|
||||
configurationMethod: ConfigurationMethodEnum
|
||||
modelCredential: ModelCredential
|
||||
onSelectCredential: (credential: Credential) => void
|
||||
onUpdate?: () => void
|
||||
}
|
||||
const AddCredentialInLoadBalancing = ({
|
||||
provider,
|
||||
onSetup,
|
||||
model,
|
||||
configurationMethod,
|
||||
modelCredential,
|
||||
onSelectCredential,
|
||||
onUpdate,
|
||||
}: AddCredentialInLoadBalancingProps) => {
|
||||
const { t } = useTranslation()
|
||||
const {
|
||||
available_credentials,
|
||||
} = modelCredential
|
||||
const customModel = configurationMethod === ConfigurationMethodEnum.customizableModel
|
||||
const renderTrigger = useCallback((open?: boolean) => {
|
||||
return (
|
||||
<div className={cn(
|
||||
'flex h-8 items-center rounded-lg px-3 hover:bg-state-base-hover',
|
||||
'system-sm-medium flex h-8 items-center rounded-lg px-3 text-text-accent hover:bg-state-base-hover',
|
||||
open && 'bg-state-base-hover',
|
||||
)}>
|
||||
<RiAddLine className='system-sm-medium h-4 w-4 text-text-accent' />
|
||||
Add credential
|
||||
<RiAddLine className='mr-2 h-4 w-4' />
|
||||
{
|
||||
customModel
|
||||
? t('common.modelProvider.auth.addCredential')
|
||||
: t('common.modelProvider.auth.addApiKey')
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Authorized
|
||||
credentials={[]}
|
||||
provider={provider.provider}
|
||||
provider={provider}
|
||||
renderTrigger={renderTrigger}
|
||||
onSetup={onSetup}
|
||||
items={[
|
||||
{
|
||||
title: customModel ? t('common.modelProvider.auth.modelCredentials') : t('common.modelProvider.auth.apiKeys'),
|
||||
model,
|
||||
credentials: available_credentials ?? [],
|
||||
},
|
||||
]}
|
||||
configurationMethod={configurationMethod}
|
||||
onItemClick={onSelectCredential}
|
||||
placement='bottom-start'
|
||||
onUpdate={onUpdate}
|
||||
isModelCredential={customModel}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,52 +12,60 @@ import {
|
|||
} from '@/app/components/base/button'
|
||||
import type {
|
||||
CustomConfigurationModelFixedFields,
|
||||
CustomModelCredential,
|
||||
ModelProvider,
|
||||
} from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import { ConfigurationMethodEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import Authorized from './authorized'
|
||||
import { useAuth } from './hooks'
|
||||
import {
|
||||
useAuth,
|
||||
useCustomModels,
|
||||
} from './hooks'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
type AddCustomModelProps = {
|
||||
provider: ModelProvider,
|
||||
configurationMethod: ConfigurationMethodEnum,
|
||||
currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields,
|
||||
models: CustomModelCredential[]
|
||||
}
|
||||
const AddCustomModel = ({
|
||||
provider,
|
||||
configurationMethod,
|
||||
currentCustomConfigurationModelFixedFields,
|
||||
models,
|
||||
}: AddCustomModelProps) => {
|
||||
const { t } = useTranslation()
|
||||
const noModels = !models.length
|
||||
const customModels = useCustomModels(provider)
|
||||
const noModels = !customModels.length
|
||||
const {
|
||||
handleOpenModal,
|
||||
} = useAuth(provider, configurationMethod, currentCustomConfigurationModelFixedFields)
|
||||
} = useAuth(provider, configurationMethod, currentCustomConfigurationModelFixedFields, true)
|
||||
const handleClick = useCallback(() => {
|
||||
if (noModels)
|
||||
handleOpenModal()
|
||||
}, [handleOpenModal, noModels])
|
||||
handleOpenModal()
|
||||
}, [handleOpenModal])
|
||||
const ButtonComponent = useMemo(() => {
|
||||
return (
|
||||
<Button
|
||||
variant='ghost-accent'
|
||||
size='small'
|
||||
onClick={handleClick}
|
||||
className={cn(noModels && 'text-text-accent')}
|
||||
>
|
||||
<RiAddCircleFill className='mr-1 h-3.5 w-3.5' />
|
||||
{t('common.modelProvider.addModel')}
|
||||
</Button>
|
||||
)
|
||||
}, [handleClick, noModels])
|
||||
}, [handleClick])
|
||||
|
||||
const renderTrigger = useCallback(() => {
|
||||
return ButtonComponent
|
||||
}, [ButtonComponent])
|
||||
const renderTrigger = useCallback((open?: boolean) => {
|
||||
return (
|
||||
<Button
|
||||
variant='ghost'
|
||||
size='small'
|
||||
className={cn(open && 'bg-components-button-ghost-bg-hover')}
|
||||
>
|
||||
<RiAddCircleFill className='mr-1 h-3.5 w-3.5' />
|
||||
{t('common.modelProvider.addModel')}
|
||||
</Button>
|
||||
)
|
||||
}, [t])
|
||||
|
||||
if (noModels)
|
||||
return ButtonComponent
|
||||
|
|
@ -66,11 +74,14 @@ const AddCustomModel = ({
|
|||
<Authorized
|
||||
provider={provider}
|
||||
configurationMethod={ConfigurationMethodEnum.customizableModel}
|
||||
items={models.map(model => ({
|
||||
items={customModels.map(model => ({
|
||||
model,
|
||||
credentials: model.available_model_credentials ?? [],
|
||||
}))}
|
||||
renderTrigger={renderTrigger}
|
||||
isModelCredential
|
||||
enableAddModelCredential
|
||||
bottomAddModelCredentialText={t('common.modelProvider.auth.addNewModel')}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,41 +3,51 @@ import {
|
|||
useCallback,
|
||||
} from 'react'
|
||||
import { RiAddLine } from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import CredentialItem from './credential-item'
|
||||
import type {
|
||||
Credential,
|
||||
CustomModel,
|
||||
CustomModelCredential,
|
||||
} from '../../declarations'
|
||||
import Button from '@/app/components/base/button'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
|
||||
type AuthorizedItemProps = {
|
||||
model?: CustomModel
|
||||
model?: CustomModelCredential
|
||||
title?: string
|
||||
disabled?: boolean
|
||||
onDelete?: (id: string) => void
|
||||
onEdit?: (model?: CustomModel, credential?: Credential) => void
|
||||
onSetDefault?: (id: string) => void
|
||||
onItemClick?: (id: string) => void
|
||||
onDelete?: (credential?: Credential, model?: CustomModel) => void
|
||||
onEdit?: (credential?: Credential, model?: CustomModel) => void
|
||||
showItemSelectedIcon?: boolean
|
||||
selectedCredentialId?: string
|
||||
disableSetDefault?: boolean
|
||||
credentials: Credential[]
|
||||
onItemClick?: (credential: Credential, model?: CustomModel) => void
|
||||
enableAddModelCredential?: boolean
|
||||
}
|
||||
export const AuthorizedItem = ({
|
||||
model,
|
||||
title,
|
||||
credentials,
|
||||
disabled,
|
||||
onDelete,
|
||||
onEdit,
|
||||
onSetDefault,
|
||||
onItemClick,
|
||||
showItemSelectedIcon,
|
||||
selectedCredentialId,
|
||||
disableSetDefault,
|
||||
onItemClick,
|
||||
enableAddModelCredential,
|
||||
}: AuthorizedItemProps) => {
|
||||
const { t } = useTranslation()
|
||||
const handleEdit = useCallback((credential?: Credential) => {
|
||||
onEdit?.(model, credential)
|
||||
onEdit?.(credential, model)
|
||||
}, [onEdit, model])
|
||||
const handleDelete = useCallback((credential?: Credential) => {
|
||||
onDelete?.(credential, model)
|
||||
}, [onDelete, model])
|
||||
const handleItemClick = useCallback((credential: Credential) => {
|
||||
onItemClick?.(credential, model)
|
||||
}, [onItemClick, model])
|
||||
|
||||
return (
|
||||
<div className='p-1'>
|
||||
{
|
||||
|
|
@ -47,23 +57,28 @@ export const AuthorizedItem = ({
|
|||
>
|
||||
<div className='h-5 w-5 shrink-0'></div>
|
||||
<div
|
||||
className='system-md-medium mx-1 truncate text-text-primary'
|
||||
className='system-md-medium mx-1 grow truncate text-text-primary'
|
||||
title={model.model}
|
||||
>
|
||||
{model.model}
|
||||
{title ?? model.model}
|
||||
</div>
|
||||
<Tooltip
|
||||
asChild
|
||||
popupContent='Add model credential'
|
||||
>
|
||||
<Button
|
||||
className='h-6 w-6 rounded-full p-0'
|
||||
size='small'
|
||||
variant='secondary-accent'
|
||||
>
|
||||
<RiAddLine className='h-4 w-4' />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
{
|
||||
enableAddModelCredential && (
|
||||
<Tooltip
|
||||
asChild
|
||||
popupContent={t('common.modelProvider.auth.addModelCredential')}
|
||||
>
|
||||
<Button
|
||||
className='h-6 w-6 shrink-0 rounded-full p-0'
|
||||
size='small'
|
||||
variant='secondary-accent'
|
||||
onClick={() => handleEdit?.()}
|
||||
>
|
||||
<RiAddLine className='h-4 w-4' />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -73,13 +88,11 @@ export const AuthorizedItem = ({
|
|||
key={credential.credential_id}
|
||||
credential={credential}
|
||||
disabled={disabled}
|
||||
onDelete={onDelete}
|
||||
onDelete={handleDelete}
|
||||
onEdit={handleEdit}
|
||||
onSetDefault={onSetDefault}
|
||||
onItemClick={onItemClick}
|
||||
showSelectedIcon={showItemSelectedIcon}
|
||||
selectedCredentialId={selectedCredentialId}
|
||||
disableSetDefault={disableSetDefault}
|
||||
onItemClick={handleItemClick}
|
||||
/>
|
||||
))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,19 +13,16 @@ 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 Button from '@/app/components/base/button'
|
||||
|
||||
type CredentialItemProps = {
|
||||
credential: Credential
|
||||
disabled?: boolean
|
||||
onDelete?: (id: string) => void
|
||||
onDelete?: (credential: Credential) => void
|
||||
onEdit?: (credential?: Credential) => void
|
||||
onSetDefault?: (id: string) => void
|
||||
onItemClick?: (credential: Credential) => void
|
||||
disableRename?: boolean
|
||||
disableEdit?: boolean
|
||||
disableDelete?: boolean
|
||||
disableSetDefault?: boolean
|
||||
onItemClick?: (id: string) => void
|
||||
showSelectedIcon?: boolean
|
||||
selectedCredentialId?: string
|
||||
}
|
||||
|
|
@ -34,19 +31,17 @@ const CredentialItem = ({
|
|||
disabled,
|
||||
onDelete,
|
||||
onEdit,
|
||||
onSetDefault,
|
||||
onItemClick,
|
||||
disableRename,
|
||||
disableEdit,
|
||||
disableDelete,
|
||||
disableSetDefault,
|
||||
onItemClick,
|
||||
showSelectedIcon,
|
||||
selectedCredentialId,
|
||||
}: CredentialItemProps) => {
|
||||
const { t } = useTranslation()
|
||||
const showAction = useMemo(() => {
|
||||
return !(disableRename && disableEdit && disableDelete && disableSetDefault)
|
||||
}, [disableRename, disableEdit, disableDelete, disableSetDefault])
|
||||
return !(disableRename && disableEdit && disableDelete)
|
||||
}, [disableRename, disableEdit, disableDelete])
|
||||
|
||||
return (
|
||||
<div
|
||||
|
|
@ -54,7 +49,7 @@ const CredentialItem = ({
|
|||
className={cn(
|
||||
'group flex h-8 items-center rounded-lg p-1 hover:bg-state-base-hover',
|
||||
)}
|
||||
onClick={() => onItemClick?.(credential.credential_id)}
|
||||
onClick={() => onItemClick?.(credential)}
|
||||
>
|
||||
<div className='flex w-0 grow items-center space-x-1.5'>
|
||||
{
|
||||
|
|
@ -79,20 +74,6 @@ const CredentialItem = ({
|
|||
{
|
||||
showAction && (
|
||||
<div className='ml-2 hidden shrink-0 items-center group-hover:flex'>
|
||||
{
|
||||
!disableSetDefault && (
|
||||
<Button
|
||||
size='small'
|
||||
disabled={disabled}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
onSetDefault?.(credential.credential_id)
|
||||
}}
|
||||
>
|
||||
{t('plugin.auth.setDefault')}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
{
|
||||
!disableEdit && (
|
||||
<Tooltip popupContent={t('common.operation.edit')}>
|
||||
|
|
@ -116,7 +97,7 @@ const CredentialItem = ({
|
|||
disabled={disabled}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
onDelete?.(credential.credential_id)
|
||||
onDelete?.(credential)
|
||||
}}
|
||||
>
|
||||
<RiDeleteBinLine className='h-4 w-4 text-text-tertiary hover:text-text-destructive' />
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import {
|
|||
useState,
|
||||
} from 'react'
|
||||
import {
|
||||
RiAddLine,
|
||||
RiEqualizer2Line,
|
||||
} from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
|
@ -32,6 +33,7 @@ type AuthorizedProps = {
|
|||
provider: ModelProvider,
|
||||
configurationMethod: ConfigurationMethodEnum,
|
||||
currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields,
|
||||
isModelCredential?: boolean
|
||||
items: {
|
||||
model?: CustomModel
|
||||
credentials: Credential[]
|
||||
|
|
@ -45,16 +47,18 @@ type AuthorizedProps = {
|
|||
placement?: PortalToFollowElemOptions['placement']
|
||||
triggerPopupSameWidth?: boolean
|
||||
popupClassName?: string
|
||||
onItemClick?: (id: string) => void
|
||||
showItemSelectedIcon?: boolean
|
||||
onUpdate?: () => void
|
||||
disableSetDefault?: boolean
|
||||
onItemClick?: (credential: Credential, model?: CustomModel) => void
|
||||
enableAddModelCredential?: boolean
|
||||
bottomAddModelCredentialText?: string
|
||||
}
|
||||
const Authorized = ({
|
||||
provider,
|
||||
configurationMethod,
|
||||
currentCustomConfigurationModelFixedFields,
|
||||
items,
|
||||
isModelCredential,
|
||||
selectedCredential,
|
||||
disabled,
|
||||
renderTrigger,
|
||||
|
|
@ -64,10 +68,11 @@ const Authorized = ({
|
|||
placement = 'bottom-end',
|
||||
triggerPopupSameWidth = false,
|
||||
popupClassName,
|
||||
onItemClick,
|
||||
showItemSelectedIcon,
|
||||
onUpdate,
|
||||
disableSetDefault,
|
||||
onItemClick,
|
||||
enableAddModelCredential,
|
||||
bottomAddModelCredentialText,
|
||||
}: AuthorizedProps) => {
|
||||
const { t } = useTranslation()
|
||||
const [isLocalOpen, setIsLocalOpen] = useState(false)
|
||||
|
|
@ -86,13 +91,20 @@ const Authorized = ({
|
|||
handleConfirmDelete,
|
||||
deleteCredentialId,
|
||||
handleOpenModal,
|
||||
} = useAuth(provider, configurationMethod, currentCustomConfigurationModelFixedFields, onUpdate)
|
||||
} = useAuth(provider, configurationMethod, currentCustomConfigurationModelFixedFields, isModelCredential, onUpdate)
|
||||
|
||||
const handleEdit = useCallback((model?: CustomModel, credential?: Credential) => {
|
||||
handleOpenModal(model, credential)
|
||||
const handleEdit = useCallback((credential?: Credential, model?: CustomModel) => {
|
||||
handleOpenModal(credential, model)
|
||||
setMergedIsOpen(false)
|
||||
}, [handleOpenModal, setMergedIsOpen])
|
||||
|
||||
const handleItemClick = useCallback((credential: Credential, model?: CustomModel) => {
|
||||
if (!onItemClick)
|
||||
return handleActiveCredential(credential, model)
|
||||
|
||||
onItemClick?.(credential, model)
|
||||
}, [handleActiveCredential, onItemClick])
|
||||
|
||||
return (
|
||||
<>
|
||||
<PortalToFollowElem
|
||||
|
|
@ -135,24 +147,38 @@ const Authorized = ({
|
|||
disabled={disabled}
|
||||
onDelete={openConfirmDelete}
|
||||
onEdit={handleEdit}
|
||||
onSetDefault={handleActiveCredential}
|
||||
onItemClick={onItemClick}
|
||||
showItemSelectedIcon={showItemSelectedIcon}
|
||||
selectedCredentialId={selectedCredential?.credential_id}
|
||||
disableSetDefault={disableSetDefault}
|
||||
onItemClick={handleItemClick}
|
||||
enableAddModelCredential={enableAddModelCredential}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
<div className='h-[1px] bg-divider-subtle'></div>
|
||||
<div className='p-2'>
|
||||
<Button
|
||||
onClick={() => handleOpenModal()}
|
||||
className='w-full'
|
||||
>
|
||||
add api key
|
||||
</Button>
|
||||
</div>
|
||||
{
|
||||
isModelCredential && (
|
||||
<div
|
||||
onClick={() => handleEdit()}
|
||||
className='system-xs-medium flex h-[30px] cursor-pointer items-center px-3 text-text-accent-light-mode-only'
|
||||
>
|
||||
<RiAddLine className='mr-1 h-4 w-4' />
|
||||
{bottomAddModelCredentialText ?? t('common.modelProvider.auth.addModelCredential')}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
!isModelCredential && (
|
||||
<div className='p-2'>
|
||||
<Button
|
||||
onClick={() => handleEdit()}
|
||||
className='w-full'
|
||||
>
|
||||
{t('common.modelProvider.auth.addApiKey')}
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,32 @@
|
|||
import { memo } from 'react'
|
||||
import { RiEqualizer2Line } from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Button from '@/app/components/base/button'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
type ConfigModelProps = {
|
||||
className?: string
|
||||
onClick?: () => void
|
||||
}
|
||||
const ConfigModel = ({
|
||||
className,
|
||||
onClick,
|
||||
}: ConfigModelProps) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<Button
|
||||
variant='secondary'
|
||||
size='small'
|
||||
className={cn(
|
||||
'shrink-0',
|
||||
className,
|
||||
)}
|
||||
onClick={onClick}
|
||||
>
|
||||
<RiEqualizer2Line className='mr-1 h-4 w-4' />
|
||||
{t('common.operation.config')}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(ConfigModel)
|
||||
|
|
@ -67,6 +67,9 @@ const ConfigProvider = ({
|
|||
configurationMethod={ConfigurationMethodEnum.predefinedModel}
|
||||
items={[
|
||||
{
|
||||
model: {
|
||||
model: t('common.modelProvider.auth.apiKeys'),
|
||||
} as any,
|
||||
credentials: available_credentials ?? [],
|
||||
},
|
||||
]}
|
||||
|
|
|
|||
|
|
@ -3,3 +3,4 @@ export * from './use-credential-status'
|
|||
export * from './use-custom-models'
|
||||
export * from './use-auth'
|
||||
export * from './use-auth-service'
|
||||
export * from './use-credential-data'
|
||||
|
|
|
|||
|
|
@ -15,10 +15,10 @@ import type {
|
|||
CustomModel,
|
||||
} from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
|
||||
export const useGetCredential = (provider: string, credentialId?: string, model?: CustomModel, configFrom?: string) => {
|
||||
const providerData = useGetProviderCredential(!model && !!credentialId, provider, credentialId)
|
||||
const modelData = useGetModelCredential(!!model && !!credentialId, provider, credentialId, model?.model, model?.model_type, configFrom)
|
||||
return model ? modelData : providerData
|
||||
export const useGetCredential = (provider: string, isModelCredential?: boolean, credentialId?: string, model?: CustomModel, configFrom?: string) => {
|
||||
const providerData = useGetProviderCredential(!isModelCredential && !!credentialId, provider, credentialId)
|
||||
const modelData = useGetModelCredential(!!isModelCredential && !!credentialId, provider, credentialId, model?.model, model?.model_type, configFrom)
|
||||
return isModelCredential ? modelData : providerData
|
||||
}
|
||||
|
||||
export const useAuthService = (provider: string) => {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ export const useAuth = (
|
|||
provider: ModelProvider,
|
||||
configurationMethod: ConfigurationMethodEnum,
|
||||
currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields,
|
||||
isModelCredential?: boolean,
|
||||
onUpdate?: () => void,
|
||||
) => {
|
||||
const { t } = useTranslation()
|
||||
|
|
@ -37,9 +38,9 @@ export const useAuth = (
|
|||
const pendingOperationCredentialId = useRef<string | null>(null)
|
||||
const pendingOperationModel = useRef<CustomModel | null>(null)
|
||||
const [deleteCredentialId, setDeleteCredentialId] = useState<string | null>(null)
|
||||
const openConfirmDelete = useCallback((credentialId?: string, model?: CustomModel) => {
|
||||
if (credentialId)
|
||||
pendingOperationCredentialId.current = credentialId
|
||||
const openConfirmDelete = useCallback((credential?: Credential, model?: CustomModel) => {
|
||||
if (credential)
|
||||
pendingOperationCredentialId.current = credential.credential_id
|
||||
if (model)
|
||||
pendingOperationModel.current = model
|
||||
|
||||
|
|
@ -55,13 +56,13 @@ export const useAuth = (
|
|||
doingActionRef.current = doing
|
||||
setDoingAction(doing)
|
||||
}, [])
|
||||
const handleActiveCredential = useCallback(async (id: string, model?: CustomModel) => {
|
||||
const handleActiveCredential = useCallback(async (credential: Credential, model?: CustomModel) => {
|
||||
if (doingActionRef.current)
|
||||
return
|
||||
try {
|
||||
handleSetDoingAction(true)
|
||||
await getActiveCredentialService(!!model)({
|
||||
credential_id: id,
|
||||
credential_id: credential.credential_id,
|
||||
model: model?.model,
|
||||
model_type: model?.model_type,
|
||||
})
|
||||
|
|
@ -70,6 +71,7 @@ export const useAuth = (
|
|||
message: t('common.api.actionSuccess'),
|
||||
})
|
||||
onUpdate?.()
|
||||
handleRefreshModel(provider, configurationMethod, undefined)
|
||||
}
|
||||
finally {
|
||||
handleSetDoingAction(false)
|
||||
|
|
@ -84,7 +86,7 @@ export const useAuth = (
|
|||
}
|
||||
try {
|
||||
handleSetDoingAction(true)
|
||||
await getDeleteCredentialService(!!pendingOperationModel.current)({
|
||||
await getDeleteCredentialService(!!isModelCredential)({
|
||||
credential_id: pendingOperationCredentialId.current,
|
||||
model: pendingOperationModel.current?.model,
|
||||
model_type: pendingOperationModel.current?.model_type,
|
||||
|
|
@ -97,11 +99,12 @@ export const useAuth = (
|
|||
handleRefreshModel(provider, configurationMethod, undefined)
|
||||
setDeleteCredentialId(null)
|
||||
pendingOperationCredentialId.current = null
|
||||
pendingOperationModel.current = null
|
||||
}
|
||||
finally {
|
||||
handleSetDoingAction(false)
|
||||
}
|
||||
}, [onUpdate, notify, t, handleSetDoingAction, getDeleteCredentialService])
|
||||
}, [onUpdate, notify, t, handleSetDoingAction, getDeleteCredentialService, isModelCredential])
|
||||
const handleAddCredential = useCallback((model?: CustomModel) => {
|
||||
if (model)
|
||||
pendingOperationModel.current = model
|
||||
|
|
@ -114,9 +117,9 @@ export const useAuth = (
|
|||
|
||||
let res: { result?: string } = {}
|
||||
if (payload.credential_id)
|
||||
res = await getEditCredentialService(!!payload.model)(payload as any)
|
||||
res = await getEditCredentialService(!!isModelCredential)(payload as any)
|
||||
else
|
||||
res = await getAddCredentialService(!!payload.model)(payload as any)
|
||||
res = await getAddCredentialService(!!isModelCredential)(payload as any)
|
||||
|
||||
if (res.result === 'success') {
|
||||
notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
|
||||
|
|
@ -127,15 +130,16 @@ export const useAuth = (
|
|||
handleSetDoingAction(false)
|
||||
}
|
||||
}, [onUpdate, notify, t, handleSetDoingAction, getEditCredentialService, getAddCredentialService])
|
||||
const handleOpenModal = useCallback((model?: CustomModel, credential?: Credential) => {
|
||||
const handleOpenModal = useCallback((credential?: Credential, model?: CustomModel) => {
|
||||
handleOpenModelModal(
|
||||
provider,
|
||||
configurationMethod,
|
||||
currentCustomConfigurationModelFixedFields,
|
||||
isModelCredential,
|
||||
credential,
|
||||
model,
|
||||
)
|
||||
}, [handleOpenModelModal, provider, configurationMethod, currentCustomConfigurationModelFixedFields])
|
||||
}, [handleOpenModelModal, provider, configurationMethod, currentCustomConfigurationModelFixedFields, isModelCredential])
|
||||
|
||||
return {
|
||||
pendingOperationCredentialId,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
import { useMemo } from 'react'
|
||||
import { useGetCredential } from './use-auth-service'
|
||||
import type {
|
||||
Credential,
|
||||
CustomModelCredential,
|
||||
ModelProvider,
|
||||
} from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
|
||||
export const useCredentialData = (provider: ModelProvider, providerFormSchemaPredefined: boolean, isModelCredential?: boolean, credential?: Credential, model?: CustomModelCredential) => {
|
||||
const configFrom = useMemo(() => {
|
||||
if (providerFormSchemaPredefined)
|
||||
return 'predefined-model'
|
||||
return 'custom-model'
|
||||
}, [providerFormSchemaPredefined])
|
||||
const {
|
||||
isLoading,
|
||||
data: credentialData = {},
|
||||
} = useGetCredential(provider.provider, isModelCredential, credential?.credential_id, model, configFrom)
|
||||
|
||||
return {
|
||||
isLoading,
|
||||
credentialData,
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
import { useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type {
|
||||
Credential,
|
||||
CustomModelCredential,
|
||||
ModelLoadBalancingConfig,
|
||||
ModelProvider,
|
||||
} from '../../declarations'
|
||||
|
|
@ -13,6 +15,9 @@ import { FormTypeEnum } from '@/app/components/base/form/types'
|
|||
export const useModelFormSchemas = (
|
||||
provider: ModelProvider,
|
||||
providerFormSchemaPredefined: boolean,
|
||||
credentials?: Record<string, any>,
|
||||
credential?: Credential,
|
||||
model?: CustomModelCredential,
|
||||
draftConfig?: ModelLoadBalancingConfig,
|
||||
) => {
|
||||
const { t } = useTranslation()
|
||||
|
|
@ -22,11 +27,17 @@ export const useModelFormSchemas = (
|
|||
model_credential_schema,
|
||||
} = provider
|
||||
const formSchemas = useMemo(() => {
|
||||
const modelTypeSchema = genModelTypeFormSchema(supported_model_types)
|
||||
const modelNameSchema = genModelNameFormSchema(model_credential_schema?.model)
|
||||
if (!!model) {
|
||||
modelTypeSchema.disabled = true
|
||||
modelNameSchema.disabled = true
|
||||
}
|
||||
return providerFormSchemaPredefined
|
||||
? provider_credential_schema.credential_form_schemas
|
||||
: [
|
||||
genModelTypeFormSchema(supported_model_types),
|
||||
genModelNameFormSchema(model_credential_schema?.model),
|
||||
modelTypeSchema,
|
||||
modelNameSchema,
|
||||
...(draftConfig?.enabled ? [] : model_credential_schema.credential_form_schemas),
|
||||
]
|
||||
}, [
|
||||
|
|
@ -36,21 +47,36 @@ export const useModelFormSchemas = (
|
|||
model_credential_schema?.credential_form_schemas,
|
||||
model_credential_schema?.model,
|
||||
draftConfig?.enabled,
|
||||
model,
|
||||
])
|
||||
|
||||
const formSchemasWithAuthorizationName = useMemo(() => {
|
||||
const authorizationNameSchema = {
|
||||
type: FormTypeEnum.textInput,
|
||||
variable: '__authorization_name__',
|
||||
label: t('plugin.auth.authorizationName'),
|
||||
required: true,
|
||||
}
|
||||
|
||||
return [
|
||||
{
|
||||
type: FormTypeEnum.textInput,
|
||||
variable: '__authorization_name__',
|
||||
label: t('plugin.auth.authorizationName'),
|
||||
required: true,
|
||||
},
|
||||
authorizationNameSchema,
|
||||
...formSchemas,
|
||||
]
|
||||
}, [formSchemas, t])
|
||||
|
||||
const formValues = useMemo(() => {
|
||||
let result = {}
|
||||
if (credentials)
|
||||
result = { ...credentials }
|
||||
if (credential)
|
||||
result = { ...result, __authorization_name__: credential?.credential_name }
|
||||
if (model)
|
||||
result = { ...result, __model_name: model?.model, __model_type: model?.model_type }
|
||||
return result
|
||||
}, [credentials, credential, model])
|
||||
|
||||
return {
|
||||
formSchemas: formSchemasWithAuthorizationName,
|
||||
formValues,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,3 +3,4 @@ export { default as SwitchCredentialInLoadBalancing } from './switch-credential-
|
|||
export { default as AddCredentialInLoadBalancing } from './add-credential-in-load-balancing'
|
||||
export { default as AddCustomModel } from './add-custom-model'
|
||||
export { default as ConfigProvider } from './config-provider'
|
||||
export { default as ConfigModel } from './config-model'
|
||||
|
|
|
|||
|
|
@ -10,13 +10,11 @@ import Indicator from '@/app/components/header/indicator'
|
|||
import Badge from '@/app/components/base/badge'
|
||||
import Authorized from './authorized'
|
||||
import type {
|
||||
Credential,
|
||||
ModelLoadBalancingConfig,
|
||||
ModelProvider,
|
||||
} from '../declarations'
|
||||
import { ConfigurationMethodEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
import { useCredentialStatus } from './hooks'
|
||||
import { useModelModalHandler } from '../hooks'
|
||||
import cn from '@/utils/classnames'
|
||||
|
||||
type SwitchCredentialInLoadBalancingProps = {
|
||||
|
|
@ -27,42 +25,16 @@ type SwitchCredentialInLoadBalancingProps = {
|
|||
const SwitchCredentialInLoadBalancing = ({
|
||||
provider,
|
||||
draftConfig,
|
||||
setDraftConfig,
|
||||
}: SwitchCredentialInLoadBalancingProps) => {
|
||||
const { t } = useTranslation()
|
||||
const {
|
||||
available_credentials,
|
||||
current_credential_name,
|
||||
} = useCredentialStatus(provider)
|
||||
const handleOpenModal = useModelModalHandler()
|
||||
console.log(draftConfig, 'draftConfig')
|
||||
|
||||
const handleSetup = useCallback((credential?: Credential) => {
|
||||
handleOpenModal(provider, ConfigurationMethodEnum.predefinedModel, undefined, credential)
|
||||
}, [handleOpenModal, provider])
|
||||
|
||||
const handleItemClick = useCallback((id: string) => {
|
||||
setDraftConfig((prev) => {
|
||||
if (!prev)
|
||||
return prev
|
||||
const newConfigs = [...prev.configs]
|
||||
const index = newConfigs.findIndex(config => config.name === '__inherit__')
|
||||
const inheritConfig = newConfigs[index]
|
||||
const modifiedConfig = inheritConfig ? {
|
||||
...inheritConfig,
|
||||
credential_id: id,
|
||||
} : {
|
||||
name: '__inherit__',
|
||||
credential_id: id,
|
||||
credentials: {},
|
||||
}
|
||||
newConfigs.splice(index, 1, modifiedConfig)
|
||||
return {
|
||||
...prev,
|
||||
configs: newConfigs,
|
||||
}
|
||||
})
|
||||
}, [setDraftConfig])
|
||||
const handleItemClick = useCallback(() => {
|
||||
console.log('handleItemClick', draftConfig)
|
||||
}, [])
|
||||
|
||||
const renderTrigger = useCallback(() => {
|
||||
const selectedCredentialId = draftConfig?.configs.find(config => config.name === '__inherit__')?.credential_id
|
||||
|
|
@ -96,12 +68,21 @@ const SwitchCredentialInLoadBalancing = ({
|
|||
|
||||
return (
|
||||
<Authorized
|
||||
provider={provider.provider}
|
||||
credentials={available_credentials || []}
|
||||
onSetup={handleSetup}
|
||||
provider={provider}
|
||||
configurationMethod={ConfigurationMethodEnum.customizableModel}
|
||||
items={[
|
||||
{
|
||||
model: {
|
||||
model: t('common.modelProvider.modelCredentials'),
|
||||
} as any,
|
||||
credentials: available_credentials || [],
|
||||
},
|
||||
]}
|
||||
renderTrigger={renderTrigger}
|
||||
onItemClick={handleItemClick}
|
||||
disableSetDefault
|
||||
isModelCredential
|
||||
enableAddModelCredential
|
||||
bottomAddModelCredentialText={t('common.modelProvider.addModelCredential')}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,33 +38,35 @@ import type {
|
|||
import Loading from '@/app/components/base/loading'
|
||||
import {
|
||||
useAuth,
|
||||
useGetCredential,
|
||||
useCredentialData,
|
||||
} from '@/app/components/header/account-setting/model-provider-page/model-auth/hooks'
|
||||
|
||||
type ModelModalProps = {
|
||||
provider: ModelProvider
|
||||
model?: CustomModel
|
||||
credential?: Credential
|
||||
configurateMethod: ConfigurationMethodEnum
|
||||
currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields
|
||||
onCancel: () => void
|
||||
onSave: () => void
|
||||
model?: CustomModel
|
||||
credential?: Credential
|
||||
isModelCredential?: boolean
|
||||
}
|
||||
|
||||
const ModelModal: FC<ModelModalProps> = ({
|
||||
provider,
|
||||
model,
|
||||
configurateMethod,
|
||||
currentCustomConfigurationModelFixedFields,
|
||||
credential,
|
||||
onCancel,
|
||||
onSave,
|
||||
model,
|
||||
credential,
|
||||
isModelCredential,
|
||||
}) => {
|
||||
const providerFormSchemaPredefined = configurateMethod === ConfigurationMethodEnum.predefinedModel
|
||||
const {
|
||||
isLoading,
|
||||
data: credentialData = {},
|
||||
} = useGetCredential(provider.provider, credential?.credential_id, model)
|
||||
credentialData,
|
||||
} = useCredentialData(provider, providerFormSchemaPredefined, isModelCredential, credential, model)
|
||||
const {
|
||||
handleSaveCredential,
|
||||
handleConfirmDelete,
|
||||
|
|
@ -72,7 +74,7 @@ const ModelModal: FC<ModelModalProps> = ({
|
|||
closeConfirmDelete,
|
||||
openConfirmDelete,
|
||||
doingAction,
|
||||
} = useAuth(provider, configurateMethod, currentCustomConfigurationModelFixedFields, onSave)
|
||||
} = useAuth(provider, configurateMethod, currentCustomConfigurationModelFixedFields, isModelCredential, onSave)
|
||||
const {
|
||||
credentials: formSchemasValue,
|
||||
} = credentialData as any
|
||||
|
|
@ -81,7 +83,10 @@ const ModelModal: FC<ModelModalProps> = ({
|
|||
const isEditMode = !!formSchemasValue && isCurrentWorkspaceManager
|
||||
const { t } = useTranslation()
|
||||
const language = useLanguage()
|
||||
const { formSchemas } = useModelFormSchemas(provider, providerFormSchemaPredefined)
|
||||
const {
|
||||
formSchemas,
|
||||
formValues,
|
||||
} = useModelFormSchemas(provider, providerFormSchemaPredefined, formSchemasValue, credential, model)
|
||||
const formRef = useRef<FormRefObject>(null)
|
||||
|
||||
const handleSave = useCallback(async () => {
|
||||
|
|
@ -152,10 +157,7 @@ const ModelModal: FC<ModelModalProps> = ({
|
|||
showRadioUI: formSchema.type === FormTypeEnum.radio,
|
||||
}
|
||||
}) as FormSchema[]}
|
||||
defaultValues={{
|
||||
...formSchemasValue,
|
||||
__authorization_name__: credential?.credential_name,
|
||||
}}
|
||||
defaultValues={formValues}
|
||||
inputClassName='justify-start'
|
||||
ref={formRef}
|
||||
/>
|
||||
|
|
@ -186,7 +188,7 @@ const ModelModal: FC<ModelModalProps> = ({
|
|||
variant='warning'
|
||||
size='large'
|
||||
className='mr-2'
|
||||
onClick={() => openConfirmDelete(credential?.credential_id, model)}
|
||||
onClick={() => openConfirmDelete(credential, model)}
|
||||
>
|
||||
{t('common.operation.remove')}
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -1,264 +0,0 @@
|
|||
import type { FC } from 'react'
|
||||
import {
|
||||
memo,
|
||||
useEffect,
|
||||
useMemo,
|
||||
useRef,
|
||||
useState,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import type {
|
||||
CustomConfigurationModelFixedFields,
|
||||
ModelLoadBalancingConfigEntry,
|
||||
ModelProvider,
|
||||
} from '../declarations'
|
||||
import {
|
||||
ConfigurationMethodEnum,
|
||||
FormTypeEnum,
|
||||
} from '../declarations'
|
||||
|
||||
import {
|
||||
useLanguage,
|
||||
} from '../hooks'
|
||||
import { ValidatedStatus } from '../../key-validator/declarations'
|
||||
import { validateLoadBalancingCredentials } from '../utils'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { Lock01 } from '@/app/components/base/icons/src/vender/solid/security'
|
||||
import { LinkExternal02 } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import { useToastContext } from '@/app/components/base/toast'
|
||||
import Confirm from '@/app/components/base/confirm'
|
||||
import AuthForm from '@/app/components/base/form/form-scenarios/auth'
|
||||
import type {
|
||||
FormRefObject,
|
||||
FormSchema,
|
||||
} from '@/app/components/base/form/types'
|
||||
|
||||
type ModelModalProps = {
|
||||
provider: ModelProvider
|
||||
configurationMethod: ConfigurationMethodEnum
|
||||
currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields
|
||||
entry?: ModelLoadBalancingConfigEntry
|
||||
onCancel: () => void
|
||||
onSave: (entry: ModelLoadBalancingConfigEntry) => void
|
||||
onRemove: () => void
|
||||
}
|
||||
|
||||
const ModelLoadBalancingEntryModal: FC<ModelModalProps> = ({
|
||||
provider,
|
||||
configurationMethod,
|
||||
currentCustomConfigurationModelFixedFields,
|
||||
entry,
|
||||
onCancel,
|
||||
onSave,
|
||||
onRemove,
|
||||
}) => {
|
||||
const providerFormSchemaPredefined = configurationMethod === ConfigurationMethodEnum.predefinedModel
|
||||
const isEditMode = !!entry
|
||||
const { t } = useTranslation()
|
||||
const { notify } = useToastContext()
|
||||
const language = useLanguage()
|
||||
const [loading, setLoading] = useState(false)
|
||||
const [showConfirm, setShowConfirm] = useState(false)
|
||||
const formSchemas = useMemo(() => {
|
||||
return [
|
||||
{
|
||||
type: FormTypeEnum.textInput,
|
||||
label: {
|
||||
en_US: 'Config Name',
|
||||
zh_Hans: '配置名称',
|
||||
},
|
||||
variable: 'name',
|
||||
required: true,
|
||||
show_on: [],
|
||||
placeholder: {
|
||||
en_US: 'Enter your Config Name here',
|
||||
zh_Hans: '输入配置名称',
|
||||
},
|
||||
} as any,
|
||||
...(
|
||||
providerFormSchemaPredefined
|
||||
? provider.provider_credential_schema.credential_form_schemas
|
||||
: provider.model_credential_schema.credential_form_schemas
|
||||
),
|
||||
]
|
||||
}, [
|
||||
providerFormSchemaPredefined,
|
||||
provider.provider_credential_schema?.credential_form_schemas,
|
||||
provider.model_credential_schema?.credential_form_schemas,
|
||||
])
|
||||
const formRef = useRef<FormRefObject>(null)
|
||||
|
||||
const [
|
||||
defaultFormSchemaValue,
|
||||
] = useMemo(() => {
|
||||
const defaultFormSchemaValue: Record<string, string | number> = {}
|
||||
|
||||
formSchemas.forEach((formSchema) => {
|
||||
if (formSchema.default)
|
||||
defaultFormSchemaValue[formSchema.variable] = formSchema.default
|
||||
})
|
||||
|
||||
return [
|
||||
defaultFormSchemaValue,
|
||||
]
|
||||
}, [formSchemas])
|
||||
const [initialValue, setInitialValue] = useState<ModelLoadBalancingConfigEntry['credentials']>()
|
||||
useEffect(() => {
|
||||
if (entry && !initialValue) {
|
||||
setInitialValue({
|
||||
...defaultFormSchemaValue,
|
||||
...entry.credentials,
|
||||
id: entry.id,
|
||||
name: entry.name,
|
||||
} as Record<string, string | undefined | boolean>)
|
||||
}
|
||||
}, [entry, defaultFormSchemaValue, initialValue])
|
||||
const formSchemasValue = useMemo(() => ({
|
||||
...currentCustomConfigurationModelFixedFields,
|
||||
...initialValue,
|
||||
}), [currentCustomConfigurationModelFixedFields, initialValue])
|
||||
|
||||
const handleSave = async () => {
|
||||
try {
|
||||
setLoading(true)
|
||||
const {
|
||||
isCheckValidated,
|
||||
values,
|
||||
} = formRef.current?.getFormValues({
|
||||
needCheckValidatedValues: true,
|
||||
needTransformWhenSecretFieldIsPristine: true,
|
||||
}) || { isCheckValidated: false, values: {} }
|
||||
if (!isCheckValidated)
|
||||
return
|
||||
const res = await validateLoadBalancingCredentials(
|
||||
providerFormSchemaPredefined,
|
||||
provider.provider,
|
||||
values,
|
||||
entry?.id,
|
||||
)
|
||||
if (res.status === ValidatedStatus.Success) {
|
||||
// notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
|
||||
const { __model_type, __model_name, name, ...credentials } = values
|
||||
onSave({
|
||||
...(entry || {}),
|
||||
name: name as string,
|
||||
credentials: credentials as Record<string, string | boolean | undefined>,
|
||||
})
|
||||
// onCancel()
|
||||
}
|
||||
else {
|
||||
notify({ type: 'error', message: res.message || '' })
|
||||
}
|
||||
}
|
||||
finally {
|
||||
setLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
const handleRemove = () => {
|
||||
onRemove?.()
|
||||
}
|
||||
|
||||
return (
|
||||
<PortalToFollowElem open>
|
||||
<PortalToFollowElemContent className='z-[60] h-full w-full'>
|
||||
<div className='fixed inset-0 flex items-center justify-center bg-black/[.25]'>
|
||||
<div className='mx-2 max-h-[calc(100vh-120px)] w-[640px] overflow-y-auto rounded-2xl bg-white shadow-xl'>
|
||||
<div className='px-8 pt-8'>
|
||||
<div className='mb-2 flex items-center justify-between'>
|
||||
<div className='text-xl font-semibold text-gray-900'>{t(isEditMode ? 'common.modelProvider.editConfig' : 'common.modelProvider.addConfig')}</div>
|
||||
</div>
|
||||
<AuthForm
|
||||
formSchemas={formSchemas.map((formSchema) => {
|
||||
return {
|
||||
...formSchema,
|
||||
name: formSchema.variable,
|
||||
showRadioUI: formSchema.type === FormTypeEnum.radio,
|
||||
}
|
||||
}) as FormSchema[]}
|
||||
defaultValues={formSchemasValue}
|
||||
inputClassName='justify-start'
|
||||
ref={formRef}
|
||||
/>
|
||||
<div className='sticky bottom-0 flex flex-wrap items-center justify-between gap-y-2 bg-white py-6'>
|
||||
{
|
||||
(provider.help && (provider.help.title || provider.help.url))
|
||||
? (
|
||||
<a
|
||||
href={provider.help?.url[language] || provider.help?.url.en_US}
|
||||
target='_blank' rel='noopener noreferrer'
|
||||
className='inline-flex items-center text-xs text-primary-600'
|
||||
onClick={e => !provider.help.url && e.preventDefault()}
|
||||
>
|
||||
{provider.help.title?.[language] || provider.help.url[language] || provider.help.title?.en_US || provider.help.url.en_US}
|
||||
<LinkExternal02 className='ml-1 h-3 w-3' />
|
||||
</a>
|
||||
)
|
||||
: <div />
|
||||
}
|
||||
<div>
|
||||
{
|
||||
isEditMode && (
|
||||
<Button
|
||||
size='large'
|
||||
className='mr-2 text-[#D92D20]'
|
||||
onClick={() => setShowConfirm(true)}
|
||||
>
|
||||
{t('common.operation.remove')}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
<Button
|
||||
size='large'
|
||||
className='mr-2'
|
||||
onClick={onCancel}
|
||||
>
|
||||
{t('common.operation.cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
size='large'
|
||||
variant='primary'
|
||||
onClick={handleSave}
|
||||
disabled={loading}
|
||||
>
|
||||
{t('common.operation.save')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className='border-t-[0.5px] border-t-black/5'>
|
||||
<div className='flex items-center justify-center bg-gray-50 py-3 text-xs text-gray-500'>
|
||||
<Lock01 className='mr-1 h-3 w-3 text-gray-500' />
|
||||
{t('common.modelProvider.encrypted.front')}
|
||||
<a
|
||||
className='mx-1 text-primary-600'
|
||||
target='_blank' rel='noopener noreferrer'
|
||||
href='https://pycryptodome.readthedocs.io/en/latest/src/cipher/oaep.html'
|
||||
>
|
||||
PKCS1_OAEP
|
||||
</a>
|
||||
{t('common.modelProvider.encrypted.back')}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
showConfirm && (
|
||||
<Confirm
|
||||
title={t('common.modelProvider.confirmDelete')}
|
||||
isShow={showConfirm}
|
||||
onCancel={() => setShowConfirm(false)}
|
||||
onConfirm={handleRemove}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(ModelLoadBalancingEntryModal)
|
||||
|
|
@ -70,11 +70,11 @@ const CredentialPanel = ({
|
|||
}
|
||||
const credentialLabel = useMemo(() => {
|
||||
if (!hasCredential)
|
||||
return t('common.model.unAuthorized')
|
||||
return t('common.modelProvider.auth.unAuthorized')
|
||||
if (authorized)
|
||||
return current_credential_name
|
||||
if (authRemoved)
|
||||
return t('common.model.authRemoved')
|
||||
return t('common.modelProvider.auth.authRemoved')
|
||||
|
||||
return ''
|
||||
}, [authorized, authRemoved, current_credential_name, hasCredential])
|
||||
|
|
|
|||
|
|
@ -7,12 +7,10 @@ import {
|
|||
RiLoader2Line,
|
||||
} from '@remixicon/react'
|
||||
import type {
|
||||
CustomConfigurationModelFixedFields,
|
||||
ModelItem,
|
||||
ModelProvider,
|
||||
} from '../declarations'
|
||||
import { ConfigurationMethodEnum } from '../declarations'
|
||||
import type { Credential } from '../declarations'
|
||||
import {
|
||||
MODEL_PROVIDER_QUOTA_GET_PAID,
|
||||
modelTypeFormat,
|
||||
|
|
@ -22,23 +20,21 @@ import ModelBadge from '../model-badge'
|
|||
import CredentialPanel from './credential-panel'
|
||||
import QuotaPanel from './quota-panel'
|
||||
import ModelList from './model-list'
|
||||
import AddModelButton from './add-model-button'
|
||||
import { fetchModelProviderModelList } from '@/service/common'
|
||||
import { useEventEmitterContextContext } from '@/context/event-emitter'
|
||||
import { IS_CE_EDITION } from '@/config'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import cn from '@/utils/classnames'
|
||||
import { AddCustomModel } from '@/app/components/header/account-setting/model-provider-page/model-auth'
|
||||
|
||||
export const UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST = 'UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST'
|
||||
type ProviderAddedCardProps = {
|
||||
notConfigured?: boolean
|
||||
provider: ModelProvider
|
||||
onOpenModal: (configurationMethod: ConfigurationMethodEnum, currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields, credential?: Credential) => void
|
||||
}
|
||||
const ProviderAddedCard: FC<ProviderAddedCardProps> = ({
|
||||
notConfigured,
|
||||
provider,
|
||||
onOpenModal,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const { eventEmitter } = useEventEmitterContextContext()
|
||||
|
|
@ -159,9 +155,9 @@ const ProviderAddedCard: FC<ProviderAddedCardProps> = ({
|
|||
)}
|
||||
{
|
||||
configurationMethods.includes(ConfigurationMethodEnum.customizableModel) && isCurrentWorkspaceManager && (
|
||||
<AddModelButton
|
||||
onClick={() => onOpenModal(ConfigurationMethodEnum.customizableModel)}
|
||||
className='flex'
|
||||
<AddCustomModel
|
||||
provider={provider}
|
||||
configurationMethod={ConfigurationMethodEnum.customizableModel}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
@ -174,7 +170,6 @@ const ProviderAddedCard: FC<ProviderAddedCardProps> = ({
|
|||
provider={provider}
|
||||
models={modelList}
|
||||
onCollapse={() => setCollapsed(true)}
|
||||
onConfig={currentCustomConfigurationModelFixedFields => onOpenModal(ConfigurationMethodEnum.customizableModel, currentCustomConfigurationModelFixedFields)}
|
||||
onChange={(provider: string) => getModelList(provider)}
|
||||
/>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,31 +1,29 @@
|
|||
import { memo, useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useDebounceFn } from 'ahooks'
|
||||
import type { CustomConfigurationModelFixedFields, ModelItem, ModelProvider } from '../declarations'
|
||||
import { ConfigurationMethodEnum, ModelStatusEnum } from '../declarations'
|
||||
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'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { Balance } from '@/app/components/base/icons/src/vender/line/financeAndECommerce'
|
||||
import { Settings01 } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import Switch from '@/app/components/base/switch'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import { useProviderContext, useProviderContextSelector } from '@/context/provider-context'
|
||||
import { disableModel, enableModel } from '@/service/common'
|
||||
import { Plan } from '@/app/components/billing/type'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import { ConfigModel } from '../model-auth'
|
||||
|
||||
export type ModelListItemProps = {
|
||||
model: ModelItem
|
||||
provider: ModelProvider
|
||||
isConfigurable: boolean
|
||||
onConfig: (currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields) => void
|
||||
onModifyLoadBalancing?: (model: ModelItem) => void
|
||||
}
|
||||
|
||||
const ModelListItem = ({ model, provider, isConfigurable, onConfig, onModifyLoadBalancing }: ModelListItemProps) => {
|
||||
const ModelListItem = ({ model, provider, isConfigurable, onModifyLoadBalancing }: ModelListItemProps) => {
|
||||
const { t } = useTranslation()
|
||||
const { plan } = useProviderContext()
|
||||
const modelLoadBalancingEnabled = useProviderContextSelector(state => state.modelLoadBalancingEnabled)
|
||||
|
|
@ -46,7 +44,7 @@ const ModelListItem = ({ model, provider, isConfigurable, onConfig, onModifyLoad
|
|||
|
||||
return (
|
||||
<div
|
||||
key={model.model}
|
||||
key={`${model.model}-${model.fetch_from}`}
|
||||
className={classNames(
|
||||
'group flex h-8 items-center rounded-lg pl-2 pr-2.5',
|
||||
isConfigurable && 'hover:bg-components-panel-on-panel-item-bg-hover',
|
||||
|
|
@ -74,29 +72,12 @@ const ModelListItem = ({ model, provider, isConfigurable, onConfig, onModifyLoad
|
|||
</ModelName>
|
||||
<div className='flex shrink-0 items-center'>
|
||||
{
|
||||
model.fetch_from === ConfigurationMethodEnum.customizableModel
|
||||
? (isCurrentWorkspaceManager && (
|
||||
<Button
|
||||
size='small'
|
||||
className='hidden group-hover:flex'
|
||||
onClick={() => onConfig({ __model_name: model.model, __model_type: model.model_type })}
|
||||
>
|
||||
<Settings01 className='mr-1 h-3.5 w-3.5' />
|
||||
{t('common.modelProvider.config')}
|
||||
</Button>
|
||||
))
|
||||
: (isCurrentWorkspaceManager && (modelLoadBalancingEnabled || plan.type === Plan.sandbox) && !model.deprecated && [ModelStatusEnum.active, ModelStatusEnum.disabled].includes(model.status))
|
||||
? (
|
||||
<Button
|
||||
size='small'
|
||||
className='opacity-0 transition-opacity group-hover:opacity-100'
|
||||
onClick={() => onModifyLoadBalancing?.(model)}
|
||||
>
|
||||
<Balance className='mr-1 h-3.5 w-3.5' />
|
||||
{t('common.modelProvider.configLoadBalancing')}
|
||||
</Button>
|
||||
)
|
||||
: null
|
||||
(isCurrentWorkspaceManager && (modelLoadBalancingEnabled || plan.type === Plan.sandbox) && !model.deprecated && [ModelStatusEnum.active, ModelStatusEnum.disabled].includes(model.status)) && (
|
||||
<ConfigModel
|
||||
className='hidden group-hover:flex'
|
||||
onClick={() => onModifyLoadBalancing?.(model)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
{
|
||||
model.deprecated
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import {
|
|||
} from '@remixicon/react'
|
||||
import type {
|
||||
Credential,
|
||||
CustomConfigurationModelFixedFields,
|
||||
ModelItem,
|
||||
ModelProvider,
|
||||
} from '../declarations'
|
||||
|
|
@ -17,33 +16,30 @@ import {
|
|||
import ModelListItem from './model-list-item'
|
||||
import { useModalContextSelector } from '@/context/modal-context'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import { useCustomModels } from '@/app/components/header/account-setting/model-provider-page/model-auth/hooks'
|
||||
import { AddCustomModel } from '@/app/components/header/account-setting/model-provider-page/model-auth'
|
||||
|
||||
type ModelListProps = {
|
||||
provider: ModelProvider
|
||||
models: ModelItem[]
|
||||
onCollapse: () => void
|
||||
onConfig: (currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields) => void
|
||||
onChange?: (provider: string) => void
|
||||
}
|
||||
const ModelList: FC<ModelListProps> = ({
|
||||
provider,
|
||||
models,
|
||||
onCollapse,
|
||||
onConfig,
|
||||
onChange,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const configurativeMethods = provider.configurate_methods.filter(method => method !== ConfigurationMethodEnum.fetchFromRemote)
|
||||
const { isCurrentWorkspaceManager } = useAppContext()
|
||||
const isConfigurable = configurativeMethods.includes(ConfigurationMethodEnum.customizableModel)
|
||||
const customModels = useCustomModels(provider)
|
||||
const setShowModelLoadBalancingModal = useModalContextSelector(state => state.setShowModelLoadBalancingModal)
|
||||
const onModifyLoadBalancing = useCallback((model: ModelItem, credential?: Credential) => {
|
||||
setShowModelLoadBalancingModal({
|
||||
provider,
|
||||
credential,
|
||||
configurateMethod: model.fetch_from,
|
||||
model: model!,
|
||||
open: !!model,
|
||||
onClose: () => setShowModelLoadBalancingModal(null),
|
||||
|
|
@ -75,7 +71,6 @@ const ModelList: FC<ModelListProps> = ({
|
|||
provider={provider}
|
||||
configurationMethod={ConfigurationMethodEnum.customizableModel}
|
||||
currentCustomConfigurationModelFixedFields={undefined}
|
||||
models={customModels}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
|
@ -84,12 +79,11 @@ const ModelList: FC<ModelListProps> = ({
|
|||
{
|
||||
models.map(model => (
|
||||
<ModelListItem
|
||||
key={model.model}
|
||||
key={`${model.model}-${model.fetch_from}`}
|
||||
{...{
|
||||
model,
|
||||
provider,
|
||||
isConfigurable,
|
||||
onConfig,
|
||||
onModifyLoadBalancing,
|
||||
}}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -3,23 +3,32 @@ import { useCallback } from 'react'
|
|||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
RiDeleteBinLine,
|
||||
RiEqualizer2Line,
|
||||
} from '@remixicon/react'
|
||||
import type { ConfigurationMethodEnum, CustomConfigurationModelFixedFields, ModelLoadBalancingConfig, ModelLoadBalancingConfigEntry, ModelProvider } from '../declarations'
|
||||
import type {
|
||||
Credential,
|
||||
CustomConfigurationModelFixedFields,
|
||||
CustomModelCredential,
|
||||
ModelCredential,
|
||||
ModelLoadBalancingConfig,
|
||||
ModelLoadBalancingConfigEntry,
|
||||
ModelProvider,
|
||||
} from '../declarations'
|
||||
import { ConfigurationMethodEnum } from '../declarations'
|
||||
import Indicator from '../../../indicator'
|
||||
import CooldownTimer from './cooldown-timer'
|
||||
import classNames from '@/utils/classnames'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import Switch from '@/app/components/base/switch'
|
||||
import { Balance } from '@/app/components/base/icons/src/vender/line/financeAndECommerce'
|
||||
import { Edit02 } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import { AlertTriangle } from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback'
|
||||
import { useModalContextSelector } from '@/context/modal-context'
|
||||
import UpgradeBtn from '@/app/components/billing/upgrade-btn'
|
||||
import s from '@/app/components/custom/style.module.css'
|
||||
import GridMask from '@/app/components/base/grid-mask'
|
||||
import { useProviderContextSelector } from '@/context/provider-context'
|
||||
import { IS_CE_EDITION } from '@/config'
|
||||
import { AddCredentialInLoadBalancing } from '@/app/components/header/account-setting/model-provider-page/model-auth'
|
||||
import { useModelModalHandler } from '@/app/components/header/account-setting/model-provider-page/hooks'
|
||||
|
||||
export type ModelLoadBalancingConfigsProps = {
|
||||
draftConfig?: ModelLoadBalancingConfig
|
||||
|
|
@ -29,19 +38,26 @@ export type ModelLoadBalancingConfigsProps = {
|
|||
currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields
|
||||
withSwitch?: boolean
|
||||
className?: string
|
||||
modelCredential: ModelCredential
|
||||
onUpdate?: () => void
|
||||
model: CustomModelCredential
|
||||
}
|
||||
|
||||
const ModelLoadBalancingConfigs = ({
|
||||
draftConfig,
|
||||
setDraftConfig,
|
||||
provider,
|
||||
model,
|
||||
configurationMethod,
|
||||
currentCustomConfigurationModelFixedFields,
|
||||
withSwitch = false,
|
||||
className,
|
||||
modelCredential,
|
||||
onUpdate,
|
||||
}: ModelLoadBalancingConfigsProps) => {
|
||||
const { t } = useTranslation()
|
||||
const modelLoadBalancingEnabled = useProviderContextSelector(state => state.modelLoadBalancingEnabled)
|
||||
const handleOpenModal = useModelModalHandler()
|
||||
|
||||
const updateConfigEntry = useCallback(
|
||||
(
|
||||
|
|
@ -66,6 +82,21 @@ const ModelLoadBalancingConfigs = ({
|
|||
[setDraftConfig],
|
||||
)
|
||||
|
||||
const addConfigEntry = useCallback((credential: Credential) => {
|
||||
setDraftConfig((prev: any) => {
|
||||
if (!prev)
|
||||
return prev
|
||||
return {
|
||||
...prev,
|
||||
configs: [...prev.configs, {
|
||||
credential_id: credential.credential_id,
|
||||
enabled: true,
|
||||
name: credential.credential_name,
|
||||
}],
|
||||
}
|
||||
})
|
||||
}, [setDraftConfig])
|
||||
|
||||
const toggleModalBalancing = useCallback((enabled: boolean) => {
|
||||
if ((modelLoadBalancingEnabled || !enabled) && draftConfig) {
|
||||
setDraftConfig({
|
||||
|
|
@ -82,54 +113,6 @@ const ModelLoadBalancingConfigs = ({
|
|||
}))
|
||||
}, [updateConfigEntry])
|
||||
|
||||
const setShowModelLoadBalancingEntryModal = useModalContextSelector(state => state.setShowModelLoadBalancingEntryModal)
|
||||
|
||||
const toggleEntryModal = useCallback((index?: number, entry?: ModelLoadBalancingConfigEntry) => {
|
||||
setShowModelLoadBalancingEntryModal({
|
||||
payload: {
|
||||
currentProvider: provider,
|
||||
currentConfigurationMethod: configurationMethod,
|
||||
currentCustomConfigurationModelFixedFields,
|
||||
entry,
|
||||
index,
|
||||
},
|
||||
onSaveCallback: ({ entry: result }) => {
|
||||
if (entry) {
|
||||
// edit
|
||||
setDraftConfig(prev => ({
|
||||
...prev,
|
||||
enabled: !!prev?.enabled,
|
||||
configs: prev?.configs.map((config, i) => i === index ? result! : config) || [],
|
||||
}))
|
||||
}
|
||||
else {
|
||||
// add
|
||||
setDraftConfig(prev => ({
|
||||
...prev,
|
||||
enabled: !!prev?.enabled,
|
||||
configs: (prev?.configs || []).concat([{ ...result!, enabled: true }]),
|
||||
}))
|
||||
}
|
||||
},
|
||||
onRemoveCallback: ({ index }) => {
|
||||
if (index !== undefined && (draftConfig?.configs?.length ?? 0) > index) {
|
||||
setDraftConfig(prev => ({
|
||||
...prev,
|
||||
enabled: !!prev?.enabled,
|
||||
configs: prev?.configs.filter((_, i) => i !== index) || [],
|
||||
}))
|
||||
}
|
||||
},
|
||||
})
|
||||
}, [
|
||||
configurationMethod,
|
||||
currentCustomConfigurationModelFixedFields,
|
||||
draftConfig?.configs?.length,
|
||||
provider,
|
||||
setDraftConfig,
|
||||
setShowModelLoadBalancingEntryModal,
|
||||
])
|
||||
|
||||
const clearCountdown = useCallback((index: number) => {
|
||||
updateConfigEntry(index, ({ ttl: _, ...entry }) => {
|
||||
return {
|
||||
|
|
@ -211,9 +194,21 @@ const ModelLoadBalancingConfigs = ({
|
|||
<div className='flex items-center gap-1 opacity-0 transition-opacity group-hover:opacity-100'>
|
||||
<span
|
||||
className='flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-components-button-secondary-bg text-text-tertiary transition-colors hover:bg-components-button-secondary-bg-hover'
|
||||
onClick={() => toggleEntryModal(index, config)}
|
||||
onClick={() => {
|
||||
handleOpenModal(
|
||||
provider,
|
||||
configurationMethod,
|
||||
currentCustomConfigurationModelFixedFields,
|
||||
configurationMethod === ConfigurationMethodEnum.customizableModel,
|
||||
(config.credential_id && config.name) ? {
|
||||
credential_id: config.credential_id,
|
||||
credential_name: config.name,
|
||||
} : undefined,
|
||||
model,
|
||||
)
|
||||
}}
|
||||
>
|
||||
<Edit02 className='h-4 w-4' />
|
||||
<RiEqualizer2Line className='h-4 w-4' />
|
||||
</span>
|
||||
<span
|
||||
className='flex h-8 w-8 cursor-pointer items-center justify-center rounded-lg bg-components-button-secondary-bg text-text-tertiary transition-colors hover:bg-components-button-secondary-bg-hover'
|
||||
|
|
@ -237,13 +232,17 @@ const ModelLoadBalancingConfigs = ({
|
|||
})}
|
||||
<AddCredentialInLoadBalancing
|
||||
provider={provider}
|
||||
onSetup={() => toggleEntryModal()}
|
||||
model={model}
|
||||
configurationMethod={configurationMethod}
|
||||
modelCredential={modelCredential}
|
||||
onSelectCredential={addConfigEntry}
|
||||
onUpdate={onUpdate}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{
|
||||
draftConfig.enabled && draftConfig.configs.length < 2 && (
|
||||
<div className='flex h-[34px] items-center border-t border-t-divider-subtle bg-components-panel-bg px-6 text-xs text-text-secondary'>
|
||||
<div className='flex h-[34px] items-center rounded-b-xl border-t border-t-divider-subtle bg-components-panel-bg px-6 text-xs text-text-secondary'>
|
||||
<AlertTriangle className='mr-1 h-3 w-3 text-[#f79009]' />
|
||||
{t('common.modelProvider.loadBalancingLeastKeyWarning')}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { memo, useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import useSWR from 'swr'
|
||||
import type {
|
||||
Credential,
|
||||
ModelItem,
|
||||
|
|
@ -8,21 +7,27 @@ import type {
|
|||
ModelLoadBalancingConfigEntry,
|
||||
ModelProvider,
|
||||
} from '../declarations'
|
||||
import { FormTypeEnum } from '../declarations'
|
||||
import {
|
||||
ConfigurationMethodEnum,
|
||||
FormTypeEnum,
|
||||
} from '../declarations'
|
||||
import ModelIcon from '../model-icon'
|
||||
import ModelName from '../model-name'
|
||||
import { savePredefinedLoadBalancingConfig } from '../utils'
|
||||
import ModelLoadBalancingConfigs from './model-load-balancing-configs'
|
||||
import classNames from '@/utils/classnames'
|
||||
import Modal from '@/app/components/base/modal'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { fetchModelLoadBalancingConfig } from '@/service/common'
|
||||
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,
|
||||
} from '@/service/use-models'
|
||||
|
||||
export type ModelLoadBalancingModalProps = {
|
||||
provider: ModelProvider
|
||||
configurateMethod: ConfigurationMethodEnum
|
||||
model: ModelItem
|
||||
credential?: Credential
|
||||
open?: boolean
|
||||
|
|
@ -33,6 +38,7 @@ export type ModelLoadBalancingModalProps = {
|
|||
// model balancing config modal
|
||||
const ModelLoadBalancingModal = ({
|
||||
provider,
|
||||
configurateMethod,
|
||||
model,
|
||||
credential,
|
||||
open = false,
|
||||
|
|
@ -43,13 +49,18 @@ const ModelLoadBalancingModal = ({
|
|||
const { notify } = useToastContext()
|
||||
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
||||
const { data, mutate } = useSWR(
|
||||
`/workspaces/current/model-providers/${provider.provider}/models/credentials?model=${model.model}&model_type=${model.model_type}`,
|
||||
fetchModelLoadBalancingConfig,
|
||||
)
|
||||
|
||||
const originalConfig = data?.load_balancing
|
||||
const providerFormSchemaPredefined = configurateMethod === ConfigurationMethodEnum.predefinedModel
|
||||
const configFrom = providerFormSchemaPredefined ? 'predefined-model' : 'custom-model'
|
||||
const {
|
||||
isLoading,
|
||||
data,
|
||||
refetch,
|
||||
} = useGetModelCredential(true, provider.provider, credential?.credential_id, model.model, model.model_type, configFrom)
|
||||
const modelCredential = data
|
||||
const {
|
||||
load_balancing,
|
||||
} = modelCredential ?? {}
|
||||
const originalConfig = load_balancing
|
||||
const [draftConfig, setDraftConfig] = useState<ModelLoadBalancingConfig>()
|
||||
const originalConfigMap = useMemo(() => {
|
||||
if (!originalConfig)
|
||||
|
|
@ -90,25 +101,24 @@ const ModelLoadBalancingModal = ({
|
|||
return result
|
||||
}, [extendedSecretFormSchemas, originalConfigMap])
|
||||
|
||||
const { mutateAsync: updateModelLoadBalancingConfig } = useUpdateModelLoadBalancingConfig(provider.provider)
|
||||
const handleSave = async () => {
|
||||
try {
|
||||
setLoading(true)
|
||||
const res = await savePredefinedLoadBalancingConfig(
|
||||
provider.provider,
|
||||
({
|
||||
...(data?.credentials ?? {}),
|
||||
__model_type: model.model_type,
|
||||
__model_name: model.model,
|
||||
}),
|
||||
const res = await updateModelLoadBalancingConfig(
|
||||
{
|
||||
...draftConfig,
|
||||
enabled: Boolean(draftConfig?.enabled),
|
||||
configs: draftConfig!.configs.map(encodeConfigEntrySecretValues),
|
||||
config_from: configFrom,
|
||||
model: model.model,
|
||||
model_type: model.model_type,
|
||||
load_balancing: {
|
||||
...draftConfig,
|
||||
configs: draftConfig!.configs.map(encodeConfigEntrySecretValues),
|
||||
enabled: Boolean(draftConfig?.enabled),
|
||||
},
|
||||
},
|
||||
)
|
||||
if (res.result === 'success') {
|
||||
notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
|
||||
mutate()
|
||||
onSave?.(provider.provider)
|
||||
onClose?.()
|
||||
}
|
||||
|
|
@ -125,7 +135,11 @@ const ModelLoadBalancingModal = ({
|
|||
className='w-[640px] max-w-none px-8 pt-8'
|
||||
title={
|
||||
<div className='pb-3 font-semibold'>
|
||||
<div className='h-[30px]'>{t('common.modelProvider.configLoadBalancing')}</div>
|
||||
<div className='h-[30px]'>{
|
||||
draftConfig?.enabled
|
||||
? t('common.modelProvider.auth.configLoadBalancing')
|
||||
: t('common.modelProvider.auth.configModel')
|
||||
}</div>
|
||||
{Boolean(model) && (
|
||||
<div className='flex h-5 items-center'>
|
||||
<ModelIcon
|
||||
|
|
@ -167,25 +181,34 @@ const ModelLoadBalancingModal = ({
|
|||
<div className='text-sm text-text-secondary'>{t('common.modelProvider.providerManaged')}</div>
|
||||
<div className='text-xs text-text-tertiary'>{t('common.modelProvider.providerManagedDescription')}</div>
|
||||
</div>
|
||||
<SwitchCredentialInLoadBalancing
|
||||
{/* <SwitchCredentialInLoadBalancing
|
||||
draftConfig={draftConfig}
|
||||
setDraftConfig={setDraftConfig}
|
||||
provider={provider}
|
||||
/>
|
||||
/> */}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<ModelLoadBalancingConfigs {...{
|
||||
draftConfig,
|
||||
setDraftConfig,
|
||||
provider,
|
||||
currentCustomConfigurationModelFixedFields: {
|
||||
__model_name: model.model,
|
||||
__model_type: model.model_type,
|
||||
},
|
||||
configurationMethod: model.fetch_from,
|
||||
className: 'mt-2',
|
||||
}} />
|
||||
{
|
||||
modelCredential && (
|
||||
<ModelLoadBalancingConfigs {...{
|
||||
draftConfig,
|
||||
setDraftConfig,
|
||||
provider,
|
||||
currentCustomConfigurationModelFixedFields: {
|
||||
__model_name: model.model,
|
||||
__model_type: model.model_type,
|
||||
},
|
||||
configurationMethod: model.fetch_from,
|
||||
className: 'mt-2',
|
||||
modelCredential,
|
||||
onUpdate: refetch,
|
||||
model: {
|
||||
model: model.model,
|
||||
model_type: model.model_type,
|
||||
},
|
||||
}} />
|
||||
)
|
||||
}
|
||||
</div>
|
||||
|
||||
<div className='mt-6 flex items-center justify-end gap-2'>
|
||||
|
|
@ -196,6 +219,7 @@ const ModelLoadBalancingModal = ({
|
|||
disabled={
|
||||
loading
|
||||
|| (draftConfig?.enabled && (draftConfig?.configs.filter(config => config.enabled).length ?? 0) < 2)
|
||||
|| isLoading
|
||||
}
|
||||
>{t('common.operation.save')}</Button>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -56,9 +56,6 @@ const ExternalAPIModal = dynamic(() => import('@/app/components/datasets/externa
|
|||
const ModelLoadBalancingModal = dynamic(() => import('@/app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-modal'), {
|
||||
ssr: false,
|
||||
})
|
||||
const ModelLoadBalancingEntryModal = dynamic(() => import('@/app/components/header/account-setting/model-provider-page/model-modal/model-load-balancing-entry-modal'), {
|
||||
ssr: false,
|
||||
})
|
||||
const OpeningSettingModal = dynamic(() => import('@/app/components/base/features/new-feature-panel/conversation-opener/modal'), {
|
||||
ssr: false,
|
||||
})
|
||||
|
|
@ -81,6 +78,7 @@ export type ModelModalType = {
|
|||
currentProvider: ModelProvider
|
||||
currentConfigurationMethod: ConfigurationMethodEnum
|
||||
currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields
|
||||
isModelCredential?: boolean
|
||||
credential?: Credential
|
||||
model?: CustomModel
|
||||
}
|
||||
|
|
@ -99,7 +97,6 @@ export type ModalContextState = {
|
|||
setShowModelModal: Dispatch<SetStateAction<ModalState<ModelModalType> | null>>
|
||||
setShowExternalKnowledgeAPIModal: Dispatch<SetStateAction<ModalState<CreateExternalAPIReq> | null>>
|
||||
setShowModelLoadBalancingModal: Dispatch<SetStateAction<ModelLoadBalancingModalProps | null>>
|
||||
setShowModelLoadBalancingEntryModal: Dispatch<SetStateAction<ModalState<LoadBalancingEntryModalType> | null>>
|
||||
setShowOpeningModal: Dispatch<SetStateAction<ModalState<OpeningStatement & {
|
||||
promptVariables?: PromptVariable[]
|
||||
workflowVariables?: InputVar[]
|
||||
|
|
@ -117,7 +114,6 @@ const ModalContext = createContext<ModalContextState>({
|
|||
setShowModelModal: noop,
|
||||
setShowExternalKnowledgeAPIModal: noop,
|
||||
setShowModelLoadBalancingModal: noop,
|
||||
setShowModelLoadBalancingEntryModal: noop,
|
||||
setShowOpeningModal: noop,
|
||||
setShowUpdatePluginModal: noop,
|
||||
})
|
||||
|
|
@ -142,7 +138,6 @@ export const ModalContextProvider = ({
|
|||
const [showModelModal, setShowModelModal] = useState<ModalState<ModelModalType> | null>(null)
|
||||
const [showExternalKnowledgeAPIModal, setShowExternalKnowledgeAPIModal] = useState<ModalState<CreateExternalAPIReq> | null>(null)
|
||||
const [showModelLoadBalancingModal, setShowModelLoadBalancingModal] = useState<ModelLoadBalancingModalProps | null>(null)
|
||||
const [showModelLoadBalancingEntryModal, setShowModelLoadBalancingEntryModal] = useState<ModalState<LoadBalancingEntryModalType> | null>(null)
|
||||
const [showOpeningModal, setShowOpeningModal] = useState<ModalState<OpeningStatement & {
|
||||
promptVariables?: PromptVariable[]
|
||||
workflowVariables?: InputVar[]
|
||||
|
|
@ -208,30 +203,12 @@ export const ModalContextProvider = ({
|
|||
setShowExternalKnowledgeAPIModal(null)
|
||||
}, [showExternalKnowledgeAPIModal])
|
||||
|
||||
const handleCancelModelLoadBalancingEntryModal = useCallback(() => {
|
||||
showModelLoadBalancingEntryModal?.onCancelCallback?.()
|
||||
setShowModelLoadBalancingEntryModal(null)
|
||||
}, [showModelLoadBalancingEntryModal])
|
||||
|
||||
const handleCancelOpeningModal = useCallback(() => {
|
||||
setShowOpeningModal(null)
|
||||
if (showOpeningModal?.onCancelCallback)
|
||||
showOpeningModal.onCancelCallback()
|
||||
}, [showOpeningModal])
|
||||
|
||||
const handleSaveModelLoadBalancingEntryModal = useCallback((entry: ModelLoadBalancingConfigEntry) => {
|
||||
showModelLoadBalancingEntryModal?.onSaveCallback?.({
|
||||
...showModelLoadBalancingEntryModal.payload,
|
||||
entry,
|
||||
})
|
||||
setShowModelLoadBalancingEntryModal(null)
|
||||
}, [showModelLoadBalancingEntryModal])
|
||||
|
||||
const handleRemoveModelLoadBalancingEntry = useCallback(() => {
|
||||
showModelLoadBalancingEntryModal?.onRemoveCallback?.(showModelLoadBalancingEntryModal.payload)
|
||||
setShowModelLoadBalancingEntryModal(null)
|
||||
}, [showModelLoadBalancingEntryModal])
|
||||
|
||||
const handleSaveApiBasedExtension = (newApiBasedExtension: ApiBasedExtension) => {
|
||||
if (showApiBasedExtensionModal?.onSaveCallback)
|
||||
showApiBasedExtensionModal.onSaveCallback(newApiBasedExtension)
|
||||
|
|
@ -273,7 +250,6 @@ export const ModalContextProvider = ({
|
|||
setShowModelModal,
|
||||
setShowExternalKnowledgeAPIModal,
|
||||
setShowModelLoadBalancingModal,
|
||||
setShowModelLoadBalancingEntryModal,
|
||||
setShowOpeningModal,
|
||||
setShowUpdatePluginModal,
|
||||
}}>
|
||||
|
|
@ -340,9 +316,10 @@ export const ModalContextProvider = ({
|
|||
<ModelModal
|
||||
provider={showModelModal.payload.currentProvider}
|
||||
configurateMethod={showModelModal.payload.currentConfigurationMethod}
|
||||
model={showModelModal.payload.model}
|
||||
currentCustomConfigurationModelFixedFields={showModelModal.payload.currentCustomConfigurationModelFixedFields}
|
||||
isModelCredential={showModelModal.payload.isModelCredential}
|
||||
credential={showModelModal.payload.credential}
|
||||
model={showModelModal.payload.model}
|
||||
onCancel={handleCancelModelModal}
|
||||
onSave={handleSaveModelModal}
|
||||
/>
|
||||
|
|
@ -365,19 +342,6 @@ export const ModalContextProvider = ({
|
|||
<ModelLoadBalancingModal {...showModelLoadBalancingModal!} />
|
||||
)
|
||||
}
|
||||
{
|
||||
!!showModelLoadBalancingEntryModal && (
|
||||
<ModelLoadBalancingEntryModal
|
||||
provider={showModelLoadBalancingEntryModal.payload.currentProvider}
|
||||
configurationMethod={showModelLoadBalancingEntryModal.payload.currentConfigurationMethod}
|
||||
currentCustomConfigurationModelFixedFields={showModelLoadBalancingEntryModal.payload.currentCustomConfigurationModelFixedFields}
|
||||
entry={showModelLoadBalancingEntryModal.payload.entry}
|
||||
onCancel={handleCancelModelLoadBalancingEntryModal}
|
||||
onSave={handleSaveModelLoadBalancingEntryModal}
|
||||
onRemove={handleRemoveModelLoadBalancingEntry}
|
||||
/>
|
||||
)
|
||||
}
|
||||
{showOpeningModal && (
|
||||
<OpeningSettingModal
|
||||
data={showOpeningModal.payload}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ const translation = {
|
|||
deleteApp: 'Delete App',
|
||||
settings: 'Settings',
|
||||
setup: 'Setup',
|
||||
config: 'Config',
|
||||
getForFree: 'Get for free',
|
||||
reload: 'Reload',
|
||||
ok: 'OK',
|
||||
|
|
@ -66,7 +67,6 @@ const translation = {
|
|||
more: 'More',
|
||||
selectAll: 'Select All',
|
||||
deSelectAll: 'Deselect All',
|
||||
config: 'Config',
|
||||
},
|
||||
errorMsg: {
|
||||
fieldRequired: '{{field}} is required',
|
||||
|
|
@ -145,8 +145,6 @@ const translation = {
|
|||
addMoreModel: 'Go to settings to add more models',
|
||||
settingsLink: 'Model Provider Settings',
|
||||
capabilities: 'MultiModal Capabilities',
|
||||
unAuthorized: 'Unauthorized',
|
||||
authRemoved: 'Auth removed',
|
||||
},
|
||||
menus: {
|
||||
status: 'beta',
|
||||
|
|
@ -489,6 +487,18 @@ const translation = {
|
|||
discoverMore: 'Discover more in ',
|
||||
emptyProviderTitle: 'Model provider not set up',
|
||||
emptyProviderTip: 'Please install a model provider first.',
|
||||
auth: {
|
||||
unAuthorized: 'Unauthorized',
|
||||
authRemoved: 'Auth removed',
|
||||
apiKeys: 'API Keys',
|
||||
addApiKey: 'Add API Key',
|
||||
addNewModel: 'Add new model',
|
||||
addCredential: 'Add credential',
|
||||
addModelCredential: 'Add model credential',
|
||||
modelCredentials: 'Model credentials',
|
||||
configModel: 'Config model',
|
||||
configLoadBalancing: 'Config Load Balancing',
|
||||
},
|
||||
},
|
||||
dataSource: {
|
||||
add: 'Add a data source',
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ const translation = {
|
|||
deleteApp: '删除应用',
|
||||
settings: '设置',
|
||||
setup: '设置',
|
||||
config: '配置',
|
||||
getForFree: '免费获取',
|
||||
reload: '刷新',
|
||||
ok: '好的',
|
||||
|
|
@ -66,7 +67,6 @@ const translation = {
|
|||
more: '更多',
|
||||
selectAll: '全选',
|
||||
deSelectAll: '取消全选',
|
||||
config: '配置',
|
||||
},
|
||||
errorMsg: {
|
||||
fieldRequired: '{{field}} 为必填项',
|
||||
|
|
@ -145,8 +145,6 @@ const translation = {
|
|||
addMoreModel: '添加更多模型',
|
||||
settingsLink: '模型设置',
|
||||
capabilities: '多模态能力',
|
||||
unAuthorized: '未授权',
|
||||
authRemoved: '授权已移除',
|
||||
},
|
||||
menus: {
|
||||
status: 'beta',
|
||||
|
|
@ -489,6 +487,18 @@ const translation = {
|
|||
discoverMore: '发现更多就在',
|
||||
emptyProviderTitle: '尚未安装模型供应商',
|
||||
emptyProviderTip: '请安装模型供应商。',
|
||||
auth: {
|
||||
unAuthorized: '未授权',
|
||||
authRemoved: '授权已移除',
|
||||
apiKeys: 'API 密钥',
|
||||
addApiKey: '添加 API 密钥',
|
||||
addNewModel: '添加新模型',
|
||||
addCredential: '添加凭据',
|
||||
addModelCredential: '添加模型凭据',
|
||||
modelCredentials: '模型凭据',
|
||||
configModel: '配置模型',
|
||||
configLoadBalancing: '配置负载均衡',
|
||||
},
|
||||
},
|
||||
dataSource: {
|
||||
add: '添加数据源',
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import {
|
|||
import type {
|
||||
ModelCredential,
|
||||
ModelItem,
|
||||
ModelLoadBalancingConfig,
|
||||
ModelTypeEnum,
|
||||
ProviderCredential,
|
||||
} from '@/app/components/header/account-setting/model-provider-page/declarations'
|
||||
|
|
@ -29,7 +30,7 @@ export const useGetProviderCredential = (enabled: boolean, provider: string, cre
|
|||
return useQuery({
|
||||
enabled,
|
||||
queryKey: [NAME_SPACE, 'model-list', provider, credentialId],
|
||||
queryFn: () => get<{ data: ProviderCredential }>(`/workspaces/current/model-providers/${provider}/credentials${credentialId ? `?credential_id=${credentialId}` : ''}`),
|
||||
queryFn: () => get<ProviderCredential>(`/workspaces/current/model-providers/${provider}/credentials${credentialId ? `?credential_id=${credentialId}` : ''}`),
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -82,7 +83,8 @@ export const useGetModelCredential = (
|
|||
return useQuery({
|
||||
enabled,
|
||||
queryKey: [NAME_SPACE, 'model-list', provider, model, modelType, credentialId],
|
||||
queryFn: () => get<{ data: ModelCredential }>(`/workspaces/current/model-providers/${provider}/models/credentials?model=${model}&model_type=${modelType}$credential_id=${credentialId}$config_from=${configFrom}`),
|
||||
queryFn: () => get<ModelCredential>(`/workspaces/current/model-providers/${provider}/models/credentials?model=${model}&model_type=${modelType}&config_from=${configFrom}${credentialId ? `&credential_id=${credentialId}` : ''}`),
|
||||
staleTime: 0,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -136,3 +138,16 @@ export const useActiveModelCredential = (provider: string) => {
|
|||
}),
|
||||
})
|
||||
}
|
||||
|
||||
export const useUpdateModelLoadBalancingConfig = (provider: string) => {
|
||||
return useMutation({
|
||||
mutationFn: (data: {
|
||||
config_from: string
|
||||
model: string
|
||||
model_type: ModelTypeEnum
|
||||
load_balancing: ModelLoadBalancingConfig
|
||||
}) => post<{ result: string }>(`/workspaces/current/model-providers/${provider}/models`, {
|
||||
body: data,
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue