Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

provider-context.tsx 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. 'use client'
  2. import { createContext, useContext, useContextSelector } from 'use-context-selector'
  3. import useSWR from 'swr'
  4. import { useEffect, useState } from 'react'
  5. import dayjs from 'dayjs'
  6. import { useTranslation } from 'react-i18next'
  7. import {
  8. fetchModelList,
  9. fetchModelProviders,
  10. fetchSupportRetrievalMethods,
  11. } from '@/service/common'
  12. import {
  13. CurrentSystemQuotaTypeEnum,
  14. ModelStatusEnum,
  15. ModelTypeEnum,
  16. } from '@/app/components/header/account-setting/model-provider-page/declarations'
  17. import type { Model, ModelProvider } from '@/app/components/header/account-setting/model-provider-page/declarations'
  18. import type { RETRIEVE_METHOD } from '@/types/app'
  19. import { Plan, type UsagePlanInfo } from '@/app/components/billing/type'
  20. import { fetchCurrentPlanInfo } from '@/service/billing'
  21. import { parseCurrentPlan } from '@/app/components/billing/utils'
  22. import { defaultPlan } from '@/app/components/billing/config'
  23. import Toast from '@/app/components/base/toast'
  24. import {
  25. useEducationStatus,
  26. } from '@/service/use-education'
  27. import { noop } from 'lodash-es'
  28. type ProviderContextState = {
  29. modelProviders: ModelProvider[]
  30. refreshModelProviders: () => void
  31. textGenerationModelList: Model[]
  32. supportRetrievalMethods: RETRIEVE_METHOD[]
  33. isAPIKeySet: boolean
  34. plan: {
  35. type: Plan
  36. usage: UsagePlanInfo
  37. total: UsagePlanInfo
  38. }
  39. isFetchedPlan: boolean
  40. enableBilling: boolean
  41. onPlanInfoChanged: () => void
  42. enableReplaceWebAppLogo: boolean
  43. modelLoadBalancingEnabled: boolean
  44. datasetOperatorEnabled: boolean
  45. enableEducationPlan: boolean
  46. isEducationWorkspace: boolean
  47. isEducationAccount: boolean
  48. }
  49. const ProviderContext = createContext<ProviderContextState>({
  50. modelProviders: [],
  51. refreshModelProviders: noop,
  52. textGenerationModelList: [],
  53. supportRetrievalMethods: [],
  54. isAPIKeySet: true,
  55. plan: {
  56. type: Plan.sandbox,
  57. usage: {
  58. vectorSpace: 32,
  59. buildApps: 12,
  60. teamMembers: 1,
  61. annotatedResponse: 1,
  62. documentsUploadQuota: 50,
  63. },
  64. total: {
  65. vectorSpace: 200,
  66. buildApps: 50,
  67. teamMembers: 1,
  68. annotatedResponse: 10,
  69. documentsUploadQuota: 500,
  70. },
  71. },
  72. isFetchedPlan: false,
  73. enableBilling: false,
  74. onPlanInfoChanged: noop,
  75. enableReplaceWebAppLogo: false,
  76. modelLoadBalancingEnabled: false,
  77. datasetOperatorEnabled: false,
  78. enableEducationPlan: false,
  79. isEducationWorkspace: false,
  80. isEducationAccount: false,
  81. })
  82. export const useProviderContext = () => useContext(ProviderContext)
  83. // Adding a dangling comma to avoid the generic parsing issue in tsx, see:
  84. // https://github.com/microsoft/TypeScript/issues/15713
  85. export const useProviderContextSelector = <T,>(selector: (state: ProviderContextState) => T): T =>
  86. useContextSelector(ProviderContext, selector)
  87. type ProviderContextProviderProps = {
  88. children: React.ReactNode
  89. }
  90. export const ProviderContextProvider = ({
  91. children,
  92. }: ProviderContextProviderProps) => {
  93. const { data: providersData, mutate: refreshModelProviders } = useSWR('/workspaces/current/model-providers', fetchModelProviders)
  94. const fetchModelListUrlPrefix = '/workspaces/current/models/model-types/'
  95. const { data: textGenerationModelList } = useSWR(`${fetchModelListUrlPrefix}${ModelTypeEnum.textGeneration}`, fetchModelList)
  96. const { data: supportRetrievalMethods } = useSWR('/datasets/retrieval-setting', fetchSupportRetrievalMethods)
  97. const [plan, setPlan] = useState(defaultPlan)
  98. const [isFetchedPlan, setIsFetchedPlan] = useState(false)
  99. const [enableBilling, setEnableBilling] = useState(true)
  100. const [enableReplaceWebAppLogo, setEnableReplaceWebAppLogo] = useState(false)
  101. const [modelLoadBalancingEnabled, setModelLoadBalancingEnabled] = useState(false)
  102. const [datasetOperatorEnabled, setDatasetOperatorEnabled] = useState(false)
  103. const [enableEducationPlan, setEnableEducationPlan] = useState(false)
  104. const [isEducationWorkspace, setIsEducationWorkspace] = useState(false)
  105. const { data: isEducationAccount } = useEducationStatus(!enableEducationPlan)
  106. const fetchPlan = async () => {
  107. try {
  108. const data = await fetchCurrentPlanInfo()
  109. if (!data) {
  110. console.error('Failed to fetch plan info: data is undefined')
  111. return
  112. }
  113. // set default value to avoid undefined error
  114. setEnableBilling(data.billing?.enabled ?? false)
  115. setEnableEducationPlan(data.education?.enabled ?? false)
  116. setIsEducationWorkspace(data.education?.activated ?? false)
  117. setEnableReplaceWebAppLogo(data.can_replace_logo ?? false)
  118. if (data.billing?.enabled) {
  119. setPlan(parseCurrentPlan(data) as any)
  120. setIsFetchedPlan(true)
  121. }
  122. if (data.model_load_balancing_enabled)
  123. setModelLoadBalancingEnabled(true)
  124. if (data.dataset_operator_enabled)
  125. setDatasetOperatorEnabled(true)
  126. }
  127. catch (error) {
  128. console.error('Failed to fetch plan info:', error)
  129. // set default value to avoid undefined error
  130. setEnableBilling(false)
  131. setEnableEducationPlan(false)
  132. setIsEducationWorkspace(false)
  133. setEnableReplaceWebAppLogo(false)
  134. }
  135. }
  136. useEffect(() => {
  137. fetchPlan()
  138. }, [])
  139. const { t } = useTranslation()
  140. useEffect(() => {
  141. if (localStorage.getItem('anthropic_quota_notice') === 'true')
  142. return
  143. if (dayjs().isAfter(dayjs('2025-03-17')))
  144. return
  145. if (providersData?.data && providersData.data.length > 0) {
  146. const anthropic = providersData.data.find(provider => provider.provider === 'anthropic')
  147. if (anthropic && anthropic.system_configuration.current_quota_type === CurrentSystemQuotaTypeEnum.trial) {
  148. const quota = anthropic.system_configuration.quota_configurations.find(item => item.quota_type === anthropic.system_configuration.current_quota_type)
  149. if (quota && quota.is_valid && quota.quota_used < quota.quota_limit) {
  150. Toast.notify({
  151. type: 'info',
  152. message: t('common.provider.anthropicHosted.trialQuotaTip'),
  153. duration: 60000,
  154. onClose: () => {
  155. localStorage.setItem('anthropic_quota_notice', 'true')
  156. },
  157. })
  158. }
  159. }
  160. }
  161. }, [providersData, t])
  162. return (
  163. <ProviderContext.Provider value={{
  164. modelProviders: providersData?.data || [],
  165. refreshModelProviders,
  166. textGenerationModelList: textGenerationModelList?.data || [],
  167. isAPIKeySet: !!textGenerationModelList?.data.some(model => model.status === ModelStatusEnum.active),
  168. supportRetrievalMethods: supportRetrievalMethods?.retrieval_method || [],
  169. plan,
  170. isFetchedPlan,
  171. enableBilling,
  172. onPlanInfoChanged: fetchPlan,
  173. enableReplaceWebAppLogo,
  174. modelLoadBalancingEnabled,
  175. datasetOperatorEnabled,
  176. enableEducationPlan,
  177. isEducationWorkspace,
  178. isEducationAccount: isEducationAccount?.result || false,
  179. }}>
  180. {children}
  181. </ProviderContext.Provider>
  182. )
  183. }
  184. export default ProviderContext