Skip to content

Commit 6218637

Browse files
Merge pull request #194 from modelstudioai/feat/global-watermark-config
Feat/global watermark config
2 parents 0dbf071 + 0c7ba72 commit 6218637

29 files changed

Lines changed: 447 additions & 52 deletions

packages/commands/src/commands/config/set.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ export default defineCommand({
1212
valueHint: "<key>",
1313
description: {
1414
"en-US":
15-
"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)",
15+
"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)",
1616
"zh-CN":
17-
"配置项名称(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)",
17+
"配置项名称(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)",
1818
},
1919
required: true,
2020
},
@@ -29,6 +29,7 @@ export default defineCommand({
2929
"--key language --value zh-CN",
3030
"--key output --value json",
3131
"--key timeout --value 600",
32+
"--key watermark --value false",
3233
"--key base_url --value https://dashscope.aliyuncs.com",
3334
"--config company-plan --key api-key-capabilities --value text.chat,image.generate",
3435
],

packages/commands/src/commands/config/shared.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import {
33
ExitCode,
44
isApiKeyCapability,
55
normalizeModelBaseUrl,
6+
parseBooleanValue,
67
SUPPORTED_LANGUAGES,
78
} from "bailian-cli-core";
89

@@ -13,6 +14,7 @@ export const VALID_KEYS = [
1314
"output",
1415
"output_dir",
1516
"timeout",
17+
"watermark",
1618
"api_key",
1719
"access_token",
1820
"access_key_id",
@@ -62,7 +64,7 @@ export const UI_ENUM_KEYS: Record<string, string[]> = {
6264
};
6365

6466
// Keys the UI renders as a true/false dropdown and stores as a boolean.
65-
export const UI_BOOLEAN_KEYS = new Set<string>(["telemetry"]);
67+
export const UI_BOOLEAN_KEYS = new Set<string>(["telemetry", "watermark"]);
6668

6769
// Default model each `default_*_model` key falls back to when left unset. These
6870
// mirror the inline `|| "<model>"` fallbacks in the generation commands
@@ -164,7 +166,10 @@ export function resolveKey(key: string): string {
164166
* Validate a single config entry and coerce its value to the stored type.
165167
* Throws BailianError(USAGE) for unknown keys or invalid values.
166168
*/
167-
export function validateAndCoerce(key: string, value: string): string | number | string[] {
169+
export function validateAndCoerce(
170+
key: string,
171+
value: string,
172+
): string | number | boolean | string[] {
168173
const resolvedKey = resolveKey(key);
169174

170175
if (!(VALID_KEYS as readonly string[]).includes(resolvedKey)) {
@@ -201,6 +206,8 @@ export function validateAndCoerce(key: string, value: string): string | number |
201206

202207
if (resolvedKey === "base_url") return normalizeModelBaseUrl(value);
203208

209+
if (resolvedKey === "watermark") return parseBooleanValue(value, "watermark");
210+
204211
if (resolvedKey === "api_key_capabilities") {
205212
let rawCapabilities: unknown;
206213
if (value.trim().startsWith("[")) {

packages/commands/src/commands/config/show.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export default defineCommand({
1818
base_url: client.baseUrl,
1919
output: settings.output,
2020
timeout: settings.timeout,
21+
watermark: settings.watermark,
2122
config: settings.configName ?? "default",
2223
config_file: store.path,
2324
};

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ export default defineCommand({
207207
"prompt-extend",
208208
);
209209

210-
const watermark = resolveWatermark(flags.watermark);
210+
const watermark = resolveWatermark(flags.watermark, settings.watermark);
211211

212212
const parameters: NonNullable<DashScopeImageRequest["parameters"]> = {
213213
size: resolveImageSize(flags.size, route.sizeProfile),

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ export default defineCommand({
185185
"prompt-extend",
186186
);
187187

188-
const watermark = resolveWatermark(flags.watermark);
188+
const watermark = resolveWatermark(flags.watermark, settings.watermark);
189189

190190
const parameters: NonNullable<DashScopeImageRequest["parameters"]> = {
191191
size,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ export default defineCommand({
197197

198198
// --- Build request body ---
199199
const promptExtend = resolveBooleanFlag(flags.promptExtend, undefined, "prompt-extend");
200-
const watermark = resolveWatermark(flags.watermark);
200+
const watermark = resolveWatermark(flags.watermark, settings.watermark);
201201

202202
const body: DashScopeVideoEditRequest = {
203203
model,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ export default defineCommand({
208208
resolvedFileUrl = await ctx.client.uploadFile(fileUrl, model);
209209
}
210210

211-
const watermark = resolveWatermark(flags.watermark);
211+
const watermark = resolveWatermark(flags.watermark, settings.watermark);
212212
const promptExtend = resolveBooleanFlag(flags.promptExtend, undefined, "prompt-extend");
213213

214214
const body: DashScopeVideoRequest = {

packages/commands/src/commands/video/ref.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ export default defineCommand({
249249

250250
// --- Build request body ---
251251
const promptExtend = resolveBooleanFlag(flags.promptExtend, undefined, "prompt-extend");
252-
const watermark = resolveWatermark(flags.watermark);
252+
const watermark = resolveWatermark(flags.watermark, settings.watermark);
253253

254254
const body: DashScopeVideoRefRequest = {
255255
model,

packages/commands/tests/config-shared.test.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,9 @@ test("default-speech-recognition-model alias accepts an ASR model ID", () => {
3333
"qwen-audio-3.0-asr-flash",
3434
);
3535
});
36+
37+
test("watermark config accepts only boolean text and stores a boolean", () => {
38+
expect(validateAndCoerce("watermark", "false")).toBe(false);
39+
expect(validateAndCoerce("watermark", "TRUE")).toBe(true);
40+
expect(() => validateAndCoerce("watermark", "yes")).toThrow(/true or false/i);
41+
});

packages/commands/tests/config-ui.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,10 @@ test("GET /api/config 返回全部 profile、明文密钥与持久化激活项",
200200
expect(res.json.keys).toContain("console_site");
201201
expect(res.json.keys).toContain("telemetry");
202202
expect(res.json.keys).toContain("default_speech_recognition_model");
203+
expect(res.json.keys).toContain("watermark");
203204
expect(res.json.enums.console_site).toEqual(["domestic", "international"]);
204205
expect(res.json.booleanKeys).toContain("telemetry");
206+
expect(res.json.booleanKeys).toContain("watermark");
205207
// Default field hints are surfaced as prefilled values in the UI.
206208
expect(res.json.fieldDefaults.default_image_model).toBe("qwen-image-3.0");
207209
expect(res.json.fieldDefaults.default_text_model).toBe("qwen3.8-max");

0 commit comments

Comments
 (0)