feat: publish sanitized custom.97 source
This commit is contained in:
1022 files changed
+69903
-19207
No files matched your search
+37
-32
@@ -1,7 +1,6 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
"strings"
|
||||
@@ -68,11 +67,15 @@ type textQuotaSummary struct {
|
||||
}
|
||||
|
||||
// hasBillableUsage reports whether this request should incur any charge.
|
||||
// A request can carry zero tokens yet still be billable via a tool-call
|
||||
// Claude reports cache tokens separately from ordinary input and output.
|
||||
// A request can carry zero ordinary tokens yet still be billable via cache or a tool-call
|
||||
// surcharge (e.g. /v1/alpha/search returns no usage but bills one web_search
|
||||
// call), so token count alone is not sufficient to decide.
|
||||
func (s *textQuotaSummary) hasBillableUsage() bool {
|
||||
return s.FixedPriceBilling || s.TotalTokens > 0 || !s.ToolCallSurchargeQuota.IsZero()
|
||||
return s.FixedPriceBilling || s.TotalTokens > 0 ||
|
||||
(s.IsClaudeUsageSemantic && (s.CacheTokens > 0 || s.CacheCreationTokens > 0 ||
|
||||
s.CacheCreationTokens5m > 0 || s.CacheCreationTokens1h > 0)) ||
|
||||
!s.ToolCallSurchargeQuota.IsZero()
|
||||
}
|
||||
|
||||
func cacheWriteTokensTotal(summary textQuotaSummary) int {
|
||||
@@ -132,7 +135,7 @@ func mergeToolSurchargeItems(items []ToolSurchargeItem) []ToolSurchargeItem {
|
||||
merged[lastIndex].Name == item.Name &&
|
||||
merged[lastIndex].Price == item.Price {
|
||||
if item.Count > math.MaxInt-merged[lastIndex].Count {
|
||||
common.SysError("tool surcharge call count overflow for " + item.Name)
|
||||
common.SysError(common.LogText("tool surcharge call count overflow for %s", item.Name))
|
||||
merged[lastIndex].Count = math.MaxInt
|
||||
} else {
|
||||
merged[lastIndex].Count += item.Count
|
||||
@@ -155,7 +158,12 @@ func calculateTextToolCallSurcharge(ctx *gin.Context, relayInfo *relaycommon.Rel
|
||||
if tool == nil {
|
||||
continue
|
||||
}
|
||||
items = collectToolSurchargeItem(items, name, tool.CallCount, summary.ModelName)
|
||||
count := tool.CallCount
|
||||
if count > relaycommon.MaxBillableToolCallCount {
|
||||
logger.LogWarn(ctx, common.LogText("tool surcharge call count clamped: tool=%s count=%d", name, count))
|
||||
count = relaycommon.MaxBillableToolCallCount
|
||||
}
|
||||
items = collectToolSurchargeItem(items, name, count, summary.ModelName)
|
||||
}
|
||||
}
|
||||
if relayInfo.RelayMode != relayconstant.RelayModeResponses &&
|
||||
@@ -163,17 +171,6 @@ func calculateTextToolCallSurcharge(ctx *gin.Context, relayInfo *relaycommon.Rel
|
||||
items = collectToolSurchargeItem(items, dto.BuildInToolWebSearchPreview, 1, summary.ModelName)
|
||||
}
|
||||
|
||||
items = collectToolSurchargeItem(
|
||||
items,
|
||||
dto.BuildInToolWebSearch,
|
||||
ctx.GetInt("claude_web_search_requests"),
|
||||
summary.ModelName,
|
||||
)
|
||||
|
||||
if ctx.GetBool("gemini_google_search_call") {
|
||||
items = collectToolSurchargeItem(items, dto.BuildInToolGoogleSearch, 1, summary.ModelName)
|
||||
}
|
||||
|
||||
summary.ToolSurchargeItems = mergeToolSurchargeItems(items)
|
||||
var surcharge decimal.Decimal
|
||||
for _, item := range summary.ToolSurchargeItems {
|
||||
@@ -390,11 +387,18 @@ func usageSemanticFromUsage(relayInfo *relaycommon.RelayInfo, usage *dto.Usage)
|
||||
return "openai"
|
||||
}
|
||||
|
||||
func PostTextConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, usage *dto.Usage, extraContent []string) {
|
||||
func PostTextConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, usage *dto.Usage, extraContent []*common.Message) {
|
||||
originUsage := usage
|
||||
billingUsage := effectiveBillingUsage(usage)
|
||||
var cacheReadAdjustment *claudeCacheReadAdjustment
|
||||
if !common.GetContextKeyBool(ctx, constant.ContextKeyLocalCountTokens) {
|
||||
billingUsage, cacheReadAdjustment = normalizeClaudeCacheReadUsage(relayInfo, billingUsage)
|
||||
if cacheReadAdjustment != nil && cacheReadAdjustment.Status == "invalid_usage" {
|
||||
logger.LogWarn(ctx, "invalid Claude cache-read usage; channel compatibility adjustment skipped")
|
||||
}
|
||||
}
|
||||
if usage == nil {
|
||||
extraContent = append(extraContent, "上游无计费信息")
|
||||
extraContent = append(extraContent, common.NewMessage("Upstream returned no usage"))
|
||||
}
|
||||
if originUsage != nil && !ctx.GetBool("attempt_checkpoint") {
|
||||
ObserveChannelAffinityUsageCacheByRelayFormat(ctx, billingUsage, relayInfo.GetFinalRequestRelayFormat())
|
||||
@@ -437,21 +441,20 @@ func PostTextConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, us
|
||||
Div(decimal.NewFromInt(1000)).
|
||||
Mul(decimal.NewFromFloat(summary.GroupRatio)).
|
||||
Mul(decimal.NewFromFloat(common.QuotaPerUnit))
|
||||
extraContent = append(extraContent, fmt.Sprintf(
|
||||
"%s 调用 %d 次,调用花费 %s",
|
||||
item.Name,
|
||||
item.Count,
|
||||
logger.LogQuota(common.QuotaFromDecimal(q)),
|
||||
))
|
||||
extraContent = append(extraContent, common.NewMessage("{{name}} called {{count}} times, cost {{quota}}", map[string]any{
|
||||
"name": item.Name,
|
||||
"count": item.Count,
|
||||
"quota": logger.FormatQuota(common.QuotaFromDecimal(q)),
|
||||
}))
|
||||
}
|
||||
if summary.AudioInputPrice > 0 && summary.AudioTokens > 0 {
|
||||
q := decimal.NewFromFloat(summary.AudioInputPrice).Div(decimal.NewFromInt(1000000)).Mul(decimal.NewFromInt(int64(summary.AudioTokens))).Mul(decimal.NewFromFloat(summary.GroupRatio)).Mul(decimal.NewFromFloat(common.QuotaPerUnit))
|
||||
extraContent = append(extraContent, fmt.Sprintf("Audio Input 花费 %s", logger.LogQuota(common.QuotaFromDecimal(q))))
|
||||
extraContent = append(extraContent, common.NewMessage("Audio input cost {{quota}}", map[string]any{"quota": logger.FormatQuota(common.QuotaFromDecimal(q))}))
|
||||
}
|
||||
|
||||
if !summary.hasBillableUsage() {
|
||||
extraContent = append(extraContent, "上游没有返回计费信息,无法扣费(可能是上游超时)")
|
||||
logger.LogError(ctx, fmt.Sprintf("total tokens is 0, cannot consume quota, userId %d, channelId %d, tokenId %d, model %s, pre-consumed quota %d", relayInfo.UserId, relayInfo.ChannelId, relayInfo.TokenId, summary.ModelName, relayInfo.FinalPreConsumedQuota))
|
||||
extraContent = append(extraContent, common.NewMessage("Upstream returned no usage, so nothing was charged (possibly an upstream timeout)"))
|
||||
logger.LogError(ctx, common.LogText("total tokens is 0, cannot consume quota, userId %d, channelId %d, tokenId %d, model %s, pre-consumed quota %d", relayInfo.UserId, relayInfo.ChannelId, relayInfo.TokenId, summary.ModelName, relayInfo.FinalPreConsumedQuota))
|
||||
} else if relayInfo.DurableAttemptID == 0 {
|
||||
model.UpdateUserUsedQuotaAndRequestCount(relayInfo.UserId, summary.Quota)
|
||||
model.UpdateChannelUsedQuota(relayInfo.ChannelId, summary.Quota)
|
||||
@@ -459,21 +462,20 @@ func PostTextConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, us
|
||||
|
||||
if relayInfo.DurableAttemptID == 0 {
|
||||
if err := SettleBilling(ctx, relayInfo, summary.Quota); err != nil {
|
||||
logger.LogError(ctx, "error settling billing: "+err.Error())
|
||||
logger.LogError(ctx, common.LogText("error settling billing: %s", err.Error()))
|
||||
}
|
||||
}
|
||||
|
||||
logModel := summary.ModelName
|
||||
if strings.HasPrefix(logModel, "gpt-4-gizmo") {
|
||||
logModel = "gpt-4-gizmo-*"
|
||||
extraContent = append(extraContent, fmt.Sprintf("模型 %s", summary.ModelName))
|
||||
extraContent = append(extraContent, common.NewMessage("Model {{model}}", map[string]any{"model": summary.ModelName}))
|
||||
}
|
||||
if strings.HasPrefix(logModel, "gpt-4o-gizmo") {
|
||||
logModel = "gpt-4o-gizmo-*"
|
||||
extraContent = append(extraContent, fmt.Sprintf("模型 %s", summary.ModelName))
|
||||
extraContent = append(extraContent, common.NewMessage("Model {{model}}", map[string]any{"model": summary.ModelName}))
|
||||
}
|
||||
|
||||
logContent := strings.Join(extraContent, ", ")
|
||||
var other *model.LogOther
|
||||
if summary.IsClaudeUsageSemantic {
|
||||
other = GenerateClaudeOtherInfo(ctx, relayInfo,
|
||||
@@ -488,6 +490,9 @@ func PostTextConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, us
|
||||
other = GenerateTextOtherInfo(ctx, relayInfo, summary.ModelRatio, summary.GroupRatio, summary.CompletionRatio, summary.CacheTokens, summary.CacheRatio, summary.ModelPrice, relayInfo.PriceData.GroupRatioInfo.GroupSpecialRatio)
|
||||
}
|
||||
appendUsageBillingPathForLog(other, common.GetContextKeyBool(ctx, constant.ContextKeyLocalCountTokens), originUsage)
|
||||
if cacheReadAdjustment != nil {
|
||||
other.SetAdmin("cache_read_adjustment", cacheReadAdjustment)
|
||||
}
|
||||
if adminRejectReason != "" {
|
||||
other.SetAdmin("reject_reason", adminRejectReason)
|
||||
}
|
||||
@@ -542,7 +547,7 @@ func PostTextConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, us
|
||||
ModelName: logModel,
|
||||
TokenName: summary.TokenName,
|
||||
Quota: summary.Quota,
|
||||
Content: logContent,
|
||||
Content: extraContent,
|
||||
TokenId: relayInfo.TokenId,
|
||||
UseTimeSeconds: int(summary.UseTimeSeconds),
|
||||
IsStream: relayInfo.IsStream,
|
||||
|
||||
Reference in new issue
Block a user