model-list-item.tsx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  1. import { memo, useCallback } from 'react'
  2. import { useTranslation } from 'react-i18next'
  3. import classNames from 'classnames'
  4. import { useDebounceFn } from 'ahooks'
  5. import type { CustomConfigurationModelFixedFields, ModelItem, ModelProvider } from '../declarations'
  6. import { ConfigurationMethodEnum, ModelStatusEnum } from '../declarations'
  7. import ModelBadge from '../model-badge'
  8. import ModelIcon from '../model-icon'
  9. import ModelName from '../model-name'
  10. import Button from '@/app/components/base/button'
  11. import { Balance } from '@/app/components/base/icons/src/vender/line/financeAndECommerce'
  12. import { Settings01 } from '@/app/components/base/icons/src/vender/line/general'
  13. import Switch from '@/app/components/base/switch'
  14. import TooltipPlus from '@/app/components/base/tooltip-plus'
  15. import { useProviderContext, useProviderContextSelector } from '@/context/provider-context'
  16. import { disableModel, enableModel } from '@/service/common'
  17. import { Plan } from '@/app/components/billing/type'
  18. export type ModelListItemProps = {
  19. model: ModelItem
  20. provider: ModelProvider
  21. isConfigurable: boolean
  22. onConfig: (currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields) => void
  23. onModifyLoadBalancing?: (model: ModelItem) => void
  24. }
  25. const ModelListItem = ({ model, provider, isConfigurable, onConfig, onModifyLoadBalancing }: ModelListItemProps) => {
  26. const { t } = useTranslation()
  27. const { plan } = useProviderContext()
  28. const modelLoadBalancingEnabled = useProviderContextSelector(state => state.modelLoadBalancingEnabled)
  29. const toggleModelEnablingStatus = useCallback(async (enabled: boolean) => {
  30. if (enabled)
  31. await enableModel(`/workspaces/current/model-providers/${provider.provider}/models/enable`, { model: model.model, model_type: model.model_type })
  32. else
  33. await disableModel(`/workspaces/current/model-providers/${provider.provider}/models/disable`, { model: model.model, model_type: model.model_type })
  34. }, [model.model, model.model_type, provider.provider])
  35. const { run: debouncedToggleModelEnablingStatus } = useDebounceFn(toggleModelEnablingStatus, { wait: 500 })
  36. const onEnablingStateChange = useCallback(async (value: boolean) => {
  37. debouncedToggleModelEnablingStatus(value)
  38. }, [debouncedToggleModelEnablingStatus])
  39. return (
  40. <div
  41. key={model.model}
  42. className={classNames(
  43. 'group flex items-center pl-2 pr-2.5 h-8 rounded-lg',
  44. isConfigurable && 'hover:bg-gray-50',
  45. model.deprecated && 'opacity-60',
  46. )}
  47. >
  48. <ModelIcon
  49. className='shrink-0 mr-2'
  50. provider={provider}
  51. modelName={model.model}
  52. />
  53. <ModelName
  54. className='grow text-sm font-normal text-gray-900'
  55. modelItem={model}
  56. showModelType
  57. showMode
  58. showContextSize
  59. >
  60. {modelLoadBalancingEnabled && !model.deprecated && model.load_balancing_enabled && (
  61. <ModelBadge className='ml-1 uppercase text-indigo-600 border-indigo-300'>
  62. <Balance className='w-3 h-3 mr-0.5' />
  63. {t('common.modelProvider.loadBalancingHeadline')}
  64. </ModelBadge>
  65. )}
  66. </ModelName>
  67. <div className='shrink-0 flex items-center'>
  68. {
  69. model.fetch_from === ConfigurationMethodEnum.customizableModel
  70. ? (
  71. <Button
  72. className='hidden group-hover:flex py-0 h-7 text-xs font-medium text-gray-700'
  73. onClick={() => onConfig({ __model_name: model.model, __model_type: model.model_type })}
  74. >
  75. <Settings01 className='mr-[5px] w-3.5 h-3.5' />
  76. {t('common.modelProvider.config')}
  77. </Button>
  78. )
  79. : ((modelLoadBalancingEnabled || plan.type === Plan.sandbox) && !model.deprecated && [ModelStatusEnum.active, ModelStatusEnum.disabled].includes(model.status))
  80. ? (
  81. <Button
  82. className='opacity-0 group-hover:opacity-100 px-3 h-[28px] text-xs text-gray-700 rounded-md transition-opacity'
  83. onClick={() => onModifyLoadBalancing?.(model)}
  84. >
  85. <Balance className='mr-1 w-[14px] h-[14px]' />
  86. {t('common.modelProvider.configLoadBalancing')}
  87. </Button>
  88. )
  89. : null
  90. }
  91. {
  92. model.deprecated
  93. ? (
  94. <TooltipPlus popupContent={<span className='font-semibold'>{t('common.modelProvider.modelHasBeenDeprecated')}</span>} offset={{ mainAxis: 4 }}>
  95. <Switch defaultValue={false} disabled size='md' />
  96. </TooltipPlus>
  97. )
  98. : (
  99. <Switch
  100. className='ml-2'
  101. defaultValue={model?.status === ModelStatusEnum.active}
  102. disabled={![ModelStatusEnum.active, ModelStatusEnum.disabled].includes(model.status)}
  103. size='md'
  104. onChange={onEnablingStateChange}
  105. />
  106. )
  107. }
  108. </div>
  109. </div>
  110. )
  111. }
  112. export default memo(ModelListItem)