Просмотр исходного кода

fix: move image count n to OtherRatio to prevent double-counting

The previous commit commented out AddOtherRatio("n") in the Ali
adaptor to fix double-counting but this could cause billing evasion
when n is specified via extra["parameters"] instead of request.N.

Root cause: ImagePriceRatio in GetTokenCountMeta() already included
n, AND channel adaptors added OtherRatio("n"), resulting in n²
billing.

Proper fix:
- Remove n from ImagePriceRatio (keep sizeRatio * qualityRatio only)
- In ImageHelper, add default OtherRatio("n") when adaptor hasn't
  set one; set fallback tokens to 1 (base unit)
- Restore Ali adaptor's AddOtherRatio("n") — it uses actual upstream
  parameters/response count, preventing billing evasion
CaIon 1 месяц назад
Родитель
Сommit
ab99c30884
3 измененных файлов с 24 добавлено и 19 удалено
  1. 5 6
      dto/openai_image.go
  2. 8 11
      relay/channel/ali/image.go
  3. 11 2
      relay/image_handler.go

+ 5 - 6
dto/openai_image.go

@@ -148,15 +148,14 @@ func (i *ImageRequest) GetTokenCountMeta() *types.TokenCountMeta {
 		}
 	}
 
-	// not support token count for dalle
-	n := uint(1)
-	if i.N != nil {
-		n = *i.N
-	}
+	// n is NOT included here; it is handled via OtherRatio("n") in
+	// image_handler.go (default) or channel adaptors (actual count).
+	// Including n here caused double-counting for channels that also
+	// set OtherRatio("n") (e.g. Ali/Bailian).
 	return &types.TokenCountMeta{
 		CombineText:     i.Prompt,
 		MaxTokens:       1584,
-		ImagePriceRatio: sizeRatio * qualityRatio * float64(n),
+		ImagePriceRatio: sizeRatio * qualityRatio,
 	}
 }
 

+ 8 - 11
relay/channel/ali/image.go

@@ -54,10 +54,9 @@ func oaiImage2AliImageRequest(info *relaycommon.RelayInfo, request dto.ImageRequ
 		}
 	}
 
-	// 检查n参数
-	// if imageRequest.Parameters.N != 0 {
-	// 	info.PriceData.AddOtherRatio("n", float64(imageRequest.Parameters.N))
-	// }
+	if imageRequest.Parameters.N != 0 {
+		info.PriceData.AddOtherRatio("n", float64(imageRequest.Parameters.N))
+	}
 
 	// 同步图片模型和异步图片模型请求格式不一样
 	if isSync {
@@ -328,13 +327,11 @@ func aliImageHandler(a *Adaptor, c *gin.Context, resp *http.Response, info *rela
 	}
 
 	imageResponses := responseAli2OpenAIImage(c, aliResponse, originRespBody, info, responseFormat)
-	// 可能生成多张图片,修正计费数量n
-	// 注释掉,否则会导致多次扣费用
-	// if aliResponse.Usage.ImageCount != 0 {
-	// 	info.PriceData.AddOtherRatio("n", float64(aliResponse.Usage.ImageCount))
-	// } else if len(imageResponses.Data) != 0 {
-	// 	info.PriceData.AddOtherRatio("n", float64(len(imageResponses.Data)))
-	// }
+	if aliResponse.Usage.ImageCount != 0 {
+		info.PriceData.AddOtherRatio("n", float64(aliResponse.Usage.ImageCount))
+	} else if len(imageResponses.Data) != 0 {
+		info.PriceData.AddOtherRatio("n", float64(len(imageResponses.Data)))
+	}
 	jsonResponse, err := common.Marshal(imageResponses)
 	if err != nil {
 		return types.NewError(err, types.ErrorCodeBadResponseBody), nil

+ 11 - 2
relay/image_handler.go

@@ -117,11 +117,20 @@ func ImageHelper(c *gin.Context, info *relaycommon.RelayInfo) (newAPIError *type
 	if request.N != nil {
 		imageN = *request.N
 	}
+
+	// n is handled via OtherRatio so it is applied exactly once in quota
+	// calculation (both price-based and ratio-based paths).
+	// Adaptors may have already set a more accurate count from the
+	// upstream response; only set the default when they haven't.
+	if _, hasN := info.PriceData.OtherRatios["n"]; !hasN {
+		info.PriceData.AddOtherRatio("n", float64(imageN))
+	}
+
 	if usage.(*dto.Usage).TotalTokens == 0 {
-		usage.(*dto.Usage).TotalTokens = int(imageN)
+		usage.(*dto.Usage).TotalTokens = 1
 	}
 	if usage.(*dto.Usage).PromptTokens == 0 {
-		usage.(*dto.Usage).PromptTokens = int(imageN)
+		usage.(*dto.Usage).PromptTokens = 1
 	}
 
 	quality := "standard"