import * as RadixDialog from '@radix-ui/react-dialog'; import classNames from 'classnames'; import { motion, type Transition, type Variants } from 'framer-motion'; import { memo } from 'react'; import { useChatUsage } from '~/lib/hooks/useChatUsage'; import { DialogDescription, DialogTitle } from '../../ui/Dialog'; import { IconButton } from '../../ui/IconButton'; import { ChatUsageVisualization } from './ChatUsageVisualization'; const transition: Transition = { duration: 0.15, ease: [0.16, 1, 0.3, 1], // cubicBezier(.16,1,.3,1) }; const backdropVariants: Variants = { closed: { opacity: 0, transition, }, open: { opacity: 1, transition, }, }; const dialogVariants: Variants = { closed: { x: '-50%', y: '-40%', scale: 0.96, opacity: 0, transition, }, open: { x: '-50%', y: '-50%', scale: 1, opacity: 1, transition, }, }; interface ChatUsageDialogProps { isOpen: boolean; onClose: () => void; } export const ChatUsageDialog = memo(({ isOpen, onClose }: ChatUsageDialogProps) => { const { usageStats, isLoading, refreshUsageStats } = useChatUsage(); const formatNumber = (num: number | null) => { if (num === null) { return '0'; } return num.toLocaleString(); }; const formatLargeNumber = (num: number | null) => { if (num === null) { return '0'; } if (num < 1000) { return num.toString(); } if (num < 1000000) { return `${(num / 1000).toFixed(1)}K`; } return `${(num / 1000000).toFixed(1)}M`; }; // 计算成功率 const successRate = () => { if (!usageStats) { return 0; } const successCount = usageStats.byStatus.find((s) => s.status === 'SUCCESS')?._count || 0; const totalCount = usageStats.total._count; return totalCount > 0 ? (successCount / totalCount) * 100 : 0; }; // 计算平均 token 消耗 const avgTokenPerRequest = () => { if (!usageStats || usageStats.total._count === 0) { return 0; } return (usageStats.total._sum.totalTokens || 0) / usageStats.total._count; }; const cardClasses = classNames( 'p-4 rounded-lg shadow-sm', 'bg-upage-elements-bg-depth-1', 'border border-upage-elements-borderColor', ); return ( 用于展示 API 使用情况统计数据,包括请求次数、Token 用量及成功率等信息。
API 使用统计
{isLoading && (
数据刷新中...
)} {!usageStats ? (

暂无数据

还没有使用记录,开始使用 AI 功能来生成数据统计。

) : (
总请求次数
{formatNumber(usageStats.total._count)}
总 Token 用量
{formatLargeNumber(usageStats.total._sum.totalTokens)}
输入 Token
{formatLargeNumber(usageStats.total._sum.inputTokens)}
输出 Token
{formatLargeNumber(usageStats.total._sum.outputTokens)}

请求成功率

{successRate().toFixed(1)}%
{usageStats.byStatus.find((s) => s.status === 'SUCCESS')?._count || 0} /{' '} {usageStats.total._count}
{usageStats.byStatus.map((status) => (
{status.status === 'SUCCESS' ? '成功' : status.status === 'FAILED' ? '失败' : status.status === 'PENDING' ? '处理中' : status.status === 'ABORTED' ? '中止' : status.status}
{formatNumber(status._count)}
))}

Token 消耗统计

平均每次请求消耗
{formatLargeNumber(avgTokenPerRequest())} Tokens
Token 类型分布
输入 Token
{formatLargeNumber(usageStats.total._sum.inputTokens)} ( {usageStats.total._sum.totalTokens ? ( ((usageStats.total._sum.inputTokens || 0) / usageStats.total._sum.totalTokens) * 100 ).toFixed(0) : 0} %)
输出 Token
{formatLargeNumber(usageStats.total._sum.outputTokens)} ( {usageStats.total._sum.totalTokens ? ( ((usageStats.total._sum.outputTokens || 0) / usageStats.total._sum.totalTokens) * 100 ).toFixed(0) : 0} %)
缓存 Token
{formatLargeNumber(usageStats.total._sum.cachedTokens)} ( {usageStats.total._sum.totalTokens ? ( ((usageStats.total._sum.cachedTokens || 0) / usageStats.total._sum.totalTokens) * 100 ).toFixed(0) : 0} %)

使用趋势

{usageStats.byDate.length > 0 ? ( <>
今日请求
{usageStats.byDate.length > 0 ? formatNumber(usageStats.byDate[usageStats.byDate.length - 1].count) : '0'}
最近趋势
{usageStats.byDate.length > 1 ? ( (() => { const current = usageStats.byDate[usageStats.byDate.length - 1].count; const previous = usageStats.byDate[usageStats.byDate.length - 2].count; const diff = current - previous; const percentage = previous !== 0 ? (diff / previous) * 100 : 0; return (
较前一日: 0, 'text-red-500 dark:text-red-400': diff < 0, 'text-upage-elements-textTertiary': diff === 0, })} > {diff > 0 ? ( ) : diff < 0 ? ( ) : ( )} {Math.abs(percentage).toFixed(0)}%
); })() ) : ( 尚无对比数据 )}
) : (
暂无数据
)}

使用统计图表

)}
); });