mirror of
https://github.com/JimLiu/baoyu-skills.git
synced 2026-07-26 11:59:46 +08:00
feat(baoyu-imagine): add DashScope Wan 2.7 image model support (#141)
* feat(baoyu-imagine): add DashScope Wan 2.7 image model support Closes #139. Adds the new `wan2.7-image-pro` and `wan2.7-image` model family to the DashScope provider so users can call Wan 2.7 directly through the official Aliyun (Bailian) API instead of going through Replicate. - Register `wan2.7-image-pro` and `wan2.7-image` as a new `wan27` family in the DashScope provider with their own size resolution rules: pixel range `[768*768, 4096*4096]` for `wan2.7-image-pro` text-to-image, `[768*768, 2048*2048]` for `wan2.7-image-pro` with refs and for the base `wan2.7-image` model in any mode, with aspect ratios validated against the documented `[1:8, 8:1]` band. - Allow up to 9 reference images per request (image editing / multi-image fusion). Local files are inlined as base64 data URLs; `http(s)://` paths are forwarded as-is. Other DashScope models still reject `--ref` with a hint to switch to a wan2.7 model or another provider. - Drop `prompt_extend` from the request body for the Wan 2.7 family (not part of the Wan 2.7 API surface) and skip the Qwen-only negative prompt for this family. - Allow `--provider dashscope --ref ...` in `detectProvider` so users can opt into Wan 2.7 reference workflows, while keeping Wan 2.7 out of the auto-detect ref priority list. - Add provider, reference, and usage-example documentation, plus unit tests covering family routing, size derivation across the three pixel-budget modes, ratio rejection, explicit-size validation, and the new `--provider dashscope` ref opt-in path. Made-with: Cursor * fix(baoyu-imagine): force n=1 for DashScope wan2.7 to avoid silent multi-image billing Cross-checked the implementation against the official Wan 2.7 image generation & editing API reference and found that the API defaults `parameters.n` to 4 in non-collage mode (1-4 range, billed per image). baoyu-imagine has single-image save semantics — only the first image in the response is kept — so without an explicit `n: 1` users would silently pay for 3 discarded images per request. - Always send `parameters.n: 1` in the wan2.7 request body - Reject `--n > 1` for wan2.7 with a clear error pointing at the single-image save semantics - Add tests asserting the request body shape (n=1, no prompt_extend, no negative_prompt) and the --n>1 rejection - Document the defaults-vs-skill mismatch in the dashscope reference Made-with: Cursor * Fix DashScope Wan 2.7 review feedback
This commit is contained in:
@@ -19,6 +19,7 @@ import {
|
||||
parseArgs,
|
||||
parseOpenAIImageApiDialect,
|
||||
parseSimpleYaml,
|
||||
validateReferenceImages,
|
||||
} from "./main.ts";
|
||||
|
||||
function makeArgs(overrides: Partial<CliArgs> = {}): CliArgs {
|
||||
@@ -123,6 +124,15 @@ test("parseArgs falls back to positional prompt and rejects invalid provider", (
|
||||
);
|
||||
});
|
||||
|
||||
test("validateReferenceImages can skip remote URLs for providers that support them", async () => {
|
||||
await validateReferenceImages(["https://example.com/ref.png"], { allowRemoteUrls: true });
|
||||
|
||||
await assert.rejects(
|
||||
() => validateReferenceImages(["https://example.com/ref.png"]),
|
||||
/Reference image not found/,
|
||||
);
|
||||
});
|
||||
|
||||
test("parseSimpleYaml parses nested defaults and provider limits", () => {
|
||||
const yaml = `
|
||||
version: 2
|
||||
@@ -308,7 +318,7 @@ test("detectProvider rejects non-ref-capable providers and prefers Google first
|
||||
() =>
|
||||
detectProvider(
|
||||
makeArgs({
|
||||
provider: "dashscope",
|
||||
provider: "zai",
|
||||
referenceImages: ["ref.png"],
|
||||
}),
|
||||
),
|
||||
@@ -426,6 +436,33 @@ test("detectProvider infers Seedream from model id and allows Seedream reference
|
||||
);
|
||||
});
|
||||
|
||||
test("detectProvider allows DashScope reference-image workflows when explicitly chosen for wan2.7 models", (t) => {
|
||||
useEnv(t, {
|
||||
GOOGLE_API_KEY: null,
|
||||
OPENAI_API_KEY: null,
|
||||
AZURE_OPENAI_API_KEY: null,
|
||||
AZURE_OPENAI_BASE_URL: null,
|
||||
OPENROUTER_API_KEY: null,
|
||||
DASHSCOPE_API_KEY: "dashscope-key",
|
||||
MINIMAX_API_KEY: null,
|
||||
REPLICATE_API_TOKEN: null,
|
||||
JIMENG_ACCESS_KEY_ID: null,
|
||||
JIMENG_SECRET_ACCESS_KEY: null,
|
||||
ARK_API_KEY: null,
|
||||
});
|
||||
|
||||
assert.equal(
|
||||
detectProvider(
|
||||
makeArgs({
|
||||
provider: "dashscope",
|
||||
model: "wan2.7-image-pro",
|
||||
referenceImages: ["ref.png"],
|
||||
}),
|
||||
),
|
||||
"dashscope",
|
||||
);
|
||||
});
|
||||
|
||||
test("detectProvider selects MiniMax when only MiniMax credentials are configured or the model id matches", (t) => {
|
||||
useEnv(t, {
|
||||
GOOGLE_API_KEY: null,
|
||||
@@ -504,7 +541,7 @@ test("loadBatchTasks and createTaskArgs resolve batch-relative paths", async (t)
|
||||
id: "hero",
|
||||
promptFiles: ["prompts/hero.md"],
|
||||
image: "out/hero",
|
||||
ref: ["refs/hero.png"],
|
||||
ref: ["refs/hero.png", "https://example.com/ref.png"],
|
||||
ar: "16:9",
|
||||
},
|
||||
],
|
||||
@@ -533,6 +570,7 @@ test("loadBatchTasks and createTaskArgs resolve batch-relative paths", async (t)
|
||||
assert.equal(taskArgs.imagePath, path.join(loaded.batchDir, "out/hero"));
|
||||
assert.deepEqual(taskArgs.referenceImages, [
|
||||
path.join(loaded.batchDir, "refs/hero.png"),
|
||||
"https://example.com/ref.png",
|
||||
]);
|
||||
assert.equal(taskArgs.provider, "replicate");
|
||||
assert.equal(taskArgs.aspectRatio, "16:9");
|
||||
@@ -557,5 +595,29 @@ test("path normalization, worker count, and retry classification follow expected
|
||||
),
|
||||
false,
|
||||
);
|
||||
assert.equal(
|
||||
isRetryableGenerationError(
|
||||
new Error("DashScope wan2.7 image models accept at most 9 reference images. Received 10."),
|
||||
),
|
||||
false,
|
||||
);
|
||||
assert.equal(
|
||||
isRetryableGenerationError(
|
||||
new Error("DashScope wan2.7 image models in baoyu-imagine support exactly one output image per request."),
|
||||
),
|
||||
false,
|
||||
);
|
||||
assert.equal(
|
||||
isRetryableGenerationError(
|
||||
new Error("DashScope wan2.7 image models support aspect ratios in [1:8, 8:1]."),
|
||||
),
|
||||
false,
|
||||
);
|
||||
assert.equal(
|
||||
isRetryableGenerationError(
|
||||
new Error("DashScope wan2.7-image requires total pixels between 768*768 and 2048*2048."),
|
||||
),
|
||||
false,
|
||||
);
|
||||
assert.equal(isRetryableGenerationError(new Error("socket hang up")), true);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user