feat: show more usage info in billing page (#4808)

This commit is contained in:
Joel 2024-05-30 16:15:38 +08:00 committed by GitHub
parent 11f173693b
commit a7fb1ffcd8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 134 additions and 23 deletions

View File

@ -0,0 +1,6 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="file-upload">
<path id="Icon" d="M20 10.5V6.8C20 5.11984 20 4.27976 19.673 3.63803C19.3854 3.07354 18.9265 2.6146 18.362 2.32698C17.7202 2 16.8802 2 15.2 2H8.8C7.11984 2 6.27976 2 5.63803 2.32698C5.07354 2.6146 4.6146 3.07354 4.32698 3.63803C4 4.27976 4 5.11984 4 6.8V17.2C4 18.8802 4 19.7202 4.32698 20.362C4.6146 20.9265 5.07354 21.3854 5.63803 21.673C6.27976 22 7.11984 22 8.8 22H12M14 11H8M10 15H8M16 7H8" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path id="Icon_2" d="M15 18L18 15M18 15L21 18M18 15L18 21" stroke="black" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 746 B

View File

@ -0,0 +1,52 @@
{
"icon": {
"type": "element",
"isRootNode": true,
"name": "svg",
"attributes": {
"width": "24",
"height": "24",
"viewBox": "0 0 24 24",
"fill": "none",
"xmlns": "http://www.w3.org/2000/svg"
},
"children": [
{
"type": "element",
"name": "g",
"attributes": {
"id": "file-upload"
},
"children": [
{
"type": "element",
"name": "path",
"attributes": {
"id": "Icon",
"d": "M20 10.5V6.8C20 5.11984 20 4.27976 19.673 3.63803C19.3854 3.07354 18.9265 2.6146 18.362 2.32698C17.7202 2 16.8802 2 15.2 2H8.8C7.11984 2 6.27976 2 5.63803 2.32698C5.07354 2.6146 4.6146 3.07354 4.32698 3.63803C4 4.27976 4 5.11984 4 6.8V17.2C4 18.8802 4 19.7202 4.32698 20.362C4.6146 20.9265 5.07354 21.3854 5.63803 21.673C6.27976 22 7.11984 22 8.8 22H12M14 11H8M10 15H8M16 7H8",
"stroke": "currentColor",
"stroke-width": "2",
"stroke-linecap": "round",
"stroke-linejoin": "round"
},
"children": []
},
{
"type": "element",
"name": "path",
"attributes": {
"id": "Icon_2",
"d": "M15 18L18 15M18 15L21 18M18 15L18 21",
"stroke": "currentColor",
"stroke-width": "2",
"stroke-linecap": "round",
"stroke-linejoin": "round"
},
"children": []
}
]
}
]
},
"name": "FileUpload"
}

View File

@ -0,0 +1,16 @@
// GENERATE BY script
// DON NOT EDIT IT MANUALLY
import * as React from 'react'
import data from './FileUpload.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 = 'FileUpload'
export default Icon

View File

@ -7,4 +7,5 @@ export { default as FileDownload02 } from './FileDownload02'
export { default as FilePlus01 } from './FilePlus01'
export { default as FilePlus02 } from './FilePlus02'
export { default as FileText } from './FileText'
export { default as FileUpload } from './FileUpload'
export { default as Folder } from './Folder'

View File

@ -86,11 +86,13 @@ export const defaultPlan = {
buildApps: 1,
teamMembers: 1,
annotatedResponse: 1,
documentsUploadQuota: 1,
},
total: {
vectorSpace: 10,
buildApps: 10,
teamMembers: 1,
annotatedResponse: 10,
documentsUploadQuota: 50,
},
}

View File

@ -7,7 +7,11 @@ import { Plan } from '../type'
import VectorSpaceInfo from '../usage-info/vector-space-info'
import AppsInfo from '../usage-info/apps-info'
import UpgradeBtn from '../upgrade-btn'
import { User01 } from '../../base/icons/src/vender/line/users'
import { MessageFastPlus } from '../../base/icons/src/vender/line/communication'
import { FileUpload } from '../../base/icons/src/vender/line/files'
import { useProviderContext } from '@/context/provider-context'
import UsageInfo from '@/app/components/billing/usage-info'
const typeStyle = {
[Plan.sandbox]: {
@ -41,6 +45,11 @@ const PlanComp: FC<Props> = ({
type,
} = plan
const {
usage,
total,
} = plan
const isInHeader = loc === 'header'
return (
@ -76,8 +85,30 @@ const PlanComp: FC<Props> = ({
{/* Plan detail */}
<div className='rounded-xl bg-white px-6 py-3'>
<VectorSpaceInfo className='py-3' />
<UsageInfo
className='py-3'
Icon={User01}
name={t('billing.plansCommon.teamMembers')}
usage={usage.teamMembers}
total={total.teamMembers}
/>
<AppsInfo className='py-3' />
<VectorSpaceInfo className='py-3' />
<UsageInfo
className='py-3'
Icon={MessageFastPlus}
name={t('billing.plansCommon.annotationQuota')}
usage={usage.annotatedResponse}
total={total.annotatedResponse}
/>
<UsageInfo
className='py-3'
Icon={FileUpload}
name={t('billing.plansCommon.documentsUploadQuota')}
usage={usage.documentsUploadQuota}
total={total.documentsUploadQuota}
/>
{isInHeader && type === Plan.sandbox && (
<UpgradeBtn
className='flex-shrink-0 my-3'

View File

@ -28,7 +28,7 @@ export type PlanInfo = {
annotatedResponse: number
}
export type UsagePlanInfo = Pick<PlanInfo, 'vectorSpace' | 'buildApps' | 'teamMembers' | 'annotatedResponse'>
export type UsagePlanInfo = Pick<PlanInfo, 'vectorSpace' | 'buildApps' | 'teamMembers' | 'annotatedResponse' | 'documentsUploadQuota'>
export enum DocumentProcessingPriority {
standard = 'standard',
@ -59,6 +59,10 @@ export type CurrentPlanInfoBackend = {
size: number
limit: number // total. 0 means unlimited
}
documents_upload_quota: {
size: number
limit: number // total. 0 means unlimited
}
docs_processing: DocumentProcessingPriority
can_replace_logo: boolean
}

View File

@ -16,12 +16,14 @@ export const parseCurrentPlan = (data: CurrentPlanInfoBackend) => {
buildApps: data.apps?.size || 0,
teamMembers: data.members.size,
annotatedResponse: data.annotation_quota_limit.size,
documentsUploadQuota: data.documents_upload_quota.size,
},
total: {
vectorSpace: parseLimit(data.vector_space.limit),
buildApps: parseLimit(data.apps?.limit) || 0,
teamMembers: parseLimit(data.members.limit),
annotatedResponse: parseLimit(data.annotation_quota_limit.limit),
documentsUploadQuota: parseLimit(data.documents_upload_quota.limit),
},
}
}

View File

@ -1,7 +1,7 @@
'use client'
import { useEffect, useRef, useState } from 'react'
import { useCallback, useEffect } from 'react'
import Link from 'next/link'
import { useBoolean, useClickAway } from 'ahooks'
import { useBoolean } from 'ahooks'
import { useSelectedLayoutSegment } from 'next/navigation'
import { Bars3Icon } from '@heroicons/react/20/solid'
import HeaderBillingBtn from '../billing/header-billing-btn'
@ -15,9 +15,9 @@ import GithubStar from './github-star'
import { WorkspaceProvider } from '@/context/workspace-context'
import { useAppContext } from '@/context/app-context'
import LogoSite from '@/app/components/base/logo/logo-site'
import PlanComp from '@/app/components/billing/plan'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import { useProviderContext } from '@/context/provider-context'
import { useModalContext } from '@/context/modal-context'
const navClassName = `
flex items-center relative mr-0 sm:mr-3 px-3 h-8 rounded-xl
@ -26,18 +26,21 @@ const navClassName = `
`
const Header = () => {
const { isCurrentWorkspaceManager, langeniusVersionInfo } = useAppContext()
const [showUpgradePanel, setShowUpgradePanel] = useState(false)
const upgradeBtnRef = useRef<HTMLElement>(null)
useClickAway(() => {
setShowUpgradePanel(false)
}, upgradeBtnRef)
const { isCurrentWorkspaceManager } = useAppContext()
const selectedSegment = useSelectedLayoutSegment()
const media = useBreakpoints()
const isMobile = media === MediaType.mobile
const [isShowNavMenu, { toggle, setFalse: hideNavMenu }] = useBoolean(false)
const { enableBilling } = useProviderContext()
const { enableBilling, plan } = useProviderContext()
const { setShowPricingModal, setShowAccountSettingModal } = useModalContext()
const isFreePlan = plan.type === 'sandbox'
const handlePlanClick = useCallback(() => {
if (isFreePlan)
setShowPricingModal()
else
setShowAccountSettingModal({ payload: 'billing' })
}, [isFreePlan, setShowAccountSettingModal, setShowPricingModal])
useEffect(() => {
hideNavMenu()
@ -79,15 +82,7 @@ const Header = () => {
<EnvNav />
{enableBilling && (
<div className='mr-3 select-none'>
<HeaderBillingBtn onClick={() => setShowUpgradePanel(true)} />
{showUpgradePanel && (
<div
ref={upgradeBtnRef as any}
className='fixed z-10 top-12 right-1 w-[360px]'
>
<PlanComp loc='header' />
</div>
)}
<HeaderBillingBtn onClick={handlePlanClick} />
</div>
)}
<WorkspaceProvider>

View File

@ -40,7 +40,7 @@ const ModalContext = createContext<{
setShowApiBasedExtensionModal: Dispatch<SetStateAction<ModalState<ApiBasedExtension> | null>>
setShowModerationSettingModal: Dispatch<SetStateAction<ModalState<ModerationConfig> | null>>
setShowExternalDataToolModal: Dispatch<SetStateAction<ModalState<ExternalDataTool> | null>>
setShowPricingModal: Dispatch<SetStateAction<any>>
setShowPricingModal: () => void
setShowAnnotationFullModal: () => void
setShowModelModal: Dispatch<SetStateAction<ModalState<ModelModalType> | null>>
}>({
@ -50,7 +50,7 @@ const ModalContext = createContext<{
setShowExternalDataToolModal: () => { },
setShowPricingModal: () => { },
setShowAnnotationFullModal: () => { },
setShowModelModal: () => {},
setShowModelModal: () => { },
})
export const useModalContext = () => useContext(ModalContext)

View File

@ -28,6 +28,7 @@ const translation = {
talkToSales: 'Talk to Sales',
modelProviders: 'Model Providers',
teamMembers: 'Team Members',
annotationQuota: 'Annotation Quota',
buildApps: 'Build Apps',
vectorSpace: 'Vector Space',
vectorSpaceBillingTooltip: 'Each 1MB can store about 1.2million characters of vectorized data(estimated using OpenAI Embeddings, varies across models).',

View File

@ -29,6 +29,7 @@ const translation = {
modelProviders: '支持的模型提供商',
teamMembers: '团队成员',
buildApps: '构建应用程序数',
annotationQuota: '标注回复数',
vectorSpace: '向量空间',
vectorSpaceTooltip: '向量空间是 LLMs 理解您的数据所需的长期记忆系统。',
vectorSpaceBillingTooltip: '向量存储是将知识库向量化处理后为让 LLMs 理解数据而使用的长期记忆存储1MB 大约能满足1.2 million character 的向量化后数据存储(以 OpenAI Embedding 模型估算,不同模型计算方式有差异)。在向量化过程中,实际的压缩或尺寸减小取决于内容的复杂性和冗余性。',