From 6d86ead4937cd93f73af4a83723989c65fd087d5 Mon Sep 17 00:00:00 2001 From: MasterChiefCN <49179444+MasterChiefCN@users.noreply.github.com> Date: Mon, 24 Aug 2026 10:05:09 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=8C=89=E5=8F=82=E8=80=83=E7=B4=A0?= =?UTF-8?q?=E6=9D=90=E5=8C=B9=E9=85=8D=E8=A7=86=E9=A2=91=E7=94=9F=E6=88=90?= =?UTF-8?q?=E4=BB=B7=E6=A0=BC=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/internal/service/model_router.go | 8 ++++ backend/internal/service/model_router_test.go | 47 +++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/backend/internal/service/model_router.go b/backend/internal/service/model_router.go index 0f815dbda..36e841ad0 100644 --- a/backend/internal/service/model_router.go +++ b/backend/internal/service/model_router.go @@ -684,6 +684,14 @@ func skuSelectorForIntent(intent ModelRequestIntent) map[string]string { } switch normalizeCapability(intent.Capability) { case "video": + // 价格档按实际参考素材归类。供应商执行仍可使用 reference_to_video、extend + // 等细分操作;计价时视频参考优先归为视频生视频,其余图片参考无论数量 + // 都归为图生视频。 + if intent.Inputs["video"] > 0 { + selector["operation"] = "video_to_video" + } else if intent.Inputs["image"] > 0 { + selector["operation"] = "image_to_video" + } if count := intent.Inputs["image"]; count > 0 { selector["imageCount"] = strconv.Itoa(count) } diff --git a/backend/internal/service/model_router_test.go b/backend/internal/service/model_router_test.go index 6eb5d5c48..e076f1e74 100644 --- a/backend/internal/service/model_router_test.go +++ b/backend/internal/service/model_router_test.go @@ -31,3 +31,50 @@ func TestSKUSelectorIncludesVideoReferenceImageCount(t *testing.T) { t.Fatalf("matched tier = %#v", matched) } } + +func TestSKUSelectorTreatsAnyVideoReferenceAsVideoToVideo(t *testing.T) { + intent := ModelRequestIntentFromTaskInput(map[string]any{ + "mode": "video", + "referenceImages": []any{map[string]any{"url": "https://example.com/reference.png"}}, + "referenceVideos": []any{map[string]any{"url": "https://example.com/reference.mp4"}}, + "referenceAudios": []any{map[string]any{"url": "https://example.com/reference.mp3"}}, + "capabilityOptions": map[string]any{"vquality": "720p"}, + }, "canvas_video", "reference_to_video") + selector := skuSelectorForIntent(intent) + if selector["operation"] != "video_to_video" { + t.Fatalf("operation = %q, want video_to_video; selector = %#v", selector["operation"], selector) + } + + modelWithTiers := model.ChannelModel{PriceTiers: []model.ChannelModelPriceTier{ + {SelectorJSON: `{}`, Enabled: true, PriceConfigured: true}, + {SelectorJSON: `{"operation":"video_to_video"}`, Enabled: true, PriceConfigured: true}, + }} + matched := channelModelPriceTierForIntent(modelWithTiers, intent) + if matched == nil || matched.SelectorJSON != `{"operation":"video_to_video"}` { + t.Fatalf("matched tier = %#v", matched) + } +} + +func TestSKUSelectorTreatsAnyImageReferenceCountAsImageToVideo(t *testing.T) { + intent := ModelRequestIntentFromTaskInput(map[string]any{ + "mode": "video", + "referenceImages": []any{ + map[string]any{"url": "https://example.com/reference-1.png"}, + map[string]any{"url": "https://example.com/reference-2.png"}, + map[string]any{"url": "https://example.com/reference-3.png"}, + }, + }, "canvas_video", "reference_to_video") + selector := skuSelectorForIntent(intent) + if selector["operation"] != "image_to_video" || selector["imageCount"] != "3" { + t.Fatalf("selector = %#v, want image_to_video with imageCount 3", selector) + } + + modelWithTiers := model.ChannelModel{PriceTiers: []model.ChannelModelPriceTier{ + {SelectorJSON: `{}`, Enabled: true, PriceConfigured: true}, + {SelectorJSON: `{"operation":"image_to_video"}`, Enabled: true, PriceConfigured: true}, + }} + matched := channelModelPriceTierForIntent(modelWithTiers, intent) + if matched == nil || matched.SelectorJSON != `{"operation":"image_to_video"}` { + t.Fatalf("matched tier = %#v", matched) + } +}