mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-07 13:18:18 +08:00
fix: 未知 Grok 文本兜底排除 image/video/audio 等媒体族
带版本号的媒体 ID(grok-2-image-1212、grok-5-video)会被 grok-N* 白名单当成文本,错吃 4.5 token 价。vision 多模态 仍按 token 计;HasIdentifiedTokenPricing 也不放行这些 ID。
This commit is contained in:
@@ -862,6 +862,9 @@ func (s *BillingService) grokUnknownTextFamilyFallback(model string) *ModelPrici
|
||||
|
||||
func isGrokUnknownTextFamilyModel(model string) bool {
|
||||
native := strings.ToLower(strings.TrimSpace(xai.StripGrokProviderPrefix(model)))
|
||||
if isGrokMediaFamilyModel(native) {
|
||||
return false
|
||||
}
|
||||
switch {
|
||||
case native == "grok", native == "grok-latest":
|
||||
return true
|
||||
@@ -877,6 +880,19 @@ func isGrokUnknownTextFamilyModel(model string) bool {
|
||||
}
|
||||
}
|
||||
|
||||
// isGrokMediaFamilyModel matches ids that are billed per image/video/audio unit
|
||||
// rather than per token, so version-numbered media ids (grok-2-image-1212,
|
||||
// grok-5-video) cannot slip into the unknown-text fallback and pick up a token
|
||||
// card. "vision" is deliberately absent: multimodal chat models are token billed.
|
||||
func isGrokMediaFamilyModel(native string) bool {
|
||||
for _, marker := range []string{"imagine", "image", "video", "audio", "speech", "tts", "transcribe", "realtime"} {
|
||||
if strings.Contains(native, marker) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// HasIdentifiedTokenPricing 判断模型能否在价格表中被"确定性识别"出 token 价格。
|
||||
//
|
||||
// 与 GetModelPricing 的关键区别:本函数拒绝按子串猜系列的兜底。GetModelPricing 会
|
||||
|
||||
@@ -1221,6 +1221,14 @@ func TestGetModelPricing_UnknownGrokTextFallsBackToGrok45(t *testing.T) {
|
||||
require.InDelta(t, baseline.CacheReadPricePerToken, pricing.CacheReadPricePerToken, 1e-12, model)
|
||||
}
|
||||
|
||||
// Per-unit media ids must not inherit the text card just because they carry
|
||||
// a version number; they are billed by the image/video/audio paths instead.
|
||||
for _, model := range []string{"grok-2-image-1212", "grok-2-audio", "grok-5-video", "x-ai/grok-6-image"} {
|
||||
require.False(t, isGrokUnknownTextFamilyModel(model), "model %s", model)
|
||||
}
|
||||
// Multimodal chat models stay token billed.
|
||||
require.True(t, isGrokUnknownTextFamilyModel("grok-2-vision-1212"))
|
||||
|
||||
for _, model := range []string{
|
||||
"grok-imagine-image-3.0",
|
||||
"grok-imagine-video-2",
|
||||
|
||||
@@ -372,6 +372,12 @@ func TestBillingServiceHasIdentifiedTokenPricing_RejectsFamilyGuesses(t *testing
|
||||
}
|
||||
require.False(t, billing.HasIdentifiedTokenPricing(""))
|
||||
require.False(t, billing.HasIdentifiedTokenPricing("zz-unpriced-response-model"))
|
||||
// Versioned media ids may inherit a text card via GetModelPricing; the
|
||||
// identified-token gate must still reject them so response-model billing
|
||||
// cannot adopt grok-4.5 rates for image/audio/video ids.
|
||||
require.False(t, billing.HasIdentifiedTokenPricing("grok-2-image-1212"))
|
||||
require.False(t, billing.HasIdentifiedTokenPricing("grok-2-audio"))
|
||||
require.False(t, billing.HasIdentifiedTokenPricing("grok-5-video"))
|
||||
}
|
||||
|
||||
func TestGatewayServiceRecordUsage_ResponseModelRejectsUnidentifiedFamilyName(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user