LGTM
This commit is contained in:
parent
9248e26af2
commit
f2a2651b8a
95 changed files with 3993 additions and 1471 deletions
|
|
@ -1,32 +1,83 @@
|
|||
import { existsSync, mkdirSync, writeFileSync } from 'node:fs';
|
||||
import { join } from 'node:path';
|
||||
import { OUTPUT_DIR } from './config.js';
|
||||
import { storyboard } from './storyboard.js';
|
||||
import type { Storyboard } from './script.js';
|
||||
import { storyboards } from './storyboard.js';
|
||||
|
||||
/**
|
||||
* Emit the narration script for the synth step.
|
||||
* Emit per-storyboard narration scripts for the synth step.
|
||||
*
|
||||
* Synth (tts/synth.py) runs BEFORE recording, so it needs the full ordered
|
||||
* narration list — text + per-cue gaps — without depending on Playwright,
|
||||
* the dashboard, or auth. Walk the storyboard cues, write a flat manifest,
|
||||
* exit.
|
||||
* narration list — text + per-cue gaps + voice config — without depending
|
||||
* on Playwright, the dashboard, or auth. Walk each storyboard's cues, write
|
||||
* a flat manifest under `output/<name>/narration-script.json`, then write
|
||||
* an index manifest at `output/storyboards.json` so render.sh knows which
|
||||
* storyboard slugs to loop over.
|
||||
*
|
||||
* The cue index in this manifest is the source of truth: the runner later
|
||||
* The cue index in each manifest is the source of truth: the runner later
|
||||
* matches storyboard cues to measured durations by index.
|
||||
*/
|
||||
function main(): void {
|
||||
if (!existsSync(OUTPUT_DIR)) mkdirSync(OUTPUT_DIR, { recursive: true });
|
||||
// Em/en-dashes and ellipses make Qwen3-TTS produce dramatic pauses, sighs,
|
||||
// or audible breaths — the captions still render the original (unicode-rich)
|
||||
// text from the storyboard; only the synth input is sanitised.
|
||||
function normalizeForTts(text: string): string {
|
||||
return text
|
||||
.replace(/\s*[—–]\s*/g, ', ')
|
||||
.replace(/…/g, '.')
|
||||
.replace(/\.{3,}/g, '.')
|
||||
.replace(/\s{2,}/g, ' ')
|
||||
.trim();
|
||||
}
|
||||
|
||||
function emitScript(storyboard: Storyboard): string {
|
||||
const dir = join(OUTPUT_DIR, storyboard.name);
|
||||
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
||||
|
||||
const items = storyboard.cues.map((cue, cueIndex) => ({
|
||||
cueIndex,
|
||||
text: cue.text.trim(),
|
||||
text: normalizeForTts(cue.text),
|
||||
gapBeforeMs: cue.gapBeforeMs,
|
||||
}));
|
||||
|
||||
const manifest = { items };
|
||||
const path = join(OUTPUT_DIR, 'narration-script.json');
|
||||
// The voice block is consumed by tts/synth.py — see _resolve_reference and
|
||||
// the cache check there for which fields invalidate cached audio.
|
||||
const manifest = {
|
||||
storyboard: storyboard.name,
|
||||
voice: {
|
||||
instruct: storyboard.voice.instruct,
|
||||
language: storyboard.voice.language,
|
||||
temperature: storyboard.voice.temperature ?? 0.6,
|
||||
topP: storyboard.voice.topP ?? 0.9,
|
||||
seed: storyboard.voice.seed ?? 42,
|
||||
},
|
||||
items,
|
||||
};
|
||||
const path = join(dir, 'narration-script.json');
|
||||
writeFileSync(path, JSON.stringify(manifest, null, 2));
|
||||
console.log(`Wrote ${items.length} narration cues to ${path}`);
|
||||
console.log(`[preflight] [${storyboard.name}] wrote ${items.length} cues → ${path}`);
|
||||
return path;
|
||||
}
|
||||
|
||||
function main(): void {
|
||||
if (!existsSync(OUTPUT_DIR)) mkdirSync(OUTPUT_DIR, { recursive: true });
|
||||
|
||||
for (const sb of storyboards) emitScript(sb);
|
||||
|
||||
// Index for shell loops — each entry has every field render.sh needs to
|
||||
// address per-storyboard outputs without re-parsing the TS source.
|
||||
const index = {
|
||||
storyboards: storyboards.map((sb) => ({
|
||||
name: sb.name,
|
||||
aspect: sb.video.aspect,
|
||||
outputFps: sb.video.outputFps,
|
||||
minDurationS: sb.video.minDurationS,
|
||||
maxDurationS: sb.video.maxDurationS,
|
||||
posterTimeS: sb.video.posterTimeS,
|
||||
})),
|
||||
};
|
||||
const indexPath = join(OUTPUT_DIR, 'storyboards.json');
|
||||
writeFileSync(indexPath, JSON.stringify(index, null, 2));
|
||||
console.log(`[preflight] wrote storyboard index → ${indexPath}`);
|
||||
}
|
||||
|
||||
main();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue