diff --git a/backend/internal/protocol/official_catalog_test.go b/backend/internal/protocol/official_catalog_test.go index 8434b3c35..2927db4a9 100644 --- a/backend/internal/protocol/official_catalog_test.go +++ b/backend/internal/protocol/official_catalog_test.go @@ -431,3 +431,37 @@ func manifestTestBody(t *testing.T, spec RequestSpec) map[string]any { } return body } + +func TestOfficialArkSeedreamMapsAspectRatioToPixelSize(t *testing.T) { + adapter := officialPackageAdapter(t, "volcengine-ark-seedream.yingce-plugin", "volcengine-ark-image") + tests := []struct { + name, aspectRatio, wantSize string + }{ + {name: "ratio maps to 2K pixels", aspectRatio: "1:1", wantSize: "2048x2048"}, + {name: "landscape ratio", aspectRatio: "16:9", wantSize: "2560x1440"}, + {name: "auto maps to 2k tier", aspectRatio: "auto", wantSize: "2k"}, + {name: "pixel size passes through", aspectRatio: "1920x1080", wantSize: "1920x1080"}, + {name: "tier passes through", aspectRatio: "4k", wantSize: "4k"}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + create, err := adapter.BuildCreate(context.Background(), RequestContext{Request: GenerationRequest{Model: "doubao-seedream-5-0-260128", Prompt: "circle", AspectRatio: tt.aspectRatio}}) + if err != nil { + t.Fatal(err) + } + if create.Path != "/api/v3/images/generations" { + t.Fatalf("Seedream create = %#v", create) + } + if body := manifestTestBody(t, create); body["size"] != tt.wantSize { + t.Fatalf("Seedream size = %#v, want %q", body["size"], tt.wantSize) + } + }) + } + create, err := adapter.BuildCreate(context.Background(), RequestContext{Request: GenerationRequest{Model: "doubao-seedream-5-0-260128", Prompt: "circle"}}) + if err != nil { + t.Fatal(err) + } + if _, ok := manifestTestBody(t, create)["size"]; ok { + t.Fatalf("Seedream must omit size when no ratio is requested") + } +} diff --git a/plugin-packages/generate-catalog.mjs b/plugin-packages/generate-catalog.mjs index 111a4176e..896f12aee 100644 --- a/plugin-packages/generate-catalog.mjs +++ b/plugin-packages/generate-catalog.mjs @@ -249,11 +249,18 @@ add({ response: { status: "succeeded", images: map(ref("response.data"), "item", { url: omit(ref("item.url")), dataUrl: conditional(ref("item.b64_json"), { $concat: ["data:image/png;base64,", ref("item.b64_json")] }) }), errorPaths: ["error.code"], messagePaths: ["error.message"] } }); +const arkSeedreamRatioSizes = [ + ["auto", "2k"], ["1:1", "2048x2048"], ["4:3", "2304x1728"], ["3:4", "1728x2304"], ["16:9", "2560x1440"], ["9:16", "1440x2560"], + ["3:2", "2496x1664"], ["2:3", "1664x2496"], ["21:9", "3024x1296"] +]; + add({ id: "volcengine-ark-seedream", providerId: "volcengine-ark-image", name: "Volcengine Ark Seedream Images", vendor: "Volcengine", capability: "image", baseUrl: "https://ark.cn-beijing.volces.com", auth: bearer, params: imageParams, create: jsonCreate("/api/v3/images/generations", { - model: ref("request.model"), prompt: ref("request.prompt"), size: omit(ref("request.aspectRatio")), + model: ref("request.model"), prompt: ref("request.prompt"), + // Ark 的 size 只接受 WIDTHxHEIGHT 或 2k/3k/4k;统一层的比例值在这里换算成 2K 档像素尺寸,像素或档位值原样透传。 + size: omit({ $switch: { cases: arkSeedreamRatioSizes.map(([ratio, size]) => ({ when: eq(ref("request.aspectRatio"), ratio), then: size })), default: ref("request.aspectRatio") } }), image: omit(map(ref("request.images"), "media", ref("media.value"))), sequential_image_generation: omit(ref("request.providerOptions.volcengine-ark-image.sequential_image_generation")), sequential_image_generation_options: omit(ref("request.providerOptions.volcengine-ark-image.sequential_image_generation_options")), diff --git a/plugin-packages/volcengine-ark-seedream.yingce-plugin b/plugin-packages/volcengine-ark-seedream.yingce-plugin index 7664c7856..b2c2e197c 100644 Binary files a/plugin-packages/volcengine-ark-seedream.yingce-plugin and b/plugin-packages/volcengine-ark-seedream.yingce-plugin differ