index.tsx 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. import type { FC } from 'react'
  2. import { useState } from 'react'
  3. import { useTranslation } from 'react-i18next'
  4. import type {
  5. CustomConfigurationModelFixedFields,
  6. ModelItem,
  7. ModelProvider,
  8. } from '../declarations'
  9. import { ConfigurationMethodEnum } from '../declarations'
  10. import {
  11. DEFAULT_BACKGROUND_COLOR,
  12. MODEL_PROVIDER_QUOTA_GET_PAID,
  13. modelTypeFormat,
  14. } from '../utils'
  15. import ProviderIcon from '../provider-icon'
  16. import ModelBadge from '../model-badge'
  17. import CredentialPanel from './credential-panel'
  18. import QuotaPanel from './quota-panel'
  19. import ModelList from './model-list'
  20. import AddModelButton from './add-model-button'
  21. import { ChevronDownDouble } from '@/app/components/base/icons/src/vender/line/arrows'
  22. import { Loading02 } from '@/app/components/base/icons/src/vender/line/general'
  23. import { fetchModelProviderModelList } from '@/service/common'
  24. import { useEventEmitterContextContext } from '@/context/event-emitter'
  25. import { IS_CE_EDITION } from '@/config'
  26. export const UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST = 'UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST'
  27. type ProviderAddedCardProps = {
  28. provider: ModelProvider
  29. onOpenModal: (configurationMethod: ConfigurationMethodEnum, currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields) => void
  30. }
  31. const ProviderAddedCard: FC<ProviderAddedCardProps> = ({
  32. provider,
  33. onOpenModal,
  34. }) => {
  35. const { t } = useTranslation()
  36. const { eventEmitter } = useEventEmitterContextContext()
  37. const [fetched, setFetched] = useState(false)
  38. const [loading, setLoading] = useState(false)
  39. const [collapsed, setCollapsed] = useState(true)
  40. const [modelList, setModelList] = useState<ModelItem[]>([])
  41. const configurationMethods = provider.configurate_methods.filter(method => method !== ConfigurationMethodEnum.fetchFromRemote)
  42. const systemConfig = provider.system_configuration
  43. const hasModelList = fetched && !!modelList.length
  44. const showQuota = systemConfig.enabled && [...MODEL_PROVIDER_QUOTA_GET_PAID].includes(provider.provider) && !IS_CE_EDITION
  45. const getModelList = async (providerName: string) => {
  46. if (loading)
  47. return
  48. try {
  49. setLoading(true)
  50. const modelsData = await fetchModelProviderModelList(`/workspaces/current/model-providers/${providerName}/models`)
  51. setModelList(modelsData.data)
  52. setCollapsed(false)
  53. setFetched(true)
  54. }
  55. finally {
  56. setLoading(false)
  57. }
  58. }
  59. const handleOpenModelList = () => {
  60. if (fetched) {
  61. setCollapsed(false)
  62. return
  63. }
  64. getModelList(provider.provider)
  65. }
  66. eventEmitter?.useSubscription((v: any) => {
  67. if (v?.type === UPDATE_MODEL_PROVIDER_CUSTOM_MODEL_LIST && v.payload === provider.provider)
  68. getModelList(v.payload)
  69. })
  70. return (
  71. <div
  72. className='mb-2 rounded-xl border-[0.5px] border-black/5 shadow-xs'
  73. style={{ background: provider.background || DEFAULT_BACKGROUND_COLOR }}
  74. >
  75. <div className='flex pl-3 py-2 pr-2 rounded-t-xl'>
  76. <div className='grow px-1 pt-1 pb-0.5'>
  77. <ProviderIcon
  78. className='mb-2'
  79. provider={provider}
  80. />
  81. <div className='flex gap-0.5'>
  82. {
  83. provider.supported_model_types.map(modelType => (
  84. <ModelBadge key={modelType}>
  85. {modelTypeFormat(modelType)}
  86. </ModelBadge>
  87. ))
  88. }
  89. </div>
  90. </div>
  91. {
  92. showQuota && (
  93. <QuotaPanel
  94. provider={provider}
  95. />
  96. )
  97. }
  98. {
  99. configurationMethods.includes(ConfigurationMethodEnum.predefinedModel) && (
  100. <CredentialPanel
  101. onSetup={() => onOpenModal(ConfigurationMethodEnum.predefinedModel)}
  102. provider={provider}
  103. />
  104. )
  105. }
  106. </div>
  107. {
  108. collapsed && (
  109. <div className='group flex items-center justify-between pl-2 py-1.5 pr-[11px] border-t border-t-black/5 bg-white/30 text-xs font-medium text-gray-500'>
  110. <div className='group-hover:hidden pl-1 pr-1.5 h-6 leading-6'>
  111. {
  112. hasModelList
  113. ? t('common.modelProvider.modelsNum', { num: modelList.length })
  114. : t('common.modelProvider.showModels')
  115. }
  116. </div>
  117. <div
  118. className='hidden group-hover:flex items-center pl-1 pr-1.5 h-6 rounded-lg hover:bg-white cursor-pointer'
  119. onClick={handleOpenModelList}
  120. >
  121. <ChevronDownDouble className='mr-0.5 w-3 h-3' />
  122. {
  123. hasModelList
  124. ? t('common.modelProvider.showModelsNum', { num: modelList.length })
  125. : t('common.modelProvider.showModels')
  126. }
  127. {
  128. loading && (
  129. <Loading02 className='ml-0.5 animate-spin w-3 h-3' />
  130. )
  131. }
  132. </div>
  133. {
  134. configurationMethods.includes(ConfigurationMethodEnum.customizableModel) && (
  135. <AddModelButton
  136. onClick={() => onOpenModal(ConfigurationMethodEnum.customizableModel)}
  137. className='hidden group-hover:flex group-hover:text-primary-600'
  138. />
  139. )
  140. }
  141. </div>
  142. )
  143. }
  144. {
  145. !collapsed && (
  146. <ModelList
  147. provider={provider}
  148. models={modelList}
  149. onCollapse={() => setCollapsed(true)}
  150. onConfig={currentCustomConfigurationModelFixedFields => onOpenModal(ConfigurationMethodEnum.customizableModel, currentCustomConfigurationModelFixedFields)}
  151. onChange={(provider: string) => getModelList(provider)}
  152. />
  153. )
  154. }
  155. </div>
  156. )
  157. }
  158. export default ProviderAddedCard