Skip to content

Commit 3708ec2

Browse files
Merge pull request #13 from modelstudioai/feat/watermark-and-paired-flags
fix: Fix the issue of the watermark being always on and address the i…
2 parents 8544f40 + 99ef96d commit 3708ec2

13 files changed

Lines changed: 326 additions & 77 deletions

File tree

packages/cli/src/args.ts

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,15 @@ interface FlagSchema {
2525
arrays: Set<string>;
2626
}
2727

28+
function buildAllowedFlagKeys(options: OptionDef[]): Set<string> {
29+
const keys = new Set<string>();
30+
for (const opt of options) {
31+
const key = flagKey(opt);
32+
if (key) keys.add(key);
33+
}
34+
return keys;
35+
}
36+
2837
function buildSchema(options: OptionDef[]): FlagSchema {
2938
const booleans = new Set<string>();
3039
const numbers = new Set<string>();
@@ -91,6 +100,7 @@ export function scanCommandPath(argv: string[], globalOptions: OptionDef[] = [])
91100
* - default: string
92101
*/
93102
export function parseFlags(argv: string[], options: OptionDef[]): GlobalFlags {
103+
const allowedKeys = buildAllowedFlagKeys(options);
94104
const schema = buildSchema(options);
95105
const flags: GlobalFlags = {
96106
quiet: false,
@@ -130,20 +140,30 @@ export function parseFlags(argv: string[], options: OptionDef[]): GlobalFlags {
130140

131141
const camelKey = kebabToCamel(key);
132142

143+
if (!allowedKeys.has(camelKey)) {
144+
throw new BailianError(
145+
`Unknown flag "--${key}". Run with --help to see available options.`,
146+
ExitCode.USAGE,
147+
);
148+
}
149+
150+
// Switch-style flags (--quiet, --dry-run): no value. Value flags need a non-flag next token.
133151
if (schema.booleans.has(camelKey)) {
134152
(flags as Record<string, unknown>)[camelKey] = true;
135153
i++;
136154
continue;
137155
}
138156

157+
// --prompt <text>, --watermark <bool>, …
139158
if (value === undefined) {
140159
i++;
141-
value = argv[i];
160+
const next = argv[i];
161+
if (next === undefined || next.startsWith("-")) {
162+
throw new BailianError(`Flag --${key} requires a value.`, ExitCode.USAGE);
163+
}
164+
value = next;
142165
}
143166

144-
if (value === undefined)
145-
throw new BailianError(`Flag --${key} requires a value.`, ExitCode.USAGE);
146-
147167
if (schema.arrays.has(camelKey)) {
148168
const arr = (flags as Record<string, unknown>)[camelKey] as string[] | undefined;
149169
if (arr) arr.push(value);

packages/cli/src/commands/image/edit.ts

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,19 @@ import {
1515
type DashScopeImageSyncResponse,
1616
ExitCode,
1717
BailianError,
18+
resolveBooleanFlag,
19+
resolveWatermark,
1820
} from "bailian-cli-core";
1921
import { downloadFile } from "../../utils/download.ts";
2022
import { runConcurrent, downloadParallel, getConcurrency } from "../../utils/concurrent.ts";
2123
import { promptText, failIfMissing } from "../../output/prompt.ts";
2224
import { emitResult, emitBare } from "../../output/output.ts";
2325
import { resolveImageSize } from "../../utils/image-size.ts";
2426
import { join } from "path";
27+
import {
28+
BOOL_FLAG_PROMPT_EXTEND_CLI_TRUE,
29+
BOOL_FLAG_WATERMARK,
30+
} from "../../utils/flag-descriptions.ts";
2531

2632
export default defineCommand({
2733
name: "image edit",
@@ -47,9 +53,14 @@ export default defineCommand({
4753
flag: "--negative-prompt <text>",
4854
description: "Negative prompt to exclude unwanted content",
4955
},
50-
{ flag: "--prompt-extend", description: "Enable prompt smart rewrite (default: true)" },
51-
{ flag: "--no-prompt-extend", description: "Disable prompt extend" },
52-
{ flag: "--watermark", description: "Add watermark to output images" },
56+
{
57+
flag: "--prompt-extend <bool>",
58+
description: BOOL_FLAG_PROMPT_EXTEND_CLI_TRUE,
59+
},
60+
{
61+
flag: "--watermark <bool>",
62+
description: BOOL_FLAG_WATERMARK,
63+
},
5364
{ flag: "--out-dir <dir>", description: "Download images to directory" },
5465
{ flag: "--out-prefix <prefix>", description: "Filename prefix (default: edited)" },
5566
],
@@ -58,6 +69,7 @@ export default defineCommand({
5869
'bl image edit --image https://example.com/logo.png --prompt "Change color to blue" --n 3',
5970
'bl image edit --image ./a.png --image ./b.png --prompt "把两张图合并成一张拼图"',
6071
'bl image edit --image https://example.com/photo.png --prompt "Remove the person" --model qwen-image-2.0-pro',
72+
'bl image edit --image ./photo.png --prompt "把背景换成海滩" --watermark false',
6173
],
6274
async run(config: Config, flags: GlobalFlags) {
6375
// Normalize --image to string array (supports both single and repeated flags)
@@ -96,22 +108,16 @@ export default defineCommand({
96108
);
97109
const n = (flags.n as number) ?? 1;
98110

99-
// Determine prompt_extend
100-
let promptExtend: boolean | undefined;
101-
if (flags.noPromptExtend === true) {
102-
promptExtend = false;
103-
} else if (flags.promptExtend === true) {
104-
promptExtend = true;
105-
} else {
106-
promptExtend = true; // default on for qwen-image
107-
}
111+
const promptExtend = resolveBooleanFlag(flags.promptExtend, true, "prompt-extend");
108112

109113
// Build content: all images first, then text prompt
110114
const contentItems: Array<{ image?: string; text?: string }> = resolvedImages.map(
111115
(u: string) => ({ image: u }),
112116
);
113117
contentItems.push({ text: prompt! });
114118

119+
const watermark = resolveWatermark(flags.watermark);
120+
115121
const body: DashScopeImageRequest = {
116122
model,
117123
input: {
@@ -127,7 +133,7 @@ export default defineCommand({
127133
n,
128134
seed: flags.seed as number | undefined,
129135
prompt_extend: promptExtend,
130-
watermark: flags.watermark === true ? true : undefined,
136+
watermark,
131137
negative_prompt: (flags.negativePrompt as string) || undefined,
132138
},
133139
};

packages/cli/src/commands/image/generate.ts

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,19 @@ import {
1717
type OutputFormat,
1818
type DashScopeTaskResponse,
1919
generateFilename,
20+
resolveBooleanFlag,
21+
resolveWatermark,
2022
} from "bailian-cli-core";
2123
import { poll } from "../../utils/polling.ts";
2224
import { downloadFile } from "../../utils/download.ts";
2325
import { runConcurrent, downloadParallel, getConcurrency } from "../../utils/concurrent.ts";
2426
import { promptText, failIfMissing } from "../../output/prompt.ts";
2527
import { emitResult, emitBare } from "../../output/output.ts";
2628
import { resolveImageSize } from "../../utils/image-size.ts";
29+
import {
30+
BOOL_FLAG_PROMPT_EXTEND_IMAGE_GENERATE,
31+
BOOL_FLAG_WATERMARK,
32+
} from "../../utils/flag-descriptions.ts";
2733

2834
import { join } from "path";
2935

@@ -57,11 +63,13 @@ export default defineCommand({
5763
description: "Negative prompt to exclude unwanted content",
5864
},
5965
{
60-
flag: "--prompt-extend",
61-
description: "Automatically extend prompt for better results (default: true for qwen-image)",
66+
flag: "--prompt-extend <bool>",
67+
description: BOOL_FLAG_PROMPT_EXTEND_IMAGE_GENERATE,
68+
},
69+
{
70+
flag: "--watermark <bool>",
71+
description: BOOL_FLAG_WATERMARK,
6272
},
63-
{ flag: "--no-prompt-extend", description: "Disable prompt extend" },
64-
{ flag: "--watermark", description: "Add watermark to generated images" },
6573
{
6674
flag: "--no-wait",
6775
description: "Return task ID immediately without waiting (async models only)",
@@ -78,7 +86,9 @@ export default defineCommand({
7886
'bl image generate --prompt "一只穿太空服的猫在火星上"',
7987
'bl image generate --prompt "Logo design" --n 3 --out-dir ./generated/',
8088
'bl image generate --prompt "Mountain landscape" --size 2688*1536',
81-
'bl image generate --prompt "A castle" --seed 42 --no-prompt-extend',
89+
'bl image generate --prompt "A castle" --seed 42 --prompt-extend false',
90+
'bl image generate --prompt "Logo" --watermark false',
91+
'bl image generate --prompt "An alien in the space" --watermark false',
8292
'bl image generate --prompt "sunset" --model wan2.6-t2i --no-wait --quiet',
8393
'bl image generate --prompt "Pro quality" --model qwen-image-2.0-pro',
8494
'bl image generate --prompt "Product shots" --n 2 --concurrent 3 # 6 images in parallel',
@@ -111,15 +121,13 @@ export default defineCommand({
111121
const n = (flags.n as number) ?? 1;
112122
const concurrent = getConcurrency(flags);
113123

114-
// Determine prompt_extend: default true for qwen-image, undefined for others
115-
let promptExtend: boolean | undefined;
116-
if (flags.noPromptExtend === true) {
117-
promptExtend = false;
118-
} else if (flags.promptExtend === true) {
119-
promptExtend = true;
120-
} else if (useSync) {
121-
promptExtend = true; // qwen-image default
122-
}
124+
const promptExtend = resolveBooleanFlag(
125+
flags.promptExtend,
126+
useSync ? true : undefined,
127+
"prompt-extend",
128+
);
129+
130+
const watermark = resolveWatermark(flags.watermark);
123131

124132
const body: DashScopeImageRequest = {
125133
model,
@@ -131,7 +139,7 @@ export default defineCommand({
131139
n,
132140
seed: flags.seed as number | undefined,
133141
prompt_extend: promptExtend,
134-
watermark: flags.watermark === true ? true : undefined,
142+
watermark,
135143
negative_prompt: (flags.negativePrompt as string) || undefined,
136144
},
137145
};

packages/cli/src/commands/video/edit.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,17 @@ import {
1515
resolveCredential,
1616
BailianError,
1717
ExitCode,
18+
resolveBooleanFlag,
19+
resolveWatermark,
1820
} from "bailian-cli-core";
1921
import { poll } from "../../utils/polling.ts";
2022
import { downloadFile, formatBytes } from "../../utils/download.ts";
2123
import { promptText, failIfMissing } from "../../output/prompt.ts";
2224
import { emitResult, emitBare } from "../../output/output.ts";
25+
import {
26+
BOOL_FLAG_PROMPT_EXTEND_API_DEFAULT,
27+
BOOL_FLAG_WATERMARK,
28+
} from "../../utils/flag-descriptions.ts";
2329

2430
export default defineCommand({
2531
name: "video edit",
@@ -51,9 +57,14 @@ export default defineCommand({
5157
flag: "--audio-setting <mode>",
5258
description: "Audio: auto (default) or origin (keep original)",
5359
},
54-
{ flag: "--prompt-extend", description: "Enable prompt intelligent rewriting (default: true)" },
55-
{ flag: "--no-prompt-extend", description: "Disable prompt intelligent rewriting" },
56-
{ flag: "--watermark", description: 'Add "AI生成" watermark' },
60+
{
61+
flag: "--prompt-extend <bool>",
62+
description: BOOL_FLAG_PROMPT_EXTEND_API_DEFAULT,
63+
},
64+
{
65+
flag: "--watermark <bool>",
66+
description: BOOL_FLAG_WATERMARK,
67+
},
5768
{ flag: "--seed <n>", description: "Random seed for reproducible generation", type: "number" },
5869
{ flag: "--download <path>", description: "Save video to file on completion" },
5970
{ flag: "--no-wait", description: "Return task ID immediately without waiting" },
@@ -71,6 +82,7 @@ export default defineCommand({
7182
'bl video edit --video https://example.com/input.mp4 --prompt "将整个画面转换为黏土风格"',
7283
'bl video edit --video https://example.com/input.mp4 --prompt "替换衣服为图片中的款式" --ref-image https://example.com/clothes.png',
7384
'bl video edit --video https://example.com/input.mp4 --prompt "Convert to anime style" --resolution 720P --download output.mp4',
85+
'bl video edit --video https://example.com/input.mp4 --prompt "给视频里的小猫穿上衣服" --watermark false',
7486
],
7587
async run(config: Config, flags: GlobalFlags) {
7688
// --- Validate video URL ---
@@ -127,8 +139,8 @@ export default defineCommand({
127139
}
128140

129141
// --- Build request body ---
130-
const promptExtend =
131-
flags.noPromptExtend === true ? false : flags.promptExtend === true ? true : undefined;
142+
const promptExtend = resolveBooleanFlag(flags.promptExtend, undefined, "prompt-extend");
143+
const watermark = resolveWatermark(flags.watermark);
132144

133145
const body: DashScopeVideoEditRequest = {
134146
model,
@@ -143,7 +155,7 @@ export default defineCommand({
143155
duration: (flags.duration as number) || undefined,
144156
audio_setting: (flags.audioSetting as "auto" | "origin") || undefined,
145157
prompt_extend: promptExtend,
146-
watermark: flags.watermark === true ? true : undefined,
158+
watermark,
147159
seed: flags.seed as number | undefined,
148160
},
149161
};

packages/cli/src/commands/video/generate.ts

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,18 @@ import {
1515
resolveCredential,
1616
BailianError,
1717
ExitCode,
18+
resolveBooleanFlag,
19+
resolveWatermark,
1820
} from "bailian-cli-core";
1921
import { poll } from "../../utils/polling.ts";
2022
import { downloadFile, formatBytes } from "../../utils/download.ts";
2123
import { runConcurrent, getConcurrency } from "../../utils/concurrent.ts";
2224
import { promptText, failIfMissing } from "../../output/prompt.ts";
2325
import { emitResult, emitBare } from "../../output/output.ts";
26+
import {
27+
BOOL_FLAG_PROMPT_EXTEND_API_DEFAULT,
28+
BOOL_FLAG_WATERMARK,
29+
} from "../../utils/flag-descriptions.ts";
2430

2531
// Normalize shorthand resolution (720P, 1080P) to pixel format for video generation models
2632
const RESOLUTION_SHORTCUTS: Record<string, string> = {
@@ -58,8 +64,14 @@ export default defineCommand({
5864
description: "Video duration in seconds (default: 5)",
5965
type: "number",
6066
},
61-
{ flag: "--prompt-extend", description: "Automatically extend prompt for better results" },
62-
{ flag: "--watermark", description: "Add watermark to generated video" },
67+
{
68+
flag: "--prompt-extend <bool>",
69+
description: BOOL_FLAG_PROMPT_EXTEND_API_DEFAULT,
70+
},
71+
{
72+
flag: "--watermark <bool>",
73+
description: BOOL_FLAG_WATERMARK,
74+
},
6375
{ flag: "--seed <n>", description: "Random seed for reproducible generation", type: "number" },
6476
{ flag: "--download <path>", description: "Save video to file on completion" },
6577
{ flag: "--no-wait", description: "Return task ID immediately without waiting" },
@@ -78,6 +90,7 @@ export default defineCommand({
7890
'bl video generate --prompt "Ocean waves at sunset." --download sunset.mp4',
7991
'bl video generate --image https://example.com/cat.png --prompt "让画面中的猫动起来"',
8092
'bl video generate --prompt "Mountain landscape" --resolution 1280*720 --duration 5',
93+
'bl video generate --prompt "A cat playing with a ball" --watermark false',
8194
],
8295
async run(config: Config, flags: GlobalFlags) {
8396
let prompt = flags.prompt as string | undefined;
@@ -110,6 +123,9 @@ export default defineCommand({
110123
resolvedImageUrl = await resolveFileUrl(imageUrl, credential.token, model);
111124
}
112125

126+
const watermark = resolveWatermark(flags.watermark);
127+
const promptExtend = resolveBooleanFlag(flags.promptExtend, undefined, "prompt-extend");
128+
113129
const body: DashScopeVideoRequest = {
114130
model,
115131
input: {
@@ -124,8 +140,8 @@ export default defineCommand({
124140
resolution: normalizeResolution(flags.resolution as string) || undefined,
125141
ratio: (flags.ratio as string) || undefined,
126142
duration: (flags.duration as number) || undefined,
127-
prompt_extend: flags.promptExtend === true ? true : undefined,
128-
watermark: flags.watermark === true ? true : undefined,
143+
prompt_extend: promptExtend,
144+
watermark,
129145
seed: flags.seed as number | undefined,
130146
},
131147
};

0 commit comments

Comments
 (0)