import { useState } from "react"; import { formatCompactInteger, formatInteger } from "../../utils/numberFormat"; import { Icon } from "../ui/Icon"; import { Tooltip, type TooltipAnchor } from "../ui/Tooltip"; import { informationOutlineIcon } from "../ui/icons"; import { CacheHitRateChart } from "./CacheHitRateChart"; import styles from "./HomeMetrics.module.scss"; export type HomeMetricsData = { llmCalls: number; successfulCalls: number; failedCalls: number; tokenUsage: number; promptTokens: number; cacheReadTokens: number; cacheWriteTokens: number; }; const TOKEN_PRICE_PER_MILLION = { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25, } as const; function formatMetricValue(value: number) { const full = formatInteger(value); const compact = formatCompactInteger(value); return full === compact ? full : `${full} (${compact})`; } function formatRate(value: number | null) { return value === null ? t("暂无数据") : `${(Math.max(0, Math.min(1, value)) * 100).toFixed(2)}%`; } function calculateRate(numerator: number, denominator: number) { return denominator > 0 ? numerator / denominator : null; } function priceTokens(tokens: number, pricePerMillion: number) { return (tokens / 1_000_000) * pricePerMillion; } function formatUSD(value: number) { return `$${value.toFixed(2)}`; } function elementAnchor(element: HTMLElement): TooltipAnchor { return { contextElement: element, getBoundingClientRect: () => element.getBoundingClientRect(), }; } function InfoTooltip({ content }: { content: string }) { const [anchor, setAnchor] = useState(null); return <>
{content}
; } export function HomeMetrics({ data }: { data: HomeMetricsData }) { const inputTokens = Math.max(0, data.promptTokens - data.cacheReadTokens - data.cacheWriteTokens); const outputTokens = Math.max(0, data.tokenUsage - data.promptTokens); const defaultCacheHitRate = calculateRate(data.cacheReadTokens, data.cacheReadTokens + inputTokens); const cacheReuseRate = calculateRate( data.cacheReadTokens, data.cacheReadTokens + data.cacheWriteTokens + inputTokens, ); const successfulCallRate = calculateRate(data.successfulCalls, data.llmCalls); const costs = { input: priceTokens(inputTokens, TOKEN_PRICE_PER_MILLION.input), output: priceTokens(outputTokens, TOKEN_PRICE_PER_MILLION.output), cacheRead: priceTokens(data.cacheReadTokens, TOKEN_PRICE_PER_MILLION.cacheRead), cacheWrite: priceTokens(data.cacheWriteTokens, TOKEN_PRICE_PER_MILLION.cacheWrite), }; const totalCost = costs.input + costs.output + costs.cacheRead + costs.cacheWrite; const cacheCost = costs.cacheRead + costs.cacheWrite; const cacheTooltip = [ t("当前:{rate}", { rate: formatRate(defaultCacheHitRate) }), t("公式:缓存读取 /(缓存读取 + 非缓存输入)"), t("默认 {defaultRate} / 计入创建 {reuseRate}", { defaultRate: formatRate(defaultCacheHitRate), reuseRate: formatRate(cacheReuseRate), }), ].join("\n"); const callsTooltip = [ t("按历史 LLM 调用记录汇总,进行中的调用不计入。"), "", t("总调用:{count}", { count: formatMetricValue(data.llmCalls) }), t("成功调用:{count}", { count: formatMetricValue(data.successfulCalls) }), t("异常调用:{count}", { count: formatMetricValue(data.failedCalls) }), t("成功占比:{rate}", { rate: formatRate(successfulCallRate) }), ].join("\n"); const tokensTooltip = [ t("总请求 Token 包含提示词和模型输出。"), "", t("总请求:{tokens}", { tokens: formatMetricValue(data.tokenUsage) }), t("提示词:{tokens}", { tokens: formatMetricValue(data.promptTokens) }), t("输出推算:{tokens}", { tokens: formatMetricValue(outputTokens) }), t("非缓存输入:{tokens}", { tokens: formatMetricValue(inputTokens) }), t("缓存读取:{tokens}", { tokens: formatMetricValue(data.cacheReadTokens) }), t("缓存写入:{tokens}", { tokens: formatMetricValue(data.cacheWriteTokens) }), "", t("缓存读写已计入提示词侧统计。"), ].join("\n"); const costTooltip = [ t("按 Claude Opus 4.7 价格估算。"), t("缓存统计策略:默认口径({rate})", { rate: formatRate(defaultCacheHitRate) }), "", t("普通输入:{tokens} × ${price}/1M = {cost}", { tokens: formatMetricValue(inputTokens), price: TOKEN_PRICE_PER_MILLION.input, cost: formatUSD(costs.input), }), t("模型输出:{tokens} × ${price}/1M = {cost}", { tokens: formatMetricValue(outputTokens), price: TOKEN_PRICE_PER_MILLION.output, cost: formatUSD(costs.output), }), t("缓存读取:{tokens} × ${price}/1M = {cost}", { tokens: formatMetricValue(data.cacheReadTokens), price: TOKEN_PRICE_PER_MILLION.cacheRead, cost: formatUSD(costs.cacheRead), }), t("缓存写入:{tokens} × ${price}/1M = {cost}", { tokens: formatMetricValue(data.cacheWriteTokens), price: TOKEN_PRICE_PER_MILLION.cacheWrite, cost: formatUSD(costs.cacheWrite), }), "", t("合计:{cost}", { cost: formatUSD(totalCost) }), ].join("\n"); return
{t("缓存命中率")}
{t("LLM 调用")}
{formatCompactInteger(data.llmCalls)}
{t("成功 {successful} / 异常 {failed}", { successful: formatCompactInteger(data.successfulCalls), failed: formatCompactInteger(data.failedCalls), })}
{t("Token 消耗")}
{formatCompactInteger(data.tokenUsage)}
{t("提示词 {tokens}", { tokens: formatCompactInteger(data.promptTokens) })}
{t("价值估算")}
{formatUSD(totalCost)}
{t("缓存读写 {cost}", { cost: formatUSD(cacheCost) })}
; }