Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

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