Files
2026-08-17 10:01:04 +08:00

90 lines
4.1 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package common
import "github.com/qianfree/team-api/relay/dto"
// TokenDetails Token 使用量细分
type TokenDetails struct {
CachedTokens int `json:"cached_tokens,omitempty"`
CachedCreationTokens int `json:"cached_creation_tokens,omitempty"` // Claude cache_creation_input_tokens
CachedCreation5mTokens int `json:"cached_creation_5m_tokens,omitempty"` // Claude 5分钟缓存创建
CachedCreation1hTokens int `json:"cached_creation_1h_tokens,omitempty"` // Claude 1小时缓存创建
// CacheWriteTokens 本次写入缓存的 token(OpenAI Responses cache_write_tokens,观测字段)。
// 注意:OpenAI 缓存写入按普通输入价计费(含于 PromptTokens),不得并入 CachedCreationTokens
// 计费桶(Claude 写入才有独立 CacheCreationPrice),计费引擎不读取本字段
CacheWriteTokens int `json:"cache_write_tokens,omitempty"`
AudioTokens int `json:"audio_tokens,omitempty"`
TextTokens int `json:"text_tokens,omitempty"`
ImageTokens int `json:"image_tokens,omitempty"`
ReasoningTokens int `json:"reasoning_tokens,omitempty"`
AcceptedPredictionTokens int `json:"accepted_prediction_tokens,omitempty"`
RejectedPredictionTokens int `json:"rejected_prediction_tokens,omitempty"`
}
// Usage Token 使用量信息
type Usage struct {
PromptTokens int `json:"prompt_tokens"`
CompletionTokens int `json:"completion_tokens"`
TotalTokens int `json:"total_tokens"`
CacheCreationTokens int `json:"cache_creation_tokens,omitempty"` // 缓存创建 token 总量
PromptTokensDetails *TokenDetails `json:"prompt_tokens_details,omitempty"`
CompletionTokenDetails *TokenDetails `json:"completion_token_details,omitempty"`
// CacheIncludedInPrompt 标记 PromptTokens 是否包含 cache tokens。
// true: PromptTokens 是总量,cache 是其子集,计费时需扣减避免重复计费(OpenAI 原生 API)
// false(默认): PromptTokens 与 cache 独立,不扣减(Claude API、第三方兼容 API)
CacheIncludedInPrompt bool `json:"-"`
}
// TotalInputTokens 返回「含缓存的总输入 token」:口径未包含缓存(Claude)时补加缓存读/写,
// 口径已包含(OpenAI/Gemini)时原样返回。bil_usage_logs.input_tokens 统一按此口径入库,
// 保证跨渠道 SUM 聚合语义一致(cache_read/cache_creation 列为其子集明细)。
func (u *Usage) TotalInputTokens() int {
if u == nil {
return 0
}
total := u.PromptTokens
if !u.CacheIncludedInPrompt && u.PromptTokensDetails != nil {
total += u.PromptTokensDetails.CachedTokens + u.PromptTokensDetails.CachedCreationTokens
}
return total
}
// DtoTokenDetailsToCommon 将 dto.TokenDetails 转换为 common.TokenDetails
func DtoTokenDetailsToCommon(d *dto.TokenDetails) *TokenDetails {
if d == nil {
return nil
}
return &TokenDetails{
CachedTokens: d.CachedTokens,
CachedCreationTokens: d.CachedCreationTokens,
CachedCreation5mTokens: d.CachedCreation5mTokens,
CachedCreation1hTokens: d.CachedCreation1hTokens,
CacheWriteTokens: d.CacheWriteTokens,
AudioTokens: d.AudioTokens,
TextTokens: d.TextTokens,
ImageTokens: d.ImageTokens,
ReasoningTokens: d.ReasoningTokens,
AcceptedPredictionTokens: d.AcceptedPredictionTokens,
RejectedPredictionTokens: d.RejectedPredictionTokens,
}
}
// CommonTokenDetailsToDto 将 common.TokenDetails 转换为 dto.TokenDetails
func CommonTokenDetailsToDto(c *TokenDetails) *dto.TokenDetails {
if c == nil {
return nil
}
return &dto.TokenDetails{
CachedTokens: c.CachedTokens,
CachedCreationTokens: c.CachedCreationTokens,
CachedCreation5mTokens: c.CachedCreation5mTokens,
CachedCreation1hTokens: c.CachedCreation1hTokens,
CacheWriteTokens: c.CacheWriteTokens,
AudioTokens: c.AudioTokens,
TextTokens: c.TextTokens,
ImageTokens: c.ImageTokens,
ReasoningTokens: c.ReasoningTokens,
AcceptedPredictionTokens: c.AcceptedPredictionTokens,
RejectedPredictionTokens: c.RejectedPredictionTokens,
}
}