Quellcode durchsuchen

Feat/provider add zhipuai (#1192)

Co-authored-by: Joel <iamjoel007@gmail.com>
zxhlyh vor 1 Jahr
Ursprung
Commit
60e0bbd713
22 geänderte Dateien mit 371 neuen und 126 gelöschten Zeilen
  1. 3 43
      web/app/(commonLayout)/apps/Apps.tsx
  2. 1 1
      web/app/components/app/configuration/config-model/index.tsx
  3. 38 7
      web/app/components/app/configuration/config-model/param-item.tsx
  4. 2 0
      web/app/components/base/icons/assets/public/llm/zhipuai-text-cn.svg
  5. 2 0
      web/app/components/base/icons/assets/public/llm/zhipuai-text.svg
  6. 3 0
      web/app/components/base/icons/assets/public/llm/zhipuai.svg
  7. 31 0
      web/app/components/base/icons/src/public/llm/Zhipuai.json
  8. 16 0
      web/app/components/base/icons/src/public/llm/Zhipuai.tsx
  9. 24 0
      web/app/components/base/icons/src/public/llm/ZhipuaiText.json
  10. 16 0
      web/app/components/base/icons/src/public/llm/ZhipuaiText.tsx
  11. 24 0
      web/app/components/base/icons/src/public/llm/ZhipuaiTextCn.json
  12. 16 0
      web/app/components/base/icons/src/public/llm/ZhipuaiTextCn.tsx
  13. 3 0
      web/app/components/base/icons/src/public/llm/index.ts
  14. 2 0
      web/app/components/header/account-setting/model-page/configs/index.ts
  15. 55 0
      web/app/components/header/account-setting/model-page/configs/zhipuai.tsx
  16. 1 0
      web/app/components/header/account-setting/model-page/declarations.ts
  17. 4 2
      web/app/components/header/account-setting/model-page/index.tsx
  18. 4 0
      web/app/components/header/account-setting/model-page/model-item/FreeQuota.tsx
  19. 1 1
      web/app/components/header/account-setting/model-page/model-item/Setting.tsx
  20. 0 71
      web/hooks/use-pay.ts
  21. 124 0
      web/hooks/use-pay.tsx
  22. 1 1
      web/service/common.ts

+ 3 - 43
web/app/(commonLayout)/apps/Apps.tsx

@@ -1,7 +1,6 @@
 'use client'
 
-import { useCallback, useEffect, useRef, useState } from 'react'
-import { useRouter } from 'next/navigation'
+import { useEffect, useRef } from 'react'
 import useSWRInfinite from 'swr/infinite'
 import { useTranslation } from 'react-i18next'
 import AppCard from './AppCard'
@@ -10,11 +9,7 @@ import type { AppListResponse } from '@/models/app'
 import { fetchAppList } from '@/service/apps'
 import { useAppContext } from '@/context/app-context'
 import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
-import Confirm from '@/app/components/base/confirm/common'
-import {
-  useAnthropicCheckPay,
-  useSparkCheckQuota,
-} from '@/hooks/use-pay'
+import { CheckModal } from '@/hooks/use-pay'
 
 const getKey = (pageIndex: number, previousPageData: AppListResponse) => {
   if (!pageIndex || previousPageData.has_more)
@@ -27,15 +22,6 @@ const Apps = () => {
   const { isCurrentWorkspaceManager } = useAppContext()
   const { data, isLoading, setSize, mutate } = useSWRInfinite(getKey, fetchAppList, { revalidateFirstPage: false })
   const anchorRef = useRef<HTMLDivElement>(null)
-  const router = useRouter()
-  const [showPayStatusModal, setShowPayStatusModal] = useState(true)
-  const anthropicConfirmInfo = useAnthropicCheckPay()
-  const sparkConfirmInfo = useSparkCheckQuota()
-
-  const handleCancelShowPayStatusModal = useCallback(() => {
-    setShowPayStatusModal(false)
-    router.replace('/', { forceOptimisticNavigation: false })
-  }, [router])
 
   useEffect(() => {
     document.title = `${t('app.title')} -  Dify`
@@ -64,33 +50,7 @@ const Apps = () => {
       {data?.map(({ data: apps }) => apps.map(app => (
         <AppCard key={app.id} app={app} onRefresh={mutate} />
       )))}
-      {
-        showPayStatusModal && anthropicConfirmInfo && (
-          <Confirm
-            isShow
-            onCancel={handleCancelShowPayStatusModal}
-            onConfirm={handleCancelShowPayStatusModal}
-            type={anthropicConfirmInfo.type}
-            title={anthropicConfirmInfo.title}
-            showOperateCancel={false}
-            confirmText={(anthropicConfirmInfo.type === 'danger' && t('common.operation.ok')) || ''}
-          />
-        )
-      }
-      {
-        showPayStatusModal && sparkConfirmInfo && (
-          <Confirm
-            isShow
-            onCancel={handleCancelShowPayStatusModal}
-            onConfirm={handleCancelShowPayStatusModal}
-            type={sparkConfirmInfo.type}
-            title={sparkConfirmInfo.title}
-            desc={sparkConfirmInfo.desc}
-            showOperateCancel={false}
-            confirmText={(sparkConfirmInfo.type === 'danger' && t('common.operation.ok')) || ''}
-          />
-        )
-      }
+      <CheckModal />
     </nav>
     <div ref={anchorRef} className='h-0'> </div>
     </>

+ 1 - 1
web/app/components/app/configuration/config-model/index.tsx

@@ -213,7 +213,7 @@ const ConfigModel: FC<IConfigModelProps> = ({
 
   const handleParamChange = (key: string, value: number) => {
     const currParamsRule = getAllParams()[provider]?.[modelId]
-    let notOutRangeValue = parseFloat(value.toFixed(2))
+    let notOutRangeValue = parseFloat((value || 0).toFixed(2))
     notOutRangeValue = Math.max(currParamsRule[key].min, notOutRangeValue)
     notOutRangeValue = Math.min(currParamsRule[key].max, notOutRangeValue)
 

+ 38 - 7
web/app/components/app/configuration/config-model/param-item.tsx

@@ -1,9 +1,20 @@
 'use client'
 import type { FC } from 'react'
-import React from 'react'
+import React, { useEffect } from 'react'
 import Tooltip from '@/app/components/base/tooltip'
 import Slider from '@/app/components/base/slider'
 
+export const getFitPrecisionValue = (num: number, precision: number | null) => {
+  if (!precision || !(`${num}`).includes('.'))
+    return num
+
+  const currNumPrecision = (`${num}`).split('.')[1].length
+  if (currNumPrecision > precision)
+    return parseFloat(num.toFixed(precision))
+
+  return num
+}
+
 export type IParamIteProps = {
   id: string
   name: string
@@ -12,10 +23,26 @@ export type IParamIteProps = {
   step?: number
   min?: number
   max: number
+  precision: number | null
   onChange: (key: string, value: number) => void
 }
 
-const ParamIte: FC<IParamIteProps> = ({ id, name, tip, step = 0.1, min = 0, max, value, onChange }) => {
+const TIMES_TEMPLATE = '1000000000000'
+const ParamItem: FC<IParamIteProps> = ({ id, name, tip, step = 0.1, min = 0, max, precision, value, onChange }) => {
+  const getToIntTimes = (num: number) => {
+    if (precision)
+      return parseInt(TIMES_TEMPLATE.slice(0, precision + 1), 10)
+    if (num < 5)
+      return 10
+    return 1
+  }
+
+  const times = getToIntTimes(max)
+
+  useEffect(() => {
+    if (precision)
+      onChange(id, getFitPrecisionValue(value, precision))
+  }, [value, precision])
   return (
     <div className="flex items-center justify-between">
       <div className="flex items-center">
@@ -29,17 +56,21 @@ const ParamIte: FC<IParamIteProps> = ({ id, name, tip, step = 0.1, min = 0, max,
       </div>
       <div className="flex items-center">
         <div className="mr-4 w-[120px]">
-          <Slider value={max < 5 ? value * 10 : value} min={min < 0 ? min * 10 : min} max={max < 5 ? max * 10 : max} onChange={value => onChange(id, value / (max < 5 ? 10 : 1))} />
+          <Slider value={value * times} min={min * times} max={max * times} onChange={(value) => {
+            onChange(id, value / times)
+          }} />
         </div>
         <input type="number" min={min} max={max} step={step} className="block w-[64px] h-9 leading-9 rounded-lg border-0 pl-1 pl py-1.5 bg-gray-50 text-gray-900  placeholder:text-gray-400 focus:ring-1 focus:ring-inset focus:ring-primary-600" value={value} onChange={(e) => {
-          const value = parseFloat(e.target.value)
-          if (value < min || value > max)
-            return
+          let value = getFitPrecisionValue(isNaN(parseFloat(e.target.value)) ? min : parseFloat(e.target.value), precision)
+          if (value < min)
+            value = min
 
+          if (value > max)
+            value = max
           onChange(id, value)
         }} />
       </div>
     </div>
   )
 }
-export default React.memo(ParamIte)
+export default React.memo(ParamItem)

Datei-Diff unterdrückt, da er zu groß ist
+ 2 - 0
web/app/components/base/icons/assets/public/llm/zhipuai-text-cn.svg


Datei-Diff unterdrückt, da er zu groß ist
+ 2 - 0
web/app/components/base/icons/assets/public/llm/zhipuai-text.svg


Datei-Diff unterdrückt, da er zu groß ist
+ 3 - 0
web/app/components/base/icons/assets/public/llm/zhipuai.svg


Datei-Diff unterdrückt, da er zu groß ist
+ 31 - 0
web/app/components/base/icons/src/public/llm/Zhipuai.json


+ 16 - 0
web/app/components/base/icons/src/public/llm/Zhipuai.tsx

@@ -0,0 +1,16 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './Zhipuai.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
+  props,
+  ref,
+) => <IconBase {...props} ref={ref} data={data as IconData} />)
+
+Icon.displayName = 'Zhipuai'
+
+export default Icon

Datei-Diff unterdrückt, da er zu groß ist
+ 24 - 0
web/app/components/base/icons/src/public/llm/ZhipuaiText.json


+ 16 - 0
web/app/components/base/icons/src/public/llm/ZhipuaiText.tsx

@@ -0,0 +1,16 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ZhipuaiText.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
+  props,
+  ref,
+) => <IconBase {...props} ref={ref} data={data as IconData} />)
+
+Icon.displayName = 'ZhipuaiText'
+
+export default Icon

Datei-Diff unterdrückt, da er zu groß ist
+ 24 - 0
web/app/components/base/icons/src/public/llm/ZhipuaiTextCn.json


+ 16 - 0
web/app/components/base/icons/src/public/llm/ZhipuaiTextCn.tsx

@@ -0,0 +1,16 @@
+// GENERATE BY script
+// DON NOT EDIT IT MANUALLY
+
+import * as React from 'react'
+import data from './ZhipuaiTextCn.json'
+import IconBase from '@/app/components/base/icons/IconBase'
+import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
+
+const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
+  props,
+  ref,
+) => <IconBase {...props} ref={ref} data={data as IconData} />)
+
+Icon.displayName = 'ZhipuaiTextCn'
+
+export default Icon

+ 3 - 0
web/app/components/base/icons/src/public/llm/index.ts

@@ -29,3 +29,6 @@ export { default as ReplicateText } from './ReplicateText'
 export { default as Replicate } from './Replicate'
 export { default as XorbitsInferenceText } from './XorbitsInferenceText'
 export { default as XorbitsInference } from './XorbitsInference'
+export { default as ZhipuaiTextCn } from './ZhipuaiTextCn'
+export { default as ZhipuaiText } from './ZhipuaiText'
+export { default as Zhipuai } from './Zhipuai'

+ 2 - 0
web/app/components/header/account-setting/model-page/configs/index.ts

@@ -11,6 +11,7 @@ import chatglm from './chatglm'
 import xinference from './xinference'
 import openllm from './openllm'
 import localai from './localai'
+import zhipuai from './zhipuai'
 
 export default {
   openai,
@@ -26,4 +27,5 @@ export default {
   xinference,
   openllm,
   localai,
+  zhipuai,
 }

+ 55 - 0
web/app/components/header/account-setting/model-page/configs/zhipuai.tsx

@@ -0,0 +1,55 @@
+import { ProviderEnum } from '../declarations'
+import type { ProviderConfig } from '../declarations'
+import { Zhipuai, ZhipuaiText, ZhipuaiTextCn } from '@/app/components/base/icons/src/public/llm'
+
+const config: ProviderConfig = {
+  selector: {
+    name: {
+      'en': 'ZHIPU AI',
+      'zh-Hans': '智谱 AI',
+    },
+    icon: <Zhipuai className='w-full h-full' />,
+  },
+  item: {
+    key: ProviderEnum.zhipuai,
+    titleIcon: {
+      'en': <ZhipuaiText className='-ml-1 h-7' />,
+      'zh-Hans': <ZhipuaiTextCn className='h-8' />,
+    },
+  },
+  modal: {
+    key: ProviderEnum.zhipuai,
+    title: {
+      'en': 'ZHIPU AI',
+      'zh-Hans': '智谱 AI',
+    },
+    icon: <Zhipuai className='w-6 h-6' />,
+    link: {
+      href: 'https://open.bigmodel.cn/usercenter/apikeys',
+      label: {
+        'en': 'Get your API key from ZHIPU AI',
+        'zh-Hans': '从智谱 AI 获取 API Key',
+      },
+    },
+    validateKeys: [
+      'api_key',
+    ],
+    fields: [
+      {
+        type: 'text',
+        key: 'api_key',
+        required: true,
+        label: {
+          'en': 'APIKey',
+          'zh-Hans': 'APIKey',
+        },
+        placeholder: {
+          'en': 'Enter your APIKey here',
+          'zh-Hans': '在此输入您的 APIKey',
+        },
+      },
+    ],
+  },
+}
+
+export default config

+ 1 - 0
web/app/components/header/account-setting/model-page/declarations.ts

@@ -42,6 +42,7 @@ export enum ProviderEnum {
   'xinference' = 'xinference',
   'openllm' = 'openllm',
   'localai' = 'localai',
+  'zhipuai' = 'zhipuai',
 }
 
 export type ProviderConfigItem = {

+ 4 - 2
web/app/components/header/account-setting/model-page/index.tsx

@@ -78,8 +78,9 @@ const ModelPage = () => {
       config.azure_openai,
       config.replicate,
       config.huggingface_hub,
-      config.minimax,
+      config.zhipuai,
       config.spark,
+      config.minimax,
       config.tongyi,
       config.wenxin,
       config.chatglm,
@@ -91,8 +92,9 @@ const ModelPage = () => {
   else {
     modelList = [
       config.huggingface_hub,
-      config.minimax,
+      config.zhipuai,
       config.spark,
+      config.minimax,
       config.azure_openai,
       config.replicate,
       config.tongyi,

+ 4 - 0
web/app/components/header/account-setting/model-page/model-item/FreeQuota.tsx

@@ -19,6 +19,10 @@ const TIP_MAP: { [k: string]: TypeWithI18N } = {
     'en': 'Earn 3 million tokens for free',
     'zh-Hans': '免费获取 300 万个 token',
   },
+  [ProviderEnumValue.zhipuai]: {
+    'en': 'Earn 10 million tokens for free',
+    'zh-Hans': '免费获取 1000 万个 token',
+  },
 }
 type FreeQuotaProps = {
   modelItem: ProviderConfigItem

+ 1 - 1
web/app/components/header/account-setting/model-page/model-item/Setting.tsx

@@ -34,7 +34,7 @@ const Setting: FC<SettingProps> = ({
   return (
     <div className='flex items-center'>
       {
-        (modelItem.key === ProviderEnum.minimax || modelItem.key === ProviderEnum.spark) && systemFree && !systemFree?.is_valid && !IS_CE_EDITION && locale === 'zh-Hans' && (
+        (modelItem.key === ProviderEnum.minimax || modelItem.key === ProviderEnum.spark || modelItem.key === ProviderEnum.zhipuai) && systemFree && !systemFree?.is_valid && !IS_CE_EDITION && locale === 'zh-Hans' && (
           <FreeQuota
             modelItem={modelItem}
             onUpdate={onUpdate}

+ 0 - 71
web/hooks/use-pay.ts

@@ -1,71 +0,0 @@
-'use client'
-
-import { useEffect, useState } from 'react'
-import { useTranslation } from 'react-i18next'
-import useSWR from 'swr'
-import { useSearchParams } from 'next/navigation'
-import { useContext } from 'use-context-selector'
-import I18n from '@/context/i18n'
-import { ProviderEnum } from '@/app/components/header/account-setting/model-page/declarations'
-import { fetchSparkFreeQuotaVerify } from '@/service/common'
-import type { ConfirmCommonProps } from '@/app/components/base/confirm/common'
-
-export type ConfirmType = Pick<ConfirmCommonProps, 'type' | 'title' | 'desc'>
-
-export const useAnthropicCheckPay = () => {
-  const { t } = useTranslation()
-  const [confirm, setConfirm] = useState<ConfirmType | null>(null)
-  const searchParams = useSearchParams()
-  const providerName = searchParams.get('provider_name')
-  const paymentResult = searchParams.get('payment_result')
-
-  useEffect(() => {
-    if (providerName === ProviderEnum.anthropic && (paymentResult === 'succeeded' || paymentResult === 'cancelled')) {
-      setConfirm({
-        type: paymentResult === 'succeeded' ? 'success' : 'danger',
-        title: paymentResult === 'succeeded' ? t('common.actionMsg.paySucceeded') : t('common.actionMsg.payCancelled'),
-      })
-    }
-  }, [providerName, paymentResult, t])
-
-  return confirm
-}
-
-const QUOTA_RECEIVE_STATUS = {
-  success: {
-    'en': 'Anthropic',
-    'zh-Hans': '领取成功,将在 5 分钟后自动增加配额',
-  },
-  fail: {
-    'en': 'Anthropic',
-    'zh-Hans': '领取失败',
-  },
-}
-
-export const useSparkCheckQuota = () => {
-  const { locale } = useContext(I18n)
-  const [shouldVerify, setShouldVerify] = useState(false)
-  const { data } = useSWR(
-    shouldVerify
-      ? `/workspaces/current/model-providers/${ProviderEnum.spark}/free-quota-qualification-verify`
-      : null,
-    fetchSparkFreeQuotaVerify,
-  )
-  const searchParams = useSearchParams()
-  const type = searchParams.get('type')
-  const provider = searchParams.get('provider')
-  const result = searchParams.get('result')
-
-  useEffect(() => {
-    if (type === 'provider_apply_callback' && provider === ProviderEnum.spark && result === 'success')
-      setShouldVerify(true)
-  }, [type, provider, result])
-
-  return data
-    ? {
-      type: data.flag ? 'success' : 'danger',
-      title: data.flag ? QUOTA_RECEIVE_STATUS.success[locale] : QUOTA_RECEIVE_STATUS.fail[locale],
-      desc: !data.flag ? data.reason : undefined,
-    }
-    : null
-}

+ 124 - 0
web/hooks/use-pay.tsx

@@ -0,0 +1,124 @@
+'use client'
+
+import { useCallback, useEffect, useState } from 'react'
+import { useRouter, useSearchParams } from 'next/navigation'
+import { useTranslation } from 'react-i18next'
+import useSWR from 'swr'
+import { useContext } from 'use-context-selector'
+import I18n from '@/context/i18n'
+import { ProviderEnum } from '@/app/components/header/account-setting/model-page/declarations'
+import { fetchFreeQuotaVerify } from '@/service/common'
+import type { ConfirmCommonProps } from '@/app/components/base/confirm/common'
+import Confirm from '@/app/components/base/confirm/common'
+
+export type ConfirmType = Pick<ConfirmCommonProps, 'type' | 'title' | 'desc'>
+
+export const useAnthropicCheckPay = () => {
+  const { t } = useTranslation()
+  const [confirm, setConfirm] = useState<ConfirmType | null>(null)
+  const searchParams = useSearchParams()
+  const providerName = searchParams.get('provider_name')
+  const paymentResult = searchParams.get('payment_result')
+
+  useEffect(() => {
+    if (providerName === ProviderEnum.anthropic && (paymentResult === 'succeeded' || paymentResult === 'cancelled')) {
+      setConfirm({
+        type: paymentResult === 'succeeded' ? 'success' : 'danger',
+        title: paymentResult === 'succeeded' ? t('common.actionMsg.paySucceeded') : t('common.actionMsg.payCancelled'),
+      })
+    }
+  }, [providerName, paymentResult, t])
+
+  return confirm
+}
+
+const QUOTA_RECEIVE_STATUS = {
+  [ProviderEnum.spark]: {
+    success: {
+      'en': 'Successful collection, the quota will be automatically increased after 5 minutes.',
+      'zh-Hans': '领取成功,将在 5 分钟后自动增加配额',
+    },
+    fail: {
+      'en': 'Failure to collect',
+      'zh-Hans': '领取失败',
+    },
+  },
+  [ProviderEnum.zhipuai]: {
+    success: {
+      'en': 'Successful collection',
+      'zh-Hans': '领取成功',
+    },
+    fail: {
+      'en': 'Failure to collect',
+      'zh-Hans': '领取失败',
+    },
+  },
+}
+
+const FREE_CHECK_PROVIDER = [ProviderEnum.spark, ProviderEnum.zhipuai]
+export const useCheckFreeQuota = () => {
+  const { locale } = useContext(I18n)
+  const router = useRouter()
+  const [shouldVerify, setShouldVerify] = useState(false)
+  const searchParams = useSearchParams()
+  const type = searchParams.get('type')
+  const provider = searchParams.get('provider') as (ProviderEnum.spark | ProviderEnum.zhipuai)
+  const result = searchParams.get('result')
+  const token = searchParams.get('token')
+
+  const { data, error } = useSWR(
+    shouldVerify
+      ? `/workspaces/current/model-providers/${provider}/free-quota-qualification-verify?token=${token}`
+      : null,
+    fetchFreeQuotaVerify,
+  )
+
+  useEffect(() => {
+    if (error)
+      router.replace('/', { forceOptimisticNavigation: false })
+  }, [error, router])
+
+  useEffect(() => {
+    if (type === 'provider_apply_callback' && FREE_CHECK_PROVIDER.includes(provider) && result === 'success')
+      setShouldVerify(true)
+  }, [type, provider, result])
+
+  return (data && provider)
+    ? {
+      type: data.flag ? 'success' : 'danger',
+      title: data.flag ? QUOTA_RECEIVE_STATUS[provider].success[locale] : QUOTA_RECEIVE_STATUS[provider].fail[locale],
+      desc: !data.flag ? data.reason : undefined,
+    }
+    : null
+}
+
+export const CheckModal = () => {
+  const router = useRouter()
+  const { t } = useTranslation()
+  const [showPayStatusModal, setShowPayStatusModal] = useState(true)
+  const anthropicConfirmInfo = useAnthropicCheckPay()
+  const freeQuotaConfirmInfo = useCheckFreeQuota()
+
+  const handleCancelShowPayStatusModal = useCallback(() => {
+    setShowPayStatusModal(false)
+    router.replace('/', { forceOptimisticNavigation: false })
+  }, [router])
+
+  const confirmInfo = anthropicConfirmInfo || freeQuotaConfirmInfo
+
+  if (!confirmInfo || !showPayStatusModal)
+    return null
+
+  return (
+    <Confirm
+      isShow
+      onCancel={handleCancelShowPayStatusModal}
+      onConfirm={handleCancelShowPayStatusModal}
+      type={confirmInfo.type}
+      title={confirmInfo.title}
+      desc={confirmInfo.desc}
+      showOperateCancel={false}
+      confirmText={(confirmInfo.type === 'danger' && t('common.operation.ok')) || ''}
+    />
+  )
+}

+ 1 - 1
web/service/common.ts

@@ -185,6 +185,6 @@ export const fetchDocumentsLimit: Fetcher<DocumentsLimitResponse, string> = (url
   return get<DocumentsLimitResponse>(url)
 }
 
-export const fetchSparkFreeQuotaVerify: Fetcher<{ result: string; flag: boolean; reason: string }, string> = (url) => {
+export const fetchFreeQuotaVerify: Fetcher<{ result: string; flag: boolean; reason: string }, string> = (url) => {
   return get(url) as Promise<{ result: string; flag: boolean; reason: string }>
 }

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.