@lingjingai/lj-awb-cli-pre 0.4.0 → 0.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -0
- package/build/_shared.mjs +54 -5
- package/build/prod.mjs +12 -3
- package/package.json +2 -2
- package/packages/awb-cli/package.json +2 -2
- package/packages/awb-core/package.json +1 -1
- package/packages/awb-core/src/api.js +31 -0
- package/packages/awb-core/src/commands.js +141 -39
- package/packages/awb-core/src/common.js +20 -0
- package/packages/awb-core/src/output.js +176 -9
- package/packages/awb-core/src/services.js +1767 -198
- package/packages/awb-core/src/standalone.js +116 -12
- package/packages/awb-core/src/update.js +327 -0
- package/skills/lj-awb/SKILL.md +30 -9
- package/skills/lj-awb/VERSION +1 -1
- package/skills/lj-awb/compat.json +3 -3
- package/skills/lj-awb/modules/asset.md +10 -1
- package/skills/lj-awb/modules/auth.md +9 -1
- package/skills/lj-awb/modules/create-contract.md +5 -2
- package/skills/lj-awb/modules/create.md +4 -2
- package/skills/lj-awb/modules/credits.md +19 -2
- package/skills/lj-awb/modules/driver.md +1 -0
- package/skills/lj-awb/modules/image.md +3 -1
- package/skills/lj-awb/modules/model.md +5 -4
- package/skills/lj-awb/modules/task.md +4 -1
- package/skills/lj-awb/modules/upload.md +1 -1
- package/skills/lj-awb/modules/video.md +11 -2
- package/skills/lj-awb/modules/workflows.md +3 -1
- package/skills/lj-awb/references/error-codes.md +41 -0
- package/skills/lj-awb/references/model-options-read.md +7 -6
- package/skills/lj-awb/references/output-fields.md +10 -5
- package/skills/lj-awb/scripts/resolve-lj-awb-cmd.sh +106 -4
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import fsSync from 'node:fs';
|
|
3
|
+
import fs from 'node:fs/promises';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { promisify } from 'node:util';
|
|
7
|
+
import {
|
|
8
|
+
LingjingAwbCliError,
|
|
9
|
+
loadState,
|
|
10
|
+
nowIso,
|
|
11
|
+
saveState,
|
|
12
|
+
toBool,
|
|
13
|
+
toInt,
|
|
14
|
+
trimToNull,
|
|
15
|
+
} from './common.js';
|
|
16
|
+
|
|
17
|
+
const execFileAsync = promisify(execFile);
|
|
18
|
+
const DEFAULT_CLI_PACKAGE_NAME = '@lingjingai/lj-awb-cli';
|
|
19
|
+
const DEFAULT_NPM_REGISTRY = 'https://registry.npmjs.org/';
|
|
20
|
+
const DEFAULT_CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
21
|
+
const DEFAULT_NPM_TIMEOUT_MS = 15_000;
|
|
22
|
+
const AUTO_CHECK_TIMEOUT_MS = 4_000;
|
|
23
|
+
|
|
24
|
+
function commandPrefix() {
|
|
25
|
+
return process.env.LINGJING_AWB_COMMAND_PREFIX || 'lj-awb';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function boolEnv(value) {
|
|
29
|
+
return ['1', 'true', 'yes', 'y', 'on'].includes(String(value ?? '').trim().toLowerCase());
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function readPackageJsonSync(packagePath) {
|
|
33
|
+
try {
|
|
34
|
+
return JSON.parse(fsSync.readFileSync(packagePath, 'utf8'));
|
|
35
|
+
} catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function corePackagePath() {
|
|
41
|
+
return path.join(path.dirname(fileURLToPath(import.meta.url)), '..', 'package.json');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function rootPackagePath() {
|
|
45
|
+
return path.join(path.dirname(fileURLToPath(import.meta.url)), '..', '..', '..', 'package.json');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export async function readCurrentCliVersion() {
|
|
49
|
+
const pkg = JSON.parse(await fs.readFile(corePackagePath(), 'utf8'));
|
|
50
|
+
return pkg.version || 'unknown';
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function currentRootDir() {
|
|
54
|
+
return path.dirname(rootPackagePath());
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function isLocalCheckout() {
|
|
58
|
+
return fsSync.existsSync(path.join(currentRootDir(), '.git'));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function resolveCliPackageName(kwargs = {}) {
|
|
62
|
+
const explicit = trimToNull(kwargs.packageName || kwargs.package || process.env.LINGJING_AWB_CLI_PACKAGE);
|
|
63
|
+
if (explicit) return explicit;
|
|
64
|
+
const rootPkg = readPackageJsonSync(rootPackagePath());
|
|
65
|
+
const name = trimToNull(rootPkg?.name);
|
|
66
|
+
return name?.startsWith('@lingjingai/lj-awb-cli') ? name : DEFAULT_CLI_PACKAGE_NAME;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function resolveRegistry(kwargs = {}) {
|
|
70
|
+
return trimToNull(
|
|
71
|
+
kwargs.registry
|
|
72
|
+
|| process.env.LINGJING_AWB_UPDATE_REGISTRY
|
|
73
|
+
|| process.env.NPM_CONFIG_REGISTRY
|
|
74
|
+
|| process.env.npm_config_registry,
|
|
75
|
+
) || DEFAULT_NPM_REGISTRY;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function updateCheckIntervalMs() {
|
|
79
|
+
const raw = process.env.LINGJING_AWB_UPDATE_CHECK_INTERVAL_MS;
|
|
80
|
+
if (raw === undefined || raw === null || raw === '') return DEFAULT_CHECK_INTERVAL_MS;
|
|
81
|
+
return Math.max(0, toInt(raw, DEFAULT_CHECK_INTERVAL_MS));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function updateCheckDisabled() {
|
|
85
|
+
return boolEnv(process.env.LINGJING_AWB_DISABLE_UPDATE_CHECK)
|
|
86
|
+
|| boolEnv(process.env.AWB_DISABLE_UPDATE_CHECK)
|
|
87
|
+
|| ['0', 'false', 'off', 'no'].includes(String(process.env.LINGJING_AWB_UPDATE_CHECK ?? '').trim().toLowerCase());
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function forceAutoUpdateCheck() {
|
|
91
|
+
return boolEnv(process.env.LINGJING_AWB_UPDATE_CHECK)
|
|
92
|
+
|| String(process.env.LINGJING_AWB_UPDATE_CHECK || '').trim().toLowerCase() === 'force';
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function parseVersion(value) {
|
|
96
|
+
const text = String(value || '').trim().replace(/^v/i, '');
|
|
97
|
+
const [main, pre = ''] = text.split('-', 2);
|
|
98
|
+
const parts = main.split('.').map((item) => Number.parseInt(item, 10));
|
|
99
|
+
if (parts.some((item) => !Number.isFinite(item))) return null;
|
|
100
|
+
return { parts, pre };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function semverLessThan(a, b) {
|
|
104
|
+
const left = parseVersion(a);
|
|
105
|
+
const right = parseVersion(b);
|
|
106
|
+
if (!left || !right) return false;
|
|
107
|
+
for (let index = 0; index < 3; index += 1) {
|
|
108
|
+
const lv = left.parts[index] || 0;
|
|
109
|
+
const rv = right.parts[index] || 0;
|
|
110
|
+
if (lv < rv) return true;
|
|
111
|
+
if (lv > rv) return false;
|
|
112
|
+
}
|
|
113
|
+
if (left.pre && !right.pre) return true;
|
|
114
|
+
if (!left.pre && right.pre) return false;
|
|
115
|
+
return left.pre < right.pre;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function npmArgsWithRegistry(args, registry) {
|
|
119
|
+
return registry ? [...args, `--registry=${registry}`] : args;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function npmInstallSpec(packageName, version) {
|
|
123
|
+
return version && version !== 'latest' ? `${packageName}@${version}` : packageName;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
async function runNpm(args, options = {}) {
|
|
127
|
+
try {
|
|
128
|
+
const result = await execFileAsync('npm', args, {
|
|
129
|
+
cwd: currentRootDir(),
|
|
130
|
+
encoding: 'utf8',
|
|
131
|
+
timeout: options.timeoutMs || DEFAULT_NPM_TIMEOUT_MS,
|
|
132
|
+
maxBuffer: 1024 * 1024,
|
|
133
|
+
env: process.env,
|
|
134
|
+
});
|
|
135
|
+
return result;
|
|
136
|
+
} catch (error) {
|
|
137
|
+
const stderr = String(error.stderr || '').trim();
|
|
138
|
+
const stdout = String(error.stdout || '').trim();
|
|
139
|
+
throw new LingjingAwbCliError('npm 命令执行失败', {
|
|
140
|
+
type: 'network_error',
|
|
141
|
+
exitCode: 30,
|
|
142
|
+
hint: stderr || stdout || error.message || '请确认 npm 可用,并且当前网络可以访问 npm registry。',
|
|
143
|
+
details: {
|
|
144
|
+
command: `npm ${args.join(' ')}`,
|
|
145
|
+
code: error.code,
|
|
146
|
+
signal: error.signal,
|
|
147
|
+
},
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export async function fetchLatestCliVersion(options = {}) {
|
|
153
|
+
const mocked = trimToNull(process.env.LINGJING_AWB_UPDATE_LATEST_VERSION);
|
|
154
|
+
if (mocked) return mocked;
|
|
155
|
+
const packageName = options.packageName || resolveCliPackageName(options);
|
|
156
|
+
const registry = options.registry || resolveRegistry(options);
|
|
157
|
+
const result = await runNpm(
|
|
158
|
+
npmArgsWithRegistry(['view', packageName, 'version'], registry),
|
|
159
|
+
{ timeoutMs: options.timeoutMs || DEFAULT_NPM_TIMEOUT_MS },
|
|
160
|
+
);
|
|
161
|
+
const version = String(result.stdout || '').trim().replace(/^"|"$/g, '');
|
|
162
|
+
if (!/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/.test(version)) {
|
|
163
|
+
throw new LingjingAwbCliError('无法识别 npm latest 版本', {
|
|
164
|
+
type: 'runtime_error',
|
|
165
|
+
exitCode: 1,
|
|
166
|
+
hint: `npm view ${packageName} version 返回了非 semver 内容。`,
|
|
167
|
+
details: { version },
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
return version;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
function buildUpdateNotice({ currentVersion, latestVersion, packageName, checkedAt }) {
|
|
174
|
+
const command = `${commandPrefix()} update`;
|
|
175
|
+
return {
|
|
176
|
+
message: `检测到 ${commandPrefix()} 新版本 ${latestVersion}(当前 ${currentVersion})。运行 ${command} 更新 CLI 和 skill。`,
|
|
177
|
+
command,
|
|
178
|
+
checkCommand: `${commandPrefix()} update --check`,
|
|
179
|
+
packageName,
|
|
180
|
+
currentVersion,
|
|
181
|
+
latestVersion,
|
|
182
|
+
checkedAt,
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function cachedNotice(state, currentVersion, packageName) {
|
|
187
|
+
const cached = state?.updateCheck;
|
|
188
|
+
if (!cached || cached.packageName !== packageName || cached.currentVersion !== currentVersion) return null;
|
|
189
|
+
if (!cached.latestVersion || !semverLessThan(currentVersion, cached.latestVersion)) return null;
|
|
190
|
+
return buildUpdateNotice({
|
|
191
|
+
currentVersion,
|
|
192
|
+
latestVersion: cached.latestVersion,
|
|
193
|
+
packageName,
|
|
194
|
+
checkedAt: cached.checkedAtText || null,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function shouldSkipAutoCheck() {
|
|
199
|
+
if (updateCheckDisabled()) return true;
|
|
200
|
+
if (forceAutoUpdateCheck()) return false;
|
|
201
|
+
if (process.env.CI) return true;
|
|
202
|
+
if (isLocalCheckout()) return true;
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
export async function checkCliUpdate(options = {}) {
|
|
207
|
+
const currentVersion = options.currentVersion || await readCurrentCliVersion().catch(() => 'unknown');
|
|
208
|
+
const packageName = resolveCliPackageName(options);
|
|
209
|
+
if (!currentVersion || currentVersion === 'unknown' || shouldSkipAutoCheck()) return null;
|
|
210
|
+
|
|
211
|
+
const state = await loadState().catch(() => ({}));
|
|
212
|
+
const cached = state?.updateCheck || {};
|
|
213
|
+
const now = Date.now();
|
|
214
|
+
const intervalMs = options.force ? 0 : updateCheckIntervalMs();
|
|
215
|
+
const cacheHit = cached.packageName === packageName
|
|
216
|
+
&& cached.currentVersion === currentVersion
|
|
217
|
+
&& cached.checkedAt
|
|
218
|
+
&& (now - Number(cached.checkedAt) < intervalMs);
|
|
219
|
+
if (cacheHit) return cachedNotice(state, currentVersion, packageName);
|
|
220
|
+
|
|
221
|
+
try {
|
|
222
|
+
const registry = resolveRegistry(options);
|
|
223
|
+
const latestVersion = await fetchLatestCliVersion({
|
|
224
|
+
packageName,
|
|
225
|
+
registry,
|
|
226
|
+
timeoutMs: options.timeoutMs || AUTO_CHECK_TIMEOUT_MS,
|
|
227
|
+
});
|
|
228
|
+
const checkedAtText = nowIso();
|
|
229
|
+
await saveState({
|
|
230
|
+
updateCheck: {
|
|
231
|
+
packageName,
|
|
232
|
+
registry,
|
|
233
|
+
currentVersion,
|
|
234
|
+
latestVersion,
|
|
235
|
+
checkedAt: now,
|
|
236
|
+
checkedAtText,
|
|
237
|
+
},
|
|
238
|
+
}).catch(() => {});
|
|
239
|
+
if (!semverLessThan(currentVersion, latestVersion)) return null;
|
|
240
|
+
return buildUpdateNotice({ currentVersion, latestVersion, packageName, checkedAt: checkedAtText });
|
|
241
|
+
} catch (error) {
|
|
242
|
+
await saveState({
|
|
243
|
+
updateCheck: {
|
|
244
|
+
packageName,
|
|
245
|
+
currentVersion,
|
|
246
|
+
latestVersion: cached.latestVersion || null,
|
|
247
|
+
checkedAt: now,
|
|
248
|
+
checkedAtText: nowIso(),
|
|
249
|
+
error: error.message || String(error),
|
|
250
|
+
},
|
|
251
|
+
}).catch(() => {});
|
|
252
|
+
return cachedNotice({ updateCheck: cached }, currentVersion, packageName);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function tailLines(value, limit = 8) {
|
|
257
|
+
const lines = String(value || '').trim().split(/\r?\n/).filter(Boolean);
|
|
258
|
+
return lines.slice(Math.max(0, lines.length - limit));
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export async function runCliUpdate(kwargs = {}) {
|
|
262
|
+
const currentVersion = await readCurrentCliVersion().catch(() => 'unknown');
|
|
263
|
+
const packageName = resolveCliPackageName(kwargs);
|
|
264
|
+
const registry = resolveRegistry(kwargs);
|
|
265
|
+
const latestVersion = await fetchLatestCliVersion({ packageName, registry });
|
|
266
|
+
const updateAvailable = currentVersion !== 'unknown' && semverLessThan(currentVersion, latestVersion);
|
|
267
|
+
const checkOnly = toBool(kwargs.check);
|
|
268
|
+
const force = toBool(kwargs.force);
|
|
269
|
+
const installVersion = latestVersion || 'latest';
|
|
270
|
+
const installSpec = npmInstallSpec(packageName, force ? 'latest' : installVersion);
|
|
271
|
+
const installArgs = npmArgsWithRegistry(['install', '-g', installSpec], registry);
|
|
272
|
+
|
|
273
|
+
if (checkOnly) {
|
|
274
|
+
return {
|
|
275
|
+
checked: true,
|
|
276
|
+
updated: false,
|
|
277
|
+
updateAvailable,
|
|
278
|
+
packageName,
|
|
279
|
+
currentVersion,
|
|
280
|
+
latestVersion,
|
|
281
|
+
command: updateAvailable ? `${commandPrefix()} update` : null,
|
|
282
|
+
message: updateAvailable
|
|
283
|
+
? `发现新版本 ${latestVersion},运行 ${commandPrefix()} update 更新。`
|
|
284
|
+
: '当前已是最新版本。',
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (!updateAvailable && !force) {
|
|
289
|
+
return {
|
|
290
|
+
checked: true,
|
|
291
|
+
updated: false,
|
|
292
|
+
updateAvailable: false,
|
|
293
|
+
packageName,
|
|
294
|
+
currentVersion,
|
|
295
|
+
latestVersion,
|
|
296
|
+
message: '当前已是最新版本。',
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const result = await runNpm(installArgs, { timeoutMs: 120_000 });
|
|
301
|
+
await saveState({
|
|
302
|
+
updateCheck: {
|
|
303
|
+
packageName,
|
|
304
|
+
registry,
|
|
305
|
+
currentVersion: latestVersion,
|
|
306
|
+
latestVersion,
|
|
307
|
+
checkedAt: Date.now(),
|
|
308
|
+
checkedAtText: nowIso(),
|
|
309
|
+
},
|
|
310
|
+
}).catch(() => {});
|
|
311
|
+
|
|
312
|
+
return {
|
|
313
|
+
checked: true,
|
|
314
|
+
updated: true,
|
|
315
|
+
updateAvailable,
|
|
316
|
+
packageName,
|
|
317
|
+
previousVersion: currentVersion,
|
|
318
|
+
currentVersion: latestVersion,
|
|
319
|
+
latestVersion,
|
|
320
|
+
command: `npm ${installArgs.join(' ')}`,
|
|
321
|
+
skillUpdated: true,
|
|
322
|
+
restartRecommended: true,
|
|
323
|
+
message: '更新完成。请退出并重新打开 AI Agent,以加载最新 CLI 和 skill。',
|
|
324
|
+
stdoutTail: tailLines(result.stdout),
|
|
325
|
+
stderrTail: tailLines(result.stderr),
|
|
326
|
+
};
|
|
327
|
+
}
|
package/skills/lj-awb/SKILL.md
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: lj-awb
|
|
3
|
-
version: 0.4.
|
|
4
|
-
description: "灵境 AWB CLI skill。使用 `lj-awb` 命令调用动漫平台 / AWB
|
|
3
|
+
version: 0.4.6
|
|
4
|
+
description: "灵境 AWB CLI skill。使用 `lj-awb` 命令调用动漫平台 / AWB 云端能力,覆盖认证、项目组、积分(含充值购买与兑换码兑换)、模型发现、上传、统一 create 创建域、任务查询、视频超分、最终产物 artifact CRUD 与本地 JSON 导入。用户说生图、生视频、视频超分、主体、音色、素材加白、去字幕、充值、购买积分、兑换码、artifact 写入或查询时使用。正式生成、切换项目组、清空认证、兑换码、artifact 写入等写入或扣费动作前必须确认。"
|
|
5
5
|
metadata:
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
bootstrap:
|
|
7
|
+
package: "@lingjingai/lj-awb-cli"
|
|
8
|
+
version: "0.4.6"
|
|
9
|
+
bin: "lj-awb"
|
|
8
10
|
cliHelp: "lj-awb --help"
|
|
9
11
|
---
|
|
10
12
|
|
|
11
13
|
# lj-awb CLI Skill
|
|
12
14
|
|
|
13
15
|
`lj-awb` 是确定性 CLI,skill 的职责是调度:少查、少问、少重跑,按 schema 和业务链条把命令串对。不要把本 skill 当成一堆命令片段来拼。
|
|
16
|
+
普通命令如果 JSON 输出里出现 `meta._notice.update`,先完成当前用户请求,再告诉用户当前版本和最新版本,并建议执行 `lj-awb update`;更新后提醒重新打开 AI Agent。
|
|
14
17
|
|
|
15
18
|
## 先读驱动器
|
|
16
19
|
|
|
@@ -25,22 +28,35 @@ metadata:
|
|
|
25
28
|
|
|
26
29
|
## 入口命令
|
|
27
30
|
|
|
28
|
-
|
|
31
|
+
本 skill 是完整入口:如果用户只安装了 skill,也要先自举补齐 CLI。每个新环境第一次使用 `lj-awb` 前,先解析命令:
|
|
29
32
|
|
|
30
33
|
```bash
|
|
31
|
-
lj-awb
|
|
34
|
+
for dir in "$PWD/skills/lj-awb" "$HOME/.codex/skills/lj-awb" "$HOME/.claude/skills/lj-awb" "$HOME/.cc-switch/skills/lj-awb"; do
|
|
35
|
+
if [ -x "$dir/scripts/resolve-lj-awb-cmd.sh" ]; then
|
|
36
|
+
LINGJING_AWB_CMD="$(bash "$dir/scripts/resolve-lj-awb-cmd.sh")"
|
|
37
|
+
break
|
|
38
|
+
fi
|
|
39
|
+
done
|
|
40
|
+
: "${LINGJING_AWB_CMD:?lj-awb bootstrap script not found}"
|
|
32
41
|
```
|
|
33
42
|
|
|
34
|
-
|
|
43
|
+
`resolve-lj-awb-cmd.sh` 会按顺序处理:
|
|
44
|
+
|
|
45
|
+
- 已存在兼容版本 `lj-awb`:直接返回命令路径。
|
|
46
|
+
- 未安装或版本低于 [`compat.json`](compat.json) 的 `minCliVersion`:自动执行 `npm install -g @lingjingai/lj-awb-cli@<minCliVersion>`。
|
|
47
|
+
- 用户要预发环境时,安装前设置 `LINGJING_AWB_CLI_PACKAGE=@lingjingai/lj-awb-cli-pre`。
|
|
48
|
+
- 缺少 npm / Node 时,提示用户先安装 Node.js `>=20`,再重试。
|
|
49
|
+
|
|
50
|
+
脚本 stdout 只输出可执行命令;安装日志和错误走 stderr。后续命令优先使用解析结果:
|
|
35
51
|
|
|
36
52
|
```bash
|
|
37
|
-
|
|
53
|
+
"$LINGJING_AWB_CMD" --help
|
|
38
54
|
```
|
|
39
55
|
|
|
40
56
|
非单条查询任务、命令不确定或涉及写入 / 扣费时,本轮只读一次机器契约:
|
|
41
57
|
|
|
42
58
|
```bash
|
|
43
|
-
|
|
59
|
+
"$LINGJING_AWB_CMD" schema --brief -f json
|
|
44
60
|
```
|
|
45
61
|
|
|
46
62
|
`schema --brief` 只用于掌握能力域、安全分组、业务路由和 agentContract。执行具体命令前,如果命令、参数、requiredOptions、safety 或 nextActions 不确定,再读精确契约,例如 `lj-awb schema --domain model --command video-models -f json`。不要把完整 `lj-awb schema -f json` 当默认入口;只有校验覆盖、脚本生成或 brief 缺失字段时才读完整 schema。
|
|
@@ -48,6 +64,7 @@ lj-awb schema --brief -f json
|
|
|
48
64
|
schema 查询必须先返回,再组织业务命令;不要把 schema 查询和猜测命令放进同一批并行调用。
|
|
49
65
|
|
|
50
66
|
如果用户已经给出完整只读命令,且该命令在本 skill 已知范围内,可以直接执行,不必为了形式补跑 schema。命令名、参数名、requiredOptions、safety、workflow.nextActions 都以 schema 为准。旧根域 `image` / `video` / `asset` / `subject` 不存在,不要尝试旧入口。
|
|
67
|
+
`update` 只做显式安装;`update --check` 只检查不安装。
|
|
51
68
|
|
|
52
69
|
## 能力地图
|
|
53
70
|
|
|
@@ -67,9 +84,11 @@ schema 查询必须先返回,再组织业务命令;不要把 schema 查询
|
|
|
67
84
|
| 用户意图 | 先走 |
|
|
68
85
|
|----------|------|
|
|
69
86
|
| “能不能跑 / 认证 / 当前项目 / 余额” | `doctor --verify`,再按需 `account` / `project` / `credits` |
|
|
87
|
+
| “充值 / 购买积分 / 积分不够了 / 兑换码” | [`modules/credits.md`](modules/credits.md):购买走 `credits buy` 给链接,兑换走 `credits redeem`(非交互用 `--code <code>`)|
|
|
70
88
|
| “有哪些模型 / 推荐模型 / 用某某模型” | [`modules/model.md`](modules/model.md),模型口语名默认是平台模型,不是本地工具 |
|
|
71
89
|
| “生图 / 生成图片 / 参考图生图” | [`modules/driver.md`](modules/driver.md) 创作链条 + [`modules/create-contract.md`](modules/create-contract.md) |
|
|
72
90
|
| “生视频 / 首帧 / 首尾帧 / 音频参考 / 让图动起来” | [`modules/driver.md`](modules/driver.md) 创作链条 + [`modules/task-manual.md`](modules/task-manual.md) |
|
|
91
|
+
| “超分 / 放大到 2K / 1080P” | [`modules/video.md`](modules/video.md),传 `objectName` 走 material 视频超分任务体系 |
|
|
73
92
|
| “固定角色 / 主体 / 同一个人 / 可灵或 Vidu 角色一致” | [`modules/subject.md`](modules/subject.md) |
|
|
74
93
|
| “主体音色 / 音色克隆 / 给主体配音色” | [`modules/subject.md`](modules/subject.md) |
|
|
75
94
|
| “素材加白 / 白名单 / 过审 / 素材组” | [`modules/asset.md`](modules/asset.md) |
|
|
@@ -105,6 +124,8 @@ schema 查询必须先返回,再组织业务命令;不要把 schema 查询
|
|
|
105
124
|
|
|
106
125
|
## 安装与版本
|
|
107
126
|
|
|
127
|
+
如果用户只安装了 skill,第一次使用时会由 bootstrap 脚本自动安装 CLI。手动安装命令如下:
|
|
128
|
+
|
|
108
129
|
```bash
|
|
109
130
|
npm install -g @lingjingai/lj-awb-cli
|
|
110
131
|
```
|
package/skills/lj-awb/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.4.
|
|
1
|
+
0.4.6
|
|
@@ -12,8 +12,11 @@
|
|
|
12
12
|
| `lj-awb create asset-group --platform JIMENG --name "<name>" --dry-run` | 预览创建素材组 |
|
|
13
13
|
| `lj-awb create asset-group --platform JIMENG --name "<name>" --yes` | 创建素材组(云端写入) |
|
|
14
14
|
| `lj-awb create asset-group-update --group-id <id> --platform JIMENG --name "<name>" --yes` | 改指定平台素材组名 |
|
|
15
|
-
| `lj-awb create asset --group-id <id> --platform JIMENG --url "asset-review/a.png" --name "女主正面" --yes` |
|
|
15
|
+
| `lj-awb create asset --group-id <id> --platform JIMENG --url "asset-review/a.png" --name "女主正面" --yes` | 注册已上传素材;CLI 自动按扩展名传 `assetType` |
|
|
16
16
|
| `lj-awb create asset --group-id <id> --platform JIMENG --file ./a.png --name "女主正面" --yes` | 先上传到 asset-review 场景再注册(一步完成) |
|
|
17
|
+
| `lj-awb create asset --group-id <id> --platform JIMENG --file ./clip.mp4 --name "参考视频" --dry-run` | 视频素材加白,自动传 `assetType=Video` |
|
|
18
|
+
| `lj-awb create asset --group-id <id> --platform JIMENG --file ./voice.wav --name "参考音频" --dry-run` | 音频素材加白,自动传 `assetType=Audio` |
|
|
19
|
+
| `lj-awb create asset --group-id <id> --platform JIMENG --file ./clip.mov --name "参考视频" --auto-convert --yes` | 本地素材不合法时自动转码为加白规格后上传 |
|
|
17
20
|
| `lj-awb create asset-match-actor --description "..." --tags-json '[{"tagId":"o_102"}]'` | 候选匹配(角色画风 / 标签) |
|
|
18
21
|
|
|
19
22
|
## 什么时候用 match-actor
|
|
@@ -47,6 +50,12 @@ lj-awb create video --model-group-code <videoModelGroupCode> \
|
|
|
47
50
|
|
|
48
51
|
- `create asset-group` / `create asset-group-update` / `create asset` 都是云端写入,**必须确认**后追加 `--yes`。
|
|
49
52
|
- `create asset-*` 平台必须显式传 `--platform JIMENG|BYTEPLUS`;不要依赖默认平台,不要传中文名、小写名或供应商别名。
|
|
53
|
+
- `create asset` 会自动判断并传入 `assetType=Image|Video|Audio`;不要让用户手填资产类型。本地 `--file` 会在提交前校验格式、大小、尺寸、时长、帧率等规则。
|
|
54
|
+
- 本地图片限制:格式 jpeg/jpg、png、webp、bmp、tiff/tif、gif、heic/heif;宽高比(宽/高)在 [0.4,2.5];宽和高都在 [300,6000] px;单张图片小于 30MB。
|
|
55
|
+
- 本地视频限制:格式 mp4、mov;时长 [2,15] 秒;宽高比(宽/高)在 [0.4,2.5];宽和高都在 [300,6000] px;总像素数在 [409600,927408];单个视频不超过 50MB;FPS 在 [24,60]。平台文档里的 480p / 720p 体现在自动转码目标会压到合法像素区间,不再用“短边必须等于 480/720”作为源文件硬过滤。
|
|
56
|
+
- 本地音频限制:格式 wav、mp3;时长 [2,15] 秒。
|
|
57
|
+
- 本地素材不合法时,`--dry-run` 不上传,会返回 `conversionRequired=true` 和 `conversionPlan`;正式执行会询问是否自动转码为合法规格后继续。非交互脚本可追加 `--auto-convert --yes`。
|
|
58
|
+
- 如果本机缺少 `ffprobe` / `ffmpeg`,CLI 在 macOS + Homebrew 环境下会自动运行 `brew install ffmpeg`;其他环境会提示安装命令。需要关闭自动安装时设置 `LINGJING_AWB_AUTO_INSTALL_FFPROBE=0`。
|
|
50
59
|
- `model asset-review-models` 只做发现,不自动创建资产组或素材;不要把 `modelGroupCode` 塞进资产创建命令。
|
|
51
60
|
- 不使用 `/assets/submissions` 这类隐式自动补组流程;资产组是否复用、是否新建由当前任务显式决定。
|
|
52
61
|
- 主体 element(视频里的"同一个人"概念)优先走 `create subject`,不要把素材组 / 素材 ID 当 subjectId 用——两者对应平台不同业务实体。
|
|
@@ -10,9 +10,13 @@
|
|
|
10
10
|
| `lj-awb auth verify` | 联网校验 access key 是否远端有效 |
|
|
11
11
|
| `lj-awb account info` | 联网确认 access key 有效,并查看当前用户 / 团队 / 项目组 |
|
|
12
12
|
| `lj-awb doctor --verify` | 联网体检认证、API、项目组和运行环境 |
|
|
13
|
-
| `lj-awb auth login
|
|
13
|
+
| `lj-awb auth login` | 浏览器授权登录:创建登录任务、展示链接、轮询直到授权成功并自动保存 access key |
|
|
14
|
+
| `lj-awb auth login --no-wait --json` | 只创建登录任务,返回 `flowId` / `verifyUrl`,不阻塞(AI agent / 脚本用) |
|
|
15
|
+
| `lj-awb auth login --flow-id <flowId>` | 复用已有登录任务继续轮询(配合 `--no-wait`,不要重复发起新 login) |
|
|
16
|
+
| `lj-awb auth login --access-key <key>` | 跳过浏览器授权,直接校验并保存 access key |
|
|
14
17
|
| `LINGJING_AWB_ACCESS_KEY=<key> lj-awb auth login` | 从环境变量保存 access key(CLI 自动读环境变量) |
|
|
15
18
|
| `lj-awb auth login --access-key <key> --skip-verify` | 仅保存,不联网校验 |
|
|
19
|
+
| `lj-awb auth logout` | 退出登录:清除本地保存的 access key(无需 `--yes`) |
|
|
16
20
|
| `lj-awb auth clear --dry-run` | 预览清空本地认证 |
|
|
17
21
|
| `lj-awb auth clear --yes` | 确认清空本地认证 |
|
|
18
22
|
|
|
@@ -21,6 +25,10 @@
|
|
|
21
25
|
- 自动化环境只使用 `LINGJING_AWB_ACCESS_KEY`。
|
|
22
26
|
- 不要把 access key 明文写入对话、日志、文档或任务台账。
|
|
23
27
|
- `auth status` 只读本地配置;正式创作前用 `auth verify`、`account info` 或 `doctor --verify` 确认远端可用。
|
|
28
|
+
- 浏览器授权登录(`auth login` 不带 `--access-key`)默认阻塞轮询,**最长约 10 分钟**等用户在浏览器完成授权;runner 的 timeout 需 ≥ 600s。
|
|
29
|
+
- AI agent / 无法实时看输出的场景:先 `auth login --no-wait --json` 拿 `flowId` + `verifyUrl` 给用户,待用户授权后再 `auth login --flow-id <flowId>` 续轮询;**不要重复发起新的 login**,否则会生成新 `flowId` 使旧链接失效。
|
|
30
|
+
- `auth logout` 退出登录:只清本地 access key,无需 `--yes`。
|
|
31
|
+
- 登录流程相关错误(`auth_flow_expired` / `auth_flow_canceled` / `auth_flow_pending`)见 [`../references/error-codes.md`](../references/error-codes.md)。
|
|
24
32
|
- `auth clear` 是本地破坏性动作,必须先确认或 dry-run。
|
|
25
33
|
- 错误恢复(exit 3 / auth_failed / auth_required)见 [`../references/error-codes.md`](../references/error-codes.md) 场景 4。
|
|
26
34
|
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
| `--generate-num` | 生图张数 | 仅图片模型支持时使用 |
|
|
14
14
|
| `--duration` | 生视频时长,单位秒 | 对应平台旧参数 `generated_time`,只能从允许值选择 |
|
|
15
15
|
| `--need-audio` | 是否需要输出音效 | 仅用户明确要求输出音效,且 `model options.params[key=needAudio]` 存在时使用;不是上传音频入口。模型未暴露该 param 时**不要为了"显式关闭"传 `--need-audio false`**,CLI 会以 `argument_error: 模型不支持参数:needAudio` 拒绝;不传等价于不开音效 |
|
|
16
|
+
| `--model-param key=value` | 新增 / 未硬编码的模型配置参数 | key 必须来自 `model options.params[]`;可重复传。适合 `generation_effort=high` 这类通用 Enum / Boolean / Number / String 配置 |
|
|
17
|
+
| `--model-params-json` | 一次传多个通用模型配置参数 | JSON 对象或 JSON 文件路径;命令行专用参数如 `--ratio`、`--quality`、`--duration` 优先级更高 |
|
|
16
18
|
| `--resource` | 单个素材输入,可重复传 | `type:usage[:key]=path|url|asset:<id>` |
|
|
17
19
|
| `--resources-json` | 多素材输入,适合复杂 keyframe / 批量构造 | JSON 数组或 JSON 文件路径 |
|
|
18
20
|
| `--project-group-no` | 任务归属项目组 | 用户明确指定,或来自当前项目组 |
|
|
@@ -94,6 +96,7 @@ JSON 语法:
|
|
|
94
96
|
| `quality` | `--quality` | `promptParams.quality` | `quality` |
|
|
95
97
|
| `generate_num` | `--generate-num` | `promptParams.generate_num` | `generate_num` |
|
|
96
98
|
| `generated_time` | `--duration` | `promptParams.duration` | `generated_time` |
|
|
99
|
+
| 其他带 `cliArg` 的模型配置参数 | `--model-param <key>=...` / `--model-params-json` | `promptParams.<key>` | 同名透传 |
|
|
97
100
|
| `iref` | `--resource image:reference=...` | `promptParams.resources[]` | `iref` |
|
|
98
101
|
| `frames` | `--resource image:first_frame=...` | `promptParams.resources[]` | `frames` |
|
|
99
102
|
| `multi_param` | `--resource image/video/audio/subject:reference[:key]=...` | `promptParams.resources[]` | `multi_param` |
|
|
@@ -117,11 +120,11 @@ Agent 必须按顺序做:
|
|
|
117
120
|
5. 若本轮已读取 `model create-spec` 则直接复用;否则运行 `model create-spec --model-group-code <code> -f json`。
|
|
118
121
|
6. 先读 `inputRequirement`,确认是否必须提供视觉输入。
|
|
119
122
|
7. 用 `supportedIntents[]` 匹配用户意图;不要只看模型列表摘要就生成最终能力结论。
|
|
120
|
-
8. 参数枚举值只从 `model options.params[].values` 选择,素材限制只从 `model options.resources[]` 校验,参数 / 资源联动限制按 `model options.constraints[]`
|
|
123
|
+
8. 参数枚举值只从 `model options.params[].values` 选择,素材限制只从 `model options.resources[]` 校验,参数 / 资源联动限制按 `model options.constraints[]` 收窄。新增通用参数只要在 `params[]` 中出现且带 `cliArg`,就通过 `--model-param` / `--model-params-json` 显式传入。
|
|
121
124
|
9. 不主动列举所有缺失控制项;只追问会影响价格 / 效果的关键参数。视频包括 `quality`、`duration`、约束后仍可选的 `ratio`,以及用户明确要求输出音效时的 `needAudio`;图片包括 `quality`、`ratio`、`generateNum`。
|
|
122
125
|
10. 组装最终 prompt;如果可见文本发生变化,先展示给用户。
|
|
123
126
|
11. 若用户上传或指定音频文件,必须先确认 `model options.resources[]` 中存在 `mediaType=AUDIO usage=reference` 后再组织 `audio:reference` 资源;只有用户明确要求“输出是否带模型生成音效/音频”时,才检查 `model options.params[]` 是否存在 `needAudio`。
|
|
124
|
-
12. 用户未提供关键参数时,把 `model options.params[].values` 和 `defaultValue` 转成候选问题;用户选择或确认“按默认”前,不跑 `create image-fee` / `create video-fee`,也不跑 `create --dry-run
|
|
127
|
+
12. 用户未提供关键参数时,把 `model options.params[].values` 和 `defaultValue` 转成候选问题;用户选择或确认“按默认”前,不跑 `create image-fee` / `create video-fee`,也不跑 `create --dry-run`。即使模型给了 `defaultValue`,也不要静默写入请求。
|
|
125
128
|
13. 跑 `create image-fee` / `create video-fee` 获取预估积分——**只跑一次,参数取用户已确认的那组**。`fee` 是"用户敲定参数后的最终估价",不是参数探索 / 候选比较工具:不要为了对比价格档跑 `fee` × 多个 `quality` / `duration` / `ratio` 组合,也不要为了横向比同款不同渠道跑 `fee` × 多个 `modelGroupCode`;价格档差异从 `model options.feeCalcType` + 参数取值表里就能口算/展示给用户,比较应该发生在 `model options` 阶段。
|
|
126
129
|
14. 跑 `create --dry-run` 检查请求体和本地素材。
|
|
127
130
|
15. 用户确认模型、项目组、最终 prompt 文本、素材、关键参数和积分后,才追加 `--yes` 正式提交。
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
| `lj-awb create video ...` | 提交单条生视频任务 |
|
|
13
13
|
| `lj-awb create video-batch ...` | 批量提交生视频任务 |
|
|
14
14
|
| `lj-awb create video-fee ...` | 生视频估价;关键参数确认后只跑一次 |
|
|
15
|
+
| `lj-awb create video-super-resolution ...` | 基于 objectName 提交视频超分任务 |
|
|
16
|
+
| `lj-awb create video-super-resolution-fee ...` | 视频超分估价;先确认 objectName |
|
|
15
17
|
| `lj-awb create video-subtitle-removal --source-task-id <videoTaskId> ...` | 基于 material 来源视频任务提交去字幕 |
|
|
16
18
|
| `lj-awb create subject-list ...` | 查询可复用主体,避免重复发布 |
|
|
17
19
|
| `lj-awb create subject --model-code tx|vidu ...` | 创建可复用主体 element |
|
|
@@ -30,8 +32,8 @@
|
|
|
30
32
|
## 编排
|
|
31
33
|
|
|
32
34
|
- 图片 / 视频创建参数和资源绑定仍按 [`create-contract.md`](create-contract.md) 校验。
|
|
33
|
-
- 估价也在 `create` 域:`create image-fee` / `create video-fee`;只在关键参数确认后执行。
|
|
34
|
-
- 状态和等待仍在查询域:`task image-status` / `task video-status` / `task wait` / `create subject-wait` / `create subject-voice-wait` / `task video-subtitle-status`。
|
|
35
|
+
- 估价也在 `create` 域:`create image-fee` / `create video-fee` / `create video-super-resolution-fee`;只在关键参数确认后执行。
|
|
36
|
+
- 状态和等待仍在查询域:`task image-status` / `task video-status` / `task wait` / `create subject-wait` / `create subject-voice-wait` / `task video-subtitle-status` / `task video-super-resolution-status`。
|
|
35
37
|
- 所有 `create` 写入或扣费命令正式执行前必须先 `--dry-run`,用户确认后再 `--yes`。
|
|
36
38
|
- 查询型 create 子命令(`subject-list`、`subject-voice-list`、`asset-groups`、`asset-group-get`、`asset-match-actor`)是为了避免重复创建;创建前优先查重。
|
|
37
39
|
- `asset-groups` / `asset-group-get` / `asset-group` / `asset-group-update` / `asset` 都必须显式传 `--platform`;平台先由 `model asset-review-models` 或用户选择确定。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Credits Module
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
积分模块用于预算确认、项目用量统计,以及积分的购买(充值)与兑换码兑换。
|
|
4
4
|
|
|
5
5
|
## 命令
|
|
6
6
|
|
|
@@ -10,6 +10,23 @@
|
|
|
10
10
|
| `lj-awb credits balance --project-group-no <no>` | 查看可扣积分余额和指定项目组预算 |
|
|
11
11
|
| `lj-awb credits usage --project-group-no <no> --last-hours 24` | 汇总最近任务消耗 |
|
|
12
12
|
| `lj-awb credits usage --project-group-no <no> --task-types IMAGE_CREATE,VIDEO_GROUP --include-tasks` | 汇总并附带任务明细 |
|
|
13
|
+
| `lj-awb credits buy` | 引导购买 / 充值:输出充值页面链接,让用户在浏览器打开完成购买(链接已自动匹配当前环境,无需告知用户环境)|
|
|
14
|
+
| `lj-awb credits redeem` | 兑换码兑换:交互式等待用户输入兑换码,兑换成功后展示最新积分余额 |
|
|
15
|
+
| `lj-awb credits redeem --code <code>` | 直接用 `--code` 传入兑换码,跳过交互(脚本 / 非交互终端必须这样用)|
|
|
16
|
+
|
|
17
|
+
## 购买(充值)
|
|
18
|
+
|
|
19
|
+
- `credits buy` **只输出链接、不发起网络请求**,输出里只有一个 `purchaseUrl`,已自动匹配当前 CLI 所在环境。
|
|
20
|
+
- **直接把 `purchaseUrl` 给用户即可**:不要向用户提及 / 区分"预发""正式"环境,不要主动追问或提供"另一个环境的链接",也不要展示 API 地址等环境细节——对用户而言只有"充值链接"这一个概念。
|
|
21
|
+
- CLI 无法代用户完成支付,把链接交给用户在浏览器打开即可;不要承诺"已充值"。完成后可建议 `credits balance` 查看余额。
|
|
22
|
+
|
|
23
|
+
## 兑换码
|
|
24
|
+
|
|
25
|
+
- 不传 `--code` 时进入交互模式,最长等待约 **10 分钟**(可用 `--wait-seconds` 调)读取用户输入;输入会**自动去除空格 / 换行 / 制表符**,避免粘贴时带上多余字符。
|
|
26
|
+
- **非交互终端 / AI agent 不会挂起**:未提供 `--code` 时直接报 `argument_error`,必须用 `--code <兑换码>` 传入。
|
|
27
|
+
- 兑换是会改账户积分的远端写操作(`safeToAutoRun=false`):执行前向用户确认兑换码;支持 `--dry-run` 预览将要提交的兑换码。
|
|
28
|
+
- 平台接口 `code != 200` 即视为失败,CLI 抛 `redeem_failed`(保留平台原始 `msg`),提示用户确认兑换码或联系平台处理。
|
|
29
|
+
- 兑换成功后会顺带调用 `account info` 拉取并展示最新 `billingPointBalance`,无需再单独跑 `credits balance`。
|
|
13
30
|
|
|
14
31
|
## 规则
|
|
15
32
|
|
|
@@ -25,4 +42,4 @@
|
|
|
25
42
|
## 下一步
|
|
26
43
|
|
|
27
44
|
- 积分够 → 进 [`model.md`](model.md) 选模型,或直接 [`image.md`](image.md) / [`video.md`](video.md) 估价。
|
|
28
|
-
- 积分不够 →
|
|
45
|
+
- 积分不够 → 用 `credits buy` 给出充值链接,或 `credits redeem` 走兑换码;不要默认换更便宜模型,先问用户偏好。
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
- Skill 是驱动器,不是命令百科。先在本模块决定链路,只在需要时加载一个细节模块。
|
|
11
11
|
- 同一对话维护 AWB 状态账本;除非用户切换账号、团队、项目组、模型、素材、prompt 或关键参数,否则不要重复跑同样的查询。
|
|
12
12
|
- 写入 / 扣费命令遵循 schema safety:`supportsDryRun=true` 先 dry-run,`requiresConfirmation=true` 经用户确认后再 `--yes`。
|
|
13
|
+
- 如果 JSON 输出带 `meta._notice.update`,先继续完成当前业务链路,收尾时告知当前版本 / 最新版本并建议 `lj-awb update`;不要静默忽略更新提示。
|
|
13
14
|
- 旧根域 `image` / `video` / `asset` / `subject` 已移除,不要尝试旧入口,也不要给旧命令做兼容推理。
|
|
14
15
|
|
|
15
16
|
## 状态账本
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
| `--ratio` | 需要指定画幅时 | `model options.params[key=ratio].values` |
|
|
22
22
|
| `--quality` | 需要指定清晰度时 | `model options.params[key=quality].values` |
|
|
23
23
|
| `--generate-num` | 指定生成张数;模型暴露该控制项时属于价格关键参数 | `model options.params[key=generateNum].values` |
|
|
24
|
+
| `--model-param key=value` / `--model-params-json` | 新增通用模型配置参数,如 `generation_effort` | `model options.params[]` 中带 `cliArg` / `genericModelParam` 的参数 |
|
|
24
25
|
| `--resource image:reference=...` | 参考图生图 | `model create-spec.supportedIntents.mode=reference` 必须存在 |
|
|
25
26
|
| `--resources-json` | 多参考图或程序化构造 | 同 `--resource`,但用 JSON 数组表达 |
|
|
26
27
|
|
|
@@ -60,8 +61,9 @@ lj-awb create image \
|
|
|
60
61
|
- 参考图 source.value 取值优先级、"不要复用 myqcloud 完整 URL"、图片生图不使用 `reference_key` / `<<<key>>>` 等规则统一在 [`create-contract.md`](create-contract.md) §素材组织 + §Prompt 组装原则;多张参考图用资源顺序和自然语言指代映射(例如"图一中的白发女保持表情,在图二背景里坐秋千"),不要替用户编 key。
|
|
61
62
|
- `ratio` / `quality` / `generate-num` 不确定时,先查 `model options`,不要猜一个模型不支持的值。
|
|
62
63
|
- `fee` 和 `create --dry-run` 前必须确认缺失的 `ratio`、`quality`、`generate-num`;不要静默用默认值估价。用户说“按默认”后才继续。
|
|
64
|
+
- `generation_effort` 这类新增模型配置参数如果出现在 `model options.params[]`,先把可选值 / `defaultValue` 展示给用户;用户确认后用 `--model-param generation_effort=<value>` 或 `--model-params-json` 传入,不要等专用 CLI flag。
|
|
63
65
|
- 正式提交必须带 `--yes`;如果需要看请求体,先用 `--dry-run`。
|
|
64
|
-
- 批量 JSON/JSONL 每项只写 `prompt`、`ratio`、`quality`、`generate_num`、`resources`、`resource`、`customBizId
|
|
66
|
+
- 批量 JSON/JSONL 每项只写 `prompt`、`ratio`、`quality`、`generate_num`、`resources`、`resource`、`model_params`、`customBizId`,也可直接写模型配置下划线参数;模型组和项目组放命令行公共参数。
|
|
65
67
|
- **批量是 best-effort**:`create-batch` 子任务**单条失败不会回滚整批**,已成功项依然扣分并产生 taskId。提交后必读响应里每项的 `status` / `taskId` / `error`,给用户汇总"成功 N / 失败 M",对失败项单独 fix + 重跑(不要全批重跑)。
|
|
66
68
|
- **多镜头 / 多 prompt 时主动建议并行**:用户一次给出 ≥2 个同模型同参数的图片任务(典型场景:分镜、组图、多 prompt 候选)时,Agent 必须先告知"这批可以用 `create image-batch --concurrency N` 并行执行(n 个任务,预计耗时 / 单次估价 × n)",并询问用户是否要并行。用户同意 → 走 batch;用户希望逐条审稿 / 调 prompt → 继续单条 create。**不要默认一条一条串行还不告知**,这种沉默会浪费用户时间。
|
|
67
69
|
- 等待超时只代表本轮轮询结束,不能对用户说任务失败。
|