|  | @@ -3,18 +3,17 @@ import type { FC } from 'react'
 | 
											
												
													
														|  |  import React, { useState } from 'react'
 |  |  import React, { useState } from 'react'
 | 
											
												
													
														|  |  import { useTranslation } from 'react-i18next'
 |  |  import { useTranslation } from 'react-i18next'
 | 
											
												
													
														|  |  import cn from 'classnames'
 |  |  import cn from 'classnames'
 | 
											
												
													
														|  | -import useSWR from 'swr'
 |  | 
 | 
											
												
													
														|  |  import Progress from './progress'
 |  |  import Progress from './progress'
 | 
											
												
													
														|  |  import Button from '@/app/components/base/button'
 |  |  import Button from '@/app/components/base/button'
 | 
											
												
													
														|  |  import { LinkExternal02, XClose } from '@/app/components/base/icons/src/vender/line/general'
 |  |  import { LinkExternal02, XClose } from '@/app/components/base/icons/src/vender/line/general'
 | 
											
												
													
														|  |  import AccountSetting from '@/app/components/header/account-setting'
 |  |  import AccountSetting from '@/app/components/header/account-setting'
 | 
											
												
													
														|  | -import { fetchTenantInfo } from '@/service/common'
 |  | 
 | 
											
												
													
														|  |  import { IS_CE_EDITION } from '@/config'
 |  |  import { IS_CE_EDITION } from '@/config'
 | 
											
												
													
														|  |  import { useProviderContext } from '@/context/provider-context'
 |  |  import { useProviderContext } from '@/context/provider-context'
 | 
											
												
													
														|  | 
 |  | +import { formatNumber } from '@/utils/format'
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |  const APIKeyInfoPanel: FC = () => {
 |  |  const APIKeyInfoPanel: FC = () => {
 | 
											
												
													
														|  |    const isCloud = !IS_CE_EDITION
 |  |    const isCloud = !IS_CE_EDITION
 | 
											
												
													
														|  | -  const { providers }: any = useProviderContext()
 |  | 
 | 
											
												
													
														|  | 
 |  | +  const { textGenerationModelList } = useProviderContext()
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |    const { t } = useTranslation()
 |  |    const { t } = useTranslation()
 | 
											
												
													
														|  |  
 |  |  
 | 
											
										
											
												
													
														|  | @@ -22,37 +21,42 @@ const APIKeyInfoPanel: FC = () => {
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |    const [isShow, setIsShow] = useState(true)
 |  |    const [isShow, setIsShow] = useState(true)
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -  const { data: userInfo } = useSWR({ url: '/info' }, fetchTenantInfo)
 |  | 
 | 
											
												
													
														|  | -  if (!userInfo)
 |  | 
 | 
											
												
													
														|  | -    return null
 |  | 
 | 
											
												
													
														|  | 
 |  | +  const hasSetAPIKEY = !!textGenerationModelList?.find(({ model_provider: provider }) => {
 | 
											
												
													
														|  | 
 |  | +    if (provider.provider_type === 'system' && provider.quota_type === 'paid')
 | 
											
												
													
														|  | 
 |  | +      return true
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    if (provider.provider_type === 'custom')
 | 
											
												
													
														|  | 
 |  | +      return true
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  | -  const hasBindAPI = userInfo?.providers?.find(({ token_is_set }) => token_is_set)
 |  | 
 | 
											
												
													
														|  | -  if (hasBindAPI)
 |  | 
 | 
											
												
													
														|  | 
 |  | +    return false
 | 
											
												
													
														|  | 
 |  | +  })
 | 
											
												
													
														|  | 
 |  | +  if (hasSetAPIKEY)
 | 
											
												
													
														|  |      return null
 |  |      return null
 | 
											
												
													
														|  |  
 |  |  
 | 
											
												
													
														|  |    // first show in trail and not used exhausted, else find the exhausted
 |  |    // first show in trail and not used exhausted, else find the exhausted
 | 
											
												
													
														|  | -  const [used, total, providerName] = (() => {
 |  | 
 | 
											
												
													
														|  | -    if (!providers || !isCloud)
 |  | 
 | 
											
												
													
														|  | 
 |  | +  const [used, total, unit, providerName] = (() => {
 | 
											
												
													
														|  | 
 |  | +    if (!textGenerationModelList || !isCloud)
 | 
											
												
													
														|  |        return [0, 0, '']
 |  |        return [0, 0, '']
 | 
											
												
													
														|  |      let used = 0
 |  |      let used = 0
 | 
											
												
													
														|  |      let total = 0
 |  |      let total = 0
 | 
											
												
													
														|  | 
 |  | +    let unit = 'times'
 | 
											
												
													
														|  |      let trailProviderName = ''
 |  |      let trailProviderName = ''
 | 
											
												
													
														|  |      let hasFoundNotExhausted = false
 |  |      let hasFoundNotExhausted = false
 | 
											
												
													
														|  | -    Object.keys(providers).forEach((providerName) => {
 |  | 
 | 
											
												
													
														|  | 
 |  | +    textGenerationModelList?.filter(({ model_provider: provider }) => {
 | 
											
												
													
														|  | 
 |  | +      return provider.quota_type === 'trial'
 | 
											
												
													
														|  | 
 |  | +    }).forEach(({ model_provider: provider }) => {
 | 
											
												
													
														|  |        if (hasFoundNotExhausted)
 |  |        if (hasFoundNotExhausted)
 | 
											
												
													
														|  |          return
 |  |          return
 | 
											
												
													
														|  | -      providers[providerName].providers.forEach(({ quota_type, quota_limit, quota_used }: any) => {
 |  | 
 | 
											
												
													
														|  | -        if (quota_type === 'trial') {
 |  | 
 | 
											
												
													
														|  | -          if (quota_limit !== quota_used)
 |  | 
 | 
											
												
													
														|  | -            hasFoundNotExhausted = true
 |  | 
 | 
											
												
													
														|  | -
 |  | 
 | 
											
												
													
														|  | -          used = quota_used
 |  | 
 | 
											
												
													
														|  | -          total = quota_limit
 |  | 
 | 
											
												
													
														|  | -          trailProviderName = providerName
 |  | 
 | 
											
												
													
														|  | -        }
 |  | 
 | 
											
												
													
														|  | -      })
 |  | 
 | 
											
												
													
														|  | 
 |  | +      const { provider_name, quota_used, quota_limit, quota_unit } = provider
 | 
											
												
													
														|  | 
 |  | +      if (quota_limit !== quota_used)
 | 
											
												
													
														|  | 
 |  | +        hasFoundNotExhausted = true
 | 
											
												
													
														|  | 
 |  | +      used = quota_used
 | 
											
												
													
														|  | 
 |  | +      total = quota_limit
 | 
											
												
													
														|  | 
 |  | +      unit = quota_unit
 | 
											
												
													
														|  | 
 |  | +      trailProviderName = provider_name
 | 
											
												
													
														|  |      })
 |  |      })
 | 
											
												
													
														|  | -    return [used, total, trailProviderName]
 |  | 
 | 
											
												
													
														|  | 
 |  | +
 | 
											
												
													
														|  | 
 |  | +    return [used, total, unit, trailProviderName]
 | 
											
												
													
														|  |    })()
 |  |    })()
 | 
											
												
													
														|  |    const usedPercent = Math.round(used / total * 100)
 |  |    const usedPercent = Math.round(used / total * 100)
 | 
											
												
													
														|  |    const exhausted = isCloud && usedPercent === 100
 |  |    const exhausted = isCloud && usedPercent === 100
 | 
											
										
											
												
													
														|  | @@ -81,9 +85,9 @@ const APIKeyInfoPanel: FC = () => {
 | 
											
												
													
														|  |        {isCloud && (
 |  |        {isCloud && (
 | 
											
												
													
														|  |          <div className='my-5'>
 |  |          <div className='my-5'>
 | 
											
												
													
														|  |            <div className='flex items-center h-5 space-x-2 text-sm text-gray-700 font-medium'>
 |  |            <div className='flex items-center h-5 space-x-2 text-sm text-gray-700 font-medium'>
 | 
											
												
													
														|  | -            <div>{t('appOverview.apiKeyInfo.callTimes')}</div>
 |  | 
 | 
											
												
													
														|  | 
 |  | +            <div>{t(`appOverview.apiKeyInfo.${unit === 'times' ? 'callTimes' : 'usedToken'}`)}</div>
 | 
											
												
													
														|  |              <div>·</div>
 |  |              <div>·</div>
 | 
											
												
													
														|  | -            <div className={cn('font-semibold', exhausted && 'text-[#D92D20]')}>{used}/{total}</div>
 |  | 
 | 
											
												
													
														|  | 
 |  | +            <div className={cn('font-semibold', exhausted && 'text-[#D92D20]')}>{formatNumber(used)}/{formatNumber(total)}</div>
 | 
											
												
													
														|  |            </div>
 |  |            </div>
 | 
											
												
													
														|  |            <Progress className='mt-2' value={usedPercent} />
 |  |            <Progress className='mt-2' value={usedPercent} />
 | 
											
												
													
														|  |          </div>
 |  |          </div>
 |