@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.
- package/LICENSE +661 -0
- package/README.md +87 -0
- package/dist/audio-routing.d.ts +2 -0
- package/dist/audio-routing.d.ts.map +1 -0
- package/dist/audio-routing.js +4 -0
- package/dist/audio-routing.js.map +1 -0
- package/dist/audio-stage.d.ts +4 -0
- package/dist/audio-stage.d.ts.map +1 -0
- package/dist/audio-stage.js +25 -0
- package/dist/audio-stage.js.map +1 -0
- package/dist/beat-analyze.d.ts +22 -0
- package/dist/beat-analyze.d.ts.map +1 -0
- package/dist/beat-analyze.js +111 -0
- package/dist/beat-analyze.js.map +1 -0
- package/dist/beat-sync-types.d.ts +33 -0
- package/dist/beat-sync-types.d.ts.map +1 -0
- package/dist/beat-sync-types.js +4 -0
- package/dist/beat-sync-types.js.map +1 -0
- package/dist/bundle-assembler.d.ts +54 -0
- package/dist/bundle-assembler.d.ts.map +1 -0
- package/dist/bundle-assembler.js +376 -0
- package/dist/bundle-assembler.js.map +1 -0
- package/dist/bundle-durations.d.ts +5 -0
- package/dist/bundle-durations.d.ts.map +1 -0
- package/dist/bundle-durations.js +68 -0
- package/dist/bundle-durations.js.map +1 -0
- package/dist/bundle-storyboard.d.ts +11 -0
- package/dist/bundle-storyboard.d.ts.map +1 -0
- package/dist/bundle-storyboard.js +82 -0
- package/dist/bundle-storyboard.js.map +1 -0
- package/dist/captions.d.ts +25 -0
- package/dist/captions.d.ts.map +1 -0
- package/dist/captions.js +56 -0
- package/dist/captions.js.map +1 -0
- package/dist/cast-db.d.ts +61 -0
- package/dist/cast-db.d.ts.map +1 -0
- package/dist/cast-db.js +324 -0
- package/dist/cast-db.js.map +1 -0
- package/dist/cast-lora-train.d.ts +18 -0
- package/dist/cast-lora-train.d.ts.map +1 -0
- package/dist/cast-lora-train.js +215 -0
- package/dist/cast-lora-train.js.map +1 -0
- package/dist/cast-loras.d.ts +21 -0
- package/dist/cast-loras.d.ts.map +1 -0
- package/dist/cast-loras.js +69 -0
- package/dist/cast-loras.js.map +1 -0
- package/dist/clip-content-validate.d.ts +43 -0
- package/dist/clip-content-validate.d.ts.map +1 -0
- package/dist/clip-content-validate.js +115 -0
- package/dist/clip-content-validate.js.map +1 -0
- package/dist/clip-job-model.d.ts +42 -0
- package/dist/clip-job-model.d.ts.map +1 -0
- package/dist/clip-job-model.js +8 -0
- package/dist/clip-job-model.js.map +1 -0
- package/dist/clip-validate.d.ts +33 -0
- package/dist/clip-validate.d.ts.map +1 -0
- package/dist/clip-validate.js +247 -0
- package/dist/clip-validate.js.map +1 -0
- package/dist/d1-retry.d.ts +20 -0
- package/dist/d1-retry.d.ts.map +1 -0
- package/dist/d1-retry.js +67 -0
- package/dist/d1-retry.js.map +1 -0
- package/dist/db-env.d.ts +6 -0
- package/dist/db-env.d.ts.map +1 -0
- package/dist/db-env.js +2 -0
- package/dist/db-env.js.map +1 -0
- package/dist/dialogue-lines.d.ts +23 -0
- package/dist/dialogue-lines.d.ts.map +1 -0
- package/dist/dialogue-lines.js +84 -0
- package/dist/dialogue-lines.js.map +1 -0
- package/dist/film-advance-lease.d.ts +9 -0
- package/dist/film-advance-lease.d.ts.map +1 -0
- package/dist/film-advance-lease.js +19 -0
- package/dist/film-advance-lease.js.map +1 -0
- package/dist/film-model.d.ts +415 -0
- package/dist/film-model.d.ts.map +1 -0
- package/dist/film-model.js +541 -0
- package/dist/film-model.js.map +1 -0
- package/dist/film-orchestrator.d.ts +216 -0
- package/dist/film-orchestrator.d.ts.map +1 -0
- package/dist/film-orchestrator.js +2204 -0
- package/dist/film-orchestrator.js.map +1 -0
- package/dist/film-render-bridge.d.ts +26 -0
- package/dist/film-render-bridge.d.ts.map +1 -0
- package/dist/film-render-bridge.js +176 -0
- package/dist/film-render-bridge.js.map +1 -0
- package/dist/finish-hash.d.ts +10 -0
- package/dist/finish-hash.d.ts.map +1 -0
- package/dist/finish-hash.js +60 -0
- package/dist/finish-hash.js.map +1 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/dist/key-safety.d.ts +5 -0
- package/dist/key-safety.d.ts.map +1 -0
- package/dist/key-safety.js +23 -0
- package/dist/key-safety.js.map +1 -0
- package/dist/lora-bundle.d.ts +19 -0
- package/dist/lora-bundle.d.ts.map +1 -0
- package/dist/lora-bundle.js +75 -0
- package/dist/lora-bundle.js.map +1 -0
- package/dist/lora-keys.d.ts +2 -0
- package/dist/lora-keys.d.ts.map +1 -0
- package/dist/lora-keys.js +4 -0
- package/dist/lora-keys.js.map +1 -0
- package/dist/modules/conformance.d.ts +58 -0
- package/dist/modules/conformance.d.ts.map +1 -0
- package/dist/modules/conformance.js +369 -0
- package/dist/modules/conformance.js.map +1 -0
- package/dist/modules/manifest-validate.d.ts +5 -0
- package/dist/modules/manifest-validate.d.ts.map +1 -0
- package/dist/modules/manifest-validate.js +60 -0
- package/dist/modules/manifest-validate.js.map +1 -0
- package/dist/modules/registry.d.ts +184 -0
- package/dist/modules/registry.d.ts.map +1 -0
- package/dist/modules/registry.js +653 -0
- package/dist/modules/registry.js.map +1 -0
- package/dist/modules/render-pipeline.d.ts +38 -0
- package/dist/modules/render-pipeline.d.ts.map +1 -0
- package/dist/modules/render-pipeline.js +40 -0
- package/dist/modules/render-pipeline.js.map +1 -0
- package/dist/modules/types.d.ts +544 -0
- package/dist/modules/types.d.ts.map +1 -0
- package/dist/modules/types.js +57 -0
- package/dist/modules/types.js.map +1 -0
- package/dist/operator-config.d.ts +20 -0
- package/dist/operator-config.d.ts.map +1 -0
- package/dist/operator-config.js +85 -0
- package/dist/operator-config.js.map +1 -0
- package/dist/output-extract.d.ts +8 -0
- package/dist/output-extract.d.ts.map +1 -0
- package/dist/output-extract.js +129 -0
- package/dist/output-extract.js.map +1 -0
- package/dist/planner-prompt.d.ts +12 -0
- package/dist/planner-prompt.d.ts.map +1 -0
- package/dist/planner-prompt.js +337 -0
- package/dist/planner-prompt.js.map +1 -0
- package/dist/planner-yaml.d.ts +15 -0
- package/dist/planner-yaml.d.ts.map +1 -0
- package/dist/planner-yaml.js +157 -0
- package/dist/planner-yaml.js.map +1 -0
- package/dist/platform/fetcher.d.ts +3 -0
- package/dist/platform/fetcher.d.ts.map +1 -0
- package/dist/platform/fetcher.js +7 -0
- package/dist/platform/fetcher.js.map +1 -0
- package/dist/platform/index.d.ts +6 -0
- package/dist/platform/index.d.ts.map +1 -0
- package/dist/platform/index.js +5 -0
- package/dist/platform/index.js.map +1 -0
- package/dist/platform/object-store-r2.d.ts +26 -0
- package/dist/platform/object-store-r2.d.ts.map +1 -0
- package/dist/platform/object-store-r2.js +74 -0
- package/dist/platform/object-store-r2.js.map +1 -0
- package/dist/platform/orchestrator-context.d.ts +20 -0
- package/dist/platform/orchestrator-context.d.ts.map +1 -0
- package/dist/platform/orchestrator-context.js +28 -0
- package/dist/platform/orchestrator-context.js.map +1 -0
- package/dist/platform/r2-types.d.ts +41 -0
- package/dist/platform/r2-types.d.ts.map +1 -0
- package/dist/platform/r2-types.js +3 -0
- package/dist/platform/r2-types.js.map +1 -0
- package/dist/platform/types.d.ts +90 -0
- package/dist/platform/types.d.ts.map +1 -0
- package/dist/platform/types.js +23 -0
- package/dist/platform/types.js.map +1 -0
- package/dist/preflight.d.ts +57 -0
- package/dist/preflight.d.ts.map +1 -0
- package/dist/preflight.js +243 -0
- package/dist/preflight.js.map +1 -0
- package/dist/presign.d.ts +5 -0
- package/dist/presign.d.ts.map +1 -0
- package/dist/presign.js +24 -0
- package/dist/presign.js.map +1 -0
- package/dist/public-id.d.ts +8 -0
- package/dist/public-id.d.ts.map +1 -0
- package/dist/public-id.js +25 -0
- package/dist/public-id.js.map +1 -0
- package/dist/render-adopt.d.ts +3 -0
- package/dist/render-adopt.d.ts.map +1 -0
- package/dist/render-adopt.js +92 -0
- package/dist/render-adopt.js.map +1 -0
- package/dist/render-log.d.ts +25 -0
- package/dist/render-log.d.ts.map +1 -0
- package/dist/render-log.js +139 -0
- package/dist/render-log.js.map +1 -0
- package/dist/render-module-config.d.ts +28 -0
- package/dist/render-module-config.d.ts.map +1 -0
- package/dist/render-module-config.js +124 -0
- package/dist/render-module-config.js.map +1 -0
- package/dist/render-mux.d.ts +18 -0
- package/dist/render-mux.d.ts.map +1 -0
- package/dist/render-mux.js +69 -0
- package/dist/render-mux.js.map +1 -0
- package/dist/render-orchestrator.d.ts +71 -0
- package/dist/render-orchestrator.d.ts.map +1 -0
- package/dist/render-orchestrator.js +376 -0
- package/dist/render-orchestrator.js.map +1 -0
- package/dist/render-sweep.d.ts +5 -0
- package/dist/render-sweep.d.ts.map +1 -0
- package/dist/render-sweep.js +62 -0
- package/dist/render-sweep.js.map +1 -0
- package/dist/renders-db.d.ts +129 -0
- package/dist/renders-db.d.ts.map +1 -0
- package/dist/renders-db.js +752 -0
- package/dist/renders-db.js.map +1 -0
- package/dist/runpod-submit.d.ts +151 -0
- package/dist/runpod-submit.d.ts.map +1 -0
- package/dist/runpod-submit.js +469 -0
- package/dist/runpod-submit.js.map +1 -0
- package/dist/runpod-types.d.ts +2 -0
- package/dist/runpod-types.d.ts.map +1 -0
- package/dist/runpod-types.js +4 -0
- package/dist/runpod-types.js.map +1 -0
- package/dist/scatter-notify.d.ts +4 -0
- package/dist/scatter-notify.d.ts.map +1 -0
- package/dist/scatter-notify.js +43 -0
- package/dist/scatter-notify.js.map +1 -0
- package/dist/scatter-orchestrator-types.d.ts +56 -0
- package/dist/scatter-orchestrator-types.d.ts.map +1 -0
- package/dist/scatter-orchestrator-types.js +3 -0
- package/dist/scatter-orchestrator-types.js.map +1 -0
- package/dist/scatter-orchestrator.d.ts +70 -0
- package/dist/scatter-orchestrator.d.ts.map +1 -0
- package/dist/scatter-orchestrator.js +614 -0
- package/dist/scatter-orchestrator.js.map +1 -0
- package/dist/scatter.d.ts +35 -0
- package/dist/scatter.d.ts.map +1 -0
- package/dist/scatter.js +171 -0
- package/dist/scatter.js.map +1 -0
- package/dist/secret-store.d.ts +5 -0
- package/dist/secret-store.d.ts.map +1 -0
- package/dist/secret-store.js +19 -0
- package/dist/secret-store.js.map +1 -0
- package/dist/shot-durations-parse.d.ts +3 -0
- package/dist/shot-durations-parse.d.ts.map +1 -0
- package/dist/shot-durations-parse.js +43 -0
- package/dist/shot-durations-parse.js.map +1 -0
- package/dist/srt.d.ts +11 -0
- package/dist/srt.d.ts.map +1 -0
- package/dist/srt.js +54 -0
- package/dist/srt.js.map +1 -0
- package/dist/storyboard-ids.d.ts +2 -0
- package/dist/storyboard-ids.d.ts.map +1 -0
- package/dist/storyboard-ids.js +12 -0
- package/dist/storyboard-ids.js.map +1 -0
- package/dist/storyboard-projects-db.d.ts +31 -0
- package/dist/storyboard-projects-db.d.ts.map +1 -0
- package/dist/storyboard-projects-db.js +153 -0
- package/dist/storyboard-projects-db.js.map +1 -0
- package/dist/storyboard-validate.d.ts +72 -0
- package/dist/storyboard-validate.d.ts.map +1 -0
- package/dist/storyboard-validate.js +595 -0
- package/dist/storyboard-validate.js.map +1 -0
- package/dist/structured-events.d.ts +6 -0
- package/dist/structured-events.d.ts.map +1 -0
- package/dist/structured-events.js +15 -0
- package/dist/structured-events.js.map +1 -0
- package/dist/tar.d.ts +9 -0
- package/dist/tar.d.ts.map +1 -0
- package/dist/tar.js +151 -0
- package/dist/tar.js.map +1 -0
- package/dist/voices.d.ts +12 -0
- package/dist/voices.d.ts.map +1 -0
- package/dist/voices.js +37 -0
- package/dist/voices.js.map +1 -0
- package/package.json +71 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// operator-config: the persistent, INSTANCE-scoped store for config_schema fields marked
|
|
2
|
+
// `scope: "install"` (the operator-set-once knobs, e.g. notify-email's recipient address).
|
|
3
|
+
//
|
|
4
|
+
// The identity strip (#292) zeroed user_email, so this is NOT per-user: it is per-INSTALL, keyed on
|
|
5
|
+
// (module_name, field_key) in the operator_module_config D1 table (migration 0005). The operator sets
|
|
6
|
+
// these on the studio settings page (GET/PATCH /api/modules/:name/config); the core persists them
|
|
7
|
+
// here and INJECTS them into the module invoke at hook time, so a field like notify_email actually
|
|
8
|
+
// reaches the module at render.complete. Per-render fields (scope omitted / "render") are untouched
|
|
9
|
+
// by this store -- they still flow through the per-render config path.
|
|
10
|
+
//
|
|
11
|
+
// The pure helpers (install-subschema projection, clamp-on-write) are vitest-testable without a D1
|
|
12
|
+
// binding; the two query functions are verified live (matches the user-prefs / renders-db split).
|
|
13
|
+
import { validateConfig } from "./modules/registry.js";
|
|
14
|
+
/** Project a module's config_schema down to ONLY its install-scope fields. A field with no `scope`
|
|
15
|
+
* (or scope "render") is a per-render knob and is excluded -- so this store never owns render config. */
|
|
16
|
+
export function installSubschema(schema) {
|
|
17
|
+
const out = {};
|
|
18
|
+
if (!schema)
|
|
19
|
+
return out;
|
|
20
|
+
for (const [key, field] of Object.entries(schema)) {
|
|
21
|
+
if (field.scope === "install")
|
|
22
|
+
out[key] = field;
|
|
23
|
+
}
|
|
24
|
+
return out;
|
|
25
|
+
}
|
|
26
|
+
/** Does this module expose any install-scope config at all? */
|
|
27
|
+
export function hasInstallConfig(schema) {
|
|
28
|
+
return Object.keys(installSubschema(schema)).length > 0;
|
|
29
|
+
}
|
|
30
|
+
/** The set of writable install field keys for a module (what PATCH is allowed to set). */
|
|
31
|
+
export function installFieldKeys(schema) {
|
|
32
|
+
return Object.keys(installSubschema(schema));
|
|
33
|
+
}
|
|
34
|
+
/** Clamp an incoming patch to the module's install subschema, dropping unknown / render-scope keys.
|
|
35
|
+
* Reuses the SAME validateConfig clamp the invoke path uses, so a stored value can never violate the
|
|
36
|
+
* contract. Returns the full install-config (every install field, missing ones at their default). */
|
|
37
|
+
export function clampInstallPatch(schema, current, patch) {
|
|
38
|
+
const sub = installSubschema(schema);
|
|
39
|
+
const merged = { ...current, ...(patch ?? {}) };
|
|
40
|
+
return validateConfig(sub, merged);
|
|
41
|
+
}
|
|
42
|
+
// --------------------------------------------------------------------------- D1 (verified live)
|
|
43
|
+
/** Read the raw stored install values for a module (field_key -> decoded scalar). No schema applied;
|
|
44
|
+
* callers pass through validateConfig / the subschema to get a contract-clean, default-filled view. */
|
|
45
|
+
async function readStored(env, moduleName) {
|
|
46
|
+
const rs = await env.DB.prepare("SELECT field_key, value_json FROM operator_module_config WHERE module_name = ?")
|
|
47
|
+
.bind(moduleName)
|
|
48
|
+
.all();
|
|
49
|
+
const out = {};
|
|
50
|
+
for (const row of rs.results ?? []) {
|
|
51
|
+
try {
|
|
52
|
+
out[row.field_key] = JSON.parse(row.value_json);
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// a corrupt row is ignored; the field falls back to its schema default downstream.
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return out;
|
|
59
|
+
}
|
|
60
|
+
/** The module's install-config as the INVOKE path consumes it: every install field present, missing
|
|
61
|
+
* ones at their schema default, clamped to the contract. Empty schema -> {} (a clean no-op). */
|
|
62
|
+
export async function loadInstallConfig(env, moduleName, schema) {
|
|
63
|
+
const sub = installSubschema(schema);
|
|
64
|
+
if (Object.keys(sub).length === 0)
|
|
65
|
+
return {};
|
|
66
|
+
const stored = await readStored(env, moduleName);
|
|
67
|
+
return validateConfig(sub, stored);
|
|
68
|
+
}
|
|
69
|
+
/** Persist an operator PATCH: clamp to the install subschema (unknown / render keys dropped), then
|
|
70
|
+
* upsert each field. Returns the resulting full install-config view. */
|
|
71
|
+
export async function setInstallConfig(env, moduleName, schema, patch) {
|
|
72
|
+
const sub = installSubschema(schema);
|
|
73
|
+
const current = await readStored(env, moduleName);
|
|
74
|
+
const next = clampInstallPatch(schema, current, patch);
|
|
75
|
+
const now = Math.floor(Date.now() / 1000);
|
|
76
|
+
const stmt = env.DB.prepare(`INSERT INTO operator_module_config (module_name, field_key, value_json, updated_at)
|
|
77
|
+
VALUES (?, ?, ?, ?)
|
|
78
|
+
ON CONFLICT(module_name, field_key) DO UPDATE SET
|
|
79
|
+
value_json = excluded.value_json, updated_at = excluded.updated_at`);
|
|
80
|
+
const writes = Object.keys(sub).map((key) => stmt.bind(moduleName, key, JSON.stringify(next[key]), now));
|
|
81
|
+
if (writes.length)
|
|
82
|
+
await env.DB.batch(writes);
|
|
83
|
+
return next;
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=operator-config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"operator-config.js","sourceRoot":"","sources":["../src/operator-config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare function extractOutput(result: unknown): string;
|
|
2
|
+
export declare function extractUsage(result: unknown): {
|
|
3
|
+
in_: number | null;
|
|
4
|
+
out_: number | null;
|
|
5
|
+
};
|
|
6
|
+
export declare function detectProviderFailure(result: unknown): string | null;
|
|
7
|
+
export declare function extractProxiedImageUrl(result: unknown): string | null;
|
|
8
|
+
//# sourceMappingURL=output-extract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output-extract.d.ts","sourceRoot":"","sources":["../src/output-extract.ts"],"names":[],"mappings":"AAeA,wBAAgB,aAAa,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,CAmDrD;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,OAAO,GAAG;IAAE,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAqBzF;AAcD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CASpE;AAQD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAOrE"}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
// Text-model output + usage extraction (v0.21.0).
|
|
2
|
+
//
|
|
3
|
+
// Extracted from src/index.ts so these pure functions are unit-testable
|
|
4
|
+
// without importing index.ts (which pulls in `cloudflare:workers` and so
|
|
5
|
+
// can't be loaded under the plain-Node vitest pool). Mirrors the same
|
|
6
|
+
// extraction discipline used for parsers, chunking, discord, and ai-binding.
|
|
7
|
+
//
|
|
8
|
+
// Both functions normalize the many response shapes that reach the
|
|
9
|
+
// non-streaming chat path. The shapes come from: Workers AI hosted models
|
|
10
|
+
// (env.AI.run), Anthropic Messages API, Gemini, and OpenAI-style responses
|
|
11
|
+
// (both chat-completions and the Responses API) returned by unified-billing
|
|
12
|
+
// proxied models routed through env.AI.run. New shapes should be added here
|
|
13
|
+
// with a unit test in tests/output-extract.test.ts rather than inlined at a
|
|
14
|
+
// call site.
|
|
15
|
+
export function extractOutput(result) {
|
|
16
|
+
if (typeof result === "string")
|
|
17
|
+
return result;
|
|
18
|
+
const r = result;
|
|
19
|
+
if (typeof r?.response === "string")
|
|
20
|
+
return r.response;
|
|
21
|
+
if (typeof r?.result === "string")
|
|
22
|
+
return r.result;
|
|
23
|
+
// OpenAI chat-completions shape (also what AI Gateway returns for most
|
|
24
|
+
// proxied OpenAI/OpenAI-compatible chat models): { choices: [{ message }] }
|
|
25
|
+
const choices = r?.choices;
|
|
26
|
+
if (Array.isArray(choices) && typeof choices[0]?.message?.content === "string") {
|
|
27
|
+
return choices[0].message.content;
|
|
28
|
+
}
|
|
29
|
+
// Anthropic Messages API: top-level content array
|
|
30
|
+
const content = r?.content;
|
|
31
|
+
if (Array.isArray(content)) {
|
|
32
|
+
const text = content.filter((b) => b.type === "text").map((b) => b.text ?? "").join("");
|
|
33
|
+
if (text)
|
|
34
|
+
return text;
|
|
35
|
+
}
|
|
36
|
+
// OpenAI Responses API shape (used by gpt-5.x-pro and similar): a top-level
|
|
37
|
+
// `output` array of items, each with a `content` array of typed blocks.
|
|
38
|
+
// Output text lives in blocks of type "output_text" (or plain "text").
|
|
39
|
+
const out = r?.output;
|
|
40
|
+
if (Array.isArray(out)) {
|
|
41
|
+
const text = out
|
|
42
|
+
.flatMap((block) => {
|
|
43
|
+
const b = block;
|
|
44
|
+
return (b?.content ?? [])
|
|
45
|
+
.filter((c) => c?.type === "output_text" || c?.type === "text")
|
|
46
|
+
.map((c) => c.text ?? "");
|
|
47
|
+
})
|
|
48
|
+
.join("");
|
|
49
|
+
if (text)
|
|
50
|
+
return text;
|
|
51
|
+
}
|
|
52
|
+
// Gemini-native (google/gemini-* via the binding, v0.21.3):
|
|
53
|
+
// { candidates: [{ content: { parts: [{ text }] } }] }
|
|
54
|
+
const candidates = r?.candidates;
|
|
55
|
+
if (Array.isArray(candidates)) {
|
|
56
|
+
const text = (candidates[0]?.content?.parts ?? [])
|
|
57
|
+
.map((p) => p.text ?? "")
|
|
58
|
+
.join("");
|
|
59
|
+
if (text)
|
|
60
|
+
return text;
|
|
61
|
+
}
|
|
62
|
+
// LLaVA 1.5 image-to-text (@cf/llava-hf/llava-1.5-7b-hf): { description }
|
|
63
|
+
if (typeof r?.description === "string")
|
|
64
|
+
return r.description;
|
|
65
|
+
return JSON.stringify(result);
|
|
66
|
+
}
|
|
67
|
+
export function extractUsage(result) {
|
|
68
|
+
const r = result;
|
|
69
|
+
// OpenAI / Anthropic: usage object on result. OpenAI uses
|
|
70
|
+
// prompt_tokens/completion_tokens; Anthropic uses input_tokens/output_tokens.
|
|
71
|
+
const u = r?.usage;
|
|
72
|
+
if (u) {
|
|
73
|
+
return {
|
|
74
|
+
in_: u.prompt_tokens ?? u.input_tokens ?? null,
|
|
75
|
+
out_: u.completion_tokens ?? u.output_tokens ?? null,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
// Gemini-native usage (v0.21.3): usageMetadata.promptTokenCount /
|
|
79
|
+
// candidatesTokenCount (thoughtsTokenCount is reasoning, not counted as out).
|
|
80
|
+
const um = r?.usageMetadata;
|
|
81
|
+
if (um) {
|
|
82
|
+
return {
|
|
83
|
+
in_: um.promptTokenCount ?? null,
|
|
84
|
+
out_: um.candidatesTokenCount ?? null,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
return { in_: null, out_: null };
|
|
88
|
+
}
|
|
89
|
+
// Detect a provider failure envelope returned as a normal resolved value
|
|
90
|
+
// rather than thrown. Unified-billing proxied models (seen first with the
|
|
91
|
+
// OpenAI chat models in v0.21.0) can return { state: "Failed", error: "..." }
|
|
92
|
+
// from env.AI.run instead of rejecting; the gateway uses the same envelope
|
|
93
|
+
// the LongRunWorkflow already checks for video/music. Without catching it,
|
|
94
|
+
// extractOutput would JSON.stringify the envelope into chats.output and a
|
|
95
|
+
// failed turn would persist as if it succeeded.
|
|
96
|
+
//
|
|
97
|
+
// Sync chat responses (OpenAI {choices}, Anthropic {content}, Workers AI
|
|
98
|
+
// {response}) carry no `state` field, so a present `state` that isn't
|
|
99
|
+
// "Completed" is the signal. Returns the upstream error message (for the
|
|
100
|
+
// caller to surface as a 502) or null when the result looks normal.
|
|
101
|
+
export function detectProviderFailure(result) {
|
|
102
|
+
if (!result || typeof result !== "object")
|
|
103
|
+
return null;
|
|
104
|
+
const r = result;
|
|
105
|
+
if (typeof r.state === "string" && r.state !== "Completed") {
|
|
106
|
+
return typeof r.error === "string" && r.error.trim()
|
|
107
|
+
? r.error
|
|
108
|
+
: `provider returned state "${r.state}"`;
|
|
109
|
+
}
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
// Pull the generated-image URL out of a proxied image-gen response. Proxied
|
|
113
|
+
// image models (the Google nano-banana family, added v0.21.2) return a URL,
|
|
114
|
+
// not base64, wrapped in the same { state, result } envelope as video/music:
|
|
115
|
+
// { state: "Completed", result: { image: "<url>" } }
|
|
116
|
+
// The bare { image: "<url>" } form (the documented Output schema, without the
|
|
117
|
+
// binding wrapper) is accepted too. Returns the URL string or null.
|
|
118
|
+
export function extractProxiedImageUrl(result) {
|
|
119
|
+
if (!result || typeof result !== "object")
|
|
120
|
+
return null;
|
|
121
|
+
const r = result;
|
|
122
|
+
const wrapped = r.result?.image;
|
|
123
|
+
if (typeof wrapped === "string" && wrapped.length > 0)
|
|
124
|
+
return wrapped;
|
|
125
|
+
if (typeof r.image === "string" && r.image.length > 0)
|
|
126
|
+
return r.image;
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=output-extract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output-extract.js","sourceRoot":"","sources":["../src/output-extract.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { SlotId } from "./storyboard-validate.js";
|
|
2
|
+
export interface PlannerCharacter {
|
|
3
|
+
slot: SlotId;
|
|
4
|
+
name: string;
|
|
5
|
+
bible: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function buildPlanningSystemPrompt(): string;
|
|
8
|
+
export declare function buildPlanningUserMessage(brief: string, characters: PlannerCharacter[], beatBlock?: string): string;
|
|
9
|
+
export declare function buildRefinementSystemPrompt(): string;
|
|
10
|
+
export declare function buildRefinementUserMessage(currentStoryboard: unknown, message: string): string;
|
|
11
|
+
export declare function stripJsonFences(raw: string): string;
|
|
12
|
+
//# sourceMappingURL=planner-prompt.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planner-prompt.d.ts","sourceRoot":"","sources":["../src/planner-prompt.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,0BAA0B,CAAC;AAYvD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAQD,wBAAgB,yBAAyB,IAAI,MAAM,CA6JlD;AAMD,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,gBAAgB,EAAE,EAC9B,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,CAsBR;AAaD,wBAAgB,2BAA2B,IAAI,MAAM,CA+FpD;AAED,wBAAgB,0BAA0B,CACxC,iBAAiB,EAAE,OAAO,EAC1B,OAAO,EAAE,MAAM,GACd,MAAM,CAUR;AASD,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAanD"}
|
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
// Pure string helpers for the storyboard planner (v0.28.0).
|
|
2
|
+
//
|
|
3
|
+
// Holds the system + user prompt builders and the JSON fence stripper.
|
|
4
|
+
// Extracted from planner.ts so the prompt text and the output cleanup are
|
|
5
|
+
// unit-testable without dragging Env, fetch, or env.AI into the test
|
|
6
|
+
// (same pattern as parsers/, longrun-params.ts, output-extract.ts).
|
|
7
|
+
import { DIALOGUE_MAX_CHARS, FULL_PROMPT_MAX_CHARS, SCENE_PROMPT_MAX_WORDS, STORYBOARD_MAX_SCENES, STYLE_PREFIX_MAX_CHARS, } from "./storyboard-validate.js";
|
|
8
|
+
// System prompt sent to the model. Constrains output to a JSON object
|
|
9
|
+
// matching StoryboardInput. Declares the slot id enum, the style_prefix
|
|
10
|
+
// once-only rule (style_prefix is prepended to every scene at manifest-
|
|
11
|
+
// build time, so repeating style words inside a scene prompt double-
|
|
12
|
+
// applies them), and the literal-"None" convention for style_category /
|
|
13
|
+
// style_preset (the renderer disables on the string, not on null).
|
|
14
|
+
export function buildPlanningSystemPrompt() {
|
|
15
|
+
return `You are the storyboard planner for a music-video / short-film AI pipeline.
|
|
16
|
+
Your output is consumed directly by a renderer that turns each scene into
|
|
17
|
+
a Wan I2V clip with an SDXL keyframe. Return ONE JSON object that exactly
|
|
18
|
+
matches the schema below. No prose. No markdown. No YAML. Do not wrap the
|
|
19
|
+
JSON in code fences.
|
|
20
|
+
|
|
21
|
+
SCHEMA:
|
|
22
|
+
{
|
|
23
|
+
"title": string,
|
|
24
|
+
"full_prompt": string,
|
|
25
|
+
"duration_seconds": number,
|
|
26
|
+
"clip_seconds": number,
|
|
27
|
+
"style_prefix": string,
|
|
28
|
+
"style_category": string,
|
|
29
|
+
"style_preset": string,
|
|
30
|
+
"use_characters": ["A" | "B" | "C" | "D", ...],
|
|
31
|
+
"cast_rules": string,
|
|
32
|
+
"scenes": [
|
|
33
|
+
{
|
|
34
|
+
"prompt": string,
|
|
35
|
+
"character_slots": ["A" | "B" | "C" | "D", ...],
|
|
36
|
+
"act": string,
|
|
37
|
+
"start": number,
|
|
38
|
+
"end": number,
|
|
39
|
+
"target_seconds": number,
|
|
40
|
+
"dialogue": { "slot": "A" | "B" | "C" | "D", "text": string }
|
|
41
|
+
},
|
|
42
|
+
...
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
FIELDS:
|
|
47
|
+
- title: short film title; spaces become underscores in the on-disk slug.
|
|
48
|
+
- full_prompt: one or two sentence film-level summary (optional).
|
|
49
|
+
- duration_seconds: total film length target in seconds (positive number).
|
|
50
|
+
- clip_seconds: per-shot target length in seconds (positive number).
|
|
51
|
+
- style_prefix: ALL style language goes here, EXACTLY ONCE. Palette, lens,
|
|
52
|
+
era, lighting register, film stock, color grade, key visual vocabulary.
|
|
53
|
+
The renderer prepends this string verbatim to every scene prompt at
|
|
54
|
+
manifest-build time, so any style word repeated inside a scene prompt
|
|
55
|
+
is double-applied and biases the keyframe.
|
|
56
|
+
- style_category, style_preset: lookups the renderer disables on the
|
|
57
|
+
literal string "None". When you do not want a category or preset
|
|
58
|
+
applied, emit the string "None", never null and never the empty string.
|
|
59
|
+
- use_characters: slot ids loaded for this render. Slot ids are exactly
|
|
60
|
+
the literal strings "A", "B", "C", "D". Nothing else is valid. Set this
|
|
61
|
+
to the slots you plan to feature; omit slots that will not appear.
|
|
62
|
+
- cast_rules: optional plain-text rules for cast cohesion (pairings,
|
|
63
|
+
outfit constraints, prop continuity).
|
|
64
|
+
- scenes: REQUIRED, at least one entry, one per shot.
|
|
65
|
+
- scenes[].prompt: SHOT CONTENT ONLY. Subject action, framing, moment,
|
|
66
|
+
emotional beat. Do NOT include style language; that lives in
|
|
67
|
+
style_prefix above. Do NOT repeat the film title or full_prompt.
|
|
68
|
+
- scenes[].character_slots: subset of use_characters. Omit the field
|
|
69
|
+
entirely for an empty-frame shot rather than send an unloaded slot.
|
|
70
|
+
- scenes[].act: optional act tag, one of "opening", "rising", "turn",
|
|
71
|
+
"climax", "resolution".
|
|
72
|
+
- scenes[].start, end, target_seconds: optional per-shot timing in
|
|
73
|
+
seconds. start may be 0; end must be strictly greater than start;
|
|
74
|
+
target_seconds must be positive.
|
|
75
|
+
- scenes[].dialogue: OPTIONAL spoken line for the shot (auto-direction).
|
|
76
|
+
Include it ONLY when a character actually speaks on camera in that shot.
|
|
77
|
+
"slot" is the speaking character and MUST be one of that scene's
|
|
78
|
+
character_slots. "text" is the line itself: natural spoken words only,
|
|
79
|
+
no quotation marks, no "Name:" speaker prefix, no stage directions. Keep
|
|
80
|
+
it short enough to be said within the shot's length (roughly 2-3 spoken
|
|
81
|
+
words per second). Omit the field entirely for a silent shot.
|
|
82
|
+
|
|
83
|
+
HARD RULES:
|
|
84
|
+
1. style_prefix is the ONLY place style language belongs. Repeating style
|
|
85
|
+
words inside scenes[].prompt double-applies them because style_prefix
|
|
86
|
+
is prepended to every scene at manifest-build time.
|
|
87
|
+
2. Every entry in a scene's character_slots must appear in the top-level
|
|
88
|
+
use_characters array. Never lock a scene to a slot you have not loaded.
|
|
89
|
+
3. Slot ids are exactly "A", "B", "C", "D". No lowercase, no other letters.
|
|
90
|
+
4. style_category and style_preset default to the literal string "None"
|
|
91
|
+
when you do not want a lookup. Never null. Never empty string.
|
|
92
|
+
5. Numeric fields are plain JSON numbers, never strings. No units ("s",
|
|
93
|
+
"sec", "min"); seconds is implicit.
|
|
94
|
+
6. Plan 3 to 12 scenes for a vignette / single-track music video unless
|
|
95
|
+
the brief specifies otherwise.
|
|
96
|
+
6a. A scene's dialogue.slot MUST be one of that scene's character_slots
|
|
97
|
+
(the speaker has to be in the shot). Only one character speaks per
|
|
98
|
+
shot. Most shots have no dialogue; reserve it for genuine spoken beats.
|
|
99
|
+
|
|
100
|
+
LENGTH CAPS (the renderer rejects outputs over these caps because they
|
|
101
|
+
overflow SDXL's CLIP 77-token text encoder or break manifest builds):
|
|
102
|
+
7. Each scenes[].prompt: at most ${SCENE_PROMPT_MAX_WORDS} words. The pod
|
|
103
|
+
prepends 2-4 LoRA trigger tokens plus the style_prefix to every scene,
|
|
104
|
+
leaving roughly ${SCENE_PROMPT_MAX_WORDS}-word headroom inside CLIP 77.
|
|
105
|
+
Move character appearance details to the cast bible (already loaded),
|
|
106
|
+
not into the scene prompt.
|
|
107
|
+
8. style_prefix: at most ${STYLE_PREFIX_MAX_CHARS} characters. Compress.
|
|
108
|
+
Three or four palette / lens / lighting clauses is plenty; the model
|
|
109
|
+
reads ALL of it once per scene, so verbosity here costs every shot.
|
|
110
|
+
9. full_prompt: at most ${FULL_PROMPT_MAX_CHARS} characters. This is the
|
|
111
|
+
film-level summary, not the script; one or two sentences.
|
|
112
|
+
10. scenes array length: at most ${STORYBOARD_MAX_SCENES} entries. A 50-
|
|
113
|
+
shot render is already 25+ minutes of GPU time at typical clip
|
|
114
|
+
seconds; if the brief implies more, shorten clip_seconds or split.
|
|
115
|
+
11. scenes[].dialogue.text: at most ${DIALOGUE_MAX_CHARS} characters. One
|
|
116
|
+
spoken line per shot; a clip is only a few seconds, so a sentence or
|
|
117
|
+
two is the ceiling, not a speech.
|
|
118
|
+
|
|
119
|
+
GOLDEN EXAMPLE (mirrors the renderer's storyboard.example.yaml). This
|
|
120
|
+
shape is the canonical output; produce JSON that matches its style:
|
|
121
|
+
|
|
122
|
+
{
|
|
123
|
+
"title": "morning_walk",
|
|
124
|
+
"full_prompt": "Three-shot vignette: Elena walks into a hilltop clearing at dawn.",
|
|
125
|
+
"duration_seconds": 21,
|
|
126
|
+
"clip_seconds": 7,
|
|
127
|
+
"style_prefix": "cinematic 35mm film, soft golden hour light, shallow depth of field",
|
|
128
|
+
"style_category": "None",
|
|
129
|
+
"style_preset": "None",
|
|
130
|
+
"use_characters": ["A"],
|
|
131
|
+
"cast_rules": "",
|
|
132
|
+
"scenes": [
|
|
133
|
+
{
|
|
134
|
+
"prompt": "Wide establishing shot of a quiet hilltop at dawn, mist over the valley below.",
|
|
135
|
+
"act": "opening"
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"prompt": "Elena walks into frame from the left, looks out over the valley, wind in her coat.",
|
|
139
|
+
"character_slots": ["A"],
|
|
140
|
+
"act": "rising"
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"prompt": "Close-up on Elena's face, soft side light, expression of quiet resolve, eyes catching the last warm light.",
|
|
144
|
+
"character_slots": ["A"],
|
|
145
|
+
"act": "turn"
|
|
146
|
+
}
|
|
147
|
+
]
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
What that example demonstrates concretely:
|
|
151
|
+
- Each scene's prompt is ~15-25 words: subject + action + framing +
|
|
152
|
+
one beat of mood. Well inside the ${SCENE_PROMPT_MAX_WORDS}-word cap.
|
|
153
|
+
- The cast member is referenced by NAME ("Elena"), not by slot id.
|
|
154
|
+
The slot id only appears in scenes[].character_slots, never in prose.
|
|
155
|
+
- Scene 1 omits character_slots entirely because nothing in the prompt
|
|
156
|
+
references a character. Do NOT send character_slots:[] either; omit
|
|
157
|
+
the field. (The example.yaml puts ["A"] on every shot; both forms
|
|
158
|
+
are accepted, but omitting is clearer for empty-frame shots.)
|
|
159
|
+
- No appearance details in any scene prompt (no "red hair, green coat",
|
|
160
|
+
no "weathered older man"). The cast bible carries those; the renderer
|
|
161
|
+
prepends a LoRA trigger that injects the appearance vector for you.
|
|
162
|
+
- No style language in any scene prompt: "cinematic", "35mm",
|
|
163
|
+
"golden hour" all live in style_prefix and are prepended once per
|
|
164
|
+
shot. Repeating them inside a scene double-applies them.
|
|
165
|
+
- style_category and style_preset are literal "None" strings (never
|
|
166
|
+
null, never empty) because the renderer disables on the string.
|
|
167
|
+
- act values are lowercase: "opening", "rising", "turn", "climax",
|
|
168
|
+
"resolution". Each scene optionally tagged.
|
|
169
|
+
|
|
170
|
+
Return ONLY the JSON object. Nothing before it. Nothing after it.`;
|
|
171
|
+
}
|
|
172
|
+
// User-side message that carries the brief plus the cast bible. The model
|
|
173
|
+
// uses the cast to populate use_characters and per-scene character_slots.
|
|
174
|
+
// Characters are sorted by slot id so the same input always renders the
|
|
175
|
+
// same prompt, which keeps planner cache hits stable.
|
|
176
|
+
export function buildPlanningUserMessage(brief, characters, beatBlock) {
|
|
177
|
+
const sorted = [...characters].sort((a, b) => a.slot.localeCompare(b.slot));
|
|
178
|
+
const castLines = sorted.length === 0
|
|
179
|
+
? ["(none)"]
|
|
180
|
+
: sorted.map((c) => `${c.slot}) ${c.name}: ${c.bible}`);
|
|
181
|
+
const parts = [
|
|
182
|
+
"BRIEF:",
|
|
183
|
+
brief.trim(),
|
|
184
|
+
"",
|
|
185
|
+
"CAST LOADED FOR THIS RENDER:",
|
|
186
|
+
...castLines,
|
|
187
|
+
"",
|
|
188
|
+
];
|
|
189
|
+
// Beat-synced timing block (built by beat-timing.buildBeatTimingBlock when
|
|
190
|
+
// the request carried an audio beat plan). It pins the shot count, so it
|
|
191
|
+
// goes BEFORE the final instruction the model acts on.
|
|
192
|
+
if (beatBlock && beatBlock.trim().length > 0) {
|
|
193
|
+
parts.push(beatBlock.trim(), "");
|
|
194
|
+
}
|
|
195
|
+
parts.push("Plan the storyboard and return the JSON now.");
|
|
196
|
+
return parts.join("\n");
|
|
197
|
+
}
|
|
198
|
+
// ---------- Refinement chat (v0.50.0) ----------
|
|
199
|
+
//
|
|
200
|
+
// The plan route is single-shot: brief in, storyboard out. /api/storyboard/refine
|
|
201
|
+
// is the iterative path: take the current storyboard plus a free-form user
|
|
202
|
+
// message ("make scene 2 darker", "add a fight before the ending", etc.) and
|
|
203
|
+
// return a new storyboard with the change applied. Each request is stateless
|
|
204
|
+
// from the model's perspective: the current storyboard is the entire state,
|
|
205
|
+
// and the user message is the delta to apply. The frontend keeps a chat
|
|
206
|
+
// history for display but does not replay it to the model; the assumption is
|
|
207
|
+
// that the storyboard already reflects all prior accepted changes.
|
|
208
|
+
export function buildRefinementSystemPrompt() {
|
|
209
|
+
return `You are refining an existing storyboard for a music-video / short-film AI
|
|
210
|
+
pipeline. The user will request specific changes (add a scene, rewrite a
|
|
211
|
+
prompt, shorten a shot, swap which character appears, etc.). Apply EXACTLY
|
|
212
|
+
the requested change and PRESERVE everything else unchanged. Return ONE
|
|
213
|
+
JSON object matching the same schema the planner uses:
|
|
214
|
+
|
|
215
|
+
{
|
|
216
|
+
"title": string,
|
|
217
|
+
"full_prompt": string,
|
|
218
|
+
"duration_seconds": number,
|
|
219
|
+
"clip_seconds": number,
|
|
220
|
+
"style_prefix": string,
|
|
221
|
+
"style_category": string,
|
|
222
|
+
"style_preset": string,
|
|
223
|
+
"use_characters": ["A" | "B" | "C" | "D", ...],
|
|
224
|
+
"cast_rules": string,
|
|
225
|
+
"scenes": [
|
|
226
|
+
{
|
|
227
|
+
"prompt": string,
|
|
228
|
+
"character_slots": ["A" | "B" | "C" | "D", ...],
|
|
229
|
+
"act": string,
|
|
230
|
+
"start": number,
|
|
231
|
+
"end": number,
|
|
232
|
+
"target_seconds": number,
|
|
233
|
+
"dialogue": { "slot": "A" | "B" | "C" | "D", "text": string }
|
|
234
|
+
},
|
|
235
|
+
...
|
|
236
|
+
]
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
REFINEMENT RULES:
|
|
240
|
+
- If the user is silent about a field, KEEP THE OLD VALUE BIT-FOR-BIT.
|
|
241
|
+
Do not paraphrase prompts the user did not ask you to touch. Do not
|
|
242
|
+
re-tune target_seconds the user did not mention. Stability matters.
|
|
243
|
+
- If the user asks for a new scene, place it at the position they request
|
|
244
|
+
("before the ending", "after scene 2", "first"); when ambiguous, append.
|
|
245
|
+
- If the user asks to delete a scene, remove the entry; preserve the order
|
|
246
|
+
of the remaining scenes.
|
|
247
|
+
- character_slots on each scene must be a subset of use_characters. If
|
|
248
|
+
the user adds a new character or removes one, also update use_characters.
|
|
249
|
+
- dialogue: KEEP each scene's existing dialogue bit-for-bit unless the user
|
|
250
|
+
asks to change it. When you do edit or add a line, dialogue.slot must be
|
|
251
|
+
one of that scene's character_slots, "text" is plain spoken words (no
|
|
252
|
+
quotes, no speaker prefix), and at most ${DIALOGUE_MAX_CHARS} characters.
|
|
253
|
+
- style_prefix carries ALL style language. Do not add style words to
|
|
254
|
+
individual scene prompts; the renderer prepends style_prefix to every
|
|
255
|
+
scene at manifest-build time, so style words inside a scene double-apply.
|
|
256
|
+
- style_category and style_preset are "None" literal strings unless the
|
|
257
|
+
user explicitly names a category / preset. Never null. Never empty.
|
|
258
|
+
|
|
259
|
+
LENGTH CAPS (same caps as the planner; the renderer rejects outputs
|
|
260
|
+
over these because they overflow SDXL's CLIP 77-token text encoder):
|
|
261
|
+
- Each scenes[].prompt: at most ${SCENE_PROMPT_MAX_WORDS} words. If the
|
|
262
|
+
user asks you to add detail to a scene, tighten the existing wording
|
|
263
|
+
rather than letting the word count drift past the cap.
|
|
264
|
+
- style_prefix: at most ${STYLE_PREFIX_MAX_CHARS} characters. If the user
|
|
265
|
+
asks to expand the style, compress earlier clauses to make room.
|
|
266
|
+
- full_prompt: at most ${FULL_PROMPT_MAX_CHARS} characters.
|
|
267
|
+
- scenes array length: at most ${STORYBOARD_MAX_SCENES} entries. If the
|
|
268
|
+
user asks for more shots than the cap allows, add as many as fit
|
|
269
|
+
under the cap and keep the remaining requested scenes for a future
|
|
270
|
+
refinement turn; never let the array exceed the cap.
|
|
271
|
+
|
|
272
|
+
CANONICAL SHAPE (any new or edited scene must match this style;
|
|
273
|
+
mirrors the renderer's storyboard.example.yaml):
|
|
274
|
+
|
|
275
|
+
{
|
|
276
|
+
"scenes": [
|
|
277
|
+
{
|
|
278
|
+
"prompt": "Wide establishing shot of a quiet hilltop at dawn, mist over the valley below.",
|
|
279
|
+
"act": "opening"
|
|
280
|
+
},
|
|
281
|
+
{
|
|
282
|
+
"prompt": "Elena walks into frame from the left, looks out over the valley, wind in her coat.",
|
|
283
|
+
"character_slots": ["A"],
|
|
284
|
+
"act": "rising"
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
"prompt": "Close-up on Elena's face, soft side light, expression of quiet resolve, eyes catching the last warm light.",
|
|
288
|
+
"character_slots": ["A"],
|
|
289
|
+
"act": "turn"
|
|
290
|
+
}
|
|
291
|
+
]
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
What that example demonstrates:
|
|
295
|
+
- Each prompt is ~15-25 words; subject + action + framing + one beat
|
|
296
|
+
of mood. No style language, no appearance descriptors.
|
|
297
|
+
- Cast referenced by NAME in prose; slot id only in character_slots.
|
|
298
|
+
- character_slots omitted entirely for empty-frame shots (don't send
|
|
299
|
+
an empty array).
|
|
300
|
+
- act tags lowercase: opening / rising / turn / climax / resolution.
|
|
301
|
+
|
|
302
|
+
Return ONLY the JSON object. No prose, no markdown, no fences.`;
|
|
303
|
+
}
|
|
304
|
+
export function buildRefinementUserMessage(currentStoryboard, message) {
|
|
305
|
+
return [
|
|
306
|
+
"CURRENT STORYBOARD:",
|
|
307
|
+
JSON.stringify(currentStoryboard, null, 2),
|
|
308
|
+
"",
|
|
309
|
+
"USER REQUEST:",
|
|
310
|
+
message.trim(),
|
|
311
|
+
"",
|
|
312
|
+
"Return the updated storyboard JSON now.",
|
|
313
|
+
].join("\n");
|
|
314
|
+
}
|
|
315
|
+
// Pulls a JSON object out of a model completion. Handles:
|
|
316
|
+
// - bare JSON;
|
|
317
|
+
// - one or more ```json (or bare ```) code fences (prefers the LAST fence,
|
|
318
|
+
// because models often give an example block before the final answer);
|
|
319
|
+
// - prose before or after the JSON / fence.
|
|
320
|
+
// Returns the input unchanged when no JSON-looking content is found, so
|
|
321
|
+
// JSON.parse downstream surfaces a clear error.
|
|
322
|
+
export function stripJsonFences(raw) {
|
|
323
|
+
let s = raw.trim();
|
|
324
|
+
const fences = [...s.matchAll(/```(?:json)?\s*([\s\S]*?)```/g)];
|
|
325
|
+
if (fences.length > 0) {
|
|
326
|
+
s = fences[fences.length - 1][1];
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
const firstBrace = s.indexOf("{");
|
|
330
|
+
const lastBrace = s.lastIndexOf("}");
|
|
331
|
+
if (firstBrace !== -1 && lastBrace !== -1 && lastBrace > firstBrace) {
|
|
332
|
+
s = s.slice(firstBrace, lastBrace + 1);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return s.trim();
|
|
336
|
+
}
|
|
337
|
+
//# sourceMappingURL=planner-prompt.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planner-prompt.js","sourceRoot":"","sources":["../src/planner-prompt.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { StoryboardValidated } from "./storyboard-validate.js";
|
|
2
|
+
export { parseShotDurations } from "./shot-durations-parse.js";
|
|
3
|
+
export interface ParsedBundleScene {
|
|
4
|
+
shot_id: string;
|
|
5
|
+
prompt: string;
|
|
6
|
+
seconds: number;
|
|
7
|
+
dialogue?: {
|
|
8
|
+
slot: string;
|
|
9
|
+
text: string;
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
/** Extract { shot_id, prompt, seconds } from an emitted storyboard.yaml. */
|
|
13
|
+
export declare function parseStoryboardScenes(yaml: string, defaultSeconds?: number): ParsedBundleScene[];
|
|
14
|
+
export declare function serializeStoryboardYaml(value: StoryboardValidated): string;
|
|
15
|
+
//# sourceMappingURL=planner-yaml.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planner-yaml.d.ts","sourceRoot":"","sources":["../src/planner-yaml.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAEV,mBAAmB,EACpB,MAAM,0BAA0B,CAAC;AAElC,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAoD/D,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAIhB,QAAQ,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3C;AAED,4EAA4E;AAC5E,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,cAAc,SAAI,GAAG,iBAAiB,EAAE,CA4D3F;AAED,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,mBAAmB,GAAG,MAAM,CA4B1E"}
|