@effectnode/media 0.9.0 → 0.10.0

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.
Files changed (31) hide show
  1. package/dist/backend/movie-backend/agent/prompt/script.md +111 -1
  2. package/dist/backend/movie-backend/core.js +33 -0
  3. package/dist/backend/movie-backend/generation-queue.d.ts +1 -1
  4. package/dist/backend/movie-backend/generation-queue.js +75 -8
  5. package/dist/backend/movie-backend/render-media.d.ts +79 -2
  6. package/dist/backend/movie-backend/render-media.js +722 -418
  7. package/frontend/src/movie-app/components/EditorTabs/AdvancedVoiceCloneTab.tsx +366 -0
  8. package/frontend/src/movie-app/components/EditorTabs/AudioToVideoTab.tsx +406 -0
  9. package/frontend/src/movie-app/components/EditorTabs/FastImageEditTab.tsx +47 -0
  10. package/frontend/src/movie-app/components/EditorTabs/GenerateVideoTab.tsx +155 -1
  11. package/frontend/src/movie-app/components/EditorTabs/MovieStudioTab.tsx +33 -13
  12. package/frontend/src/movie-app/components/EditorTabs/SetupAiModelTab.tsx +26 -5
  13. package/frontend/src/movie-app/components/EditorTabs/UpscaleTab.tsx +342 -0
  14. package/frontend/src/movie-app/components/EditorTabs/VoiceCloneTab.tsx +365 -0
  15. package/frontend/src/movie-app/components/ProjectEditorPage.tsx +130 -125
  16. package/frontend/src/movie-app/stores/advancedVoiceCloneStore.ts +207 -0
  17. package/frontend/src/movie-app/stores/aiModelStore.ts +25 -2
  18. package/frontend/src/movie-app/stores/audioToVideoStore.ts +274 -0
  19. package/frontend/src/movie-app/stores/generationStore.ts +156 -255
  20. package/frontend/src/movie-app/stores/movieStudioStore.ts +10 -3
  21. package/frontend/src/movie-app/stores/queueStore.ts +47 -1
  22. package/frontend/src/movie-app/stores/upscaleStore.ts +118 -0
  23. package/frontend/src/movie-app/stores/voiceCloneStore.ts +227 -0
  24. package/package.json +1 -1
  25. package/frontend/src/movie-app/components/EditorTabs/BatchVoiceVideoTab.tsx +0 -913
  26. package/frontend/src/movie-app/components/EditorTabs/ExtendVideoTab.tsx +0 -305
  27. package/frontend/src/movie-app/components/EditorTabs/ExtractImageTab.tsx +0 -249
  28. package/frontend/src/movie-app/components/EditorTabs/SceneVisualTab.tsx +0 -267
  29. package/frontend/src/movie-app/lib/batchVoiceStorage.ts +0 -75
  30. package/frontend/src/movie-app/stores/batchVoiceStore.ts +0 -990
  31. package/frontend/src/movie-app/stores/sceneVisualStore.ts +0 -251
@@ -2,6 +2,14 @@
2
2
 
3
3
  ```bash
4
4
 
5
+ uv run mlx_audio.tts.generate \
6
+ --model Qwen/Qwen3-TTS-12Hz-1.7B-Base \
7
+ --text "Ghost reporting. ... 你好嗎?" \
8
+ --ref_audio ./reference_voice.wav \
9
+ --play --output ./out --audio_format mp3 --stream --save --instruct "slow down"
10
+
11
+
12
+
5
13
  uv run mlx_audio.tts.generate \
6
14
  --model Qwen/Qwen3-TTS-12Hz-1.7B-Base \
7
15
  --text "Ghost reporting. ... 你好嗎?" \
@@ -10,13 +18,15 @@ uv run mlx_audio.tts.generate \
10
18
 
11
19
  ```
12
20
 
21
+ <!-- mlx-community/Kokoro-82M-bf16 -->
22
+
13
23
  <!-- Low quality -->
14
24
 
15
25
  ```bash
16
26
 
17
27
  uv run mlx_audio.tts.generate \
18
28
  --model Qwen/Qwen3-TTS-12Hz-0.6B-Base \
19
- --text "Ghost reporting. 明月幾時有?把酒問青天。不知天上宮闕,今夕是何年。我欲乘風歸去,又恐瓊樓玉宇,高處不勝寒。起舞弄清影,何似在人間!轉朱閣,低綺戶,照無眠。不應有恨,何事長向別時圓?人有悲歡離合,月有陰晴圓缺,此事古難全。但願人長久,千里共嬋娟。 中秋節快樂!" \
29
+ --text "Ghost reporting. 中秋節快樂! 明月幾時有?把酒問青天。不知天上宮闕,今夕是何年。我欲乘風歸去,又恐瓊樓玉宇,高處不勝寒。起舞弄清影,何似在人間!轉朱閣,低綺戶,照無眠。不應有恨,何事長向別時圓?人有悲歡離合,月有陰晴圓缺,此事古難全。但願人長久,千里共嬋娟。 中秋節快樂!" \
20
30
  --ref_audio ./reference_voice.wav \
21
31
  --play --output ./out --audio_format mp3 --stream --save --instruct "slow down"
22
32
 
@@ -70,6 +80,15 @@ mlxgen upscale \
70
80
  --output input_upscaled_2048.png
71
81
 
72
82
 
83
+ mlxgen upscale \
84
+ --model AbstractFramework/seedvr2-7b-8bit \
85
+ --image-path input.png \
86
+ --resolution 1x \
87
+ --seed 42 \
88
+ --mlx-cache-limit-gb 100 \
89
+ --output input_refined_1x.png
90
+
91
+
73
92
  ```
74
93
 
75
94
  # upscale video
@@ -100,4 +119,95 @@ mlxgen upscale \
100
119
  --output upscalde_video.mp4
101
120
 
102
121
 
122
+ ```
123
+
124
+ ```bash
125
+
126
+
127
+ ##
128
+ ##
129
+ ##
130
+
131
+ cd to workspace/python-src/dots-tts-mlx
132
+
133
+ # 1. install the quant-aware runtime (>= v0.2.0)
134
+ pip install "git+https://github.com/sb1992/dots-tts-mlx.git@v0.2.0"
135
+
136
+ # 2. download the variant you want (use "mf-int4/*" for the faster MeanFlow decoder)
137
+ hf download shraey/dots-tts-mlx --include "mf-int4/*" --local-dir ./dots-tts-mlx-weights
138
+
139
+ # 1. install the quant-aware runtime (>= v0.2.0)
140
+ pip install "git+https://github.com/sb1992/dots-tts-mlx.git@v0.2.0"
141
+
142
+ # 2. download the variant you want (use "mf-int4/*" for the faster MeanFlow decoder)
143
+ hf download shraey/dots-tts-mlx --include "int4/*" --local-dir ./dots-tts-mlx-weights
144
+
145
+ # 2. download the variant you want (use "mf-int4/*" for the faster MeanFlow decoder)
146
+ hf download shraey/dots-tts-mlx --include "mf-int4/*" --local-dir ./dots-tts-mlx-weights
147
+
148
+ # 3. run (files land in ./dots-tts-mlx-weights/int4/)
149
+ dots-tts --model ./dots-tts-mlx-weights/int4 \
150
+ --text "Hello from MLX." --ref-audio reference.wav --language YUE \
151
+ --out-path out --out-prefix clone
152
+
153
+ dots-tts --model ./dots-tts-mlx-weights/mf-int4 \
154
+ --text "我講一個笑話比你聽. 有一日,個阿伯去茶餐廳食飯,嗌咗個「揚州炒飯」。食食吓,阿伯叫住伙計:「哥仔!你呢個揚州炒飯裡面,點解連一隻蝦都冇嘅?」伙計好冷靜咁答佢:「阿伯,咁你食『煲仔飯』嗰陣,裡面又有冇煲仔呀?」" \
155
+ --ref-audio reference.wav --language YUE \
156
+ --out-path out --out-prefix cantonese; \
157
+ afplay ./out/cantonese_000.wav
158
+
159
+
160
+ dots-tts --model ./dots-tts-mlx-weights/int4 \
161
+ --text "Ghost reporting. 我講一個笑話比你聽. 有一日,個阿伯去茶餐廳食飯,嗌咗個「揚州炒飯」。食食吓,阿伯叫住伙計:「哥仔!你呢個揚州炒飯裡面,點解連一隻蝦都冇嘅?」伙計好冷靜咁答佢:「阿伯,咁你食『煲仔飯』嗰陣,裡面又有冇煲仔呀?」" \
162
+ --ref-audio reference.wav --language YUE \
163
+ --out-path out --out-prefix fast; \
164
+
165
+ afplay ./out/fast_000.wav
166
+
167
+
168
+ dots-tts --model ./dots-tts-mlx-weights/int4 \
169
+ --text "Ghost reporting. 今日有d dry. 等我講一個笑話比你聽啦! 有一日,個阿伯去茶餐廳食飯,嗌咗個「揚州炒飯」。食食吓,阿伯叫住伙計:「哥仔!你呢個揚州炒飯裡面,點解連一隻蝦都冇嘅?」伙計好冷靜咁答佢:「阿伯,咁你食『煲仔飯』嗰陣,裡面又有冇煲仔呀?」 哈哈哈哈" \
170
+ --ref-audio reference.wav --language YUE \
171
+ --out-path out --out-prefix good_int4; \
172
+ afplay ./out/good_int4_000.wav
173
+
174
+
175
+ dots-tts --model ./dots-tts-mlx-weights/mf-int4 \
176
+ --text "Ghost reporting. 今日有d dry. 等我講一個笑話比你聽啦! 有一日,個阿伯去茶餐廳食飯,嗌咗個「揚州炒飯」。食食吓,阿伯叫住伙計:「哥仔!你呢個揚州炒飯裡面,點解連一隻蝦都冇嘅?」伙計好冷靜咁答佢:「阿伯,咁你食『煲仔飯』嗰陣,裡面又有冇煲仔呀?」 哈哈哈哈" \
177
+ --ref-audio reference.wav --language YUE \
178
+ --out-path out --out-prefix good_mf-int4; \
179
+
180
+ afplay ./out/good_mf-int4_000.wav
181
+
182
+
183
+ ## not very good.
184
+
185
+ # Faster 15 steps
186
+ # cwd at the git folder
187
+ uv run ltx-2-mlx a2v --image /Users/loklok/coder-workspace/cantonese/food.png --audio /Users/loklok/coder-workspace/cantonese/food-short.wav --frame-rate 24 --output ./out-mp4 --prompt "scene at restarurant" --stage1-steps 15 --stage2-steps 3
188
+
189
+ # Standard 30 steps
190
+ # cwd at the git folder
191
+
192
+ uv run ltx-2-mlx a2v --image /Users/loklok/coder-workspace/cantonese/food.png --audio /Users/loklok/coder-workspace/cantonese/food-short.wav --frame-rate 24 --output ./out-mp4 --prompt "scene at restarurant" --stage1-steps 30 --stage2-steps 3
193
+
194
+
195
+ uv run ltx-2-mlx a2v --image /Users/loklok/coder-workspace/cantonese/food.png --audio /Users/loklok/coder-workspace/cantonese/food-short.wav --frame-rate 24 --frames 481 --output ./out/yo.mp4 --prompt "happy food ondering story at the restarurant" --stage1-steps 8 --stage2-steps 3
196
+
197
+
198
+ mkdir dots-tts-mlx
199
+ git clone https://github.com/sb1992/dots-tts-mlx.git
200
+ cd dots-tts-mlx
201
+ uv run pip install -e .
202
+
203
+ ##
204
+ ##
205
+ ##
206
+ ## dgrauet/ltx-2.3-mlx (High Quality)
207
+ ## dgrauet/ltx-2.3-mlx-q8 (Standard Quality)
208
+ ##
209
+ ##
210
+ ##
211
+
212
+
103
213
  ```
@@ -568,6 +568,39 @@ async function installPythonDependencies() {
568
568
  return false;
569
569
  }
570
570
  }
571
+ {
572
+ const pythonAppSrcDir = join(APP_DATA_DIR, "python-src");
573
+ if (!existsSync(pythonAppSrcDir)) {
574
+ mkdirSync(pythonAppSrcDir, { recursive: true });
575
+ }
576
+ const dotsTtsFolder = join(pythonAppSrcDir, "dots-tts-mlx");
577
+ if (!existsSync(dotsTtsFolder)) {
578
+ const cloneCMD = await runCommand("git", ["clone", "https://github.com/sb1992/dots-tts-mlx.git", "dots-tts-mlx"], { cwd: pythonAppSrcDir });
579
+ if (!cloneCMD.success) {
580
+ console.error("Failed to clone dots-tts-mlx:", cloneCMD.error);
581
+ return false;
582
+ }
583
+ }
584
+ // Install the dots-tts CLI (into ~/.local/bin/dots-tts, which is where
585
+ // `getDotsTtsBin()` resolves it). `uv tool install` does not require a venv.
586
+ const uvPath = await getUvPath();
587
+ const installResult = await runCommand(uvPath, ["tool", "install", "--editable", "."], { cwd: dotsTtsFolder });
588
+ if (!installResult.success) {
589
+ console.error("Failed to install dots-tts:", installResult.error || installResult.output);
590
+ return false;
591
+ }
592
+ // Install mlx-whisper (MLX-powered speech-to-text for transcription) as a
593
+ // `uv tool` so its `mlx_whisper` CLI lands in ~/.local/bin, mirroring dots-tts.
594
+ const whisperResult = await runCommand(uvPath, [
595
+ "tool",
596
+ "install",
597
+ "mlx-whisper",
598
+ ]);
599
+ if (!whisperResult.success) {
600
+ console.error("Failed to install mlx-whisper:", whisperResult.error || whisperResult.output);
601
+ return false;
602
+ }
603
+ }
571
604
  // {
572
605
  // const pythonAppSrcDir = join(APP_DATA_DIR, "python-src");
573
606
  // if (!existsSync(pythonAppSrcDir)) {
@@ -1,5 +1,5 @@
1
1
  import { type Application } from "express";
2
- export type QueueTaskType = "generate" | "render" | "render-assets" | "render-videos" | "render-scene-images" | "render-asset" | "render-scene-image" | "render-video" | "regenerate-asset" | "regenerate-video" | "regenerate-scene-image" | "fast-image-edit";
2
+ export type QueueTaskType = "generate" | "render" | "render-assets" | "render-videos" | "render-scene-images" | "render-asset" | "render-scene-image" | "render-video" | "regenerate-asset" | "regenerate-video" | "regenerate-scene-image" | "fast-image-edit" | "image-to-video" | "upscale" | "voice-clone" | "audio-to-video" | "advanced-voice-clone";
3
3
  export type QueueTaskStatus = "pending" | "running" | "completed" | "failed" | "cancelled" | "paused";
4
4
  export interface QueueTask {
5
5
  id: string;
@@ -2,7 +2,7 @@ import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, statS
2
2
  import { dirname, join } from "node:path";
3
3
  import { homedir } from "node:os";
4
4
  import { randomUUID } from "node:crypto";
5
- import { generateAssetImage, generateSceneImage, generateSceneVideo, generateFastImageEditImage, cancelActiveRender, } from "./render-media.js";
5
+ import { generateAssetImage, generateSceneImage, generateSceneVideo, generateFastImageEditImage, generateImageToVideo, generateUpscale, generateVoiceClone, generateAudioToVideo, generateAdvancedVoiceClone, cancelActiveRender, } from "./render-media.js";
6
6
  import { generateMovieStudioBible } from "./agent/agent-backend.js";
7
7
  import { movieStudioStateFile } from "./agent/workspace.js";
8
8
  const APP_DATA_DIR = join(homedir(), "media-studio");
@@ -319,7 +319,7 @@ async function runRenderSceneImages(ctx, scenes) {
319
319
  entry = { slug, ...existing };
320
320
  }
321
321
  else {
322
- const r = await generateSceneImage(ctx.projectId, sc, ctx.log);
322
+ const r = await generateSceneImage(ctx.projectId, sc, undefined, ctx.log);
323
323
  throwIfAborted(ctx.signal);
324
324
  if ("error" in r)
325
325
  throw new Error(r.error);
@@ -413,9 +413,76 @@ const handlers = {
413
413
  },
414
414
  // Generate a composite image via fast-image-edit (FLUX.2 Klein).
415
415
  "fast-image-edit": async (ctx) => {
416
- const { prompt, images } = ctx.task.payload || {};
416
+ const { prompt, images, steps, upscale } = ctx.task.payload || {};
417
417
  ctx.log("Generating composite image (FLUX.2 Klein)…\n");
418
- const r = await generateFastImageEditImage(ctx.projectId, String(prompt || ""), Array.isArray(images) ? images : [], ctx.log);
418
+ const r = await generateFastImageEditImage(ctx.projectId, String(prompt || ""), Array.isArray(images) ? images : [], Number(steps), String(upscale || "none"), ctx.log);
419
+ if ("error" in r)
420
+ throw new Error(r.error);
421
+ return r;
422
+ },
423
+ // Generate a video from a project image via LTX-2.3 (Scene Video Generation).
424
+ "image-to-video": async (ctx, getUvPath) => {
425
+ const { prompt, imagePath, width, height, frames, frameRate, mode, stage1Steps, stage2Steps, } = ctx.task.payload || {};
426
+ ctx.log("Generating scene video (LTX-2.3)…\n");
427
+ const r = await generateImageToVideo(await getUvPath(), ctx.projectId, {
428
+ prompt: String(prompt || ""),
429
+ imagePath: String(imagePath || ""),
430
+ width,
431
+ height,
432
+ frames,
433
+ frameRate,
434
+ mode,
435
+ stage1Steps,
436
+ stage2Steps,
437
+ }, ctx.log);
438
+ if ("error" in r)
439
+ throw new Error(r.error);
440
+ return r;
441
+ },
442
+ // Upscale/refine a project image via mlxgen (SeedVR2).
443
+ "upscale": async (ctx) => {
444
+ const { imagePath, resolution } = ctx.task.payload || {};
445
+ ctx.log(`Upscaling image (${resolution || "1x"})…\n`);
446
+ const r = await generateUpscale(ctx.projectId, String(imagePath || ""), String(resolution || "1x"), ctx.log);
447
+ if ("error" in r)
448
+ throw new Error(r.error);
449
+ return r;
450
+ },
451
+ // Clone a reference voice and speak the transcript.
452
+ "voice-clone": async (ctx, getUvPath) => {
453
+ const { text, refAudioPath, quality } = ctx.task.payload || {};
454
+ ctx.log("Cloning voice…\n");
455
+ const r = await generateVoiceClone(await getUvPath(), ctx.projectId, String(text || ""), String(refAudioPath || ""), String(quality || "high"), ctx.log);
456
+ if ("error" in r)
457
+ throw new Error(r.error);
458
+ return r;
459
+ },
460
+ // Clone a reference voice via dots-tts.
461
+ "advanced-voice-clone": async (ctx) => {
462
+ const { text, refAudioPath, language, outPrefix, model } = ctx.task.payload || {};
463
+ ctx.log("Cloning voice (dots-tts)…\n");
464
+ const r = await generateAdvancedVoiceClone(ctx.projectId, {
465
+ text: String(text || ""),
466
+ refAudioPath: String(refAudioPath || ""),
467
+ language: String(language || "YUE"),
468
+ outPrefix: String(outPrefix || ""),
469
+ model: String(model || ""),
470
+ }, ctx.log);
471
+ if ("error" in r)
472
+ throw new Error(r.error);
473
+ return r;
474
+ },
475
+ // Generate a video from an image + audio via ltx-2-mlx a2v.
476
+ "audio-to-video": async (ctx, getUvPath) => {
477
+ const { imagePath, audioPath, prompt, stage1Steps, frames } = ctx.task.payload || {};
478
+ ctx.log("Generating audio-to-video…\n");
479
+ const r = await generateAudioToVideo(await getUvPath(), ctx.projectId, {
480
+ imagePath: String(imagePath || ""),
481
+ audioPath: String(audioPath || ""),
482
+ prompt: String(prompt || ""),
483
+ stage1Steps: Number(stage1Steps),
484
+ frames: Number(frames),
485
+ }, ctx.log);
419
486
  if ("error" in r)
420
487
  throw new Error(r.error);
421
488
  return r;
@@ -463,7 +530,7 @@ const handlers = {
463
530
  },
464
531
  // Generate a single scene image, skipping if it already exists.
465
532
  "render-scene-image": async (ctx) => {
466
- const { scene } = ctx.task.payload || {};
533
+ const { scene, steps } = ctx.task.payload || {};
467
534
  if (!scene || typeof scene !== "object")
468
535
  throw new Error("scene is required");
469
536
  const s = slugify(scene?.slug);
@@ -474,7 +541,7 @@ const handlers = {
474
541
  ctx.log(`Already generated: scene-${s}.png — skipping\n`);
475
542
  return { slug: s, ...existing };
476
543
  }
477
- const r = await generateSceneImage(ctx.projectId, scene, ctx.log);
544
+ const r = await generateSceneImage(ctx.projectId, scene, Number(steps), ctx.log);
478
545
  if ("error" in r)
479
546
  throw new Error(r.error);
480
547
  return {
@@ -542,10 +609,10 @@ const handlers = {
542
609
  };
543
610
  },
544
611
  "regenerate-scene-image": async (ctx) => {
545
- const { scene } = ctx.task.payload || {};
612
+ const { scene, steps } = ctx.task.payload || {};
546
613
  if (!scene || typeof scene !== "object")
547
614
  throw new Error("scene is required");
548
- const r = await generateSceneImage(ctx.projectId, scene, ctx.log);
615
+ const r = await generateSceneImage(ctx.projectId, scene, Number(steps), ctx.log);
549
616
  if ("error" in r)
550
617
  throw new Error(r.error);
551
618
  return {
@@ -32,11 +32,88 @@ export declare function generateSceneVideo(uvPath: string, projectId: string, sc
32
32
  } | {
33
33
  error: string;
34
34
  }>;
35
+ /**
36
+ * Generate a video from a project image via LTX-2.3. `imagePath` must be a bare
37
+ * filename previously uploaded/generated for this project. Used by the queue
38
+ * worker for the "Scene Video Generation" tab.
39
+ */
40
+ export declare function generateImageToVideo(uvPath: string, projectId: string, params: {
41
+ prompt: string;
42
+ imagePath: string;
43
+ width?: number;
44
+ height?: number;
45
+ frames?: number;
46
+ frameRate?: number;
47
+ mode?: string;
48
+ model?: string;
49
+ stage1Steps?: number;
50
+ stage2Steps?: number;
51
+ }, onLog?: (text: string) => void): Promise<{
52
+ filename: string;
53
+ url: string;
54
+ } | {
55
+ error: string;
56
+ }>;
35
57
  /**
36
58
  * Generate a single scene image via fast-image-edit (FLUX.2 Klein), using the
37
59
  * already-generated character/place images referenced by the scene's slugs.
38
60
  */
39
- export declare function generateSceneImage(projectId: string, scene: any, onLog?: (text: string) => void): Promise<{
61
+ export declare function generateSceneImage(projectId: string, scene: any, steps?: number, onLog?: (text: string) => void): Promise<{
62
+ filename: string;
63
+ url: string;
64
+ } | {
65
+ error: string;
66
+ }>;
67
+ /**
68
+ * Upscale/refine a project image via mlxgen (SeedVR2). `imagePath` must be a
69
+ * bare filename previously uploaded/generated for this project. `resolution` is
70
+ * either "1x" (refine at native resolution) or "2048" (upscale to 2048px).
71
+ */
72
+ export declare function generateUpscale(projectId: string, imagePath: string, resolution: string, onLog?: (text: string) => void): Promise<{
73
+ filename: string;
74
+ url: string;
75
+ } | {
76
+ error: string;
77
+ }>;
78
+ /**
79
+ * Clone a reference voice and speak `text` via mlx_audio.tts.generate. `refAudioPath`
80
+ * must be a bare filename previously uploaded to this project. `quality` is "low"
81
+ * or "high" (maps to a TTS model). Output is saved under <output>/voices/.
82
+ */
83
+ export declare function generateVoiceClone(uvPath: string, projectId: string, text: string, refAudioPath: string, quality: string, onLog?: (text: string) => void): Promise<{
84
+ filename: string;
85
+ url: string;
86
+ } | {
87
+ error: string;
88
+ }>;
89
+ /**
90
+ * Generate a video from an image + audio via ltx-2-mlx `a2v` (audio-to-video).
91
+ * `imagePath` and `audioPath` must be bare filenames previously uploaded/generated
92
+ * for this project. `stage1Steps` maps to `--stage1-steps` (15 default, 30 HD).
93
+ */
94
+ export declare function generateAudioToVideo(uvPath: string, projectId: string, params: {
95
+ imagePath: string;
96
+ audioPath: string;
97
+ prompt: string;
98
+ stage1Steps: number;
99
+ frames: number;
100
+ }, onLog?: (text: string) => void): Promise<{
101
+ filename: string;
102
+ url: string;
103
+ } | {
104
+ error: string;
105
+ }>;
106
+ /**
107
+ * Clone a reference voice via dots-tts. Output is written to
108
+ * <output>/<projectId>/dots-tts/ as `<prefix>_000.wav`.
109
+ */
110
+ export declare function generateAdvancedVoiceClone(projectId: string, params: {
111
+ text: string;
112
+ refAudioPath: string;
113
+ language: string;
114
+ outPrefix: string;
115
+ model: string;
116
+ }, onLog?: (text: string) => void): Promise<{
40
117
  filename: string;
41
118
  url: string;
42
119
  } | {
@@ -47,7 +124,7 @@ export declare function generateSceneImage(projectId: string, scene: any, onLog?
47
124
  * base64 data URLs that are decoded into temp files and passed to the model as
48
125
  * separate `--image` inputs. Used by the generation queue worker.
49
126
  */
50
- export declare function generateFastImageEditImage(projectId: string, prompt: string, images: string[], onLog?: (text: string) => void): Promise<{
127
+ export declare function generateFastImageEditImage(projectId: string, prompt: string, images: string[], steps?: number, upscaleResolution?: string, onLog?: (text: string) => void): Promise<{
51
128
  filename: string;
52
129
  url: string;
53
130
  } | {