@koda-sl/baker-cli 0.305.0-dev.2c645fe6b → 0.305.0-dev.582739c3e
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/dist/cli.js
CHANGED
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
RunAbortedError,
|
|
17
17
|
SEEDANCE_DURATIONS,
|
|
18
18
|
SEEDANCE_PROFILE,
|
|
19
|
+
SPOKEN_CLIP_DURATION_S,
|
|
19
20
|
SPOKEN_WORDS_PER_SECOND,
|
|
20
21
|
VIDEO_GENERATE_MODELS,
|
|
21
22
|
ValidationError,
|
|
@@ -65,7 +66,7 @@ import {
|
|
|
65
66
|
ulid,
|
|
66
67
|
validateCanvasDeep,
|
|
67
68
|
ytDlpBlockSignal
|
|
68
|
-
} from "./chunk-
|
|
69
|
+
} from "./chunk-JI6QIAD3.js";
|
|
69
70
|
import {
|
|
70
71
|
csvOrJson,
|
|
71
72
|
daysAgoIso,
|
|
@@ -38557,6 +38558,7 @@ var CURRENCY_BY_MARKET = {
|
|
|
38557
38558
|
"the united states": "$ (US dollars)"
|
|
38558
38559
|
};
|
|
38559
38560
|
var MARKERS_TO_NAME_A_PLACE = 3;
|
|
38561
|
+
var WORDS_PER_SECOND2 = 3.06;
|
|
38560
38562
|
var MARKET_BY_LANGUAGE = {
|
|
38561
38563
|
es: "Spain",
|
|
38562
38564
|
"es-es": "Spain",
|
|
@@ -38629,9 +38631,10 @@ function marketFor(spec) {
|
|
|
38629
38631
|
}
|
|
38630
38632
|
function beatSeconds(line, videoModel) {
|
|
38631
38633
|
const words2 = line.trim().split(/\s+/).length;
|
|
38632
|
-
const spoken = words2 /
|
|
38634
|
+
const spoken = words2 / WORDS_PER_SECOND2;
|
|
38633
38635
|
const allowed = (videoModel ? clipDurationsFor(videoModel) : void 0) ?? [...SEEDANCE_DURATIONS].sort((a, b) => a - b);
|
|
38634
|
-
|
|
38636
|
+
const wanted = Math.max(spoken, SPOKEN_CLIP_DURATION_S);
|
|
38637
|
+
return allowed.find((d) => d >= wanted) ?? allowed[allowed.length - 1];
|
|
38635
38638
|
}
|
|
38636
38639
|
var BRAND_PLATE = "A solid flat brand colour plate \u2014 an end card. No people, no objects, no scenery, no text of any kind.";
|
|
38637
38640
|
var ASKS_FOR_LEGIBLE = /\b(focus on the (number|amount|total|price|figure|text)|readable|legible|clearly (shows?|visible)|highlighted (number|amount|total)|showing the (number|amount|total|price))\b/i;
|
|
@@ -38861,6 +38864,22 @@ function adSpecToBlueprint(spec, opts = {}) {
|
|
|
38861
38864
|
scenes
|
|
38862
38865
|
};
|
|
38863
38866
|
}
|
|
38867
|
+
function beatsTooShortToPlay(spec) {
|
|
38868
|
+
return spec.beats.map((beat, i) => ({ i, spoken: beat.say.trim().split(/\s+/).filter(Boolean).length / WORDS_PER_SECOND2 })).filter(({ spoken }) => spoken < SPOKEN_CLIP_DURATION_S).map(({ i }) => i + 1);
|
|
38869
|
+
}
|
|
38870
|
+
function withoutCastName(text2, names) {
|
|
38871
|
+
let out = text2;
|
|
38872
|
+
for (const name of names) {
|
|
38873
|
+
const token = name.trim();
|
|
38874
|
+
if (token.length < 3) continue;
|
|
38875
|
+
const pattern = new RegExp(`(?<![\\p{L}\\p{N}])${escapeForPattern(token)}(?![\\p{L}\\p{N}])`, "giu");
|
|
38876
|
+
out = out.replace(pattern, "the person in the reference");
|
|
38877
|
+
}
|
|
38878
|
+
return out;
|
|
38879
|
+
}
|
|
38880
|
+
function escapeForPattern(value) {
|
|
38881
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
38882
|
+
}
|
|
38864
38883
|
|
|
38865
38884
|
// src/engine/scaffold/ad-brand-overlay.ts
|
|
38866
38885
|
var markFallback = (name) => name.trim() ? ` onerror="this.replaceWith(Object.assign(document.createElement('span'),{className:this.className+' brand-wordmark',textContent:${JSON.stringify(name.trim())}}))"` : "";
|
|
@@ -39362,6 +39381,13 @@ var scaffoldAdCommand = defineCommand111({
|
|
|
39362
39381
|
process.exit(1);
|
|
39363
39382
|
return;
|
|
39364
39383
|
}
|
|
39384
|
+
if (handle) {
|
|
39385
|
+
const names = [handle, avatar?.name].filter((value) => Boolean(value));
|
|
39386
|
+
spec.data.beats = spec.data.beats.map((beat) => ({ ...beat, show: withoutCastName(beat.show, names) }));
|
|
39387
|
+
if (spec.data.cast?.description) {
|
|
39388
|
+
spec.data.cast = { ...spec.data.cast, description: withoutCastName(spec.data.cast.description, names) };
|
|
39389
|
+
}
|
|
39390
|
+
}
|
|
39365
39391
|
const blueprint = adSpecToBlueprint(spec.data, { avatarAccent: avatar?.profile?.accent, videoModel: chosenVideoModel });
|
|
39366
39392
|
const slug = args.slug ?? path24.basename(specPath).replace(/\.[^.]+$/, "");
|
|
39367
39393
|
const outPath = args.out ?? (args.slug ? path24.join("src/creatives", slug, `${slug}.canvas.json`) : path24.join(path24.dirname(specPath), `${slug}.canvas.json`));
|
|
@@ -39453,6 +39479,9 @@ var scaffoldAdCommand = defineCommand111({
|
|
|
39453
39479
|
ok: true,
|
|
39454
39480
|
data: { canvas: outPath, beats: spec.data.beats.length, slug },
|
|
39455
39481
|
hints: [
|
|
39482
|
+
// Before anything else: a beat too short to play is a beat to merge, and it is
|
|
39483
|
+
// free to fix here and expensive to discover in a finished ad.
|
|
39484
|
+
...shortBeatHint(beatsTooShortToPlay(spec.data), spec.data.beats.length),
|
|
39456
39485
|
...noBrand ? [
|
|
39457
39486
|
"Built with NO brand mark and no closing card, because you passed --no-brand. Say that in your reply: the user is getting an unbranded ad and should know it, not discover it. When they do have a logo, put it in `src/brand/logos/` and re-run without the flag."
|
|
39458
39487
|
] : [],
|
|
@@ -39511,6 +39540,12 @@ var scaffoldAdCommand = defineCommand111({
|
|
|
39511
39540
|
});
|
|
39512
39541
|
}
|
|
39513
39542
|
});
|
|
39543
|
+
function shortBeatHint(short, total) {
|
|
39544
|
+
if (short.length === 0) return [];
|
|
39545
|
+
return [
|
|
39546
|
+
`Beat${short.length === 1 ? "" : "s"} ${short.join(", ")} of ${total} ${short.length === 1 ? "is" : "are"} under ${SPOKEN_CLIP_DURATION_S}s \u2014 a beat lasts exactly as long as its line takes to read, so a two-word line is a three-second shot, and a run of those plays as a slideshow rather than an ad. Do NOT pad them: that buys seconds of somebody standing still. Merge them, so each beat carries a whole thought \u2014 an ad of this length usually wants two or three beats, not six. Edit the spec and re-run this command.`
|
|
39547
|
+
];
|
|
39548
|
+
}
|
|
39514
39549
|
|
|
39515
39550
|
// src/commands/canvas/scaffold-video.ts
|
|
39516
39551
|
import { access as access2, cp as cp2, mkdir as mkdir8, readFile as readFile19, rm as rm7, writeFile as writeFile10 } from "fs/promises";
|
|
@@ -57795,23 +57830,23 @@ function uploadFailure(path47) {
|
|
|
57795
57830
|
}
|
|
57796
57831
|
|
|
57797
57832
|
// src/commands/studio/spokenPace.ts
|
|
57798
|
-
var
|
|
57833
|
+
var WORDS_PER_SECOND3 = SPOKEN_WORDS_PER_SECOND;
|
|
57799
57834
|
var spokenWords = spokenWordsIn;
|
|
57800
57835
|
function wordsThatFit(seconds) {
|
|
57801
|
-
return Math.floor(seconds *
|
|
57836
|
+
return Math.floor(seconds * WORDS_PER_SECOND3);
|
|
57802
57837
|
}
|
|
57803
57838
|
function spokenPaceHint(prompt, seconds, model) {
|
|
57804
57839
|
const words2 = spokenWords(prompt);
|
|
57805
57840
|
if (words2 === 0) return null;
|
|
57806
57841
|
const split = model ? splitScriptFor(words2, model) : null;
|
|
57807
57842
|
if (split) {
|
|
57808
|
-
return `The line is ${words2} words \u2014 about ${Math.ceil(words2 /
|
|
57843
|
+
return `The line is ${words2} words \u2014 about ${Math.ceil(words2 / WORDS_PER_SECOND3)}s of speech \u2014 and ${model} renders at most ${split.maxSeconds}s (~${Math.floor(split.maxSeconds * WORDS_PER_SECOND3)} words). It will not refuse and it will not cut: it will RUSH, swallowing syllables. Split the script into ${split.clips} takes of roughly ${split.wordsPerClip} words each, rendered separately and cut together \u2014 break it where the thought breaks, not mid-sentence. Or move to a model that renders longer (bytedance/seedance-2.5 goes to 30s).`;
|
|
57809
57844
|
}
|
|
57810
57845
|
if (!seconds) return null;
|
|
57811
57846
|
const fits = wordsThatFit(seconds);
|
|
57812
57847
|
if (words2 <= fits) return null;
|
|
57813
57848
|
const rate = (words2 / seconds).toFixed(1);
|
|
57814
|
-
return `The line is ${words2} words and this clip is ${seconds}s \u2014 that is ${rate} words a second against a natural ${
|
|
57849
|
+
return `The line is ${words2} words and this clip is ${seconds}s \u2014 that is ${rate} words a second against a natural ${WORDS_PER_SECOND3}. The model will not run over, it will RUSH: syllables swallowed, endings clipped, and the take unusable however good the picture. Cut the line to about ${fits} words, or give it the length it needs (${Math.ceil(words2 / WORDS_PER_SECOND3)}s). Do not re-render the same line at the same length and hope.`;
|
|
57815
57850
|
}
|
|
57816
57851
|
|
|
57817
57852
|
// src/commands/studio/animate.ts
|