@xiaohhhh1/canvas-agent 0.4.50 → 0.4.52

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.
@@ -30,13 +30,14 @@ type ReferenceStyleCard = {
30
30
  voiceTone?: unknown;
31
31
  categoryFit?: unknown;
32
32
  };
33
+ type StoryboardLayoutVersion = "director-table-scripted-v1" | "hybrid-three-anchor-v1" | "legacy-five-row-v1";
33
34
  type ScriptTask = {
34
35
  id: string;
35
36
  workflow: "flow-c";
36
37
  market: string;
37
38
  duration_seconds?: 10 | 20 | 30;
38
- storyboard_layout_version?: "hybrid-three-anchor-v1" | "legacy-five-row-v1";
39
- storyboardLayoutVersion?: "hybrid-three-anchor-v1" | "legacy-five-row-v1";
39
+ storyboard_layout_version?: StoryboardLayoutVersion;
40
+ storyboardLayoutVersion?: StoryboardLayoutVersion;
40
41
  reference_style_card?: ReferenceStyleCard;
41
42
  referenceStyleCard?: ReferenceStyleCard;
42
43
  requested_count: number;
@@ -503,7 +503,7 @@ class ExpiredCapabilityError extends Error {
503
503
  }
504
504
  export function scriptChunkPrompt(id, task, ordinals) {
505
505
  const duration = Number(task.duration_seconds || 10);
506
- const layoutVersion = task.storyboard_layout_version || task.storyboardLayoutVersion || "hybrid-three-anchor-v1";
506
+ const layoutVersion = task.storyboard_layout_version || task.storyboardLayoutVersion || "director-table-scripted-v1";
507
507
  const styleCard = compactReferenceStyleCard(task.reference_style_card || task.referenceStyleCard);
508
508
  const durationRules = duration === 10 ? `
509
509
  本任务每条成片为 10 秒,不生成 masterScript。每条只输出一份 openingState 和一个完整 0–10 秒 segment;Agent 会从 structured shots 确定性渲染兼容顶层 script,并按 shots 顺序派生 segmentVoiceovers,模型不要生成这两个派生字段。` : `
@@ -512,10 +512,11 @@ export function scriptChunkPrompt(id, task, ordinals) {
512
512
  return `你正在后台处理“抖音小辉跨境工具”Flow C 脚本交接 ${id}。
513
513
  完整中心任务已经附在本提示词末尾。只创作 ordinal ${ordinals[0]} 到 ${ordinals.at(-1)}(精确列表:${ordinals.join(", ")})。
514
514
  本段 productIndex 必须严格按此映射填写:${scriptProductAssignments(task.product_quantities, ordinals)}。不得凭产品名称猜测或把相邻产品编号混用。
515
- 脚本质量绝不能因批量而降低:每条都必须独立构思、完整、真实合规,严格遵守任务 instructions、产品图片顺序和 productIndex;使用目标市场 ${task.market} 的自然本地语言与偏快但清晰的短视频节奏。${durationRules}
516
- 每条先按“画面先行”写 creativePlan,再写本段/总脚本。creativePlan 必须给出 visualHook、conflict、productIntervention、visibleProof、callbackMotivation、truthBoundary、differentiationKey,并在 escalation 或 turn 中至少给出一项真实成立的升级/转折;format 必须依据当前产品、市场、事实证据和真实场景适配选择。中国短剧式冲突/喜剧只能是适合时的实验路线,绝不是默认;工厂、仓库、超市等条件场景也只有在商品动作自然且不伪造来源、库存或销量证据时才可选,不能固定轮换。
515
+ 脚本质量绝不能因批量而降低:每条都必须独立构思、完整、真实合规,严格遵守任务 instructions、产品图片顺序和 productIndex;使用目标市场 ${task.market} 的自然本地口播与偏快但清晰的短视频节奏。${durationRules}
516
+ 每条先按“画面先行”写 creativePlan,再写本段/总脚本。creativePlan 必须给出 visualHook、conflict、productIntervention、visibleProof、callbackMotivation、truthBoundary、differentiationKey,并在 escalation 或 turn 中至少给出一项真实成立的升级/转折;format 必须依据当前产品、市场、事实证据和真实场景适配选择。另必须完成视觉磁力设计:firstFrameFocus(第一眼唯一注意物)、visualContrast(明暗/冷暖/大小/前后状态反差)、sensoryTexture(当前品类真正可见或可听的材质感官证据)、motionPeak(最有张力的动作瞬间)、compositionLighting(景别、层次、主体分离和光线方向)、localNativeDetail(目标市场原生环境/动作/拍摄习惯)、antiFlatness(明确禁止的平淡摆拍方式)。食品应优先真实热气、汁水、断面、酥脆、拉丝、挤压回弹等可验证食欲线索;工厂应优先规模、同步运动、材料变化、机械接触和成品揭示;其它品类按真实材质与使用动作动态选择,绝不能套用不相关感官词。中国短剧式冲突/喜剧只能是适合时的实验路线,绝不是默认;工厂、仓库、超市等条件场景也只有在商品动作自然且不伪造来源、库存或销量证据时才可选,不能固定轮换。
517
517
  styleCardSummary 只使用已缓存的压缩风格卡,没有就明确写“无”;不要分析、读取或转录原始参考视频。每条只生成一份 voiceProfile(性别、年龄感、音高、音质、语速、口音、停顿习惯、情绪基调),所有局部段共同引用它;每段仅用简短 voiceCue 表达情绪变化,不复写整套音色。
518
- 每个 segment 必须有完整 0–10 秒 shots、voiceCue 和 endingState;不要让模型生成 continuityMode 或 continuity。每个 shot 都包含画面、准确本地口播、可控屏幕字、商品证据、soundBgm 与 emotionalNotequalityGate 必须逐项用具体证据核对强钩子、冲突、升级/转折、商品介入、可见证明、开头回扣购买动机、事实边界与批内差异,禁止用“已满足”空话。
518
+ 每个 segment 必须有完整 0–10 秒 shots、voiceCue 和 endingState;不要让模型生成 continuityMode 或 continuity。镜头数由本条剧情实际需要决定(契约允许 1–8 个),不得为了故事板版式强行固定为三个或五个。每个 shot 都包含画面、准确本地口播、可控屏幕字、商品证据、soundBgm 与 emotionalNote;shot.visual 必须把本镜头对应的主体位置/景别、光线与颜色分离、材质细节、动作峰值和当地原生环境写成可直接画出的指令,并加入适合该场景的真实捕捉痕迹(例如自然肤色与毛孔、细发、真实布料褶皱/起毛、生活使用痕迹、混合实景光或轻微传感器颗粒),不能只写“展示商品”“人物试用”或“工厂生产”。不得把真实感写成脏污、损坏商品或刻意低清。qualityGate 仍只核对脚本事实与创意完整性,不新增“普通画面自动打回”或额外生成循环。
519
+ 【回传语言契约】为了让导演故事板稳定可读,creativePlan、masterScript 中的导演/剧情说明、voiceProfile、qualityGate、openingState、voiceCue、endingState,以及每个 shot 的 visual、evidence、soundBgm、emotionalNote 必须用清晰简洁的制作英文。每个 shot.voiceover 必须逐字使用目标市场 ${task.market} 的自然当地语言,不得翻译成英文;onScreenText 若画面确实需要展示文字,则写目标市场当地语言的准确短文案,否则写英文 NONE。不得在英文导演字段里混入另一份口播或全局时轴。
519
520
  每条 differentiationKey 必须在带货形式、第一眼画面、剧情骨架、痛点/反差、商品证明和口播气质上与本批其他条目显著不同,不能只换措辞。
520
521
  本脚本回合固定使用 GPT-5.6 Terra 高推理;不要建议换低档模型或降低推理。故事版布局由中心顶层 storyboardLayoutVersion=${layoutVersion} 管理,不要让模型选择,也不要把它重复进每条 job。
521
522
  【已缓存压缩的参考 style card】${styleCard || "无参考风格卡"}【style card 结束】
@@ -26,6 +26,13 @@ function creativePlanSchema() {
26
26
  const properties = {
27
27
  format: text,
28
28
  visualHook: text,
29
+ firstFrameFocus: text,
30
+ visualContrast: text,
31
+ sensoryTexture: text,
32
+ motionPeak: text,
33
+ compositionLighting: text,
34
+ localNativeDetail: text,
35
+ antiFlatness: text,
29
36
  conflict: text,
30
37
  escalation: nullableText,
31
38
  turn: nullableText,
@@ -181,8 +188,8 @@ function segmentVoiceoverLines(segmentValue) {
181
188
  return shots.map((shot) => String(shot.voiceover || "").trim()).filter((line) => line && !/^(none|无|sin voz|sin diálogo)$/i.test(line));
182
189
  }
183
190
  function continuityFromOpeningState(openingState) {
184
- const continuity = Object.fromEntries(continuityFields.map((field) => [field, openingState?.[field] || "由本段首镜建立"]));
185
- continuity.previousEndingFrame = openingState?.openingFrame || "本段首镜";
191
+ const continuity = Object.fromEntries(continuityFields.map((field) => [field, openingState?.[field] || "Established by the opening shot"]));
192
+ continuity.previousEndingFrame = openingState?.openingFrame || "Opening shot of this segment";
186
193
  return continuity;
187
194
  }
188
195
  /**
@@ -197,11 +204,11 @@ function withLegacySegmentScript(segmentValue, segmentIndex, segmentCount, voice
197
204
  const shots = Array.isArray(segment?.shots) ? segment.shots.map(recordOf).filter((shot) => Boolean(shot)) : [];
198
205
  if (!segment || !continuity || !endingState || !shots.length)
199
206
  return segmentValue;
200
- const context = `人物:${continuity.character};服装:${continuity.wardrobe};地点:${continuity.location};光线:${continuity.lighting};商品状态:${continuity.productState};承接动作:${continuity.unfinishedAction};本段目标:${continuity.nextGoal};上一段结尾画面:${continuity.previousEndingFrame}`;
201
- const ending = `人物:${endingState.character};服装:${endingState.wardrobe};地点:${endingState.location};光线:${endingState.lighting};商品状态:${endingState.productState};未完成动作:${endingState.unfinishedAction};下一段目标:${endingState.nextGoal};本段结尾画面:${endingState.endingFrame}`;
202
- const voice = voiceProfile ? `性别:${voiceProfile.gender};年龄感:${voiceProfile.ageImpression};音高:${voiceProfile.pitch};音质:${voiceProfile.timbre};语速:${voiceProfile.speakingRate};口音:${voiceProfile.accent};停顿习惯:${voiceProfile.pauseHabit};情绪基调:${voiceProfile.emotionalBaseline}` : "沿用本条共同音色档案";
203
- const timeline = shots.map((shot, index) => `镜头 ${index + 1}|${shot.startSeconds}–${shot.endSeconds} 秒|画面:${shot.visual}|口播:${shot.voiceover}|屏幕字:${shot.onScreenText}|证据:${shot.evidence}|声音/BGM:${shot.soundBgm}|情绪:${shot.emotionalNote}`).join("\n");
204
- return { ...segment, script: `Flow C 独立分段 ${segmentIndex + 1}/${segmentCount}\n局部时轴:010 秒;不得引用或绘制总片时间轴。\n共同音色档案:${voice}\n本段音色提示:${segment.voiceCue}\n本段起始连续性:${context}\n${timeline}\n本段结束状态:${ending}` };
207
+ const context = `CHARACTER: ${continuity.character}; WARDROBE: ${continuity.wardrobe}; LOCATION: ${continuity.location}; LIGHTING: ${continuity.lighting}; PRODUCT STATE: ${continuity.productState}; INHERITED ACTION: ${continuity.unfinishedAction}; SEGMENT GOAL: ${continuity.nextGoal}; PREVIOUS ENDING FRAME: ${continuity.previousEndingFrame}`;
208
+ const ending = `CHARACTER: ${endingState.character}; WARDROBE: ${endingState.wardrobe}; LOCATION: ${endingState.location}; LIGHTING: ${endingState.lighting}; PRODUCT STATE: ${endingState.productState}; UNFINISHED ACTION: ${endingState.unfinishedAction}; NEXT GOAL: ${endingState.nextGoal}; ENDING FRAME: ${endingState.endingFrame}`;
209
+ const voice = voiceProfile ? `GENDER: ${voiceProfile.gender}; AGE IMPRESSION: ${voiceProfile.ageImpression}; PITCH: ${voiceProfile.pitch}; TIMBRE: ${voiceProfile.timbre}; SPEAKING RATE: ${voiceProfile.speakingRate}; ACCENT: ${voiceProfile.accent}; PAUSE HABIT: ${voiceProfile.pauseHabit}; EMOTIONAL BASELINE: ${voiceProfile.emotionalBaseline}` : "Use the shared voice profile for this video";
210
+ const timeline = shots.map((shot, index) => `SHOT ${index + 1} | ${shot.startSeconds}-${shot.endSeconds}s | VISUAL: ${shot.visual} | VO: ${shot.voiceover} | ON-SCREEN TEXT: ${shot.onScreenText} | EVIDENCE: ${shot.evidence} | SOUND/BGM: ${shot.soundBgm} | EMOTION: ${shot.emotionalNote}`).join("\n");
211
+ return { ...segment, script: `FLOW C INDEPENDENT SEGMENT ${segmentIndex + 1}/${segmentCount}\nLOCAL TIMELINE: 0-10 seconds only. Never reference or draw a full-video timeline.\nVOICE PROFILE: ${voice}\nSEGMENT VOICE CUE: ${segment.voiceCue}\nOPENING CONTINUITY: ${context}\n${timeline}\nENDING STATE: ${ending}` };
205
212
  }
206
213
  function recordOf(value) {
207
214
  return value && typeof value === "object" && !Array.isArray(value) ? value : null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xiaohhhh1/canvas-agent",
3
- "version": "0.4.50",
3
+ "version": "0.4.52",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",