fix(app,canvas): 图片档位并集忽略停用线路,重生结果不再继承旧素材绑定

前台分辨率并集只收启用且权重大于 0 的供应线路,避免停用 4K 线路后仍出现不可路由档位。生成回写新媒体时清除旧 assetId,堵住原地重生后「旧素材 + 新资源」配对。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
ddCat
2026-09-17 00:08:35 +08:00
parent ab6d6d1557
commit d7388fa9a9
5 changed files with 99 additions and 13 deletions

View File

@@ -165,11 +165,7 @@ func (s *Service) PublicLogicalModels(intent *ModelRequestIntent) ([]PublicLogic
func publicLogicalModel(cached cachedLogicalModel, available bool) PublicLogicalModel {
item := cached.Model
routeSpecs := make([]CapabilitySpec, 0, len(cached.Routes))
for _, route := range cached.Routes {
routeSpecs = append(routeSpecs, route.CapabilitySpec)
}
productSpec := capabilitySpecWithRoutePresets(cached.ProductSpec, routeSpecs)
productSpec := capabilitySpecWithRoutePresets(cached.ProductSpec, enabledLogicalRouteSpecs(cached.Routes))
profiles := make([]CapabilitySpec, 0, len(cached.Routes))
seen := make(map[string]bool, len(cached.Routes))
for _, route := range cached.Routes {
@@ -253,9 +249,22 @@ func normalizeLegacyModelIDs(values []string) []string {
return result
}
func enabledLogicalRouteSpecs(routes []cachedLogicalRoute) []CapabilitySpec {
specs := make([]CapabilitySpec, 0, len(routes))
for _, route := range routes {
if !route.Route.Enabled || route.Route.Weight <= 0 {
continue
}
specs = append(specs, route.CapabilitySpec)
}
return specs
}
// capabilitySpecWithRoutePresets repairs old front-model snapshots that stored
// only `*` for a custom size. The wildcard remains for matching custom values,
// while route presets are restored for admin and creator-side selectors.
// Callers must pass only currently enabled routes; disabled or zero-weight
// routes would otherwise advertise size tiers the public catalog cannot route.
func capabilitySpecWithRoutePresets(spec CapabilitySpec, routes []CapabilitySpec) CapabilitySpec {
result := spec
result.Options = make(map[string]OptionConstraint, len(spec.Options))

View File

@@ -60,6 +60,37 @@ func TestCapabilitySpecWithRoutePresetsUnionsTiersAcrossRoutes(t *testing.T) {
}
}
func TestEnabledLogicalRouteSpecsOmitsDisabledAndZeroWeightTiers(t *testing.T) {
preset := func(size string, tier string, width int, height int) CapabilityImageSizePreset {
return CapabilityImageSizePreset{Size: size, Tier: tier, Ratio: "16:9", Width: width, Height: height}
}
product := CapabilitySpec{
Version: 1,
Capability: "image",
ImageSize: &CapabilityImageSize{Parameter: "aspect_ratio", Presets: []CapabilityImageSizePreset{preset("1824x1024", "1k", 1824, 1024)}},
}
routes := []cachedLogicalRoute{
{Route: model.LogicalModelRoute{Enabled: true, Weight: 1}, CapabilitySpec: CapabilitySpec{ImageSize: &CapabilityImageSize{Presets: []CapabilityImageSizePreset{preset("2752x1536", "2k", 2752, 1536)}}}},
{Route: model.LogicalModelRoute{Enabled: false, Weight: 1}, CapabilitySpec: CapabilitySpec{ImageSize: &CapabilityImageSize{Presets: []CapabilityImageSizePreset{preset("3840x2160", "4k", 3840, 2160)}}}},
{Route: model.LogicalModelRoute{Enabled: true, Weight: 0}, CapabilitySpec: CapabilitySpec{ImageSize: &CapabilityImageSize{Presets: []CapabilityImageSizePreset{preset("4096x2304", "4k", 4096, 2304)}}}},
}
got := capabilitySpecWithRoutePresets(product, enabledLogicalRouteSpecs(routes))
if got.ImageSize == nil {
t.Fatal("imageSize = nil")
}
tiers := make(map[string]bool, len(got.ImageSize.Presets))
for _, item := range got.ImageSize.Presets {
tiers[item.Tier] = true
}
if !tiers["1k"] || !tiers["2k"] {
t.Fatalf("expected 1k and 2k from enabled routes: %#v", got.ImageSize.Presets)
}
if tiers["4k"] {
t.Fatalf("disabled and zero-weight 4k routes must not appear in public presets: %#v", got.ImageSize.Presets)
}
}
func TestMatchCapabilityRoutesTextImagesOnlyToDeclaredProfiles(t *testing.T) {
plainText := CapabilitySpec{
Version: 1,

View File

@@ -634,11 +634,7 @@ func (s *Service) loadRouteCatalog() (*routeCatalogSnapshot, error) {
}
cached.Routes = append(cached.Routes, cachedLogicalRoute{Route: route, CapabilitySpec: capabilitySpec, ChannelModel: channelModel})
}
routeSpecs := make([]CapabilitySpec, 0, len(cached.Routes))
for _, route := range cached.Routes {
routeSpecs = append(routeSpecs, route.CapabilitySpec)
}
productSpec = capabilitySpecWithRoutePresets(productSpec, routeSpecs)
productSpec = capabilitySpecWithRoutePresets(productSpec, enabledLogicalRouteSpecs(cached.Routes))
defaults, defaultsErr := decodeLogicalDefaults(graph.Revision.DefaultOptionsJSON, productSpec)
if defaultsErr != nil {
log.Printf("logical model omitted from route catalog id=%s: invalid defaults: %v", item.ID, defaultsErr)