provider-context.tsx 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  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. type ProviderContextState = {
  25. modelProviders: ModelProvider[]
  26. refreshModelProviders: () => void
  27. textGenerationModelList: Model[]
  28. supportRetrievalMethods: RETRIEVE_METHOD[]
  29. isAPIKeySet: boolean
  30. plan: {
  31. type: Plan
  32. usage: UsagePlanInfo
  33. total: UsagePlanInfo
  34. }
  35. isFetchedPlan: boolean
  36. enableBilling: boolean
  37. onPlanInfoChanged: () => void
  38. enableReplaceWebAppLogo: boolean
  39. modelLoadBalancingEnabled: boolean
  40. datasetOperatorEnabled: boolean
  41. }
  42. const ProviderContext = createContext<ProviderContextState>({
  43. modelProviders: [],
  44. refreshModelProviders: () => { },
  45. textGenerationModelList: [],
  46. supportRetrievalMethods: [],
  47. isAPIKeySet: true,
  48. plan: {
  49. type: Plan.sandbox,
  50. usage: {
  51. vectorSpace: 32,
  52. buildApps: 12,
  53. teamMembers: 1,
  54. annotatedResponse: 1,
  55. documentsUploadQuota: 50,
  56. },
  57. total: {
  58. vectorSpace: 200,
  59. buildApps: 50,
  60. teamMembers: 1,
  61. annotatedResponse: 10,
  62. documentsUploadQuota: 500,
  63. },
  64. },
  65. isFetchedPlan: false,
  66. enableBilling: false,
  67. onPlanInfoChanged: () => { },
  68. enableReplaceWebAppLogo: false,
  69. modelLoadBalancingEnabled: false,
  70. datasetOperatorEnabled: false,
  71. })
  72. export const useProviderContext = () => useContext(ProviderContext)
  73. // Adding a dangling comma to avoid the generic parsing issue in tsx, see:
  74. // https://github.com/microsoft/TypeScript/issues/15713
  75. export const useProviderContextSelector = <T,>(selector: (state: ProviderContextState) => T): T =>
  76. useContextSelector(ProviderContext, selector)
  77. type ProviderContextProviderProps = {
  78. children: React.ReactNode
  79. }
  80. export const ProviderContextProvider = ({
  81. children,
  82. }: ProviderContextProviderProps) => {
  83. const { data: providersData, mutate: refreshModelProviders } = useSWR('/workspaces/current/model-providers', fetchModelProviders)
  84. const fetchModelListUrlPrefix = '/workspaces/current/models/model-types/'
  85. const { data: textGenerationModelList } = useSWR(`${fetchModelListUrlPrefix}${ModelTypeEnum.textGeneration}`, fetchModelList)
  86. const { data: supportRetrievalMethods } = useSWR('/datasets/retrieval-setting', fetchSupportRetrievalMethods)
  87. const [plan, setPlan] = useState(defaultPlan)
  88. const [isFetchedPlan, setIsFetchedPlan] = useState(false)
  89. const [enableBilling, setEnableBilling] = useState(true)
  90. const [enableReplaceWebAppLogo, setEnableReplaceWebAppLogo] = useState(false)
  91. const [modelLoadBalancingEnabled, setModelLoadBalancingEnabled] = useState(false)
  92. const [datasetOperatorEnabled, setDatasetOperatorEnabled] = useState(false)
  93. const fetchPlan = async () => {
  94. const data = await fetchCurrentPlanInfo()
  95. const enabled = data.billing.enabled
  96. setEnableBilling(enabled)
  97. setEnableReplaceWebAppLogo(data.can_replace_logo)
  98. if (enabled) {
  99. setPlan(parseCurrentPlan(data))
  100. setIsFetchedPlan(true)
  101. }
  102. if (data.model_load_balancing_enabled)
  103. setModelLoadBalancingEnabled(true)
  104. if (data.dataset_operator_enabled)
  105. setDatasetOperatorEnabled(true)
  106. }
  107. useEffect(() => {
  108. fetchPlan()
  109. }, [])
  110. const { t } = useTranslation()
  111. useEffect(() => {
  112. if (localStorage.getItem('anthropic_quota_notice') === 'true')
  113. return
  114. if (dayjs().isAfter(dayjs('2025-03-17')))
  115. return
  116. if (providersData?.data && providersData.data.length > 0) {
  117. const anthropic = providersData.data.find(provider => provider.provider === 'anthropic')
  118. if (anthropic && anthropic.system_configuration.current_quota_type === CurrentSystemQuotaTypeEnum.trial) {
  119. const quota = anthropic.system_configuration.quota_configurations.find(item => item.quota_type === anthropic.system_configuration.current_quota_type)
  120. if (quota && quota.is_valid && quota.quota_used < quota.quota_limit) {
  121. Toast.notify({
  122. type: 'info',
  123. message: t('common.provider.anthropicHosted.trialQuotaTip'),
  124. duration: 60000,
  125. onClose: () => {
  126. localStorage.setItem('anthropic_quota_notice', 'true')
  127. },
  128. })
  129. }
  130. }
  131. }
  132. }, [providersData, t])
  133. return (
  134. <ProviderContext.Provider value={{
  135. modelProviders: providersData?.data || [],
  136. refreshModelProviders,
  137. textGenerationModelList: textGenerationModelList?.data || [],
  138. isAPIKeySet: !!textGenerationModelList?.data.some(model => model.status === ModelStatusEnum.active),
  139. supportRetrievalMethods: supportRetrievalMethods?.retrieval_method || [],
  140. plan,
  141. isFetchedPlan,
  142. enableBilling,
  143. onPlanInfoChanged: fetchPlan,
  144. enableReplaceWebAppLogo,
  145. modelLoadBalancingEnabled,
  146. datasetOperatorEnabled,
  147. }}>
  148. {children}
  149. </ProviderContext.Provider>
  150. )
  151. }
  152. export default ProviderContext