mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-08 10:27:46 +08:00
feat(usage): 新增输出速度统计与请求详情性能分析
- 把 upstream_is_stream 物化到 usage 与 billing facts,避免 Provider 聚合回连 public.usage - 统一前端标准/流式 TPS 计算与显示,流式按首字后生成耗时计算 - 新增请求详情抽屉展示单请求输出速度与 Provider 聚合 TPS
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
export interface UsagePerformanceTiming {
|
||||
output_tokens?: number | null
|
||||
response_time_ms?: number | null
|
||||
first_byte_time_ms?: number | null
|
||||
is_stream?: boolean | null
|
||||
upstream_is_stream?: boolean | null
|
||||
}
|
||||
|
||||
export function getGenerationTimeMs(timing: UsagePerformanceTiming): number | null {
|
||||
const responseTimeMs = timing.response_time_ms
|
||||
const firstByteTimeMs = timing.first_byte_time_ms
|
||||
|
||||
if (responseTimeMs == null || firstByteTimeMs == null) return null
|
||||
if (!Number.isFinite(responseTimeMs) || !Number.isFinite(firstByteTimeMs)) return null
|
||||
if (responseTimeMs <= 0 || firstByteTimeMs < 0 || firstByteTimeMs >= responseTimeMs) return null
|
||||
|
||||
return responseTimeMs - firstByteTimeMs
|
||||
}
|
||||
|
||||
export function isOutputRateUsingGenerationTime(timing: UsagePerformanceTiming): boolean {
|
||||
return timing.upstream_is_stream ?? timing.is_stream ?? false
|
||||
}
|
||||
|
||||
export function getOutputRateDurationMs(timing: UsagePerformanceTiming): number | null {
|
||||
if (isOutputRateUsingGenerationTime(timing)) {
|
||||
return getGenerationTimeMs(timing)
|
||||
}
|
||||
|
||||
const responseTimeMs = timing.response_time_ms
|
||||
if (responseTimeMs == null || !Number.isFinite(responseTimeMs) || responseTimeMs <= 0) return null
|
||||
return responseTimeMs
|
||||
}
|
||||
|
||||
export function calculateOutputRate(timing: UsagePerformanceTiming): number | null {
|
||||
const outputTokens = timing.output_tokens ?? 0
|
||||
const outputRateDurationMs = getOutputRateDurationMs(timing)
|
||||
|
||||
if (!Number.isFinite(outputTokens) || outputTokens <= 0 || outputRateDurationMs == null) return null
|
||||
|
||||
const outputRateSeconds = outputRateDurationMs / 1000
|
||||
if (outputRateSeconds <= 0) return null
|
||||
|
||||
return outputTokens / outputRateSeconds
|
||||
}
|
||||
|
||||
export function shouldHideOutputRate(
|
||||
outputRate: number | null,
|
||||
timing: UsagePerformanceTiming,
|
||||
): boolean {
|
||||
if (!isOutputRateUsingGenerationTime(timing)) return false
|
||||
|
||||
const responseTimeMs = timing.response_time_ms
|
||||
const generationTimeMs = getGenerationTimeMs(timing)
|
||||
|
||||
if (outputRate == null || responseTimeMs == null || generationTimeMs == null) return false
|
||||
if (!Number.isFinite(outputRate) || !Number.isFinite(responseTimeMs) || responseTimeMs <= 0) return true
|
||||
|
||||
return generationTimeMs / responseTimeMs < 0.1 && outputRate > 5000
|
||||
}
|
||||
|
||||
export function getDisplayOutputRate(timing: UsagePerformanceTiming): number | null {
|
||||
const outputRate = calculateOutputRate(timing)
|
||||
if (shouldHideOutputRate(outputRate, timing)) return null
|
||||
return outputRate
|
||||
}
|
||||
|
||||
export function formatDurationMs(ms: number | null | undefined, fractionDigits = 2): string {
|
||||
if (ms == null || !Number.isFinite(ms)) return '-'
|
||||
if (ms >= 1000) return `${(ms / 1000).toFixed(fractionDigits)}s`
|
||||
return `${Math.round(ms)}ms`
|
||||
}
|
||||
|
||||
export function formatOutputRateValue(outputRate: number | null | undefined): string {
|
||||
if (outputRate == null || !Number.isFinite(outputRate)) return '-'
|
||||
if (outputRate >= 1000) return Math.round(outputRate).toLocaleString()
|
||||
if (outputRate >= 100) return `${Math.round(outputRate)}`
|
||||
if (outputRate >= 10) return outputRate.toFixed(1)
|
||||
return outputRate.toFixed(2)
|
||||
}
|
||||
|
||||
export function formatOutputRate(outputRate: number | null | undefined): string {
|
||||
const value = formatOutputRateValue(outputRate)
|
||||
if (value === '-') return value
|
||||
return `${value} tps`
|
||||
}
|
||||
Reference in New Issue
Block a user