@vibeframe/cli 0.112.1 → 0.113.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.
- package/dist/commands/_shared/project-config.d.ts +1 -1
- package/dist/commands/_shared/scene-build.d.ts +1 -1
- package/dist/commands/_shared/scene-project.d.ts +1 -1
- package/dist/commands/_shared/tts-resolve.d.ts +11 -7
- package/dist/index.js +240 -49
- package/dist/tools/_shared/elicit.d.ts +1 -1
- package/dist/tools/manifest/index.js +236 -45
- package/dist/tools/manifest/scene.d.ts +3 -3
- package/dist/tools/manifest/storyboard.d.ts +3 -3
- package/package.json +3 -3
|
@@ -4,7 +4,7 @@ export declare const LEGACY_VIBE_PROJECT_FILENAME = "vibe.project.yaml";
|
|
|
4
4
|
export type CompositionEngine = "hyperframes";
|
|
5
5
|
export type ProjectImageProvider = "openai" | "gemini" | "grok" | null;
|
|
6
6
|
export type ProjectVideoProvider = "seedance" | "grok" | "kling" | "runway" | "veo" | null;
|
|
7
|
-
export type ProjectNarrationProvider = "elevenlabs" | "kokoro" | null;
|
|
7
|
+
export type ProjectNarrationProvider = "elevenlabs" | "openai" | "kokoro" | null;
|
|
8
8
|
export type ProjectComposerProvider = "claude" | "openai" | "gemini" | null;
|
|
9
9
|
export type ProjectQuality = "draft" | "standard" | "high";
|
|
10
10
|
export interface VibeProjectConfigV1 {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* Idempotent: assets that already exist on disk are reused unless `force`.
|
|
13
13
|
*
|
|
14
14
|
* Scope held tight for v0.60:
|
|
15
|
-
* - TTS via `resolveTtsProvider` (ElevenLabs / Kokoro auto-fallback)
|
|
15
|
+
* - TTS via `resolveTtsProvider` (ElevenLabs / OpenAI / Kokoro auto-fallback)
|
|
16
16
|
* - T2I via OpenAI, Gemini, or Grok
|
|
17
17
|
* - No Whisper transcribe step (compose handles its own)
|
|
18
18
|
* - No root `index.html` synthesis — driver expects the project to
|
|
@@ -45,7 +45,7 @@ export interface VibeProjectConfig {
|
|
|
45
45
|
/** Default providers per capability. `null` means "auto-resolve from env". */
|
|
46
46
|
providers: {
|
|
47
47
|
image: "openai" | "gemini" | "grok" | null;
|
|
48
|
-
tts: "elevenlabs" | "kokoro" | null;
|
|
48
|
+
tts: "elevenlabs" | "openai" | "kokoro" | null;
|
|
49
49
|
transcribe: "whisper" | null;
|
|
50
50
|
};
|
|
51
51
|
/** Cost ceiling for `vibe remix` runs in this project. 0 disables. */
|
|
@@ -8,18 +8,21 @@
|
|
|
8
8
|
* Routes between:
|
|
9
9
|
* - **ElevenLabs** — cloud, API-key gated, paid (~$0.02/scene). Default
|
|
10
10
|
* when `ELEVENLABS_API_KEY` is set.
|
|
11
|
-
* - **
|
|
11
|
+
* - **OpenAI** — cloud gpt-4o-mini-tts, cheap (~$0.015/min of audio).
|
|
12
|
+
* Default when only `OPENAI_API_KEY` is set — the common Claude Desktop
|
|
13
|
+
* case where one key already covers backdrop images.
|
|
14
|
+
* - **Kokoro** — local Apache 2.0 model, free, ~90MB first-call download.
|
|
12
15
|
* The fallback for key-less users.
|
|
13
16
|
*
|
|
14
17
|
* The router exposes a uniform `TtsCallable` shape so call sites don't have
|
|
15
|
-
* to branch on provider id.
|
|
18
|
+
* to branch on provider id. All providers already return the same
|
|
16
19
|
* `{ success, audioBuffer, error?, characterCount? }` result.
|
|
17
20
|
*/
|
|
18
21
|
import type { KokoroLoadEvent } from "@vibeframe/ai-providers";
|
|
19
22
|
/** TTS providers VibeFrame can route to. `"auto"` picks based on key availability. */
|
|
20
|
-
export type TtsProviderName = "auto" | "elevenlabs" | "kokoro";
|
|
23
|
+
export type TtsProviderName = "auto" | "elevenlabs" | "openai" | "kokoro";
|
|
21
24
|
/** Concrete provider id surfaced in result metadata. Never `"auto"`. */
|
|
22
|
-
export type ResolvedTtsProvider = "elevenlabs" | "kokoro";
|
|
25
|
+
export type ResolvedTtsProvider = "elevenlabs" | "openai" | "kokoro";
|
|
23
26
|
/** Options accepted by every {@link TtsCallable}. Subset of provider-specific options. */
|
|
24
27
|
export interface TtsCallOptions {
|
|
25
28
|
/**
|
|
@@ -56,10 +59,11 @@ export interface TtsResolution {
|
|
|
56
59
|
* Resolution policy:
|
|
57
60
|
* - `"elevenlabs"`: requires `ELEVENLABS_API_KEY`. Throws an `ApiKeyError`-style
|
|
58
61
|
* error via {@link getApiKey} (consumed by `requireApiKey`/`exitWithError`).
|
|
62
|
+
* - `"openai"`: requires `OPENAI_API_KEY`.
|
|
59
63
|
* - `"kokoro"`: always available (local). No key check.
|
|
60
|
-
* - `"auto"` (or `undefined`):
|
|
61
|
-
*
|
|
62
|
-
*
|
|
64
|
+
* - `"auto"` (or `undefined`): ElevenLabs key configured → ElevenLabs
|
|
65
|
+
* (preserves pre-0.113 behavior — a dedicated TTS key signals intent);
|
|
66
|
+
* else OpenAI key configured → OpenAI; else Kokoro.
|
|
63
67
|
*/
|
|
64
68
|
export declare function resolveTtsProvider(preferred?: TtsProviderName): Promise<TtsResolution>;
|
|
65
69
|
/**
|
package/dist/index.js
CHANGED
|
@@ -7066,8 +7066,8 @@ var init_api_keys = __esm({
|
|
|
7066
7066
|
envVar: "OPENAI_API_KEY",
|
|
7067
7067
|
label: "OpenAI",
|
|
7068
7068
|
showInSetup: true,
|
|
7069
|
-
setupDescription: "gpt-image-2 image gen ($, default since v0.56), Whisper transcribe, Agent",
|
|
7070
|
-
envExampleComment: "OpenAI API Key (Whisper transcription, gpt-image-2 \u2014 default text-to-image since v0.56)",
|
|
7069
|
+
setupDescription: "gpt-image-2 image gen ($, default since v0.56), gpt-4o-mini-tts narration, Whisper transcribe, Agent",
|
|
7070
|
+
envExampleComment: "OpenAI API Key (Whisper transcription, gpt-4o-mini-tts narration, gpt-image-2 \u2014 default text-to-image since v0.56)",
|
|
7071
7071
|
envExampleUrl: "https://platform.openai.com/api-keys",
|
|
7072
7072
|
keyFormat: { prefix: /^sk-/, example: "sk-..." }
|
|
7073
7073
|
});
|
|
@@ -9174,8 +9174,8 @@ var init_openai = __esm({
|
|
|
9174
9174
|
id: "openai",
|
|
9175
9175
|
label: "OpenAI",
|
|
9176
9176
|
apiKey: "openai",
|
|
9177
|
-
kinds: ["llm", "image", "transcription"],
|
|
9178
|
-
resolverPriority: { image: 1 },
|
|
9177
|
+
kinds: ["llm", "image", "transcription", "speech"],
|
|
9178
|
+
resolverPriority: { image: 1, speech: 2 },
|
|
9179
9179
|
commandsUnlocked: [
|
|
9180
9180
|
"agent -p openai",
|
|
9181
9181
|
"generate image -p openai",
|
|
@@ -11597,16 +11597,19 @@ var init_elevenlabs = __esm({
|
|
|
11597
11597
|
});
|
|
11598
11598
|
|
|
11599
11599
|
// ../ai-providers/dist/kokoro/KokoroProvider.js
|
|
11600
|
-
async function
|
|
11600
|
+
async function loadKokoroRuntime() {
|
|
11601
11601
|
if (factoryOverride)
|
|
11602
|
-
return factoryOverride;
|
|
11602
|
+
return { factory: factoryOverride, device: "cpu" };
|
|
11603
11603
|
try {
|
|
11604
11604
|
const mod = await import("kokoro-js");
|
|
11605
|
-
return mod.KokoroTTS;
|
|
11605
|
+
return { factory: mod.KokoroTTS, device: "cpu" };
|
|
11606
11606
|
} catch (err) {
|
|
11607
|
-
const
|
|
11608
|
-
if (
|
|
11609
|
-
return
|
|
11607
|
+
const workspace = await loadKokoroFromWorkspace();
|
|
11608
|
+
if (workspace)
|
|
11609
|
+
return { factory: workspace, device: "cpu" };
|
|
11610
|
+
const bundled = await loadBundledKokoroRuntime();
|
|
11611
|
+
if (bundled)
|
|
11612
|
+
return bundled;
|
|
11610
11613
|
throw mapKokoroImportError(err);
|
|
11611
11614
|
}
|
|
11612
11615
|
}
|
|
@@ -11626,10 +11629,51 @@ async function loadKokoroFromWorkspace(baseDir = process.cwd()) {
|
|
|
11626
11629
|
return null;
|
|
11627
11630
|
}
|
|
11628
11631
|
}
|
|
11632
|
+
async function loadBundledKokoroRuntime(runtimeDir = process.env.VIBE_KOKORO_RUNTIME) {
|
|
11633
|
+
const base = runtimeDir?.trim();
|
|
11634
|
+
if (!base)
|
|
11635
|
+
return null;
|
|
11636
|
+
try {
|
|
11637
|
+
const { readFile: readFile56, writeFile: writeFile61, mkdir: mkdir31 } = await import("node:fs/promises");
|
|
11638
|
+
const { join: join30, resolve: resolve86 } = await import("node:path");
|
|
11639
|
+
const { pathToFileURL } = await import("node:url");
|
|
11640
|
+
const { homedir: homedir8 } = await import("node:os");
|
|
11641
|
+
const transformersDir = resolve86(base, "node_modules", "@huggingface", "transformers");
|
|
11642
|
+
const ortDistDir = resolve86(base, "node_modules", "onnxruntime-web", "dist");
|
|
11643
|
+
const transformers = await import(pathToFileURL(join30(transformersDir, "dist", "transformers.web.js")).href);
|
|
11644
|
+
const cacheRoot = join30(homedir8(), ".cache", "vibeframe", "models");
|
|
11645
|
+
transformers.env.allowLocalModels = false;
|
|
11646
|
+
transformers.env.useCustomCache = true;
|
|
11647
|
+
transformers.env.customCache = {
|
|
11648
|
+
async match(key) {
|
|
11649
|
+
try {
|
|
11650
|
+
return new Response(await readFile56(join30(cacheRoot, encodeURIComponent(String(key)))));
|
|
11651
|
+
} catch {
|
|
11652
|
+
return void 0;
|
|
11653
|
+
}
|
|
11654
|
+
},
|
|
11655
|
+
async put(key, response) {
|
|
11656
|
+
try {
|
|
11657
|
+
const buf = Buffer.from(await response.arrayBuffer());
|
|
11658
|
+
await mkdir31(cacheRoot, { recursive: true });
|
|
11659
|
+
await writeFile61(join30(cacheRoot, encodeURIComponent(String(key))), buf);
|
|
11660
|
+
} catch {
|
|
11661
|
+
}
|
|
11662
|
+
}
|
|
11663
|
+
};
|
|
11664
|
+
transformers.env.backends.onnx.wasm.wasmPaths = pathToFileURL(ortDistDir + "/").href;
|
|
11665
|
+
const factory = await loadKokoroFromWorkspace(base);
|
|
11666
|
+
if (!factory)
|
|
11667
|
+
return null;
|
|
11668
|
+
return { factory, device: "cpu" };
|
|
11669
|
+
} catch {
|
|
11670
|
+
return null;
|
|
11671
|
+
}
|
|
11672
|
+
}
|
|
11629
11673
|
function mapKokoroImportError(err) {
|
|
11630
11674
|
const code = err instanceof Error && "code" in err ? err.code : void 0;
|
|
11631
11675
|
if (code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND") {
|
|
11632
|
-
return new Error("Local Kokoro TTS is unavailable:
|
|
11676
|
+
return new Error("Local Kokoro TTS is unavailable: kokoro-js could not be loaded from the npm install, the workspace node_modules, or the bundled extension runtime. Set OPENAI_API_KEY or ELEVENLABS_API_KEY to use a cloud voice instead (ttsProvider: openai / elevenlabs), or install the engine locally with `npm i kokoro-js` in your workspace folder.");
|
|
11633
11677
|
}
|
|
11634
11678
|
return err instanceof Error ? err : new Error(String(err));
|
|
11635
11679
|
}
|
|
@@ -11637,10 +11681,12 @@ function loadModel(progress) {
|
|
|
11637
11681
|
if (modelPromise)
|
|
11638
11682
|
return modelPromise;
|
|
11639
11683
|
modelPromise = (async () => {
|
|
11640
|
-
const
|
|
11641
|
-
|
|
11684
|
+
const runtime = await loadKokoroRuntime();
|
|
11685
|
+
const override = process.env.VIBE_ONNX_DEVICE;
|
|
11686
|
+
const device = override === "cpu" || override === "wasm" ? override : runtime.device;
|
|
11687
|
+
return runtime.factory.from_pretrained(KOKORO_MODEL_ID, {
|
|
11642
11688
|
dtype: "q8",
|
|
11643
|
-
device
|
|
11689
|
+
device,
|
|
11644
11690
|
progress_callback: progress ? (raw) => progress(normaliseEvent(raw)) : void 0
|
|
11645
11691
|
});
|
|
11646
11692
|
})().catch((err) => {
|
|
@@ -11724,7 +11770,7 @@ var init_kokoro = __esm({
|
|
|
11724
11770
|
label: "Kokoro (local)",
|
|
11725
11771
|
apiKey: null,
|
|
11726
11772
|
kinds: ["speech"],
|
|
11727
|
-
resolverPriority: { speech:
|
|
11773
|
+
resolverPriority: { speech: 3 }
|
|
11728
11774
|
});
|
|
11729
11775
|
}
|
|
11730
11776
|
});
|
|
@@ -11996,12 +12042,119 @@ var init_openai_image = __esm({
|
|
|
11996
12042
|
}
|
|
11997
12043
|
});
|
|
11998
12044
|
|
|
12045
|
+
// ../ai-providers/dist/openai-tts/OpenAiTtsProvider.js
|
|
12046
|
+
var OPENAI_TTS_VOICES, DEFAULT_VOICE, DEFAULT_MODEL2, TTS_429_MAX_RETRIES2, TTS_429_RETRY_DELAY_MS2, OpenAiTtsProvider, openaiTtsProvider;
|
|
12047
|
+
var init_OpenAiTtsProvider = __esm({
|
|
12048
|
+
"../ai-providers/dist/openai-tts/OpenAiTtsProvider.js"() {
|
|
12049
|
+
"use strict";
|
|
12050
|
+
OPENAI_TTS_VOICES = [
|
|
12051
|
+
"alloy",
|
|
12052
|
+
"ash",
|
|
12053
|
+
"ballad",
|
|
12054
|
+
"cedar",
|
|
12055
|
+
"coral",
|
|
12056
|
+
"echo",
|
|
12057
|
+
"fable",
|
|
12058
|
+
"marin",
|
|
12059
|
+
"nova",
|
|
12060
|
+
"onyx",
|
|
12061
|
+
"sage",
|
|
12062
|
+
"shimmer",
|
|
12063
|
+
"verse"
|
|
12064
|
+
];
|
|
12065
|
+
DEFAULT_VOICE = "marin";
|
|
12066
|
+
DEFAULT_MODEL2 = "gpt-4o-mini-tts";
|
|
12067
|
+
TTS_429_MAX_RETRIES2 = 1;
|
|
12068
|
+
TTS_429_RETRY_DELAY_MS2 = 2e3;
|
|
12069
|
+
OpenAiTtsProvider = class {
|
|
12070
|
+
constructor() {
|
|
12071
|
+
this.id = "openai";
|
|
12072
|
+
this.name = "OpenAI TTS";
|
|
12073
|
+
this.description = "OpenAI cloud text-to-speech (gpt-4o-mini-tts)";
|
|
12074
|
+
this.capabilities = ["text-to-speech"];
|
|
12075
|
+
this.isAvailable = true;
|
|
12076
|
+
this.baseUrl = "https://api.openai.com/v1";
|
|
12077
|
+
}
|
|
12078
|
+
async initialize(config2) {
|
|
12079
|
+
this.apiKey = config2.apiKey;
|
|
12080
|
+
if (config2.baseUrl) {
|
|
12081
|
+
this.baseUrl = config2.baseUrl;
|
|
12082
|
+
}
|
|
12083
|
+
}
|
|
12084
|
+
isConfigured() {
|
|
12085
|
+
return !!this.apiKey;
|
|
12086
|
+
}
|
|
12087
|
+
async textToSpeech(text, options = {}) {
|
|
12088
|
+
if (!this.apiKey) {
|
|
12089
|
+
return { success: false, error: "OpenAI API key not configured" };
|
|
12090
|
+
}
|
|
12091
|
+
const voice = (options.voice ?? DEFAULT_VOICE).toLowerCase();
|
|
12092
|
+
if (!OPENAI_TTS_VOICES.includes(voice)) {
|
|
12093
|
+
return {
|
|
12094
|
+
success: false,
|
|
12095
|
+
error: `Unknown OpenAI voice "${options.voice}". Available voices: ${OPENAI_TTS_VOICES.join(", ")}.`
|
|
12096
|
+
};
|
|
12097
|
+
}
|
|
12098
|
+
try {
|
|
12099
|
+
let response;
|
|
12100
|
+
for (let attempt = 0; ; attempt++) {
|
|
12101
|
+
response = await fetch(`${this.baseUrl}/audio/speech`, {
|
|
12102
|
+
method: "POST",
|
|
12103
|
+
headers: {
|
|
12104
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
12105
|
+
"Content-Type": "application/json"
|
|
12106
|
+
},
|
|
12107
|
+
body: JSON.stringify({
|
|
12108
|
+
model: options.model ?? DEFAULT_MODEL2,
|
|
12109
|
+
input: text,
|
|
12110
|
+
voice,
|
|
12111
|
+
response_format: "mp3",
|
|
12112
|
+
...options.speed !== void 0 && { speed: options.speed },
|
|
12113
|
+
...options.instructions !== void 0 && { instructions: options.instructions }
|
|
12114
|
+
})
|
|
12115
|
+
});
|
|
12116
|
+
if (response.status === 429 && attempt < TTS_429_MAX_RETRIES2) {
|
|
12117
|
+
await new Promise((resolveDelay) => setTimeout(resolveDelay, TTS_429_RETRY_DELAY_MS2 * (attempt + 1)));
|
|
12118
|
+
continue;
|
|
12119
|
+
}
|
|
12120
|
+
break;
|
|
12121
|
+
}
|
|
12122
|
+
if (!response.ok) {
|
|
12123
|
+
const error = await response.text();
|
|
12124
|
+
return { success: false, error: `OpenAI TTS failed: ${error}` };
|
|
12125
|
+
}
|
|
12126
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
12127
|
+
return {
|
|
12128
|
+
success: true,
|
|
12129
|
+
audioBuffer: Buffer.from(arrayBuffer),
|
|
12130
|
+
characterCount: text.length
|
|
12131
|
+
};
|
|
12132
|
+
} catch (error) {
|
|
12133
|
+
return {
|
|
12134
|
+
success: false,
|
|
12135
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
12136
|
+
};
|
|
12137
|
+
}
|
|
12138
|
+
}
|
|
12139
|
+
};
|
|
12140
|
+
openaiTtsProvider = new OpenAiTtsProvider();
|
|
12141
|
+
}
|
|
12142
|
+
});
|
|
12143
|
+
|
|
12144
|
+
// ../ai-providers/dist/openai-tts/index.js
|
|
12145
|
+
var init_openai_tts = __esm({
|
|
12146
|
+
"../ai-providers/dist/openai-tts/index.js"() {
|
|
12147
|
+
"use strict";
|
|
12148
|
+
init_OpenAiTtsProvider();
|
|
12149
|
+
}
|
|
12150
|
+
});
|
|
12151
|
+
|
|
11999
12152
|
// ../ai-providers/dist/runway/RunwayProvider.js
|
|
12000
|
-
var
|
|
12153
|
+
var DEFAULT_MODEL3, RunwayProvider, runwayProvider;
|
|
12001
12154
|
var init_RunwayProvider = __esm({
|
|
12002
12155
|
"../ai-providers/dist/runway/RunwayProvider.js"() {
|
|
12003
12156
|
"use strict";
|
|
12004
|
-
|
|
12157
|
+
DEFAULT_MODEL3 = "gen4.5";
|
|
12005
12158
|
RunwayProvider = class _RunwayProvider {
|
|
12006
12159
|
constructor() {
|
|
12007
12160
|
this.id = "runway";
|
|
@@ -12044,7 +12197,7 @@ var init_RunwayProvider = __esm({
|
|
|
12044
12197
|
"1:1": "960:960"
|
|
12045
12198
|
};
|
|
12046
12199
|
const apiRatio = ratioMap[options?.aspectRatio || "16:9"] || "1280:720";
|
|
12047
|
-
const model = options?.model ||
|
|
12200
|
+
const model = options?.model || DEFAULT_MODEL3;
|
|
12048
12201
|
if (!options?.referenceImage && model !== "gen4.5") {
|
|
12049
12202
|
return {
|
|
12050
12203
|
id: "",
|
|
@@ -12306,11 +12459,11 @@ var init_runway = __esm({
|
|
|
12306
12459
|
|
|
12307
12460
|
// ../ai-providers/dist/kling/KlingProvider.js
|
|
12308
12461
|
import { createHmac } from "node:crypto";
|
|
12309
|
-
var
|
|
12462
|
+
var DEFAULT_MODEL4, STD_MODE_MODELS, KlingProvider, klingProvider;
|
|
12310
12463
|
var init_KlingProvider = __esm({
|
|
12311
12464
|
"../ai-providers/dist/kling/KlingProvider.js"() {
|
|
12312
12465
|
"use strict";
|
|
12313
|
-
|
|
12466
|
+
DEFAULT_MODEL4 = "kling-v2-5-turbo";
|
|
12314
12467
|
STD_MODE_MODELS = ["kling-v2-5-turbo", "kling-v2-6", "kling-v3", "kling-v3-omni"];
|
|
12315
12468
|
KlingProvider = class {
|
|
12316
12469
|
constructor() {
|
|
@@ -12373,7 +12526,7 @@ var init_KlingProvider = __esm({
|
|
|
12373
12526
|
}
|
|
12374
12527
|
try {
|
|
12375
12528
|
const token = this.generateToken();
|
|
12376
|
-
const model = options?.model ||
|
|
12529
|
+
const model = options?.model || DEFAULT_MODEL4;
|
|
12377
12530
|
let mode = options?.mode || "std";
|
|
12378
12531
|
if (!STD_MODE_MODELS.includes(model) && mode === "std") {
|
|
12379
12532
|
mode = "pro";
|
|
@@ -12744,11 +12897,11 @@ var init_kling = __esm({
|
|
|
12744
12897
|
});
|
|
12745
12898
|
|
|
12746
12899
|
// ../ai-providers/dist/grok/GrokProvider.js
|
|
12747
|
-
var
|
|
12900
|
+
var DEFAULT_MODEL5, GrokProvider, grokProvider;
|
|
12748
12901
|
var init_GrokProvider = __esm({
|
|
12749
12902
|
"../ai-providers/dist/grok/GrokProvider.js"() {
|
|
12750
12903
|
"use strict";
|
|
12751
|
-
|
|
12904
|
+
DEFAULT_MODEL5 = "grok-imagine-video";
|
|
12752
12905
|
GrokProvider = class {
|
|
12753
12906
|
constructor() {
|
|
12754
12907
|
this.id = "grok";
|
|
@@ -12915,7 +13068,7 @@ var init_GrokProvider = __esm({
|
|
|
12915
13068
|
try {
|
|
12916
13069
|
const duration = Math.round(Math.min(15, Math.max(1, options?.duration || 5)));
|
|
12917
13070
|
const body = {
|
|
12918
|
-
model:
|
|
13071
|
+
model: DEFAULT_MODEL5,
|
|
12919
13072
|
prompt: prompt3,
|
|
12920
13073
|
duration,
|
|
12921
13074
|
aspect_ratio: options?.aspectRatio || "16:9"
|
|
@@ -18122,9 +18275,11 @@ __export(dist_exports2, {
|
|
|
18122
18275
|
KOKORO_MODEL_ID: () => KOKORO_MODEL_ID,
|
|
18123
18276
|
KlingProvider: () => KlingProvider,
|
|
18124
18277
|
KokoroProvider: () => KokoroProvider,
|
|
18278
|
+
OPENAI_TTS_VOICES: () => OPENAI_TTS_VOICES,
|
|
18125
18279
|
OllamaProvider: () => OllamaProvider,
|
|
18126
18280
|
OpenAIImageProvider: () => OpenAIImageProvider,
|
|
18127
18281
|
OpenAIProvider: () => OpenAIProvider,
|
|
18282
|
+
OpenAiTtsProvider: () => OpenAiTtsProvider,
|
|
18128
18283
|
ReplicateProvider: () => ReplicateProvider,
|
|
18129
18284
|
RunwayProvider: () => RunwayProvider,
|
|
18130
18285
|
WhisperProvider: () => WhisperProvider,
|
|
@@ -18148,9 +18303,12 @@ __export(dist_exports2, {
|
|
|
18148
18303
|
isGeminiTextModelAlias: () => isGeminiTextModelAlias,
|
|
18149
18304
|
klingProvider: () => klingProvider,
|
|
18150
18305
|
kokoroProvider: () => kokoroProvider,
|
|
18306
|
+
loadBundledKokoroRuntime: () => loadBundledKokoroRuntime,
|
|
18307
|
+
loadKokoroFromWorkspace: () => loadKokoroFromWorkspace,
|
|
18151
18308
|
ollamaProvider: () => ollamaProvider,
|
|
18152
18309
|
openaiImageProvider: () => openaiImageProvider,
|
|
18153
18310
|
openaiProvider: () => openaiProvider,
|
|
18311
|
+
openaiTtsProvider: () => openaiTtsProvider,
|
|
18154
18312
|
providerRegistry: () => providerRegistry,
|
|
18155
18313
|
replicateProvider: () => replicateProvider,
|
|
18156
18314
|
resolveGeminiTextModel: () => resolveGeminiTextModel,
|
|
@@ -18173,6 +18331,7 @@ var init_dist2 = __esm({
|
|
|
18173
18331
|
init_elevenlabs();
|
|
18174
18332
|
init_kokoro();
|
|
18175
18333
|
init_openai_image();
|
|
18334
|
+
init_openai_tts();
|
|
18176
18335
|
init_runway();
|
|
18177
18336
|
init_kling();
|
|
18178
18337
|
init_grok();
|
|
@@ -26347,10 +26506,22 @@ var init_api_key = __esm({
|
|
|
26347
26506
|
|
|
26348
26507
|
// src/commands/_shared/tts-resolve.ts
|
|
26349
26508
|
async function resolveTtsProvider(preferred = "auto") {
|
|
26350
|
-
|
|
26509
|
+
let choice = preferred;
|
|
26510
|
+
if (choice === "auto") {
|
|
26511
|
+
if (await getConfiguredApiKey("ELEVENLABS_API_KEY")) {
|
|
26512
|
+
choice = "elevenlabs";
|
|
26513
|
+
} else if (await getConfiguredApiKey("OPENAI_API_KEY")) {
|
|
26514
|
+
choice = "openai";
|
|
26515
|
+
} else {
|
|
26516
|
+
choice = "kokoro";
|
|
26517
|
+
}
|
|
26518
|
+
}
|
|
26351
26519
|
if (choice === "elevenlabs") {
|
|
26352
26520
|
return buildElevenLabs();
|
|
26353
26521
|
}
|
|
26522
|
+
if (choice === "openai") {
|
|
26523
|
+
return buildOpenAi();
|
|
26524
|
+
}
|
|
26354
26525
|
return buildKokoro();
|
|
26355
26526
|
}
|
|
26356
26527
|
async function buildElevenLabs() {
|
|
@@ -26366,6 +26537,19 @@ async function buildElevenLabs() {
|
|
|
26366
26537
|
});
|
|
26367
26538
|
return { provider: "elevenlabs", audioExtension: "mp3", call };
|
|
26368
26539
|
}
|
|
26540
|
+
async function buildOpenAi() {
|
|
26541
|
+
const key = await getApiKey("OPENAI_API_KEY", "OpenAI");
|
|
26542
|
+
if (!key) {
|
|
26543
|
+
throw new TtsKeyMissingError("openai");
|
|
26544
|
+
}
|
|
26545
|
+
const provider = new OpenAiTtsProvider();
|
|
26546
|
+
await provider.initialize({ apiKey: key });
|
|
26547
|
+
const call = async (text, opts) => provider.textToSpeech(text, {
|
|
26548
|
+
voice: opts?.voice,
|
|
26549
|
+
speed: opts?.speed
|
|
26550
|
+
});
|
|
26551
|
+
return { provider: "openai", audioExtension: "mp3", call };
|
|
26552
|
+
}
|
|
26369
26553
|
async function buildKokoro() {
|
|
26370
26554
|
const provider = new KokoroProvider();
|
|
26371
26555
|
await provider.initialize({});
|
|
@@ -26378,11 +26562,11 @@ async function buildKokoro() {
|
|
|
26378
26562
|
}
|
|
26379
26563
|
function parseTtsProviderName(value) {
|
|
26380
26564
|
if (!value) return "auto";
|
|
26381
|
-
if (value === "auto" || value === "elevenlabs" || value === "kokoro") {
|
|
26565
|
+
if (value === "auto" || value === "elevenlabs" || value === "openai" || value === "kokoro") {
|
|
26382
26566
|
return value;
|
|
26383
26567
|
}
|
|
26384
26568
|
throw new Error(
|
|
26385
|
-
`Invalid --tts: ${value}. Valid: auto, elevenlabs, kokoro.`
|
|
26569
|
+
`Invalid --tts: ${value}. Valid: auto, elevenlabs, openai, kokoro.`
|
|
26386
26570
|
);
|
|
26387
26571
|
}
|
|
26388
26572
|
var TtsKeyMissingError;
|
|
@@ -26394,7 +26578,7 @@ var init_tts_resolve = __esm({
|
|
|
26394
26578
|
TtsKeyMissingError = class extends Error {
|
|
26395
26579
|
constructor(provider) {
|
|
26396
26580
|
super(
|
|
26397
|
-
provider === "elevenlabs" ? "ElevenLabs API key required (ELEVENLABS_API_KEY). Run 'vibe setup', set ELEVENLABS_API_KEY in .env, or pass --tts kokoro for local synthesis." : `Provider ${provider} is unavailable.`
|
|
26581
|
+
provider === "elevenlabs" ? "ElevenLabs API key required (ELEVENLABS_API_KEY). Run 'vibe setup', set ELEVENLABS_API_KEY in .env, or pass --tts kokoro for local synthesis." : provider === "openai" ? "OpenAI API key required (OPENAI_API_KEY). Run 'vibe setup', set OPENAI_API_KEY in .env, or pass --tts kokoro for local synthesis." : `Provider ${provider} is unavailable.`
|
|
26398
26582
|
);
|
|
26399
26583
|
this.provider = provider;
|
|
26400
26584
|
this.name = "TtsKeyMissingError";
|
|
@@ -31013,7 +31197,7 @@ async function executeSceneAdd(opts) {
|
|
|
31013
31197
|
throw error;
|
|
31014
31198
|
}
|
|
31015
31199
|
opts.onProgress?.(
|
|
31016
|
-
resolution.provider === "kokoro" ? "Generating narration with Kokoro (local \u2014 first run downloads ~
|
|
31200
|
+
resolution.provider === "kokoro" ? "Generating narration with Kokoro (local \u2014 first run downloads a ~90MB model)..." : resolution.provider === "openai" ? "Generating narration with OpenAI (gpt-4o-mini-tts)..." : "Generating narration with ElevenLabs..."
|
|
31017
31201
|
);
|
|
31018
31202
|
const tts = await resolution.call(narrationText, {
|
|
31019
31203
|
voice: opts.voice,
|
|
@@ -31536,9 +31720,9 @@ Run 'vibe schema scene.<command>' for structured parameter info.`
|
|
|
31536
31720
|
"Image prompt \u2014 generates assets/scene-<id>.png via the configured image provider"
|
|
31537
31721
|
).option("--headline <text>", "Visible headline (defaults to the humanised scene name)").option("--kicker <text>", "Small label above the headline (explainer / product-shot)").option("--insert-into <path>", "Root composition file to update", "index.html").option("--project <dir>", "Project directory", ".").option("--image-provider <name>", "Image provider: gemini, openai", "gemini").option(
|
|
31538
31722
|
"--tts <provider>",
|
|
31539
|
-
"TTS provider: auto, elevenlabs, kokoro (default auto \u2014
|
|
31723
|
+
"TTS provider: auto, elevenlabs, openai, kokoro (default auto \u2014 ElevenLabs key > OpenAI key > Kokoro local)",
|
|
31540
31724
|
"auto"
|
|
31541
|
-
).option("--voice <id>", "Voice id (ElevenLabs name/id, or Kokoro id like af_heart
|
|
31725
|
+
).option("--voice <id>", "Voice id (ElevenLabs name/id, OpenAI voice like marin, or Kokoro id like af_heart)").option(
|
|
31542
31726
|
"--no-audio",
|
|
31543
31727
|
"Skip TTS even when --narration is provided (useful for tests/agent dry runs)"
|
|
31544
31728
|
).option("--no-image", "Skip image generation even when --visuals is provided").option(
|
|
@@ -59619,13 +59803,13 @@ async function createBuildPlan(opts) {
|
|
|
59619
59803
|
const backdropCue = backdropPrompt ?? backdropReference?.raw;
|
|
59620
59804
|
const videoCue = videoPrompt ?? videoReference?.raw;
|
|
59621
59805
|
const musicCue = musicPrompt ?? musicReference?.raw;
|
|
59622
|
-
const narrationCost = resolved.narration.resolved === "elevenlabs" ? ELEVENLABS_NARRATION_COST_USD : 0;
|
|
59806
|
+
const narrationCost = resolved.narration.resolved === "elevenlabs" ? ELEVENLABS_NARRATION_COST_USD : resolved.narration.resolved === "openai" ? OPENAI_NARRATION_COST_USD : 0;
|
|
59623
59807
|
const narrationCache = narrationText && !narrationReference ? narrationCacheDescriptor({
|
|
59624
59808
|
beatId: beat.id,
|
|
59625
59809
|
cue: narrationText,
|
|
59626
59810
|
provider: resolved.narration.resolved,
|
|
59627
59811
|
voice,
|
|
59628
|
-
ext: resolved.narration.resolved === "
|
|
59812
|
+
ext: resolved.narration.resolved === "kokoro" ? "wav" : "mp3"
|
|
59629
59813
|
}) : null;
|
|
59630
59814
|
const backdropCache = augmentedBackdropPrompt && !backdropReference ? backdropCacheDescriptor({
|
|
59631
59815
|
beatId: beat.id,
|
|
@@ -60043,17 +60227,20 @@ function providerInput(opts) {
|
|
|
60043
60227
|
async function resolveNarrationProvider(input, projectDir) {
|
|
60044
60228
|
const requested = input.value.toLowerCase();
|
|
60045
60229
|
const hasElevenLabs = Boolean(await getApiKeyFromConfig("elevenlabs", { cwd: projectDir }));
|
|
60046
|
-
const
|
|
60230
|
+
const hasOpenAi = Boolean(await getApiKeyFromConfig("openai", { cwd: projectDir }));
|
|
60231
|
+
const resolved = requested === "elevenlabs" ? "elevenlabs" : requested === "openai" ? "openai" : requested === "kokoro" ? "kokoro" : hasElevenLabs ? "elevenlabs" : hasOpenAi ? "openai" : "kokoro";
|
|
60232
|
+
const requiresKey = resolved !== "kokoro";
|
|
60233
|
+
const hasKey = resolved === "elevenlabs" ? hasElevenLabs : resolved === "openai" ? hasOpenAi : true;
|
|
60047
60234
|
return {
|
|
60048
60235
|
kind: "narration",
|
|
60049
60236
|
requested: input.requested,
|
|
60050
60237
|
resolved,
|
|
60051
60238
|
source: input.source,
|
|
60052
|
-
requiresKey
|
|
60053
|
-
configured:
|
|
60054
|
-
...
|
|
60055
|
-
...
|
|
60056
|
-
retryWith:
|
|
60239
|
+
requiresKey,
|
|
60240
|
+
configured: hasKey,
|
|
60241
|
+
...requiresKey ? { configKey: resolved } : {},
|
|
60242
|
+
...requiresKey && !hasKey ? { missingKey: providerEnvVar(resolved) } : {},
|
|
60243
|
+
retryWith: requiresKey && !hasKey ? ["vibe setup --full"] : []
|
|
60057
60244
|
};
|
|
60058
60245
|
}
|
|
60059
60246
|
async function keyedProviderResolution(opts, projectDir) {
|
|
@@ -60149,7 +60336,7 @@ function loadPlanEnv(projectDir) {
|
|
|
60149
60336
|
dir = dirname21(dir);
|
|
60150
60337
|
}
|
|
60151
60338
|
}
|
|
60152
|
-
var import_dotenv3, VIDEO_COST_USD, MUSIC_COST_USD, ELEVENLABS_NARRATION_COST_USD, COMPOSE_COST_USD, SUPPORTED_BUILD_IMAGE_PROVIDERS;
|
|
60339
|
+
var import_dotenv3, VIDEO_COST_USD, MUSIC_COST_USD, ELEVENLABS_NARRATION_COST_USD, OPENAI_NARRATION_COST_USD, COMPOSE_COST_USD, SUPPORTED_BUILD_IMAGE_PROVIDERS;
|
|
60153
60340
|
var init_build_plan = __esm({
|
|
60154
60341
|
"src/commands/_shared/build-plan.ts"() {
|
|
60155
60342
|
"use strict";
|
|
@@ -60167,6 +60354,7 @@ var init_build_plan = __esm({
|
|
|
60167
60354
|
VIDEO_COST_USD = 5;
|
|
60168
60355
|
MUSIC_COST_USD = 0.5;
|
|
60169
60356
|
ELEVENLABS_NARRATION_COST_USD = 0.05;
|
|
60357
|
+
OPENAI_NARRATION_COST_USD = 0.01;
|
|
60170
60358
|
COMPOSE_COST_USD = 0.06;
|
|
60171
60359
|
SUPPORTED_BUILD_IMAGE_PROVIDERS = ["openai", "gemini", "grok"];
|
|
60172
60360
|
}
|
|
@@ -67930,8 +68118,9 @@ function planBuildElicitation(args) {
|
|
|
67930
68118
|
description: "Which TTS engine narrates the video?",
|
|
67931
68119
|
enum: [...NARRATION_CHOICES],
|
|
67932
68120
|
enumNames: [
|
|
67933
|
-
"Kokoro \u2014 free, runs
|
|
67934
|
-
"
|
|
68121
|
+
"Kokoro \u2014 free, runs on this machine (first use downloads a ~90 MB voice model; slower)",
|
|
68122
|
+
"OpenAI \u2014 fast cloud voice, uses your OpenAI API key (~$0.02 per video)",
|
|
68123
|
+
"ElevenLabs \u2014 premium cloud voices, uses your ElevenLabs credits"
|
|
67935
68124
|
]
|
|
67936
68125
|
};
|
|
67937
68126
|
required.push("narration");
|
|
@@ -67987,7 +68176,7 @@ var NARRATION_CHOICES, BACKDROP_CHOICES;
|
|
|
67987
68176
|
var init_elicit = __esm({
|
|
67988
68177
|
"src/tools/_shared/elicit.ts"() {
|
|
67989
68178
|
"use strict";
|
|
67990
|
-
NARRATION_CHOICES = ["kokoro", "elevenlabs"];
|
|
68179
|
+
NARRATION_CHOICES = ["kokoro", "openai", "elevenlabs"];
|
|
67991
68180
|
BACKDROP_CHOICES = ["skip", "openai"];
|
|
67992
68181
|
}
|
|
67993
68182
|
});
|
|
@@ -68465,7 +68654,9 @@ var init_scene2 = __esm({
|
|
|
68465
68654
|
skipVideo: external_exports.boolean().optional().describe("Skip video generation for every beat (use existing MP4 assets if present)."),
|
|
68466
68655
|
skipMusic: external_exports.boolean().optional().describe("Skip music generation for every beat (use existing audio assets if present)."),
|
|
68467
68656
|
skipRender: external_exports.boolean().optional().describe("Stop after compose \u2014 produces compositions/*.html but no final MP4."),
|
|
68468
|
-
ttsProvider: external_exports.enum(["auto", "elevenlabs", "kokoro"]).optional().describe(
|
|
68657
|
+
ttsProvider: external_exports.enum(["auto", "elevenlabs", "openai", "kokoro"]).optional().describe(
|
|
68658
|
+
"TTS provider override. Default 'auto' (elevenlabs key > openai key > local kokoro)."
|
|
68659
|
+
),
|
|
68469
68660
|
voice: external_exports.string().optional().describe("TTS voice id (provider-specific)."),
|
|
68470
68661
|
imageProvider: external_exports.enum(["openai"]).optional().describe("Image provider for backdrops. Default 'openai' (gpt-image-2)."),
|
|
68471
68662
|
videoProvider: external_exports.enum(["seedance", "grok", "kling", "runway", "veo"]).optional().describe("Video provider for per-beat video cues. Default seedance."),
|
|
@@ -70320,7 +70511,7 @@ var init_storyboard2 = __esm({
|
|
|
70320
70511
|
skipBackdrop: external_exports.boolean().optional().describe("Don't include backdrop image generation in the plan."),
|
|
70321
70512
|
skipVideo: external_exports.boolean().optional().describe("Don't include video generation in the plan."),
|
|
70322
70513
|
skipMusic: external_exports.boolean().optional().describe("Don't include music generation in the plan."),
|
|
70323
|
-
ttsProvider: external_exports.enum(["auto", "elevenlabs", "kokoro"]).optional().describe("TTS provider override."),
|
|
70514
|
+
ttsProvider: external_exports.enum(["auto", "elevenlabs", "openai", "kokoro"]).optional().describe("TTS provider override."),
|
|
70324
70515
|
voice: external_exports.string().optional().describe("Voice id."),
|
|
70325
70516
|
imageProvider: external_exports.string().optional().describe("Image provider override."),
|
|
70326
70517
|
imageQuality: external_exports.enum(["standard", "hd"]).optional().describe("Image quality override."),
|
|
@@ -73436,7 +73627,7 @@ init_source();
|
|
|
73436
73627
|
// package.json
|
|
73437
73628
|
var package_default = {
|
|
73438
73629
|
name: "@vibeframe/cli",
|
|
73439
|
-
version: "0.
|
|
73630
|
+
version: "0.113.0",
|
|
73440
73631
|
description: "VibeFrame CLI - agentic video workflow runtime",
|
|
73441
73632
|
private: false,
|
|
73442
73633
|
license: "MIT",
|
|
@@ -83439,13 +83630,13 @@ init_output();
|
|
|
83439
83630
|
import { resolve as resolve61 } from "node:path";
|
|
83440
83631
|
var VALID_STAGES = ["assets", "compose", "sync", "render", "all"];
|
|
83441
83632
|
var VALID_MODES = ["agent", "batch", "auto"];
|
|
83442
|
-
var VALID_TTS_PROVIDERS = ["auto", "elevenlabs", "kokoro"];
|
|
83633
|
+
var VALID_TTS_PROVIDERS = ["auto", "elevenlabs", "openai", "kokoro"];
|
|
83443
83634
|
var VALID_IMAGE_PROVIDERS = ["openai", "gemini", "grok"];
|
|
83444
83635
|
var VALID_VIDEO_PROVIDERS = ["seedance", "grok", "kling", "runway", "veo"];
|
|
83445
83636
|
var VALID_MUSIC_PROVIDERS = ["elevenlabs", "replicate"];
|
|
83446
83637
|
var VALID_COMPOSERS = ["claude", "openai", "gemini"];
|
|
83447
83638
|
var VALID_IMAGE_QUALITIES = ["standard", "hd"];
|
|
83448
|
-
var planCommand = new Command("plan").description("Read STORYBOARD.md and show build plan, costs, missing cues, and provider needs").argument("[project-dir]", "Video project directory", ".").option("--stage <stage>", `Stage to plan: ${VALID_STAGES.join("|")}`, "all").option("--beat <id>", "Restrict the plan to one beat").option("--mode <mode>", "Build mode: agent|batch|auto", "auto").option("--skip-narration", "Don't include narration generation in the plan").option("--skip-backdrop", "Don't include backdrop image generation in the plan").option("--skip-video", "Don't include video generation in the plan").option("--skip-music", "Don't include music generation in the plan").option("--tts <provider>", "TTS provider: auto|elevenlabs|kokoro").option("--voice <id>", "Voice id").option("--image-provider <name>", `Image provider: ${VALID_IMAGE_PROVIDERS.join("|")}`).option("--video-provider <name>", `Video provider: ${VALID_VIDEO_PROVIDERS.join("|")}`).option("--music-provider <name>", `Music provider: ${VALID_MUSIC_PROVIDERS.join("|")}`).option("--quality <q>", "Image quality: standard|hd").option("--image-size <s>", "Image size: 1024x1024|1536x1024|1024x1536").option("--composer <provider>", "Batch composer: claude|openai|gemini").option("--force", "Plan regeneration even when outputs already exist").option("--max-cost <usd>", "Fail if estimated cost exceeds this USD cap").action(async (projectDirArg, options) => {
|
|
83639
|
+
var planCommand = new Command("plan").description("Read STORYBOARD.md and show build plan, costs, missing cues, and provider needs").argument("[project-dir]", "Video project directory", ".").option("--stage <stage>", `Stage to plan: ${VALID_STAGES.join("|")}`, "all").option("--beat <id>", "Restrict the plan to one beat").option("--mode <mode>", "Build mode: agent|batch|auto", "auto").option("--skip-narration", "Don't include narration generation in the plan").option("--skip-backdrop", "Don't include backdrop image generation in the plan").option("--skip-video", "Don't include video generation in the plan").option("--skip-music", "Don't include music generation in the plan").option("--tts <provider>", "TTS provider: auto|elevenlabs|openai|kokoro").option("--voice <id>", "Voice id").option("--image-provider <name>", `Image provider: ${VALID_IMAGE_PROVIDERS.join("|")}`).option("--video-provider <name>", `Video provider: ${VALID_VIDEO_PROVIDERS.join("|")}`).option("--music-provider <name>", `Music provider: ${VALID_MUSIC_PROVIDERS.join("|")}`).option("--quality <q>", "Image quality: standard|hd").option("--image-size <s>", "Image size: 1024x1024|1536x1024|1024x1536").option("--composer <provider>", "Batch composer: claude|openai|gemini").option("--force", "Plan regeneration even when outputs already exist").option("--max-cost <usd>", "Fail if estimated cost exceeds this USD cap").action(async (projectDirArg, options) => {
|
|
83449
83640
|
const startedAt = Date.now();
|
|
83450
83641
|
const stage = String(options.stage ?? "all");
|
|
83451
83642
|
if (!VALID_STAGES.includes(stage)) {
|
|
@@ -83636,7 +83827,7 @@ var VALID_STAGES2 = ["assets", "compose", "sync", "render", "all"];
|
|
|
83636
83827
|
var VALID_IMAGE_PROVIDERS2 = ["openai", "gemini", "grok"];
|
|
83637
83828
|
var VALID_VIDEO_PROVIDERS2 = ["seedance", "grok", "kling", "runway", "veo"];
|
|
83638
83829
|
var VALID_MUSIC_PROVIDERS2 = ["elevenlabs", "replicate"];
|
|
83639
|
-
var buildCommand = new Command("build").description("Build a VibeFrame video project from STORYBOARD.md").argument("[project-dir]", "Video project directory", ".").option("--stage <stage>", `Build stage: ${VALID_STAGES2.join("|")}`, "all").option("--beat <id>", "Restrict asset/compose work to one beat id").option("--mode <mode>", "Build mode: agent|batch|auto", "auto").option("--effort <level>", "Compose effort tier (batch mode only): low|medium|high", "medium").option("--composer <provider>", "Batch composer: claude|openai|gemini").option("--max-cost <usd>", "Fail before provider spend when estimated cost exceeds this USD cap").option("--skip-narration", "Don't dispatch TTS even when beats declare narration cues").option("--skip-backdrop", "Don't dispatch image-gen even when beats declare backdrop cues").option("--skip-video", "Don't dispatch video generation even when beats declare video cues").option("--skip-music", "Don't dispatch music generation even when beats declare music cues").option("--skip-render", "Compose only \u2014 don't render to MP4").option("--tts <provider>", "TTS provider: auto|elevenlabs|kokoro").option("--voice <id>", "Voice id").option("--image-provider <name>", `Image provider: ${VALID_IMAGE_PROVIDERS2.join("|")}`).option("--video-provider <name>", `Video provider: ${VALID_VIDEO_PROVIDERS2.join("|")}`).option("--music-provider <name>", `Music provider: ${VALID_MUSIC_PROVIDERS2.join("|")}`).option("--quality <q>", "Image quality: standard|hd", "hd").option("--image-size <s>", "Image size: 1024x1024|1536x1024|1024x1536", "1536x1024").option("--force", "Re-dispatch primitives even when assets already exist").option("--dry-run", "Preview parameters without dispatching").addHelpText(
|
|
83830
|
+
var buildCommand = new Command("build").description("Build a VibeFrame video project from STORYBOARD.md").argument("[project-dir]", "Video project directory", ".").option("--stage <stage>", `Build stage: ${VALID_STAGES2.join("|")}`, "all").option("--beat <id>", "Restrict asset/compose work to one beat id").option("--mode <mode>", "Build mode: agent|batch|auto", "auto").option("--effort <level>", "Compose effort tier (batch mode only): low|medium|high", "medium").option("--composer <provider>", "Batch composer: claude|openai|gemini").option("--max-cost <usd>", "Fail before provider spend when estimated cost exceeds this USD cap").option("--skip-narration", "Don't dispatch TTS even when beats declare narration cues").option("--skip-backdrop", "Don't dispatch image-gen even when beats declare backdrop cues").option("--skip-video", "Don't dispatch video generation even when beats declare video cues").option("--skip-music", "Don't dispatch music generation even when beats declare music cues").option("--skip-render", "Compose only \u2014 don't render to MP4").option("--tts <provider>", "TTS provider: auto|elevenlabs|openai|kokoro").option("--voice <id>", "Voice id").option("--image-provider <name>", `Image provider: ${VALID_IMAGE_PROVIDERS2.join("|")}`).option("--video-provider <name>", `Video provider: ${VALID_VIDEO_PROVIDERS2.join("|")}`).option("--music-provider <name>", `Music provider: ${VALID_MUSIC_PROVIDERS2.join("|")}`).option("--quality <q>", "Image quality: standard|hd", "hd").option("--image-size <s>", "Image size: 1024x1024|1536x1024|1024x1536", "1536x1024").option("--force", "Re-dispatch primitives even when assets already exist").option("--dry-run", "Preview parameters without dispatching").addHelpText(
|
|
83640
83831
|
"after",
|
|
83641
83832
|
`
|
|
83642
83833
|
Examples:
|
|
@@ -11,7 +11,7 @@ import type { ElicitForm } from "../adapters/mcp.js";
|
|
|
11
11
|
/** The subset of build args that drive the question set. */
|
|
12
12
|
export interface BuildChoiceArgs {
|
|
13
13
|
stage?: "assets" | "compose" | "sync" | "render" | "all";
|
|
14
|
-
ttsProvider?: "auto" | "elevenlabs" | "kokoro";
|
|
14
|
+
ttsProvider?: "auto" | "elevenlabs" | "openai" | "kokoro";
|
|
15
15
|
skipNarration?: boolean;
|
|
16
16
|
skipBackdrop?: boolean;
|
|
17
17
|
imageProvider?: string;
|
|
@@ -191,8 +191,8 @@ var init_api_keys = __esm({
|
|
|
191
191
|
envVar: "OPENAI_API_KEY",
|
|
192
192
|
label: "OpenAI",
|
|
193
193
|
showInSetup: true,
|
|
194
|
-
setupDescription: "gpt-image-2 image gen ($, default since v0.56), Whisper transcribe, Agent",
|
|
195
|
-
envExampleComment: "OpenAI API Key (Whisper transcription, gpt-image-2 \u2014 default text-to-image since v0.56)",
|
|
194
|
+
setupDescription: "gpt-image-2 image gen ($, default since v0.56), gpt-4o-mini-tts narration, Whisper transcribe, Agent",
|
|
195
|
+
envExampleComment: "OpenAI API Key (Whisper transcription, gpt-4o-mini-tts narration, gpt-image-2 \u2014 default text-to-image since v0.56)",
|
|
196
196
|
envExampleUrl: "https://platform.openai.com/api-keys",
|
|
197
197
|
keyFormat: { prefix: /^sk-/, example: "sk-..." }
|
|
198
198
|
});
|
|
@@ -2299,8 +2299,8 @@ var init_openai = __esm({
|
|
|
2299
2299
|
id: "openai",
|
|
2300
2300
|
label: "OpenAI",
|
|
2301
2301
|
apiKey: "openai",
|
|
2302
|
-
kinds: ["llm", "image", "transcription"],
|
|
2303
|
-
resolverPriority: { image: 1 },
|
|
2302
|
+
kinds: ["llm", "image", "transcription", "speech"],
|
|
2303
|
+
resolverPriority: { image: 1, speech: 2 },
|
|
2304
2304
|
commandsUnlocked: [
|
|
2305
2305
|
"agent -p openai",
|
|
2306
2306
|
"generate image -p openai",
|
|
@@ -4722,16 +4722,19 @@ var init_elevenlabs = __esm({
|
|
|
4722
4722
|
});
|
|
4723
4723
|
|
|
4724
4724
|
// ../ai-providers/dist/kokoro/KokoroProvider.js
|
|
4725
|
-
async function
|
|
4725
|
+
async function loadKokoroRuntime() {
|
|
4726
4726
|
if (factoryOverride)
|
|
4727
|
-
return factoryOverride;
|
|
4727
|
+
return { factory: factoryOverride, device: "cpu" };
|
|
4728
4728
|
try {
|
|
4729
4729
|
const mod = await import("kokoro-js");
|
|
4730
|
-
return mod.KokoroTTS;
|
|
4730
|
+
return { factory: mod.KokoroTTS, device: "cpu" };
|
|
4731
4731
|
} catch (err) {
|
|
4732
|
-
const
|
|
4733
|
-
if (
|
|
4734
|
-
return
|
|
4732
|
+
const workspace = await loadKokoroFromWorkspace();
|
|
4733
|
+
if (workspace)
|
|
4734
|
+
return { factory: workspace, device: "cpu" };
|
|
4735
|
+
const bundled = await loadBundledKokoroRuntime();
|
|
4736
|
+
if (bundled)
|
|
4737
|
+
return bundled;
|
|
4735
4738
|
throw mapKokoroImportError(err);
|
|
4736
4739
|
}
|
|
4737
4740
|
}
|
|
@@ -4751,10 +4754,51 @@ async function loadKokoroFromWorkspace(baseDir = process.cwd()) {
|
|
|
4751
4754
|
return null;
|
|
4752
4755
|
}
|
|
4753
4756
|
}
|
|
4757
|
+
async function loadBundledKokoroRuntime(runtimeDir = process.env.VIBE_KOKORO_RUNTIME) {
|
|
4758
|
+
const base = runtimeDir?.trim();
|
|
4759
|
+
if (!base)
|
|
4760
|
+
return null;
|
|
4761
|
+
try {
|
|
4762
|
+
const { readFile: readFile45, writeFile: writeFile51, mkdir: mkdir26 } = await import("node:fs/promises");
|
|
4763
|
+
const { join: join27, resolve: resolve66 } = await import("node:path");
|
|
4764
|
+
const { pathToFileURL } = await import("node:url");
|
|
4765
|
+
const { homedir: homedir6 } = await import("node:os");
|
|
4766
|
+
const transformersDir = resolve66(base, "node_modules", "@huggingface", "transformers");
|
|
4767
|
+
const ortDistDir = resolve66(base, "node_modules", "onnxruntime-web", "dist");
|
|
4768
|
+
const transformers = await import(pathToFileURL(join27(transformersDir, "dist", "transformers.web.js")).href);
|
|
4769
|
+
const cacheRoot = join27(homedir6(), ".cache", "vibeframe", "models");
|
|
4770
|
+
transformers.env.allowLocalModels = false;
|
|
4771
|
+
transformers.env.useCustomCache = true;
|
|
4772
|
+
transformers.env.customCache = {
|
|
4773
|
+
async match(key) {
|
|
4774
|
+
try {
|
|
4775
|
+
return new Response(await readFile45(join27(cacheRoot, encodeURIComponent(String(key)))));
|
|
4776
|
+
} catch {
|
|
4777
|
+
return void 0;
|
|
4778
|
+
}
|
|
4779
|
+
},
|
|
4780
|
+
async put(key, response) {
|
|
4781
|
+
try {
|
|
4782
|
+
const buf = Buffer.from(await response.arrayBuffer());
|
|
4783
|
+
await mkdir26(cacheRoot, { recursive: true });
|
|
4784
|
+
await writeFile51(join27(cacheRoot, encodeURIComponent(String(key))), buf);
|
|
4785
|
+
} catch {
|
|
4786
|
+
}
|
|
4787
|
+
}
|
|
4788
|
+
};
|
|
4789
|
+
transformers.env.backends.onnx.wasm.wasmPaths = pathToFileURL(ortDistDir + "/").href;
|
|
4790
|
+
const factory = await loadKokoroFromWorkspace(base);
|
|
4791
|
+
if (!factory)
|
|
4792
|
+
return null;
|
|
4793
|
+
return { factory, device: "cpu" };
|
|
4794
|
+
} catch {
|
|
4795
|
+
return null;
|
|
4796
|
+
}
|
|
4797
|
+
}
|
|
4754
4798
|
function mapKokoroImportError(err) {
|
|
4755
4799
|
const code = err instanceof Error && "code" in err ? err.code : void 0;
|
|
4756
4800
|
if (code === "ERR_MODULE_NOT_FOUND" || code === "MODULE_NOT_FOUND") {
|
|
4757
|
-
return new Error("Local Kokoro TTS is unavailable:
|
|
4801
|
+
return new Error("Local Kokoro TTS is unavailable: kokoro-js could not be loaded from the npm install, the workspace node_modules, or the bundled extension runtime. Set OPENAI_API_KEY or ELEVENLABS_API_KEY to use a cloud voice instead (ttsProvider: openai / elevenlabs), or install the engine locally with `npm i kokoro-js` in your workspace folder.");
|
|
4758
4802
|
}
|
|
4759
4803
|
return err instanceof Error ? err : new Error(String(err));
|
|
4760
4804
|
}
|
|
@@ -4762,10 +4806,12 @@ function loadModel(progress) {
|
|
|
4762
4806
|
if (modelPromise)
|
|
4763
4807
|
return modelPromise;
|
|
4764
4808
|
modelPromise = (async () => {
|
|
4765
|
-
const
|
|
4766
|
-
|
|
4809
|
+
const runtime = await loadKokoroRuntime();
|
|
4810
|
+
const override = process.env.VIBE_ONNX_DEVICE;
|
|
4811
|
+
const device = override === "cpu" || override === "wasm" ? override : runtime.device;
|
|
4812
|
+
return runtime.factory.from_pretrained(KOKORO_MODEL_ID, {
|
|
4767
4813
|
dtype: "q8",
|
|
4768
|
-
device
|
|
4814
|
+
device,
|
|
4769
4815
|
progress_callback: progress ? (raw) => progress(normaliseEvent(raw)) : void 0
|
|
4770
4816
|
});
|
|
4771
4817
|
})().catch((err) => {
|
|
@@ -4849,7 +4895,7 @@ var init_kokoro = __esm({
|
|
|
4849
4895
|
label: "Kokoro (local)",
|
|
4850
4896
|
apiKey: null,
|
|
4851
4897
|
kinds: ["speech"],
|
|
4852
|
-
resolverPriority: { speech:
|
|
4898
|
+
resolverPriority: { speech: 3 }
|
|
4853
4899
|
});
|
|
4854
4900
|
}
|
|
4855
4901
|
});
|
|
@@ -5121,12 +5167,119 @@ var init_openai_image = __esm({
|
|
|
5121
5167
|
}
|
|
5122
5168
|
});
|
|
5123
5169
|
|
|
5170
|
+
// ../ai-providers/dist/openai-tts/OpenAiTtsProvider.js
|
|
5171
|
+
var OPENAI_TTS_VOICES, DEFAULT_VOICE, DEFAULT_MODEL2, TTS_429_MAX_RETRIES2, TTS_429_RETRY_DELAY_MS2, OpenAiTtsProvider, openaiTtsProvider;
|
|
5172
|
+
var init_OpenAiTtsProvider = __esm({
|
|
5173
|
+
"../ai-providers/dist/openai-tts/OpenAiTtsProvider.js"() {
|
|
5174
|
+
"use strict";
|
|
5175
|
+
OPENAI_TTS_VOICES = [
|
|
5176
|
+
"alloy",
|
|
5177
|
+
"ash",
|
|
5178
|
+
"ballad",
|
|
5179
|
+
"cedar",
|
|
5180
|
+
"coral",
|
|
5181
|
+
"echo",
|
|
5182
|
+
"fable",
|
|
5183
|
+
"marin",
|
|
5184
|
+
"nova",
|
|
5185
|
+
"onyx",
|
|
5186
|
+
"sage",
|
|
5187
|
+
"shimmer",
|
|
5188
|
+
"verse"
|
|
5189
|
+
];
|
|
5190
|
+
DEFAULT_VOICE = "marin";
|
|
5191
|
+
DEFAULT_MODEL2 = "gpt-4o-mini-tts";
|
|
5192
|
+
TTS_429_MAX_RETRIES2 = 1;
|
|
5193
|
+
TTS_429_RETRY_DELAY_MS2 = 2e3;
|
|
5194
|
+
OpenAiTtsProvider = class {
|
|
5195
|
+
constructor() {
|
|
5196
|
+
this.id = "openai";
|
|
5197
|
+
this.name = "OpenAI TTS";
|
|
5198
|
+
this.description = "OpenAI cloud text-to-speech (gpt-4o-mini-tts)";
|
|
5199
|
+
this.capabilities = ["text-to-speech"];
|
|
5200
|
+
this.isAvailable = true;
|
|
5201
|
+
this.baseUrl = "https://api.openai.com/v1";
|
|
5202
|
+
}
|
|
5203
|
+
async initialize(config2) {
|
|
5204
|
+
this.apiKey = config2.apiKey;
|
|
5205
|
+
if (config2.baseUrl) {
|
|
5206
|
+
this.baseUrl = config2.baseUrl;
|
|
5207
|
+
}
|
|
5208
|
+
}
|
|
5209
|
+
isConfigured() {
|
|
5210
|
+
return !!this.apiKey;
|
|
5211
|
+
}
|
|
5212
|
+
async textToSpeech(text, options = {}) {
|
|
5213
|
+
if (!this.apiKey) {
|
|
5214
|
+
return { success: false, error: "OpenAI API key not configured" };
|
|
5215
|
+
}
|
|
5216
|
+
const voice = (options.voice ?? DEFAULT_VOICE).toLowerCase();
|
|
5217
|
+
if (!OPENAI_TTS_VOICES.includes(voice)) {
|
|
5218
|
+
return {
|
|
5219
|
+
success: false,
|
|
5220
|
+
error: `Unknown OpenAI voice "${options.voice}". Available voices: ${OPENAI_TTS_VOICES.join(", ")}.`
|
|
5221
|
+
};
|
|
5222
|
+
}
|
|
5223
|
+
try {
|
|
5224
|
+
let response;
|
|
5225
|
+
for (let attempt = 0; ; attempt++) {
|
|
5226
|
+
response = await fetch(`${this.baseUrl}/audio/speech`, {
|
|
5227
|
+
method: "POST",
|
|
5228
|
+
headers: {
|
|
5229
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
5230
|
+
"Content-Type": "application/json"
|
|
5231
|
+
},
|
|
5232
|
+
body: JSON.stringify({
|
|
5233
|
+
model: options.model ?? DEFAULT_MODEL2,
|
|
5234
|
+
input: text,
|
|
5235
|
+
voice,
|
|
5236
|
+
response_format: "mp3",
|
|
5237
|
+
...options.speed !== void 0 && { speed: options.speed },
|
|
5238
|
+
...options.instructions !== void 0 && { instructions: options.instructions }
|
|
5239
|
+
})
|
|
5240
|
+
});
|
|
5241
|
+
if (response.status === 429 && attempt < TTS_429_MAX_RETRIES2) {
|
|
5242
|
+
await new Promise((resolveDelay) => setTimeout(resolveDelay, TTS_429_RETRY_DELAY_MS2 * (attempt + 1)));
|
|
5243
|
+
continue;
|
|
5244
|
+
}
|
|
5245
|
+
break;
|
|
5246
|
+
}
|
|
5247
|
+
if (!response.ok) {
|
|
5248
|
+
const error = await response.text();
|
|
5249
|
+
return { success: false, error: `OpenAI TTS failed: ${error}` };
|
|
5250
|
+
}
|
|
5251
|
+
const arrayBuffer = await response.arrayBuffer();
|
|
5252
|
+
return {
|
|
5253
|
+
success: true,
|
|
5254
|
+
audioBuffer: Buffer.from(arrayBuffer),
|
|
5255
|
+
characterCount: text.length
|
|
5256
|
+
};
|
|
5257
|
+
} catch (error) {
|
|
5258
|
+
return {
|
|
5259
|
+
success: false,
|
|
5260
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
5261
|
+
};
|
|
5262
|
+
}
|
|
5263
|
+
}
|
|
5264
|
+
};
|
|
5265
|
+
openaiTtsProvider = new OpenAiTtsProvider();
|
|
5266
|
+
}
|
|
5267
|
+
});
|
|
5268
|
+
|
|
5269
|
+
// ../ai-providers/dist/openai-tts/index.js
|
|
5270
|
+
var init_openai_tts = __esm({
|
|
5271
|
+
"../ai-providers/dist/openai-tts/index.js"() {
|
|
5272
|
+
"use strict";
|
|
5273
|
+
init_OpenAiTtsProvider();
|
|
5274
|
+
}
|
|
5275
|
+
});
|
|
5276
|
+
|
|
5124
5277
|
// ../ai-providers/dist/runway/RunwayProvider.js
|
|
5125
|
-
var
|
|
5278
|
+
var DEFAULT_MODEL3, RunwayProvider, runwayProvider;
|
|
5126
5279
|
var init_RunwayProvider = __esm({
|
|
5127
5280
|
"../ai-providers/dist/runway/RunwayProvider.js"() {
|
|
5128
5281
|
"use strict";
|
|
5129
|
-
|
|
5282
|
+
DEFAULT_MODEL3 = "gen4.5";
|
|
5130
5283
|
RunwayProvider = class _RunwayProvider {
|
|
5131
5284
|
constructor() {
|
|
5132
5285
|
this.id = "runway";
|
|
@@ -5169,7 +5322,7 @@ var init_RunwayProvider = __esm({
|
|
|
5169
5322
|
"1:1": "960:960"
|
|
5170
5323
|
};
|
|
5171
5324
|
const apiRatio = ratioMap[options?.aspectRatio || "16:9"] || "1280:720";
|
|
5172
|
-
const model = options?.model ||
|
|
5325
|
+
const model = options?.model || DEFAULT_MODEL3;
|
|
5173
5326
|
if (!options?.referenceImage && model !== "gen4.5") {
|
|
5174
5327
|
return {
|
|
5175
5328
|
id: "",
|
|
@@ -5431,11 +5584,11 @@ var init_runway = __esm({
|
|
|
5431
5584
|
|
|
5432
5585
|
// ../ai-providers/dist/kling/KlingProvider.js
|
|
5433
5586
|
import { createHmac } from "node:crypto";
|
|
5434
|
-
var
|
|
5587
|
+
var DEFAULT_MODEL4, STD_MODE_MODELS, KlingProvider, klingProvider;
|
|
5435
5588
|
var init_KlingProvider = __esm({
|
|
5436
5589
|
"../ai-providers/dist/kling/KlingProvider.js"() {
|
|
5437
5590
|
"use strict";
|
|
5438
|
-
|
|
5591
|
+
DEFAULT_MODEL4 = "kling-v2-5-turbo";
|
|
5439
5592
|
STD_MODE_MODELS = ["kling-v2-5-turbo", "kling-v2-6", "kling-v3", "kling-v3-omni"];
|
|
5440
5593
|
KlingProvider = class {
|
|
5441
5594
|
constructor() {
|
|
@@ -5498,7 +5651,7 @@ var init_KlingProvider = __esm({
|
|
|
5498
5651
|
}
|
|
5499
5652
|
try {
|
|
5500
5653
|
const token = this.generateToken();
|
|
5501
|
-
const model = options?.model ||
|
|
5654
|
+
const model = options?.model || DEFAULT_MODEL4;
|
|
5502
5655
|
let mode = options?.mode || "std";
|
|
5503
5656
|
if (!STD_MODE_MODELS.includes(model) && mode === "std") {
|
|
5504
5657
|
mode = "pro";
|
|
@@ -5869,11 +6022,11 @@ var init_kling = __esm({
|
|
|
5869
6022
|
});
|
|
5870
6023
|
|
|
5871
6024
|
// ../ai-providers/dist/grok/GrokProvider.js
|
|
5872
|
-
var
|
|
6025
|
+
var DEFAULT_MODEL5, GrokProvider, grokProvider;
|
|
5873
6026
|
var init_GrokProvider = __esm({
|
|
5874
6027
|
"../ai-providers/dist/grok/GrokProvider.js"() {
|
|
5875
6028
|
"use strict";
|
|
5876
|
-
|
|
6029
|
+
DEFAULT_MODEL5 = "grok-imagine-video";
|
|
5877
6030
|
GrokProvider = class {
|
|
5878
6031
|
constructor() {
|
|
5879
6032
|
this.id = "grok";
|
|
@@ -6040,7 +6193,7 @@ var init_GrokProvider = __esm({
|
|
|
6040
6193
|
try {
|
|
6041
6194
|
const duration = Math.round(Math.min(15, Math.max(1, options?.duration || 5)));
|
|
6042
6195
|
const body = {
|
|
6043
|
-
model:
|
|
6196
|
+
model: DEFAULT_MODEL5,
|
|
6044
6197
|
prompt: prompt3,
|
|
6045
6198
|
duration,
|
|
6046
6199
|
aspect_ratio: options?.aspectRatio || "16:9"
|
|
@@ -11247,9 +11400,11 @@ __export(dist_exports2, {
|
|
|
11247
11400
|
KOKORO_MODEL_ID: () => KOKORO_MODEL_ID,
|
|
11248
11401
|
KlingProvider: () => KlingProvider,
|
|
11249
11402
|
KokoroProvider: () => KokoroProvider,
|
|
11403
|
+
OPENAI_TTS_VOICES: () => OPENAI_TTS_VOICES,
|
|
11250
11404
|
OllamaProvider: () => OllamaProvider,
|
|
11251
11405
|
OpenAIImageProvider: () => OpenAIImageProvider,
|
|
11252
11406
|
OpenAIProvider: () => OpenAIProvider,
|
|
11407
|
+
OpenAiTtsProvider: () => OpenAiTtsProvider,
|
|
11253
11408
|
ReplicateProvider: () => ReplicateProvider,
|
|
11254
11409
|
RunwayProvider: () => RunwayProvider,
|
|
11255
11410
|
WhisperProvider: () => WhisperProvider,
|
|
@@ -11273,9 +11428,12 @@ __export(dist_exports2, {
|
|
|
11273
11428
|
isGeminiTextModelAlias: () => isGeminiTextModelAlias,
|
|
11274
11429
|
klingProvider: () => klingProvider,
|
|
11275
11430
|
kokoroProvider: () => kokoroProvider,
|
|
11431
|
+
loadBundledKokoroRuntime: () => loadBundledKokoroRuntime,
|
|
11432
|
+
loadKokoroFromWorkspace: () => loadKokoroFromWorkspace,
|
|
11276
11433
|
ollamaProvider: () => ollamaProvider,
|
|
11277
11434
|
openaiImageProvider: () => openaiImageProvider,
|
|
11278
11435
|
openaiProvider: () => openaiProvider,
|
|
11436
|
+
openaiTtsProvider: () => openaiTtsProvider,
|
|
11279
11437
|
providerRegistry: () => providerRegistry,
|
|
11280
11438
|
replicateProvider: () => replicateProvider,
|
|
11281
11439
|
resolveGeminiTextModel: () => resolveGeminiTextModel,
|
|
@@ -11298,6 +11456,7 @@ var init_dist2 = __esm({
|
|
|
11298
11456
|
init_elevenlabs();
|
|
11299
11457
|
init_kokoro();
|
|
11300
11458
|
init_openai_image();
|
|
11459
|
+
init_openai_tts();
|
|
11301
11460
|
init_runway();
|
|
11302
11461
|
init_kling();
|
|
11303
11462
|
init_grok();
|
|
@@ -28713,10 +28872,22 @@ var init_esm = __esm({
|
|
|
28713
28872
|
|
|
28714
28873
|
// src/commands/_shared/tts-resolve.ts
|
|
28715
28874
|
async function resolveTtsProvider(preferred = "auto") {
|
|
28716
|
-
|
|
28875
|
+
let choice = preferred;
|
|
28876
|
+
if (choice === "auto") {
|
|
28877
|
+
if (await getConfiguredApiKey("ELEVENLABS_API_KEY")) {
|
|
28878
|
+
choice = "elevenlabs";
|
|
28879
|
+
} else if (await getConfiguredApiKey("OPENAI_API_KEY")) {
|
|
28880
|
+
choice = "openai";
|
|
28881
|
+
} else {
|
|
28882
|
+
choice = "kokoro";
|
|
28883
|
+
}
|
|
28884
|
+
}
|
|
28717
28885
|
if (choice === "elevenlabs") {
|
|
28718
28886
|
return buildElevenLabs();
|
|
28719
28887
|
}
|
|
28888
|
+
if (choice === "openai") {
|
|
28889
|
+
return buildOpenAi();
|
|
28890
|
+
}
|
|
28720
28891
|
return buildKokoro();
|
|
28721
28892
|
}
|
|
28722
28893
|
async function buildElevenLabs() {
|
|
@@ -28732,6 +28903,19 @@ async function buildElevenLabs() {
|
|
|
28732
28903
|
});
|
|
28733
28904
|
return { provider: "elevenlabs", audioExtension: "mp3", call };
|
|
28734
28905
|
}
|
|
28906
|
+
async function buildOpenAi() {
|
|
28907
|
+
const key = await getApiKey("OPENAI_API_KEY", "OpenAI");
|
|
28908
|
+
if (!key) {
|
|
28909
|
+
throw new TtsKeyMissingError("openai");
|
|
28910
|
+
}
|
|
28911
|
+
const provider = new OpenAiTtsProvider();
|
|
28912
|
+
await provider.initialize({ apiKey: key });
|
|
28913
|
+
const call = async (text, opts) => provider.textToSpeech(text, {
|
|
28914
|
+
voice: opts?.voice,
|
|
28915
|
+
speed: opts?.speed
|
|
28916
|
+
});
|
|
28917
|
+
return { provider: "openai", audioExtension: "mp3", call };
|
|
28918
|
+
}
|
|
28735
28919
|
async function buildKokoro() {
|
|
28736
28920
|
const provider = new KokoroProvider();
|
|
28737
28921
|
await provider.initialize({});
|
|
@@ -28744,11 +28928,11 @@ async function buildKokoro() {
|
|
|
28744
28928
|
}
|
|
28745
28929
|
function parseTtsProviderName(value) {
|
|
28746
28930
|
if (!value) return "auto";
|
|
28747
|
-
if (value === "auto" || value === "elevenlabs" || value === "kokoro") {
|
|
28931
|
+
if (value === "auto" || value === "elevenlabs" || value === "openai" || value === "kokoro") {
|
|
28748
28932
|
return value;
|
|
28749
28933
|
}
|
|
28750
28934
|
throw new Error(
|
|
28751
|
-
`Invalid --tts: ${value}. Valid: auto, elevenlabs, kokoro.`
|
|
28935
|
+
`Invalid --tts: ${value}. Valid: auto, elevenlabs, openai, kokoro.`
|
|
28752
28936
|
);
|
|
28753
28937
|
}
|
|
28754
28938
|
var TtsKeyMissingError;
|
|
@@ -28760,7 +28944,7 @@ var init_tts_resolve = __esm({
|
|
|
28760
28944
|
TtsKeyMissingError = class extends Error {
|
|
28761
28945
|
constructor(provider) {
|
|
28762
28946
|
super(
|
|
28763
|
-
provider === "elevenlabs" ? "ElevenLabs API key required (ELEVENLABS_API_KEY). Run 'vibe setup', set ELEVENLABS_API_KEY in .env, or pass --tts kokoro for local synthesis." : `Provider ${provider} is unavailable.`
|
|
28947
|
+
provider === "elevenlabs" ? "ElevenLabs API key required (ELEVENLABS_API_KEY). Run 'vibe setup', set ELEVENLABS_API_KEY in .env, or pass --tts kokoro for local synthesis." : provider === "openai" ? "OpenAI API key required (OPENAI_API_KEY). Run 'vibe setup', set OPENAI_API_KEY in .env, or pass --tts kokoro for local synthesis." : `Provider ${provider} is unavailable.`
|
|
28764
28948
|
);
|
|
28765
28949
|
this.provider = provider;
|
|
28766
28950
|
this.name = "TtsKeyMissingError";
|
|
@@ -32801,13 +32985,13 @@ async function createBuildPlan(opts) {
|
|
|
32801
32985
|
const backdropCue = backdropPrompt ?? backdropReference?.raw;
|
|
32802
32986
|
const videoCue = videoPrompt ?? videoReference?.raw;
|
|
32803
32987
|
const musicCue = musicPrompt ?? musicReference?.raw;
|
|
32804
|
-
const narrationCost = resolved.narration.resolved === "elevenlabs" ? ELEVENLABS_NARRATION_COST_USD : 0;
|
|
32988
|
+
const narrationCost = resolved.narration.resolved === "elevenlabs" ? ELEVENLABS_NARRATION_COST_USD : resolved.narration.resolved === "openai" ? OPENAI_NARRATION_COST_USD : 0;
|
|
32805
32989
|
const narrationCache = narrationText && !narrationReference ? narrationCacheDescriptor({
|
|
32806
32990
|
beatId: beat.id,
|
|
32807
32991
|
cue: narrationText,
|
|
32808
32992
|
provider: resolved.narration.resolved,
|
|
32809
32993
|
voice,
|
|
32810
|
-
ext: resolved.narration.resolved === "
|
|
32994
|
+
ext: resolved.narration.resolved === "kokoro" ? "wav" : "mp3"
|
|
32811
32995
|
}) : null;
|
|
32812
32996
|
const backdropCache = augmentedBackdropPrompt && !backdropReference ? backdropCacheDescriptor({
|
|
32813
32997
|
beatId: beat.id,
|
|
@@ -33225,17 +33409,20 @@ function providerInput(opts) {
|
|
|
33225
33409
|
async function resolveNarrationProvider(input, projectDir) {
|
|
33226
33410
|
const requested = input.value.toLowerCase();
|
|
33227
33411
|
const hasElevenLabs = Boolean(await getApiKeyFromConfig("elevenlabs", { cwd: projectDir }));
|
|
33228
|
-
const
|
|
33412
|
+
const hasOpenAi = Boolean(await getApiKeyFromConfig("openai", { cwd: projectDir }));
|
|
33413
|
+
const resolved = requested === "elevenlabs" ? "elevenlabs" : requested === "openai" ? "openai" : requested === "kokoro" ? "kokoro" : hasElevenLabs ? "elevenlabs" : hasOpenAi ? "openai" : "kokoro";
|
|
33414
|
+
const requiresKey = resolved !== "kokoro";
|
|
33415
|
+
const hasKey = resolved === "elevenlabs" ? hasElevenLabs : resolved === "openai" ? hasOpenAi : true;
|
|
33229
33416
|
return {
|
|
33230
33417
|
kind: "narration",
|
|
33231
33418
|
requested: input.requested,
|
|
33232
33419
|
resolved,
|
|
33233
33420
|
source: input.source,
|
|
33234
|
-
requiresKey
|
|
33235
|
-
configured:
|
|
33236
|
-
...
|
|
33237
|
-
...
|
|
33238
|
-
retryWith:
|
|
33421
|
+
requiresKey,
|
|
33422
|
+
configured: hasKey,
|
|
33423
|
+
...requiresKey ? { configKey: resolved } : {},
|
|
33424
|
+
...requiresKey && !hasKey ? { missingKey: providerEnvVar(resolved) } : {},
|
|
33425
|
+
retryWith: requiresKey && !hasKey ? ["vibe setup --full"] : []
|
|
33239
33426
|
};
|
|
33240
33427
|
}
|
|
33241
33428
|
async function keyedProviderResolution(opts, projectDir) {
|
|
@@ -33331,7 +33518,7 @@ function loadPlanEnv(projectDir) {
|
|
|
33331
33518
|
dir = dirname9(dir);
|
|
33332
33519
|
}
|
|
33333
33520
|
}
|
|
33334
|
-
var import_dotenv2, VIDEO_COST_USD, MUSIC_COST_USD, ELEVENLABS_NARRATION_COST_USD, COMPOSE_COST_USD, SUPPORTED_BUILD_IMAGE_PROVIDERS;
|
|
33521
|
+
var import_dotenv2, VIDEO_COST_USD, MUSIC_COST_USD, ELEVENLABS_NARRATION_COST_USD, OPENAI_NARRATION_COST_USD, COMPOSE_COST_USD, SUPPORTED_BUILD_IMAGE_PROVIDERS;
|
|
33335
33522
|
var init_build_plan = __esm({
|
|
33336
33523
|
"src/commands/_shared/build-plan.ts"() {
|
|
33337
33524
|
"use strict";
|
|
@@ -33349,6 +33536,7 @@ var init_build_plan = __esm({
|
|
|
33349
33536
|
VIDEO_COST_USD = 5;
|
|
33350
33537
|
MUSIC_COST_USD = 0.5;
|
|
33351
33538
|
ELEVENLABS_NARRATION_COST_USD = 0.05;
|
|
33539
|
+
OPENAI_NARRATION_COST_USD = 0.01;
|
|
33352
33540
|
COMPOSE_COST_USD = 0.06;
|
|
33353
33541
|
SUPPORTED_BUILD_IMAGE_PROVIDERS = ["openai", "gemini", "grok"];
|
|
33354
33542
|
}
|
|
@@ -51379,7 +51567,7 @@ function pickOutputPath(data) {
|
|
|
51379
51567
|
}
|
|
51380
51568
|
|
|
51381
51569
|
// src/tools/_shared/elicit.ts
|
|
51382
|
-
var NARRATION_CHOICES = ["kokoro", "elevenlabs"];
|
|
51570
|
+
var NARRATION_CHOICES = ["kokoro", "openai", "elevenlabs"];
|
|
51383
51571
|
var BACKDROP_CHOICES = ["skip", "openai"];
|
|
51384
51572
|
function planBuildElicitation(args) {
|
|
51385
51573
|
const assetsWillRun = args.stage === void 0 || args.stage === "all" || args.stage === "assets";
|
|
@@ -51394,8 +51582,9 @@ function planBuildElicitation(args) {
|
|
|
51394
51582
|
description: "Which TTS engine narrates the video?",
|
|
51395
51583
|
enum: [...NARRATION_CHOICES],
|
|
51396
51584
|
enumNames: [
|
|
51397
|
-
"Kokoro \u2014 free, runs
|
|
51398
|
-
"
|
|
51585
|
+
"Kokoro \u2014 free, runs on this machine (first use downloads a ~90 MB voice model; slower)",
|
|
51586
|
+
"OpenAI \u2014 fast cloud voice, uses your OpenAI API key (~$0.02 per video)",
|
|
51587
|
+
"ElevenLabs \u2014 premium cloud voices, uses your ElevenLabs credits"
|
|
51399
51588
|
]
|
|
51400
51589
|
};
|
|
51401
51590
|
required.push("narration");
|
|
@@ -52600,9 +52789,9 @@ sceneCommand.command("add").description("Add a new scene to a project: AI narrat
|
|
|
52600
52789
|
"Image prompt \u2014 generates assets/scene-<id>.png via the configured image provider"
|
|
52601
52790
|
).option("--headline <text>", "Visible headline (defaults to the humanised scene name)").option("--kicker <text>", "Small label above the headline (explainer / product-shot)").option("--insert-into <path>", "Root composition file to update", "index.html").option("--project <dir>", "Project directory", ".").option("--image-provider <name>", "Image provider: gemini, openai", "gemini").option(
|
|
52602
52791
|
"--tts <provider>",
|
|
52603
|
-
"TTS provider: auto, elevenlabs, kokoro (default auto \u2014
|
|
52792
|
+
"TTS provider: auto, elevenlabs, openai, kokoro (default auto \u2014 ElevenLabs key > OpenAI key > Kokoro local)",
|
|
52604
52793
|
"auto"
|
|
52605
|
-
).option("--voice <id>", "Voice id (ElevenLabs name/id, or Kokoro id like af_heart
|
|
52794
|
+
).option("--voice <id>", "Voice id (ElevenLabs name/id, OpenAI voice like marin, or Kokoro id like af_heart)").option(
|
|
52606
52795
|
"--no-audio",
|
|
52607
52796
|
"Skip TTS even when --narration is provided (useful for tests/agent dry runs)"
|
|
52608
52797
|
).option("--no-image", "Skip image generation even when --visuals is provided").option(
|
|
@@ -52863,7 +53052,7 @@ async function executeSceneAdd(opts) {
|
|
|
52863
53052
|
throw error;
|
|
52864
53053
|
}
|
|
52865
53054
|
opts.onProgress?.(
|
|
52866
|
-
resolution.provider === "kokoro" ? "Generating narration with Kokoro (local \u2014 first run downloads ~
|
|
53055
|
+
resolution.provider === "kokoro" ? "Generating narration with Kokoro (local \u2014 first run downloads a ~90MB model)..." : resolution.provider === "openai" ? "Generating narration with OpenAI (gpt-4o-mini-tts)..." : "Generating narration with ElevenLabs..."
|
|
52867
53056
|
);
|
|
52868
53057
|
const tts = await resolution.call(narrationText, {
|
|
52869
53058
|
voice: opts.voice,
|
|
@@ -53623,7 +53812,9 @@ var sceneBuildSchema = external_exports.object({
|
|
|
53623
53812
|
skipVideo: external_exports.boolean().optional().describe("Skip video generation for every beat (use existing MP4 assets if present)."),
|
|
53624
53813
|
skipMusic: external_exports.boolean().optional().describe("Skip music generation for every beat (use existing audio assets if present)."),
|
|
53625
53814
|
skipRender: external_exports.boolean().optional().describe("Stop after compose \u2014 produces compositions/*.html but no final MP4."),
|
|
53626
|
-
ttsProvider: external_exports.enum(["auto", "elevenlabs", "kokoro"]).optional().describe(
|
|
53815
|
+
ttsProvider: external_exports.enum(["auto", "elevenlabs", "openai", "kokoro"]).optional().describe(
|
|
53816
|
+
"TTS provider override. Default 'auto' (elevenlabs key > openai key > local kokoro)."
|
|
53817
|
+
),
|
|
53627
53818
|
voice: external_exports.string().optional().describe("TTS voice id (provider-specific)."),
|
|
53628
53819
|
imageProvider: external_exports.enum(["openai"]).optional().describe("Image provider for backdrops. Default 'openai' (gpt-image-2)."),
|
|
53629
53820
|
videoProvider: external_exports.enum(["seedance", "grok", "kling", "runway", "veo"]).optional().describe("Video provider for per-beat video cues. Default seedance."),
|
|
@@ -57461,7 +57652,7 @@ var planTool = defineTool({
|
|
|
57461
57652
|
skipBackdrop: external_exports.boolean().optional().describe("Don't include backdrop image generation in the plan."),
|
|
57462
57653
|
skipVideo: external_exports.boolean().optional().describe("Don't include video generation in the plan."),
|
|
57463
57654
|
skipMusic: external_exports.boolean().optional().describe("Don't include music generation in the plan."),
|
|
57464
|
-
ttsProvider: external_exports.enum(["auto", "elevenlabs", "kokoro"]).optional().describe("TTS provider override."),
|
|
57655
|
+
ttsProvider: external_exports.enum(["auto", "elevenlabs", "openai", "kokoro"]).optional().describe("TTS provider override."),
|
|
57465
57656
|
voice: external_exports.string().optional().describe("Voice id."),
|
|
57466
57657
|
imageProvider: external_exports.string().optional().describe("Image provider override."),
|
|
57467
57658
|
imageQuality: external_exports.enum(["standard", "hd"]).optional().describe("Image quality override."),
|
|
@@ -145,7 +145,7 @@ export declare const sceneBuildTool: import("../define-tool.js").ToolDefinition<
|
|
|
145
145
|
skipVideo: z.ZodOptional<z.ZodBoolean>;
|
|
146
146
|
skipMusic: z.ZodOptional<z.ZodBoolean>;
|
|
147
147
|
skipRender: z.ZodOptional<z.ZodBoolean>;
|
|
148
|
-
ttsProvider: z.ZodOptional<z.ZodEnum<["auto", "elevenlabs", "kokoro"]>>;
|
|
148
|
+
ttsProvider: z.ZodOptional<z.ZodEnum<["auto", "elevenlabs", "openai", "kokoro"]>>;
|
|
149
149
|
voice: z.ZodOptional<z.ZodString>;
|
|
150
150
|
imageProvider: z.ZodOptional<z.ZodEnum<["openai"]>>;
|
|
151
151
|
videoProvider: z.ZodOptional<z.ZodEnum<["seedance", "grok", "kling", "runway", "veo"]>>;
|
|
@@ -167,7 +167,7 @@ export declare const sceneBuildTool: import("../define-tool.js").ToolDefinition<
|
|
|
167
167
|
skipBackdrop?: boolean | undefined;
|
|
168
168
|
skipRender?: boolean | undefined;
|
|
169
169
|
imageProvider?: "openai" | undefined;
|
|
170
|
-
ttsProvider?: "elevenlabs" | "auto" | "kokoro" | undefined;
|
|
170
|
+
ttsProvider?: "openai" | "elevenlabs" | "auto" | "kokoro" | undefined;
|
|
171
171
|
skipVideo?: boolean | undefined;
|
|
172
172
|
skipMusic?: boolean | undefined;
|
|
173
173
|
videoProvider?: "grok" | "seedance" | "kling" | "runway" | "veo" | undefined;
|
|
@@ -188,7 +188,7 @@ export declare const sceneBuildTool: import("../define-tool.js").ToolDefinition<
|
|
|
188
188
|
skipBackdrop?: boolean | undefined;
|
|
189
189
|
skipRender?: boolean | undefined;
|
|
190
190
|
imageProvider?: "openai" | undefined;
|
|
191
|
-
ttsProvider?: "elevenlabs" | "auto" | "kokoro" | undefined;
|
|
191
|
+
ttsProvider?: "openai" | "elevenlabs" | "auto" | "kokoro" | undefined;
|
|
192
192
|
skipVideo?: boolean | undefined;
|
|
193
193
|
skipMusic?: boolean | undefined;
|
|
194
194
|
videoProvider?: "grok" | "seedance" | "kling" | "runway" | "veo" | undefined;
|
|
@@ -87,7 +87,7 @@ export declare const planTool: import("../define-tool.js").ToolDefinition<z.ZodO
|
|
|
87
87
|
skipBackdrop: z.ZodOptional<z.ZodBoolean>;
|
|
88
88
|
skipVideo: z.ZodOptional<z.ZodBoolean>;
|
|
89
89
|
skipMusic: z.ZodOptional<z.ZodBoolean>;
|
|
90
|
-
ttsProvider: z.ZodOptional<z.ZodEnum<["auto", "elevenlabs", "kokoro"]>>;
|
|
90
|
+
ttsProvider: z.ZodOptional<z.ZodEnum<["auto", "elevenlabs", "openai", "kokoro"]>>;
|
|
91
91
|
voice: z.ZodOptional<z.ZodString>;
|
|
92
92
|
imageProvider: z.ZodOptional<z.ZodString>;
|
|
93
93
|
imageQuality: z.ZodOptional<z.ZodEnum<["standard", "hd"]>>;
|
|
@@ -107,7 +107,7 @@ export declare const planTool: import("../define-tool.js").ToolDefinition<z.ZodO
|
|
|
107
107
|
skipNarration?: boolean | undefined;
|
|
108
108
|
skipBackdrop?: boolean | undefined;
|
|
109
109
|
imageProvider?: string | undefined;
|
|
110
|
-
ttsProvider?: "elevenlabs" | "auto" | "kokoro" | undefined;
|
|
110
|
+
ttsProvider?: "openai" | "elevenlabs" | "auto" | "kokoro" | undefined;
|
|
111
111
|
skipVideo?: boolean | undefined;
|
|
112
112
|
skipMusic?: boolean | undefined;
|
|
113
113
|
videoProvider?: "grok" | "seedance" | "kling" | "runway" | "veo" | undefined;
|
|
@@ -125,7 +125,7 @@ export declare const planTool: import("../define-tool.js").ToolDefinition<z.ZodO
|
|
|
125
125
|
skipNarration?: boolean | undefined;
|
|
126
126
|
skipBackdrop?: boolean | undefined;
|
|
127
127
|
imageProvider?: string | undefined;
|
|
128
|
-
ttsProvider?: "elevenlabs" | "auto" | "kokoro" | undefined;
|
|
128
|
+
ttsProvider?: "openai" | "elevenlabs" | "auto" | "kokoro" | undefined;
|
|
129
129
|
skipVideo?: boolean | undefined;
|
|
130
130
|
skipMusic?: boolean | undefined;
|
|
131
131
|
videoProvider?: "grok" | "seedance" | "kling" | "runway" | "veo" | undefined;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vibeframe/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.113.0",
|
|
4
4
|
"description": "VibeFrame CLI - agentic video workflow runtime",
|
|
5
5
|
"private": false,
|
|
6
6
|
"license": "MIT",
|
|
@@ -83,8 +83,8 @@
|
|
|
83
83
|
"tsx": "^4.21.0",
|
|
84
84
|
"typescript": "^5.3.3",
|
|
85
85
|
"vitest": "^1.2.2",
|
|
86
|
-
"@vibeframe/ai-providers": "0.
|
|
87
|
-
"@vibeframe/core": "0.
|
|
86
|
+
"@vibeframe/ai-providers": "0.113.0",
|
|
87
|
+
"@vibeframe/core": "0.113.0"
|
|
88
88
|
},
|
|
89
89
|
"engines": {
|
|
90
90
|
"node": ">=20"
|