|
@@ -184,19 +184,19 @@ func TextHelper(c *gin.Context, info *relaycommon.RelayInfo) (newAPIError *types
|
|
|
if usage.(*dto.Usage).CompletionTokenDetails.AudioTokens > 0 || usage.(*dto.Usage).PromptTokensDetails.AudioTokens > 0 {
|
|
if usage.(*dto.Usage).CompletionTokenDetails.AudioTokens > 0 || usage.(*dto.Usage).PromptTokensDetails.AudioTokens > 0 {
|
|
|
service.PostAudioConsumeQuota(c, info, usage.(*dto.Usage), "")
|
|
service.PostAudioConsumeQuota(c, info, usage.(*dto.Usage), "")
|
|
|
} else {
|
|
} else {
|
|
|
- postConsumeQuota(c, info, usage.(*dto.Usage), "")
|
|
|
|
|
|
|
+ postConsumeQuota(c, info, usage.(*dto.Usage))
|
|
|
}
|
|
}
|
|
|
return nil
|
|
return nil
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-func postConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, usage *dto.Usage, extraContent string) {
|
|
|
|
|
|
|
+func postConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, usage *dto.Usage, extraContent ...string) {
|
|
|
if usage == nil {
|
|
if usage == nil {
|
|
|
usage = &dto.Usage{
|
|
usage = &dto.Usage{
|
|
|
PromptTokens: relayInfo.GetEstimatePromptTokens(),
|
|
PromptTokens: relayInfo.GetEstimatePromptTokens(),
|
|
|
CompletionTokens: 0,
|
|
CompletionTokens: 0,
|
|
|
TotalTokens: relayInfo.GetEstimatePromptTokens(),
|
|
TotalTokens: relayInfo.GetEstimatePromptTokens(),
|
|
|
}
|
|
}
|
|
|
- extraContent += "(可能是请求出错)"
|
|
|
|
|
|
|
+ extraContent = append(extraContent, "上游无计费信息")
|
|
|
}
|
|
}
|
|
|
useTimeSeconds := time.Now().Unix() - relayInfo.StartTime.Unix()
|
|
useTimeSeconds := time.Now().Unix() - relayInfo.StartTime.Unix()
|
|
|
promptTokens := usage.PromptTokens
|
|
promptTokens := usage.PromptTokens
|
|
@@ -246,8 +246,8 @@ func postConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, usage
|
|
|
dWebSearchQuota = decimal.NewFromFloat(webSearchPrice).
|
|
dWebSearchQuota = decimal.NewFromFloat(webSearchPrice).
|
|
|
Mul(decimal.NewFromInt(int64(webSearchTool.CallCount))).
|
|
Mul(decimal.NewFromInt(int64(webSearchTool.CallCount))).
|
|
|
Div(decimal.NewFromInt(1000)).Mul(dGroupRatio).Mul(dQuotaPerUnit)
|
|
Div(decimal.NewFromInt(1000)).Mul(dGroupRatio).Mul(dQuotaPerUnit)
|
|
|
- extraContent += fmt.Sprintf("Web Search 调用 %d 次,上下文大小 %s,调用花费 %s",
|
|
|
|
|
- webSearchTool.CallCount, webSearchTool.SearchContextSize, dWebSearchQuota.String())
|
|
|
|
|
|
|
+ extraContent = append(extraContent, fmt.Sprintf("Web Search 调用 %d 次,上下文大小 %s,调用花费 %s",
|
|
|
|
|
+ webSearchTool.CallCount, webSearchTool.SearchContextSize, dWebSearchQuota.String()))
|
|
|
}
|
|
}
|
|
|
} else if strings.HasSuffix(modelName, "search-preview") {
|
|
} else if strings.HasSuffix(modelName, "search-preview") {
|
|
|
// search-preview 模型不支持 response api
|
|
// search-preview 模型不支持 response api
|
|
@@ -258,8 +258,8 @@ func postConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, usage
|
|
|
webSearchPrice = operation_setting.GetWebSearchPricePerThousand(modelName, searchContextSize)
|
|
webSearchPrice = operation_setting.GetWebSearchPricePerThousand(modelName, searchContextSize)
|
|
|
dWebSearchQuota = decimal.NewFromFloat(webSearchPrice).
|
|
dWebSearchQuota = decimal.NewFromFloat(webSearchPrice).
|
|
|
Div(decimal.NewFromInt(1000)).Mul(dGroupRatio).Mul(dQuotaPerUnit)
|
|
Div(decimal.NewFromInt(1000)).Mul(dGroupRatio).Mul(dQuotaPerUnit)
|
|
|
- extraContent += fmt.Sprintf("Web Search 调用 1 次,上下文大小 %s,调用花费 %s",
|
|
|
|
|
- searchContextSize, dWebSearchQuota.String())
|
|
|
|
|
|
|
+ extraContent = append(extraContent, fmt.Sprintf("Web Search 调用 1 次,上下文大小 %s,调用花费 %s",
|
|
|
|
|
+ searchContextSize, dWebSearchQuota.String()))
|
|
|
}
|
|
}
|
|
|
// claude web search tool 计费
|
|
// claude web search tool 计费
|
|
|
var dClaudeWebSearchQuota decimal.Decimal
|
|
var dClaudeWebSearchQuota decimal.Decimal
|
|
@@ -269,8 +269,8 @@ func postConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, usage
|
|
|
claudeWebSearchPrice = operation_setting.GetClaudeWebSearchPricePerThousand()
|
|
claudeWebSearchPrice = operation_setting.GetClaudeWebSearchPricePerThousand()
|
|
|
dClaudeWebSearchQuota = decimal.NewFromFloat(claudeWebSearchPrice).
|
|
dClaudeWebSearchQuota = decimal.NewFromFloat(claudeWebSearchPrice).
|
|
|
Div(decimal.NewFromInt(1000)).Mul(dGroupRatio).Mul(dQuotaPerUnit).Mul(decimal.NewFromInt(int64(claudeWebSearchCallCount)))
|
|
Div(decimal.NewFromInt(1000)).Mul(dGroupRatio).Mul(dQuotaPerUnit).Mul(decimal.NewFromInt(int64(claudeWebSearchCallCount)))
|
|
|
- extraContent += fmt.Sprintf("Claude Web Search 调用 %d 次,调用花费 %s",
|
|
|
|
|
- claudeWebSearchCallCount, dClaudeWebSearchQuota.String())
|
|
|
|
|
|
|
+ extraContent = append(extraContent, fmt.Sprintf("Claude Web Search 调用 %d 次,调用花费 %s",
|
|
|
|
|
+ claudeWebSearchCallCount, dClaudeWebSearchQuota.String()))
|
|
|
}
|
|
}
|
|
|
// file search tool 计费
|
|
// file search tool 计费
|
|
|
var dFileSearchQuota decimal.Decimal
|
|
var dFileSearchQuota decimal.Decimal
|
|
@@ -281,8 +281,8 @@ func postConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, usage
|
|
|
dFileSearchQuota = decimal.NewFromFloat(fileSearchPrice).
|
|
dFileSearchQuota = decimal.NewFromFloat(fileSearchPrice).
|
|
|
Mul(decimal.NewFromInt(int64(fileSearchTool.CallCount))).
|
|
Mul(decimal.NewFromInt(int64(fileSearchTool.CallCount))).
|
|
|
Div(decimal.NewFromInt(1000)).Mul(dGroupRatio).Mul(dQuotaPerUnit)
|
|
Div(decimal.NewFromInt(1000)).Mul(dGroupRatio).Mul(dQuotaPerUnit)
|
|
|
- extraContent += fmt.Sprintf("File Search 调用 %d 次,调用花费 %s",
|
|
|
|
|
- fileSearchTool.CallCount, dFileSearchQuota.String())
|
|
|
|
|
|
|
+ extraContent = append(extraContent, fmt.Sprintf("File Search 调用 %d 次,调用花费 %s",
|
|
|
|
|
+ fileSearchTool.CallCount, dFileSearchQuota.String()))
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
var dImageGenerationCallQuota decimal.Decimal
|
|
var dImageGenerationCallQuota decimal.Decimal
|
|
@@ -290,7 +290,7 @@ func postConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, usage
|
|
|
if ctx.GetBool("image_generation_call") {
|
|
if ctx.GetBool("image_generation_call") {
|
|
|
imageGenerationCallPrice = operation_setting.GetGPTImage1PriceOnceCall(ctx.GetString("image_generation_call_quality"), ctx.GetString("image_generation_call_size"))
|
|
imageGenerationCallPrice = operation_setting.GetGPTImage1PriceOnceCall(ctx.GetString("image_generation_call_quality"), ctx.GetString("image_generation_call_size"))
|
|
|
dImageGenerationCallQuota = decimal.NewFromFloat(imageGenerationCallPrice).Mul(dGroupRatio).Mul(dQuotaPerUnit)
|
|
dImageGenerationCallQuota = decimal.NewFromFloat(imageGenerationCallPrice).Mul(dGroupRatio).Mul(dQuotaPerUnit)
|
|
|
- extraContent += fmt.Sprintf("Image Generation Call 花费 %s", dImageGenerationCallQuota.String())
|
|
|
|
|
|
|
+ extraContent = append(extraContent, fmt.Sprintf("Image Generation Call 花费 %s", dImageGenerationCallQuota.String()))
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
var quotaCalculateDecimal decimal.Decimal
|
|
var quotaCalculateDecimal decimal.Decimal
|
|
@@ -331,7 +331,7 @@ func postConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, usage
|
|
|
// 重新计算 base tokens
|
|
// 重新计算 base tokens
|
|
|
baseTokens = baseTokens.Sub(dAudioTokens)
|
|
baseTokens = baseTokens.Sub(dAudioTokens)
|
|
|
audioInputQuota = decimal.NewFromFloat(audioInputPrice).Div(decimal.NewFromInt(1000000)).Mul(dAudioTokens).Mul(dGroupRatio).Mul(dQuotaPerUnit)
|
|
audioInputQuota = decimal.NewFromFloat(audioInputPrice).Div(decimal.NewFromInt(1000000)).Mul(dAudioTokens).Mul(dGroupRatio).Mul(dQuotaPerUnit)
|
|
|
- extraContent += fmt.Sprintf("Audio Input 花费 %s", audioInputQuota.String())
|
|
|
|
|
|
|
+ extraContent = append(extraContent, fmt.Sprintf("Audio Input 花费 %s", audioInputQuota.String()))
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
promptQuota := baseTokens.Add(cachedTokensWithRatio).
|
|
promptQuota := baseTokens.Add(cachedTokensWithRatio).
|
|
@@ -356,17 +356,25 @@ func postConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, usage
|
|
|
// 添加 image generation call 计费
|
|
// 添加 image generation call 计费
|
|
|
quotaCalculateDecimal = quotaCalculateDecimal.Add(dImageGenerationCallQuota)
|
|
quotaCalculateDecimal = quotaCalculateDecimal.Add(dImageGenerationCallQuota)
|
|
|
|
|
|
|
|
|
|
+ if len(relayInfo.PriceData.OtherRatios) > 0 {
|
|
|
|
|
+ for key, otherRatio := range relayInfo.PriceData.OtherRatios {
|
|
|
|
|
+ dOtherRatio := decimal.NewFromFloat(otherRatio)
|
|
|
|
|
+ quotaCalculateDecimal = quotaCalculateDecimal.Mul(dOtherRatio)
|
|
|
|
|
+ extraContent = append(extraContent, fmt.Sprintf("其他倍率 %s: %f", key, otherRatio))
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
quota := int(quotaCalculateDecimal.Round(0).IntPart())
|
|
quota := int(quotaCalculateDecimal.Round(0).IntPart())
|
|
|
totalTokens := promptTokens + completionTokens
|
|
totalTokens := promptTokens + completionTokens
|
|
|
|
|
|
|
|
- var logContent string
|
|
|
|
|
|
|
+ //var logContent string
|
|
|
|
|
|
|
|
// record all the consume log even if quota is 0
|
|
// record all the consume log even if quota is 0
|
|
|
if totalTokens == 0 {
|
|
if totalTokens == 0 {
|
|
|
// in this case, must be some error happened
|
|
// in this case, must be some error happened
|
|
|
// we cannot just return, because we may have to return the pre-consumed quota
|
|
// we cannot just return, because we may have to return the pre-consumed quota
|
|
|
quota = 0
|
|
quota = 0
|
|
|
- logContent += fmt.Sprintf("(可能是上游超时)")
|
|
|
|
|
|
|
+ extraContent = append(extraContent, "上游没有返回计费信息,无法扣费(可能是上游超时)")
|
|
|
logger.LogError(ctx, fmt.Sprintf("total tokens is 0, cannot consume quota, userId %d, channelId %d, "+
|
|
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, modelName, relayInfo.FinalPreConsumedQuota))
|
|
"tokenId %d, model %s, pre-consumed quota %d", relayInfo.UserId, relayInfo.ChannelId, relayInfo.TokenId, modelName, relayInfo.FinalPreConsumedQuota))
|
|
|
} else {
|
|
} else {
|
|
@@ -405,15 +413,13 @@ func postConsumeQuota(ctx *gin.Context, relayInfo *relaycommon.RelayInfo, usage
|
|
|
logModel := modelName
|
|
logModel := modelName
|
|
|
if strings.HasPrefix(logModel, "gpt-4-gizmo") {
|
|
if strings.HasPrefix(logModel, "gpt-4-gizmo") {
|
|
|
logModel = "gpt-4-gizmo-*"
|
|
logModel = "gpt-4-gizmo-*"
|
|
|
- logContent += fmt.Sprintf(",模型 %s", modelName)
|
|
|
|
|
|
|
+ extraContent = append(extraContent, fmt.Sprintf("模型 %s", modelName))
|
|
|
}
|
|
}
|
|
|
if strings.HasPrefix(logModel, "gpt-4o-gizmo") {
|
|
if strings.HasPrefix(logModel, "gpt-4o-gizmo") {
|
|
|
logModel = "gpt-4o-gizmo-*"
|
|
logModel = "gpt-4o-gizmo-*"
|
|
|
- logContent += fmt.Sprintf(",模型 %s", modelName)
|
|
|
|
|
- }
|
|
|
|
|
- if extraContent != "" {
|
|
|
|
|
- logContent += ", " + extraContent
|
|
|
|
|
|
|
+ extraContent = append(extraContent, fmt.Sprintf("模型 %s", modelName))
|
|
|
}
|
|
}
|
|
|
|
|
+ logContent := strings.Join(extraContent, ", ")
|
|
|
other := service.GenerateTextOtherInfo(ctx, relayInfo, modelRatio, groupRatio, completionRatio, cacheTokens, cacheRatio, modelPrice, relayInfo.PriceData.GroupRatioInfo.GroupSpecialRatio)
|
|
other := service.GenerateTextOtherInfo(ctx, relayInfo, modelRatio, groupRatio, completionRatio, cacheTokens, cacheRatio, modelPrice, relayInfo.PriceData.GroupRatioInfo.GroupSpecialRatio)
|
|
|
if imageTokens != 0 {
|
|
if imageTokens != 0 {
|
|
|
other["image"] = true
|
|
other["image"] = true
|