@lingjingai/lj-awb-cli-pre 0.3.16 → 0.3.17

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 CHANGED
@@ -22,12 +22,9 @@ CLI 本身只负责平台调用、参数校验、精简输出和安全确认;
22
22
  | 积分 | `credits` | 可扣积分余额、项目组预算、任务用量统计 |
23
23
  | 模型 | `model` | 生图 / 生视频模型发现、模型参数白名单 |
24
24
  | 上传 | `upload` | 本地图片 / 视频 / 音频上传为平台可访问素材 |
25
- | 图片 | `image` | 生图估价、提交、批量提交、状态查询 |
26
- | 视频 | `video` | 生视频估价、提交、批量提交、状态查询、去字幕 |
25
+ | 创建 | `create` | 生图、生视频、主体、音色、素材和去字幕提交 |
27
26
  | 任务 | `task` | 任务列表、等待、任务台账和台账轮询 |
28
- | 资产 | `asset` | 素材库匹配、素材组、素材注册 |
29
27
  | 最终产物 | `artifact` | Workbench 剧本、资产、视频最终产物 CRUD 与本地 JSON 导入 |
30
- | 主体 | `subject` | 可复用主体资产发布与查询 |
31
28
 
32
29
  ## 环境要求
33
30
 
@@ -114,7 +111,7 @@ lj-awb account info
114
111
  lj-awb doctor
115
112
  lj-awb doctor --verify
116
113
  lj-awb schema -f json
117
- lj-awb schema --domain video -f json
114
+ lj-awb schema --domain create -f json
118
115
  lj-awb auth status
119
116
  lj-awb auth verify
120
117
  lj-awb account info
@@ -148,8 +145,8 @@ Agent 不应该靠记忆猜命令参数。进入任务前推荐先读取机器
148
145
 
149
146
  ```bash
150
147
  lj-awb schema -f json
151
- lj-awb schema --domain image -f json
152
- lj-awb schema --domain video --command create -f json
148
+ lj-awb schema --domain create -f json
149
+ lj-awb schema --domain create --command video -f json
153
150
  ```
154
151
 
155
152
  正式创作前推荐做一次体检:
@@ -235,7 +232,7 @@ lj-awb create video \
235
232
  如果参考图会复用,推荐先发布主体资产:
236
233
 
237
234
  ```bash
238
- lj-awb create subject --name 女主 --primary-file ./actor.png --yes
235
+ lj-awb create subject --model-code tx --name 女主 --resource primary:./actor.png --yes
239
236
  lj-awb create subject-wait --element-id <elementId> --wait-seconds 300
240
237
  lj-awb create video \
241
238
  --model-group-code <modelGroupCode> \
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lingjingai/lj-awb-cli-pre",
3
- "version": "0.3.16",
3
+ "version": "0.3.17",
4
4
  "description": "Lingjing AWB CLI monorepo with shared core, standalone CLI, and agent skills (pre-release build pointing to https://animeworkbench-pre.lingjingai.cn)",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lingjingai/awb-cli-bin",
3
- "version": "0.3.16",
3
+ "version": "0.3.17",
4
4
  "description": "Standalone CLI for Lingjing AWB",
5
5
  "private": true,
6
6
  "license": "MIT",
@@ -13,6 +13,6 @@
13
13
  "README.md"
14
14
  ],
15
15
  "dependencies": {
16
- "@lingjingai/awb-core": "0.3.16"
16
+ "@lingjingai/awb-core": "0.3.17"
17
17
  }
18
18
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lingjingai/awb-core",
3
- "version": "0.3.16",
3
+ "version": "0.3.17",
4
4
  "description": "Shared core runtime for Lingjing AWB CLI",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -177,6 +177,10 @@ export async function fetchModelGroupInfoAll(modelGroupCode) {
177
177
  return await apiFetch(`/api/resource/model/info/group/${encodeURIComponent(modelGroupCode)}/all`, { method: 'GET' });
178
178
  }
179
179
 
180
+ export async function fetchAssetReviewModels() {
181
+ return await apiFetch('/api/material/creation/model/asset-review/list', { method: 'GET' });
182
+ }
183
+
180
184
  export async function fetchUploadSecret(payload = {}) {
181
185
  return await apiFetch('/api/anime/workbench/TencentCloud/getSecret', { body: payload });
182
186
  }
@@ -241,8 +245,11 @@ export async function listAssetGroups(payload = {}) {
241
245
  return await apiFetch('/api/material/asset-groups/list', { body: payload });
242
246
  }
243
247
 
244
- export async function getAssetGroup(groupId) {
245
- return await apiFetch(`/api/material/asset-groups/${encodeURIComponent(groupId)}`, { method: 'GET' });
248
+ export async function getAssetGroup(groupId, payload = {}) {
249
+ return await apiFetch(`/api/material/asset-groups/${encodeURIComponent(groupId)}`, {
250
+ method: 'GET',
251
+ query: payload,
252
+ });
246
253
  }
247
254
 
248
255
  export async function createAssetGroup(payload = {}) {
@@ -8,6 +8,7 @@ import {
8
8
  assetGroupList,
9
9
  assetGroupUpdate,
10
10
  assetMatchActor,
11
+ assetReviewModels,
11
12
  assetRegister,
12
13
  creditsBalance,
13
14
  creditsUsageSummary,
@@ -74,6 +75,7 @@ const PROJECT_ID_ARG = { name: 'project-id', valueName: 'projectId', description
74
75
  const PROJECT_GROUP_ARG = { name: 'project-group-no', valueName: 'no', description: '项目组编号;不传时读取当前项目组 / 环境变量 / 本地状态' };
75
76
  const CUSTOM_BIZ_ARG = { name: 'custom-biz-id', valueName: 'id', description: '外部追踪 ID;不传则请求不携带 customBizId' };
76
77
  const MODEL_GROUP_ARG = { name: 'model-group-code', valueName: 'code', description: '模型组编码;创建和参数查询只传这个字段' };
78
+ const ASSET_PLATFORM_ARG = { name: 'platform', valueName: 'platform', description: '素材加白平台,必须显式传 JIMENG 或 BYTEPLUS,不做别名推断' };
77
79
  const MODEL_LIST_ARGS = [
78
80
  { name: 'model', valueName: 'keyword', description: '按模型名、编码、供应商或输入方式过滤;不传时查询全部' },
79
81
  { name: 'limit', valueName: 'n', description: '默认文本最多展示 N 条,默认 8;JSON 输出始终返回全部匹配' },
@@ -399,6 +401,24 @@ export function registerAwbCommands(cli) {
399
401
  func: async (_ctx, kwargs) => listModels('video', kwargs),
400
402
  });
401
403
 
404
+ cli({
405
+ name: 'model asset-review-models',
406
+ description: commandHelp('查询支持素材加白的模型组与平台平铺关系', {
407
+ examples: [
408
+ 'lj-awb model asset-review-models',
409
+ 'lj-awb model asset-review-models --platform JIMENG',
410
+ 'lj-awb model asset-review-models --model-group-code <code>',
411
+ ],
412
+ hint: '该命令只负责发现 modelGroupCode 与 platform 的关系;资产组和素材创建仍通过 create asset-group / create asset 显式传 --platform。',
413
+ }),
414
+ args: [
415
+ MODEL_GROUP_ARG,
416
+ ASSET_PLATFORM_ARG,
417
+ INCLUDE_RAW_ARG,
418
+ ],
419
+ func: async (_ctx, kwargs) => assetReviewModels(kwargs),
420
+ });
421
+
402
422
  cli({
403
423
  name: 'model options',
404
424
  description: commandHelp('查询指定模型支持的 CLI 参数、枚举值、素材约束和条件约束', {
@@ -448,7 +468,8 @@ export function registerAwbCommands(cli) {
448
468
  description: commandHelp('上传本地图片 / 视频 / 音频到平台 COS,并返回 backendPath / URL', {
449
469
  examples: [
450
470
  'lj-awb upload files --files ./a.png,./b.mp4 --dry-run',
451
- 'lj-awb upload files --file ./ref.png --scene-type material-video-create',
471
+ 'lj-awb upload files --file ./ref.png',
472
+ 'lj-awb upload files --file ./first-frame.png --scene-type material-video-create',
452
473
  ],
453
474
  hint: '不会暴露 COS 临时密钥;skill 只使用返回的 backendPath / url。',
454
475
  }),
@@ -456,7 +477,7 @@ export function registerAwbCommands(cli) {
456
477
  { name: 'file', valueName: 'path', description: '单个文件路径' },
457
478
  { name: 'files', valueName: 'paths', description: '多个文件路径,逗号分隔' },
458
479
  { name: 'files-json', valueName: 'path|json', description: '文件数组 JSON 或 JSON 文件路径' },
459
- { name: 'scene-type', valueName: 'scene', description: '上传场景,默认 material-image-edit' },
480
+ { name: 'scene-type', valueName: 'scene', description: '上传场景;未传时图片默认 material-image-draw,音视频默认 material-video-create;图片用于视频 / 主体复用时显式传 material-video-create' },
460
481
  { name: 'project-no', valueName: 'no', description: '可选项目组编号;不传时读取当前项目组 / 环境变量 / 本地状态' },
461
482
  DRY_RUN_ARG,
462
483
  ],
@@ -726,10 +747,11 @@ export function registerAwbCommands(cli) {
726
747
  cli({
727
748
  name: 'create asset-groups',
728
749
  description: commandHelp('查询素材组', {
729
- examples: ['lj-awb create asset-groups --name "女主"'],
750
+ examples: ['lj-awb create asset-groups --platform JIMENG --name "女主"'],
730
751
  }),
731
752
  args: [
732
753
  { name: 'name', valueName: 'keyword', description: '素材组名称关键词' },
754
+ ASSET_PLATFORM_ARG,
733
755
  { name: 'group-ids', valueName: 'ids', description: '素材组 ID,逗号分隔' },
734
756
  { name: 'page-number', valueName: 'n', description: '页码' },
735
757
  { name: 'page-size', valueName: 'n', description: '每页数量' },
@@ -741,9 +763,12 @@ export function registerAwbCommands(cli) {
741
763
  cli({
742
764
  name: 'create asset-group-get',
743
765
  description: commandHelp('查看素材组详情', {
744
- examples: ['lj-awb create asset-group-get --group-id <id>'],
766
+ examples: ['lj-awb create asset-group-get --group-id <id> --platform JIMENG'],
745
767
  }),
746
- args: [{ name: 'group-id', valueName: 'id', description: '素材组 ID' }],
768
+ args: [
769
+ { name: 'group-id', valueName: 'id', description: '素材组 ID' },
770
+ ASSET_PLATFORM_ARG,
771
+ ],
747
772
  func: async (_ctx, kwargs) => assetGroupGet(kwargs),
748
773
  });
749
774
 
@@ -751,13 +776,14 @@ export function registerAwbCommands(cli) {
751
776
  name: 'create asset-group',
752
777
  description: commandHelp('创建素材组(用于素材注册时作为命名空间)', {
753
778
  examples: [
754
- 'lj-awb create asset-group --name "女主素材组" --dry-run',
755
- 'lj-awb create asset-group --name "女主素材组" --description "用于第二集女主相关素材" --yes',
779
+ 'lj-awb create asset-group --name "女主素材组" --platform JIMENG --dry-run',
780
+ 'lj-awb create asset-group --name "女主素材组" --platform JIMENG --description "用于第二集女主相关素材" --yes',
756
781
  ],
757
782
  }),
758
783
  args: [
759
784
  { name: 'name', valueName: 'name', description: '素材组名称' },
760
785
  { name: 'description', valueName: 'text', description: '素材组描述' },
786
+ ASSET_PLATFORM_ARG,
761
787
  { name: 'project-name', valueName: 'name', description: '项目名,默认 default' },
762
788
  DRY_RUN_ARG,
763
789
  YES_ARG,
@@ -768,12 +794,13 @@ export function registerAwbCommands(cli) {
768
794
  cli({
769
795
  name: 'create asset-group-update',
770
796
  description: commandHelp('更新素材组名称 / 描述', {
771
- examples: ['lj-awb create asset-group-update --group-id <id> --name "新名称" --dry-run'],
797
+ examples: ['lj-awb create asset-group-update --group-id <id> --platform JIMENG --name "新名称" --dry-run'],
772
798
  }),
773
799
  args: [
774
800
  { name: 'group-id', valueName: 'id', description: '素材组 ID' },
775
801
  { name: 'name', valueName: 'name', description: '新名称' },
776
802
  { name: 'description', valueName: 'text', description: '新描述' },
803
+ ASSET_PLATFORM_ARG,
777
804
  { name: 'project-name', valueName: 'name', description: '项目名' },
778
805
  DRY_RUN_ARG,
779
806
  YES_ARG,
@@ -784,7 +811,7 @@ export function registerAwbCommands(cli) {
784
811
  cli({
785
812
  name: 'create asset',
786
813
  description: commandHelp('把 COS 路径 / URL / 本地文件注册成平台素材', {
787
- examples: ['lj-awb create asset --group-id <id> --url "material/upload/a.png" --name "女主正面" --dry-run'],
814
+ examples: ['lj-awb create asset --group-id <id> --platform JIMENG --url "asset-review/upload/a.png" --name "女主正面" --dry-run'],
788
815
  }),
789
816
  args: [
790
817
  { name: 'group-id', valueName: 'id', description: '素材组 ID' },
@@ -792,7 +819,7 @@ export function registerAwbCommands(cli) {
792
819
  { name: 'file', valueName: 'path', description: '本地素材文件;会先上传' },
793
820
  { name: 'url', valueName: 'url', description: '素材 URL 或 COS 路径' },
794
821
  { name: 'backend-path', valueName: 'path', description: 'upload files 返回的 backendPath' },
795
- { name: 'platform', valueName: 'platform', description: '可选平台字段' },
822
+ ASSET_PLATFORM_ARG,
796
823
  DRY_RUN_ARG,
797
824
  YES_ARG,
798
825
  ],
@@ -1276,12 +1303,12 @@ export function registerAwbCommands(cli) {
1276
1303
  'lj-awb create subject --model-code tx --name 女主 --resource primary:./three-view.png --dry-run',
1277
1304
  'lj-awb create subject --model-code vidu --name 女主 --resource primary:material/assets/a.png --resource face:./face.png --yes',
1278
1305
  ],
1279
- hint: '参考图 slot:primary | three-view | face | side | back。主体 modelCode:KeLing / 可灵 tx,Vidu vidu。无 primary 时 three-view 自动升为主图;本地路径(./ 或绝对路径)会自动上传,含 :// 或 material/ 前缀的视为已上传 URL。',
1306
+ hint: '参考图 slot:primary | three-view | face | side | back。主体 modelCode 只接受 tx / vidu:KeLing / 可灵主体明确传 tx,Vidu 主体明确传 vidu。无 primary 时 three-view 自动升为主图;本地路径(./ 或绝对路径)会自动上传,含 :// 或 material/ 前缀的视为已上传 URL。',
1280
1307
  }),
1281
1308
  args: [
1282
1309
  { name: 'name', valueName: 'name', description: '主体名称' },
1283
1310
  { name: 'description', valueName: 'text', description: '主体描述' },
1284
- { name: 'model-code', valueName: 'code', description: '主体创建模型编码 tx / vidu;KeLing / 可灵用 tx,Vidu vidu' },
1311
+ { name: 'model-code', valueName: 'code', description: '主体创建模型编码,仅 tx / vidu;KeLing / 可灵传 tx,Vidu vidu' },
1285
1312
  { name: 'reference-type', valueName: 'type', description: '参考类型,默认 image_refer' },
1286
1313
  { name: 'voice-id', valueName: 'id', description: '参考音色 ID,可选' },
1287
1314
  { name: 'tags-json', valueName: 'json', description: '标签数组,例如 [{"tagId":"o_102"}]' },
@@ -1363,7 +1390,7 @@ export function registerAwbCommands(cli) {
1363
1390
  }),
1364
1391
  args: [
1365
1392
  { name: 'input-file', valueName: 'path', description: '批量输入文件' },
1366
- { name: 'model-code', valueName: 'code', description: '默认主体创建模型编码 tx / vidu;单条可覆盖' },
1393
+ { name: 'model-code', valueName: 'code', description: '默认主体创建模型编码,仅 tx / vidu;单条可覆盖' },
1367
1394
  { name: 'project-name', valueName: 'name', description: '默认项目名' },
1368
1395
  { name: 'concurrency', valueName: 'n', description: '并发数,默认 1' },
1369
1396
  DRY_RUN_ARG,
@@ -21,7 +21,8 @@ export const TASK_UPLOAD_SCENE = {
21
21
  VIDEO_CREATE: 'material-video-create',
22
22
  VIDEO_GROUP: 'material-video-create',
23
23
  SUBJECT: 'material-video-create',
24
- DEFAULT: 'material-image-edit',
24
+ ASSET_REVIEW: 'asset-review',
25
+ DEFAULT: 'material-image-draw',
25
26
  };
26
27
  export const TERMINAL_TASK_STATES = new Set([
27
28
  'SUCCESS',
@@ -160,9 +160,6 @@ function normalizeDryRun(data = {}) {
160
160
  localFiles,
161
161
  results: Array.isArray(data.results) ? data.results.map((row) => normalizeDryRunResult(row)) : data.results,
162
162
  nextRefSubject: data.nextRefSubject,
163
- resolvedModelCode: data.resolvedModelCode,
164
- resolvedFrom: data.resolvedFrom,
165
- resolvedFromValue: data.resolvedFromValue,
166
163
  });
167
164
  }
168
165
 
@@ -338,6 +335,7 @@ function normalizeAsset(data = {}) {
338
335
  registered: data.registered,
339
336
  groupId: data.groupId,
340
337
  assetId: data.assetId,
338
+ platform: data.platform,
341
339
  name: data.name,
342
340
  projectName: data.projectName,
343
341
  assetPath: data.assetPath,
@@ -536,6 +534,7 @@ export function normalizeOutputData(commandName, data) {
536
534
  return normalizeAsset(data);
537
535
  case 'model image-models':
538
536
  case 'model video-models':
537
+ case 'model asset-review-models':
539
538
  return normalizeList(data, ['models', 'items', 'rows']);
540
539
  case 'account teams':
541
540
  return normalizeList(data, ['teams']);
@@ -699,6 +698,7 @@ function rowSummary(row) {
699
698
  'remoteTaskId',
700
699
  'taskType',
701
700
  'modelGroupCode',
701
+ 'platform',
702
702
  'provider',
703
703
  'displayName',
704
704
  'modelDesc',
@@ -1117,10 +1117,8 @@ export function formatTextOutput(commandName, data, context = {}) {
1117
1117
  'taskType',
1118
1118
  'taskStatus',
1119
1119
  'modelCode',
1120
- 'resolvedModelCode',
1121
- 'resolvedFrom',
1122
- 'resolvedFromValue',
1123
1120
  'modelGroupCode',
1121
+ 'platform',
1124
1122
  'projectGroupNo',
1125
1123
  'projectId',
1126
1124
  'groupId',
@@ -58,6 +58,9 @@ const REMOTE_VOICE_MIME_TYPES = new Set([
58
58
  'video/mp4',
59
59
  ]);
60
60
  const REMOTE_VOICE_EXTENSIONS = new Set(['.mp3', '.wav', '.m4a', '.aac', '.ogg', '.mp4']);
61
+ const ASSET_PLATFORM_CODES = ['JIMENG', 'BYTEPLUS'];
62
+ const ASSET_PLATFORM_CODE_SET = new Set(ASSET_PLATFORM_CODES);
63
+ const ASSET_PLATFORM_HINT = ASSET_PLATFORM_CODES.join('|');
61
64
 
62
65
  export function normalizeUserInfo(payload) {
63
66
  const data = payload && typeof payload === 'object' ? payload : {};
@@ -732,6 +735,44 @@ export async function listModels(kind, kwargs = {}) {
732
735
  return { usage, models };
733
736
  }
734
737
 
738
+ function requireAssetPlatform(value, options = {}) {
739
+ const flag = options.flag || '--platform';
740
+ const platform = trimToNull(value);
741
+ if (!platform) {
742
+ throw argumentError(`缺少参数:${flag}`, `素材加白平台必须显式传入 ${ASSET_PLATFORM_HINT},不要依赖默认平台。`);
743
+ }
744
+ if (!ASSET_PLATFORM_CODE_SET.has(platform)) {
745
+ throw argumentError(`不支持的平台:${platform}`, `只接受 ${ASSET_PLATFORM_HINT};请使用 model asset-review-models 查看模型支持的平台。`);
746
+ }
747
+ return platform;
748
+ }
749
+
750
+ function optionalAssetPlatform(value) {
751
+ if (value == null || value === '') return null;
752
+ return requireAssetPlatform(value);
753
+ }
754
+
755
+ function normalizeAssetReviewModelRecord(item = {}) {
756
+ return compactRecord({
757
+ modelGroupCode: item?.modelGroupCode ?? item?.groupCode ?? null,
758
+ platform: item?.platform ?? null,
759
+ });
760
+ }
761
+
762
+ export async function assetReviewModels(kwargs = {}) {
763
+ const modelGroupCode = trimToNull(kwargs.modelGroupCode);
764
+ const platform = optionalAssetPlatform(kwargs.platform);
765
+ const payload = await awbApi.fetchAssetReviewModels();
766
+ const models = normalizeRows(payload)
767
+ .map((item) => normalizeAssetReviewModelRecord(item))
768
+ .filter((item) => !modelGroupCode || item.modelGroupCode === modelGroupCode)
769
+ .filter((item) => !platform || item.platform === platform);
770
+ return {
771
+ models,
772
+ ...(toBool(kwargs.includeRaw) ? { raw: payload } : {}),
773
+ };
774
+ }
775
+
735
776
  async function findModelGroup(modelGroupCode, options = {}) {
736
777
  const includeRaw = Boolean(options.includeRaw);
737
778
  const [imageResult, videoResult] = await Promise.allSettled([
@@ -2168,7 +2209,35 @@ async function readJsonMaybeFile(value, fallback) {
2168
2209
  return JSON.parse(fileText);
2169
2210
  }
2170
2211
 
2171
- async function collectFileSpecs(kwargs = {}, defaultSceneType = TASK_UPLOAD_SCENE.DEFAULT) {
2212
+ const AUDIO_VIDEO_EXTENSIONS = new Set([
2213
+ '.aac',
2214
+ '.aiff',
2215
+ '.avi',
2216
+ '.flac',
2217
+ '.m4a',
2218
+ '.m4v',
2219
+ '.mkv',
2220
+ '.mov',
2221
+ '.mp3',
2222
+ '.mp4',
2223
+ '.mpeg',
2224
+ '.mpg',
2225
+ '.oga',
2226
+ '.ogg',
2227
+ '.ogv',
2228
+ '.wav',
2229
+ '.webm',
2230
+ ]);
2231
+
2232
+ function defaultUploadSceneForFile(filePath, mimeType = '') {
2233
+ const normalizedMime = String(mimeType || '').toLowerCase();
2234
+ if (normalizedMime.startsWith('audio/') || normalizedMime.startsWith('video/')) return TASK_UPLOAD_SCENE.VIDEO_CREATE;
2235
+ const ext = path.extname(String(filePath || '')).toLowerCase();
2236
+ if (AUDIO_VIDEO_EXTENSIONS.has(ext)) return TASK_UPLOAD_SCENE.VIDEO_CREATE;
2237
+ return TASK_UPLOAD_SCENE.DEFAULT;
2238
+ }
2239
+
2240
+ async function collectFileSpecs(kwargs = {}, defaultSceneType = null) {
2172
2241
  const specs = [];
2173
2242
  for (const file of parseListArg(kwargs.file)) specs.push({ file });
2174
2243
  for (const file of parseListArg(kwargs.files)) specs.push({ file });
@@ -2181,11 +2250,14 @@ async function collectFileSpecs(kwargs = {}, defaultSceneType = TASK_UPLOAD_SCEN
2181
2250
  }
2182
2251
  }
2183
2252
  return specs
2184
- .map((item) => ({
2185
- file: trimToNull(item.file ?? item.path ?? item.filePath),
2186
- sceneType: trimToNull(item.sceneType ?? kwargs.sceneType) ?? defaultSceneType,
2187
- projectNo: trimToNull(item.projectNo ?? kwargs.projectNo) ?? '',
2188
- }))
2253
+ .map((item) => {
2254
+ const file = trimToNull(item.file ?? item.path ?? item.filePath);
2255
+ return {
2256
+ file,
2257
+ sceneType: trimToNull(item.sceneType ?? kwargs.sceneType) ?? defaultSceneType ?? defaultUploadSceneForFile(file),
2258
+ projectNo: trimToNull(item.projectNo ?? kwargs.projectNo) ?? '',
2259
+ };
2260
+ })
2189
2261
  .filter((item) => item.file);
2190
2262
  }
2191
2263
 
@@ -2194,7 +2266,7 @@ function dryRunBackendPath(filePath, sceneType) {
2194
2266
  }
2195
2267
 
2196
2268
  export async function uploadFilesCommand(kwargs = {}) {
2197
- const specs = await collectFileSpecs(kwargs, trimToNull(kwargs.sceneType) ?? TASK_UPLOAD_SCENE.DEFAULT);
2269
+ const specs = await collectFileSpecs(kwargs, trimToNull(kwargs.sceneType));
2198
2270
  if (!specs.length) throw argumentError('缺少上传文件', '传 --file <path> 或 --files a.png,b.mp4。');
2199
2271
  if (toBool(kwargs.dryRun)) {
2200
2272
  const files = [];
@@ -2224,7 +2296,7 @@ export async function uploadLocalFile(filePath, options = {}) {
2224
2296
  throw argumentError(`文件不存在:${filePath}`);
2225
2297
  }
2226
2298
  const buffer = await fs.readFile(inspected.filePath);
2227
- const sceneType = options.sceneType ?? TASK_UPLOAD_SCENE.DEFAULT;
2299
+ const sceneType = options.sceneType ?? defaultUploadSceneForFile(inspected.filePath, inspected.mimeType);
2228
2300
  const groupId = crypto.randomUUID().replaceAll('-', '');
2229
2301
  const secret = await awbApi.fetchUploadSecret({
2230
2302
  sceneType,
@@ -3433,6 +3505,7 @@ function normalizeAssetGroup(item = {}) {
3433
3505
  groupId: item?.id ?? item?.groupId ?? item?.assetGroupsId ?? null,
3434
3506
  name: item?.name ?? item?.groupName ?? null,
3435
3507
  description: item?.description ?? null,
3508
+ platform: item?.platform ?? null,
3436
3509
  projectName: item?.projectName ?? null,
3437
3510
  };
3438
3511
  }
@@ -3640,43 +3713,53 @@ export async function assetMatchActor(kwargs = {}) {
3640
3713
  }
3641
3714
 
3642
3715
  export async function assetGroupList(kwargs = {}) {
3716
+ const platform = requireAssetPlatform(kwargs.platform);
3643
3717
  const payload = await awbApi.listAssetGroups({
3644
3718
  name: kwargs.name ?? '',
3719
+ platform,
3645
3720
  pageNumber: toInt(kwargs.pageNumber, 1),
3646
3721
  pageSize: toInt(kwargs.pageSize, 20),
3647
3722
  ...(parseListArg(kwargs.groupIds).length ? { groupIds: parseListArg(kwargs.groupIds) } : {}),
3648
3723
  });
3649
- return { groups: extractAssetGroupRows(payload), raw: toBool(kwargs.includeRaw) ? payload : undefined };
3724
+ return { platform, groups: extractAssetGroupRows(payload), raw: toBool(kwargs.includeRaw) ? payload : undefined };
3650
3725
  }
3651
3726
 
3652
3727
  export async function assetGroupGet(kwargs = {}) {
3653
3728
  const groupId = requireValue(kwargs, 'groupId', 'group-id');
3654
- const payload = await awbApi.getAssetGroup(groupId);
3655
- return payload && typeof payload === 'object' && !Array.isArray(payload)
3656
- ? normalizeAssetGroup(payload)
3657
- : extractAssetGroupRows(payload)[0] ?? { groupId };
3729
+ const platform = requireAssetPlatform(kwargs.platform);
3730
+ const payload = await awbApi.getAssetGroup(groupId, { platform });
3731
+ if (payload && typeof payload === 'object' && !Array.isArray(payload)) {
3732
+ const group = normalizeAssetGroup(payload);
3733
+ return { ...group, platform: group.platform ?? platform };
3734
+ }
3735
+ return extractAssetGroupRows(payload)[0] ?? { groupId, platform };
3658
3736
  }
3659
3737
 
3660
3738
  export async function assetGroupCreate(kwargs = {}) {
3661
3739
  const name = requireValue(kwargs, 'name');
3740
+ const platform = requireAssetPlatform(kwargs.platform);
3662
3741
  const body = {
3663
3742
  name,
3664
3743
  description: kwargs.description ?? '',
3744
+ platform,
3665
3745
  projectName: kwargs.projectName ?? 'default',
3666
3746
  };
3667
3747
  if (toBool(kwargs.dryRun)) return { dryRun: true, action: 'create asset-group', request: body };
3668
3748
  ensureConfirmed(kwargs, '创建素材组是云端写入动作,需要确认', { action: 'create asset-group', body });
3669
3749
  const payload = await awbApi.createAssetGroup(body);
3670
- return { created: true, groupId: payload?.id ?? payload?.groupId ?? payload ?? null, name, projectName: body.projectName };
3750
+ return { created: true, groupId: payload?.id ?? payload?.groupId ?? payload ?? null, name, platform, projectName: body.projectName };
3671
3751
  }
3672
3752
 
3673
3753
  export async function assetGroupUpdate(kwargs = {}) {
3674
3754
  const groupId = requireValue(kwargs, 'groupId', 'group-id');
3675
- const body = {};
3755
+ const platform = requireAssetPlatform(kwargs.platform);
3756
+ const body = { platform };
3676
3757
  if (kwargs.name != null) body.name = kwargs.name;
3677
3758
  if (kwargs.description != null) body.description = kwargs.description;
3678
3759
  if (kwargs.projectName != null) body.projectName = kwargs.projectName;
3679
- if (!Object.keys(body).length) throw argumentError('缺少素材组更新字段', '至少传 --name、--description --project-name。');
3760
+ if (!['name', 'description', 'projectName'].some((key) => Object.prototype.hasOwnProperty.call(body, key))) {
3761
+ throw argumentError('缺少素材组更新字段', '至少传 --name、--description 或 --project-name;--platform 只用于定位平台资产组。');
3762
+ }
3680
3763
  if (toBool(kwargs.dryRun)) return { dryRun: true, action: 'create asset-group-update', groupId, request: body };
3681
3764
  ensureConfirmed(kwargs, '更新素材组是云端写入动作,需要确认', { action: 'create asset-group-update', groupId, body });
3682
3765
  await awbApi.updateAssetGroup(groupId, body);
@@ -3692,6 +3775,7 @@ function extractAssetId(payload) {
3692
3775
  export async function assetRegister(kwargs = {}) {
3693
3776
  const groupId = requireValue(kwargs, 'groupId', 'group-id');
3694
3777
  const name = requireValue(kwargs, 'name');
3778
+ const platform = requireAssetPlatform(kwargs.platform);
3695
3779
  const localFile = trimToNull(kwargs.file);
3696
3780
  const assetPath = trimToNull(kwargs.backendPath) ?? normalizeCosAssetPath(kwargs.url);
3697
3781
  if (!localFile && !assetPath) throw argumentError('缺少素材路径', '传 --file、--backend-path 或 --url。');
@@ -3701,20 +3785,20 @@ export async function assetRegister(kwargs = {}) {
3701
3785
  action: 'create asset',
3702
3786
  request: {
3703
3787
  assetGroupsId: groupId,
3704
- url: localFile ? normalizeCosAssetPath(dryRunBackendPath(localFile, TASK_UPLOAD_SCENE.SUBJECT)) : assetPath,
3788
+ url: localFile ? normalizeCosAssetPath(dryRunBackendPath(localFile, TASK_UPLOAD_SCENE.ASSET_REVIEW)) : assetPath,
3705
3789
  name,
3706
- ...(kwargs.platform ? { platform: kwargs.platform } : {}),
3790
+ platform,
3707
3791
  },
3708
3792
  localFile: localFile ? await inspectLocalFile(localFile) : null,
3709
3793
  };
3710
3794
  }
3711
3795
  ensureConfirmed(kwargs, '注册素材是云端写入动作,需要确认', { action: 'create asset', groupId, name });
3712
- const uploaded = localFile ? await uploadLocalFile(localFile, { sceneType: TASK_UPLOAD_SCENE.SUBJECT }) : null;
3796
+ const uploaded = localFile ? await uploadLocalFile(localFile, { sceneType: TASK_UPLOAD_SCENE.ASSET_REVIEW }) : null;
3713
3797
  const body = {
3714
3798
  assetGroupsId: groupId,
3715
3799
  url: normalizeCosAssetPath(uploaded?.backendPath ?? assetPath),
3716
3800
  name,
3717
- ...(kwargs.platform ? { platform: kwargs.platform } : {}),
3801
+ platform,
3718
3802
  };
3719
3803
  const payload = await awbApi.registerAsset(body);
3720
3804
  return {
@@ -3722,6 +3806,7 @@ export async function assetRegister(kwargs = {}) {
3722
3806
  assetId: extractAssetId(payload),
3723
3807
  groupId,
3724
3808
  name,
3809
+ platform,
3725
3810
  assetPath: body.url,
3726
3811
  ...(uploaded ? { upload: uploaded } : {}),
3727
3812
  };
@@ -4008,37 +4093,32 @@ function tagListFromArg(value) {
4008
4093
  .filter((item) => item.tagId);
4009
4094
  }
4010
4095
 
4011
- function normalizeSubjectCreateModelCode(value) {
4012
- const text = trimToNull(value);
4013
- if (!text) return null;
4014
- const normalized = text.toLowerCase();
4015
- if (normalized === 'tx' || normalized === 'vidu') return normalized;
4016
- return null;
4017
- }
4096
+ const SUBJECT_MODEL_CODE_HINT = '传 --model-code tx|vidu;KeLing / 可灵主体明确传 tx,Vidu 主体明确传 vidu。';
4018
4097
 
4019
4098
  function resolveSubjectCreateModelCode(kwargs = {}) {
4020
4099
  const explicitModelCode = trimToNull(kwargs.modelCode ?? kwargs.model_code);
4021
- const modelCode = normalizeSubjectCreateModelCode(explicitModelCode);
4022
- if (modelCode) return { modelCode };
4100
+ if (explicitModelCode === 'tx' || explicitModelCode === 'vidu') {
4101
+ return { modelCode: explicitModelCode };
4102
+ }
4023
4103
  if (explicitModelCode) {
4024
4104
  throw argumentError(
4025
4105
  `主体 modelCode 不支持:${explicitModelCode}`,
4026
- '只支持 --model-code tx|vidu;KeLing / 可灵用 tx,Vidu 用 vidu。',
4106
+ SUBJECT_MODEL_CODE_HINT,
4027
4107
  );
4028
4108
  }
4029
4109
 
4030
4110
  throw argumentError(
4031
4111
  '缺少主体 modelCode',
4032
- '传 --model-code tx|vidu;KeLing / 可灵用 tx,Vidu 用 vidu。',
4112
+ SUBJECT_MODEL_CODE_HINT,
4033
4113
  );
4034
4114
  }
4035
4115
 
4036
- function buildSubjectCreateBody(kwargs, specs, assets) {
4116
+ function buildSubjectCreateBody(kwargs, specs, assets, modelCodeResolution = resolveSubjectCreateModelCode(kwargs)) {
4037
4117
  const name = requireValue(kwargs, 'name');
4038
4118
  const description = trimToNull(kwargs.description ?? kwargs.elementDescription) ?? name;
4039
4119
  const primary = assets.find((item) => item.isPrimary);
4040
4120
  const referAssets = assets.filter((item) => item.assetPath);
4041
- const { modelCode } = resolveSubjectCreateModelCode(kwargs);
4121
+ const { modelCode } = modelCodeResolution;
4042
4122
  return compactRecord({
4043
4123
  reqTaskId: trimToNull(kwargs.reqTaskId),
4044
4124
  modelCode,
@@ -4117,10 +4197,7 @@ export async function subjectPublish(kwargs = {}) {
4117
4197
  dryRun: true,
4118
4198
  action: 'create subject',
4119
4199
  name,
4120
- resolvedModelCode: modelCodeResolution.modelCode,
4121
- resolvedFrom: modelCodeResolution.resolvedFrom,
4122
- resolvedFromValue: modelCodeResolution.resolvedFromValue,
4123
- request: buildSubjectCreateBody(kwargs, specs, assets),
4200
+ request: buildSubjectCreateBody(kwargs, specs, assets, modelCodeResolution),
4124
4201
  assets,
4125
4202
  localFiles: await inspectLocalFiles(specs.map((item) => item.file).filter(Boolean)),
4126
4203
  nextRefSubject: `${name}=<externalId>`,
@@ -4140,7 +4217,7 @@ export async function subjectPublish(kwargs = {}) {
4140
4217
  ...(uploaded ? { upload: uploaded } : {}),
4141
4218
  });
4142
4219
  }
4143
- const body = buildSubjectCreateBody(kwargs, specs, assets);
4220
+ const body = buildSubjectCreateBody(kwargs, specs, assets, modelCodeResolution);
4144
4221
  const payload = await awbApi.createElement(body);
4145
4222
  const elementId = extractCreatedElementId(payload);
4146
4223
  if (!elementId) throw new LingjingAwbCliError('主体创建完成但未拿到 elementId', { type: 'api_error', exitCode: 1, details: payload });
@@ -4229,14 +4306,14 @@ export async function subtitleRemove(kwargs = {}) {
4229
4306
  });
4230
4307
  await appendTaskRecord(kwargs, {
4231
4308
  taskId: result.taskId,
4232
- taskType: 'VIDEO_GROUP',
4309
+ taskType: 'VIDEO_SUBTITLE_REMOVAL',
4233
4310
  projectGroupNo: built.projectGroupNo,
4234
4311
  promptSummary: `去字幕 sourceTaskId=${built.sourceTaskId}`,
4235
4312
  });
4236
4313
  return {
4237
4314
  ...result,
4238
4315
  nextCommand: result.taskId
4239
- ? `lj-awb task wait --task-id ${result.taskId} --task-type VIDEO_GROUP${built.projectGroupNo ? ` --project-group-no ${built.projectGroupNo}` : ''} -f json`
4316
+ ? `lj-awb task video-subtitle-status --task-id ${result.taskId}${built.projectGroupNo ? ` --project-group-no ${built.projectGroupNo}` : ''} -f json`
4240
4317
  : null,
4241
4318
  };
4242
4319
  }
@@ -4270,6 +4347,6 @@ export async function subtitleStatus(kwargs = {}) {
4270
4347
  return taskStatus({
4271
4348
  ...kwargs,
4272
4349
  taskId,
4273
- taskType: 'VIDEO_GROUP',
4350
+ taskType: 'VIDEO_SUBTITLE_REMOVAL',
4274
4351
  });
4275
4352
  }
@@ -217,6 +217,33 @@ const VIRTUAL_COMMANDS = [
217
217
  ];
218
218
 
219
219
  const RENAMED_COMMAND_HINTS = {
220
+ image: 'create image',
221
+ 'image fee': 'create image-fee',
222
+ 'image create': 'create image',
223
+ 'image create-batch': 'create image-batch',
224
+ 'image status': 'task image-status',
225
+ video: 'create video',
226
+ 'video fee': 'create video-fee',
227
+ 'video create': 'create video',
228
+ 'video create-batch': 'create video-batch',
229
+ 'video status': 'task video-status',
230
+ 'video subtitle-remove': 'create video-subtitle-removal',
231
+ 'video subtitle-status': 'task video-subtitle-status',
232
+ asset: 'create asset',
233
+ 'asset match-actor': 'create asset-match-actor',
234
+ 'asset groups': 'create asset-groups',
235
+ 'asset group': 'create asset-group-get',
236
+ 'asset group-create': 'create asset-group',
237
+ 'asset group-update': 'create asset-group-update',
238
+ 'asset register': 'create asset',
239
+ subject: 'create subject',
240
+ 'subject list': 'create subject-list',
241
+ 'subject publish': 'create subject',
242
+ 'subject wait': 'create subject-wait',
243
+ 'subject publish-batch': 'create subject-batch',
244
+ 'subject voice list': 'create subject-voice-list',
245
+ 'subject voice create': 'create subject-voice',
246
+ 'subject voice wait': 'create subject-voice-wait',
220
247
  'workspace me': 'account info',
221
248
  'workspace teams': 'account teams',
222
249
  'workspace team-select': 'account switch-team',
@@ -367,6 +394,7 @@ const GROUP_EXAMPLES = {
367
394
  model: [
368
395
  'lj-awb model image-models --model Banana',
369
396
  'lj-awb model video-models --model Seedance',
397
+ 'lj-awb model asset-review-models --platform JIMENG',
370
398
  'lj-awb model input-guide',
371
399
  'lj-awb model options --model-group-code <code>',
372
400
  'lj-awb model create-spec --model-group-code <code>',
@@ -381,8 +409,8 @@ const GROUP_EXAMPLES = {
381
409
  'lj-awb create video-fee --model-group-code <code> --prompt "雨夜奔跑" --duration 5',
382
410
  'lj-awb create subject --model-code tx --name 女主 --resource primary:./three-view.png --dry-run',
383
411
  'lj-awb create subject-wait --element-id <elementId> --wait-seconds 300',
384
- 'lj-awb create asset --group-id <id> --file ./actor.png --name "女主正面" --dry-run',
385
- 'lj-awb create asset-groups --name "女主"',
412
+ 'lj-awb create asset --group-id <id> --platform JIMENG --file ./actor.png --name "女主正面" --dry-run',
413
+ 'lj-awb create asset-groups --platform JIMENG --name "女主"',
386
414
  ],
387
415
  task: [
388
416
  'lj-awb task list --task-type IMAGE_CREATE --project-group-no <no>',
@@ -417,10 +445,11 @@ const COMMAND_REQUIRED_OPTIONS = {
417
445
  'task video-subtitle-status': ['taskId'],
418
446
  'task wait': ['taskId', 'taskType'],
419
447
  'create asset-match-actor': ['description'],
420
- 'create asset-group-get': ['groupId'],
421
- 'create asset-group': ['name'],
422
- 'create asset-group-update': ['groupId'],
423
- 'create asset': ['groupId', 'name'],
448
+ 'create asset-groups': ['platform'],
449
+ 'create asset-group-get': ['groupId', 'platform'],
450
+ 'create asset-group': ['name', 'platform'],
451
+ 'create asset-group-update': ['groupId', 'platform'],
452
+ 'create asset': ['groupId', 'name', 'platform'],
424
453
  'artifact script row': ['rowKind', 'entityKey'],
425
454
  'artifact script children': ['parentKey'],
426
455
  'artifact script delete-row': ['rowKind', 'entityKey'],
@@ -595,6 +624,7 @@ const OUTPUT_KIND_BY_COMMAND = {
595
624
  'credits usage': 'credits_usage',
596
625
  'model image-models': 'model_list',
597
626
  'model video-models': 'model_list',
627
+ 'model asset-review-models': 'asset_review_model_list',
598
628
  'model options': 'model_options',
599
629
  'model create-spec': 'model_create_spec',
600
630
  'model input-guide': 'model_input_guide',
@@ -687,9 +717,9 @@ const PREFLIGHTS_BY_COMMAND = {
687
717
  'create subject': ['doctor --verify', 'create subject --model-code tx|vidu --dry-run'],
688
718
  'create subject-batch': ['doctor --verify', 'prepare JSONL input with modelCode', 'create subject-batch --dry-run'],
689
719
  'create video-subtitle-removal': ['doctor --verify', 'create video-subtitle-removal --source-task-id <videoTaskId> --dry-run'],
690
- 'create asset-group': ['create asset-group --dry-run'],
691
- 'create asset-group-update': ['create asset-group-update --dry-run'],
692
- 'create asset': ['create asset --dry-run'],
720
+ 'create asset-group': ['model asset-review-models', 'create asset-group --platform <platform> --dry-run'],
721
+ 'create asset-group-update': ['create asset-group-update --platform <platform> --dry-run'],
722
+ 'create asset': ['model asset-review-models', 'create asset --platform <platform> --dry-run'],
693
723
  'upload files': ['upload files --dry-run'],
694
724
  };
695
725
 
@@ -803,6 +833,7 @@ function buildAgentContract() {
803
833
  'schema version / domains / commands',
804
834
  'auth / account / team / current projectGroup',
805
835
  'modelCandidates by taskKind + keyword',
836
+ 'assetReviewModels by modelGroupCode / platform',
806
837
  'modelOptions / modelCreateSpec by modelGroupCode',
807
838
  'uploaded backendPath by local file path or remote URL',
808
839
  'taskId -> taskType / projectGroupNo / resultUrls / errorMessage',
@@ -817,6 +848,7 @@ function buildAgentContract() {
817
848
  'supportsDryRun=true 的写入 / 扣费命令先 dry-run,确认后 yes;不要把 dry-run 当参数探索工具反复跑。',
818
849
  '用户给出多条同模型同参数任务时优先 batch + task-record-file,不要单条循环 create。',
819
850
  '命令返回 nextCommand / nextRefSubject / nextVoiceArg 时优先复用返回值,不手拼等价命令。',
851
+ '素材加白平台先通过 model asset-review-models 或用户明确输入确定;create asset-* 必须显式传 --platform,不要依赖默认平台。',
820
852
  '旧根域 image / video / asset / subject 已移除;只使用 create / task / artifact 等 schema 暴露的 domain。',
821
853
  ],
822
854
  canonicalFields: {
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: lj-awb
3
- version: 0.3.16
3
+ version: 0.3.17
4
4
  description: "灵境 AWB CLI skill。使用 `lj-awb` 命令调用动漫平台 / AWB 云端能力,覆盖认证、项目组、积分、模型发现、上传、统一 create 创建域、任务查询、最终产物 artifact CRUD 与本地 JSON 导入。用户说生图、生视频、主体、音色、素材加白、去字幕、artifact 写入或查询时使用。正式生成、切换项目组、清空认证、artifact 写入等写入或扣费动作前必须确认。"
5
5
  metadata:
6
6
  requires:
@@ -1 +1 @@
1
- 0.3.16
1
+ 0.3.17
@@ -1,6 +1,6 @@
1
1
  {
2
- "skillVersion": "0.3.16",
3
- "minCliVersion": "0.3.16",
2
+ "skillVersion": "0.3.17",
3
+ "minCliVersion": "0.3.17",
4
4
  "preferredCommand": "lj-awb",
5
- "updatedAt": "2026-05-18"
5
+ "updatedAt": "2026-05-19"
6
6
  }
@@ -1,18 +1,19 @@
1
1
  # Asset Module
2
2
 
3
- 资产模块负责素材库的"分组管理 + 素材注册 + 候选匹配",**专为 Seedance / BytePlus / 即梦系列生视频前的"加白 / 过审"流程服务**。可灵 / KeLing 和 Vidu 系列用 [`subject.md`](subject.md) 的 `create subject`,不走 asset。
3
+ 资产模块负责素材库的"分组管理 + 素材注册 + 候选匹配",服务于生视频前需要平台素材加白 / 过审的流程。是否支持素材加白、支持哪个平台,以 `model asset-review-models` 返回为准;不要按模型名称硬编码推断。可灵 / KeLing 和 Vidu 的角色一致性通常走 [`subject.md`](subject.md) 的 `create subject`,不要把主体 `modelCode=tx|vidu` 和资产平台 `JIMENG|BYTEPLUS` 混用。
4
4
 
5
5
  ## 命令
6
6
 
7
7
  | 命令 | 用途 |
8
8
  |------|------|
9
- | `lj-awb create asset-groups --name "<keyword>"` | 查素材组(按名搜,避免重建已有的) |
10
- | `lj-awb create asset-group-get --group-id <id>` | 查素材组详情 + 成员 |
11
- | `lj-awb create asset-group --name "<name>" --dry-run` | 预览创建素材组 |
12
- | `lj-awb create asset-group --name "<name>" --yes` | 创建素材组(云端写入) |
13
- | `lj-awb create asset-group-update --group-id <id> --name "<name>" --yes` | 改素材组名 |
14
- | `lj-awb create asset --group-id <id> --url "material/assets/a.png" --name "女主正面" --yes` | 注册已上传素材 |
15
- | `lj-awb create asset --group-id <id> --file ./a.png --name "女主正面" --yes` | 先上传再注册(一步完成) |
9
+ | `lj-awb model asset-review-models --model-group-code <code>` | 查该模型是否支持素材加白及支持的平台 |
10
+ | `lj-awb create asset-groups --platform JIMENG --name "<keyword>"` | 按平台查素材组(按名搜,避免重建已有的) |
11
+ | `lj-awb create asset-group-get --group-id <id> --platform JIMENG` | 按平台查素材组详情 + 成员 |
12
+ | `lj-awb create asset-group --platform JIMENG --name "<name>" --dry-run` | 预览创建素材组 |
13
+ | `lj-awb create asset-group --platform JIMENG --name "<name>" --yes` | 创建素材组(云端写入) |
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` | 注册已上传素材 |
16
+ | `lj-awb create asset --group-id <id> --platform JIMENG --file ./a.png --name "女主正面" --yes` | 先上传到 asset-review 场景再注册(一步完成) |
16
17
  | `lj-awb create asset-match-actor --description "..." --tags-json '[{"tagId":"o_102"}]'` | 候选匹配(角色画风 / 标签) |
17
18
 
18
19
  ## 什么时候用 match-actor
@@ -22,32 +23,38 @@
22
23
  ## 完整加白流程
23
24
 
24
25
  ```bash
25
- # 1. 找/建分组
26
- lj-awb create asset-groups --name "项目X-角色"
27
- lj-awb create asset-group --name "项目X-角色" --yes
26
+ # 0. 确认模型是否支持素材加白,以及应使用哪个平台
27
+ lj-awb model asset-review-models --model-group-code <videoModelGroupCode>
28
+
29
+ # 1. 找/建分组;platform 必须来自上一步返回或用户明确指定
30
+ lj-awb create asset-groups --platform JIMENG --name "项目X-角色"
31
+ lj-awb create asset-group --platform JIMENG --name "项目X-角色" --yes
28
32
 
29
33
  # 2. 注册(本地文件版,自动上传)
30
- lj-awb create asset --group-id <id> --file ./hero.png --name "主角正面" --dry-run
31
- lj-awb create asset --group-id <id> --file ./hero.png --name "主角正面" --yes
34
+ lj-awb create asset --group-id <id> --platform JIMENG --file ./hero.png --name "主角正面" --dry-run
35
+ lj-awb create asset --group-id <id> --platform JIMENG --file ./hero.png --name "主角正面" --yes
32
36
 
33
37
  # 3. 等审核(create asset 返回 taskId 时)
34
38
  lj-awb task wait --task-id <id> --task-type ASSET_REGISTER --wait-seconds 180
35
39
 
36
40
  # 4. 终态后用于视频
37
- lj-awb create video --model-group-code <seedance-code> \
38
- --resource image:reference=material/assets/hero.png \
41
+ lj-awb create video --model-group-code <videoModelGroupCode> \
42
+ --resource image:reference:hero=asset:<assetId> \
39
43
  ...
40
44
  ```
41
45
 
42
46
  ## 规则
43
47
 
44
48
  - `create asset-group` / `create asset-group-update` / `create asset` 都是云端写入,**必须确认**后追加 `--yes`。
49
+ - `create asset-*` 平台必须显式传 `--platform JIMENG|BYTEPLUS`;不要依赖默认平台,不要传中文名、小写名或供应商别名。
50
+ - `model asset-review-models` 只做发现,不自动创建资产组或素材;不要把 `modelGroupCode` 塞进资产创建命令。
51
+ - 不使用 `/assets/submissions` 这类隐式自动补组流程;资产组是否复用、是否新建由当前任务显式决定。
45
52
  - 主体 element(视频里的"同一个人"概念)优先走 `create subject`,不要把素材组 / 素材 ID 当 subjectId 用——两者对应平台不同业务实体。
46
- - `create asset --file` 在 `--dry-run` 阶段不会真上传,只预览 backendPath 推断结果。
53
+ - `create asset --file` 在 `--dry-run` 阶段不会真上传,只预览 `asset-review/...` backendPath 推断结果。
47
54
  - 输出字段速查见 [`../references/output-fields.md`](../references/output-fields.md) 的"素材"小节。
48
55
 
49
56
  ## 下一步
50
57
 
51
- - 注册成功 → `assetPath`(形如 `material/assets/a.png`)作为 `--resource image:reference=<path>` 传给 `create video`。
52
- - 想看 group 里有哪些素材 → `create asset-group-get --group-id <id>`。
58
+ - 注册成功 → 优先按模型 create-spec / options 要求使用返回的 `assetId` `assetPath`;需要 asset_id 时写 `--resource image:reference:<key>=asset:<assetId>`。
59
+ - 想看 group 里有哪些素材 → `create asset-group-get --group-id <id> --platform <platform>`。
53
60
  - 长期复用同一角色(可灵)→ 改走 [`subject.md`](subject.md)。
@@ -34,3 +34,4 @@
34
34
  - 状态和等待仍在查询域:`task image-status` / `task video-status` / `task wait` / `create subject-wait` / `create subject-voice-wait` / `task video-subtitle-status`。
35
35
  - 所有 `create` 写入或扣费命令正式执行前必须先 `--dry-run`,用户确认后再 `--yes`。
36
36
  - 查询型 create 子命令(`subject-list`、`subject-voice-list`、`asset-groups`、`asset-group-get`、`asset-match-actor`)是为了避免重复创建;创建前优先查重。
37
+ - `asset-groups` / `asset-group-get` / `asset-group` / `asset-group-update` / `asset` 都必须显式传 `--platform`;平台先由 `model asset-review-models` 或用户选择确定。
@@ -20,6 +20,7 @@ Agent 在当前任务中记录这些值,后续直接复用:
20
20
  | `auth/account/team` | `doctor --verify`、`account info` | 登录 / 团队切换 |
21
21
  | `projectGroupNo` | `project current` 或用户指定 | 项目组切换 |
22
22
  | `modelCandidates` | `model image-models` / `model video-models` | 任务类型或关键词变化 |
23
+ | `assetReviewModels` / `assetReviewPlatform` | `model asset-review-models` | `modelGroupCode` 或平台切换 |
23
24
  | `modelOptions` / `createSpec` | `model options` / `model create-spec` | `modelGroupCode` 变化 |
24
25
  | `backendPath` | `upload files` 或 create dry-run/yes 的 upload 输出 | 本地文件或远端 URL 变化 |
25
26
  | `task` | create 返回的 `taskId` / `nextCommand` / wait 结果 | 任务终态后只追加结果 |
@@ -73,8 +74,9 @@ CLI 当前能力分为:
73
74
 
74
75
  ### 素材库与加白
75
76
 
76
- - Seedance / BytePlus / 即梦等素材预审走 `create asset-*`;KeLing / Vidu 角色一致性走主体,不走 asset。
77
- - 创建素材组前先 `create asset-groups --name` 查重;有可用组就复用。
77
+ - 素材预审是否可用先查 `model asset-review-models --model-group-code <code>`;不要按模型名硬编码判断,也不要把 `modelGroupCode` 传入资产创建命令。
78
+ - `create asset-*` 必须显式传 `--platform JIMENG|BYTEPLUS`,平台来自 `model asset-review-models` 或用户明确选择;不要依赖 material 默认平台。
79
+ - 创建素材组前先 `create asset-groups --platform <platform> --name` 查重;有可用组就复用。
78
80
  - `create asset --file` 会在正式阶段自动上传并注册;同一文件多任务复用时,先 `upload files` 缓存 `backendPath`。
79
81
  - 注册成功后优先使用 `assetPath`,不要重新上传同一文件。
80
82
 
@@ -103,4 +105,5 @@ CLI 当前能力分为:
103
105
  - 不要把 `--need-audio` 当音频输入;音频输入只能是 `audio:reference`。
104
106
  - 不要把主体 `elementId` 当 `externalId`。
105
107
  - 不要用单条 create 循环处理明显批量任务。
108
+ - 不要调用 `/assets/submissions` 或其它自动补齐资产组的隐式接口;素材组和素材注册必须通过 CLI 显式步骤完成。
106
109
  - 不要直连 material / asset / 外部服务;统一走 `lj-awb`。
@@ -8,6 +8,7 @@
8
8
  |------|------|
9
9
  | `lj-awb model image-models --model "<keyword>"` | 查询生图候选模型 |
10
10
  | `lj-awb model video-models --model "<keyword>"` | 查询生视频候选模型 |
11
+ | `lj-awb model asset-review-models --model-group-code <code>` | 查询支持素材加白的模型组与平台关系 |
11
12
  | `lj-awb model input-guide -f json` | 查看统一创建参数、resources 字段和素材绑定规则 |
12
13
  | `lj-awb model options --model-group-code <code> -f json` | 查看该模型支持的 CLI 参数、枚举值、默认值、素材约束和条件约束 |
13
14
  | `lj-awb model create-spec --model-group-code <code> -f json` | 查看该模型如何创建任务:输入模式、素材绑定规则、示例和前置步骤 |
@@ -80,6 +81,7 @@ Agent 读取这些字段:
80
81
  - `model options` 是参数和素材约束入口;`model create-spec` 是创建方式入口。判断用户需求能否满足,优先看 `create-spec.supportedIntents[]`;素材格式 / 数量 / 时长限制看 `options.resources[]`;参数 / 资源联动看 `options.constraints[]`(`effect=no_selectable_values` 表示触发后该目标参数没有可选枚举,不要追问或传入)。
81
82
  - `supportLastFrameOnly` 只表示模型是否支持「仅尾帧」输入;首尾帧过渡能力看 frames 资源的 `usage` 是否包含 `last_frame` 和数量约束。
82
83
  - 用户说「上传音频 / 使用音乐 / 配音 / 音频参考」是**素材输入**,先看 `options.resources[]` 有没有 `mediaType=AUDIO usage=reference`;**不要先去找 `needAudio`**(那是输出音效开关)。具体使用规则、`reference_key` / `<<<key>>>` 对齐和 `--need-audio` 不是音频入口等都见 [`create-contract.md`](create-contract.md) §素材组织 + §Prompt 组装原则。
84
+ - 用户要走素材加白 / 素材库过审时,先跑 `model asset-review-models --model-group-code <code>` 判断该模型是否支持以及平台值;不要根据模型名称猜平台,也不要把 `modelGroupCode` 放进资产组或素材创建命令。
83
85
  - 关键参数选择、`fee` / `create --dry-run` 前的追问流程、`inputRequirement.visualInputRequired` 检查等创建前校验见 [`create-contract.md`](create-contract.md) §创建前校验。
84
86
  - 输出字段速查见 [`../references/output-fields.md`](../references/output-fields.md) 的"模型"小节。
85
87
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  主体模块用于创建 / 查询平台主体 element。视频主体参考应使用主体的 `externalId`,通过 `--resource subject:reference:<key>=asset:<externalId>` 传给视频创建命令。
4
4
 
5
- > **发布主体前必须传 `--model-code <tx|vidu>`**:KeLing / Kling / 可灵 → `tx`,Vidu `vidu`。不传 → CLI `argument_error: 缺少主体 modelCode`;放过去后端 `ElementCreateHandler` 也会按 `modelCode` 路由请求体(Vidu / KeLing 字段集不一样),空值在两端都会失败。如果用户没说目标平台,先追问"这个主体将来主要用在 KeLing / 可灵 还是 Vidu?"
5
+ > **发布主体前必须传 `--model-code <tx|vidu>`**:KeLing / 可灵主体明确传 `tx`,Vidu 主体明确传 `vidu`。CLI 不接受 `keling`、`可灵`、`tencent`、`vidu-q` 等别名;不传或传错都会报 `argument_error`。如果用户没说目标平台,先追问"这个主体将来主要用在 KeLing / 可灵 还是 Vidu?"
6
6
 
7
7
  ## 命令
8
8
 
@@ -13,8 +13,8 @@
13
13
  | `lj-awb create subject-voice --name 女主音色 --file ./voice.mp3 --yes` | 创建主体音色并返回 voiceRecordId |
14
14
  | `lj-awb create subject-voice-wait --voice-record-id <voiceRecordId> --wait-seconds 300` | 等待音色 externalId 回填 |
15
15
  | `lj-awb create subject-voice-list --name "女主"` | 查询已创建音色 |
16
- | `lj-awb create subject --model-code tx --name 女主 --resource primary:./three-view.png --dry-run` | 预览 KeLing 主体创建,request.modelCode 自动为 `tx` |
17
- | `lj-awb create subject --model-code vidu --name 女主 --resource primary:./three-view.png --dry-run` | 预览 Vidu 主体创建,request.modelCode 自动为 `vidu` |
16
+ | `lj-awb create subject --model-code tx --name 女主 --resource primary:./three-view.png --dry-run` | 预览 KeLing 主体创建,request.modelCode `tx` |
17
+ | `lj-awb create subject --model-code vidu --name 女主 --resource primary:./three-view.png --dry-run` | 预览 Vidu 主体创建,request.modelCode `vidu` |
18
18
  | `lj-awb create subject --model-code tx --name 女主 --resource primary:./three-view.png --yes` | 创建主体并返回 elementId |
19
19
  | `lj-awb create subject-wait --element-id <elementId> --wait-seconds 300` | 等待 externalId 回填 |
20
20
  | `lj-awb create subject --model-code vidu --name 女主 --resource primary:material/assets/a.png --yes` | 用已上传素材创建主体 |
@@ -24,7 +24,7 @@
24
24
  ## 规则
25
25
 
26
26
  - 发布前确认主体名称、主参考图、可选正脸 / 侧面 / 背面图、项目名。
27
- - 必须传 `--model-code tx|vidu`:KeLing / Kling / 可灵 → `tx`,Vidu `vidu`。
27
+ - 必须传 `--model-code tx|vidu`:KeLing / 可灵用 `tx`,Vidu `vidu`。不要传平台名别名。
28
28
  - 如主体需要参考音色,先用 `create subject-voice --file <audio>` 创建音色,再 `create subject-voice-wait` 拿到 `externalId`,最后把它作为 `create subject --voice-id <externalId>`。
29
29
  - `create subject-voice` 的音色来源三选一:`--file` 本地音频、`--voice-url` / `--audio-url` 已上传 material 音频路径、`--video-id` 已有视频 ID。
30
30
  - 参考图统一通过 `--resource <slot>:<file|url>` 传入,slot ∈ `primary | three-view | face | side | back`。无 `primary` 时 `three-view` 自动升为主图;本地路径(`./` 或绝对路径)会自动上传,含 `://` 或 `material/` 前缀的视为已上传 URL。
@@ -172,7 +172,7 @@ lj-awb create video \
172
172
  判断要点:
173
173
 
174
174
  - `create subject-wait` 成功后优先使用返回的 `nextRefSubject`。
175
- - `--model-code` 只接受 `tx|vidu`;KeLing / 可灵用 `tx`,Vidu 用 `vidu`。它不是视频模型的 `modelGroupCode`。
175
+ - `--model-code` 只接受 `tx|vidu`;KeLing / 可灵用 `tx`,Vidu 用 `vidu`。
176
176
  - `subject:reference:<key>=asset:<subjectId>` 必须放主体 ID;普通图片素材资产 ID 只能用于 `image:reference=asset:<assetId>` 等素材引用。
177
177
  - prompt 中出现 `<<<key>>>` 时必须有同名 reference 资源;不出现时不强制补。
178
178
 
@@ -7,7 +7,8 @@
7
7
  | 命令 | 用途 |
8
8
  |------|------|
9
9
  | `lj-awb upload files --files ./a.png,./b.mp4 --dry-run` | 预览上传文件 |
10
- | `lj-awb upload files --file ./ref.png --scene-type material-video-create` | 上传单个参考素材 |
10
+ | `lj-awb upload files --file ./ref.png` | 上传图片创建参考素材,默认 `material-image-draw` |
11
+ | `lj-awb upload files --file ./first.png --scene-type material-video-create` | 上传生视频 / 主体复用素材 |
11
12
  | `lj-awb upload files --files-json ./files.json` | 按 JSON 清单上传 |
12
13
 
13
14
  ## 规则
@@ -16,17 +17,18 @@
16
17
  - 后续任务的 `source.value` 一律使用 `backendPath`(例如 `material/...` 或 `/material/...`),**不要使用回显的 `url` 字段**。`url` 只是用于人工预览,把完整 `https://*.myqcloud.com/...` 直接塞回任务请求会让请求体冗余,也会破坏请求一致性。
17
18
  - 对 Agent 来说,优先使用返回的结构化字段,不要从自然语言输出里猜 URL。
18
19
  - 生图 / 生视频命令传本地参考文件时,会在内部自动上传;只有需要复用素材时才单独调用 `upload files`。
20
+ - 单独预上传时按下游任务选择 scene:未传 `--scene-type` 时,图片默认 `material-image-draw`,音频 / 视频默认 `material-video-create`;图片若要作为生视频首帧 / 尾帧 / 参考图或主体图复用,必须显式传 `--scene-type material-video-create`;只有明确走图片编辑入口时才传 `material-image-edit`。
19
21
  - 即使把平台 COS 完整 URL 当作 `source.value` 传入,CLI 会自动剥离 host 还原为 `backendPath`;但不要依赖该自愈,仍以传 `backendPath` 为准。
20
22
  - 输出字段速查见 [`../references/output-fields.md`](../references/output-fields.md) 的"文件上传"小节;上传失败(exit 30 / `upload_failed`)见 [`../references/error-codes.md`](../references/error-codes.md) 场景 6。
21
23
 
22
24
  ## 下一步
23
25
 
24
- 拿到 `uploads[].backendPath`(形如 `material/...`)后立刻就近喂给下游命令,不要重复 upload:
26
+ 拿到 `files[].backendPath`(形如 `material/...`)后立刻就近喂给下游命令,不要重复 upload:
25
27
 
26
28
  - 生图参考图:`lj-awb create image ... --resource image:reference=material/...`
27
29
  - 生视频首帧 / 尾帧 / 参考图:`lj-awb create video ... --resource image:first_frame=material/...`
28
30
  - 视频参考音频:`lj-awb create video ... --resource audio:reference=material/...`
29
31
  - 主体发布参考图:`lj-awb create subject ... --resource primary:material/...`
30
- - 注册到素材库(长期复用):`lj-awb create asset --group-id <id> --url material/... --name "..." --yes`
32
+ - 注册到素材库(素材加白):优先让 `lj-awb create asset --group-id <id> --platform <platform> --file ./a.png --name "..." --yes` 自动上传到 `asset-review` 场景;若已单独上传,使用 `--backend-path asset-review/...` 或 `--url asset-review/...`。
31
33
 
32
34
  > `create image` / `create video` / `create subject` 传 `--file` / 本地路径时**会自动 upload**——只有需要"先看 backendPath / 跨任务复用同一份素材"时才单独跑 `upload files`。
@@ -12,7 +12,7 @@
12
12
  - [批量任务](#批量任务) — `create-batch --concurrency`
13
13
  - [分镜流水线(分镜图 → 视频)](#分镜流水线分镜图--视频) — GPT Image 2 分镜 → 视频生成
14
14
  - [预上传后批量复用](#预上传后批量复用) — `upload files` 一次,多任务复用 `backendPath`
15
- - [素材库加白后生视频](#素材库加白后生视频) — Seedance / 即梦的 `create asset` → 视频
15
+ - [素材库加白后生视频](#素材库加白后生视频) — `model asset-review-models` `create asset` → 视频
16
16
  - [Artifact 流水线错误恢复](#artifact-流水线错误恢复) — `import-storyboard` / 批量写入失败的局部重试
17
17
 
18
18
  ## 通用启动流程
@@ -140,8 +140,8 @@ lj-awb task record-poll \
140
140
  1. 准备 `image.jsonl`,每行一个镜头的 `prompt` 和共用参考图(人物、场景):
141
141
 
142
142
  ```json
143
- {"prompt":"镜头1:徐然推开 502 户门,门缝透出暖光...","ratio":"9:16","quality":"2k","resources":[{"type":"image","usage":"reference","source":{"kind":"url","value":"material/image-edit/<人物参考>"}},{"type":"image","usage":"reference","source":{"kind":"url","value":"material/image-edit/<场景参考>"}}]}
144
- {"prompt":"镜头2:徐然侧身贴墙,听门外脚步声...","ratio":"9:16","quality":"2k","resources":[{"type":"image","usage":"reference","source":{"kind":"url","value":"material/image-edit/<人物参考>"}}]}
143
+ {"prompt":"镜头1:徐然推开 502 户门,门缝透出暖光...","ratio":"9:16","quality":"2k","resources":[{"type":"image","usage":"reference","source":{"kind":"url","value":"material/image-draw/<人物参考>"}},{"type":"image","usage":"reference","source":{"kind":"url","value":"material/image-draw/<场景参考>"}}]}
144
+ {"prompt":"镜头2:徐然侧身贴墙,听门外脚步声...","ratio":"9:16","quality":"2k","resources":[{"type":"image","usage":"reference","source":{"kind":"url","value":"material/image-draw/<人物参考>"}}]}
145
145
  ```
146
146
 
147
147
  2. 批量生分镜图(GPT Image 2 通道,并行 4):
@@ -167,8 +167,8 @@ lj-awb task record-poll \
167
167
  4. 把每条 `taskId` 的 `result` 图(COS 对象路径,**用 `backendPath` 形式**)作为视频任务的 `first_frame`,组装 `video.jsonl`:
168
168
 
169
169
  ```json
170
- {"prompt":"镜头1 动起来:徐然缓慢推门,光线从门缝渐扩","duration":5,"ratio":"9:16","quality":"720","resources":[{"type":"image","usage":"first_frame","source":{"kind":"url","value":"material/image-edit/<镜头1结果>"}}]}
171
- {"prompt":"镜头2 动起来:徐然贴墙呼吸起伏,听门外动静","duration":5,"ratio":"9:16","quality":"720","resources":[{"type":"image","usage":"first_frame","source":{"kind":"url","value":"material/image-edit/<镜头2结果>"}}]}
170
+ {"prompt":"镜头1 动起来:徐然缓慢推门,光线从门缝渐扩","duration":5,"ratio":"9:16","quality":"720","resources":[{"type":"image","usage":"first_frame","source":{"kind":"url","value":"material/image-draw/<镜头1结果>"}}]}
171
+ {"prompt":"镜头2 动起来:徐然贴墙呼吸起伏,听门外动静","duration":5,"ratio":"9:16","quality":"720","resources":[{"type":"image","usage":"first_frame","source":{"kind":"url","value":"material/image-draw/<镜头2结果>"}}]}
172
172
  ```
173
173
 
174
174
  5. 批量生视频(视频模型通道,并行 3):
@@ -197,11 +197,10 @@ lj-awb task record-poll \
197
197
  ```bash
198
198
  lj-awb upload files \
199
199
  --files ./hero.png,./scene.png \
200
- --scene-type material-video-create \
201
200
  -f json
202
201
  ```
203
202
 
204
- 读取响应 `data.uploads[].backendPath`(形如 `material/...`),把这个值(**不是 `url` 字段**)写入下游:
203
+ 读取响应 `data.files[].backendPath`(形如 `material/...`),把这个值(**不是 `url` 字段**)写入下游。上面是图片创建参考图,默认 scene 是 `material-image-draw`;如果预上传后要作为视频首帧 / 尾帧 / 参考图或主体素材复用,命令必须显式加 `--scene-type material-video-create`。
205
204
 
206
205
  ```bash
207
206
  lj-awb create video-batch \
@@ -228,23 +227,28 @@ lj-awb create video-batch \
228
227
 
229
228
  ## 素材库加白后生视频
230
229
 
231
- 适用:Seedance / BytePlus / 即梦系列视频模型,要求参考图先在素材库登记并完成"加白"才能用于生视频。可灵 / KeLing 和 Vidu 系列可走 [主体参考生成视频](#主体参考生成视频),不走 asset。
230
+ 适用:`model asset-review-models` 返回支持素材加白的平台模型。不要按 Seedance / BytePlus / 即梦等名称硬编码判断;可灵 / KeLing 和 Vidu 的角色一致性通常走 [主体参考生成视频](#主体参考生成视频),不走 asset。
232
231
 
233
232
  ```bash
234
- # 1. 找/建分组
235
- lj-awb create asset-groups --name "项目X-角色"
236
- lj-awb create asset-group --name "项目X-角色" --dry-run
237
- lj-awb create asset-group --name "项目X-角色" --yes
233
+ # 0. 先确认该视频模型支持哪个素材加白平台
234
+ lj-awb model asset-review-models --model-group-code <videoModelGroupCode>
235
+
236
+ # 1. 找/建分组;platform 必须来自上一步返回或用户明确指定
237
+ lj-awb create asset-groups --platform JIMENG --name "项目X-角色"
238
+ lj-awb create asset-group --platform JIMENG --name "项目X-角色" --dry-run
239
+ lj-awb create asset-group --platform JIMENG --name "项目X-角色" --yes
238
240
 
239
241
  # 2. 注册参考图(本地文件版,--file 在 --yes 阶段自动上传 + 注册一步完成)
240
242
  lj-awb create asset \
241
243
  --group-id <groupId> \
244
+ --platform JIMENG \
242
245
  --file ./hero.png \
243
246
  --name "主角正面" \
244
247
  --dry-run
245
248
 
246
249
  lj-awb create asset \
247
250
  --group-id <groupId> \
251
+ --platform JIMENG \
248
252
  --file ./hero.png \
249
253
  --name "主角正面" \
250
254
  --yes
@@ -255,24 +259,24 @@ lj-awb task wait \
255
259
  --task-type ASSET_REGISTER \
256
260
  --wait-seconds 180
257
261
 
258
- # 4. 加白成功后拿到的 assetPath 用于视频创建
262
+ # 4. 加白成功后按模型资源要求使用 assetId 或 assetPath 创建视频
259
263
  lj-awb create video-fee \
260
- --model-group-code <seedance-code> \
264
+ --model-group-code <videoModelGroupCode> \
261
265
  --prompt "<...>" \
262
- --resource image:reference=material/assets/hero.png \
266
+ --resource image:reference:hero=asset:<assetId> \
263
267
  --project-group-no <projectGroupNo>
264
268
 
265
269
  lj-awb create video \
266
- --model-group-code <seedance-code> \
270
+ --model-group-code <videoModelGroupCode> \
267
271
  --prompt "<...>" \
268
- --resource image:reference=material/assets/hero.png \
272
+ --resource image:reference:hero=asset:<assetId> \
269
273
  --project-group-no <projectGroupNo> \
270
274
  --dry-run
271
275
 
272
276
  lj-awb create video \
273
- --model-group-code <seedance-code> \
277
+ --model-group-code <videoModelGroupCode> \
274
278
  --prompt "<...>" \
275
- --resource image:reference=material/assets/hero.png \
279
+ --resource image:reference:hero=asset:<assetId> \
276
280
  --project-group-no <projectGroupNo> \
277
281
  --yes
278
282
  ```
@@ -281,8 +285,9 @@ lj-awb create video \
281
285
 
282
286
  - 用户描述"我有这样一个角色,平台上有没有现成的"时,先跑 `create asset-match-actor --description ... --tags-json '...'`,命中合适候选就跳过 register。
283
287
  - 加白未终态时直接拿 `assetPath` 喂给视频,平台会拒;必须先 `task wait` 到 `taskStatus=success`。
284
- - 同一角色后续视频任务复用同一 `assetPath`,不要每次重新 register。
285
- - asset 系列只服务于 Seedance / BytePlus / 即梦,**不要**把 `assetPath` 当成可灵的 `subject:reference` 用,反之亦然。
288
+ - 同一角色后续视频任务复用同一 `assetId` / `assetPath`,不要每次重新 register。
289
+ - asset 系列只服务于素材加白;**不要**把素材 `assetId` / `assetPath` 当成可灵的 `subject:reference` 用,反之亦然。
290
+ - 不要调用隐式 submissions 自动补组;素材组查重、创建、素材注册都用显式 CLI 步骤。
286
291
 
287
292
  ## Artifact 流水线错误恢复
288
293
 
@@ -47,7 +47,7 @@
47
47
 
48
48
  | outputKind | 命令 | 必报给用户 | agent 内部用 | 可丢弃 |
49
49
  |------------|------|-----------|--------------|--------|
50
- | `upload_result` | `upload files` | 上传文件数、`uploads[].backendPath` | `backendPath`(喂给 `--resource <type>:<usage>=<backendPath>`) | `uploads[].url`、mimeType |
50
+ | `upload_result` | `upload files` | 上传文件数、`files[].backendPath` | `backendPath`(喂给 `--resource <type>:<usage>=<backendPath>`) | `files[].url`、mimeType |
51
51
 
52
52
  ## 生图 / 生视频
53
53
 
@@ -89,11 +89,12 @@
89
89
 
90
90
  | outputKind | 命令 | 必报给用户 | agent 内部用 | 可丢弃 |
91
91
  |------------|------|-----------|--------------|--------|
92
+ | `asset_review_model_list` | `model asset-review-models` | `modelGroupCode`、`platform` | `platform`(后续 create asset-* 必填) | — |
92
93
  | `asset_match_list` | `create asset-match-actor` | 候选列表(名称 + 评分) | `assetId/groupId` | — |
93
- | `asset_group_list` | `create asset-groups` | `count` + 组名 | `groupId`(下游 register 必填) | — |
94
- | `asset_group_detail` | `create asset-group-get` | 组名、成员数 | `groupId` | — |
95
- | `asset_group_write_result` | `create asset-group / group-update` | `created/updated`、`groupId` | — | — |
96
- | `asset_register_result` | `create asset` | `registered`、`assetId`、`assetPath` | `assetId`(下游引用) | upload 嵌套 |
94
+ | `asset_group_list` | `create asset-groups` | `platform`、`count` + 组名 | `groupId`(下游 register 必填) | — |
95
+ | `asset_group_detail` | `create asset-group-get` | `platform`、组名、成员数 | `groupId` | — |
96
+ | `asset_group_write_result` | `create asset-group / group-update` | `created/updated`、`groupId`、`platform` | — | — |
97
+ | `asset_register_result` | `create asset` | `registered`、`assetId`、`assetPath`、`platform` | `assetId`(下游引用) | upload 嵌套 |
97
98
 
98
99
  ## Artifact(产物 CRUD)
99
100