mirror of
https://github.com/Wei-Shaw/claude-relay-service.git
synced 2026-01-22 16:43:35 +00:00
Merge PR #548: 修复Claude Console流式响应usage统计不完整问题
- 完善message_delta中usage数据提取逻辑,支持提取input_tokens、cache_read_input_tokens等所有字段 - 添加兜底保护机制,确保流结束时不会丢失未保存的usage数据 - 提升关键日志级别从debug到info,便于问题排查 - 修复流式请求中input_tokens和cache_read_input_tokens为0的统计bug 作者: DokiDoki1103 PR: https://github.com/Wei-Shaw/claude-relay-service/pull/548
This commit is contained in:
@@ -517,14 +517,55 @@ class ClaudeConsoleRelayService {
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
data.type === 'message_delta' &&
|
||||
data.usage &&
|
||||
data.usage.output_tokens !== undefined
|
||||
) {
|
||||
if (data.type === 'message_delta' && data.usage) {
|
||||
// 提取所有usage字段,message_delta可能包含完整的usage信息
|
||||
if (data.usage.output_tokens !== undefined) {
|
||||
collectedUsageData.output_tokens = data.usage.output_tokens || 0
|
||||
}
|
||||
|
||||
if (collectedUsageData.input_tokens !== undefined && !finalUsageReported) {
|
||||
// 提取input_tokens(如果存在)
|
||||
if (data.usage.input_tokens !== undefined) {
|
||||
collectedUsageData.input_tokens = data.usage.input_tokens || 0
|
||||
}
|
||||
|
||||
// 提取cache相关的tokens
|
||||
if (data.usage.cache_creation_input_tokens !== undefined) {
|
||||
collectedUsageData.cache_creation_input_tokens =
|
||||
data.usage.cache_creation_input_tokens || 0
|
||||
}
|
||||
if (data.usage.cache_read_input_tokens !== undefined) {
|
||||
collectedUsageData.cache_read_input_tokens =
|
||||
data.usage.cache_read_input_tokens || 0
|
||||
}
|
||||
|
||||
// 检查是否有详细的 cache_creation 对象
|
||||
if (
|
||||
data.usage.cache_creation &&
|
||||
typeof data.usage.cache_creation === 'object'
|
||||
) {
|
||||
collectedUsageData.cache_creation = {
|
||||
ephemeral_5m_input_tokens:
|
||||
data.usage.cache_creation.ephemeral_5m_input_tokens || 0,
|
||||
ephemeral_1h_input_tokens:
|
||||
data.usage.cache_creation.ephemeral_1h_input_tokens || 0
|
||||
}
|
||||
}
|
||||
|
||||
logger.info(
|
||||
'📊 [Console] Collected usage data from message_delta:',
|
||||
JSON.stringify(collectedUsageData)
|
||||
)
|
||||
|
||||
// 如果已经收集到了完整数据,触发回调
|
||||
if (
|
||||
collectedUsageData.input_tokens !== undefined &&
|
||||
collectedUsageData.output_tokens !== undefined &&
|
||||
!finalUsageReported
|
||||
) {
|
||||
logger.info(
|
||||
'🎯 [Console] Complete usage data collected:',
|
||||
JSON.stringify(collectedUsageData)
|
||||
)
|
||||
usageCallback({ ...collectedUsageData, accountId })
|
||||
finalUsageReported = true
|
||||
}
|
||||
@@ -569,6 +610,41 @@ class ClaudeConsoleRelayService {
|
||||
}
|
||||
}
|
||||
|
||||
// 🔧 兜底逻辑:确保所有未保存的usage数据都不会丢失
|
||||
if (!finalUsageReported) {
|
||||
if (
|
||||
collectedUsageData.input_tokens !== undefined ||
|
||||
collectedUsageData.output_tokens !== undefined
|
||||
) {
|
||||
// 补全缺失的字段
|
||||
if (collectedUsageData.input_tokens === undefined) {
|
||||
collectedUsageData.input_tokens = 0
|
||||
logger.warn(
|
||||
'⚠️ [Console] message_delta missing input_tokens, setting to 0. This may indicate incomplete usage data.'
|
||||
)
|
||||
}
|
||||
if (collectedUsageData.output_tokens === undefined) {
|
||||
collectedUsageData.output_tokens = 0
|
||||
logger.warn(
|
||||
'⚠️ [Console] message_delta missing output_tokens, setting to 0. This may indicate incomplete usage data.'
|
||||
)
|
||||
}
|
||||
// 确保有 model 字段
|
||||
if (!collectedUsageData.model) {
|
||||
collectedUsageData.model = body.model
|
||||
}
|
||||
logger.info(
|
||||
`📊 [Console] Saving incomplete usage data via fallback: ${JSON.stringify(collectedUsageData)}`
|
||||
)
|
||||
usageCallback({ ...collectedUsageData, accountId })
|
||||
finalUsageReported = true
|
||||
} else {
|
||||
logger.warn(
|
||||
'⚠️ [Console] Stream completed but no usage data was captured! This indicates a problem with SSE parsing or API response format.'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 确保流正确结束
|
||||
if (!responseStream.destroyed) {
|
||||
responseStream.end()
|
||||
|
||||
Reference in New Issue
Block a user