@xiaohhhh1/canvas-agent 0.4.61 → 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>>;
@@ -655,13 +655,14 @@ ${durationRules}
655
655
  }
656
656
  export function creativeCandidatePrompt(id, task, ordinals) {
657
657
  const products = relevantProductInputs(task, ordinals);
658
- 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);
659
659
  const ledger = (task.creative_fingerprint_ledger || []).slice(-60);
660
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)}.
661
- 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)}
662
662
  Optional learned style abstractions: ${compactJson(styleCards, 5_000)}
663
663
  Already accepted fingerprint ledger: ${compactJson(ledger, 8_000)}
664
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.
665
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.
666
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.
667
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.
@@ -670,7 +671,7 @@ creativeFingerprint must use five concise semantic labels: characterRelation, sc
670
671
  function compactReferenceStyleCard(value) {
671
672
  if (!value || typeof value !== "object")
672
673
  return "";
673
- 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"];
674
675
  const compact = Object.fromEntries(fields.flatMap((field) => {
675
676
  const text = String(value[field] || "").trim().replace(/\s+/g, " ").slice(0, 400);
676
677
  return text ? [[field, text]] : [];
@@ -681,13 +682,15 @@ function compactReferenceStyleCard(value) {
681
682
  Object.assign(compact, { applicability: { categories, markets } });
682
683
  return Object.keys(compact).length ? compact : null;
683
684
  }
684
- function relevantStyleCards(cards, products) {
685
+ function relevantStyleCards(cards, products, market = "") {
685
686
  const categories = new Set(products.map((product) => String(product.category || "").trim().toLowerCase()).filter(Boolean));
686
- if (!categories.size)
687
- return cards.slice(0, 3);
688
687
  const matched = cards.filter((card) => {
689
688
  const allowed = Array.isArray(card.applicability?.categories) ? card.applicability.categories.map((item) => String(item || "").trim().toLowerCase()).filter(Boolean) : [];
690
- 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;
691
694
  });
692
695
  return matched.length ? matched : [];
693
696
  }
@@ -710,6 +713,7 @@ function selectedCandidatePlan(value) {
710
713
  throw new Error("中心缺少选中的创意候选");
711
714
  return {
712
715
  visualPremise: value.visualPremise,
716
+ learnedTemplateId: value.learnedTemplateId || null,
713
717
  mutationAxes: value.mutationAxes,
714
718
  culturalAnchors: value.culturalAnchors,
715
719
  spectacleEscalation: value.spectacleEscalation,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xiaohhhh1/canvas-agent",
3
- "version": "0.4.61",
3
+ "version": "0.4.62",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",