From 3477a08dad2fe180a5e04d781ac8d19ebd88c26a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8B=A5=E9=BA=92?= Date: Tue, 8 Sep 2026 16:33:03 +0800 Subject: [PATCH] feat(config): add profile-level watermark setting --- packages/commands/src/commands/config/set.ts | 5 +- .../commands/src/commands/config/shared.ts | 11 ++- packages/commands/src/commands/config/show.ts | 1 + packages/commands/src/commands/image/edit.ts | 2 +- .../commands/src/commands/image/generate.ts | 2 +- packages/commands/src/commands/video/edit.ts | 2 +- .../commands/src/commands/video/generate.ts | 2 +- packages/commands/src/commands/video/ref.ts | 2 +- packages/commands/tests/config-shared.test.ts | 6 ++ packages/commands/tests/config-ui.test.ts | 2 + .../commands/tests/e2e/config.e2e.test.ts | 43 ++++++++++ .../tests/e2e/watermark-config.e2e.test.ts | 80 +++++++++++++++++++ packages/core/src/config/loader.ts | 1 + packages/core/src/config/schema.ts | 4 + packages/core/src/utils/boolean-flag.ts | 6 +- packages/core/tests/config-priority.test.ts | 8 ++ packages/core/tests/image-input.test.ts | 1 + packages/core/tests/index.test.ts | 4 + packages/core/tests/mcp.test.ts | 1 + .../runtime/src/utils/flag-descriptions.ts | 5 +- skills/bailian-cli/reference/config.md | 12 ++- skills/bailian-gen/reference/image.md | 4 +- skills/bailian-gen/reference/video.md | 44 +++++----- 23 files changed, 206 insertions(+), 42 deletions(-) create mode 100644 packages/commands/tests/e2e/watermark-config.e2e.test.ts diff --git a/packages/commands/src/commands/config/set.ts b/packages/commands/src/commands/config/set.ts index 7a4a0dc..f81a7be 100644 --- a/packages/commands/src/commands/config/set.ts +++ b/packages/commands/src/commands/config/set.ts @@ -12,9 +12,9 @@ export default defineCommand({ valueHint: "", description: { "en-US": - "Config key (language, base_url, output, output_dir, timeout, api_key, api_key_capabilities, access_token, access_key_id, access_key_secret, security_token, default_*_model, workspace_id)", + "Config key (language, base_url, output, output_dir, timeout, watermark, api_key, api_key_capabilities, access_token, access_key_id, access_key_secret, security_token, default_*_model, workspace_id)", "zh-CN": - "配置项名称(language、base_url、output、output_dir、timeout、api_key、api_key_capabilities、access_token、access_key_id、access_key_secret、security_token、default_*_model、workspace_id)", + "配置项名称(language、base_url、output、output_dir、timeout、watermark、api_key、api_key_capabilities、access_token、access_key_id、access_key_secret、security_token、default_*_model、workspace_id)", }, required: true, }, @@ -29,6 +29,7 @@ export default defineCommand({ "--key language --value zh-CN", "--key output --value json", "--key timeout --value 600", + "--key watermark --value false", "--key base_url --value https://dashscope.aliyuncs.com", "--config company-plan --key api-key-capabilities --value text.chat,image.generate", ], diff --git a/packages/commands/src/commands/config/shared.ts b/packages/commands/src/commands/config/shared.ts index 66865d4..e903d84 100644 --- a/packages/commands/src/commands/config/shared.ts +++ b/packages/commands/src/commands/config/shared.ts @@ -3,6 +3,7 @@ import { ExitCode, isApiKeyCapability, normalizeModelBaseUrl, + parseBooleanValue, SUPPORTED_LANGUAGES, } from "bailian-cli-core"; @@ -13,6 +14,7 @@ export const VALID_KEYS = [ "output", "output_dir", "timeout", + "watermark", "api_key", "access_token", "access_key_id", @@ -62,7 +64,7 @@ export const UI_ENUM_KEYS: Record = { }; // Keys the UI renders as a true/false dropdown and stores as a boolean. -export const UI_BOOLEAN_KEYS = new Set(["telemetry"]); +export const UI_BOOLEAN_KEYS = new Set(["telemetry", "watermark"]); // Default model each `default_*_model` key falls back to when left unset. These // mirror the inline `|| ""` fallbacks in the generation commands @@ -164,7 +166,10 @@ export function resolveKey(key: string): string { * Validate a single config entry and coerce its value to the stored type. * Throws BailianError(USAGE) for unknown keys or invalid values. */ -export function validateAndCoerce(key: string, value: string): string | number | string[] { +export function validateAndCoerce( + key: string, + value: string, +): string | number | boolean | string[] { const resolvedKey = resolveKey(key); if (!(VALID_KEYS as readonly string[]).includes(resolvedKey)) { @@ -201,6 +206,8 @@ export function validateAndCoerce(key: string, value: string): string | number | if (resolvedKey === "base_url") return normalizeModelBaseUrl(value); + if (resolvedKey === "watermark") return parseBooleanValue(value, "watermark"); + if (resolvedKey === "api_key_capabilities") { let rawCapabilities: unknown; if (value.trim().startsWith("[")) { diff --git a/packages/commands/src/commands/config/show.ts b/packages/commands/src/commands/config/show.ts index 49ca83d..c8d41f7 100644 --- a/packages/commands/src/commands/config/show.ts +++ b/packages/commands/src/commands/config/show.ts @@ -18,6 +18,7 @@ export default defineCommand({ base_url: client.baseUrl, output: settings.output, timeout: settings.timeout, + watermark: settings.watermark, config: settings.configName ?? "default", config_file: store.path, }; diff --git a/packages/commands/src/commands/image/edit.ts b/packages/commands/src/commands/image/edit.ts index 466b256..e6af2c0 100644 --- a/packages/commands/src/commands/image/edit.ts +++ b/packages/commands/src/commands/image/edit.ts @@ -207,7 +207,7 @@ export default defineCommand({ "prompt-extend", ); - const watermark = resolveWatermark(flags.watermark); + const watermark = resolveWatermark(flags.watermark, settings.watermark); const parameters: NonNullable = { size: resolveImageSize(flags.size, route.sizeProfile), diff --git a/packages/commands/src/commands/image/generate.ts b/packages/commands/src/commands/image/generate.ts index 44c5d48..6c09a12 100644 --- a/packages/commands/src/commands/image/generate.ts +++ b/packages/commands/src/commands/image/generate.ts @@ -185,7 +185,7 @@ export default defineCommand({ "prompt-extend", ); - const watermark = resolveWatermark(flags.watermark); + const watermark = resolveWatermark(flags.watermark, settings.watermark); const parameters: NonNullable = { size, diff --git a/packages/commands/src/commands/video/edit.ts b/packages/commands/src/commands/video/edit.ts index 3db1b5a..28ab29c 100644 --- a/packages/commands/src/commands/video/edit.ts +++ b/packages/commands/src/commands/video/edit.ts @@ -197,7 +197,7 @@ export default defineCommand({ // --- Build request body --- const promptExtend = resolveBooleanFlag(flags.promptExtend, undefined, "prompt-extend"); - const watermark = resolveWatermark(flags.watermark); + const watermark = resolveWatermark(flags.watermark, settings.watermark); const body: DashScopeVideoEditRequest = { model, diff --git a/packages/commands/src/commands/video/generate.ts b/packages/commands/src/commands/video/generate.ts index a2aab9a..f3121db 100644 --- a/packages/commands/src/commands/video/generate.ts +++ b/packages/commands/src/commands/video/generate.ts @@ -208,7 +208,7 @@ export default defineCommand({ resolvedFileUrl = await ctx.client.uploadFile(fileUrl, model); } - const watermark = resolveWatermark(flags.watermark); + const watermark = resolveWatermark(flags.watermark, settings.watermark); const promptExtend = resolveBooleanFlag(flags.promptExtend, undefined, "prompt-extend"); const body: DashScopeVideoRequest = { diff --git a/packages/commands/src/commands/video/ref.ts b/packages/commands/src/commands/video/ref.ts index 6535907..67819fe 100644 --- a/packages/commands/src/commands/video/ref.ts +++ b/packages/commands/src/commands/video/ref.ts @@ -249,7 +249,7 @@ export default defineCommand({ // --- Build request body --- const promptExtend = resolveBooleanFlag(flags.promptExtend, undefined, "prompt-extend"); - const watermark = resolveWatermark(flags.watermark); + const watermark = resolveWatermark(flags.watermark, settings.watermark); const body: DashScopeVideoRefRequest = { model, diff --git a/packages/commands/tests/config-shared.test.ts b/packages/commands/tests/config-shared.test.ts index 2c30e41..925942d 100644 --- a/packages/commands/tests/config-shared.test.ts +++ b/packages/commands/tests/config-shared.test.ts @@ -33,3 +33,9 @@ test("default-speech-recognition-model alias accepts an ASR model ID", () => { "qwen-audio-3.0-asr-flash", ); }); + +test("watermark config accepts only boolean text and stores a boolean", () => { + expect(validateAndCoerce("watermark", "false")).toBe(false); + expect(validateAndCoerce("watermark", "TRUE")).toBe(true); + expect(() => validateAndCoerce("watermark", "yes")).toThrow(/true or false/i); +}); diff --git a/packages/commands/tests/config-ui.test.ts b/packages/commands/tests/config-ui.test.ts index dfccaa7..3a5d6ae 100644 --- a/packages/commands/tests/config-ui.test.ts +++ b/packages/commands/tests/config-ui.test.ts @@ -200,8 +200,10 @@ test("GET /api/config 返回全部 profile、明文密钥与持久化激活项", expect(res.json.keys).toContain("console_site"); expect(res.json.keys).toContain("telemetry"); expect(res.json.keys).toContain("default_speech_recognition_model"); + expect(res.json.keys).toContain("watermark"); expect(res.json.enums.console_site).toEqual(["domestic", "international"]); expect(res.json.booleanKeys).toContain("telemetry"); + expect(res.json.booleanKeys).toContain("watermark"); // Default field hints are surfaced as prefilled values in the UI. expect(res.json.fieldDefaults.default_image_model).toBe("qwen-image-3.0"); expect(res.json.fieldDefaults.default_text_model).toBe("qwen3.8-max"); diff --git a/packages/commands/tests/e2e/config.e2e.test.ts b/packages/commands/tests/e2e/config.e2e.test.ts index 173b6b8..d38e15f 100644 --- a/packages/commands/tests/e2e/config.e2e.test.ts +++ b/packages/commands/tests/e2e/config.e2e.test.ts @@ -64,10 +64,53 @@ describe("e2e: config", () => { config_file?: string; base_url?: string; timeout?: number; + watermark?: boolean; }>(stdout); expect(data.config_file).toBeDefined(); expect(data.base_url).toBeDefined(); expect(data.timeout).toBeDefined(); + expect(data.watermark).toBe(true); + }); + + test("config set 将 watermark 作为 boolean 写入并由 config show 读回", async () => { + const configDir = mkdtempSync(join(tmpdir(), "bl-config-watermark-")); + try { + const env = { BAILIAN_CONFIG_DIR: configDir }; + const setResult = await runCommandE2e( + CONFIG_ROUTES, + [ + "config", + "set", + "--config", + "media", + "--key", + "watermark", + "--value", + "false", + "--output", + "json", + ], + env, + ); + expect(setResult.exitCode, setResult.stderr).toBe(0); + expect(parseStdoutJson<{ watermark?: boolean }>(setResult.stdout).watermark).toBe(false); + + const persisted = JSON.parse(readFileSync(join(configDir, "config.json"), "utf8")) as Record< + string, + Record + >; + expect(persisted.media?.watermark).toBe(false); + + const showResult = await runCommandE2e( + CONFIG_ROUTES, + ["config", "show", "--config", "media", "--output", "json"], + env, + ); + expect(showResult.exitCode, showResult.stderr).toBe(0); + expect(parseStdoutJson<{ watermark?: boolean }>(showResult.stdout).watermark).toBe(false); + } finally { + rmSync(configDir, { recursive: true, force: true }); + } }); test("config show --output text", async () => { diff --git a/packages/commands/tests/e2e/watermark-config.e2e.test.ts b/packages/commands/tests/e2e/watermark-config.e2e.test.ts new file mode 100644 index 0000000..91a6636 --- /dev/null +++ b/packages/commands/tests/e2e/watermark-config.e2e.test.ts @@ -0,0 +1,80 @@ +import { mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { describe, expect, test } from "vite-plus/test"; +import { parseStdoutJson, runCommandE2e } from "./helpers.ts"; +import { IMAGE_ROUTES, VIDEO_ROUTES, type E2eRouteExports } from "./topic-routes.ts"; + +interface WatermarkScenario { + name: string; + routes: E2eRouteExports; + args: string[]; +} + +const scenarios: WatermarkScenario[] = [ + { + name: "image generate", + routes: IMAGE_ROUTES, + args: ["image", "generate", "--prompt", "A cat"], + }, + { + name: "image edit", + routes: IMAGE_ROUTES, + args: [ + "image", + "edit", + "--image", + "https://example.com/input.png", + "--prompt", + "Blue background", + ], + }, + { + name: "video generate", + routes: VIDEO_ROUTES, + args: ["video", "generate", "--prompt", "A cat waves"], + }, + { + name: "video edit", + routes: VIDEO_ROUTES, + args: ["video", "edit", "--video", "https://example.com/input.mp4", "--prompt", "Warm colors"], + }, + { + name: "video ref", + routes: VIDEO_ROUTES, + args: [ + "video", + "ref", + "--image", + "https://example.com/person.png", + "--prompt", + "Image 1 waves", + ], + }, +]; + +describe("e2e: global watermark config", () => { + for (const scenario of scenarios) { + test(`${scenario.name} uses watermark=false from the selected Profile`, async () => { + const configDir = mkdtempSync(join(tmpdir(), "bl-watermark-profile-")); + try { + writeFileSync( + join(configDir, "config.json"), + JSON.stringify({ media: { watermark: false } }, null, 2) + "\n", + ); + const { stdout, stderr, exitCode } = await runCommandE2e( + scenario.routes, + [...scenario.args, "--config", "media", "--dry-run", "--output", "json"], + { BAILIAN_CONFIG_DIR: configDir }, + ); + expect(exitCode, stderr).toBe(0); + const data = parseStdoutJson<{ + request?: { parameters?: { watermark?: boolean } }; + }>(stdout); + expect(data.request?.parameters?.watermark).toBe(false); + } finally { + rmSync(configDir, { recursive: true, force: true }); + } + }); + } +}); diff --git a/packages/core/src/config/loader.ts b/packages/core/src/config/loader.ts index 096f991..faec839 100644 --- a/packages/core/src/config/loader.ts +++ b/packages/core/src/config/loader.ts @@ -272,6 +272,7 @@ export function buildSettings(s: ResolutionSources): Settings { outputExplicit: Boolean(flags.output || env.DASHSCOPE_OUTPUT || file.output), outputDir: file.output_dir || undefined, timeout, + watermark: file.watermark ?? true, defaultTextModel: file.default_text_model, defaultVideoModel: file.default_video_model, defaultImageToVideoModel: file.default_image_to_video_model, diff --git a/packages/core/src/config/schema.ts b/packages/core/src/config/schema.ts index 0b945c6..a64e618 100644 --- a/packages/core/src/config/schema.ts +++ b/packages/core/src/config/schema.ts @@ -35,6 +35,7 @@ export interface ConfigFile { output?: "text" | "json"; output_dir?: string; timeout?: number; + watermark?: boolean; default_text_model?: string; default_video_model?: string; default_image_to_video_model?: string; @@ -63,6 +64,7 @@ export const CONFIG_FILE_KEYS = [ "output", "output_dir", "timeout", + "watermark", "default_text_model", "default_video_model", "default_image_to_video_model", @@ -156,6 +158,7 @@ export function parseConfigFile(raw: unknown): ConfigFile { if (typeof obj.output_dir === "string" && obj.output_dir.length > 0) out.output_dir = obj.output_dir; if (typeof obj.timeout === "number" && obj.timeout > 0) out.timeout = obj.timeout; + if (typeof obj.watermark === "boolean") out.watermark = obj.watermark; if (typeof obj.default_text_model === "string" && obj.default_text_model.length > 0) out.default_text_model = obj.default_text_model; if (typeof obj.default_video_model === "string" && obj.default_video_model.length > 0) @@ -224,6 +227,7 @@ export interface Settings { outputExplicit: boolean; outputDir?: string; timeout: number; + watermark: boolean; defaultTextModel?: string; defaultVideoModel?: string; defaultImageToVideoModel?: string; diff --git a/packages/core/src/utils/boolean-flag.ts b/packages/core/src/utils/boolean-flag.ts index 984af8c..c3e0073 100644 --- a/packages/core/src/utils/boolean-flag.ts +++ b/packages/core/src/utils/boolean-flag.ts @@ -34,7 +34,7 @@ export function resolveBooleanFlag( return defaultWhenUnset; } -/** Resolve `--watermark` flag; default true when unset. */ -export function resolveWatermark(flagValue: unknown): boolean { - return parseOptionalBooleanValue(flagValue, "watermark") ?? true; +/** Resolve `--watermark`; command flag overrides config, then defaults to true. */ +export function resolveWatermark(flagValue: unknown, configuredValue?: boolean): boolean { + return parseOptionalBooleanValue(flagValue, "watermark") ?? configuredValue ?? true; } diff --git a/packages/core/tests/config-priority.test.ts b/packages/core/tests/config-priority.test.ts index 9d5ce1b..fcbbf14 100644 --- a/packages/core/tests/config-priority.test.ts +++ b/packages/core/tests/config-priority.test.ts @@ -79,6 +79,14 @@ test("default_speech_recognition_model 从配置文件进入运行时 Settings", expect(resolve({ file }).defaultSpeechRecognitionModel).toBe("qwen-audio-3.0-asr-flash"); }); +test("watermark 从配置文件进入 Settings,缺省时保持合规默认值 true", () => { + expect(parseConfigFile({ watermark: false }).watermark).toBe(false); + expect(parseConfigFile({ watermark: true }).watermark).toBe(true); + expect(parseConfigFile({ watermark: "false" }).watermark).toBeUndefined(); + expect(resolve({ file: { watermark: false } }).watermark).toBe(false); + expect(resolve({}).watermark).toBe(true); +}); + test("baseUrl:flag > env > file > 默认,所有来源统一归一化", () => { const flags = { baseUrl: "https://flag.example.com/compatible-mode/v1?source=flag" }; const env = { DASHSCOPE_BASE_URL: "https://env.example.com/apps/anthropic#env" }; diff --git a/packages/core/tests/image-input.test.ts b/packages/core/tests/image-input.test.ts index 85e87b3..4821431 100644 --- a/packages/core/tests/image-input.test.ts +++ b/packages/core/tests/image-input.test.ts @@ -28,6 +28,7 @@ function makeSettings(configName?: string): Settings { output: "json", outputExplicit: false, timeout: 30, + watermark: true, verbose: false, quiet: true, dryRun: false, diff --git a/packages/core/tests/index.test.ts b/packages/core/tests/index.test.ts index 44eb765..cc0a90a 100644 --- a/packages/core/tests/index.test.ts +++ b/packages/core/tests/index.test.ts @@ -31,6 +31,7 @@ function testDeps(identity: Partial = {}): { output: "json", outputExplicit: true, timeout: 30, + watermark: true, verbose: false, quiet: true, dryRun: false, @@ -290,6 +291,9 @@ test("resolveWatermark uses flag or defaults to true", () => { expect(resolveWatermark("false")).toBe(false); expect(resolveWatermark("true")).toBe(true); expect(resolveWatermark(undefined)).toBe(true); + expect(resolveWatermark(undefined, false)).toBe(false); + expect(resolveWatermark("true", false)).toBe(true); + expect(resolveWatermark("false", true)).toBe(false); }); test("resolveBooleanFlag uses flag or defaultWhenUnset", () => { diff --git a/packages/core/tests/mcp.test.ts b/packages/core/tests/mcp.test.ts index 357f419..5100977 100644 --- a/packages/core/tests/mcp.test.ts +++ b/packages/core/tests/mcp.test.ts @@ -23,6 +23,7 @@ function testDeps(overrides?: Partial): { identity: Identity; settings output: "json", outputExplicit: true, timeout: 5, + watermark: true, verbose: false, quiet: true, dryRun: false, diff --git a/packages/runtime/src/utils/flag-descriptions.ts b/packages/runtime/src/utils/flag-descriptions.ts index 9faea8c..bc49b9b 100644 --- a/packages/runtime/src/utils/flag-descriptions.ts +++ b/packages/runtime/src/utils/flag-descriptions.ts @@ -1,8 +1,9 @@ /** Shared --foo help text; keep wording consistent with actual CLI/request behavior. */ export const BOOL_FLAG_WATERMARK = { - "en-US": "Enable watermark (true/false). Omit flag to use CLI default (true).", - "zh-CN": "是否启用水印(true/false)。不传时使用 CLI 默认值 true。", + "en-US": + "Enable watermark (true/false). Omit flag to use the Profile setting or CLI default (true).", + "zh-CN": "是否启用水印(true/false)。不传时使用 Profile 配置或 CLI 默认值 true。", }; /** CLI sends prompt_extend=true when flag omitted (qwen-image edit, etc.). */ diff --git a/skills/bailian-cli/reference/config.md b/skills/bailian-cli/reference/config.md index 2c3f696..2ca6348 100644 --- a/skills/bailian-cli/reference/config.md +++ b/skills/bailian-cli/reference/config.md @@ -88,10 +88,10 @@ bl config list --output json #### Flags -| Flag | Type | Required | Description | -| ----------------- | ------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `--key ` | string | yes | Config key (language, base*url, output, output_dir, timeout, api_key, api_key_capabilities, access_token, access_key_id, access_key_secret, security_token, default*\*\_model, workspace_id) | -| `--value ` | string | yes | Value to set | +| Flag | Type | Required | Description | +| ----------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `--key ` | string | yes | Config key (language, base*url, output, output_dir, timeout, watermark, api_key, api_key_capabilities, access_token, access_key_id, access_key_secret, security_token, default*\*\_model, workspace_id) | +| `--value ` | string | yes | Value to set | #### Examples @@ -107,6 +107,10 @@ bl config set --key output --value json bl config set --key timeout --value 600 ``` +```bash +bl config set --key watermark --value false +``` + ```bash bl config set --key base_url --value https://dashscope.aliyuncs.com ``` diff --git a/skills/bailian-gen/reference/image.md b/skills/bailian-gen/reference/image.md index 983a78d..b90506e 100644 --- a/skills/bailian-gen/reference/image.md +++ b/skills/bailian-gen/reference/image.md @@ -36,7 +36,7 @@ Index: [index.md](index.md) | `--negative-prompt ` | string | no | Negative prompt to exclude unwanted content | | `--function ` | string | no | wanx\*-imageedit function (default: description_edit). Examples: stylization_all, description_edit | | `--prompt-extend ` | boolean | no | Enable prompt extend (true/false). Omit flag to use CLI default (true). | -| `--watermark ` | boolean | no | Enable watermark (true/false). Omit flag to use CLI default (true). | +| `--watermark ` | boolean | no | Enable watermark (true/false). Omit flag to use the Profile setting or CLI default (true). | | `--out-dir ` | string | no | Download images to directory | | `--out-prefix ` | string | no | Filename prefix (default: edited) | | `--async` | switch | no | Return async task id without waiting | @@ -99,7 +99,7 @@ bl image edit --image ./photo.png --prompt "Replace the background with a beach" | `--seed ` | number | no | Random seed for reproducible generation | | `--negative-prompt ` | string | no | Negative prompt to exclude unwanted content | | `--prompt-extend ` | boolean | no | Enable prompt extend (true/false). Omit flag: true for qwen-image sync; parameter omitted on async models (API default). | -| `--watermark ` | boolean | no | Enable watermark (true/false). Omit flag to use CLI default (true). | +| `--watermark ` | boolean | no | Enable watermark (true/false). Omit flag to use the Profile setting or CLI default (true). | | `--async` | switch | no | Return async task id without waiting | | `--concurrent ` | number | no | Run N parallel requests (default: 1) | | `--out-dir ` | string | no | Download images to directory | diff --git a/skills/bailian-gen/reference/video.md b/skills/bailian-gen/reference/video.md index 8e6a21d..2f5d90e 100644 --- a/skills/bailian-gen/reference/video.md +++ b/skills/bailian-gen/reference/video.md @@ -56,26 +56,26 @@ bl video download --task-id 3b256896-xxxx --out video.mp4 --quiet #### Flags -| Flag | Type | Required | Description | -| -------------------------------- | ------- | -------- | --------------------------------------------------------------------------------------- | -| `--model ` | string | no | Model ID (default: happyhorse-1.0-video-edit) | -| `--video ` | string | yes | Input video URL or local file (mp4/mov, 2-10s) | -| `--prompt ` | string | no | Edit instruction (e.g. "Convert the scene to a claymation style") | -| `--ref-image ` | string | no | Reference image URL (up to 4, comma-separated) | -| `--negative-prompt ` | string | no | Negative prompt to exclude unwanted content | -| `--resolution ` | string | no | Resolution: 720P or 1080P (default: 1080P) | -| `--ratio ` | string | no | Aspect ratio (16:9, 9:16, 1:1, 4:3, 3:4) | -| `--duration ` | number | no | Output video duration in seconds (2-10) | -| `--audio-setting ` | string | no | Audio: auto (default) or origin (keep original) | -| `--prompt-extend ` | boolean | no | Enable prompt extend (true/false). Omit flag to omit the parameter (DashScope default). | -| `--watermark ` | boolean | no | Enable watermark (true/false). Omit flag to use CLI default (true). | -| `--seed ` | number | no | Random seed for reproducible generation | -| `--download ` | string | no | Save video to file on completion | -| `--async` | switch | no | Return async task id without waiting | -| `--concurrent ` | number | no | Run N parallel requests (default: 1) | -| `--poll-interval ` | number | no | Polling interval when waiting (default: 15) | -| `--api-key ` | string | no | API key | -| `--base-url ` | string | no | API base URL | +| Flag | Type | Required | Description | +| -------------------------------- | ------- | -------- | ------------------------------------------------------------------------------------------ | +| `--model ` | string | no | Model ID (default: happyhorse-1.0-video-edit) | +| `--video ` | string | yes | Input video URL or local file (mp4/mov, 2-10s) | +| `--prompt ` | string | no | Edit instruction (e.g. "Convert the scene to a claymation style") | +| `--ref-image ` | string | no | Reference image URL (up to 4, comma-separated) | +| `--negative-prompt ` | string | no | Negative prompt to exclude unwanted content | +| `--resolution ` | string | no | Resolution: 720P or 1080P (default: 1080P) | +| `--ratio ` | string | no | Aspect ratio (16:9, 9:16, 1:1, 4:3, 3:4) | +| `--duration ` | number | no | Output video duration in seconds (2-10) | +| `--audio-setting ` | string | no | Audio: auto (default) or origin (keep original) | +| `--prompt-extend ` | boolean | no | Enable prompt extend (true/false). Omit flag to omit the parameter (DashScope default). | +| `--watermark ` | boolean | no | Enable watermark (true/false). Omit flag to use the Profile setting or CLI default (true). | +| `--seed ` | number | no | Random seed for reproducible generation | +| `--download ` | string | no | Save video to file on completion | +| `--async` | switch | no | Return async task id without waiting | +| `--concurrent ` | number | no | Run N parallel requests (default: 1) | +| `--poll-interval ` | number | no | Polling interval when waiting (default: 15) | +| `--api-key ` | string | no | API key | +| `--base-url ` | string | no | API base URL | #### Examples @@ -117,7 +117,7 @@ bl video edit --video https://example.com/input.mp4 --prompt "Put clothes on the | `--ratio ` | string | no | Aspect ratio (e.g. 16:9, 9:16, 1:1) | | `--duration ` | number | no | Video duration in seconds (default: 5) | | `--prompt-extend ` | boolean | no | Enable prompt extend (true/false). Omit flag to omit the parameter (DashScope default). | -| `--watermark ` | boolean | no | Enable watermark (true/false). Omit flag to use CLI default (true). | +| `--watermark ` | boolean | no | Enable watermark (true/false). Omit flag to use the Profile setting or CLI default (true). | | `--seed ` | number | no | Random seed for reproducible generation | | `--download ` | string | no | Save video to file on completion | | `--file ` | string | no | Reference file URL or local path for file-to-video (wan3.0-video only; mutually exclusive with --image/--last-frame) | @@ -172,7 +172,7 @@ bl video generate --prompt "A cat playing with a ball" --watermark false | `--ratio ` | string | no | Aspect ratio (16:9, 9:16, 1:1) | | `--duration ` | number | no | Video duration in seconds (default: 5) | | `--prompt-extend ` | boolean | no | Enable prompt extend (true/false). Omit flag to omit the parameter (DashScope default). | -| `--watermark ` | boolean | no | Enable watermark (true/false). Omit flag to use CLI default (true). | +| `--watermark ` | boolean | no | Enable watermark (true/false). Omit flag to use the Profile setting or CLI default (true). | | `--seed ` | number | no | Random seed for reproducible generation | | `--download ` | string | no | Save video to file on completion | | `--async` | switch | no | Return async task id without waiting |