@aswless_854771076/ai_short_studio_cli 0.1.30 → 0.1.32

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
@@ -38,6 +38,7 @@ CLI 只把 refresh token 保存到系统钥匙串,access token 仅驻留内存
38
38
  - `ai-short-studio canvas get|apply`:读取画布或执行低层图补丁。
39
39
  - `ai-short-studio canvas node`:节点类型/schema 查询、节点读写、执行。
40
40
  - `ai-short-studio canvas edge`:连线读写。
41
+ - `ai-short-studio canvas continuity analyze`:视频生成前分析镜头依赖,可修复已具备源视频的首尾帧连线。
41
42
  - `ai-short-studio canvas asset`:资产列表、上传、版本选择和下载。
42
43
  - `ai-short-studio task`:异步任务读取、等待和取消。
43
44
  - `ai-short-studio config`:模型、provider、默认模型、能力默认值和并发配置。
@@ -45,6 +46,8 @@ CLI 只把 refresh token 保存到系统钥匙串,access token 仅驻留内存
45
46
  ```bash
46
47
  ai-short-studio canvas edge add --project <projectId> --from <sourceNodeId>:<sourceHandle> --to <targetNodeId>:<targetHandle> --json
47
48
  ai-short-studio canvas edge delete <edgeId> --project <projectId> --yes --json
49
+ ai-short-studio canvas continuity analyze --project <projectId> --json
50
+ ai-short-studio canvas continuity analyze --project <projectId> --apply-ready --json
48
51
  ai-short-studio canvas asset select-version <assetId> --project <projectId> --version <versionId> --json
49
52
  ```
50
53
 
@@ -75,19 +78,27 @@ ai-short-studio canvas settings set --project "$PROJECT_ID" --file settings.json
75
78
  }
76
79
  ```
77
80
 
78
- `null` 或空字符串会清除项目覆盖并恢复继承。设置 `artStyle` 会把当前关联的 `visualBible` 保存为项目快照,画风库后续变化不会反向更新项目;同一请求显式传入 `visualBible` 时以显式值为准。所有者和管理员可写,协作者只读;409 冲突后重新 `settings get` 并携带新 `expectedVersion` 重试。`canvas apply` 仍用于节点、连线和视口等低层画布图补丁;Pexels 继续使用 `project provider get|set|test`。
81
+ `null` 或空字符串会清除项目覆盖并恢复继承。设置 `artStyle` 会把当前关联的 `visualBible` 保存为项目快照,画风库后续变化不会反向更新项目;同一请求显式传入 `visualBible` 时以显式值为准。所有者和管理员可写,协作者只读;409 冲突后重新 `settings get` 并携带新 `expectedVersion` 重试。`canvas apply` 仍用于节点、连线和视口等低层画布图补丁;它显式请求完整画布响应,正常保存不预读全图,409 后才读取最新状态并合并重试。Pexels 继续使用 `project provider get|set|test`。
82
+
83
+ 使用 `canvas node edit-shot <nodeId> --project <projectId> --file shot.json` 编辑镜头。命令会追加并选中不可变的人工 DOCUMENT 版本,不允许修改 `shotKey`、`shotIndex` 或来源身份,旧版本继续可选。
79
84
 
80
85
  CLI 通过 `/api/v1/bootstrap` 完成版本、连通性与 Supabase 公共配置预检,并直接使用现有 `/api/projects`、`/api/canvas/node-types`、项目画布与资产路由。
81
86
 
82
- 视频生成节点固定使用参考图生视频,不再提供 `videoInputMode`;图片连接到 `references`,不会作为视频首帧。
87
+ `canvas node types [kind] --json` 同时兼容节点目录 schema v1/v2,并原样返回动态节点的 `source`、`definitionId` 和 `definitionVersionId`。后台发布后重新执行该命令即可读取新目录;归档节点不能新建,但已有实例仍按画布中的固定版本 schema 更新和执行。CLI 创建节点只提交 `kind` 与配置,版本由服务端固定,不能由客户端伪造。
88
+
89
+ 新建视频生成节点按实时模型能力执行:首尾帧模型使用 `start-frame` + `end-frame`,普通图生视频使用 `start-frame`,多图参考模型使用 `references`。历史节点未声明新版输入语义时继续按原多图参考逻辑执行,不会被读取或保存自动迁移。
83
90
 
84
91
  `storyboard-image` schema 现在暴露节点级 `gridSize`。CLI 继续按实时 schema 通用写入,配套 Skill 会分析每个镜头的动作、运镜、多人调度和连续性难度,向用户确认后逐镜设置;未单独设置或连接旧服务时回退到项目格数,系统默认为 6 格。
85
92
 
86
93
  `canvas settings set` 支持项目级 `imageResolution`、`imageQuality`、`videoResolution`,未覆盖的图片、图片编辑和视频节点会继承这些默认值。候选值来自 `settings get` 对应字段的实时 `options`;节点仅在需要偏离项目默认时,按当前模型 `capabilities` 写入 `resolution`、`quality` 覆盖。
87
94
 
95
+ 项目输出语言通过 `ai-short-studio canvas settings set --project <PROJECT_ID> --field outputLanguage --value en` 设置,也可用 `null` 恢复自动。语言变化只把相关下游节点标为 stale,不删除历史资产或自动生成。交付时只下载每镜 selected 原始 MP4,按 `S001.mp4` 顺序命名,并用 manifest 记录镜号、节点、资产、版本和文件名;字幕单独交付,不烧录进原始视频。
96
+
88
97
  百炼 CosyVoice 的 `tts` 节点通过实时 schema 提供音色、语言、格式、采样率、音量、语速、音调和声音指令。先用 `canvas settings get` 确认最终 `audioModel`,再从 `canvas node types` 返回的 `tts.configSchema` 选择字段和值;CLI 会在写入前校验必填字段、类型、整数、枚举和数值上下限。
89
98
 
90
- 声音克隆使用实时目录中的 `voice-clone` 节点:参考音频连接 `audio`,成功后将 `voice` 输出连接到 `tts.voice`,无需手工复制音色 ID。
99
+ 声音设计使用实时目录中的 `voice-design` 节点:提供声音描述并按 schema 配置试听文本、目标模型等参数,成功后将 `voice` 输出连接到 `tts.voice`。声音克隆使用 `voice-clone`:参考音频连接 `audio`,成功后同样连接 `voice` 输出,无需手工复制音色 ID。
100
+
101
+ 视频首尾帧使用实时目录中的 `video-frame-extract` 节点,配置为 `{"position":"first"}` 或 `{"position":"last"}`。其 IMAGE 输出保留来源视频版本;连续性和拆格连接只是建议,只有用户勾选确认后才写入,创建节点和连线不会自动执行或付费。
91
102
 
92
103
  运行 `ai-short-studio <topic> --help` 查看精确参数。可执行命令使用完整产品名 `ai-short-studio`,同时避免与其他 CLI 冲突。所有结构化响应保持 JSON;API 错误也返回稳定的 `error.code`、`status`、`retryable` 和 `details`。
93
104
 
@@ -0,0 +1,13 @@
1
+ import { BaseCommand } from '../../../base-command.js';
2
+ export default class CanvasContinuityAnalyze extends BaseCommand {
3
+ static description: string;
4
+ static flags: {
5
+ project: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
6
+ 'apply-ready': import("@oclif/core/interfaces").BooleanFlag<boolean>;
7
+ 'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
8
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
9
+ locale: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
10
+ profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
+ };
12
+ run(): Promise<void>;
13
+ }
@@ -0,0 +1,25 @@
1
+ import { Flags } from '@oclif/core';
2
+ import { BaseCommand } from '../../../base-command.js';
3
+ import { commandApi, projectFlag } from '../../../command-helpers.js';
4
+ export default class CanvasContinuityAnalyze extends BaseCommand {
5
+ static description = '在生成视频前分析镜头依赖,并可修复已具备源视频的首尾帧连线';
6
+ static flags = {
7
+ ...BaseCommand.baseFlags,
8
+ project: projectFlag,
9
+ 'apply-ready': Flags.boolean({ description: '应用当前可修复的全部连续性关系', default: false }),
10
+ };
11
+ async run() {
12
+ const { flags } = await this.parse(CanvasContinuityAnalyze);
13
+ const { api } = await commandApi(flags);
14
+ const analysis = await api.continuityAnalysis(flags.project);
15
+ if (!flags['apply-ready'])
16
+ return this.print(analysis);
17
+ const expectedVersion = analysis.canvasVersion;
18
+ if (!Number.isSafeInteger(expectedVersion))
19
+ throw new Error('连续性分析缺少画布版本');
20
+ this.print(await api.applyContinuity(flags.project, {
21
+ expectedVersion: expectedVersion,
22
+ applyAll: true,
23
+ }));
24
+ }
25
+ }
@@ -3,6 +3,6 @@ import { BaseCommand } from '../../../base-command.js';
3
3
  import { commandApi, projectFlag, readJsonInput } from '../../../command-helpers.js';
4
4
  export default class CanvasNodeAdd extends BaseCommand {
5
5
  static args = { kind: Args.string({ required: true }) };
6
- static flags = { ...BaseCommand.baseFlags, project: projectFlag, x: Flags.integer({ default: 0 }), y: Flags.integer({ default: 0 }), title: Flags.string(), config: Flags.string({ description: '配置 JSON 文件' }) };
6
+ static flags = { ...BaseCommand.baseFlags, project: projectFlag, x: Flags.integer({ default: 0 }), y: Flags.integer({ default: 0 }), title: Flags.string(), config: Flags.string({ description: '配置 JSON 文件,例如 video-frame-extract 使用 {"position":"first"}' }) };
7
7
  async run() { const { args, flags } = await this.parse(CanvasNodeAdd); const { api } = await commandApi(flags); this.print(await api.addNode(flags.project, { kind: args.kind, x: flags.x, y: flags.y, title: flags.title, config: flags.config ? await readJsonInput(flags.config) : {} })); }
8
8
  }
@@ -0,0 +1,15 @@
1
+ import { BaseCommand } from '../../../base-command.js';
2
+ export default class CanvasNodeEditShot extends BaseCommand {
3
+ static args: {
4
+ nodeId: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
5
+ };
6
+ static flags: {
7
+ project: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
8
+ file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
+ 'base-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
+ json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
+ locale: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
12
+ profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
+ };
14
+ run(): Promise<void>;
15
+ }
@@ -0,0 +1,36 @@
1
+ import { Args, Flags } from '@oclif/core';
2
+ import { BaseCommand } from '../../../base-command.js';
3
+ import { commandApi, projectFlag, readJsonInput } from '../../../command-helpers.js';
4
+ export default class CanvasNodeEditShot extends BaseCommand {
5
+ static args = { nodeId: Args.string({ required: true }) };
6
+ static flags = {
7
+ ...BaseCommand.baseFlags,
8
+ project: projectFlag,
9
+ file: Flags.string({ description: '镜头 JSON 文件;省略时读取 stdin' }),
10
+ };
11
+ async run() {
12
+ const { args, flags } = await this.parse(CanvasNodeEditShot);
13
+ const { api } = await commandApi(flags);
14
+ const canvas = await api.canvas(flags.project);
15
+ const node = canvas.nodes.find((candidate) => candidate.id === args.nodeId);
16
+ if (!node || node.kind !== 'storyboard-shot')
17
+ throw new Error(`镜头节点不存在:${args.nodeId}`);
18
+ let basedOnVersionId = typeof node.data.selectedOutputVersionId === 'string'
19
+ ? node.data.selectedOutputVersionId
20
+ : '';
21
+ if (!basedOnVersionId && typeof node.refId === 'string') {
22
+ const payload = await api.asset(flags.project, node.refId);
23
+ const asset = payload.asset && typeof payload.asset === 'object' && !Array.isArray(payload.asset)
24
+ ? payload.asset
25
+ : {};
26
+ basedOnVersionId = typeof asset.selectedVersionId === 'string' ? asset.selectedVersionId : '';
27
+ }
28
+ if (!basedOnVersionId)
29
+ throw new Error('镜头当前版本不存在');
30
+ this.print(await api.updateStoryboardShot(flags.project, args.nodeId, {
31
+ expectedCanvasVersion: canvas.version,
32
+ basedOnVersionId,
33
+ shot: await readJsonInput(flags.file),
34
+ }));
35
+ }
36
+ }
@@ -1,5 +1,6 @@
1
1
  import { BaseCommand } from '../../../base-command.js';
2
2
  export default class CanvasNodeTypes extends BaseCommand {
3
+ static description: string;
3
4
  static args: {
4
5
  kind: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
5
6
  };
@@ -2,6 +2,7 @@ import { Args } from '@oclif/core';
2
2
  import { BaseCommand } from '../../../base-command.js';
3
3
  import { commandApi } from '../../../command-helpers.js';
4
4
  export default class CanvasNodeTypes extends BaseCommand {
5
+ static description = '读取服务端实时画布节点类型与 schema';
5
6
  static args = { kind: Args.string() };
6
7
  static flags = BaseCommand.baseFlags;
7
8
  async run() { const { args, flags } = await this.parse(CanvasNodeTypes); const { api } = await commandApi(flags); const catalog = await api.nodeTypes(); this.print(args.kind ? catalog.nodeTypes.find((item) => item.kind === args.kind) ?? null : catalog); }
@@ -43,7 +43,7 @@ export default class CanvasSettingsSet extends BaseCommand {
43
43
  static flags = {
44
44
  ...BaseCommand.baseFlags,
45
45
  project: projectFlag,
46
- field: Flags.string({ description: '要更新的设置字段,如 imageResolution、imageQuality、videoResolution', dependsOn: ['value'], exclusive: ['file'] }),
46
+ field: Flags.string({ description: '要更新的设置字段,如 outputLanguage、imageResolution、imageQuality、videoResolution', dependsOn: ['value'], exclusive: ['file'] }),
47
47
  value: Flags.string({ description: '字段值', dependsOn: ['field'], exclusive: ['file'] }),
48
48
  file: Flags.string({ description: '设置 JSON 文件;省略时读取 stdin', exclusive: ['field', 'value'] }),
49
49
  };
@@ -17,10 +17,14 @@ interface CanvasDto extends JsonObject {
17
17
  version: number;
18
18
  nodes: CanvasNode[];
19
19
  edges: JsonObject[];
20
+ nodeTypesByVersionId?: Record<string, NodeType>;
20
21
  }
21
22
  interface NodeType extends JsonObject {
22
23
  kind: string;
23
24
  title: string;
25
+ source?: 'builtin' | 'custom';
26
+ definitionId?: string | null;
27
+ definitionVersionId?: string | null;
24
28
  defaultConfig: JsonObject;
25
29
  configSchema: JsonObject;
26
30
  }
@@ -51,9 +55,17 @@ export declare class VvicatApi {
51
55
  listNodes(projectId: string): Promise<CanvasNode[]>;
52
56
  node(projectId: string, nodeId: string): Promise<CanvasNode>;
53
57
  listEdges(projectId: string): Promise<JsonObject[]>;
58
+ continuityAnalysis(projectId: string): Promise<JsonObject>;
59
+ applyContinuity(projectId: string, input: {
60
+ expectedVersion: number;
61
+ suggestionIds?: string[];
62
+ applyAll?: boolean;
63
+ }): Promise<JsonObject>;
54
64
  patchCanvas(projectId: string, input: JsonObject): Promise<JsonObject>;
65
+ updateStoryboardShot(projectId: string, nodeId: string, input: JsonObject): Promise<JsonObject>;
55
66
  nodeTypes(): Promise<{
56
- schemaVersion: number;
67
+ schemaVersion: 1 | 2;
68
+ catalogRevision?: string;
57
69
  nodeTypes: NodeType[];
58
70
  }>;
59
71
  addNode(projectId: string, input: {
@@ -27,6 +27,9 @@ function validateConfigSchema(nodeType, config, requiredValues = config ?? {}) {
27
27
  if (fieldSchema.type === 'integer' && !Number.isInteger(value)) {
28
28
  throw new Error(`节点 ${nodeType.kind} 的 ${key} 必须是整数`);
29
29
  }
30
+ if (fieldSchema.type === 'boolean' && typeof value !== 'boolean') {
31
+ throw new Error(`节点 ${nodeType.kind} 的 ${key} 必须是布尔值`);
32
+ }
30
33
  if (typeof value === 'number' && typeof fieldSchema.minimum === 'number' && value < fieldSchema.minimum) {
31
34
  throw new Error(`节点 ${nodeType.kind} 的 ${key} 不能小于 ${fieldSchema.minimum}`);
32
35
  }
@@ -101,12 +104,29 @@ export class VvicatApi {
101
104
  async listEdges(projectId) {
102
105
  return (await this.canvas(projectId)).edges;
103
106
  }
107
+ async continuityAnalysis(projectId) {
108
+ const payload = await this.client.request(`/api/projects/${projectId}/canvas/continuity`);
109
+ return payload.data.analysis;
110
+ }
111
+ applyContinuity(projectId, input) {
112
+ return this.client.request(`/api/projects/${projectId}/canvas/continuity`, { method: 'POST', body: input });
113
+ }
104
114
  patchCanvas(projectId, input) {
105
- return this.client.request(`/api/projects/${projectId}/canvas`, { method: 'PATCH', body: input });
115
+ return this.client.request(`/api/projects/${projectId}/canvas`, {
116
+ method: 'PATCH', headers: { Prefer: 'return=representation' }, body: input,
117
+ });
118
+ }
119
+ updateStoryboardShot(projectId, nodeId, input) {
120
+ return this.client.request(`/api/projects/${projectId}/canvas/nodes/${nodeId}/storyboard-shot`, {
121
+ method: 'PATCH', body: input,
122
+ });
106
123
  }
107
124
  async nodeTypes() {
108
125
  const payload = await this.client.request('/api/canvas/node-types');
109
- return payload.data;
126
+ if (payload.data.schemaVersion !== 1 && payload.data.schemaVersion !== 2) {
127
+ throw new Error(`不支持的节点目录版本:${payload.data.schemaVersion}`);
128
+ }
129
+ return { ...payload.data, schemaVersion: payload.data.schemaVersion };
110
130
  }
111
131
  async addNode(projectId, input) {
112
132
  const canvas = await this.canvas(projectId);
@@ -136,7 +156,9 @@ export class VvicatApi {
136
156
  if (!node)
137
157
  throw new Error(`节点不存在:${nodeId}`);
138
158
  const catalog = await this.nodeTypes();
139
- const definition = catalog.nodeTypes.find((item) => item.kind === node.kind);
159
+ const definitionVersionId = typeof node.data.definitionVersionId === 'string' ? node.data.definitionVersionId : null;
160
+ const definition = catalog.nodeTypes.find((item) => item.kind === node.kind)
161
+ ?? (definitionVersionId ? canvas.nodeTypesByVersionId?.[definitionVersionId] : undefined);
140
162
  if (!definition)
141
163
  throw new Error(`未知节点类型:${node.kind}`);
142
164
  const nextConfig = { ...node.data.config, ...config };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aswless_854771076/ai_short_studio_cli",
3
- "version": "0.1.30",
3
+ "version": "0.1.32",
4
4
  "description": "VVICAT 无限画布项目命令行工具",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -34,35 +34,123 @@ description: Use when an agent needs to inspect or operate VVICAT infinite-canva
34
34
 
35
35
  1. 明确原始故事或剧本、目标受众与平台、语言、成片画幅、总时长与镜头目标时长、风格参考、人物/场景/道具约束,以及交付是否包含剧本、设定、分镜图、视频和音频;除本文明确的素材画幅与视频生成时长默认值外,缺项先问。
36
36
  2. 完成 preflight、账户配置读取和节点目录检查后,新项目按“project list → 确认名称/用途 → project create → project get + canvas get + canvas settings get”继续,既有项目读取相同的已有资源;再按“项目配置门禁”确认、原子写入并回读 settings。两种项目都必须在任何创作节点之前通过门禁;既有项目只修改用户确认字段,并优先复用已确认的节点与 selected version。
37
- 3. 原文需要改编时执行 `novel-to-script`。分镜拆解前必须先完成人物、场景、道具等本次故事涉及的素材生成。角色、道具、场景/背景、分镜图及其他视觉参考素材,用户未指定画幅时统一采用推荐值 `aspectRatio: 16:9`;用户明确指定其他画幅或平台硬性要求不同时,以用户要求为准。创建或更新节点前读取实时 `configSchema`:支持 `aspectRatio` 的节点必须显式写入最终值,不得误继承项目中的其他画幅;不支持时不得伪造字段,应说明实际继承来源并在付费生成前确认最终有效画幅。人物视觉方案的每个 `appearance.descriptions` 候选必须拆成独立输入,并采用“一候选描述 → 一个三视图节点 → 一个独立图片资产”的方式生成;道具存在多个候选方案时同样处理。每个三视图节点只能接收一个人物形象或一个道具候选,提示词必须明确“只生成当前候选的一张三视图,不得拼接其他候选”;单张三视图内部可以包含同一对象的正面、侧面和背面,但禁止把多个候选方案纵向、横向或宫格拼成一张图。`count` 只表示同一候选的独立生成版本数,每个结果必须作为独立图片版本展示和选择,不得合并为一张长图。互不依赖的素材节点应同批执行并收集真实任务 ID,再并发 `task wait`,不得等待一个完成后才提交下一个;存在上游依赖时按依赖顺序分批执行。每个任务都必须到成功终态,并让用户确认后为每项素材设置 selected version。任一素材未生成成功、未确认或没有 selected version 时,禁止执行 `storyboard-breakdown`,先询问用户并补齐。
38
- 4. 按实时节点 schema,把已确认的剧本节点,以及每个人物、场景、道具等相关素材节点,逐项连接到 `storyboard-breakdown` 对应输入 handle(通常为 `script`、`characters`、`locations`、`props`)。执行前重新读取画布和连线,确认本次故事涉及的素材节点无遗漏;即使服务端把素材输入标为可选,标准创作流程也不得省略。任一对应连线缺失时禁止拆解,先补线;素材范围不清楚时先询问用户。全部门禁满足后才执行并等待。成功后刷新画布,读取服务端自动创建的 `storyboard-shot` 和 `storyboard-image`,不得重复手工创建。
39
- 5. 生成分镜图前,用 `canvas asset get/list` 取得人物、场景、道具等已选版本,必要时下载,并把实际图片或可访问预览展示给用户;只提供资产 ID、文件路径或文字说明不算展示。用户明确确认素材与选版后,读取 `storyboard-image` 的实时 `configSchema`,用户未指定画幅且 schema 支持时将 `aspectRatio: 16:9` 显式写入节点,再分析每个镜头的动作阶段、运镜变化、多人调度和连续性难度,选择 schema 允许的最小够用格数:简单镜头建议 4 格,常规镜头使用默认 6 格,复杂镜头建议 9 格,16/25 格只用于用户明确需要的长动作或高密度关键帧。向用户展示逐镜建议并确认后,将各自 `gridSize` 写入对应节点;旧服务 schema 未暴露字段时不得虚假写入,应说明限制并回退到项目有效值,`gridSize` 未另行确认时为 6 格。连续叙事优先建议 `imageLayout: storyboard`,同时说明 `grid` 与 `single` 可选,最终由用户确认布局、镜头范围、参考资产、模型与费用范围。未展示或未确认时禁止生成分镜图。
40
- 6. 执行分镜图后按“生成后自我审计”检查任务、配置和真实产物,并把实际分镜图或可访问预览展示给用户。用户明确确认分镜图以及需要制作的视频镜头后,才能刷新画布并复用服务端自动创建的 `storyboard-video-prompt`;宫格和故事版均先按实际布局重写完整视频提示词,再经用户确认后执行自动创建的 `video-generate`。视频生成默认不拆格,整张分镜图连接到 `references` 且仅作参考,不得作为首帧;节点不再提供 `videoInputMode`。为给后续剪辑留余量,设镜头目标时长为 `d`:`0 < d <= 5` 时生成 5 秒,`5 < d <= 10` 时生成 10 秒,`10 < d <= 15` 时生成 15 秒;保留原目标时长供剪辑裁切,不得为了凑生成档位改写叙事时长。`d` 缺失或非法时默认生成 5 秒;`d > 15` 时先拆镜或取得用户确认。最终值必须由实时 `video-generate.configSchema` 支持;模型不支持目标档位时,展示可用选项并在付费生成前确认,不得静默缩短。音频按交付范围执行。未展示或未确认分镜图时禁止生成视频。
37
+ 3. 原文需要改编时执行 `novel-to-script`。分镜拆解前必须先完成人物、场景、道具等本次故事涉及的素材生成。角色、道具、场景/背景、分镜图及其他视觉参考素材,用户未指定画幅时统一采用推荐值 `aspectRatio: 16:9`;用户明确指定其他画幅或平台硬性要求不同时,以用户要求为准。创建或更新节点前读取实时 `configSchema`:支持 `aspectRatio` 的节点必须显式写入最终值,不得误继承项目中的其他画幅;不支持时不得伪造字段,应说明实际继承来源并在付费生成前确认最终有效画幅。人物视觉方案的每个 `appearance.descriptions` 候选必须拆成独立输入,并采用“一候选描述 → 一个三视图节点 → 一个独立图片资产”的方式生成;道具存在多个候选方案(真/假、原版/复制品、干净/破损等成对或多版本)时,**必须按“关联资产参考图门禁”先生成基础版并用户确认 selected version,再把该基础版的 image-resource 作为参考图连入派生版 turnaround/design 节点,prompt 逐条枚举允许的差异**,不得两版并行独立生成。每个三视图/设计节点只能接收一个人物形象或一个道具候选,提示词必须明确“只生成当前候选的一张三视图,不得拼接其他候选”;单张三视图内部可以包含同一对象的正面、侧面和背面,但禁止把多个候选方案纵向、横向或宫格拼成一张图。`count` 只表示同一候选的独立生成版本数,每个结果必须作为独立图片版本展示和选择,不得合并为一张长图。互不依赖的素材节点应同批执行并收集真实任务 ID,再并发 `task wait`,不得等待一个完成后才提交下一个;存在上游依赖(例如假道具依赖真道具参考图、童年形象依赖成年形象参考图)时必须按依赖顺序分批执行,参考图未选定 selected version 前不得提交下游派生节点。每个任务都必须到成功终态,并让用户确认后为每项素材设置 selected version。任一素材未生成成功、未确认或没有 selected version 时,禁止执行 `storyboard-breakdown`,先询问用户并补齐。
38
+ 4. 按实时节点 schema,把已确认的剧本节点,以及每个人物、场景、道具等相关素材节点,逐项连接到 `storyboard-breakdown` 对应输入 handle(通常为 `script`、`characters`、`locations`、`props`)。执行前重新读取画布和连线,确认本次故事涉及的素材节点无遗漏;即使服务端把素材输入标为可选,标准创作流程也不得省略。任一对应连线缺失时禁止拆解,先补线;素材范围不清楚时先询问用户。全部门禁满足后才执行并等待。成功后刷新画布,读取服务端自动创建的 `storyboard-shot` 和 `storyboard-image`,不得重复手工创建,并通过“分镜素材连线门禁”。
39
+ 5. 生成分镜图前,必须先通过“分镜素材连线门禁”。再用 `canvas asset get/list` 取得人物、场景、道具等已选版本,必要时下载,并把实际图片或可访问预览展示给用户;只提供资产 ID、文件路径或文字说明不算展示。用户明确确认素材与选版后,读取 `storyboard-image` 的实时 `configSchema`,用户未指定画幅且 schema 支持时将 `aspectRatio: 16:9` 显式写入节点,再分析每个镜头的动作阶段、运镜变化、多人调度和连续性难度,选择 schema 允许的最小够用格数:简单镜头建议 4 格,常规镜头使用默认 6 格,复杂镜头建议 9 格,16/25 格只用于用户明确需要的长动作或高密度关键帧。向用户展示逐镜建议并确认后,将各自 `gridSize` 写入对应节点;旧服务 schema 未暴露字段时不得虚假写入,应说明限制并回退到项目有效值,`gridSize` 未另行确认时为 6 格。连续叙事优先建议 `imageLayout: storyboard`,同时说明 `grid` 与 `single` 可选,最终由用户确认布局、镜头范围、参考资产、模型与费用范围。未展示、未确认或连线门禁未通过时禁止生成分镜图。
40
+ 6. 执行分镜图后按“生成后自我审计”检查任务、配置和真实产物,并把实际分镜图或可访问预览展示给用户。用户明确确认分镜图以及需要制作的视频镜头后,先运行 `canvas continuity analyze --project <projectId> --json`,在任何视频任务提交前取得相邻镜头依赖、等待关系和当前可修复项;不得先生成全部视频再分析。依赖前一镜尾帧的镜头必须等待前一镜视频成功,随后运行 `canvas continuity analyze --project <projectId> --apply-ready --json` 创建提帧节点与连线,再提交下一镜。之后才能复用服务端自动创建的 `storyboard-video-prompt`;宫格和故事版均先按实际布局重写完整视频提示词,再经用户确认后执行自动创建的 `video-generate`。整张故事版不得自动接入视频;只使用已有宫格拆分结果,并按模型能力建议首尾帧、普通首帧或最多四张多图参考。缺拆格结果时提示先运行拆分节点,绝不自动执行。为给后续剪辑留余量,设镜头目标时长为 `d`:`0 < d <= 5` 时生成 5 秒,`5 < d <= 10` 时生成 10 秒,`10 < d <= 15` 时生成 15 秒;保留原目标时长供剪辑裁切,不得为了凑生成档位改写叙事时长。`d` 缺失或非法时默认生成 5 秒;`d > 15` 时先拆镜或取得用户确认。最终值必须由实时 `video-generate.configSchema` 支持;模型不支持目标档位时,展示可用选项并在付费生成前确认,不得静默缩短。音频按交付范围执行。未展示或未确认分镜图时禁止生成视频。
41
41
  7. 配置门禁固定用一次 `canvas settings set` 写入确认字段;通过门禁后的节点与连线写入,仍需在每次写入前重新读取画布版本,优先用专用 node/edge 命令,批量图变更才用低层 `canvas apply`。每次执行都读取真实任务 ID 并 `task wait`,不用固定 sleep。
42
- 8. 每批图片、视频或音频生成完成后必须先通过“生成后自我审计”,才能报告成功、请求选版或进入下一付费阶段。交付前再次确认 selected version 与下载目录,记录项目、节点、任务和资产 ID、审计结论、失败项与未决项。临时项目在所有结束路径删除;既有项目绝不擅自删除。
42
+ 8. 每批图片、视频或音频生成完成后必须先通过“生成后自我审计”,才能报告成功、请求选版或进入下一付费阶段。在进入视频生成前,必须额外依次执行:(a)“镜头级素材审计”全量清单,核对 reference 集合覆盖镜中人物/场景/道具、无跨类型错边、成对资源引用正确版本、stale 清零、道具词扫 description 兜底、资源文字设定贯穿到 shot/image;(b)“上下镜连续性审计”,按时序逐对相邻镜核对人物位置、道具状态、光影色调、动势视线、景别节奏、叙事桥接,并给有动作连续关系的镜组互加 reference、给极端特写/物证镜补入必要的人物 reference;(c)“分镜逻辑审计”,对照叙事期望逐项扫掉关键词误命中、真假道具互串、跨段同名实体误连、黑场/空镜多余连线、多版本角色(成年/童年)误连、龙套角色引用主角资源等问题,输出逐镜审计表并精确删/加边直到 wired=plan;(d) 把图像模型的已知先验 bias(数字、具象动物、实体面具、中文字样等)列入视频阶段 prompt 的 negative 约束。交付前再次确认 selected version 与下载目录,记录项目、节点、任务和资产 ID、审计结论、失败项与未决项。临时项目在所有结束路径删除;既有项目绝不擅自删除。
43
+
44
+ ## 分镜素材连线门禁
45
+
46
+ 在首次生成或重跑任何 `storyboard-image` 前,对当前画布的每个 `storyboard-shot → storyboard-image` 配对执行以下检查;任一项失败都禁止付费生成:
47
+
48
+ 1. 读取当前 shot 的 selected asset 完整结构,并以已确认的人物、场景、道具资源名称核对 `characters`、`location(s)`、`props` 与 `description`、`sourceText/source_text`、`imagePrompt/image_prompt`。若叙事字段明确出现某资源而对应结构字段为空、漏项或冲突,判定 breakdown 产物不完整;不能因为文字 prompt 提到了素材就视为已注入参考图。若 `props` 结构字段缺失(某些模型版本只输出 characters/location),必须用关键词扫 description/video_prompt/photographyPlan 来确定每镜道具,不得因为字段缺失就跳过。
49
+ 2. 只把资源全名、稳定资源 key 或用户已确认的别名视为确定匹配。简称、同类物、真假版本、多人/多场景同名等无法唯一映射时,列出“镜头 → 候选资源”并询问用户,不得自行猜测。
50
+ 3. 为每镜生成期望素材表,逐项核对其 selected version、实际图片产物和目标 `storyboard-image` 的引用边。视觉素材优先从已选版 `image-resource` 的图片输出接入实时 schema 支持的 `reference` 或对应语义 handle;不能用 `prop-turnaround` 等生成节点本身冒充最终参考资产。核对时必须分别统计人物、场景、道具三类素材两种边:(a) 从各自图片资源连入 `storyboard-image.reference` 的图片参考边;(b) 从资源文字设定节点(`character-resource`/`location-resource`/`prop-resource`)连入 `storyboard-shot.<handle>` 和 `storyboard-image.<handle>` 的文字边。两类边都要三类素材对称覆盖,不能只看图片参考边而漏掉文字边——道具类资源尤其容易出现“文字只连到 breakdown、三视图只连到 reference、但 prop-resource 本身没连到 shot/image”的物化 bug,导致编号/印记/negative 约束等文字信息在 shot/image 阶段全部丢失。道具边数显著少于人物/场景时即为物化 bug,按下一条补线。
51
+ 4. 按实时输入输出 schema 和业务链路审计全部相关边,拒绝跨类型、反向、互连、重复和串镜边。`prop-turnaround` 的图片只能物化到对应道具图片资源,不得连到 `location-image`、其他 turnaround 或无关镜头。
52
+ 5. 发现已物化画布缺线或错线时,先输出精确差异:要删除的 edge ID、要新增的 source/handle → target/handle、受影响镜头和预计重跑范围。不得改写自动生成的 shot asset、伪造 `props` 字段或重复创建自动下游节点。
53
+ 6. 仅在映射唯一或用户已确认后修复。写前重读画布版本;优先使用 `canvas edge add/delete`,只删除精确 edge ID,保留无关和用户自建连线。写后重新读取并重复同一审计,确认实际边集合等于期望集合、无重复且再次执行不会产生新差异,才允许只重跑受影响镜头。
54
+
55
+ 结构字段漏项属于上游产物或物化缺陷,不得静默绕过。能用确定映射恢复 reference 时按上述幂等流程修复;不能确定时停止并报告缺口,等待用户选择重新拆解或确认映射。
56
+
57
+ ## 关联资产参考图门禁(真假/版本/衍生)
58
+
59
+ 故事里存在“真/假”“原版/复制品”“同款不同状态”的成对道具、不同年龄同一人物、或母题相关的场景时,三视图和分镜图必须保持视觉血缘一致性,禁止各版本互不相干地自由发挥:
60
+
61
+ 1. **先生成基础版,再衍生对照版**。成对资源中先跑“真/原版/成年/主场景”的 turnaround/design 节点,让用户确认 selected version 后,再把它的 `image-resource` 作为参考图连到派生节点(假/复制品/童年/对照场景)的 turnaround/design 输入(若实时 schema 支持 reference 类 handle)或写入 prompt(“必须与已确认的 {基础版名称} 采用完全相同的器型、轮廓、尺寸、材质肌理和工艺细节,唯一允许差异为……”)。禁止两版同时独立生成后再期望图像模型自己保持一致。
62
+ 2. **差异显式枚举**。衍生版的 prompt 必须逐条列出“唯一允许差异”(例如:赝品只有两处印记、编号尾号不同、磨损略轻;童年形象必须共享眼型/鼻梁/脸型/发色),其余项一律写“与真品完全一致”。不能只写“与真品近似”。
63
+ 3. **禁止具象化母题元素**。当视觉圣经禁止宗教符号或特定图样、但剧本要求抽象呼应(例如“猎隼面向西方”的猎隼母题)时,道具/人物饰钮只能用**抽象剪影/勾形/几何轮廓**,prompt 必须明确“不是鸟类、没有眼睛/喙/羽毛/真实鸟头”,并把母题图样列在 negative 里,避免图像模型画成具象猛禽/人像/宗教纹样。
64
+ 4. **关联参考必须作为 reference 边入图**。基础版一旦选定,其 `image-resource` 必须作为 `reference` 连入所有衍生版的 turnaround/design,以及所有出现该道具(不论真假)的 `storyboard-image`。不能只在文字 prompt 里描述而不给参考图;文字描述对图像模型的约束力远低于参考图。
65
+ 5. **审查顺序:真→假→镜**。审计时先核对基础版三视图质量(造型、工艺、非宗教、非具象),再核对衍生版差异点是否完全符合 prompt 且与基础版轮廓一致,最后核对每镜的 reference 集里是否同时包含该镜出现版本的三视图。任一环节失败都回滚重跑,不得“视频阶段再修”。
66
+
67
+ ## 镜头级素材审计(必跑清单)
68
+
69
+ 在付费生成视频或交付前,必须对每一个 `storyboard-shot → storyboard-image` 配对执行以下机械审计并输出结构化结果;任何一项缺失都先补线再继续:
70
+
71
+ 1. **reference 来源完整**。枚举该 `storyboard-image` 的全部 `reference` 入边,反向 trace 到 `image-resource → turnaround/design → resource`,分别归类为人物/场景/道具/分镜图本身;与该镜 shot asset 里的 `characters`、`location`、以及从 description/video_prompt 扫出的道具名做集合比较,三类素材都应覆盖,不能有名字在镜中但没有 reference 图。注意同一角色可能存在 character-design 和 character-visual-design 两个 resource 节点,审计必须并集两个来源,不能因后者覆盖前者而误报缺失。
72
+ 2. **没有错边/串镜/跨类型边**。扫描画布全局,拒绝以下边:`prop-turnaround → location-image`、`*-turnaround → *-turnaround`(任何类型 turnaround 之间互连)、`image-resource → storyboard-image` 指向的分镜图与该图片资产镜号不符、`A→B` 和 `B→A` 同时存在形成环。
73
+ 3. **成对资源一致**。对每组成对资源(真/假道具、成年/童年人物),核对该镜引用的版本正确(赝品出镜镜必须引用赝品三视图,不能用真品的;童年镜必须引用童年资源);若镜中真假同框,两个版本的 reference 都必须在。
74
+ 4. **结构字段兜底**。shot asset 的 `props` 字段缺失时,必须用关键词扫 description/video_prompt/photographyPlan 补出道具集合,不能因为字段空就判为无道具。关键词匹配优先长名/特异名(如“镇族金器拍卖赝品”优先于“金器”),避免把“真品”关键词误命中到赝品镜。
75
+ 5. **stale 节点清零**。画布上 `status=stale` 的节点数量必须为 0;不为 0 时列出并删除,保留可能被用户显式收藏的版本(需询问)。
76
+ 6. **资源文字设定必须贯穿到 shot/image**。`character-resource`、`location-resource`、`prop-resource` 三类文字设定的输出边必须对称:除连到对应 turnaround/design 节点和 `storyboard-breakdown` 外,还要按镜中实际出现连到 `storyboard-shot.<characters|locations|props>` 和 `storyboard-image.<characters|locations|props>`。不能只把道具连到 breakdown(会导致 shot/image 阶段看不到道具文字设定,只看到三视图参考图,编号/印记/文字提示词全部丢失)。审计时单独统计三类资源 → shot 的边数、三类资源 → image 的边数,三类分布必须一致,明显偏少(例如人物/场景全连而道具边数为 0)即判定为物化 bug,按幂等流程补线。
77
+ 7. **输出审计报告**。审计完成后给出:每镜实际 reference 清单、缺失项、错边列表、stale 数、成对资源一致性检查结果、以及待重跑的镜头列表;用户确认后再补边/重跑。
78
+
79
+ 审计脚本应一次性覆盖全部镜头,不要“抽样”或只看几镜;几十镜规模下全量审计成本仍很低,漏检代价高。
80
+
81
+ ## 上下镜连续性审计(镜头间一致性)
82
+
83
+ 在素材连线审计通过后、生成视频前,必须再做一次**按时间线顺序**的跨镜连续性检查。这一步独立于单镜素材审计,关注的是“上一镜结尾到下一镜开头”的视觉连续性:
84
+
85
+ 先执行 `canvas continuity analyze --project <projectId> --json`。该命令只读取镜头、lineage、模型能力与连线,不创建任务、不产生模型费用;输出中的 `waiting-for-source-video` 表示下一镜必须等待上一镜完成,`readyFixes` 表示可用 `--apply-ready` 免费补建提帧节点与连线。视频完成后仍需按本节清单复检真实画面。
86
+
87
+ 1. **检查清单**。按 shotKey 顺序逐镜对相邻两镜核对:
88
+ - **人物身份与位置**:上一镜的主要人物下一镜是否还在;越肩/反打镜头的前景人物是否与上个对话方匹配;同一场景多镜之间服装/妆容/干湿/血迹等是否一致。
89
+ - **道具状态与位置**:上一镜刚出现/移动/封存的道具下一镜位置是否连贯(例:镜 6 手刚打开胸针背板,镜 7 必须是同一胸针压痕;镜 9 金沙飘向档案盒,镜 10 文件叠化要能看出“异能→纸本”的视觉桥接)。
90
+ - **光影与色调**:同一场景内相邻镜的色温、光源方向必须一致(暖金权力空间保持暖金侧逆光、冷蓝档案空间保持冷蓝顶侧光,跨场景转场要有硬切或黑场);段尾镜要为下一段开头做光线过渡(例:修复室最后一镜努尔抬眼、右侧带暖金反光,接暖金拍卖厅全景)。
91
+ - **动势与视线**:上一镜角色的动作方向/视线方向,下一镜是否承接;跳切、匹配切需要视觉重心在屏幕同一位置或动作方向一致;竖屏 9:16 多镜要优先沿竖轴设计运动(向下推、向上拉、垂直叠化),避免横向无动机跳。
92
+ - **景别呼吸节奏**:不能连续多镜同景别无动机切换;关键钩子前要留一镜短时长(≤2s)做屏息,长举证镜可给 4–6s。
93
+ - **叙事桥接**:时间/空间跳跃必须有可识别的桥(黑场、声音、视线引导、动作匹配),不能让观众猜“人怎么到那里了”。
94
+ 2. **极端特写/空镜/物证镜也必须人物 reference**。`characters` 字段为空但画面里会露出手、肩、眼等身体部分时(例如极端特写胸针压痕但努尔手指入镜、微距金器但白手套入镜),**必须把对应人物的 image-resource 作为 reference 连入**,否则该身体部位可能被画成第三人称或出现手指数量错误。
95
+ 3. **关联镜头互相作为参考**。对于成对/多镜动作(匹配切、叠化、连续推轨、正反打),除了各自的人物/场景/道具 reference,还应把前一镜和后一镜的 `storyboard-image` 输出也作为 `reference` 接进来(双向或单向视剪辑方向),让图像模型在镜间保持构图、光线、道具位置的连续。
96
+ 4. **已知模型先验 bias 必须在 video 阶段二次约束**。图像模型对面具、号牌数字或动物意象等词有强先验;这些要在 video-generate 的 prompt 里二次写出明确的形状与禁止项,不能依赖分镜图阶段的约束。
97
+ 5. **时序问题必须报给用户**。发现剧本/分镜顺序本身的时序错位(例如某段镜组发生时间早于前一段却排在后面)、或人物/道具位置无法通过剪辑弥补的跳变时,不能自行改镜,必须列出来让用户决定调镜序还是补过渡镜。
98
+
99
+ ## 分镜逻辑审计(内容与匹配)
100
+
101
+ 素材连线和连续性审计都通过后、进入视频生成前,必须对每个 shot 的**叙事内容、文字匹配、资源引用正确性**做一次逻辑审计,专门抓“看起来连线都齐但其实引错了/引多了/引少了”的问题:
102
+
103
+ 1. **对照叙事期望,扫掉“关键词误命中”连线**。用关键词匹配 props/characters 时必然有误命中,必须逐镜人工或半人工复核:
104
+ - **场景特异性优先于通用关键词**。“断环标记”同时出现在复检权限平板(会议室)和普通竞拍牌(电梯),不能因为“断环”二字就把两个道具都连上。要根据 location 和其他关键词(平板 vs 号牌、会议室 vs 电梯)判定。
105
+ - **真假版本不能互串**。真品关键词(“三处印记/尾号04”)命中时,不能把赝品三视图连上;反之亦然。镜中明确写“方形金质砝码/拍品”时连赝品,写“原册/真品三处印记”时连真品。
106
+ - **跨段同名/相似实体不能互串**。“金器被调换”描述里的“金器”是回忆里父亲核对的真/假两件,不是展厅展柜里的那一件,不能因为出现“金器”二字就连赝品三视图。
107
+ - **身体/戒指/人物不等于对应资源**。“她左手猎隼戒指”不是一个独立道具,不要误连其他戒指资源;“档案袋/文件/报告/报纸”等未在 prop-resource 中定义的现场物件,不要强行映射到已定义道具。
108
+ - **空镜/黑场/片名镜**(纯黑、字幕、全片头等)没有任何道具,也不应有 location 的实际画面,不能连任何 reference 或道具/场景;连了就是误命中,必须删除。
109
+ 2. **检查龙套/临时角色**。shot 的 `characters` 字段里出现未在 character-resource 中定义的角色(例如拍卖师、工作人员、路人、独立鉴定人)时:
110
+ - 不强行创建完整角色资源(三视图/turnaround 成本高),但必须在 storyboard-image 的 prompt/config 里写明“无名龙套、正装、海湾阿拉伯面孔、非主角脸、无特殊标识”,避免图像模型用主角脸凑数。
111
+ - 龙套镜不应有 `characters` 边指向主角的 character-resource。
112
+ 3. **多版本角色(成年/童年、年轻/老年)严格按景别连**。同一角色的不同年龄段(如努尔 vs 年幼努尔)是两个独立 resource:
113
+ - 成年主角的近景/中景/特写只连成年版,不能因为“努尔”关键词命中就把童年版也连上(会让模型在成年镜画出儿童脸)。
114
+ - 明确的童年/回忆镜(人物表列“年幼努尔”、action 写明“蹲下身对小努尔说话”)才连童年版。
115
+ - 过渡镜/混合镜(匹配剪辑、跨时空同框)两个版本都要连。
116
+ 4. **“物证/文件/纸页叠化”类镜头不能引错实体**。交接簿、复检许可、旧编号页、现场报告等临时纸张如果不是已定义 prop,不要为它们连上无关的实体道具(例如平板、藏册)。纸页叠化是蒙太奇语言,不是单个道具特写。
117
+ 5. **逐镜打印审计表**。对几十镜规模的项目,输出一张“镜号 / 时长 / 角色(plan)/ 道具(plan)/ 场景 / 实际 wired chars / 实际 wired props / 实际 refs 数 / 问题”表,人工扫一遍:plan 和 wired 不一致的、wired 比 plan 多出奇怪条目、黑场镜仍有 props/location 连线的、龙套镜引用了主角资源的,全部列出并修。
118
+ 6. **视频阶段 negative 清单**。分镜图阶段修不掉的图像模型先验(面具买家画眼罩、竞拍牌画数字、隼画成具象猛禽、证章上出现中文字等),整理成逐镜 negative prompt 清单,在 video-generate 节点 config.prompt 里逐条显式禁止,不要寄希望于视频模型自己纠正。
119
+ 7. **时长/节奏校验**。核对各段总时长与剧本秒数的偏差(例如 39+45+39=123s 对 120s 剧本,偏差在视频剪辑桶内可消化);单镜过长过短、或单镜承担三段以上动作(匹配剪辑超过 3 段)的,提示用户可能需要拆镜或延长。
120
+
121
+ 逻辑审计发现的连线错误必须精确删除(删 edge ID,不动正确边);不要图省事把整个节点或全部边清空重连。每次删边/加边后必须重新读画布、重复同一份审计表直到 wired 集合等于期望集合。
43
122
 
44
123
  ## 生成后自我审计
45
124
 
46
125
  每批生成完成后必须主动审计,不等待用户指出问题,也不能用 `task wait` 成功代替审计:
47
126
 
48
- 1. 重新读取任务、画布、节点、连线和资产,确认所有任务处于成功终态,预期产物真实存在,selected version、输入引用和自动创建的下游节点没有错位、遗漏或重复。
127
+ 1. 重新读取任务、画布、节点、连线和资产,确认所有任务处于成功终态,预期产物真实存在,selected version、输入引用和自动创建的下游节点没有错位、遗漏或重复;分镜图片还必须重新执行“分镜素材连线门禁”和“分镜逻辑审计”,确认任务实际使用的上游版本包含全部期望参考、且没有误连的资源。
49
128
  2. 对照执行前确认值核对节点最终有效配置:视觉素材默认或显式画幅正确,视频生成时长符合 `5/10/15` 秒档位,模型、分辨率、质量、布局和格数没有被继承值意外覆盖。
50
129
  3. 实际查看图片/视频/音频预览;核对人物身份、场景、道具、动作顺序、构图、连续性,以及黑帧、拉伸、裁切、破音、空结果等明显缺陷。能从资产元数据取得的画幅和时长必须与配置交叉核对。
51
130
  4. 输出简短审计结论,逐项列出通过项、缺陷、失败项和未决项。只读即可确认的问题直接补查;涉及再次付费生成、改选版本或覆盖用户内容时先展示问题并取得确认。自我审计不能替代用户选版和阶段确认。
52
131
 
53
- ## TTS 与声音克隆
132
+ ## TTS、声音设计与声音克隆
54
133
 
55
- 语音交付使用 `audio`、`voice-clone` 和 `tts` 节点,并以服务端实时节点目录为准:
134
+ 语音交付使用 `audio`、`voice-design`、`voice-clone` 和 `tts` 节点,并以服务端实时节点目录为准:
56
135
 
57
- 1. 先执行 `canvas settings get` 和 `canvas node types --json`,确认最终生效的 `audioModel`、`tts.configSchema`、`voice-clone.configSchema` 及端口。不要根据百炼网页文档猜测当前服务已支持的字段或音色。
136
+ 1. 先执行 `canvas settings get` 和 `canvas node types --json`,确认最终生效的 `audioModel`、`tts.configSchema`、`voice-design.configSchema`、`voice-clone.configSchema` 及端口。不要根据百炼网页文档猜测当前服务已支持的字段或音色。
58
137
  2. `tts` 的文本通过 `text` 输入端口或 `config.text` 提供;音色通过 `tts.voice` 连线或 `config.voice` 提供。连线音色优先于手填值,并使任务采用该克隆产物记录的精确 CosyVoice 目标模型。执行前必须回读画布,确认文本、音色和最终 `audioModel` 一致。
59
138
  3. `cosyvoice-v3.5-plus` 与 `cosyvoice-v3.5-flash` 只接受声音设计或声音克隆生成的同型号音色 ID,不接受 `longxiaochun`、`longxiaochun_v3` 等系统预置音色名,也不能混用其他 CosyVoice 型号的 ID。违反该约束会在供应商请求前返回 `COSYVOICE_TTS_CUSTOM_VOICE_REQUIRED:<model>`;不要通过反复更换预置音色重试。
60
- 4. 需要克隆时,先创建或绑定含已授权参考音频的 `audio` 节点,再创建 `voice-clone`,连接 `audio.audio voice-clone.audio`。按实时 schema 确认 `prefix`、`targetModel`、`languageHints`、`maxPromptAudioLength` 和 `enablePreprocess`;`prefix` 只含字母和数字且不超过 10 位,参考音频截取范围为 3~30 秒。声音克隆会创建远端资源,任务不自动重试;失败时先检查输入,不得盲目重复执行。
61
- 5. 运行 `voice-clone` 后取得真实任务 ID 并执行 `task wait`。成功后刷新画布,确认产物包含非空音色 ID 和与 `targetModel` 对应的模型键,再连接 `voice-clone.voice tts.voice`。不得预先猜测音色 ID,也不要把任务 ID、节点 ID 或预置音色名当作音色 ID。
62
- 6. CosyVoice `tts` 只写实时 schema 声明的 `languageHints`、`format`、`sampleRate`、`volume`、`cosyRate`、`pitch` `instruction`。默认值通常为 WAV、24000 Hz、音量 50、语速 1、音调 1;最终仍以实时 schema 为准。`instruction` 只用于 schema 和有效模型共同允许的型号,最多 100 个计权字符,汉字按 2 个计算。非 CosyVoice 模型使用 `rate`,不得同时套用 CosyVoice 参数。
63
- 7. 运行 `tts` 后必须等待任务终态并刷新资产,实际试听音频,检查空音频、破音、语言、音色、语速、音调和时长。任务失败时先按错误码修正:`*_VOICE_ID_REQUIRED` 表示音色缺失,`COSYVOICE_TTS_CUSTOM_VOICE_REQUIRED:<model>` 表示 v3.5 音色来源或型号错误,`COSYVOICE_TTS_INSTRUCTION_TOO_LONG` 表示声音指令超限,`COSYVOICE_TTS_LANGUAGE_HINT_UNSUPPORTED:<language>` 表示语言提示不兼容;只有供应商临时错误才按任务的 `retryable` 判断是否重试。
139
+ 4. 需要设计声音时创建 `voice-design`,通过 `prompt` 输入或配置提供声音描述,并按实时 schema 确认 `previewText`、`prefix`、`targetModel` 和 `languageHints`。运行后取得真实任务 ID 并执行 `task wait`;成功后刷新画布,连接 `voice-design.voice tts.voice`。
140
+ 5. 需要克隆时,先创建或绑定含已授权参考音频的 `audio` 节点,再创建 `voice-clone`,连接 `audio.audio voice-clone.audio`。按实时 schema 确认 `prefix`、`targetModel`、`languageHints`、`maxPromptAudioLength` `enablePreprocess`;`prefix` 只含字母和数字且不超过 10 位,参考音频截取范围为 3~30 秒。声音克隆会创建远端资源,任务不自动重试;失败时先检查输入,不得盲目重复执行。
141
+ 6. 运行 `voice-clone` 后取得真实任务 ID 并执行 `task wait`。成功后刷新画布,确认产物包含非空音色 ID 和与 `targetModel` 对应的模型键,再连接 `voice-clone.voice tts.voice`。不得预先猜测音色 ID,也不要把任务 ID、节点 ID 或预置音色名当作音色 ID。
142
+ 7. CosyVoice `tts` 只写实时 schema 声明的 `languageHints`、`format`、`sampleRate`、`volume`、`cosyRate`、`pitch` `instruction`。默认值通常为 WAV、24000 Hz、音量 50、语速 1、音调 1;最终仍以实时 schema 为准。`instruction` 只用于 schema 和有效模型共同允许的型号,最多 100 个计权字符,汉字按 2 个计算。非 CosyVoice 模型使用 `rate`,不得同时套用 CosyVoice 参数。
143
+ 8. 运行 `tts` 后必须等待任务终态并刷新资产,实际试听音频,检查空音频、破音、语言、音色、语速、音调和时长。任务失败时先按错误码修正:`*_VOICE_ID_REQUIRED` 表示音色缺失,`COSYVOICE_TTS_CUSTOM_VOICE_REQUIRED:<model>` 表示 v3.5 音色来源或型号错误,`COSYVOICE_TTS_INSTRUCTION_TOO_LONG` 表示声音指令超限,`COSYVOICE_TTS_LANGUAGE_HINT_UNSUPPORTED:<language>` 表示语言提示不兼容;只有供应商临时错误才按任务的 `retryable` 判断是否重试。
64
144
 
65
- Meme 推荐链路为 `text.text → meme-scene-analysis.story`,运行后把自动生成的计划资源连接到 `meme-material-search.plan`,再把素材包资源连接到 `cat-meme-video.materials`;原故事仍连接 `cat-meme-video.story`,计划资源可同时连接 `cat-meme-video.plan`。每一步完成后刷新画布,使用服务端自动创建的资源节点,不能伪造或重复创建资源。`cat-meme-video` 的 `config` 需按实时 schema 确认 `aspectRatio`(`1:1`、`9:16` 或 `16:9`)与 `resolution`(`720p` 或 `1080p`);它们是节点输出参数,不替代项目配置门禁。
145
+ ## Meme 专属流程门禁
146
+
147
+ 用户要求制作 Meme 视频时,默认且标准的成片链路必须使用 `meme-scene-analysis` → `meme-material-search` → `cat-meme-video` 专属节点。禁止静默使用 `storyboard-breakdown`、`storyboard-image`、`storyboard-video-prompt` 或通用 `video-generate` 代替,也不得因为项目配置中存在 Seedance 等 `videoModel` 就调用视频生成模型。只有用户明确要求生成式视频路线,并在得知画风、费用和流程变化后再次确认,才可改走通用视频生成。
148
+
149
+ 标准连线为 `text.text → meme-scene-analysis.story`;分析成功后刷新画布,复用自动创建的 `meme-material-search` 和计划资源;素材检索成功后再次刷新,复用自动创建的 `cat-meme-video` 和素材包资源。最终应包含素材包资源 `.text → cat-meme-video.materials`、原故事 `.text → cat-meme-video.story`,以及计划资源 `.text → cat-meme-video.plan`。不得手工重复创建自动下游节点或资源。`cat-meme-video` 使用分析模型、内置猫素材/背景/BGM 与 FFmpeg 合成,输出由节点自身 `aspectRatio` 和 `resolution` 决定,不使用项目 `videoModel` 或通用 `videoResolution` 触发 Seedance。
150
+
151
+ 即使用户明确不使用外部素材,也必须运行 `meme-material-search`:Pexels 可保持关闭,节点仍会解析内置背景和内置道具,并对库外必显道具调用图片模型生成。运行后检查素材包的缺失项;每个 `mustShow` 道具必须存在当前可用素材或可复用的同名合格素材,才可运行视频节点。不要为了绕过缺失道具而擅自删改剧情。
152
+
153
+ 遇到 `CAT_MEME_REQUIRED_PROP_MISSING` 时回到素材检索补齐道具;遇到 `CAT_MEME_DISPLAY_CONTENT_REQUIRED` 时修复场景计划中的屏幕内容;遇到 `CAT_MEME_FFMPEG_FAILED` 时报告渲染器错误并在修复或部署后重试。任何失败都不得在未获用户确认时自动切换到通用 `video-generate`。`cat-meme-video` 的 `config` 仍需按实时 schema 确认 `aspectRatio`(`1:1`、`9:16` 或 `16:9`)与 `resolution`(`720p` 或 `1080p`)。
66
154
 
67
155
  详细命令按需读取 [references/commands.md](references/commands.md),或运行 `ai-short-studio <topic> --help`。
68
156
 
@@ -72,6 +160,14 @@ Meme 推荐链路为 `text.text → meme-scene-analysis.story`,运行后把自
72
160
 
73
161
  任务涉及剪辑设计或实现、Remotion composition、时间线、裁切、字幕、转场、音频编排或渲染时,必须先加载并遵循 `remotion-best-practices`,再把 VVICAT 已确认的视频、图片和音频资产用于剪辑。该 Skill 不可用时先请用户安装,不得凭零散的 Remotion 知识自行设计剪辑流程;纯素材生成无需加载。
74
162
 
163
+ ## 无限画布成片与交付
164
+
165
+ - 开始或恢复操作时先读取最新画布、settings 和节点 schema;用 `canvas node edit-shot` 编辑 `storyboard-shot`,每次追加不可变版本,并核对 `selectedOutputVersionId`,不得覆盖历史版本。
166
+ - 在 `canvas settings get` 后让用户确认 `outputLanguage` 为自动、`zh` 或 `en`;变化只把拆镜、视频提示词、TTS 和视频节点标为 stale,不删除资产、不清除选版、不自动重跑。试听原生配音并核对语言;节点显式 `languageHints` 优先。
167
+ - 戒指等实体必须进入镜头 `props`。肢体仅在剧情需要时出现,并在画面中可见归属于人物;纯道具镜头不得凭空增加手、手套、人物或 UI。上游变化后只按 stale 链路重跑,历史版本继续保留。
168
+ - 视频输入按模型实时能力选择严格首尾帧、普通首帧图生视频或多图参考;`video-frame-extract` 与连续性关系先展示建议,用户确认后才写入,另行确认后才执行任务。
169
+ - 原始视频交付只下载每镜已选中的 MP4,按镜号命名 `S001.mp4`、`S002.mp4`……;字幕在编排/交付层单独生成,不烧录进原始视频。`manifest` 每行至少记录 `shotNumber`、`nodeId`、`assetId`、`versionId`、`fileName`,不得混入分镜图、音频中间件或烧录字幕版本。
170
+
75
171
  ## 安全边界
76
172
 
77
173
  - 不把密码、access token、refresh token 或 API Key 放入参数、日志、Skill 或仓库。
@@ -82,7 +178,9 @@ Meme 推荐链路为 `text.text → meme-scene-analysis.story`,运行后把自
82
178
  - `config get` 只应返回 `hasApiKey`,不得依赖或要求服务端回显密钥。
83
179
  - `project provider get` 只返回配置状态。`project provider set` 的 JSON 必须来自安全 stdin 或不入库的临时秘密文件,禁止把 Key 写进命令参数、仓库文件或会回显的 shell 历史。
84
180
  - 删除用户既有项目、覆盖完整画布或修改模型配置前,先明确目标和影响;没有授权就停在读取或生成变更计划。
85
- - `canvas apply` 只用于节点、连线、视口等低层图补丁,不能代替 `canvas settings set`。项目配置遇到 409 时必须重新读取和确认。
181
+ - `canvas apply` 只用于节点、连线、视口等低层图补丁,不能代替 `canvas settings set`。CLI 保存显式请求完整画布响应;正常保存不额外预读全图,遇到 409 才重新读取、合并并确认后重试。项目配置遇到 409 时也必须重新读取和确认。
182
+ - 编辑 `storyboard-shot` 必须使用 `canvas node edit-shot`。该命令追加人工资产版本并固定选版,不允许修改 `shotKey`、`shotIndex` 或来源身份;409 后重新读取镜头版本再确认,不能覆盖历史版本。
183
+ - 提取视频首帧或尾帧时先从实时目录确认 `video-frame-extract`,配置 `{"position":"first"}` 或 `{"position":"last"}`。新节点按实时能力选择严格首尾帧、普通首帧图生视频或多图参考;未声明新版语义的历史节点保持旧参考图行为。连续性和拆格关系必须先展示建议,只有用户确认后才能写入;创建节点或连线不等于执行或付费,运行前仍须确认。
86
184
 
87
185
  ## 示例
88
186
 
@@ -120,3 +218,25 @@ ai-short-studio canvas node list --project "$PROJECT_ID" --json
120
218
  - 任务成功就直接交付:每批生成后必须重新读取状态与资产、核对配置并实际查看产物,输出审计结论后才能继续。
121
219
  - 下载列表中的任意 URL:先确认资产的 selected version,再下载。
122
220
  - 测试创建资源但未清理:用调用方的 `finally`/trap 删除唯一前缀项目。
221
+ - 道具三视图未连入分镜图:仅把 `prop-resource` 文字连到 `storyboard-breakdown` 不够;必须让每个 `prop-turnaround` 产出的 `image-resource`(三视图 PNG)按镜实际出现连到对应 `storyboard-image.reference`。人物/场景会自动物化连线,道具链路当前(0.1.26)有缺漏:连线门禁必须同时数三类素材(人物/场景/道具)从各自 turnaround/image 节点走到 storyboard-image reference 的边数;道具边数显著少于人物/场景时即物化 bug,按本文“分镜素材连线门禁”补齐。
222
+ - 误以为道具资源 name 写得克制 = 分镜里就会克制:`prop-resource` 文字 description 被直接喂给图像模型,`无装饰/朴素/光面/克制到无特征` 这类词会让道具画成无记忆点的几何体(例如方形金器变砖块/花瓶/随机金色器物)。文字应描述具体但不奢华的工艺语言(手工锤纹、抽象几何线刻、小型器耳/饰钮等),明确“不是光面金属块”;视觉圣经的“克制奢华”不等于“无装饰”。在 prop-turnaround 提示词里必须写清器型、可识别的工艺细节和家族特征(如呼应母题的小型饰钮),否则关键道具的连续性和辨认度会崩溃。
223
+ - 把 breakdown output 的 props 字段当作一定存在:shot JSON 可能只有 `characters`/`location` 而缺 `props` 字段。不能因为结构字段缺失就判定道具没出现;必须同时扫 `description`、`video_prompt` 和 `photographyPlan` 中出现的道具关键词(金器/胸针/平板/藏册/证章/牌/记录/报道等)来建立镜头→道具映射,再据此补 reference 边。匹配唯一后再写边;简称、同名、真假版本无法唯一映射时询问用户。
224
+ - 道具 turnaround 串错链路:检查 `prop-turnaround` 不得有到 `location-image`、其他 `prop-turnaround` 或非图片资源的出边;发现跨类型/互连边立即删除。修复只删精确 edge ID,不影响其他连线。
225
+ - CosyVoice v3.5-plus 用 v2 预置音色名:`cosyvoice-v3.5-plus` 不接受 `longxiaochun/longshu/longshuo` 等 v2 预置名,传入会返回 `COSYVOICE_TTS_FAILED(400): InvalidParameter`;空 voice 会返回 `BAILIAN_VOICE_ID_REQUIRED`。v3.5-plus 只接受通过 `voice-design` 或 `voice-clone` 生成的同型号音色 ID(形如 `cosyvoice-v3.5-plus-<prefix>-...`);不要反复换预置名重试。`instruction` 长度按计权字符计(CJK 算 2、ASCII 算 1),v3.5-plus 上限 100,超长返回 `COSYVOICE_TTS_INSTRUCTION_TOO_LONG`。
226
+ - 并发跑多个 storyboard-breakdown 后误以为资产互换:任务终态成功后,必须按 shot 节点的 `parentAssetId` 和 `producerNodeId` 重新核对产出归属,不能按提交顺序假设;如果某段镜头内容与接入的 screenplay 时段不符,检查是否有历史旧版本/旧资产仍被引用,先清理 stale 节点再重跑。
227
+ - 真假/衍生道具同时独立生成:成对资源必须先生成并确认基础版(真/原版/成年/主场景),再以它的 image-resource 为 reference 跑派生版(假/复制/童年/对照场景),prompt 显式枚举“唯一允许差异”;禁止两版并行独立生成后靠文字 prompt 保持一致。
228
+ - 母题元素被画成具象物:剧本里的隐喻(如猎隼、家族纹章)在视觉圣经里通常要求“抽象几何、非宗教、非具象”,但图像模型会把“隼/鹰/鸟”强先验画成具象猛禽头/羽毛/眼睛。prompt 里必须避免动物名词,改用形状描述(“向上勾起的逗号形/弯勾饰片”)并在 negative 中列“眼睛/喙/羽毛/真实鸟头”。
229
+ - 同名/多版本资源漏审:同一角色可能存在 character-design 与 character-visual-design 两个 resource,审计 reference 覆盖时必须并集所有同名资源的图片产物,不能只看一个就报“缺失”。
230
+ - 镜头级素材审计靠抽样:几十镜量级下也必须全量审计每个 shot 的 reference 集与镜中素材对比,不能抽样或只抽查前几镜;脚本化比对三类素材(人物/场景/道具)reference 边数应不低于镜中素材出现次数。
231
+ - 关键词匹配没做场景/真假消歧:道具“断环标记”同时出现在平板和竞拍牌上、“金器”同时指真品和赝品、“努尔”同时指成年和童年版本,不能靠单个关键词命中就连线;必须结合 location(会议室vs电梯)、真假关键词(三印/04 vs 两印/07)、景别和叙事上下文判定,否则会出现“平板镜连竞拍牌”“成年镜连童年资源”等跨串。
232
+ - 黑场/字幕/空镜连了道具或场景:纯黑开场、静默黑场、片名落版、全声音无画面等镜,不能连任何 image-resource/prop/location,否则模型会强行画东西破坏空镜。
233
+ - 龙套镜引用了主角资源:拍卖师、工作人员、路人、独立鉴定人等无名角色如果没有独立 character-resource,要在 storyboard-image 的 prompt 里写明“非主角脸”,不能让角色边指向努尔/拉希德/奥马尔的三视图,否则会把龙套画成主角的脸。
234
+ - 纸本叠化/交接簿/报告等临时物件强绑到实体道具:蒙太奇里的纸页、文件、报告、现场封袋如果不是预定义道具,不要误连平板/藏册等实体;这些是程序戏不是具体道具。
235
+ - 删错边用“全清重连”代替精确删 edge ID:发现误连边时要精确删具体 edge ID,不要批量清空相关节点连线或重建节点;重连会丢失用户手工调整过的连线,且增加二次错误风险。
236
+ - 改了道具/人物/场景 turnaround 后忘了旧 description 会打架:如果在分镜图生成后更新了道具设定(例如把“方形金质砝码”改成“带盖礼器+勾形饰钮”),`storyboard-shot` 的 description 仍是 breakdown 阶段的旧文字(asset 不可直接编辑),图像模型会在旧文字(砝码)和新参考图(方盒)之间冲突,表现为反复重跑都画回旧造型。必须在受影响镜的 `storyboard-image.prompt` 里写显式覆盖(“忽略 description 里的 X,按参考图绘制 Y,四个特征逐条列出”),不要只靠参考图。重跑节点产生新 id 后,之前加的参考边也会丢,要重新连。
237
+ - 极端远景/微距交替镜的小物体先验太强:当镜次构成为“远景展柜里小物体 + 微距局部”时,GPT-Image-2 容易把物体画成光面几何块(即使 prompt 强调饰钮/纹饰);这是分镜草图阶段的已知极限,不要无限迭代。中近景/中景(物体占画面 ≥1/4)的构图能稳定拿到正确造型;远景镜可以接受,到 `video-generate` 阶段通过 motion prompt(推近到顶部饰钮、运镜覆盖关键特征)保证最终视频帧里造型正确。
238
+ - 极端特写/物证镜忘记补人物 reference:`characters` 字段为空但画面里会露出手、眼、肩等身体部位(胸针压痕镜有努尔手指、金器微距带白手套、证章特写带手部)时,必须把对应人物的三视图 image-resource 作为 reference 连入,否则手指/手部会画成第三人称或数量错误。
239
+ - 关联镜头没互加 reference:匹配切、叠化、连续推轨、正反打、同一动作多镜等强关联镜组,应该把前后镜的 storyboard-image 互作为 reference,保证构图/光线/道具位置连续;不能只单独看每镜自己的人物/场景/道具 reference。
240
+ - 只做单镜审计不做时序审计:镜头间的人物位置跳跃、道具状态不连贯、色温跳变、视线失配、无桥硬切,必须按 shotKey 顺序逐对相邻镜核对;几十镜量级全量成本仍低,漏检代价高。
241
+ - 把图像模型先验问题留到视频阶段不做记录:“面具买家”会被画眼罩、“竞拍牌”会被加数字、“隼”会被画成具象猛禽,这些必须在视频生成前列成 negative 清单写入 video-generate prompt,不能只依赖分镜图阶段的 negative。
242
+ - 道具文字设定只连到 breakdown 就以为够了:`prop-resource` 必须像 `character-resource`/`location-resource` 一样,除连到 `prop-turnaround` 和 `storyboard-breakdown` 外,按镜中出现把文字节点连到对应 `storyboard-shot.props` 和 `storyboard-image.props`;否则 shot/image 阶段只能看到三视图 PNG,拿不到编号、印记或 negative 约束等文字设定,分镜图会出现牌面画数字、印记形状错误等连续性 bug。审计时必须单独统计三类资源到 shot 和到 image 的文字边数,要求三类分布对称;道具边数为零而人物/场景大量存在时即为异常。
@@ -66,6 +66,7 @@ ai-short-studio canvas settings get --project "$PROJECT_ID" --json
66
66
  ai-short-studio canvas settings set --project "$PROJECT_ID" --field aspectRatio --value 9:16 --json
67
67
  ai-short-studio canvas settings set --project "$PROJECT_ID" --field artStyle --value "$ART_STYLE_ID" --json
68
68
  ai-short-studio canvas settings set --project "$PROJECT_ID" --field imageResolution --value 2K --json
69
+ ai-short-studio canvas settings set --project "$PROJECT_ID" --field outputLanguage --value en --json
69
70
  ai-short-studio canvas settings set --project "$PROJECT_ID" --file settings.json --json
70
71
  ```
71
72
 
@@ -101,6 +102,7 @@ ai-short-studio canvas node list --project <projectId> --json
101
102
  ai-short-studio canvas node get <nodeId> --project <projectId> --json
102
103
  ai-short-studio canvas node add <kind> --project <projectId> [--x N] [--y N] [--title <text>] [--config <config.json>] --json
103
104
  ai-short-studio canvas node update <nodeId> --project <projectId> --config <config.json> --json
105
+ ai-short-studio canvas node edit-shot <nodeId> --project <projectId> [--file <shot.json>] --json
104
106
  ai-short-studio canvas node delete <nodeId> --project <projectId> --yes --json
105
107
  ai-short-studio canvas node run <nodeId> --project <projectId> --json
106
108
  ```
@@ -115,9 +117,36 @@ ai-short-studio canvas edge add --project <projectId> --from <sourceNodeId>:<sou
115
117
  ai-short-studio canvas edge delete <edgeId> --project <projectId> --yes --json
116
118
  ```
117
119
 
120
+ 网页增量保存使用 `Prefer: return=minimal` 获取固定大小回执;CLI 的后续命令依赖完整画布,因此显式使用 `Prefer: return=representation`。正常保存前不额外读取全图;发生 409 时重新读取最新画布、合并本地补丁并确认后重试。
121
+
122
+ `canvas node edit-shot` 的文件或 stdin 内容是镜头字段对象。命令读取当前画布版本和当前资产选版后追加一个人工 DOCUMENT 版本;`shotKey`、`shotIndex` 和来源身份不可修改,旧版本不会被覆盖或删除。
123
+
124
+ 首尾帧提取使用实时目录中的 `video-frame-extract`,配置为 `{"position":"first"}` 或 `{"position":"last"}`。输入连接 `video`,输出 `image` 是独立 IMAGE 资产版本并记录来源视频版本。新视频节点按实时 capability 选择严格首尾帧、普通首帧图生视频或多图参考;历史节点保留旧语义。连续性与拆格建议需用户确认才写入,节点与连线创建后仍需另行确认执行,不会自动付费。
125
+
126
+ 原始视频交付先按镜号读取视频节点的 `selectedOutputVersionId`,再逐个执行 `canvas asset download`,保存为 `S001.mp4`、`S002.mp4`……。同时生成逐行 `manifest`,每行包含 `shotNumber`、`nodeId`、`assetId`、`versionId`、`fileName`。只下载 selected 原始 MP4;字幕单独交付,不混入分镜图、音频中间件或烧录字幕版本。
127
+
118
128
  handle 名称来自节点类型目录中的输入输出 schema,不要自行推断。
119
129
 
120
- Meme 推荐连线为:`text.text → meme-scene-analysis.story`、自动生成的计划资源 `.text → meme-material-search.plan`、素材包资源 `.text → cat-meme-video.materials`、原故事 `.text → cat-meme-video.story`,以及可选的计划资源 `.text → cat-meme-video.plan`。分析或检索任务成功后先刷新画布,取得服务端自动创建的真实资源节点 ID。`cat-meme-video` 的 `config` 支持 `aspectRatio: "1:1" | "9:16" | "16:9"` 和 `resolution: "720p" | "1080p"`;创建或更新节点前仍以实时 schema 为准。
130
+ ## 镜头连续性
131
+
132
+ ```bash
133
+ ai-short-studio canvas continuity analyze --project <projectId> --json
134
+ ai-short-studio canvas continuity analyze --project <projectId> --apply-ready --json
135
+ ```
136
+
137
+ 默认命令在视频生成前只读分析相邻镜头、故事板 lineage、视频模型能力和现有连线,不创建节点或任务。`dependencies` 中的 `waiting-for-source-video` 表示必须先生成上一镜;上一镜成功后再次分析,使用 `--apply-ready` 原子创建当前可用的尾帧提取节点和目标连线。它不会运行视频节点,也不能替代生成后的真实画面审计。
138
+
139
+ ### Meme 专属节点流程
140
+
141
+ Meme 视频默认使用 `meme-scene-analysis` → `meme-material-search` → `cat-meme-video`,禁止静默改用 `storyboard-*` 或通用 `video-generate`。项目中的 Seedance 等 `videoModel` 不参与 `cat-meme-video` 合成;只有用户明确要求生成式视频并确认额外费用与画风变化后,才可使用通用视频节点。
142
+
143
+ 1. 连接 `text.text → meme-scene-analysis.story`,运行并等待任务终态。
144
+ 2. 刷新画布,复用自动创建的计划资源和 `meme-material-search`;不要手工添加重复节点。
145
+ 3. 运行素材检索。即使不使用外部素材也不能跳过:Pexels 可关闭,内置背景、内置道具和库外道具图片生成仍在该节点完成。
146
+ 4. 刷新画布,复用自动创建的 `cat-meme-video`,核对原故事、计划和素材包三条输入边,并确认素材包没有无法复用的必显道具缺失项。
147
+ 5. 按实时 schema 设置节点的 `aspectRatio: "1:1" | "9:16" | "16:9"` 和 `resolution: "720p" | "1080p"`,运行并等待终态,再下载和审计真实视频。
148
+
149
+ 错误恢复固定为:`CAT_MEME_REQUIRED_PROP_MISSING` 回到素材检索;`CAT_MEME_DISPLAY_CONTENT_REQUIRED` 修复计划;`CAT_MEME_FFMPEG_FAILED` 修复或部署渲染器后重试。不得把失败当作切换通用视频生成的授权。
121
150
 
122
151
  项目级默认参数使用 `canvas settings set` 写入 `imageResolution`、`imageQuality`、`videoResolution`;候选值读取 `settings get` 对应字段的实时 `options`。通用 `image-generate`、`image-edit` 节点只在需要偏离项目默认时,才在 `config` 写入字符串 `resolution`、`quality`;`video-generate` 同理可覆盖 `resolution`。节点覆盖值必须来自当前节点模型 `capabilities`,没有对应能力声明时不写入。
123
152