@argo-video/cli 0.8.0 → 0.9.1

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 CHANGED
@@ -47,8 +47,9 @@ npm i -D @argo-video/cli
47
47
  # Initialize project
48
48
  npx argo init
49
49
 
50
- # Edit your demo script
50
+ # Edit your demo script (or convert an existing Playwright test)
51
51
  vim demos/example.demo.ts
52
+ npx argo init --from tests/checkout.spec.ts # auto-convert
52
53
 
53
54
  # Run the full pipeline
54
55
  npx argo pipeline example
@@ -174,6 +175,7 @@ export default defineConfig({
174
175
 
175
176
  ```
176
177
  argo init Scaffold demo files + config
178
+ argo init --from <test> Convert Playwright test to Argo demo
177
179
  argo record <demo> Record browser session
178
180
  argo tts generate <manifest> Generate TTS clips from manifest
179
181
  argo export <demo> Merge video + audio to MP4
@@ -251,15 +253,19 @@ choco install ffmpeg # Windows
251
253
  |--------|------|---------|---------|
252
254
  | `engines.kokoro()` | local | built-in | none |
253
255
  | `engines.mlxAudio()` | local | `pip install mlx-audio` | none |
256
+ | `engines.openai()` | cloud | `npm i openai` | `OPENAI_API_KEY` |
257
+ | `engines.elevenlabs()` | cloud | `npm i @elevenlabs/elevenlabs-js` | `ELEVENLABS_API_KEY` |
258
+ | `engines.gemini()` | cloud | `npm i @google/genai` | `GEMINI_API_KEY` |
259
+ | `engines.sarvam()` | cloud | `npm i sarvamai` | `SARVAM_API_KEY` |
254
260
 
255
261
  **Voice cloning** — Clone your own voice locally with mlx-audio. Record a 15-second clip, and every demo sounds like you — privately, no data leaves your machine:
256
262
 
257
263
  ```bash
258
264
  # Record a reference clip (macOS)
259
- ./scripts/record-voice-ref.sh assets/ref-voice.wav
265
+ bash $(npm root)/@argo-video/cli/scripts/record-voice-ref.sh assets/ref-voice.wav
260
266
 
261
267
  # Preview cloned voice against your manifest
262
- ./scripts/voice-clone-preview.sh \
268
+ bash $(npm root)/@argo-video/cli/scripts/voice-clone-preview.sh \
263
269
  --ref-audio assets/ref-voice.wav \
264
270
  --ref-text "Transcript of what I said." \
265
271
  --voiceover demos/showcase.voiceover.json --play
@@ -274,10 +280,6 @@ choco install ffmpeg # Windows
274
280
  }),
275
281
  }
276
282
  ```
277
- | `engines.openai()` | cloud | `npm i openai` | `OPENAI_API_KEY` |
278
- | `engines.elevenlabs()` | cloud | `npm i elevenlabs` | `ELEVENLABS_API_KEY` |
279
- | `engines.gemini()` | cloud | `npm i @google/genai` | `GEMINI_API_KEY` |
280
- | `engines.sarvam()` | cloud | none (fetch) | `SARVAM_API_KEY` |
281
283
 
282
284
  2. **Record** — Playwright runs the demo script in a real browser. The `narration` fixture records timestamps for each `mark()` call. Video is captured at native resolution.
283
285
 
package/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AA4B5C,wBAAgB,aAAa,IAAI,OAAO,CA0IvC"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AA4B5C,wBAAgB,aAAa,IAAI,OAAO,CAiJvC"}
package/dist/cli.js CHANGED
@@ -5,7 +5,7 @@ import { record } from './record.js';
5
5
  import { generateClips } from './tts/generate.js';
6
6
  import { exportVideo } from './export.js';
7
7
  import { runPipeline } from './pipeline.js';
8
- import { init } from './init.js';
8
+ import { init, initFrom } from './init.js';
9
9
  import { validateDemo } from './validate.js';
10
10
  import { runDoctor, formatDoctorResults } from './doctor.js';
11
11
  function validateDemoName(name) {
@@ -146,8 +146,17 @@ export function createProgram() {
146
146
  program
147
147
  .command('init')
148
148
  .description('Initialize a new Argo project')
149
- .action(async () => {
150
- await init();
149
+ .option('--from <path>', 'convert an existing Playwright test into an Argo demo')
150
+ .option('--demo <name>', 'demo name (defaults to filename without extension)')
151
+ .action(async (cmdOpts) => {
152
+ if (cmdOpts.from) {
153
+ if (cmdOpts.demo)
154
+ validateDemoName(cmdOpts.demo);
155
+ await initFrom({ from: cmdOpts.from, demo: cmdOpts.demo });
156
+ }
157
+ else {
158
+ await init();
159
+ }
151
160
  });
152
161
  return program;
153
162
  }
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
package/dist/init.d.ts CHANGED
@@ -1,2 +1,17 @@
1
1
  export declare function init(cwd?: string): Promise<void>;
2
+ export interface InitFromOptions {
3
+ /** Path to the Playwright test file to convert. */
4
+ from: string;
5
+ /** Demo name override. Defaults to filename without extension. */
6
+ demo?: string;
7
+ /** Working directory. Defaults to process.cwd(). */
8
+ cwd?: string;
9
+ }
10
+ /**
11
+ * Convert an existing Playwright test into an Argo demo project.
12
+ * Generates demo script (with fixture swap + mark() calls),
13
+ * skeleton voiceover.json (with _hint fields for LLM),
14
+ * and skeleton overlays.json.
15
+ */
16
+ export declare function initFrom(options: InitFromOptions): Promise<void>;
2
17
  //# sourceMappingURL=init.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AA6IA,wBAAsB,IAAI,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAcrE"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"AAmJA,wBAAsB,IAAI,CAAC,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,IAAI,CAAC,CAcrE;AAED,MAAM,WAAW,eAAe;IAC9B,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,kEAAkE;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oDAAoD;IACpD,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED;;;;;GAKG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA4DtE"}
package/dist/init.js CHANGED
@@ -1,5 +1,6 @@
1
- import { mkdir, writeFile, access } from 'node:fs/promises';
2
- import { join } from 'node:path';
1
+ import { mkdir, writeFile, readFile, access } from 'node:fs/promises';
2
+ import { join, basename } from 'node:path';
3
+ import { parsePlaywrightTest, generateDemoScript, generateVoiceoverSkeleton, generateOverlaysSkeleton, } from './parse-playwright.js';
3
4
  async function writeIfMissing(filePath, content) {
4
5
  try {
5
6
  await access(filePath);
@@ -138,4 +139,56 @@ export async function init(cwd = process.cwd()) {
138
139
  console.log(' 2. Run: npx argo record example');
139
140
  console.log(' 3. Run: npx argo pipeline example');
140
141
  }
142
+ /**
143
+ * Convert an existing Playwright test into an Argo demo project.
144
+ * Generates demo script (with fixture swap + mark() calls),
145
+ * skeleton voiceover.json (with _hint fields for LLM),
146
+ * and skeleton overlays.json.
147
+ */
148
+ export async function initFrom(options) {
149
+ const cwd = options.cwd ?? process.cwd();
150
+ const source = await readFile(options.from, 'utf-8');
151
+ // Derive demo name from filename: checkout.spec.ts → checkout
152
+ // Sanitize to match CLI's demo name validation: [a-zA-Z0-9][a-zA-Z0-9_-]*
153
+ const rawName = options.demo ??
154
+ basename(options.from)
155
+ .replace(/\.(spec|test|demo)\.(ts|js|mjs)$/, '')
156
+ .replace(/\.(ts|js|mjs)$/, '');
157
+ const demoName = rawName
158
+ .replace(/[^a-zA-Z0-9_-]/g, '-') // replace invalid chars with hyphens
159
+ .replace(/^-+/, '') // strip leading hyphens
160
+ .replace(/-+/g, '-'); // collapse consecutive hyphens
161
+ if (!demoName || !/^[a-zA-Z0-9]/.test(demoName)) {
162
+ throw new Error(`Cannot derive a valid demo name from "${rawName}". ` +
163
+ `Use --demo <name> to specify one (letters, numbers, hyphens, underscores).`);
164
+ }
165
+ const parsed = parsePlaywrightTest(source);
166
+ if (parsed.scenes.length === 0) {
167
+ throw new Error(`No scenes detected in ${options.from}. The file should contain Playwright actions like page.goto(), page.click(), etc.`);
168
+ }
169
+ const demosDir = join(cwd, 'demos');
170
+ await mkdir(demosDir, { recursive: true });
171
+ // Generate demo script
172
+ const demoScript = generateDemoScript(parsed);
173
+ await writeIfMissing(join(demosDir, `${demoName}.demo.ts`), demoScript);
174
+ // Generate voiceover skeleton with hints
175
+ const voiceover = generateVoiceoverSkeleton(parsed);
176
+ const voiceoverJson = JSON.stringify(voiceover, null, 2) + '\n';
177
+ await writeIfMissing(join(demosDir, `${demoName}.voiceover.json`), voiceoverJson);
178
+ // Generate overlays skeleton
179
+ const overlays = generateOverlaysSkeleton(parsed);
180
+ const overlaysJson = JSON.stringify(overlays, null, 2) + '\n';
181
+ await writeIfMissing(join(demosDir, `${demoName}.overlays.json`), overlaysJson);
182
+ // Scaffold config files if they don't exist
183
+ await writeIfMissing(join(cwd, 'argo.config.mjs'), ARGO_CONFIG);
184
+ await writeIfMissing(join(cwd, 'playwright.config.ts'), PLAYWRIGHT_CONFIG);
185
+ console.log(`\nConverted ${options.from} → ${demoName} (${parsed.scenes.length} scenes)`);
186
+ console.log('\nNext steps:');
187
+ console.log(` 1. Fill in voiceover text: demos/${demoName}.voiceover.json`);
188
+ console.log(` (use _hint fields as context, then remove them)`);
189
+ console.log(` 2. Refine overlays: demos/${demoName}.overlays.json`);
190
+ console.log(` 3. Run: npx argo pipeline ${demoName}`);
191
+ console.log(`\nTip: Ask your LLM to "flesh out the voiceover for ${demoName}" — it can`);
192
+ console.log('read the _hint fields and write natural narration text for each scene.');
193
+ }
141
194
  //# sourceMappingURL=init.js.map
package/dist/init.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Parses a Playwright test/script and extracts logical scene boundaries
3
+ * for converting into an Argo demo.
4
+ */
5
+ export interface ParsedScene {
6
+ /** Auto-generated scene name (kebab-case). */
7
+ name: string;
8
+ /** Lines of source code belonging to this scene. */
9
+ lines: string[];
10
+ /** Hint describing what happens in this scene (for LLM voiceover generation). */
11
+ hint: string;
12
+ }
13
+ export interface ParsedPlaywrightTest {
14
+ /** The test/function name found in the source. */
15
+ testName: string;
16
+ /** Detected scenes with their source lines and hints. */
17
+ scenes: ParsedScene[];
18
+ /** Original source lines (for reference). */
19
+ sourceLines: string[];
20
+ /** Imports found in the original file. */
21
+ imports: string[];
22
+ }
23
+ /**
24
+ * Parse a Playwright test file and extract scene boundaries.
25
+ */
26
+ export declare function parsePlaywrightTest(source: string): ParsedPlaywrightTest;
27
+ /**
28
+ * Generate an Argo demo script from a parsed Playwright test.
29
+ */
30
+ export declare function generateDemoScript(parsed: ParsedPlaywrightTest): string;
31
+ /**
32
+ * Generate a skeleton voiceover manifest from parsed scenes.
33
+ * Includes _hint fields for LLM-assisted text generation.
34
+ */
35
+ export declare function generateVoiceoverSkeleton(parsed: ParsedPlaywrightTest): Array<{
36
+ scene: string;
37
+ text: string;
38
+ _hint: string;
39
+ }>;
40
+ /**
41
+ * Generate a skeleton overlays manifest from parsed scenes.
42
+ * Creates a lower-third for each scene as a starting point.
43
+ */
44
+ export declare function generateOverlaysSkeleton(parsed: ParsedPlaywrightTest): Array<{
45
+ scene: string;
46
+ type: string;
47
+ text: string;
48
+ }>;
49
+ //# sourceMappingURL=parse-playwright.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-playwright.d.ts","sourceRoot":"","sources":["../src/parse-playwright.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,WAAW;IAC1B,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,oDAAoD;IACpD,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,oBAAoB;IACnC,kDAAkD;IAClD,QAAQ,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,6CAA6C;IAC7C,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,0CAA0C;IAC1C,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AA8FD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,oBAAoB,CA2ExE;AAmDD;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,CAqCvE;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,oBAAoB,GAC3B,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAMvD;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,oBAAoB,GAC3B,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAMtD"}
@@ -0,0 +1,265 @@
1
+ /**
2
+ * Parses a Playwright test/script and extracts logical scene boundaries
3
+ * for converting into an Argo demo.
4
+ */
5
+ /**
6
+ * Pattern matchers for scene boundary detection.
7
+ * Each returns a scene name suggestion and hint text if the line matches.
8
+ */
9
+ const BOUNDARY_PATTERNS = [
10
+ // test.step('name', ...) — explicit steps are the strongest signal
11
+ {
12
+ regex: /test\.step\(\s*(['"`])(.+?)\1/,
13
+ sceneName: (m) => slugify(m[2]),
14
+ hint: (m) => `test.step: ${m[2]}`,
15
+ alwaysBoundary: true,
16
+ },
17
+ // page.goto(url)
18
+ {
19
+ regex: /page\.goto\(\s*(['"`])(.+?)\1/,
20
+ sceneName: (m) => slugifyUrl(m[2]),
21
+ hint: (_m, line) => line.trim(),
22
+ alwaysBoundary: true,
23
+ },
24
+ // page.goto(variable/expression)
25
+ {
26
+ regex: /page\.goto\((.+?)\)/,
27
+ sceneName: () => 'navigate',
28
+ hint: (_m, line) => line.trim(),
29
+ alwaysBoundary: true,
30
+ },
31
+ // // Comment lines — strong candidate for scene label
32
+ {
33
+ regex: /^\s*\/\/\s*(.+)/,
34
+ sceneName: (m) => slugify(m[1]),
35
+ hint: (m) => `comment: ${m[1].trim()}`,
36
+ alwaysBoundary: true,
37
+ },
38
+ // page.click / locator.click
39
+ {
40
+ regex: /\.click\(/,
41
+ sceneName: () => 'click-action',
42
+ hint: (_m, line) => line.trim(),
43
+ alwaysBoundary: false,
44
+ },
45
+ // page.fill / locator.fill
46
+ {
47
+ regex: /\.fill\(/,
48
+ sceneName: () => 'form-input',
49
+ hint: (_m, line) => line.trim(),
50
+ alwaysBoundary: false,
51
+ },
52
+ // expect(...).toBeVisible / toHaveText / etc.
53
+ {
54
+ regex: /expect\(.+?\)\.\w+/,
55
+ sceneName: () => 'verify',
56
+ hint: (_m, line) => line.trim(),
57
+ alwaysBoundary: false,
58
+ },
59
+ // page.waitForSelector / page.waitForURL / locator.waitFor
60
+ {
61
+ regex: /\.waitFor(?:Selector|URL|Navigation)?\(/,
62
+ sceneName: () => 'wait',
63
+ hint: (_m, line) => line.trim(),
64
+ alwaysBoundary: false,
65
+ },
66
+ ];
67
+ /** Lines that are structural and should not form their own scenes. */
68
+ const SKIP_PATTERNS = [
69
+ /^\s*$/, // blank lines
70
+ /^\s*import\s/, // imports
71
+ /^\s*(?:const|let|var)\s/, // variable declarations (unless they contain actions)
72
+ /^\s*[{})\]];?\s*$/, // lone braces/brackets
73
+ /^\s*(?:test|describe)\s*\(/, // test/describe wrappers
74
+ /^\s*(?:test|describe)\.(?!step)\w+\(/, // test.only, describe.skip, etc. (but NOT test.step)
75
+ /^\s*async\s/, // async arrow functions
76
+ /^\s*\}\s*\)\s*;?\s*$/, // closing }) patterns
77
+ ];
78
+ function shouldSkipLine(line) {
79
+ // Don't skip if line contains a Playwright action
80
+ if (/page\.|locator|expect\(/.test(line))
81
+ return false;
82
+ return SKIP_PATTERNS.some((p) => p.test(line));
83
+ }
84
+ /**
85
+ * Parse a Playwright test file and extract scene boundaries.
86
+ */
87
+ export function parsePlaywrightTest(source) {
88
+ const sourceLines = source.split('\n');
89
+ // Extract imports
90
+ const imports = sourceLines.filter((l) => /^\s*import\s/.test(l));
91
+ // Find the test name
92
+ const testNameMatch = source.match(/test\(\s*(['"`])(.+?)\1/);
93
+ const testName = testNameMatch?.[2] ?? 'demo';
94
+ // Collect actions grouped into scenes
95
+ const scenes = [];
96
+ let currentActions = [];
97
+ let currentSceneName = '';
98
+ /** True when the current scene was named by test.step — suppresses other boundary flushes. */
99
+ let namedByStep = false;
100
+ let sceneNameCounts = new Map();
101
+ function flushScene() {
102
+ if (currentActions.length === 0)
103
+ return;
104
+ // Determine scene name
105
+ let name = currentSceneName || inferSceneName(currentActions);
106
+ name = deduplicateName(name, sceneNameCounts);
107
+ scenes.push({
108
+ name,
109
+ lines: currentActions.map((a) => a.line),
110
+ hint: currentActions.map((a) => a.hint).join(', '),
111
+ });
112
+ currentActions = [];
113
+ currentSceneName = '';
114
+ namedByStep = false;
115
+ }
116
+ for (const line of sourceLines) {
117
+ if (shouldSkipLine(line))
118
+ continue;
119
+ // Check if this line matches a boundary pattern
120
+ let matched = false;
121
+ for (const pattern of BOUNDARY_PATTERNS) {
122
+ const m = line.match(pattern.regex);
123
+ if (!m)
124
+ continue;
125
+ const isStep = pattern.regex.source.startsWith('test\\.step');
126
+ if (isStep) {
127
+ // test.step always starts a new scene
128
+ if (currentActions.length > 0)
129
+ flushScene();
130
+ currentSceneName = pattern.sceneName(m);
131
+ namedByStep = true;
132
+ }
133
+ else if (pattern.alwaysBoundary && !namedByStep && currentActions.length > 0) {
134
+ // Other boundaries (goto, comments) flush only if not inside a test.step scene
135
+ flushScene();
136
+ currentSceneName = pattern.sceneName(m);
137
+ }
138
+ else if (!currentSceneName) {
139
+ currentSceneName = pattern.sceneName(m);
140
+ }
141
+ currentActions.push({ line, hint: pattern.hint(m, line) });
142
+ matched = true;
143
+ break;
144
+ }
145
+ if (!matched && /page\.|locator|expect\(/.test(line)) {
146
+ // It's a Playwright action but not a recognized pattern — still include it
147
+ currentActions.push({ line, hint: line.trim() });
148
+ }
149
+ }
150
+ // Flush remaining actions
151
+ flushScene();
152
+ return { testName, scenes, sourceLines, imports };
153
+ }
154
+ /**
155
+ * Infer a scene name from the actions it contains.
156
+ */
157
+ function inferSceneName(actions) {
158
+ for (const a of actions) {
159
+ // Try to extract a meaningful name from selectors
160
+ const selectorMatch = a.line.match(/['"`]([#.][a-zA-Z0-9_-]+)['"`]/);
161
+ if (selectorMatch) {
162
+ return slugify(selectorMatch[1].replace(/^[#.]/, ''));
163
+ }
164
+ // Try aria labels
165
+ const ariaMatch = a.line.match(/getByRole\(.+?,\s*\{\s*name:\s*['"`](.+?)['"`]/);
166
+ if (ariaMatch) {
167
+ return slugify(ariaMatch[1]);
168
+ }
169
+ // Try getByText
170
+ const textMatch = a.line.match(/getByText\(\s*['"`](.+?)['"`]/);
171
+ if (textMatch) {
172
+ return slugify(textMatch[1]);
173
+ }
174
+ }
175
+ return 'step';
176
+ }
177
+ function slugify(text) {
178
+ return text
179
+ .toLowerCase()
180
+ .replace(/[^a-z0-9]+/g, '-')
181
+ .replace(/^-+|-+$/g, '')
182
+ .slice(0, 30) || 'step';
183
+ }
184
+ function slugifyUrl(url) {
185
+ // Extract the meaningful path segment
186
+ try {
187
+ const pathname = new URL(url, 'http://localhost').pathname;
188
+ const segment = pathname.split('/').filter(Boolean).pop() ?? 'home';
189
+ return slugify(segment);
190
+ }
191
+ catch {
192
+ return slugify(url);
193
+ }
194
+ }
195
+ function deduplicateName(name, counts) {
196
+ const count = counts.get(name) ?? 0;
197
+ counts.set(name, count + 1);
198
+ return count === 0 ? name : `${name}-${count + 1}`;
199
+ }
200
+ /**
201
+ * Generate an Argo demo script from a parsed Playwright test.
202
+ */
203
+ export function generateDemoScript(parsed) {
204
+ const lines = [];
205
+ // Check if any scene lines contain expect() to decide on imports
206
+ const hasExpect = parsed.scenes.some(s => s.lines.some(l => /\bexpect\s*\(/.test(l)));
207
+ if (hasExpect) {
208
+ lines.push("import { test, expect } from '@argo-video/cli';");
209
+ }
210
+ else {
211
+ lines.push("import { test } from '@argo-video/cli';");
212
+ }
213
+ lines.push("import { showOverlay, withOverlay } from '@argo-video/cli';");
214
+ lines.push('');
215
+ lines.push(`test('${parsed.testName}', async ({ page, narration }) => {`);
216
+ for (const scene of parsed.scenes) {
217
+ lines.push('');
218
+ lines.push(` narration.mark('${scene.name}');`);
219
+ for (const sourceLine of scene.lines) {
220
+ // Strip test.step() wrappers — we flatten steps into narration.mark() scenes
221
+ const stripped = sourceLine
222
+ .replace(/^\s*test\.step\s*\(\s*(['"`]).*?\1\s*,\s*async\s*\(\s*\)\s*=>\s*\{\s*$/, '')
223
+ .replace(/^\s*\}\s*\)\s*;?\s*$/, '');
224
+ if (stripped === '')
225
+ continue;
226
+ // Normalize indentation to 2-space inside the test block
227
+ const trimmed = stripped.replace(/^\s+/, '');
228
+ lines.push(` ${trimmed}`);
229
+ }
230
+ lines.push(` await page.waitForTimeout(narration.durationFor('${scene.name}'));`);
231
+ }
232
+ lines.push('});');
233
+ lines.push('');
234
+ return lines.join('\n');
235
+ }
236
+ /**
237
+ * Generate a skeleton voiceover manifest from parsed scenes.
238
+ * Includes _hint fields for LLM-assisted text generation.
239
+ */
240
+ export function generateVoiceoverSkeleton(parsed) {
241
+ return parsed.scenes.map((s) => ({
242
+ scene: s.name,
243
+ text: '',
244
+ _hint: s.hint,
245
+ }));
246
+ }
247
+ /**
248
+ * Generate a skeleton overlays manifest from parsed scenes.
249
+ * Creates a lower-third for each scene as a starting point.
250
+ */
251
+ export function generateOverlaysSkeleton(parsed) {
252
+ return parsed.scenes.map((s) => ({
253
+ scene: s.name,
254
+ type: 'lower-third',
255
+ text: humanize(s.name),
256
+ }));
257
+ }
258
+ /** Convert kebab-case scene name to Title Case display text. */
259
+ function humanize(name) {
260
+ return name
261
+ .split('-')
262
+ .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
263
+ .join(' ');
264
+ }
265
+ //# sourceMappingURL=parse-playwright.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parse-playwright.js","sourceRoot":"","sources":["../src/parse-playwright.ts"],"names":[],"mappings":"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"}
@@ -22,11 +22,11 @@ export class ElevenLabsEngine {
22
22
  throw new Error('TTS text must not be empty');
23
23
  let ElevenLabsClient;
24
24
  try {
25
- // @ts-ignore — elevenlabs is an optional dependency
26
- ({ ElevenLabsClient } = await import('elevenlabs'));
25
+ // @ts-ignore — @elevenlabs/elevenlabs-js is an optional dependency
26
+ ({ ElevenLabsClient } = await import('@elevenlabs/elevenlabs-js'));
27
27
  }
28
28
  catch {
29
- throw new Error("ElevenLabs TTS engine requires the 'elevenlabs' package. Install it with: npm i elevenlabs");
29
+ throw new Error("ElevenLabs TTS engine requires the '@elevenlabs/elevenlabs-js' package. Install it with: npm i @elevenlabs/elevenlabs-js");
30
30
  }
31
31
  const client = new ElevenLabsClient({ apiKey: this.resolveApiKey() });
32
32
  const audioStream = await client.textToSpeech.convert(options.voice ?? '21m00Tcm4TlvDq8ikWAM', // Rachel default
@@ -1 +1 @@
1
- {"version":3,"file":"elevenlabs.js","sourceRoot":"","sources":["../../../src/tts/engines/elevenlabs.ts"],"names":[],"mappings":"AASA,MAAM,OAAO,gBAAgB;IACnB,MAAM,CAAS;IACf,KAAK,CAAS;IACd,SAAS,CAAS;IAClB,eAAe,CAAS;IAEhC,YAAY,OAAiC;QAC3C,IAAI,CAAC,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,EAAE,CAAC;QACpC,IAAI,CAAC,KAAK,GAAG,OAAO,EAAE,KAAK,IAAI,uBAAuB,CAAC;QACvD,IAAI,CAAC,SAAS,GAAG,OAAO,EAAE,SAAS,IAAI,GAAG,CAAC;QAC3C,IAAI,CAAC,eAAe,GAAG,OAAO,EAAE,eAAe,IAAI,IAAI,CAAC;IAC1D,CAAC;IAEO,aAAa;QACnB,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,EAAE,CAAC;QAChE,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CACb,6CAA6C;gBAC7C,oEAAoE,CACrE,CAAC;QACJ,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,IAAY,EAAE,OAAyB;QACpD,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAEjE,IAAI,gBAAqB,CAAC;QAC1B,IAAI,CAAC;YACH,oDAAoD;YACpD,CAAC,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC;QACtD,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CACb,4FAA4F,CAC7F,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;QACtE,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,OAAO,CACnD,OAAO,CAAC,KAAK,IAAI,sBAAsB,EAAE,iBAAiB;QAC1D;YACE,IAAI;YACJ,QAAQ,EAAE,IAAI,CAAC,KAAK;YACpB,cAAc,EAAE;gBACd,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,gBAAgB,EAAE,IAAI,CAAC,eAAe;aACvC;SACF,CACF,CAAC;QAEF,6BAA6B;QAC7B,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,WAAW,EAAE,CAAC;YACtC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAClC,CAAC;QACD,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAExC,iCAAiC;QACjC,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;QACtD,OAAO,YAAY,CAAC,SAAS,CAAC,CAAC;IACjC,CAAC;CACF"}
1
+ {"version":3,"file":"elevenlabs.js","sourceRoot":"","sources":["../../../src/tts/engines/elevenlabs.ts"],"names":[],"mappings":"AASA,MAAM,OAAO,gBAAgB;IACnB,MAAM,CAAS;IACf,KAAK,CAAS;IACd,SAAS,CAAS;IAClB,eAAe,CAAS;IAEhC,YAAY,OAAiC;QAC3C,IAAI,CAAC,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,EAAE,CAAC;QACpC,IAAI,CAAC,KAAK,GAAG,OAAO,EAAE,KAAK,IAAI,uBAAuB,CAAC;QACvD,IAAI,CAAC,SAAS,GAAG,OAAO,EAAE,SAAS,IAAI,GAAG,CAAC;QAC3C,IAAI,CAAC,eAAe,GAAG,OAAO,EAAE,eAAe,IAAI,IAAI,CAAC;IAC1D,CAAC;IAEO,aAAa;QACnB,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,EAAE,CAAC;QAChE,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CACb,6CAA6C;gBAC7C,oEAAoE,CACrE,CAAC;QACJ,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,IAAY,EAAE,OAAyB;QACpD,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAEjE,IAAI,gBAAqB,CAAC;QAC1B,IAAI,CAAC;YACH,mEAAmE;YACnE,CAAC,EAAE,gBAAgB,EAAE,GAAG,MAAM,MAAM,CAAC,2BAA2B,CAAC,CAAC,CAAC;QACrE,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CACb,0HAA0H,CAC3H,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;QACtE,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,OAAO,CACnD,OAAO,CAAC,KAAK,IAAI,sBAAsB,EAAE,iBAAiB;QAC1D;YACE,IAAI;YACJ,QAAQ,EAAE,IAAI,CAAC,KAAK;YACpB,cAAc,EAAE;gBACd,SAAS,EAAE,IAAI,CAAC,SAAS;gBACzB,gBAAgB,EAAE,IAAI,CAAC,eAAe;aACvC;SACF,CACF,CAAC;QAEF,6BAA6B;QAC7B,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,WAAW,EAAE,CAAC;YACtC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAClC,CAAC;QACD,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAExC,iCAAiC;QACjC,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;QACtD,OAAO,YAAY,CAAC,SAAS,CAAC,CAAC;IACjC,CAAC;CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"sarvam.d.ts","sourceRoot":"","sources":["../../../src/tts/engines/sarvam.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhE,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,YAAa,YAAW,SAAS;IAC5C,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAS;gBAEV,OAAO,CAAC,EAAE,mBAAmB;IAKzC,OAAO,CAAC,aAAa;IAWf,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC;CAsCzE"}
1
+ {"version":3,"file":"sarvam.d.ts","sourceRoot":"","sources":["../../../src/tts/engines/sarvam.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhE,MAAM,WAAW,mBAAmB;IAClC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,YAAa,YAAW,SAAS;IAC5C,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAS;gBAEV,OAAO,CAAC,EAAE,mBAAmB;IAKzC,OAAO,CAAC,aAAa;IAWf,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC;CAoCzE"}
@@ -16,33 +16,30 @@ export class SarvamEngine {
16
16
  async generate(text, options) {
17
17
  if (!text?.trim())
18
18
  throw new Error('TTS text must not be empty');
19
- const response = await fetch('https://api.sarvam.ai/text-to-speech', {
20
- method: 'POST',
21
- headers: {
22
- 'Content-Type': 'application/json',
23
- 'API-Subscription-Key': this.resolveApiKey(),
24
- },
25
- body: JSON.stringify({
26
- inputs: [text],
27
- target_language_code: options.lang ?? 'hi-IN',
28
- speaker: options.voice ?? 'meera',
29
- model: this.model,
30
- pitch: 0,
31
- pace: options.speed ?? 1.0,
32
- loudness: 1.5,
33
- enable_preprocessing: true,
34
- }),
35
- });
36
- if (!response.ok) {
37
- const body = await response.text();
38
- throw new Error(`Sarvam TTS API error ${response.status}: ${body}`);
19
+ let SarvamAI;
20
+ try {
21
+ // @ts-ignore — sarvamai is an optional dependency
22
+ ({ default: SarvamAI } = await import('sarvamai'));
23
+ }
24
+ catch {
25
+ throw new Error("Sarvam TTS engine requires the 'sarvamai' package. Install it with: npm i sarvamai");
39
26
  }
40
- const json = await response.json();
41
- if (!json.audios?.[0]) {
27
+ const client = new SarvamAI({ apiSubscriptionKey: this.resolveApiKey() });
28
+ const response = await client.textToSpeech.convert({
29
+ inputs: [text],
30
+ target_language_code: options.lang ?? 'hi-IN',
31
+ speaker: options.voice ?? 'meera',
32
+ model: this.model,
33
+ pitch: 0,
34
+ pace: options.speed ?? 1.0,
35
+ loudness: 1.5,
36
+ enable_preprocessing: true,
37
+ });
38
+ if (!response.audios?.[0]) {
42
39
  throw new Error('Sarvam TTS returned no audio data');
43
40
  }
44
41
  // Sarvam returns base64-encoded WAV
45
- const audioBuffer = Buffer.from(json.audios[0], 'base64');
42
+ const audioBuffer = Buffer.from(response.audios[0], 'base64');
46
43
  // Convert to Argo WAV format (mono Float32 24kHz)
47
44
  const { convertToWav } = await import('../engine.js');
48
45
  return convertToWav(audioBuffer);
@@ -1 +1 @@
1
- {"version":3,"file":"sarvam.js","sourceRoot":"","sources":["../../../src/tts/engines/sarvam.ts"],"names":[],"mappings":"AAOA,MAAM,OAAO,YAAY;IACf,MAAM,CAAS;IACf,KAAK,CAAS;IAEtB,YAAY,OAA6B;QACvC,IAAI,CAAC,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,EAAE,CAAC;QACpC,IAAI,CAAC,KAAK,GAAG,OAAO,EAAE,KAAK,IAAI,WAAW,CAAC;IAC7C,CAAC;IAEO,aAAa;QACnB,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC;QAC5D,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CACb,yCAAyC;gBACzC,gEAAgE,CACjE,CAAC;QACJ,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,IAAY,EAAE,OAAyB;QACpD,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAEjE,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,sCAAsC,EAAE;YACnE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,sBAAsB,EAAE,IAAI,CAAC,aAAa,EAAE;aAC7C;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,MAAM,EAAE,CAAC,IAAI,CAAC;gBACd,oBAAoB,EAAE,OAAO,CAAC,IAAI,IAAI,OAAO;gBAC7C,OAAO,EAAE,OAAO,CAAC,KAAK,IAAI,OAAO;gBACjC,KAAK,EAAE,IAAI,CAAC,KAAK;gBACjB,KAAK,EAAE,CAAC;gBACR,IAAI,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG;gBAC1B,QAAQ,EAAE,GAAG;gBACb,oBAAoB,EAAE,IAAI;aAC3B,CAAC;SACH,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CAAC,wBAAwB,QAAQ,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC,CAAC;QACtE,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAA2B,CAAC;QAC5D,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACtB,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACvD,CAAC;QAED,oCAAoC;QACpC,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;QAE1D,kDAAkD;QAClD,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;QACtD,OAAO,YAAY,CAAC,WAAW,CAAC,CAAC;IACnC,CAAC;CACF"}
1
+ {"version":3,"file":"sarvam.js","sourceRoot":"","sources":["../../../src/tts/engines/sarvam.ts"],"names":[],"mappings":"AAOA,MAAM,OAAO,YAAY;IACf,MAAM,CAAS;IACf,KAAK,CAAS;IAEtB,YAAY,OAA6B;QACvC,IAAI,CAAC,MAAM,GAAG,OAAO,EAAE,MAAM,IAAI,EAAE,CAAC;QACpC,IAAI,CAAC,KAAK,GAAG,OAAO,EAAE,KAAK,IAAI,WAAW,CAAC;IAC7C,CAAC;IAEO,aAAa;QACnB,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE,CAAC;QAC5D,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,MAAM,IAAI,KAAK,CACb,yCAAyC;gBACzC,gEAAgE,CACjE,CAAC;QACJ,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,IAAY,EAAE,OAAyB;QACpD,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAEjE,IAAI,QAAa,CAAC;QAClB,IAAI,CAAC;YACH,kDAAkD;YAClD,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;QACrD,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,IAAI,KAAK,CACb,oFAAoF,CACrF,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,QAAQ,CAAC,EAAE,kBAAkB,EAAE,IAAI,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;QAC1E,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC;YACjD,MAAM,EAAE,CAAC,IAAI,CAAC;YACd,oBAAoB,EAAE,OAAO,CAAC,IAAI,IAAI,OAAO;YAC7C,OAAO,EAAE,OAAO,CAAC,KAAK,IAAI,OAAO;YACjC,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,KAAK,EAAE,CAAC;YACR,IAAI,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG;YAC1B,QAAQ,EAAE,GAAG;YACb,oBAAoB,EAAE,IAAI;SAC3B,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;QACvD,CAAC;QAED,oCAAoC;QACpC,MAAM,WAAW,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;QAE9D,kDAAkD;QAClD,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;QACtD,OAAO,YAAY,CAAC,WAAW,CAAC,CAAC;IACnC,CAAC;CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/tts/generate.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAI7C,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,SAAS,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/C;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAkExF"}
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../src/tts/generate.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAI7C,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,SAAS,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/C;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAsExF"}
@@ -45,17 +45,22 @@ export async function generateClips(options) {
45
45
  };
46
46
  return { entry, clipPath: cache.getClipPath(demoName, entry) };
47
47
  });
48
- // Generate uncached clips sequentially — Kokoro's ONNX runtime is not
49
- // safe for concurrent generate() calls (mutex errors). The shared init
50
- // promise prevents duplicate model downloads, but generation must serialize.
51
- const uncached = entries.filter(({ entry }) => !cache.isCached(demoName, entry));
52
- for (const { entry } of uncached) {
53
- const wavBuffer = await engine.generate(entry.text, {
54
- voice: entry.voice,
55
- speed: entry.speed,
56
- lang: entry.lang,
57
- });
58
- cache.cacheClip(demoName, entry, wavBuffer);
48
+ // Log per-scene status and generate uncached clips sequentially —
49
+ // Kokoro's ONNX runtime is not safe for concurrent generate() calls.
50
+ for (const { entry } of entries) {
51
+ if (cache.isCached(demoName, entry)) {
52
+ console.log(` ▸ ${entry.scene} (cached)`);
53
+ }
54
+ else {
55
+ process.stdout.write(` ▸ ${entry.scene} (generating...)`);
56
+ const wavBuffer = await engine.generate(entry.text, {
57
+ voice: entry.voice,
58
+ speed: entry.speed,
59
+ lang: entry.lang,
60
+ });
61
+ cache.cacheClip(demoName, entry, wavBuffer);
62
+ process.stdout.write(' done\n');
63
+ }
59
64
  }
60
65
  // Read results (all clips now cached)
61
66
  return entries.map(({ entry, clipPath }) => {
@@ -1 +1 @@
1
- {"version":3,"file":"generate.js","sourceRoot":"","sources":["../../src/tts/generate.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../../src/tts/generate.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@argo-video/cli",
3
- "version": "0.8.0",
3
+ "version": "0.9.1",
4
4
  "description": "Turn Playwright demo scripts into polished product demo videos with AI voiceover",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -29,6 +29,12 @@
29
29
  "commander": "^12.0.0",
30
30
  "kokoro-js": "^1.2.1"
31
31
  },
32
+ "optionalDependencies": {
33
+ "@elevenlabs/elevenlabs-js": "^2.0.0",
34
+ "@google/genai": "^1.0.0",
35
+ "openai": "^4.0.0",
36
+ "sarvamai": "^1.0.0"
37
+ },
32
38
  "publishConfig": {
33
39
  "access": "public"
34
40
  },
@@ -39,7 +45,8 @@
39
45
  "license": "MIT",
40
46
  "files": [
41
47
  "dist",
42
- "bin"
48
+ "bin",
49
+ "scripts"
43
50
  ],
44
51
  "devDependencies": {
45
52
  "@playwright/test": "^1.50.0",
@@ -0,0 +1,174 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ import random
5
+
6
+ from PIL import Image, ImageDraw, ImageFilter, ImageFont
7
+
8
+
9
+ ROOT = Path(__file__).resolve().parents[1]
10
+ ASSETS = ROOT / "assets"
11
+ OUTPUT_PATH = ASSETS / "logo-thumb.png"
12
+ SOURCE_MARK_PATH = ASSETS / "logo-mark-source.png"
13
+
14
+ WIDTH = 1920
15
+ HEIGHT = 1080
16
+
17
+ MONO_FONT = "/System/Library/Fonts/SFNSMono.ttf"
18
+ DISPLAY_BOLD = "/Library/Fonts/SF-Compact-Display-Bold.otf"
19
+
20
+
21
+ def load_font(path: str, size: int) -> ImageFont.FreeTypeFont:
22
+ return ImageFont.truetype(path, size=size)
23
+
24
+
25
+ def normalize_mark() -> Image.Image:
26
+ if SOURCE_MARK_PATH.exists():
27
+ return Image.open(SOURCE_MARK_PATH).convert("RGBA")
28
+
29
+ original = Image.open(OUTPUT_PATH).convert("RGBA")
30
+ mark = Image.new("RGBA", original.size, (0, 0, 0, 0))
31
+ in_px = original.load()
32
+ out_px = mark.load()
33
+
34
+ for y in range(original.height):
35
+ for x in range(original.width):
36
+ r, g, b, _ = in_px[x, y]
37
+ if b > 150 and g > 110 and r < 140:
38
+ out_px[x, y] = (107, 180, 255, 255)
39
+
40
+ bbox = mark.getbbox()
41
+ if bbox is None:
42
+ raise RuntimeError("Could not isolate source logo mark")
43
+
44
+ cropped = mark.crop(bbox)
45
+ cropped.save(SOURCE_MARK_PATH)
46
+ return cropped
47
+
48
+
49
+ def lerp(a: int, b: int, t: float) -> int:
50
+ return int(a + (b - a) * t)
51
+
52
+
53
+ def make_background() -> Image.Image:
54
+ image = Image.new("RGBA", (WIDTH, HEIGHT), (0, 0, 0, 255))
55
+ px = image.load()
56
+
57
+ top_left = (8, 10, 18)
58
+ bottom_right = (18, 22, 37)
59
+ top_right = (12, 14, 26)
60
+
61
+ for y in range(HEIGHT):
62
+ ty = y / (HEIGHT - 1)
63
+ for x in range(WIDTH):
64
+ tx = x / (WIDTH - 1)
65
+ r = lerp(lerp(top_left[0], top_right[0], tx), bottom_right[0], ty)
66
+ g = lerp(lerp(top_left[1], top_right[1], tx), bottom_right[1], ty)
67
+ b = lerp(lerp(top_left[2], top_right[2], tx), bottom_right[2], ty)
68
+ px[x, y] = (r, g, b, 255)
69
+
70
+ return image
71
+
72
+
73
+ def add_radial_glow(base: Image.Image, center: tuple[int, int], radius: int, color: tuple[int, int, int], alpha: int, blur: int) -> None:
74
+ layer = Image.new("RGBA", base.size, (0, 0, 0, 0))
75
+ draw = ImageDraw.Draw(layer)
76
+ x, y = center
77
+ draw.ellipse((x - radius, y - radius, x + radius, y + radius), fill=color + (alpha,))
78
+ layer = layer.filter(ImageFilter.GaussianBlur(blur))
79
+ base.alpha_composite(layer)
80
+
81
+
82
+ def add_grid(base: Image.Image) -> None:
83
+ grid = Image.new("RGBA", base.size, (0, 0, 0, 0))
84
+ draw = ImageDraw.Draw(grid)
85
+
86
+ for x in range(120, WIDTH, 96):
87
+ draw.line((x, 0, x, HEIGHT), fill=(92, 126, 188, 14), width=1)
88
+ for y in range(96, HEIGHT, 96):
89
+ draw.line((0, y, WIDTH, y), fill=(92, 126, 188, 10), width=1)
90
+
91
+ random.seed(7)
92
+ for _ in range(240):
93
+ x = random.randint(0, WIDTH - 1)
94
+ y = random.randint(0, HEIGHT - 1)
95
+ draw.point((x, y), fill=(160, 185, 255, random.randint(10, 28)))
96
+
97
+ base.alpha_composite(grid)
98
+
99
+
100
+ def draw_mark(base: Image.Image, mark: Image.Image) -> None:
101
+ mark = mark.resize((1440, int(mark.height * (1440 / mark.width))), Image.Resampling.LANCZOS)
102
+
103
+ glow = Image.new("RGBA", base.size, (0, 0, 0, 0))
104
+ glow_mark = mark.copy()
105
+ glow_mark = glow_mark.filter(ImageFilter.GaussianBlur(14))
106
+ gx = (WIDTH - glow_mark.width) // 2
107
+ gy = 200
108
+ glow.alpha_composite(glow_mark, (gx, gy))
109
+
110
+ tint = Image.new("RGBA", base.size, (0, 0, 0, 0))
111
+ tint_draw = ImageDraw.Draw(tint)
112
+ tint_draw.ellipse((420, 220, 1500, 760), fill=(71, 136, 255, 30))
113
+ tint = tint.filter(ImageFilter.GaussianBlur(54))
114
+
115
+ base.alpha_composite(tint)
116
+ base.alpha_composite(glow, (0, 0))
117
+
118
+ mark_shadow = Image.new("RGBA", base.size, (0, 0, 0, 0))
119
+ shadow = mark.copy().filter(ImageFilter.GaussianBlur(18))
120
+ mark_shadow.alpha_composite(shadow, (gx, gy + 8))
121
+ base.alpha_composite(mark_shadow)
122
+ base.alpha_composite(mark, (gx, gy))
123
+
124
+
125
+ def draw_command_card(base: Image.Image) -> None:
126
+ card = Image.new("RGBA", base.size, (0, 0, 0, 0))
127
+ draw = ImageDraw.Draw(card)
128
+
129
+ x0, y0, x1, y1 = 500, 760, 1420, 892
130
+ shadow = Image.new("RGBA", base.size, (0, 0, 0, 0))
131
+ ImageDraw.Draw(shadow).rounded_rectangle((x0, y0 + 18, x1, y1 + 18), radius=34, fill=(0, 0, 0, 120))
132
+ shadow = shadow.filter(ImageFilter.GaussianBlur(24))
133
+ base.alpha_composite(shadow)
134
+
135
+ draw.rounded_rectangle((x0, y0, x1, y1), radius=34, fill=(14, 18, 30, 228), outline=(97, 127, 183, 88), width=2)
136
+ draw.rounded_rectangle((x0 + 2, y0 + 2, x1 - 2, y0 + 38), radius=32, fill=(18, 23, 38, 245))
137
+
138
+ button_y = y0 + 20
139
+ for idx, color in enumerate(((255, 95, 86), (255, 189, 46), (39, 201, 63))):
140
+ bx = x0 + 30 + idx * 22
141
+ draw.ellipse((bx, button_y, bx + 12, button_y + 12), fill=color)
142
+
143
+ mono = load_font(MONO_FONT, 40)
144
+ small = load_font(MONO_FONT, 24)
145
+
146
+ prompt_y = y0 + 64
147
+ draw.text((x0 + 34, prompt_y), "$", font=mono, fill=(123, 217, 129))
148
+ draw.text((x0 + 72, prompt_y), "npx argo", font=mono, fill=(110, 187, 255))
149
+ draw.text((x0 + 330, prompt_y), "pipeline", font=mono, fill=(233, 239, 252))
150
+ draw.text((x0 + 566, prompt_y), "showcase", font=mono, fill=(169, 146, 255))
151
+
152
+ note = "local-first • webkit-friendly • retina-ready"
153
+ note_box = draw.textbbox((0, 0), note, font=small)
154
+ note_x = (WIDTH - (note_box[2] - note_box[0])) / 2
155
+ draw.text((note_x, y1 + 24), note, font=small, fill=(100, 121, 160))
156
+
157
+ base.alpha_composite(card)
158
+
159
+
160
+ def main() -> None:
161
+ ASSETS.mkdir(exist_ok=True)
162
+ mark = normalize_mark()
163
+ image = make_background()
164
+ add_radial_glow(image, (WIDTH // 2, 420), 420, (48, 99, 235), 48, 96)
165
+ add_radial_glow(image, (1470, 210), 220, (41, 91, 235), 42, 84)
166
+ add_radial_glow(image, (360, 910), 300, (43, 74, 170), 34, 92)
167
+ add_grid(image)
168
+ draw_mark(image, mark)
169
+ draw_command_card(image)
170
+ image.convert("RGB").save(OUTPUT_PATH, quality=95)
171
+
172
+
173
+ if __name__ == "__main__":
174
+ main()
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Record and process a voice reference clip for mlx-audio voice cloning.
4
+ # Usage: ./scripts/record-voice-ref.sh [output_path]
5
+ #
6
+ # Requirements: ffmpeg (brew install ffmpeg), macOS with built-in mic
7
+ #
8
+ set -euo pipefail
9
+
10
+ OUTPUT="${1:-assets/ref-voice.wav}"
11
+ RAW_FILE=$(mktemp /tmp/voice-ref-raw.XXXXXX.wav)
12
+
13
+ # Suggested text — covers a wide range of English phonemes
14
+ cat <<'PROMPT'
15
+ ╔══════════════════════════════════════════════════════════════════╗
16
+ ║ Voice Reference Recording ║
17
+ ╠══════════════════════════════════════════════════════════════════╣
18
+ ║ ║
19
+ ║ Read the following text naturally, at your demo narration pace: ║
20
+ ║ ║
21
+ ║ "Hi, my name is [YOUR NAME]. I build developer tools and love ║
22
+ ║ creating great product demos. The quick brown fox jumps over ║
23
+ ║ the lazy dog. Pack my box with five dozen liquor jugs." ║
24
+ ║ ║
25
+ ║ Tips: ║
26
+ ║ • Sit ~6 inches from the mic ║
27
+ ║ • Use a quiet room (close windows, turn off fans) ║
28
+ ║ • Speak clearly at your natural pace ║
29
+ ║ • Aim for 5–15 seconds ║
30
+ ║ ║
31
+ ╚══════════════════════════════════════════════════════════════════╝
32
+
33
+ PROMPT
34
+
35
+ echo "Press ENTER to start recording (Ctrl+C to cancel)..."
36
+ read -r
37
+
38
+ echo "🎙 Recording... Press Ctrl+C when done."
39
+
40
+ # Record using macOS Core Audio (avfoundation) via ffmpeg
41
+ # Uses the default input device (built-in mic or whatever is selected in
42
+ # System Settings > Sound > Input)
43
+ ffmpeg -y -f avfoundation -i ":default" \
44
+ -acodec pcm_s16le -ar 44100 -ac 1 \
45
+ "$RAW_FILE" 2>/dev/null || true
46
+
47
+ echo ""
48
+ echo "Processing audio..."
49
+
50
+ # Get duration
51
+ DURATION=$(ffprobe -v error -show_entries format=duration \
52
+ -of csv=p=0 "$RAW_FILE" 2>/dev/null || echo "0")
53
+
54
+ if [ "$DURATION" = "0" ] || [ "$(echo "$DURATION < 2" | bc -l 2>/dev/null || echo 0)" = "1" ]; then
55
+ echo "Error: Recording too short or failed. Try again."
56
+ rm -f "$RAW_FILE"
57
+ exit 1
58
+ fi
59
+
60
+ # Create output directory if needed
61
+ mkdir -p "$(dirname "$OUTPUT")"
62
+
63
+ # Process: mono, 24kHz, noise-reduced, normalized
64
+ ffmpeg -y -i "$RAW_FILE" \
65
+ -af "highpass=f=80,lowpass=f=12000,afftdn=nf=-25,loudnorm=I=-16:TP=-1.5:LRA=11" \
66
+ -ar 24000 -ac 1 -acodec pcm_s16le \
67
+ "$OUTPUT" 2>/dev/null
68
+
69
+ rm -f "$RAW_FILE"
70
+
71
+ FINAL_DURATION=$(ffprobe -v error -show_entries format=duration \
72
+ -of csv=p=0 "$OUTPUT" 2>/dev/null)
73
+
74
+ echo ""
75
+ echo "Done! Saved to: $OUTPUT (${FINAL_DURATION}s)"
76
+ echo ""
77
+ echo "Next steps:"
78
+ echo " 1. Listen: ffplay $OUTPUT"
79
+ echo " 2. Add to your argo config:"
80
+ echo ""
81
+ echo " tts: {"
82
+ echo " engine: engines.mlxAudio({"
83
+ echo " model: 'mlx-community/Qwen3-TTS-12Hz-0.6B-Base-bf16',"
84
+ echo " refAudio: './$OUTPUT',"
85
+ echo " refText: 'YOUR EXACT TRANSCRIPT HERE',"
86
+ echo " }),"
87
+ echo " }"
@@ -0,0 +1,66 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Set up mlx-audio with all dependencies for Argo voice cloning.
4
+ # Usage: ./scripts/setup-mlx-audio.sh
5
+ #
6
+ # Creates a .venv in the project root with mlx-audio and its
7
+ # transitive deps that aren't auto-installed.
8
+ #
9
+ set -euo pipefail
10
+
11
+ VENV_DIR="${1:-.venv}"
12
+
13
+ echo "╔══════════════════════════════════════════════╗"
14
+ echo "║ Argo — mlx-audio setup (Apple Silicon) ║"
15
+ echo "╚══════════════════════════════════════════════╝"
16
+ echo ""
17
+
18
+ # Check for uv
19
+ if ! command -v uv &>/dev/null; then
20
+ echo "✗ uv not found. Install it: curl -LsSf https://astral.sh/uv/install.sh | sh"
21
+ exit 1
22
+ fi
23
+
24
+ # Check for Apple Silicon
25
+ if [[ "$(uname -m)" != "arm64" ]]; then
26
+ echo "! Warning: mlx-audio is optimized for Apple Silicon (arm64)."
27
+ echo " Current arch: $(uname -m). Performance may be poor."
28
+ fi
29
+
30
+ # Create venv
31
+ echo "★ Creating venv at ${VENV_DIR}..."
32
+ uv venv "$VENV_DIR"
33
+
34
+ # Install mlx-audio + missing transitive deps
35
+ echo "★ Installing mlx-audio..."
36
+ uv pip install -p "$VENV_DIR" mlx-audio
37
+
38
+ echo "★ Installing missing transitive dependencies..."
39
+ uv pip install -p "$VENV_DIR" "misaki[en]" num2words pip
40
+
41
+ # setuptools < 70 needed for webrtcvad's pkg_resources import
42
+ echo "★ Installing setuptools (< 70 for pkg_resources compat)..."
43
+ uv pip install -p "$VENV_DIR" "setuptools<70"
44
+
45
+ # Server deps (for OpenAI-compatible HTTP API)
46
+ echo "★ Installing server dependencies..."
47
+ uv pip install -p "$VENV_DIR" uvicorn fastapi python-multipart webrtcvad
48
+
49
+ echo ""
50
+ echo "✓ Done! mlx-audio installed at ${VENV_DIR}"
51
+ echo ""
52
+ echo "Usage:"
53
+ echo " # Start the TTS server"
54
+ echo " ${VENV_DIR}/bin/python3 -m mlx_audio.server --port 8000"
55
+ echo ""
56
+ echo " # Record a voice reference clip"
57
+ echo " ./scripts/record-voice-ref.sh assets/ref-voice.wav"
58
+ echo ""
59
+ echo " # Preview cloned voice"
60
+ echo " ./scripts/voice-clone-preview.sh \\"
61
+ echo " --ref-audio assets/ref-voice.wav \\"
62
+ echo " --ref-text 'Your transcript here.' \\"
63
+ echo " --voiceover demos/showcase.voiceover.json --play"
64
+ echo ""
65
+ echo " # Use in argo config"
66
+ echo " engines.mlxAudio({ model: 'mlx-community/Qwen3-TTS-12Hz-0.6B-Base-bf16' })"
@@ -0,0 +1,193 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Quick voice cloning preview — send voiceover text to mlx-audio server
4
+ # and get back individual clips + an optional joined clip.
5
+ #
6
+ # Usage:
7
+ # ./scripts/voice-clone-preview.sh \
8
+ # --ref-audio ./assets/ref-voice.wav \
9
+ # --ref-text "Hi, my name is Shreyas. I build developer tools." \
10
+ # --voiceover demos/showcase.voiceover.json
11
+ #
12
+ # # Single line of text (no manifest):
13
+ # ./scripts/voice-clone-preview.sh \
14
+ # --ref-audio ./assets/ref-voice.wav \
15
+ # --ref-text "Hi, my name is Shreyas." \
16
+ # --text "Welcome to the demo."
17
+ #
18
+ # Options:
19
+ # --ref-audio PATH Reference voice WAV (required)
20
+ # --ref-text TEXT Transcript of reference audio (required)
21
+ # --voiceover PATH Voiceover JSON manifest (array of {scene, text, speed?, voice?})
22
+ # --text TEXT Single text to synthesize (alternative to --voiceover)
23
+ # --model ID Model ID (default: mlx-community/Qwen3-TTS-12Hz-0.6B-Base-bf16)
24
+ # --server URL Server URL (default: http://localhost:8000)
25
+ # --out-dir PATH Output directory (default: ./voice-preview)
26
+ # --join Also produce a single joined clip
27
+ # --play Play the output when done (requires ffplay)
28
+ # --voice NAME Default voice (default: af_heart)
29
+ #
30
+ set -euo pipefail
31
+
32
+ # Defaults
33
+ MODEL="mlx-community/Qwen3-TTS-12Hz-0.6B-Base-bf16"
34
+ SERVER="http://localhost:8000"
35
+ OUT_DIR="./voice-preview"
36
+ REF_AUDIO=""
37
+ REF_TEXT=""
38
+ VOICEOVER=""
39
+ SINGLE_TEXT=""
40
+ JOIN=false
41
+ PLAY=false
42
+ VOICE="af_heart"
43
+
44
+ while [[ $# -gt 0 ]]; do
45
+ case "$1" in
46
+ --ref-audio) REF_AUDIO="$2"; shift 2;;
47
+ --ref-text) REF_TEXT="$2"; shift 2;;
48
+ --voiceover) VOICEOVER="$2"; shift 2;;
49
+ --text) SINGLE_TEXT="$2"; shift 2;;
50
+ --model) MODEL="$2"; shift 2;;
51
+ --server) SERVER="$2"; shift 2;;
52
+ --out-dir) OUT_DIR="$2"; shift 2;;
53
+ --voice) VOICE="$2"; shift 2;;
54
+ --join) JOIN=true; shift;;
55
+ --play) PLAY=true; shift;;
56
+ -h|--help)
57
+ sed -n '2,/^set /{ /^#/s/^# \?//p }' "$0"
58
+ exit 0;;
59
+ *) echo "Unknown option: $1"; exit 1;;
60
+ esac
61
+ done
62
+
63
+ if [[ -z "$REF_AUDIO" || -z "$REF_TEXT" ]]; then
64
+ echo "Error: --ref-audio and --ref-text are required."
65
+ exit 1
66
+ fi
67
+
68
+ if [[ -z "$VOICEOVER" && -z "$SINGLE_TEXT" ]]; then
69
+ echo "Error: provide --voiceover <manifest.json> or --text <string>."
70
+ exit 1
71
+ fi
72
+
73
+ # Check server is running
74
+ if ! curl -sf "$SERVER/v1/audio/speech" -o /dev/null -X POST \
75
+ -H "Content-Type: application/json" \
76
+ -d '{"model":"test","input":"test"}' 2>/dev/null; then
77
+ # It's OK if the request fails with a model error — server is up
78
+ if ! curl -sf --connect-timeout 3 "$SERVER" -o /dev/null 2>/dev/null && \
79
+ ! curl -sf --connect-timeout 3 "$SERVER/docs" -o /dev/null 2>/dev/null; then
80
+ echo "Warning: mlx-audio server may not be running at $SERVER"
81
+ echo "Start it with: python3 -m mlx_audio.server --model $MODEL"
82
+ echo ""
83
+ fi
84
+ fi
85
+
86
+ mkdir -p "$OUT_DIR"
87
+
88
+ # Build the list of clips to generate
89
+ # Format: index|scene_name|text|speed|voice
90
+ CLIPS_LIST=$(mktemp)
91
+ trap 'rm -f "$CLIPS_LIST"' EXIT
92
+
93
+ if [[ -n "$SINGLE_TEXT" ]]; then
94
+ echo "0|single|$SINGLE_TEXT|1.0|$VOICE" > "$CLIPS_LIST"
95
+ else
96
+ # Parse voiceover JSON with python (available on macOS)
97
+ python3 -c "
98
+ import json, sys
99
+ with open('$VOICEOVER') as f:
100
+ scenes = json.load(f)
101
+ for i, s in enumerate(scenes):
102
+ scene = s.get('scene', f'scene-{i}')
103
+ text = s['text'].replace('|', ' ')
104
+ speed = s.get('speed', 1.0)
105
+ voice = s.get('voice', '$VOICE')
106
+ print(f'{i}|{scene}|{text}|{speed}|{voice}')
107
+ " > "$CLIPS_LIST"
108
+ fi
109
+
110
+ TOTAL=$(wc -l < "$CLIPS_LIST" | tr -d ' ')
111
+ echo "Generating $TOTAL clip(s) via $SERVER"
112
+ echo "Model: $MODEL"
113
+ echo "Ref audio: $REF_AUDIO"
114
+ echo "Output: $OUT_DIR/"
115
+ echo ""
116
+
117
+ GENERATED_FILES=()
118
+ IDX=0
119
+
120
+ while IFS='|' read -r _ SCENE TEXT SPEED CLIP_VOICE; do
121
+ IDX=$((IDX + 1))
122
+ OUTFILE="$OUT_DIR/$(printf '%02d' "$IDX")-${SCENE}.wav"
123
+
124
+ printf " [%d/%d] %s ... " "$IDX" "$TOTAL" "$SCENE"
125
+
126
+ # Build JSON payload
127
+ PAYLOAD=$(python3 -c "
128
+ import json
129
+ p = {
130
+ 'model': '$MODEL',
131
+ 'input': $(python3 -c "import json; print(json.dumps('$TEXT'))"),
132
+ 'voice': '$CLIP_VOICE',
133
+ 'speed': $SPEED,
134
+ 'ref_audio': '$REF_AUDIO',
135
+ 'ref_text': $(python3 -c "import json; print(json.dumps('$REF_TEXT'))"),
136
+ }
137
+ print(json.dumps(p))
138
+ ")
139
+
140
+ HTTP_CODE=$(curl -sf -w '%{http_code}' -o "$OUTFILE.raw" \
141
+ -X POST "$SERVER/v1/audio/speech" \
142
+ -H "Content-Type: application/json" \
143
+ -d "$PAYLOAD" 2>/dev/null || echo "000")
144
+
145
+ if [[ "$HTTP_CODE" == "200" ]]; then
146
+ # Convert to consistent WAV format
147
+ ffmpeg -y -i "$OUTFILE.raw" \
148
+ -ar 24000 -ac 1 -acodec pcm_s16le \
149
+ "$OUTFILE" 2>/dev/null
150
+ rm -f "$OUTFILE.raw"
151
+
152
+ DURATION=$(ffprobe -v error -show_entries format=duration \
153
+ -of csv=p=0 "$OUTFILE" 2>/dev/null)
154
+ printf "done (%.1fs)\n" "$DURATION"
155
+ GENERATED_FILES+=("$OUTFILE")
156
+ else
157
+ rm -f "$OUTFILE.raw"
158
+ printf "FAILED (HTTP %s)\n" "$HTTP_CODE"
159
+ fi
160
+ done < "$CLIPS_LIST"
161
+
162
+ echo ""
163
+
164
+ # Join clips if requested
165
+ if $JOIN && [[ ${#GENERATED_FILES[@]} -gt 1 ]]; then
166
+ JOINED="$OUT_DIR/joined.wav"
167
+ CONCAT_LIST=$(mktemp)
168
+ for f in "${GENERATED_FILES[@]}"; do
169
+ echo "file '$(realpath "$f")'" >> "$CONCAT_LIST"
170
+ done
171
+
172
+ ffmpeg -y -f concat -safe 0 -i "$CONCAT_LIST" \
173
+ -ar 24000 -ac 1 -acodec pcm_s16le \
174
+ "$JOINED" 2>/dev/null
175
+ rm -f "$CONCAT_LIST"
176
+
177
+ TOTAL_DURATION=$(ffprobe -v error -show_entries format=duration \
178
+ -of csv=p=0 "$JOINED" 2>/dev/null)
179
+ echo "Joined clip: $JOINED (${TOTAL_DURATION}s)"
180
+ echo ""
181
+
182
+ if $PLAY; then
183
+ echo "Playing joined clip..."
184
+ ffplay -autoexit -nodisp "$JOINED" 2>/dev/null
185
+ fi
186
+ elif $PLAY && [[ ${#GENERATED_FILES[@]} -gt 0 ]]; then
187
+ LAST_IDX=$(( ${#GENERATED_FILES[@]} - 1 ))
188
+ PLAY_FILE="${GENERATED_FILES[$LAST_IDX]}"
189
+ echo "Playing: $PLAY_FILE"
190
+ ffplay -autoexit -nodisp "$PLAY_FILE" 2>/dev/null
191
+ fi
192
+
193
+ echo "Done! Clips saved to $OUT_DIR/"