@xiaohhhh1/canvas-agent 0.4.60 → 0.4.62

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.
@@ -8,6 +8,7 @@ import { videoEvidenceTimestamps } from "../integrations/fastmoss.js";
8
8
  const ANALYSIS_TIMEOUT_MS = 10 * 60_000;
9
9
  const TRANSCRIPT_LANGUAGES = "en.*,es.*,zh.*,pt.*,fr.*,de.*,vi.*,th.*,id.*,ms.*,ja.*,ko.*";
10
10
  const LOCAL_ASR_MODEL = "onnx-community/whisper-base";
11
+ const VIDEO_INTELLIGENCE_SCHEMA_VERSION = "commerce-video-intelligence-v5";
11
12
  let localAsrPipeline;
12
13
  export function shouldUploadVideoArchive(input, publicUrl) {
13
14
  return input.kind !== "uploaded-mp4" || input.url !== publicUrl;
@@ -153,11 +154,11 @@ export function localVideoAnalysisPrompt(source, durationMs, transcript, attachm
153
154
  durationMs,
154
155
  })}\n\n` +
155
156
  `带时间码的口播字幕:\n${transcript}\n\n` +
156
- `只返回一个 JSON 对象,不要 Markdown。字段必须是:schemaVersion="commerce-video-intelligence-v3";durationMs;language;summary;` +
157
+ `只返回一个 JSON 对象,不要 Markdown。字段必须是:schemaVersion="${VIDEO_INTELLIGENCE_SCHEMA_VERSION}";durationMs;language;summary;` +
157
158
  `sellingFormat{primary,label,secondary,rationale,evidence[{startMs,endMs,observation}],confidence};` +
158
159
  `hook{startMs,endMs,visual,spokenText,onScreenText,patternInterrupt,openLoop};productFirstSeenMs;` +
159
160
  `segments[{startMs,endMs,role,visual,spokenText,onScreenText,audio,editing,confidence}](至少2段);` +
160
- `creativeMutationProfile{coreVisualPremise,mutationAxes[至少2项],culturalSignals[{market,signal,narrativeRole,aestheticRole,transferConditions,avoidStereotype,evidence[{startMs,endMs,observation}]}],firstFrameComposition,spectacleMechanism,productIntegration,transferableRule,culturalLimitations,doNotCopy,evidence[{startMs,endMs,observation}],confidence};` +
161
+ `creativeMutationProfile{coreVisualPremise,mutationAxes[至少2项],culturalSignals[{market,signal,narrativeRole,aestheticRole,transferConditions,avoidStereotype,evidence[{startMs,endMs,observation}]}],firstFrameComposition,spectacleMechanism,productIntegration,captureProfile{subjectDominance,depthAndDensity,colorLightContrast,materialTexture,cameraEnergy,captureImperfections},transferableRule,culturalLimitations,doNotCopy,evidence[{startMs,endMs,observation}],confidence};` +
161
162
  `mechanisms[{type,label,mechanism,whyItMayWork,evidence[{startMs,endMs,observation}],confidence,replicationRisk}](type 仅 hook/conflict/proof/pacing/trust/product-reveal/offer-framing/cta/audio/visual-grammar/environment/visual-mutation/culture-code/spectacle);` +
162
163
  `viralHypotheses[{hypothesis,supportingMetrics,supportingEvidence[{startMs,endMs,observation}],confounders,confidence}];` +
163
164
  `nonReplicableFactors;complianceRisks;originalityGuidance{preserveMechanisms,mustRewrite,forbiddenCopying}。`;
@@ -1,5 +1,5 @@
1
1
  type JsonSchema = Record<string, unknown>;
2
- export declare const FLOW_C_CREATIVE_CANDIDATE_CONTRACT_VERSION = "flow-c-creative-candidates-v3";
2
+ export declare const FLOW_C_CREATIVE_CANDIDATE_CONTRACT_VERSION = "flow-c-creative-candidates-v4";
3
3
  export declare function flowCCreativeCandidateOutputSchema(count: number): JsonSchema;
4
4
  export declare function parseFlowCCreativeCandidateOutput(value: string, expectedOrdinals: number[]): Record<string, unknown>[];
5
5
  export {};
@@ -1,11 +1,13 @@
1
1
  import { assertStrictResponseSchema } from './script-output.js';
2
- export const FLOW_C_CREATIVE_CANDIDATE_CONTRACT_VERSION = 'flow-c-creative-candidates-v3';
2
+ export const FLOW_C_CREATIVE_CANDIDATE_CONTRACT_VERSION = 'flow-c-creative-candidates-v4';
3
3
  const text = { type: 'string', minLength: 1 };
4
+ const nullableText = { anyOf: [text, { type: 'null' }] };
4
5
  function object(properties) {
5
6
  return { type: 'object', properties, required: Object.keys(properties), additionalProperties: false };
6
7
  }
7
8
  function candidateSchema() {
8
9
  return object({
10
+ learnedTemplateId: nullableText,
9
11
  visualPremise: text,
10
12
  mutationAxes: { type: 'array', minItems: 2, maxItems: 4, items: text },
11
13
  culturalAnchors: {
@@ -21,6 +21,10 @@ type ScriptRecord = {
21
21
  };
22
22
  type ReferenceStyleCard = {
23
23
  id?: unknown;
24
+ templateKind?: unknown;
25
+ templateProfile?: unknown;
26
+ modelFamily?: unknown;
27
+ sourceDurationSeconds?: unknown;
24
28
  visualPremisePattern?: unknown;
25
29
  mutationAxes?: unknown;
26
30
  culturePattern?: unknown;
@@ -31,6 +35,10 @@ type ReferenceStyleCard = {
31
35
  rhythmPattern?: unknown;
32
36
  capturePattern?: unknown;
33
37
  voiceTone?: unknown;
38
+ targetDurationPolicy?: unknown;
39
+ retimingRule?: unknown;
40
+ segmentRule?: unknown;
41
+ omniAdaptation?: unknown;
34
42
  sourceEvidenceTier?: unknown;
35
43
  truthBoundaries?: unknown;
36
44
  applicability?: {
@@ -51,6 +59,7 @@ type ProductInput = {
51
59
  type SelectedCandidate = {
52
60
  ordinal: number;
53
61
  productIndex: number;
62
+ learnedTemplateId?: string | null;
54
63
  visualPremise: string;
55
64
  mutationAxes: string[];
56
65
  culturalAnchors: Array<Record<string, unknown>>;
@@ -645,22 +645,24 @@ ${compactJson([...selected.values()], 16_000)}
645
645
  ${durationRules}
646
646
  写作要求:
647
647
  1. visualHook、conflict、escalation/turn、productIntervention、visibleProof、purchaseReason、callbackMotivation 与所有 shots 必须执行选中卡的 visualPremise、firstFrame、spectacleEscalation、productProofAction、purchaseReason、truthBoundary 以及七项视觉执行字段;不得扩大功效、稀释构图或换成普通模板。productProofAction 必须同时写清一个真实动作及其镜头内可见结果;purchaseReason 只解释该结果为何值得目标用户购买,不能变成泛泛 CTA。
648
+ 1a. executionBindings 必须逐项指出 opening、proof、purchaseReason 和七项 visualExecution 实际落在哪个 segment/shot;executedAs 必须同时忠实对应 selected candidate 原要求和该 shot 的真实内容。opening 必须包含 segment 1 shot 1。它是可审计索引,不是新增剧情,也不能把未执行的要求写成已执行。
648
649
  2. 每条生成一份稳定 voiceProfile;每段只写简短 voiceCue。口播必须是目标市场 ${task.market} 的自然原生语言、偏快但清晰;导演说明统一用简洁制作英文。
649
650
  3. 每段永远是独立 0–10 秒,含 1–8 个按剧情需要决定的 shots、准确 voiceover、onScreenText、evidence、soundBgm、emotionalNote 与 endingState;模型不要输出 continuity 或 continuityMode。
650
651
  4. shot.visual 要直接写出主体位置、景别、光线、材质、动作峰值和当地自然环境,并保留真实皮肤、细发、布料/商品微纹理和实景混合光;禁止塑料蜡感、静态举产品、品牌广告片、电视购物或伪造工厂/销量/来源。
651
652
  5. 20/30 秒的后一段剧情承接前段 endingState,但每段仍只使用自己的局部 0–10 秒执行内容。
652
- 6. creativePlan 只写 format、visualHook、conflict、escalation/turn、productIntervention、visibleProof、purchaseReason、callbackMotivation 与 differentiationKey。callbackMotivation 必须自然回扣开场与已经展示的 purchaseReason;禁止编造折扣、库存、销量、价格或未提供的量化功效。Agent 会把选中卡的构图、材质、光线、文化、真实性边界和 fingerprint 确定性并回,中心会程序化计算质量门;模型不要重复这些字段。
653
+ 6. creativePlan 只写 format、visualHook、conflict、escalation/turn、productIntervention、visibleProof、purchaseReason、callbackMotivation 与 differentiationKey。callbackMotivation 必须自然回扣开场与已经展示的 purchaseReason;禁止编造折扣、库存、销量、价格或未提供的量化功效。Agent 会把选中卡的构图、材质、光线、文化、真实性边界和 fingerprint 确定性并回,中心会程序化计算质量门;模型不要重复这些字段。若 selected candidate 的 selectionMode=user-framework,用户原框架的开头、事件顺序、核心剧情和结尾是最高权威;只补真实证明、局部时序和执行细节,不得改成另一个创意。
653
654
  固定使用 GPT-5.6 Terra 高推理。storyboardLayoutVersion=${layoutVersion} 仅由中心管理。只返回当前结构化 jobs,不调用工具、不创建任何图片或视频任务。`;
654
655
  }
655
656
  export function creativeCandidatePrompt(id, task, ordinals) {
656
657
  const products = relevantProductInputs(task, ordinals);
657
- const styleCards = relevantStyleCards(task.reference_style_cards || [], products).map(compactReferenceStyleCard).filter(Boolean).slice(0, 6);
658
+ const styleCards = relevantStyleCards(task.reference_style_cards || [], products, task.market).map(compactReferenceStyleCard).filter(Boolean).slice(0, 6);
658
659
  const ledger = (task.creative_fingerprint_ledger || []).slice(-60);
659
660
  return `Flow C creative-candidate stage for handoff ${id}. Set contractVersion exactly to ${FLOW_C_CREATIVE_CANDIDATE_CONTRACT_VERSION}. Return exactly one group for each ordinal: ${ordinals.join(", ")}; mapping: ${scriptProductAssignments(task.product_quantities, ordinals)}.
660
- Market: ${task.market}. Product facts: ${compactJson(products, 12_000)}
661
+ Market: ${task.market}. Target output duration: ${Number(task.duration_seconds || 10)} seconds. Product facts: ${compactJson(products, 12_000)}
661
662
  Optional learned style abstractions: ${compactJson(styleCards, 5_000)}
662
663
  Already accepted fingerprint ledger: ${compactJson(ledger, 8_000)}
663
664
  For each ordinal return exactly 6 short, auditable candidate cards. These are visible structured alternatives, not hidden reasoning. Vary the overall creative skeleton through open dimensions such as relationship/identity, scene mismatch, scale/quantity, group reaction, viewpoint, sensory texture and proof action; do not rotate a fixed template list.
665
+ Set learnedTemplateId to the id of one supplied learned-video-structure card when its product/market fit is credible; otherwise set it to null. A fitting learned template has priority over free ideation. Preserve its hook-to-proof-to-purchase-reason causal structure, but re-time it to the current target duration instead of stretching, truncating or copying the source timeline. The template is model-neutral evidence: never output Seedance wording or source-specific people, dialogue, wardrobe, set or exact shots. The same learnedTemplateId may be used for multiple ordinals when useful, but each adapted candidate must still have truthful product-specific content, native VO intent and a meaningfully changed opening/proof execution. If the product has a non-empty user-authored creativeBrief, this candidate stage is bypassed entirely and no learned template may influence the script.
664
666
  Every card must be surprising but physically filmable and product-relevant. productProofAction must state one truthful intended-use action and the observable result that remains visible in the same scene. purchaseReason must state one concrete reason the supported result matters to a real target buyer; it is not a generic CTA and must not invent price, discount, scarcity, sales, inventory or unsupported quantified performance. productProofAction, purchaseReason and truthBoundary must follow supplied facts. For food, baby, medical/efficacy and personal-hygiene products, reject unhygienic display, fear marketing, dangerous use and unsupported promises.
665
667
  Every card must also contain a concrete visual execution card, not mood adjectives: firstFrameFocus names one dominant subject and its approximate 35%-85% frame share; visualContrast defines one readable scale/color/light/relationship contrast; sensoryTexture names truthful category-specific material evidence; motionPeak names the single peak physical instant; compositionLighting specifies foreground/midground/background, practical light direction and one plausible exposure/optical imperfection; localNativeDetail names observable local behavior/environment/aesthetic density with the same evidence discipline as culturalAnchors; antiFlatness names the exact generic catalogue treatment this concept must avoid. The firstFrame must pass a screenshot test: even without dialogue, a still image must show the unusual relationship, product relevance and depth hierarchy.
666
668
  Cultural anchors are optional (0–3). source must be learned-style-card, product-market-evidence, or conservative-everyday-detail. A learned-style-card anchor must cite the supplied card id in evidence. A product-market-evidence anchor must cite a concrete supplied product/market fact; if none exists, use conservative-everyday-detail and explicitly say it is ordinary context, not a custom claim. Never use flags, national costumes, royalty/public figures, religion, stereotypes or cultural mockery as shortcut hooks. Locality belongs in consumption context, natural interaction, language rhythm and aesthetic density.
@@ -669,7 +671,7 @@ creativeFingerprint must use five concise semantic labels: characterRelation, sc
669
671
  function compactReferenceStyleCard(value) {
670
672
  if (!value || typeof value !== "object")
671
673
  return "";
672
- const fields = ["id", "visualPremisePattern", "mutationAxes", "culturePattern", "spectaclePattern", "productIntegrationPattern", "openingPattern", "proofPattern", "rhythmPattern", "capturePattern", "voiceTone", "sourceEvidenceTier"];
674
+ const fields = ["id", "templateKind", "templateProfile", "modelFamily", "sourceDurationSeconds", "visualPremisePattern", "mutationAxes", "culturePattern", "spectaclePattern", "productIntegrationPattern", "openingPattern", "proofPattern", "rhythmPattern", "capturePattern", "voiceTone", "targetDurationPolicy", "retimingRule", "segmentRule", "omniAdaptation", "sourceEvidenceTier"];
673
675
  const compact = Object.fromEntries(fields.flatMap((field) => {
674
676
  const text = String(value[field] || "").trim().replace(/\s+/g, " ").slice(0, 400);
675
677
  return text ? [[field, text]] : [];
@@ -680,13 +682,15 @@ function compactReferenceStyleCard(value) {
680
682
  Object.assign(compact, { applicability: { categories, markets } });
681
683
  return Object.keys(compact).length ? compact : null;
682
684
  }
683
- function relevantStyleCards(cards, products) {
685
+ function relevantStyleCards(cards, products, market = "") {
684
686
  const categories = new Set(products.map((product) => String(product.category || "").trim().toLowerCase()).filter(Boolean));
685
- if (!categories.size)
686
- return cards.slice(0, 3);
687
687
  const matched = cards.filter((card) => {
688
688
  const allowed = Array.isArray(card.applicability?.categories) ? card.applicability.categories.map((item) => String(item || "").trim().toLowerCase()).filter(Boolean) : [];
689
- return !allowed.length || allowed.includes("all") || allowed.includes("global") || allowed.some((item) => categories.has(item));
689
+ const markets = Array.isArray(card.applicability?.markets) ? card.applicability.markets.map((item) => String(item || "").trim().toLowerCase()).filter(Boolean) : [];
690
+ const categoryFit = !categories.size || !allowed.length || allowed.includes("all") || allowed.includes("global") || allowed.some((item) => categories.has(item));
691
+ const targetMarket = String(market || "").trim().toLowerCase();
692
+ const marketFit = !markets.length || markets.includes("all") || markets.includes("global") || markets.includes(targetMarket);
693
+ return categoryFit && marketFit;
690
694
  });
691
695
  return matched.length ? matched : [];
692
696
  }
@@ -709,6 +713,7 @@ function selectedCandidatePlan(value) {
709
713
  throw new Error("中心缺少选中的创意候选");
710
714
  return {
711
715
  visualPremise: value.visualPremise,
716
+ learnedTemplateId: value.learnedTemplateId || null,
712
717
  mutationAxes: value.mutationAxes,
713
718
  culturalAnchors: value.culturalAnchors,
714
719
  spectacleEscalation: value.spectacleEscalation,
@@ -37,6 +37,24 @@ function creativePlanSchema() {
37
37
  };
38
38
  return object(properties);
39
39
  }
40
+ function executionBindingSchema() {
41
+ return object({
42
+ segmentIndex: { type: "integer", minimum: 1, maximum: 3 },
43
+ shotIndexes: { type: "array", minItems: 1, maxItems: 8, items: { type: "integer", minimum: 1, maximum: 8 } },
44
+ executedAs: text,
45
+ });
46
+ }
47
+ function executionBindingsSchema() {
48
+ return object({
49
+ opening: executionBindingSchema(),
50
+ proof: executionBindingSchema(),
51
+ purchaseReason: executionBindingSchema(),
52
+ visualExecution: object(Object.fromEntries([
53
+ "firstFrameFocus", "visualContrast", "sensoryTexture", "motionPeak",
54
+ "compositionLighting", "localNativeDetail", "antiFlatness",
55
+ ].map((field) => [field, executionBindingSchema()]))),
56
+ });
57
+ }
40
58
  function segmentSchema() {
41
59
  return object({
42
60
  voiceCue: text,
@@ -65,6 +83,7 @@ export function flowCScriptOutputSchema(durationSeconds, count) {
65
83
  productIndex: { type: "integer", minimum: 0 },
66
84
  sellingFormId: text,
67
85
  creativePlan: creativePlanSchema(),
86
+ executionBindings: executionBindingsSchema(),
68
87
  voiceProfile: voiceProfileSchema(),
69
88
  openingState: openingStateSchema(),
70
89
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xiaohhhh1/canvas-agent",
3
- "version": "0.4.60",
3
+ "version": "0.4.62",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",