@skyphusion-labs/vivijure-core 0.9.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 (267) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +87 -0
  3. package/dist/audio-routing.d.ts +2 -0
  4. package/dist/audio-routing.d.ts.map +1 -0
  5. package/dist/audio-routing.js +4 -0
  6. package/dist/audio-routing.js.map +1 -0
  7. package/dist/audio-stage.d.ts +4 -0
  8. package/dist/audio-stage.d.ts.map +1 -0
  9. package/dist/audio-stage.js +25 -0
  10. package/dist/audio-stage.js.map +1 -0
  11. package/dist/beat-analyze.d.ts +22 -0
  12. package/dist/beat-analyze.d.ts.map +1 -0
  13. package/dist/beat-analyze.js +111 -0
  14. package/dist/beat-analyze.js.map +1 -0
  15. package/dist/beat-sync-types.d.ts +33 -0
  16. package/dist/beat-sync-types.d.ts.map +1 -0
  17. package/dist/beat-sync-types.js +4 -0
  18. package/dist/beat-sync-types.js.map +1 -0
  19. package/dist/bundle-assembler.d.ts +54 -0
  20. package/dist/bundle-assembler.d.ts.map +1 -0
  21. package/dist/bundle-assembler.js +376 -0
  22. package/dist/bundle-assembler.js.map +1 -0
  23. package/dist/bundle-durations.d.ts +5 -0
  24. package/dist/bundle-durations.d.ts.map +1 -0
  25. package/dist/bundle-durations.js +68 -0
  26. package/dist/bundle-durations.js.map +1 -0
  27. package/dist/bundle-storyboard.d.ts +11 -0
  28. package/dist/bundle-storyboard.d.ts.map +1 -0
  29. package/dist/bundle-storyboard.js +82 -0
  30. package/dist/bundle-storyboard.js.map +1 -0
  31. package/dist/captions.d.ts +25 -0
  32. package/dist/captions.d.ts.map +1 -0
  33. package/dist/captions.js +56 -0
  34. package/dist/captions.js.map +1 -0
  35. package/dist/cast-db.d.ts +61 -0
  36. package/dist/cast-db.d.ts.map +1 -0
  37. package/dist/cast-db.js +324 -0
  38. package/dist/cast-db.js.map +1 -0
  39. package/dist/cast-lora-train.d.ts +18 -0
  40. package/dist/cast-lora-train.d.ts.map +1 -0
  41. package/dist/cast-lora-train.js +215 -0
  42. package/dist/cast-lora-train.js.map +1 -0
  43. package/dist/cast-loras.d.ts +21 -0
  44. package/dist/cast-loras.d.ts.map +1 -0
  45. package/dist/cast-loras.js +69 -0
  46. package/dist/cast-loras.js.map +1 -0
  47. package/dist/clip-content-validate.d.ts +43 -0
  48. package/dist/clip-content-validate.d.ts.map +1 -0
  49. package/dist/clip-content-validate.js +115 -0
  50. package/dist/clip-content-validate.js.map +1 -0
  51. package/dist/clip-job-model.d.ts +42 -0
  52. package/dist/clip-job-model.d.ts.map +1 -0
  53. package/dist/clip-job-model.js +8 -0
  54. package/dist/clip-job-model.js.map +1 -0
  55. package/dist/clip-validate.d.ts +33 -0
  56. package/dist/clip-validate.d.ts.map +1 -0
  57. package/dist/clip-validate.js +247 -0
  58. package/dist/clip-validate.js.map +1 -0
  59. package/dist/d1-retry.d.ts +20 -0
  60. package/dist/d1-retry.d.ts.map +1 -0
  61. package/dist/d1-retry.js +67 -0
  62. package/dist/d1-retry.js.map +1 -0
  63. package/dist/db-env.d.ts +6 -0
  64. package/dist/db-env.d.ts.map +1 -0
  65. package/dist/db-env.js +2 -0
  66. package/dist/db-env.js.map +1 -0
  67. package/dist/dialogue-lines.d.ts +23 -0
  68. package/dist/dialogue-lines.d.ts.map +1 -0
  69. package/dist/dialogue-lines.js +84 -0
  70. package/dist/dialogue-lines.js.map +1 -0
  71. package/dist/film-advance-lease.d.ts +9 -0
  72. package/dist/film-advance-lease.d.ts.map +1 -0
  73. package/dist/film-advance-lease.js +19 -0
  74. package/dist/film-advance-lease.js.map +1 -0
  75. package/dist/film-model.d.ts +415 -0
  76. package/dist/film-model.d.ts.map +1 -0
  77. package/dist/film-model.js +541 -0
  78. package/dist/film-model.js.map +1 -0
  79. package/dist/film-orchestrator.d.ts +216 -0
  80. package/dist/film-orchestrator.d.ts.map +1 -0
  81. package/dist/film-orchestrator.js +2204 -0
  82. package/dist/film-orchestrator.js.map +1 -0
  83. package/dist/film-render-bridge.d.ts +26 -0
  84. package/dist/film-render-bridge.d.ts.map +1 -0
  85. package/dist/film-render-bridge.js +176 -0
  86. package/dist/film-render-bridge.js.map +1 -0
  87. package/dist/finish-hash.d.ts +10 -0
  88. package/dist/finish-hash.d.ts.map +1 -0
  89. package/dist/finish-hash.js +60 -0
  90. package/dist/finish-hash.js.map +1 -0
  91. package/dist/index.d.ts +48 -0
  92. package/dist/index.d.ts.map +1 -0
  93. package/dist/index.js +45 -0
  94. package/dist/index.js.map +1 -0
  95. package/dist/key-safety.d.ts +5 -0
  96. package/dist/key-safety.d.ts.map +1 -0
  97. package/dist/key-safety.js +23 -0
  98. package/dist/key-safety.js.map +1 -0
  99. package/dist/lora-bundle.d.ts +19 -0
  100. package/dist/lora-bundle.d.ts.map +1 -0
  101. package/dist/lora-bundle.js +75 -0
  102. package/dist/lora-bundle.js.map +1 -0
  103. package/dist/lora-keys.d.ts +2 -0
  104. package/dist/lora-keys.d.ts.map +1 -0
  105. package/dist/lora-keys.js +4 -0
  106. package/dist/lora-keys.js.map +1 -0
  107. package/dist/modules/conformance.d.ts +58 -0
  108. package/dist/modules/conformance.d.ts.map +1 -0
  109. package/dist/modules/conformance.js +369 -0
  110. package/dist/modules/conformance.js.map +1 -0
  111. package/dist/modules/manifest-validate.d.ts +5 -0
  112. package/dist/modules/manifest-validate.d.ts.map +1 -0
  113. package/dist/modules/manifest-validate.js +60 -0
  114. package/dist/modules/manifest-validate.js.map +1 -0
  115. package/dist/modules/registry.d.ts +184 -0
  116. package/dist/modules/registry.d.ts.map +1 -0
  117. package/dist/modules/registry.js +653 -0
  118. package/dist/modules/registry.js.map +1 -0
  119. package/dist/modules/render-pipeline.d.ts +38 -0
  120. package/dist/modules/render-pipeline.d.ts.map +1 -0
  121. package/dist/modules/render-pipeline.js +40 -0
  122. package/dist/modules/render-pipeline.js.map +1 -0
  123. package/dist/modules/types.d.ts +544 -0
  124. package/dist/modules/types.d.ts.map +1 -0
  125. package/dist/modules/types.js +57 -0
  126. package/dist/modules/types.js.map +1 -0
  127. package/dist/operator-config.d.ts +20 -0
  128. package/dist/operator-config.d.ts.map +1 -0
  129. package/dist/operator-config.js +85 -0
  130. package/dist/operator-config.js.map +1 -0
  131. package/dist/output-extract.d.ts +8 -0
  132. package/dist/output-extract.d.ts.map +1 -0
  133. package/dist/output-extract.js +129 -0
  134. package/dist/output-extract.js.map +1 -0
  135. package/dist/planner-prompt.d.ts +12 -0
  136. package/dist/planner-prompt.d.ts.map +1 -0
  137. package/dist/planner-prompt.js +337 -0
  138. package/dist/planner-prompt.js.map +1 -0
  139. package/dist/planner-yaml.d.ts +15 -0
  140. package/dist/planner-yaml.d.ts.map +1 -0
  141. package/dist/planner-yaml.js +157 -0
  142. package/dist/planner-yaml.js.map +1 -0
  143. package/dist/platform/fetcher.d.ts +3 -0
  144. package/dist/platform/fetcher.d.ts.map +1 -0
  145. package/dist/platform/fetcher.js +7 -0
  146. package/dist/platform/fetcher.js.map +1 -0
  147. package/dist/platform/index.d.ts +6 -0
  148. package/dist/platform/index.d.ts.map +1 -0
  149. package/dist/platform/index.js +5 -0
  150. package/dist/platform/index.js.map +1 -0
  151. package/dist/platform/object-store-r2.d.ts +26 -0
  152. package/dist/platform/object-store-r2.d.ts.map +1 -0
  153. package/dist/platform/object-store-r2.js +74 -0
  154. package/dist/platform/object-store-r2.js.map +1 -0
  155. package/dist/platform/orchestrator-context.d.ts +20 -0
  156. package/dist/platform/orchestrator-context.d.ts.map +1 -0
  157. package/dist/platform/orchestrator-context.js +28 -0
  158. package/dist/platform/orchestrator-context.js.map +1 -0
  159. package/dist/platform/r2-types.d.ts +41 -0
  160. package/dist/platform/r2-types.d.ts.map +1 -0
  161. package/dist/platform/r2-types.js +3 -0
  162. package/dist/platform/r2-types.js.map +1 -0
  163. package/dist/platform/types.d.ts +90 -0
  164. package/dist/platform/types.d.ts.map +1 -0
  165. package/dist/platform/types.js +23 -0
  166. package/dist/platform/types.js.map +1 -0
  167. package/dist/preflight.d.ts +57 -0
  168. package/dist/preflight.d.ts.map +1 -0
  169. package/dist/preflight.js +243 -0
  170. package/dist/preflight.js.map +1 -0
  171. package/dist/presign.d.ts +5 -0
  172. package/dist/presign.d.ts.map +1 -0
  173. package/dist/presign.js +24 -0
  174. package/dist/presign.js.map +1 -0
  175. package/dist/public-id.d.ts +8 -0
  176. package/dist/public-id.d.ts.map +1 -0
  177. package/dist/public-id.js +25 -0
  178. package/dist/public-id.js.map +1 -0
  179. package/dist/render-adopt.d.ts +3 -0
  180. package/dist/render-adopt.d.ts.map +1 -0
  181. package/dist/render-adopt.js +92 -0
  182. package/dist/render-adopt.js.map +1 -0
  183. package/dist/render-log.d.ts +25 -0
  184. package/dist/render-log.d.ts.map +1 -0
  185. package/dist/render-log.js +139 -0
  186. package/dist/render-log.js.map +1 -0
  187. package/dist/render-module-config.d.ts +28 -0
  188. package/dist/render-module-config.d.ts.map +1 -0
  189. package/dist/render-module-config.js +124 -0
  190. package/dist/render-module-config.js.map +1 -0
  191. package/dist/render-mux.d.ts +18 -0
  192. package/dist/render-mux.d.ts.map +1 -0
  193. package/dist/render-mux.js +69 -0
  194. package/dist/render-mux.js.map +1 -0
  195. package/dist/render-orchestrator.d.ts +71 -0
  196. package/dist/render-orchestrator.d.ts.map +1 -0
  197. package/dist/render-orchestrator.js +376 -0
  198. package/dist/render-orchestrator.js.map +1 -0
  199. package/dist/render-sweep.d.ts +5 -0
  200. package/dist/render-sweep.d.ts.map +1 -0
  201. package/dist/render-sweep.js +62 -0
  202. package/dist/render-sweep.js.map +1 -0
  203. package/dist/renders-db.d.ts +129 -0
  204. package/dist/renders-db.d.ts.map +1 -0
  205. package/dist/renders-db.js +752 -0
  206. package/dist/renders-db.js.map +1 -0
  207. package/dist/runpod-submit.d.ts +151 -0
  208. package/dist/runpod-submit.d.ts.map +1 -0
  209. package/dist/runpod-submit.js +469 -0
  210. package/dist/runpod-submit.js.map +1 -0
  211. package/dist/runpod-types.d.ts +2 -0
  212. package/dist/runpod-types.d.ts.map +1 -0
  213. package/dist/runpod-types.js +4 -0
  214. package/dist/runpod-types.js.map +1 -0
  215. package/dist/scatter-notify.d.ts +4 -0
  216. package/dist/scatter-notify.d.ts.map +1 -0
  217. package/dist/scatter-notify.js +43 -0
  218. package/dist/scatter-notify.js.map +1 -0
  219. package/dist/scatter-orchestrator-types.d.ts +56 -0
  220. package/dist/scatter-orchestrator-types.d.ts.map +1 -0
  221. package/dist/scatter-orchestrator-types.js +3 -0
  222. package/dist/scatter-orchestrator-types.js.map +1 -0
  223. package/dist/scatter-orchestrator.d.ts +70 -0
  224. package/dist/scatter-orchestrator.d.ts.map +1 -0
  225. package/dist/scatter-orchestrator.js +614 -0
  226. package/dist/scatter-orchestrator.js.map +1 -0
  227. package/dist/scatter.d.ts +35 -0
  228. package/dist/scatter.d.ts.map +1 -0
  229. package/dist/scatter.js +171 -0
  230. package/dist/scatter.js.map +1 -0
  231. package/dist/secret-store.d.ts +5 -0
  232. package/dist/secret-store.d.ts.map +1 -0
  233. package/dist/secret-store.js +19 -0
  234. package/dist/secret-store.js.map +1 -0
  235. package/dist/shot-durations-parse.d.ts +3 -0
  236. package/dist/shot-durations-parse.d.ts.map +1 -0
  237. package/dist/shot-durations-parse.js +43 -0
  238. package/dist/shot-durations-parse.js.map +1 -0
  239. package/dist/srt.d.ts +11 -0
  240. package/dist/srt.d.ts.map +1 -0
  241. package/dist/srt.js +54 -0
  242. package/dist/srt.js.map +1 -0
  243. package/dist/storyboard-ids.d.ts +2 -0
  244. package/dist/storyboard-ids.d.ts.map +1 -0
  245. package/dist/storyboard-ids.js +12 -0
  246. package/dist/storyboard-ids.js.map +1 -0
  247. package/dist/storyboard-projects-db.d.ts +31 -0
  248. package/dist/storyboard-projects-db.d.ts.map +1 -0
  249. package/dist/storyboard-projects-db.js +153 -0
  250. package/dist/storyboard-projects-db.js.map +1 -0
  251. package/dist/storyboard-validate.d.ts +72 -0
  252. package/dist/storyboard-validate.d.ts.map +1 -0
  253. package/dist/storyboard-validate.js +595 -0
  254. package/dist/storyboard-validate.js.map +1 -0
  255. package/dist/structured-events.d.ts +6 -0
  256. package/dist/structured-events.d.ts.map +1 -0
  257. package/dist/structured-events.js +15 -0
  258. package/dist/structured-events.js.map +1 -0
  259. package/dist/tar.d.ts +9 -0
  260. package/dist/tar.d.ts.map +1 -0
  261. package/dist/tar.js +151 -0
  262. package/dist/tar.js.map +1 -0
  263. package/dist/voices.d.ts +12 -0
  264. package/dist/voices.d.ts.map +1 -0
  265. package/dist/voices.js +37 -0
  266. package/dist/voices.js.map +1 -0
  267. package/package.json +71 -0
@@ -0,0 +1,376 @@
1
+ // Storyboard bundle assembler (v0.31.0).
2
+ //
3
+ // Takes a validated storyboard + per-slot character refs (either R2 keys
4
+ // or inline data URLs) and produces the .tar.gz the vivijure-serverless
5
+ // GPU worker pulls via r2_io.download_and_extract().
6
+ //
7
+ // Bundle layout (mirrors what characters.py and orchestrator.py expect):
8
+ //
9
+ // storyboard.yaml film board (serializeStoryboardYaml)
10
+ // characters/registry.json per-slot {name, prompt, image}
11
+ // characters/char_<SLOT>_<safe-name>.png canonical portrait
12
+ // (registry's `image` field points here;
13
+ // characters.slot_image_path convention)
14
+ // characters/refs/<SLOT>/ref_NN.<ext> training + IP-Adapter refs
15
+ // (characters.list_character_references
16
+ // globs this dir for the readiness
17
+ // check that lora_train fires on)
18
+ // start_image.png optional top-level film start;
19
+ // auto-bootstrapped by the GPU worker
20
+ // if absent
21
+ // clips/<id>_keyframe.png optional per-scene start frame
22
+ // (Phase 4b reverse bridge); the pod
23
+ // reads it as scene <id>'s i2v start
24
+ // image (core.py scene.start_image
25
+ // fallback)
26
+ //
27
+ // Returns the R2 key at bundles/<projectName>.tar.gz on success.
28
+ import { validateStoryboard, } from "./storyboard-validate.js";
29
+ import { serializeStoryboardYaml } from "./planner-yaml.js";
30
+ import { emitTar, readTar } from "./tar.js";
31
+ import { presignR2Get, presignR2Put } from "./presign.js";
32
+ import { gunzipBytes, gzipBytes } from "./bundle-durations.js";
33
+ export { gunzipBytes } from "./bundle-durations.js";
34
+ // Mirrors characters.slot_image_path's filename convention:
35
+ // safe = name.strip().replace(" ", "_")[:40] or slot
36
+ // "char_<SLOT>_<safe>.png"
37
+ // We use literal-space replacement (not \s+) so multi-space names match
38
+ // the Python str.replace(" ", "_") behavior byte-for-byte.
39
+ export function safeCharFilename(slot, name) {
40
+ const trimmed = name.trim();
41
+ const safe = trimmed.replace(/ /g, "_").slice(0, 40) || slot;
42
+ return `char_${slot}_${safe}.png`;
43
+ }
44
+ // Sniff the image format from the first few bytes so the inner filename
45
+ // inside the tarball gets the right extension. The GPU side's
46
+ // list_character_references globs *.png, *.jpg, *.jpeg, *.webp; falling
47
+ // back to .png on an unrecognized signature is safe (the file is still
48
+ // readable by PIL, which the GPU side uses).
49
+ export function detectImageExt(bytes) {
50
+ if (bytes.length >= 8 &&
51
+ bytes[0] === 0x89 && bytes[1] === 0x50 &&
52
+ bytes[2] === 0x4e && bytes[3] === 0x47) {
53
+ return "png";
54
+ }
55
+ if (bytes.length >= 3 && bytes[0] === 0xff && bytes[1] === 0xd8 && bytes[2] === 0xff) {
56
+ return "jpg";
57
+ }
58
+ if (bytes.length >= 12 &&
59
+ bytes[0] === 0x52 && bytes[1] === 0x49 && bytes[2] === 0x46 && bytes[3] === 0x46 &&
60
+ bytes[8] === 0x57 && bytes[9] === 0x45 && bytes[10] === 0x42 && bytes[11] === 0x50) {
61
+ return "webp";
62
+ }
63
+ return "png";
64
+ }
65
+ // Decode a "data:<mime>;base64,<...>" URL to raw bytes. Returns null if
66
+ // the URL is malformed or the base64 fails to decode.
67
+ export function decodeDataUrl(dataUrl) {
68
+ const m = dataUrl.match(/^data:([\w./+-]+);base64,(.+)$/);
69
+ if (!m)
70
+ return null;
71
+ try {
72
+ const bin = atob(m[2]);
73
+ const bytes = new Uint8Array(bin.length);
74
+ for (let i = 0; i < bin.length; i++)
75
+ bytes[i] = bin.charCodeAt(i);
76
+ return bytes;
77
+ }
78
+ catch {
79
+ return null;
80
+ }
81
+ }
82
+ async function resolveImage(env, img, label) {
83
+ if (img.dataUrl) {
84
+ const bytes = decodeDataUrl(img.dataUrl);
85
+ if (!bytes)
86
+ return { error: `${label}: invalid data URL` };
87
+ return { bytes, ext: detectImageExt(bytes) };
88
+ }
89
+ if (img.key) {
90
+ // v0.39.1: staged character refs live in R2_RENDERS (the bucket the
91
+ // GPU worker also reads + writes); this used to read env.R2 and miss
92
+ // refs uploaded via the new /api/storyboard/character-ref path.
93
+ const obj = await env.R2_RENDERS.get(img.key);
94
+ if (!obj)
95
+ return { error: `${label}: R2 object not found at key "${img.key}"` };
96
+ const bytes = new Uint8Array(await obj.arrayBuffer());
97
+ return { bytes, ext: detectImageExt(bytes) };
98
+ }
99
+ return { error: `${label}: must provide either { key } or { dataUrl }` };
100
+ }
101
+ // v0.153.0 (Phase 4 hybrid keyframe parity): build a NEW bundle = an existing
102
+ // bundle + per-scene start keyframes overlaid at clips/<id>_keyframe.png. The
103
+ // pod's finalize restores projects/<name>/state.tar.gz THEN extracts the bundle
104
+ // (rp_handler _restore_prior_state -> download_and_extract), so these entries
105
+ // overwrite the state-restored keyframes and i2v_only reuses these EXACT frames.
106
+ // Used by the hybrid GPU lane so it animates the parent row's keyframes (not
107
+ // whatever the project's last render left in the shared state.tar.gz). No
108
+ // storyboard/cast needed -- we read the source bundle and splice. Returns the
109
+ // new bundle key (in R2_RENDERS).
110
+ export async function overlayKeyframesIntoBundle(env, srcBundleKey, outBundleKey, keyframes) {
111
+ const src = await env.R2_RENDERS.get(srcBundleKey);
112
+ if (!src)
113
+ return { ok: false, error: `source bundle not found: ${srcBundleKey}` };
114
+ const tarBytes = await gunzipBytes(new Uint8Array(await src.arrayBuffer()));
115
+ // Index existing entries by name so an injected keyframe replaces any prior
116
+ // entry at the same path (and preserves the rest of the bundle verbatim).
117
+ const byName = new Map();
118
+ for (const e of readTar(tarBytes))
119
+ byName.set(e.name, e);
120
+ for (const kf of keyframes) {
121
+ if (!kf.shot_id || !kf.key)
122
+ continue;
123
+ const obj = await env.R2_RENDERS.get(kf.key);
124
+ if (!obj)
125
+ return { ok: false, error: `keyframe not found in R2: ${kf.key}` };
126
+ const name = `clips/${kf.shot_id}_keyframe.png`;
127
+ byName.set(name, { name, content: new Uint8Array(await obj.arrayBuffer()) });
128
+ }
129
+ const outGz = await gzipBytes(emitTar([...byName.values()]));
130
+ await env.R2_RENDERS.put(outBundleKey, outGz, {
131
+ httpMetadata: { contentType: "application/gzip" },
132
+ });
133
+ return { ok: true, bundleKey: outBundleKey };
134
+ }
135
+ // ---- image-prep container: background-remove a cast portrait ----
136
+ //
137
+ // Cast portraits go through the IMAGE_PREP Cloudflare Container (rembg) before
138
+ // landing in the bundle, so the renderer gets a clean alpha PNG instead of a
139
+ // backgrounded one. The cleaned result is content-addressed in R2
140
+ // (cast-clean/<sha256>.png) so repeat bundles of the same portrait reuse it.
141
+ // The container has no R2 binding: we presign a GET (source) + PUT (dest) and
142
+ // it streams both, then we read the cleaned bytes back to write into the tar.
143
+ async function sha256HexBytes(bytes) {
144
+ const ab = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength);
145
+ const digest = await crypto.subtle.digest("SHA-256", ab);
146
+ const b = new Uint8Array(digest);
147
+ let s = "";
148
+ for (let i = 0; i < b.length; i++)
149
+ s += b[i].toString(16).padStart(2, "0");
150
+ return s;
151
+ }
152
+ // #759: content-addressed bundle key. Two renders that share a project title used to derive the
153
+ // SAME `bundles/<projectName>.tar.gz` key and overwrite each other's tarball mid-render.
154
+ export async function bundleKeyFor(projectName, tarBytes) {
155
+ const contentHash = (await sha256HexBytes(tarBytes)).slice(0, 16);
156
+ return `bundles/${projectName}-${contentHash}.tar.gz`;
157
+ }
158
+ // Call the image-prep container with a cold-start guard.
159
+ // rides out the port-bind window, and we retry the heavier /portrait/prep on a
160
+ // 503 (a fully-cold container can 503 when a heavy request races its bind, as
161
+ // seen in live testing). backoffMs is injectable so tests don't actually wait.
162
+ // Returns the container Response, or null on a network error.
163
+ export async function callImagePrep(env, payload, opts = {}) {
164
+ const retries = opts.retries ?? 3;
165
+ const backoffMs = opts.backoffMs ?? 1500;
166
+ const init = {
167
+ method: "POST",
168
+ headers: { "content-type": "application/json" },
169
+ body: JSON.stringify(payload),
170
+ };
171
+ // image-prep runs always-on on the fleet, reached over a Workers VPC binding
172
+ // (private, no cold start) -- so the old Container-DO singleton + warm-/health
173
+ // dance is gone (issue #83). The 503 retry stays as cheap transport insurance.
174
+ let resp = null;
175
+ for (let attempt = 0; attempt < retries; attempt++) {
176
+ try {
177
+ resp = await env.IMAGE_PREP_VPC.fetch("http://image-prep/portrait/prep", init);
178
+ }
179
+ catch {
180
+ resp = null;
181
+ }
182
+ if (resp && resp.status !== 503)
183
+ return resp;
184
+ if (attempt < retries - 1) {
185
+ await new Promise((r) => setTimeout(r, backoffMs)); // container still binding
186
+ }
187
+ }
188
+ return resp;
189
+ }
190
+ // Background-remove one portrait. Returns cleaned RGBA PNG bytes, or null if the
191
+ // container path fails (the caller falls back to the original bytes rather than
192
+ // failing the whole bundle; today the pod still rembg's portraits, so an
193
+ // un-cleaned portrait degrades gracefully).
194
+ async function prepPortraitBytes(env, bytes, sourceKey) {
195
+ try {
196
+ const hash = await sha256HexBytes(bytes);
197
+ const cleanKey = `cast-clean/${hash}.png`;
198
+ const cached = await env.R2_RENDERS.get(cleanKey);
199
+ if (cached)
200
+ return new Uint8Array(await cached.arrayBuffer());
201
+ // The container fetches the source over HTTP, so it must be an R2 object.
202
+ // Reuse the portrait's own R2 key when it has one; otherwise stage the bytes
203
+ // (a portrait supplied as an inline data URL has no key to presign).
204
+ let srcKey = sourceKey;
205
+ if (!srcKey) {
206
+ srcKey = `cast-clean/src/${hash}.png`;
207
+ await env.R2_RENDERS.put(srcKey, bytes, { httpMetadata: { contentType: "image/png" } });
208
+ }
209
+ const inputUrl = await presignR2Get(env, srcKey, 300);
210
+ const outputUrl = await presignR2Put(env, cleanKey, 300);
211
+ const resp = await callImagePrep(env, {
212
+ inputUrl,
213
+ outputUrl,
214
+ outputKey: cleanKey,
215
+ background: "alpha",
216
+ });
217
+ if (!resp || !resp.ok) {
218
+ console.warn(`image-prep failed (status ${resp ? resp.status : "network"}) for ${cleanKey}; using original portrait`);
219
+ return null;
220
+ }
221
+ const out = await env.R2_RENDERS.get(cleanKey);
222
+ if (!out) {
223
+ console.warn(`image-prep reported ok but ${cleanKey} missing in R2; using original portrait`);
224
+ return null;
225
+ }
226
+ return new Uint8Array(await out.arrayBuffer());
227
+ }
228
+ catch (err) {
229
+ console.warn(`image-prep threw (${err instanceof Error ? err.message : String(err)}); using original portrait`);
230
+ return null;
231
+ }
232
+ }
233
+ export async function assembleBundle(env, args) {
234
+ // Defensive re-validation. The caller may have skipped validateStoryboard
235
+ // or the storyboard could have been edited between plan and bundle. We
236
+ // accept the cost of re-running because validation is cheap and lets the
237
+ // assembler refuse a board that would crash the GPU worker mid-render.
238
+ const validation = validateStoryboard(args.storyboard);
239
+ if (!validation.ok) {
240
+ return { ok: false, errors: validation.errors.map((e) => `storyboard: ${e}`) };
241
+ }
242
+ const storyboard = validation.value;
243
+ const errors = [];
244
+ const files = [];
245
+ // storyboard.yaml at top level.
246
+ files.push({
247
+ name: "storyboard.yaml",
248
+ content: new TextEncoder().encode(serializeStoryboardYaml(storyboard)),
249
+ });
250
+ // Per-slot files + registry entries. Walk use_characters in the storyboard
251
+ // (not Object.keys(characterRefs)) so a stray extra slot in characterRefs
252
+ // does not end up in the registry, and a missing slot in characterRefs
253
+ // surfaces as an error here rather than silently shipping an unloaded
254
+ // slot to the GPU worker.
255
+ const registryCharacters = {};
256
+ for (const slot of storyboard.use_characters) {
257
+ const ref = args.characterRefs[slot];
258
+ if (!ref) {
259
+ errors.push(`characterRefs missing entry for slot "${slot}" (referenced in storyboard.use_characters)`);
260
+ continue;
261
+ }
262
+ if (!ref.name || ref.name.trim().length === 0) {
263
+ errors.push(`characterRefs[${slot}].name is required (non-empty string)`);
264
+ continue;
265
+ }
266
+ if (!Array.isArray(ref.trainingImages) || ref.trainingImages.length === 0) {
267
+ errors.push(`characterRefs[${slot}].trainingImages is required (non-empty array)`);
268
+ continue;
269
+ }
270
+ // Portrait: defaults to trainingImages[0] when omitted, matching how
271
+ // a fresh project bootstrap on the GPU side picks the first ref.
272
+ const portraitSrc = ref.portrait ?? ref.trainingImages[0];
273
+ const portraitResolved = await resolveImage(env, portraitSrc, `characterRefs[${slot}].portrait`);
274
+ if ("error" in portraitResolved) {
275
+ errors.push(portraitResolved.error);
276
+ continue;
277
+ }
278
+ // Background-remove the portrait via the image-prep container before it
279
+ // goes into the bundle. Best-effort: on container failure we fall back to
280
+ // the original bytes rather than fail the whole bundle.
281
+ const cleanedPortrait = await prepPortraitBytes(env, portraitResolved.bytes, portraitSrc.key);
282
+ const portraitFilename = safeCharFilename(slot, ref.name);
283
+ files.push({
284
+ name: `characters/${portraitFilename}`,
285
+ content: cleanedPortrait ?? portraitResolved.bytes,
286
+ });
287
+ // Training refs at characters/refs/<SLOT>/ref_NN.<ext>. Each image's
288
+ // ext is sniffed independently so a mixed PNG/JPEG set comes through
289
+ // intact. The order matches the input order (the GPU side's sorted glob
290
+ // re-orders alphabetically anyway, so ref_01 ... ref_NN is stable).
291
+ for (let i = 0; i < ref.trainingImages.length; i++) {
292
+ const img = ref.trainingImages[i];
293
+ const resolved = await resolveImage(env, img, `characterRefs[${slot}].trainingImages[${i}]`);
294
+ if ("error" in resolved) {
295
+ errors.push(resolved.error);
296
+ continue;
297
+ }
298
+ const num = String(i + 1).padStart(2, "0");
299
+ const innerName = img.filename ?? `ref_${num}.${resolved.ext}`;
300
+ files.push({
301
+ name: `characters/refs/${slot}/${innerName}`,
302
+ content: resolved.bytes,
303
+ });
304
+ }
305
+ registryCharacters[slot] = {
306
+ name: ref.name,
307
+ prompt: ref.prompt ?? "",
308
+ image: `characters/${portraitFilename}`,
309
+ };
310
+ }
311
+ if (errors.length > 0) {
312
+ return { ok: false, errors };
313
+ }
314
+ // characters/registry.json. Pretty-printed for human introspection
315
+ // when debugging a bundle; the GPU side's json.load doesn't care.
316
+ files.push({
317
+ name: "characters/registry.json",
318
+ content: new TextEncoder().encode(JSON.stringify({ characters: registryCharacters }, null, 2) + "\n"),
319
+ });
320
+ // Optional top-level start_image.png.
321
+ if (args.startImage) {
322
+ const startResolved = await resolveImage(env, args.startImage, "startImage");
323
+ if ("error" in startResolved) {
324
+ return { ok: false, errors: [startResolved.error] };
325
+ }
326
+ files.push({
327
+ name: "start_image.png",
328
+ content: startResolved.bytes,
329
+ });
330
+ }
331
+ // v0.148.0 (Phase 4b, the reverse bridge): per-scene start images at
332
+ // clips/<id>_keyframe.png. The pod (vivijure-src/core.py) reads each scene's
333
+ // start frame from scene.start_image, falling back to this path, so an
334
+ // externally-authored keyframe here drives that scene's Wan i2v motion with no
335
+ // pod change. Bytes are written raw (no background removal; these are full
336
+ // frames, not portraits); the pod loads by content, not extension. Keys are
337
+ // validated against the storyboard's scene ids so a typo cannot silently ship
338
+ // a keyframe no scene will ever read.
339
+ if (args.sceneStartImages) {
340
+ const sceneIds = new Set(storyboard.scenes.map((s, i) => s.id || `shot_${String(i + 1).padStart(2, "0")}`));
341
+ for (const [sceneId, img] of Object.entries(args.sceneStartImages)) {
342
+ if (!sceneIds.has(sceneId)) {
343
+ return {
344
+ ok: false,
345
+ errors: [`sceneStartImages: "${sceneId}" is not a scene id in the storyboard`],
346
+ };
347
+ }
348
+ const resolved = await resolveImage(env, img, `sceneStartImages["${sceneId}"]`);
349
+ if ("error" in resolved) {
350
+ return { ok: false, errors: [resolved.error] };
351
+ }
352
+ files.push({
353
+ name: `clips/${sceneId}_keyframe.png`,
354
+ content: resolved.bytes,
355
+ });
356
+ }
357
+ }
358
+ // Emit tar, gzip, upload.
359
+ const tarBytes = emitTar(files);
360
+ const gz = await gzipBytes(tarBytes);
361
+ const bundleKey = await bundleKeyFor(storyboard.projectName, tarBytes);
362
+ // v0.39.1: bundles land in R2_RENDERS so the GPU worker (which reads
363
+ // from its own R2_BUCKET) sees them. Pre-0.39.1 wrote to env.R2 and
364
+ // the GPU could only pull bundles after a manual copy between buckets.
365
+ await env.R2_RENDERS.put(bundleKey, gz, {
366
+ httpMetadata: { contentType: "application/gzip" },
367
+ customMetadata: { source: "skyphusion-planner" },
368
+ });
369
+ return {
370
+ ok: true,
371
+ bundleKey,
372
+ sizeBytes: gz.length,
373
+ fileCount: files.length,
374
+ };
375
+ }
376
+ //# sourceMappingURL=bundle-assembler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundle-assembler.js","sourceRoot":"","sources":["../src/bundle-assembler.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ import type { OrchestratorEnv } from "./platform/orchestrator-context.js";
2
+ export declare function gzipBytes(bytes: Uint8Array): Promise<Uint8Array>;
3
+ export declare function gunzipBytes(bytes: Uint8Array): Promise<Uint8Array>;
4
+ export declare function readShotDurationsFromBundle(env: OrchestratorEnv, bundleKey: string): Promise<Record<string, number>>;
5
+ //# sourceMappingURL=bundle-durations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundle-durations.d.ts","sourceRoot":"","sources":["../src/bundle-durations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,oCAAoC,CAAC;AAS1E,wBAAsB,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAoBtE;AAED,wBAAsB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAoBxE;AAED,wBAAsB,2BAA2B,CAC/C,GAAG,EAAE,eAAe,EACpB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAcjC"}
@@ -0,0 +1,68 @@
1
+ import { readTar } from "./tar.js";
2
+ import { parseShotDurations } from "./shot-durations-parse.js";
3
+ function chunkForStream(bytes) {
4
+ const chunk = bytes.slice();
5
+ return chunk;
6
+ }
7
+ export async function gzipBytes(bytes) {
8
+ const cs = new CompressionStream("gzip");
9
+ const writer = cs.writable.getWriter();
10
+ void writer.write(chunkForStream(bytes)).then(() => writer.close());
11
+ const reader = cs.readable.getReader();
12
+ const chunks = [];
13
+ let total = 0;
14
+ while (true) {
15
+ const { value, done } = await reader.read();
16
+ if (done)
17
+ break;
18
+ chunks.push(value);
19
+ total += value.length;
20
+ }
21
+ const out = new Uint8Array(total);
22
+ let offset = 0;
23
+ for (const c of chunks) {
24
+ out.set(c, offset);
25
+ offset += c.length;
26
+ }
27
+ return out;
28
+ }
29
+ export async function gunzipBytes(bytes) {
30
+ const ds = new DecompressionStream("gzip");
31
+ const writer = ds.writable.getWriter();
32
+ void writer.write(chunkForStream(bytes)).then(() => writer.close());
33
+ const reader = ds.readable.getReader();
34
+ const chunks = [];
35
+ let total = 0;
36
+ while (true) {
37
+ const { value, done } = await reader.read();
38
+ if (done)
39
+ break;
40
+ chunks.push(value);
41
+ total += value.length;
42
+ }
43
+ const out = new Uint8Array(total);
44
+ let offset = 0;
45
+ for (const c of chunks) {
46
+ out.set(c, offset);
47
+ offset += c.length;
48
+ }
49
+ return out;
50
+ }
51
+ export async function readShotDurationsFromBundle(env, bundleKey) {
52
+ try {
53
+ const src = await env.R2_RENDERS.get(bundleKey);
54
+ if (!src)
55
+ return {};
56
+ const tarBytes = await gunzipBytes(new Uint8Array(await src.arrayBuffer()));
57
+ for (const e of readTar(tarBytes)) {
58
+ if (e.name === "storyboard.yaml") {
59
+ return parseShotDurations(new TextDecoder().decode(e.content));
60
+ }
61
+ }
62
+ }
63
+ catch {
64
+ // best-effort
65
+ }
66
+ return {};
67
+ }
68
+ //# sourceMappingURL=bundle-durations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundle-durations.js","sourceRoot":"","sources":["../src/bundle-durations.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { Env } from "./platform/orchestrator-context.js";
2
+ import { type ParsedBundleScene } from "./planner-yaml.js";
3
+ /** Walk a gzip-decompressed ustar tar and return all non-directory entry names. */
4
+ export declare function listTarNames(tar: Uint8Array): string[];
5
+ /** Return raw bytes for a named tar entry, or null if missing. */
6
+ export declare function extractTarBytes(tar: Uint8Array, wantName: string): Uint8Array | null;
7
+ /** Walk a gzip-decompressed ustar tar and return the named file as utf-8, or null. */
8
+ export declare function extractTarText(tar: Uint8Array, wantName: string): string | null;
9
+ export declare function readBundleStoryboardYaml(env: Env, bundleKey: string): Promise<string | null>;
10
+ export declare function readBundleScenes(env: Env, bundleKey: string, defaultSeconds?: number): Promise<ParsedBundleScene[]>;
11
+ //# sourceMappingURL=bundle-storyboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundle-storyboard.d.ts","sourceRoot":"","sources":["../src/bundle-storyboard.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,oCAAoC,CAAC;AAC9D,OAAO,EAAyB,KAAK,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAkBlF,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,EAAE,CAetD;AAED,kEAAkE;AAClE,wBAAgB,eAAe,CAAC,GAAG,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAepF;AAED,sFAAsF;AACtF,wBAAgB,cAAc,CAAC,GAAG,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAG/E;AAED,wBAAsB,wBAAwB,CAAC,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAOlG;AAED,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,MAAM,EAAE,cAAc,SAAI,GAAG,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAIpH"}
@@ -0,0 +1,82 @@
1
+ // Read storyboard.yaml out of a bundles/*.tar.gz in R2. Pure tar walk + gzip decompress;
2
+ // only storyboard.yaml is extracted (the bundle schema is fixed and small).
3
+ import { parseStoryboardScenes } from "./planner-yaml.js";
4
+ function readTarString(header, offset, width) {
5
+ let s = "";
6
+ for (let i = 0; i < width; i++) {
7
+ const c = header[offset + i];
8
+ if (c === 0)
9
+ break;
10
+ s += String.fromCharCode(c);
11
+ }
12
+ return s;
13
+ }
14
+ function parseTarOctal(header, offset, width) {
15
+ const raw = readTarString(header, offset, width).trim();
16
+ if (!raw)
17
+ return 0;
18
+ return parseInt(raw, 8) || 0;
19
+ }
20
+ /** Walk a gzip-decompressed ustar tar and return all non-directory entry names. */
21
+ export function listTarNames(tar) {
22
+ const names = [];
23
+ let offset = 0;
24
+ for (;;) {
25
+ if (offset + 512 > tar.length)
26
+ break;
27
+ const header = tar.subarray(offset, offset + 512);
28
+ if (header.every((b) => b === 0))
29
+ break;
30
+ const name = readTarString(header, 0, 100);
31
+ const size = parseTarOctal(header, 124, 12);
32
+ offset += 512;
33
+ if (offset + size > tar.length)
34
+ break;
35
+ offset += Math.ceil(size / 512) * 512;
36
+ if (name)
37
+ names.push(name);
38
+ }
39
+ return names;
40
+ }
41
+ /** Return raw bytes for a named tar entry, or null if missing. */
42
+ export function extractTarBytes(tar, wantName) {
43
+ let offset = 0;
44
+ for (;;) {
45
+ if (offset + 512 > tar.length)
46
+ break;
47
+ const header = tar.subarray(offset, offset + 512);
48
+ if (header.every((b) => b === 0))
49
+ break;
50
+ const name = readTarString(header, 0, 100);
51
+ const size = parseTarOctal(header, 124, 12);
52
+ offset += 512;
53
+ if (offset + size > tar.length)
54
+ break;
55
+ const content = tar.subarray(offset, offset + size);
56
+ offset += Math.ceil(size / 512) * 512;
57
+ if (name === wantName)
58
+ return content;
59
+ }
60
+ return null;
61
+ }
62
+ /** Walk a gzip-decompressed ustar tar and return the named file as utf-8, or null. */
63
+ export function extractTarText(tar, wantName) {
64
+ const bytes = extractTarBytes(tar, wantName);
65
+ return bytes ? new TextDecoder().decode(bytes) : null;
66
+ }
67
+ export async function readBundleStoryboardYaml(env, bundleKey) {
68
+ const obj = await env.R2_RENDERS.get(bundleKey);
69
+ if (!obj)
70
+ return null;
71
+ const compressed = await obj.arrayBuffer();
72
+ const tarStream = new Blob([compressed]).stream().pipeThrough(new DecompressionStream("gzip"));
73
+ const tarBuf = new Uint8Array(await new Response(tarStream).arrayBuffer());
74
+ return extractTarText(tarBuf, "storyboard.yaml");
75
+ }
76
+ export async function readBundleScenes(env, bundleKey, defaultSeconds = 4) {
77
+ const yaml = await readBundleStoryboardYaml(env, bundleKey);
78
+ if (!yaml)
79
+ return [];
80
+ return parseStoryboardScenes(yaml, defaultSeconds);
81
+ }
82
+ //# sourceMappingURL=bundle-storyboard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bundle-storyboard.js","sourceRoot":"","sources":["../src/bundle-storyboard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ /** One time-synced caption cue, in seconds from the assembled film's 0-based start. */
2
+ export interface CaptionCue {
3
+ start: number;
4
+ end: number;
5
+ text: string;
6
+ }
7
+ /** A shot in PLAY order (scene order == concat order). `seconds` is the authored per-shot duration,
8
+ * used only when the bundle carries no beat-trimmed target for this shot. */
9
+ export interface CaptionScene {
10
+ shot_id: string;
11
+ seconds: number;
12
+ }
13
+ /** One spoken dialogue line, addressed to a shot. */
14
+ export interface CaptionLine {
15
+ shot_id: string;
16
+ text: string;
17
+ }
18
+ /** Build time-synced dialogue cues for the assembled film. `scenes` are in PLAY order; `durations`
19
+ * maps shot_id -> the real beat-trimmed seconds (a scene's authored `seconds` is the fallback). Only
20
+ * shots with a non-empty dialogue line produce a cue, timed to that shot's cumulative [start, end)
21
+ * window. Returns cues in play order; an empty array when nothing is spoken (the module then no-ops).
22
+ * A shot may carry at most one line; a later line for the same shot wins (last-write), matching how
23
+ * the dialogue stage resolves one line per speaking shot. */
24
+ export declare function buildCaptionCues(scenes: CaptionScene[], lines: CaptionLine[], durations?: Record<string, number>): CaptionCue[];
25
+ //# sourceMappingURL=captions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"captions.d.ts","sourceRoot":"","sources":["../src/captions.ts"],"names":[],"mappings":"AAcA,uFAAuF;AACvF,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED;8EAC8E;AAC9E,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qDAAqD;AACrD,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAcD;;;;;8DAK8D;AAC9D,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,YAAY,EAAE,EACtB,KAAK,EAAE,WAAW,EAAE,EACpB,SAAS,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GACrC,UAAU,EAAE,CAoBd"}