storyforge 0.11.5 → 0.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
probeDuration,
|
|
6
6
|
renderPlaceholderShot,
|
|
7
7
|
runCmd
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-EA4U7ASE.js";
|
|
9
9
|
import {
|
|
10
10
|
log
|
|
11
11
|
} from "./chunk-GJQ45C5W.js";
|
|
@@ -7014,39 +7014,62 @@ var renderManimRunPod = async (shot, ctx) => {
|
|
|
7014
7014
|
return localAdapter(shot, ctx);
|
|
7015
7015
|
}
|
|
7016
7016
|
ctx.progress.emit({ phase: "preparing", shotId: shot.id });
|
|
7017
|
-
const
|
|
7018
|
-
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
|
|
7022
|
-
|
|
7023
|
-
|
|
7024
|
-
input_data:
|
|
7025
|
-
|
|
7026
|
-
|
|
7027
|
-
|
|
7028
|
-
|
|
7029
|
-
|
|
7030
|
-
|
|
7017
|
+
const localFallback = ctx.resolvedEngine === "manim+remotion" ? renderManimRemotion : ctx.resolvedEngine === "gemini+manim+remotion" ? renderGeminiManimRemotion : renderManim;
|
|
7018
|
+
let status;
|
|
7019
|
+
try {
|
|
7020
|
+
status = await runJob(
|
|
7021
|
+
endpointId,
|
|
7022
|
+
{
|
|
7023
|
+
// Flash unpacks `input` via **kwargs into the handler. Our handler
|
|
7024
|
+
// signature is `async def render_manim_scene(input_data: dict)`, so
|
|
7025
|
+
// the payload must be nested under `input_data`.
|
|
7026
|
+
input: {
|
|
7027
|
+
input_data: {
|
|
7028
|
+
python_source: shot.manimCode,
|
|
7029
|
+
scene_class: "GeneratedScene",
|
|
7030
|
+
fps: ctx.fps,
|
|
7031
|
+
quality: "high"
|
|
7032
|
+
// manim --quality h => 1080p60; we'll downsample at concat
|
|
7033
|
+
}
|
|
7034
|
+
},
|
|
7035
|
+
executionTimeout: 600
|
|
7031
7036
|
},
|
|
7032
|
-
|
|
7033
|
-
|
|
7034
|
-
|
|
7035
|
-
|
|
7036
|
-
|
|
7037
|
-
|
|
7038
|
-
|
|
7039
|
-
|
|
7040
|
-
|
|
7041
|
-
|
|
7042
|
-
|
|
7043
|
-
|
|
7044
|
-
});
|
|
7037
|
+
{
|
|
7038
|
+
timeoutMs: 12 * 6e4,
|
|
7039
|
+
pollIntervalMs: 3e3,
|
|
7040
|
+
signal: ctx.signal,
|
|
7041
|
+
onPoll: (s) => {
|
|
7042
|
+
const phase = s.status === "IN_QUEUE" ? "preparing" : "rendering";
|
|
7043
|
+
ctx.progress.emit({
|
|
7044
|
+
phase,
|
|
7045
|
+
shotId: shot.id,
|
|
7046
|
+
warnings: s.delayTime ? [`runpod queue: ${(s.delayTime / 1e3).toFixed(1)}s`] : void 0
|
|
7047
|
+
});
|
|
7048
|
+
}
|
|
7045
7049
|
}
|
|
7046
|
-
|
|
7047
|
-
)
|
|
7050
|
+
);
|
|
7051
|
+
} catch (err) {
|
|
7052
|
+
const reason = err.message.slice(0, 200);
|
|
7053
|
+
ctx.progress.emit({
|
|
7054
|
+
phase: "preparing",
|
|
7055
|
+
shotId: shot.id,
|
|
7056
|
+
warnings: [`runpod-manim runtime failure \u2192 falling back to local manim: ${reason}`]
|
|
7057
|
+
});
|
|
7058
|
+
return localFallback(shot, ctx);
|
|
7059
|
+
}
|
|
7048
7060
|
ctx.progress.emit({ phase: "compositing", shotId: shot.id, percent: 90 });
|
|
7049
|
-
|
|
7061
|
+
let buf;
|
|
7062
|
+
try {
|
|
7063
|
+
buf = decodeBase64Mp4(status.output);
|
|
7064
|
+
} catch (err) {
|
|
7065
|
+
const reason = err.message.slice(0, 200);
|
|
7066
|
+
ctx.progress.emit({
|
|
7067
|
+
phase: "preparing",
|
|
7068
|
+
shotId: shot.id,
|
|
7069
|
+
warnings: [`runpod-manim decode failure \u2192 falling back to local manim: ${reason}`]
|
|
7070
|
+
});
|
|
7071
|
+
return localFallback(shot, ctx);
|
|
7072
|
+
}
|
|
7050
7073
|
fs13.writeFileSync(ctx.sceneOutPath, buf);
|
|
7051
7074
|
if (status.executionTime) {
|
|
7052
7075
|
const cost = status.executionTime / 1e3 * 19e-5;
|
|
@@ -8117,7 +8140,7 @@ var BridgePoller = class {
|
|
|
8117
8140
|
async invokeStitchFinal(jobId, payload) {
|
|
8118
8141
|
let stitchFinalVideo;
|
|
8119
8142
|
try {
|
|
8120
|
-
const mod = await import("./stitch-
|
|
8143
|
+
const mod = await import("./stitch-Y35UHIBV.js");
|
|
8121
8144
|
stitchFinalVideo = mod.stitchFinalVideo;
|
|
8122
8145
|
} catch (err) {
|
|
8123
8146
|
return {
|
|
@@ -90,8 +90,26 @@ function buildConcatArgs(manifestPath, outPath) {
|
|
|
90
90
|
"0",
|
|
91
91
|
"-i",
|
|
92
92
|
manifestPath,
|
|
93
|
-
"-c",
|
|
94
|
-
"
|
|
93
|
+
"-c:v",
|
|
94
|
+
"libx264",
|
|
95
|
+
"-preset",
|
|
96
|
+
"medium",
|
|
97
|
+
"-crf",
|
|
98
|
+
"18",
|
|
99
|
+
"-pix_fmt",
|
|
100
|
+
"yuv420p",
|
|
101
|
+
"-r",
|
|
102
|
+
"30",
|
|
103
|
+
"-vsync",
|
|
104
|
+
"cfr",
|
|
105
|
+
// Audio is optional in scene files; -c:a aac is safe even when
|
|
106
|
+
// some scenes are silent (lavfi placeholders) — ffmpeg synthesizes
|
|
107
|
+
// a silent audio track to match. If the scenes are all silent,
|
|
108
|
+
// the output also ends up silent and audio gets added by muxAudio.
|
|
109
|
+
"-c:a",
|
|
110
|
+
"aac",
|
|
111
|
+
"-b:a",
|
|
112
|
+
"192k",
|
|
95
113
|
outPath
|
|
96
114
|
];
|
|
97
115
|
}
|
package/dist/index.js
CHANGED
|
@@ -84,6 +84,52 @@ function loadDotEnv() {
|
|
|
84
84
|
}
|
|
85
85
|
return { loaded, sources };
|
|
86
86
|
}
|
|
87
|
+
async function fetchBridgeCredentials(opts) {
|
|
88
|
+
const fetchImpl = opts.fetchImpl ?? fetch;
|
|
89
|
+
const timeoutMs = opts.timeoutMs ?? 1e4;
|
|
90
|
+
const url = `${opts.apiUrl.replace(/\/$/, "")}/api/cli-bridge/credentials`;
|
|
91
|
+
const ctrl = new AbortController();
|
|
92
|
+
const timer = setTimeout(() => ctrl.abort(), timeoutMs);
|
|
93
|
+
let resp;
|
|
94
|
+
try {
|
|
95
|
+
resp = await fetchImpl(url, {
|
|
96
|
+
method: "GET",
|
|
97
|
+
headers: {
|
|
98
|
+
Authorization: `Bearer ${opts.token}`,
|
|
99
|
+
Accept: "application/json"
|
|
100
|
+
},
|
|
101
|
+
signal: ctrl.signal
|
|
102
|
+
});
|
|
103
|
+
} catch (err) {
|
|
104
|
+
return { loaded: [], source: url, error: err.message };
|
|
105
|
+
} finally {
|
|
106
|
+
clearTimeout(timer);
|
|
107
|
+
}
|
|
108
|
+
if (!resp.ok) {
|
|
109
|
+
const text = await resp.text().catch(() => "");
|
|
110
|
+
return { loaded: [], source: url, error: `HTTP ${resp.status}: ${text.slice(0, 200)}` };
|
|
111
|
+
}
|
|
112
|
+
let body;
|
|
113
|
+
try {
|
|
114
|
+
body = await resp.json();
|
|
115
|
+
} catch (err) {
|
|
116
|
+
return { loaded: [], source: url, error: `parse: ${err.message}` };
|
|
117
|
+
}
|
|
118
|
+
const creds = body.credentials ?? {};
|
|
119
|
+
const loaded = [];
|
|
120
|
+
for (const [key, val] of Object.entries(creds)) {
|
|
121
|
+
if (typeof val !== "string" || val.length === 0) continue;
|
|
122
|
+
if (process.env[key] != null) continue;
|
|
123
|
+
process.env[key] = val;
|
|
124
|
+
loaded.push(key);
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
loaded,
|
|
128
|
+
source: url,
|
|
129
|
+
knownCount: body.knownCount,
|
|
130
|
+
availableCount: body.availableCount
|
|
131
|
+
};
|
|
132
|
+
}
|
|
87
133
|
|
|
88
134
|
// src/utils/script-prompt.ts
|
|
89
135
|
var STYLE_GUIDES = {
|
|
@@ -855,6 +901,18 @@ async function devCommand(options) {
|
|
|
855
901
|
if (env.loaded.length > 0) {
|
|
856
902
|
log.info(`Loaded env: ${env.loaded.join(", ")} from ${env.sources.join(", ")}`);
|
|
857
903
|
}
|
|
904
|
+
const bridgeToken = process.env.FORGE_BRIDGE_TOKEN ?? process.env.BRIDGE_TOKEN ?? "";
|
|
905
|
+
if (bridgeToken) {
|
|
906
|
+
const apiUrl = process.env.FORGE_BRIDGE_URL ?? WEB_URL;
|
|
907
|
+
const credResult = await fetchBridgeCredentials({ apiUrl, token: bridgeToken });
|
|
908
|
+
if (credResult.error) {
|
|
909
|
+
log.info(`Bridge cred fetch skipped: ${credResult.error}`);
|
|
910
|
+
} else if (credResult.loaded.length > 0) {
|
|
911
|
+
log.info(`Loaded ${credResult.loaded.length} cloud creds from Vercel: ${credResult.loaded.join(", ")}`);
|
|
912
|
+
} else if (credResult.availableCount != null) {
|
|
913
|
+
log.info(`Bridge cred fetch: 0 new keys (server has ${credResult.availableCount}/${credResult.knownCount ?? "?"}, all already set locally)`);
|
|
914
|
+
}
|
|
915
|
+
}
|
|
858
916
|
void (async () => {
|
|
859
917
|
try {
|
|
860
918
|
const { gatherCliUsage, CLI_USAGE_PARSER_VERSION } = await import("./cli-usage-G762TREV.js");
|
|
@@ -1619,8 +1677,8 @@ Return ONLY the complete updated TSX. No markdown fences, no explanation.`;
|
|
|
1619
1677
|
console.log(` POST http://localhost:${port}/api/script-gen`);
|
|
1620
1678
|
}
|
|
1621
1679
|
const bridgeUrl = process.env.FORGE_BRIDGE_URL ?? WEB_URL;
|
|
1622
|
-
const
|
|
1623
|
-
if (
|
|
1680
|
+
const bridgeToken2 = process.env.FORGE_BRIDGE_TOKEN ?? process.env.BRIDGE_TOKEN ?? "";
|
|
1681
|
+
if (bridgeToken2) {
|
|
1624
1682
|
const pkgVersion = (() => {
|
|
1625
1683
|
try {
|
|
1626
1684
|
const here = path2.dirname(new URL(import.meta.url).pathname);
|
|
@@ -1631,8 +1689,8 @@ Return ONLY the complete updated TSX. No markdown fences, no explanation.`;
|
|
|
1631
1689
|
return "0.0.0";
|
|
1632
1690
|
})();
|
|
1633
1691
|
void (async () => {
|
|
1634
|
-
const { BridgePoller } = await import("./bridge-poller-
|
|
1635
|
-
const poller = new BridgePoller({ baseUrl: bridgeUrl, token:
|
|
1692
|
+
const { BridgePoller } = await import("./bridge-poller-APNLBMPW.js");
|
|
1693
|
+
const poller = new BridgePoller({ baseUrl: bridgeUrl, token: bridgeToken2, clientVersion: `storyforge ${pkgVersion}` });
|
|
1636
1694
|
poller.start();
|
|
1637
1695
|
})();
|
|
1638
1696
|
console.log("");
|
|
@@ -2454,7 +2512,7 @@ function resolveBridgeToken2(explicit) {
|
|
|
2454
2512
|
// package.json
|
|
2455
2513
|
var package_default = {
|
|
2456
2514
|
name: "storyforge",
|
|
2457
|
-
version: "0.
|
|
2515
|
+
version: "0.12.1",
|
|
2458
2516
|
description: "StoryForge \u2014 local bridge for the Forge video production web app. Parallel clip-render orchestrator (Remotion 4 + Manim + HyperFrames + ffmpeg) + final video stitcher + dependency doctor.",
|
|
2459
2517
|
type: "module",
|
|
2460
2518
|
bin: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "storyforge",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.1",
|
|
4
4
|
"description": "StoryForge — local bridge for the Forge video production web app. Parallel clip-render orchestrator (Remotion 4 + Manim + HyperFrames + ffmpeg) + final video stitcher + dependency doctor.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|