fix(pricing): 修复单独设置1K/2K/4K分辨率价格时因意图丢失quality导致价格无法匹配的Bug

This commit is contained in:
Danborad
2026-09-12 17:10:55 +08:00
parent 01a2d171f5
commit 476a91851e
3 changed files with 89 additions and 2 deletions

View File

@@ -524,7 +524,20 @@ func validateCreationSubmissionScope(run *model.CreationRun, version int64, req
if key == "videoSeconds" {
metadataKey = "seconds"
}
if approved := stringValue(meta[metadataKey]); approved != "" && approved != stringValue(config[key]) {
approved := strings.TrimSpace(stringValue(meta[metadataKey]))
candidate := strings.TrimSpace(stringValue(config[key]))
if metadataKey == "quality" {
approvedNorm := strings.ToLower(approved)
candidateNorm := strings.ToLower(candidate)
// auto/any 与空缺在图片生成中等价,前端 omittedImageQuality 可能会省略默认 quality
if (approvedNorm == "auto" || approvedNorm == "any" || approvedNorm == "") && (candidateNorm == "auto" || candidateNorm == "any" || candidateNorm == "") {
continue
}
if approvedNorm == candidateNorm {
continue
}
}
if approved != "" && approved != candidate {
return creationConflict("生成规格与已批准方案不同")
}
}

View File

@@ -388,7 +388,28 @@ func (s *Service) resolveSystemChannelModelSelection(input map[string]any, taskT
}
}
priceTier := channelModelPriceTierForIntent(*channelModel, intent)
pricingIntent := intent
if normalizeCapability(channelModel.Capability) == "image" {
pricingOptions := make(map[string]any, len(intent.Options)+2)
for k, v := range intent.Options {
pricingOptions[k] = v
}
rawQuality := strings.ToLower(strings.TrimSpace(fmt.Sprint(nextConfig["quality"])))
if rawQuality != "" && rawQuality != "<nil>" && rawQuality != "auto" && rawQuality != "any" {
pricingOptions["quality"] = rawQuality
} else if pricingOptions["quality"] == nil || pricingOptions["quality"] == "" || pricingOptions["quality"] == "auto" {
pricingOptions["quality"] = "1k"
}
if rawSize := strings.ToLower(strings.TrimSpace(fmt.Sprint(nextConfig["size"]))); rawSize != "" && rawSize != "<nil>" && rawSize != "auto" {
pricingOptions["size"] = rawSize
}
pricingIntent.Options = pricingOptions
}
priceTier := channelModelPriceTierForIntent(*channelModel, pricingIntent)
if priceTier == nil {
priceTier = channelModelPriceTierForIntent(*channelModel, intent)
}
if priceTier == nil || !ValidatePriceTierPrice(priceTier, channelModel.Capability, channelModel.Protocol) {
return input, ModelPriceNotConfigured("指定的模型未配置当前规格的有效价格")
}

View File

@@ -319,3 +319,56 @@ func newSelectionPriceTier(id string, selector string, providerModelKey string,
BillingMode: billingMode, UnitPriceMicrocredits: 10, PriceConfigured: true, Enabled: true,
}
}
func TestImageResolutionPricingOnSystemChannel(t *testing.T) {
profile := DefaultModelCapabilityConfigForModel(string(model.ChannelInterfaceGeminiImage), "gemini-image-model")
profile.Image.Quality = ImageQualityConfig{Supported: false, Default: "auto"}
profile.Image.Size = ImageSizeConfig{
Parameter: "aspect_ratio",
Values: []string{"1:1", "16:9"},
Default: "1:1",
Presets: []ImageSizePreset{
{Tier: "1k", Ratio: "16:9", Size: "1824x1024", Width: 1824, Height: 1024},
{Tier: "2k", Ratio: "16:9", Size: "2752x1536", Width: 2752, Height: 1536},
{Tier: "4k", Ratio: "16:9", Size: "3840x2160", Width: 3840, Height: 2160},
},
}
svc, _, channel, channelModel := createSystemChannelSelectionFixture(t, "image", model.ChannelInterfaceGeminiImage, profile, []model.ChannelModelPriceTier{
newSelectionPriceTier("tier-1k", `{"quality":"1k"}`, "provider-1k", "fixed_request"),
newSelectionPriceTier("tier-2k", `{"quality":"2k"}`, "provider-2k", "fixed_request"),
newSelectionPriceTier("tier-4k", `{"quality":"4k"}`, "provider-4k", "fixed_request"),
})
for _, tc := range []struct {
name string
quality string
size string
wantTier string
}{
{"1k specified", "1k", "16:9", "tier-1k"},
{"2k specified", "2k", "16:9", "tier-2k"},
{"4k specified", "4k", "16:9", "tier-4k"},
{"auto specified", "auto", "16:9", "tier-1k"},
{"empty specified", "", "16:9", "tier-1k"},
} {
t.Run(tc.name, func(t *testing.T) {
input := map[string]any{
"mode": "image",
"config": map[string]any{
"channelId": channel.ID,
"model": channelModel.ModelKey,
"size": tc.size,
"quality": tc.quality,
},
}
resolved, err := svc.resolveSystemChannelModelSelection(input, "canvas_image", "")
if err != nil {
t.Fatalf("resolve error: %v", err)
}
cfg := resolved["config"].(map[string]any)
if cfg["priceTierId"] != tc.wantTier {
t.Fatalf("priceTierId = %#v, want %s", cfg["priceTierId"], tc.wantTier)
}
})
}
}