@koda-sl/baker-cli 0.321.0 → 0.324.0-dev.593ae2dfd
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 +11 -2
- package/dist/{chunk-AEU5X443.js → chunk-63Q73JIN.js} +2 -2
- package/dist/{chunk-WHUKLAGW.js → chunk-BD4GLBWV.js} +155 -19
- package/dist/chunk-BD4GLBWV.js.map +1 -0
- package/dist/{chunk-KMQHIAYG.js → chunk-G7CQBZVF.js} +3 -3
- package/dist/{chunk-TTIGSGXE.js → chunk-OMUDHFUY.js} +1 -1
- package/dist/chunk-OMUDHFUY.js.map +1 -0
- package/dist/cli.js +26 -18
- package/dist/cli.js.map +1 -1
- package/dist/{client-QFJHI3FX.js → client-7TD3X4CY.js} +2 -2
- package/dist/engine/index.js +1 -1
- package/dist/{output-PAE5S7RI.js → output-HLNLGRIT.js} +3 -3
- package/dist/{shared-J6GGQDIL.js → shared-S5OCQHPP.js} +4 -4
- package/package.json +1 -1
- package/dist/chunk-TTIGSGXE.js.map +0 -1
- package/dist/chunk-WHUKLAGW.js.map +0 -1
- /package/dist/{chunk-AEU5X443.js.map → chunk-63Q73JIN.js.map} +0 -0
- /package/dist/{chunk-KMQHIAYG.js.map → chunk-G7CQBZVF.js.map} +0 -0
- /package/dist/{client-QFJHI3FX.js.map → client-7TD3X4CY.js.map} +0 -0
- /package/dist/{output-PAE5S7RI.js.map → output-HLNLGRIT.js.map} +0 -0
- /package/dist/{shared-J6GGQDIL.js.map → shared-S5OCQHPP.js.map} +0 -0
package/README.md
CHANGED
|
@@ -4925,6 +4925,7 @@ Word-level transcription of a video OR a bare audio track (the `video` input acc
|
|
|
4925
4925
|
|---|---|---|---|---|
|
|
4926
4926
|
| `language` | string | no | auto | ISO 639-1, 2–8 chars (e.g. `en`, `es`) |
|
|
4927
4927
|
| `transcriber` | enum | no | `groq` | `groq` (Whisper) \| `deepgram` (Nova-3, adds the `rich` output) |
|
|
4928
|
+
| `keyterms` | string[] | no | — | Up to 30 names the recogniser must not mangle — a product, a person, a phrase the script coins. The **company's own name is always applied server-side**, so it never needs listing here |
|
|
4928
4929
|
|
|
4929
4930
|
**Outputs**
|
|
4930
4931
|
|
|
@@ -4933,6 +4934,8 @@ Word-level transcription of a video OR a bare audio track (the `video` input acc
|
|
|
4933
4934
|
| `transcript` | json | `application/json` — array of `{text, start, end}` (Deepgram prefers the punctuated word form) |
|
|
4934
4935
|
| `rich` | json | `application/json` — Deepgram only: `{text, words[], paragraphs[], duration_sec, language?}` with punctuated words, sentences, and speaker indices |
|
|
4935
4936
|
|
|
4937
|
+
**Known names are spelled the way the brand spells them.** Every term (the company's own name, plus `keyterms`) is biased into the request — Deepgram `keyterm`, Whisper `prompt` — and its spelling is then enforced on the words that come back, because bias is a probability and a caption prints the mistake at full size over the ad. Verified against the take that shipped wrong: the same Spanish clip returns "Cubicap" bare and "Cubicup" with the name applied. Corrections are listed on the output's `brand_spelling_corrections` metadata, so a rewrite is visible rather than silent. A short name (under 6 characters) gets the bias only — at that length ordinary words sit one edit away, and rewriting those to protect a brand would corrupt the line. **Never patch a mishearing inside a caption composition**: that fix dies with that one creative.
|
|
4938
|
+
|
|
4936
4939
|
**Cost** — 2 credits estimate; backend reports actual based on duration (Groq: $0.04/hr, 10s minimum; Deepgram Nova-3: $0.0043/min).
|
|
4937
4940
|
|
|
4938
4941
|
**Requirements** — `ffmpeg` on PATH for audio extraction (already in the E2B sandbox image). Without it the node still works but uploads the full video and Groq's 100 MB cap applies.
|
|
@@ -5051,10 +5054,12 @@ Place and mix several audio clips onto one timeline — a music bed plus timed v
|
|
|
5051
5054
|
| `tracks` | array | yes | `[{slot, start_s, duration_s?, gain_db?}]` — `slot` matches a wired input; `start_s` is absolute seconds; `duration_s` hard-caps the clip (trimmed BEFORE placement, so an over-long source can't bleed into the next track's window); `gain_db` sets the static level (e.g. `-20` for a music bed) |
|
|
5052
5055
|
| `total_ms` | number | no | pins the final length (pad/trim) |
|
|
5053
5056
|
| `output_format` | enum | no | `mp3` (default) / `wav` / `m4a` |
|
|
5054
|
-
| `duck` | object | no | sidechain-duck one track under others: `{ track, against: [...], threshold?, ratio?, attack?, release? }` — the `track` (music) drops while any `against` track (voice) carries signal and recovers in the gaps |
|
|
5057
|
+
| `duck` | object | no | sidechain-duck one track under others: `{ track, against: [...], threshold?, ratio?, attack?, release? }` — the `track` (music) drops while any `against` track (voice) carries signal and recovers in the gaps. `threshold` is linear 0–1; **`attack` and `release` are MILLISECONDS** (typical 5–50 / 200–800, defaults 5 / 300) |
|
|
5055
5058
|
|
|
5056
5059
|
**Outputs** — `audio`. **Cost** — free (local). Requires `ffmpeg`.
|
|
5057
5060
|
|
|
5061
|
+
**The bed under a voice is two settled numbers, and `canvas validate` holds both.** A music bed sits at **−20 dB** and is sidechain-ducked against the speech; `AUDIO_MUSIC_BED_TOO_LOUD` warns above −18 dB (a hand-built cut at −13 dB was rejected by the client as too loud) and `AUDIO_MUSIC_BED_NOT_DUCKED` warns when the bed is mixed flat under speech. If a silent tail — an end card, a logo plate — sounds empty, **add the same bed as a second windowed track** (`start_s` + `duration_s`) with its own higher gain; never raise the bed that runs under the voice, which is what measuring loudness across the silent tail invites. `AUDIO_DUCK_UNITS` **blocks** a sub-millisecond `attack`/`release`: `release: 0.45` is a seconds value, and at 0.45 ms the bed snaps back to full level between syllables — which sounds exactly like music mixed too loud. `AUDIO_MUSIC_BED_SCORED_TO_ARC` warns when a `video-background-music-v1` bed's own brief asks for movement (a build, a climax, "follows her arc") under speech — see `music`. (`music-v1` is exempt: `scaffold-video` briefs it with the reference ad's own arc on purpose.)
|
|
5062
|
+
|
|
5058
5063
|
---
|
|
5059
5064
|
|
|
5060
5065
|
##### `image_background_remove`
|
|
@@ -5091,6 +5096,8 @@ Strip background → transparent PNG. Powered by `men1scus/birefnet` (Replicate)
|
|
|
5091
5096
|
|
|
5092
5097
|
Generate music from prompt OR score an existing video clip.
|
|
5093
5098
|
|
|
5099
|
+
**Both routes run on the `music_v2` engine** (`ELEVENLABS_MUSIC_ENGINE`), which is separate from the route names below — `elevenlabs/music-v1` still selects compose and `elevenlabs/video-background-music-v1` still selects video-to-music, so existing canvases keep their names. Measured on a real client cut before switching (same clips, same brief, only the engine different): over the 25s carrying speech v1's level wandered **16.3 dB** against v2's **3.9 dB**, v2 sits 1.7 dB further out of the 200 Hz–3 kHz speech band, and v2 ends at −32 dBFS where v1 collapses to −50 dB — that fade is what makes a correct bed read as "empty over the end card". v2 plays ~5× the note attacks, which is the one thing to listen for. Note the per-second **cost of v2 is unconfirmed**: ElevenLabs publishes no per-model music rate and returns no cost header, so `ELEVENLABS_MUSIC_USD_PER_SECOND` is still the v1 figure.
|
|
5100
|
+
|
|
5094
5101
|
**Inputs**
|
|
5095
5102
|
|
|
5096
5103
|
| Slot | Kind | Required | Notes |
|
|
@@ -5129,10 +5136,12 @@ Score an existing video. Requires `inputs.video`.
|
|
|
5129
5136
|
| Name | Type | Required | Notes |
|
|
5130
5137
|
|---|---|---|---|
|
|
5131
5138
|
| `model` | literal | yes | `"elevenlabs/video-background-music-v1"` |
|
|
5132
|
-
| `description` | string | no | max 1000 chars |
|
|
5139
|
+
| `description` | string | no | max 1000 chars — the score in **sound**, not in feelings (see below) |
|
|
5133
5140
|
| `tags` | string[] | no | up to 10 style tags |
|
|
5134
5141
|
| `output_format` | enum | no | mp3 family only (see `tts`) |
|
|
5135
5142
|
|
|
5143
|
+
**Under speech, a bed is furniture.** This model *watches* the cut, so it scores the footage's emotion unless told not to: name ONE steady character (instruments, tempo, texture) and forbid movement — no build, no drop, no climax, nothing that "follows the arc". A description that narrated the speaker's emotional arc ("quiet and tense while she is overwhelmed, opening as she walks, resolving warm and confident") came back as a film score, and the client's verdict was *"la musica que has elegido es muy dramática"*. Prefer tags that hold it still (`instrumental`, `understated`, `steady`, `no drums`) over tags that move it (`cinematic`, `epic`, `building`, `resolving`). The level and the ducking are separate, settled decisions — see `audio_timeline`.
|
|
5144
|
+
|
|
5136
5145
|
---
|
|
5137
5146
|
|
|
5138
5147
|
##### `dialogue`
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ApiError,
|
|
3
3
|
apiGet
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-OMUDHFUY.js";
|
|
5
5
|
import {
|
|
6
6
|
getEnv
|
|
7
7
|
} from "./chunk-UIQJZGBG.js";
|
|
@@ -294,4 +294,4 @@ export {
|
|
|
294
294
|
writeAdsOutput,
|
|
295
295
|
resolveCustomerId
|
|
296
296
|
};
|
|
297
|
-
//# sourceMappingURL=chunk-
|
|
297
|
+
//# sourceMappingURL=chunk-63Q73JIN.js.map
|
|
@@ -17,9 +17,9 @@ import {
|
|
|
17
17
|
shouldEscalate
|
|
18
18
|
} from "./chunk-UIQJZGBG.js";
|
|
19
19
|
|
|
20
|
-
//
|
|
20
|
+
// ../../.pnpm-store/v10/links/@/safe-stable-stringify/2.5.0/766ad107c42df28eeadaf0ac2f9089c8a9e200f6ba0b2b1a817b8d536cbdcc49/node_modules/safe-stable-stringify/index.js
|
|
21
21
|
var require_safe_stable_stringify = __commonJS({
|
|
22
|
-
"
|
|
22
|
+
"../../.pnpm-store/v10/links/@/safe-stable-stringify/2.5.0/766ad107c42df28eeadaf0ac2f9089c8a9e200f6ba0b2b1a817b8d536cbdcc49/node_modules/safe-stable-stringify/index.js"(exports, module) {
|
|
23
23
|
"use strict";
|
|
24
24
|
var { hasOwnProperty } = Object.prototype;
|
|
25
25
|
var stringify = configure2();
|
|
@@ -1111,7 +1111,7 @@ function resolveAdaptFormats(params) {
|
|
|
1111
1111
|
return params.formats ?? [];
|
|
1112
1112
|
}
|
|
1113
1113
|
|
|
1114
|
-
//
|
|
1114
|
+
// ../../.pnpm-store/v10/links/@/safe-stable-stringify/2.5.0/766ad107c42df28eeadaf0ac2f9089c8a9e200f6ba0b2b1a817b8d536cbdcc49/node_modules/safe-stable-stringify/esm/wrapper.js
|
|
1115
1115
|
var import__ = __toESM(require_safe_stable_stringify(), 1);
|
|
1116
1116
|
var configure = import__.default.configure;
|
|
1117
1117
|
var wrapper_default = import__.default;
|
|
@@ -3686,6 +3686,10 @@ var STAGE_CODES = {
|
|
|
3686
3686
|
OVERLAY_OUT_OF_BOUNDS: "VIDEO_OVERLAY_OUT_OF_BOUNDS",
|
|
3687
3687
|
ORPHAN_NODE: "ORPHAN_NODE",
|
|
3688
3688
|
INGEST_PATH_URL_HEALED: "INGEST_PATH_URL_HEALED",
|
|
3689
|
+
DUCK_UNITS: "AUDIO_DUCK_UNITS",
|
|
3690
|
+
MUSIC_BED_TOO_LOUD: "AUDIO_MUSIC_BED_TOO_LOUD",
|
|
3691
|
+
MUSIC_BED_NOT_DUCKED: "AUDIO_MUSIC_BED_NOT_DUCKED",
|
|
3692
|
+
MUSIC_BED_SCORED_TO_ARC: "AUDIO_MUSIC_BED_SCORED_TO_ARC",
|
|
3689
3693
|
PARALLEL_FORMAT_RENDERS: "IMAGE_PARALLEL_FORMAT_RENDERS"
|
|
3690
3694
|
};
|
|
3691
3695
|
var SPAN_MODEL_SLACK_S = 0.25;
|
|
@@ -3753,6 +3757,7 @@ function validateCanvas(input, registry) {
|
|
|
3753
3757
|
checkOutputRef(ctx);
|
|
3754
3758
|
checkOrphanNodes(ctx);
|
|
3755
3759
|
checkParallelFormatRenders(ctx);
|
|
3760
|
+
checkAudioBedMix(ctx);
|
|
3756
3761
|
checkVideoInvariants(ctx);
|
|
3757
3762
|
const hasBlocking = issues.some(isBlocking);
|
|
3758
3763
|
if (hasBlocking) return { ok: false, issues };
|
|
@@ -4739,6 +4744,108 @@ function checkParallelFormatRenders(ctx) {
|
|
|
4739
4744
|
});
|
|
4740
4745
|
}
|
|
4741
4746
|
}
|
|
4747
|
+
var MUSIC_BED_MAX_GAIN_DB = -18;
|
|
4748
|
+
var DUCK_MIN_ATTACK_MS = 0.5;
|
|
4749
|
+
var DUCK_MIN_RELEASE_MS = 10;
|
|
4750
|
+
var SPEECH_NODE_TYPES = /* @__PURE__ */ new Set(["tts", "dialogue", "audio_voice_convert", "video_lipsync"]);
|
|
4751
|
+
var SPEECH_SLOT_RE = /voice|speech|\bvo\b|^vo|_vo|dialog|narration/i;
|
|
4752
|
+
var MUSIC_SLOT_RE = /music|score|\bbed\b/i;
|
|
4753
|
+
function audioTimelineTracks(node) {
|
|
4754
|
+
const tracks = node.params?.tracks;
|
|
4755
|
+
if (!Array.isArray(tracks)) return [];
|
|
4756
|
+
return tracks.filter(
|
|
4757
|
+
(t) => typeof t === "object" && t !== null && typeof t.slot === "string"
|
|
4758
|
+
);
|
|
4759
|
+
}
|
|
4760
|
+
function checkAudioBedMix(ctx) {
|
|
4761
|
+
for (const n of ctx.canvas.nodes) {
|
|
4762
|
+
if (n.type === "audio_timeline") checkOneAudioMix(ctx, n);
|
|
4763
|
+
}
|
|
4764
|
+
}
|
|
4765
|
+
function checkOneAudioMix(ctx, node) {
|
|
4766
|
+
const tracks = audioTimelineTracks(node);
|
|
4767
|
+
if (tracks.length === 0) return;
|
|
4768
|
+
const duck = node.params?.duck;
|
|
4769
|
+
checkDuckUnits(ctx, node, duck);
|
|
4770
|
+
const sourceType = (slot) => refNodeOf(ctx, node.inputs?.[slot])?.type ?? null;
|
|
4771
|
+
const speech = tracks.filter((t) => {
|
|
4772
|
+
const type = sourceType(t.slot);
|
|
4773
|
+
return type !== null && SPEECH_NODE_TYPES.has(type) || SPEECH_SLOT_RE.test(t.slot);
|
|
4774
|
+
});
|
|
4775
|
+
if (speech.length === 0) return;
|
|
4776
|
+
const beds = tracks.filter(
|
|
4777
|
+
(t) => (sourceType(t.slot) === "music" || MUSIC_SLOT_RE.test(t.slot)) && t.duration_s === void 0
|
|
4778
|
+
);
|
|
4779
|
+
if (beds.length === 0) return;
|
|
4780
|
+
checkBedLevels(ctx, node, beds);
|
|
4781
|
+
checkBedDucked(ctx, node, beds, speech, duck);
|
|
4782
|
+
for (const bed of beds) checkBedNotScored(ctx, node, refNodeOf(ctx, node.inputs?.[bed.slot]));
|
|
4783
|
+
}
|
|
4784
|
+
var MUSIC_ARC_RE = /\b(?:emotional arc|follows? (?:her|his|their|the) arc|swell(?:s|ing)?|crescendo|climax|build(?:s|ing) (?:to|into)|resolv(?:e|es|ing)|dramatic|epic|tense|tension)\b/i;
|
|
4785
|
+
function checkBedNotScored(ctx, node, source) {
|
|
4786
|
+
if (source?.type !== "music") return;
|
|
4787
|
+
const params = source.params;
|
|
4788
|
+
if (params?.model !== "elevenlabs/video-background-music-v1") return;
|
|
4789
|
+
const brief = [params?.description, params?.prompt].filter((v) => typeof v === "string").join(" ");
|
|
4790
|
+
const found = MUSIC_ARC_RE.exec(brief);
|
|
4791
|
+
if (!found) return;
|
|
4792
|
+
ctx.issues.push({
|
|
4793
|
+
path: `nodes[${ctx.idToIndex.get(source.id) ?? -1}].params.description`,
|
|
4794
|
+
code: STAGE_CODES.MUSIC_BED_SCORED_TO_ARC,
|
|
4795
|
+
severity: "warning",
|
|
4796
|
+
node_id: source.id,
|
|
4797
|
+
node_type: source.type,
|
|
4798
|
+
message: `"${source.id}" briefs the bed with "${found[0]}", and "${node.id}" mixes it under speech \u2014 this model watches the cut, so movement asked for here comes back as a film score (a testimonial briefed that way was rejected as "muy dram\xE1tica"). Under a voice, name ONE steady character and forbid movement: no build, no drop, no climax, nothing that follows the arc`
|
|
4799
|
+
});
|
|
4800
|
+
}
|
|
4801
|
+
function checkDuckUnits(ctx, node, duck) {
|
|
4802
|
+
const index = ctx.idToIndex.get(node.id) ?? -1;
|
|
4803
|
+
if (typeof duck?.attack === "number" && duck.attack < DUCK_MIN_ATTACK_MS) {
|
|
4804
|
+
ctx.issues.push({
|
|
4805
|
+
path: `nodes[${index}].params.duck.attack`,
|
|
4806
|
+
code: STAGE_CODES.DUCK_UNITS,
|
|
4807
|
+
node_id: node.id,
|
|
4808
|
+
node_type: node.type,
|
|
4809
|
+
message: `"${node.id}" ducks with attack ${duck.attack} \u2014 this parameter is MILLISECONDS, so that is instantaneous. Use 5-50 (default 5)`
|
|
4810
|
+
});
|
|
4811
|
+
}
|
|
4812
|
+
if (typeof duck?.release === "number" && duck.release < DUCK_MIN_RELEASE_MS) {
|
|
4813
|
+
ctx.issues.push({
|
|
4814
|
+
path: `nodes[${index}].params.duck.release`,
|
|
4815
|
+
code: STAGE_CODES.DUCK_UNITS,
|
|
4816
|
+
node_id: node.id,
|
|
4817
|
+
node_type: node.type,
|
|
4818
|
+
message: `"${node.id}" ducks with release ${duck.release} \u2014 this parameter is MILLISECONDS, so the bed jumps back to full level between syllables and the mix sounds like the music is too loud. Use 200-800 (default 300); 0.45 is a seconds value`
|
|
4819
|
+
});
|
|
4820
|
+
}
|
|
4821
|
+
}
|
|
4822
|
+
function checkBedLevels(ctx, node, beds) {
|
|
4823
|
+
const index = ctx.idToIndex.get(node.id) ?? -1;
|
|
4824
|
+
for (const bed of beds) {
|
|
4825
|
+
if ((bed.gain_db ?? 0) <= MUSIC_BED_MAX_GAIN_DB) continue;
|
|
4826
|
+
const level = bed.gain_db === void 0 ? "full level (no gain_db)" : `${bed.gain_db} dB`;
|
|
4827
|
+
ctx.issues.push({
|
|
4828
|
+
path: `nodes[${index}].params.tracks`,
|
|
4829
|
+
code: STAGE_CODES.MUSIC_BED_TOO_LOUD,
|
|
4830
|
+
severity: "warning",
|
|
4831
|
+
node_id: node.id,
|
|
4832
|
+
node_type: node.type,
|
|
4833
|
+
message: `"${node.id}" runs the music bed "${bed.slot}" at ${level} under speech \u2014 a bed belongs at ${MUSIC_BED_MAX_GAIN_DB} dB or below (the scaffolder pins -20; -13 was rejected by a client as too loud). If a silent tail sounds empty, add the same bed as a SECOND windowed track (start_s + duration_s) with its own higher gain instead of raising this one`
|
|
4834
|
+
});
|
|
4835
|
+
}
|
|
4836
|
+
}
|
|
4837
|
+
function checkBedDucked(ctx, node, beds, speech, duck) {
|
|
4838
|
+
if (beds.some((bed) => bed.slot === duck?.track)) return;
|
|
4839
|
+
const quoted = (list) => list.map((t) => `"${t.slot}"`).join(", ");
|
|
4840
|
+
ctx.issues.push({
|
|
4841
|
+
path: `nodes[${ctx.idToIndex.get(node.id) ?? -1}].params.duck`,
|
|
4842
|
+
code: STAGE_CODES.MUSIC_BED_NOT_DUCKED,
|
|
4843
|
+
severity: "warning",
|
|
4844
|
+
node_id: node.id,
|
|
4845
|
+
node_type: node.type,
|
|
4846
|
+
message: `"${node.id}" mixes a music bed (${quoted(beds)}) under speech (${quoted(speech)}) with no sidechain duck on it \u2014 a flat bed fights the voice in every gap. Add params.duck { track: "${beds[0]?.slot}", against: [${quoted(speech)}] }`
|
|
4847
|
+
});
|
|
4848
|
+
}
|
|
4742
4849
|
function checkOrphanNodes(ctx) {
|
|
4743
4850
|
const out = ctx.canvas.output;
|
|
4744
4851
|
if (!out || !ctx.idToIndex.has(out.node)) return;
|
|
@@ -7031,16 +7138,28 @@ var Track = z6.object({
|
|
|
7031
7138
|
* track that came back oversized) cannot bleed into the next track's window.
|
|
7032
7139
|
*/
|
|
7033
7140
|
duration_s: z6.number().positive().optional(),
|
|
7034
|
-
/**
|
|
7035
|
-
|
|
7141
|
+
/**
|
|
7142
|
+
* Level adjustment in dB — negative attenuates. A MUSIC BED under speech
|
|
7143
|
+
* belongs at −20 dB (see the `describe` text: this number is a settled
|
|
7144
|
+
* decision, not a per-cut judgement).
|
|
7145
|
+
*/
|
|
7146
|
+
gain_db: z6.number().optional().describe(
|
|
7147
|
+
"Level adjustment in dB (negative attenuates, 0 = untouched). A music bed under speech sits at \u221220 dB and is sidechain-ducked as well; \u221212 dB crowded the voice and \u221213 dB was rejected by the client as too loud. If a silent tail (an end card, a logo plate) sounds empty, do NOT raise the bed \u2014 wire the same bed as a SECOND track windowed over the tail with its own higher gain. Measuring loudness across a window that includes the silent tail is what makes a correct bed look quiet."
|
|
7148
|
+
)
|
|
7036
7149
|
}).strict();
|
|
7037
7150
|
var DuckSpec = z6.object({
|
|
7038
|
-
track: z6.string().min(1),
|
|
7039
|
-
against: z6.array(z6.string().min(1)).min(1),
|
|
7040
|
-
threshold: z6.number().min(0).max(1).optional(),
|
|
7041
|
-
ratio: z6.number().min(1).max(20).optional(),
|
|
7042
|
-
attack:
|
|
7043
|
-
release:
|
|
7151
|
+
track: z6.string().min(1).describe("Slot to duck \u2014 the music bed."),
|
|
7152
|
+
against: z6.array(z6.string().min(1)).min(1).describe("Key slots whose signal ducks it \u2014 the voice tracks."),
|
|
7153
|
+
threshold: z6.number().min(0).max(1).optional().describe("Linear 0\u20131, not dB. Lower ducks more readily. Default 0.03."),
|
|
7154
|
+
ratio: z6.number().min(1).max(20).optional().describe("How hard it ducks. Default 8; 12 for a firm hold."),
|
|
7155
|
+
// MILLISECONDS is spelled out because a canvas shipped `attack: 0.05,
|
|
7156
|
+
// release: 0.45` — read as seconds — which is a 0.45 ms release: the bed
|
|
7157
|
+
// snapped back to full level between syllables and the client heard the
|
|
7158
|
+
// music as "too loud" at a level that measured correct.
|
|
7159
|
+
attack: z6.number().min(0.01).optional().describe("MILLISECONDS (not seconds). Typical 5\u201350; default 5. A value below 0.5 is a unit mistake."),
|
|
7160
|
+
release: z6.number().min(0.01).optional().describe(
|
|
7161
|
+
"MILLISECONDS (not seconds). Typical 200\u2013800; default 300. Anything under ~10 makes the bed pump back up between words and is a unit mistake."
|
|
7162
|
+
)
|
|
7044
7163
|
}).strict();
|
|
7045
7164
|
var AudioTimelineParams = z6.object({
|
|
7046
7165
|
tracks: z6.array(Track).min(1),
|
|
@@ -8924,15 +9043,29 @@ var MusicParams = z25.object({
|
|
|
8924
9043
|
/**
|
|
8925
9044
|
* video-to-music only — short description of the desired score
|
|
8926
9045
|
* ("upbeat synth, fast cuts, 80s") used to bias the model.
|
|
9046
|
+
*
|
|
9047
|
+
* The `describe` text below is the one piece of craft this node can enforce
|
|
9048
|
+
* nowhere else: a bed under somebody talking must be ONE steady character.
|
|
9049
|
+
* A description that narrated the speaker's emotional arc ("quiet and tense
|
|
9050
|
+
* while she is overwhelmed, opening as she walks, resolving warm and
|
|
9051
|
+
* confident") came back as a film score and the client's verdict was "la
|
|
9052
|
+
* musica que has elegido es muy dramática".
|
|
8927
9053
|
*/
|
|
8928
|
-
description: z25.string().max(1e3).optional()
|
|
9054
|
+
description: z25.string().max(1e3).optional().describe(
|
|
9055
|
+
"The score you want, in sound (instruments, tempo, texture) \u2014 not in feelings. Under speech, name ONE steady character and forbid movement: no build, no drop, no climax, no key change, nothing that 'follows the arc'. This model WATCHES the cut, so it will score the footage's emotion unless told not to \u2014 asking it to track a speaker's emotional arc is how a testimonial bed comes back dramatic. A bed is furniture; the voice carries the story."
|
|
9056
|
+
),
|
|
8929
9057
|
/** video-to-music only — up to 10 style tags. */
|
|
8930
|
-
tags: z25.array(z25.string()).max(10).optional()
|
|
9058
|
+
tags: z25.array(z25.string()).max(10).optional().describe(
|
|
9059
|
+
"Style tags. Under speech, prefer tags that hold it still (instrumental, understated, steady, no drums) over tags that move it (cinematic, epic, building, resolving, trailer)."
|
|
9060
|
+
),
|
|
8931
9061
|
output_format: z25.enum(ELEVENLABS_OUTPUT_FORMATS).optional()
|
|
8932
9062
|
}).strict();
|
|
8933
9063
|
var musicNode = delegated({
|
|
8934
9064
|
id: "music",
|
|
8935
|
-
|
|
9065
|
+
// 1.2.0: the ElevenLabs engine moved to `music_v2` (ELEVENLABS_MUSIC_ENGINE).
|
|
9066
|
+
// The bump is not cosmetic — nodeVersion is part of the canvas cache key, so
|
|
9067
|
+
// without it a re-run would serve the v1 bed the switch was made to replace.
|
|
9068
|
+
version: "1.2.0",
|
|
8936
9069
|
category: "audio",
|
|
8937
9070
|
summary: "Generate music for ad creatives and website video content. `elevenlabs/music-v1` composes from a text prompt or structured composition plan; `elevenlabs/video-background-music-v1` scores an existing video clip provided via `inputs.video`.",
|
|
8938
9071
|
when_to_use: "Use to produce background music or a full score for video ads, hero-section reels, or any motion content. Prefer the video-to-music model when you already have a cut and want music timed to it; use compose-detailed when you have only a brief or want section-level control (intro / hook / outro). Pair the resulting audio with `video_generate` or `video_lipsync` at compose time.",
|
|
@@ -9317,7 +9450,10 @@ var VideoTranscribeParams = z33.object({
|
|
|
9317
9450
|
// Provider choice is explicit (no env-based silent branching). Default Groq
|
|
9318
9451
|
// Whisper; "deepgram" routes to Deepgram Nova-3, which additionally emits a
|
|
9319
9452
|
// `rich` JSON output with punctuated words + paragraph/sentence grouping.
|
|
9320
|
-
transcriber: z33.enum(["groq", "deepgram"]).optional()
|
|
9453
|
+
transcriber: z33.enum(["groq", "deepgram"]).optional(),
|
|
9454
|
+
keyterms: z33.array(z33.string().min(2).max(60)).max(30).optional().describe(
|
|
9455
|
+
"Names the recogniser must not mangle \u2014 a product, a person, a phrase the script coins. The COMPANY'S OWN NAME is always applied server-side, so you never list it: this is for the rest. Every term is biased into the request AND its spelling enforced on the way out, because a caption prints a mishearing at full size over the ad (a real cut shipped with the brand name spelled wrong). Never patch a misspelling inside a caption composition \u2014 that fix dies with that one creative."
|
|
9456
|
+
)
|
|
9321
9457
|
}).strict();
|
|
9322
9458
|
var VideoTranscribeInputs = z33.object({
|
|
9323
9459
|
// A video (audio auto-extracted locally) OR a bare audio track. The key stays
|
|
@@ -9334,10 +9470,10 @@ var VideoTranscribeOutputs = z33.object({
|
|
|
9334
9470
|
var AUDIO_EXTRACT_TIMEOUT_MS = 6e4;
|
|
9335
9471
|
var videoTranscribeNode = defineNode({
|
|
9336
9472
|
id: "video_transcribe",
|
|
9337
|
-
version: "2.
|
|
9473
|
+
version: "2.4.0",
|
|
9338
9474
|
category: "language",
|
|
9339
9475
|
location: "local",
|
|
9340
|
-
summary: 'Transcribe a video or audio track to a word-level JSON transcript. Default `transcriber:"groq"` uses Groq Whisper Large v3 Turbo ($0.04/hr, 10s min); `transcriber:"deepgram"` uses Deepgram Nova-3 ($0.0043/min) and additionally emits a `rich` JSON output with punctuated words + paragraph/sentence grouping (and speaker indices). Automatically extracts audio locally (mono 16 kHz MP3) before uploading \u2014 reduces payload ~100\xD7 and lifts the effective duration limit well beyond Groq\'s 100 MB file cap. The `transcript` output is always an array of {text, start, end} entries ready to feed Hyperframes caption compositions (Deepgram prefers the punctuated word form).',
|
|
9476
|
+
summary: 'Transcribe a video or audio track to a word-level JSON transcript. Default `transcriber:"groq"` uses Groq Whisper Large v3 Turbo ($0.04/hr, 10s min); `transcriber:"deepgram"` uses Deepgram Nova-3 ($0.0043/min) and additionally emits a `rich` JSON output with punctuated words + paragraph/sentence grouping (and speaker indices). Automatically extracts audio locally (mono 16 kHz MP3) before uploading \u2014 reduces payload ~100\xD7 and lifts the effective duration limit well beyond Groq\'s 100 MB file cap. The `transcript` output is always an array of {text, start, end} entries ready to feed Hyperframes caption compositions (Deepgram prefers the punctuated word form). Known names are spelled the way the brand spells them: the company\'s own name is biased into the request and enforced on the output automatically, and `keyterms` adds any other name the script depends on.',
|
|
9341
9477
|
when_to_use: 'Use to generate burned-in captions for a stitched video. Pair with `hyperframe_render` and a captions composition (e.g. `tiktok-captions`) by passing the transcript JSON through `params.variables.transcript`. Pick `params.language` to filter out non-target speech (e.g. "es" for Spanish). Pick `transcriber:"deepgram"` when you want punctuation/paragraphs (read them from the `rich` output) or speaker grouping. Requires ffmpeg on PATH for audio extraction (falls back to full video upload if unavailable).',
|
|
9342
9478
|
inputs: VideoTranscribeInputs,
|
|
9343
9479
|
params: VideoTranscribeParams,
|
|
@@ -9349,7 +9485,7 @@ var videoTranscribeNode = defineNode({
|
|
|
9349
9485
|
const effectiveInputs = audioInput ?? inputs;
|
|
9350
9486
|
return await callBackendExec({
|
|
9351
9487
|
nodeType: "video_transcribe",
|
|
9352
|
-
nodeVersion: "2.
|
|
9488
|
+
nodeVersion: "2.4.0",
|
|
9353
9489
|
params,
|
|
9354
9490
|
inputs: effectiveInputs,
|
|
9355
9491
|
outputKinds: { transcript: "json", rich: "json" },
|
|
@@ -9666,4 +9802,4 @@ export {
|
|
|
9666
9802
|
defaultRegistry,
|
|
9667
9803
|
createEngineFromEnv
|
|
9668
9804
|
};
|
|
9669
|
-
//# sourceMappingURL=chunk-
|
|
9805
|
+
//# sourceMappingURL=chunk-BD4GLBWV.js.map
|