@nodaro/shared 1.9.0 → 1.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +142 -25
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +140 -46
- package/dist/index.d.ts +140 -46
- package/dist/index.js +133 -26
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/credit-identifiers.test.ts +26 -12
- package/src/__tests__/image-ref-limit.test.ts +2 -0
- package/src/__tests__/llm-models.test.ts +10 -3
- package/src/__tests__/prompt-length-limits.test.ts +3 -0
- package/src/__tests__/seedance2-continuation-ref.test.ts +24 -0
- package/src/__tests__/video-analysis-pricing.test.ts +28 -5
- package/src/__tests__/video-analysis.test.ts +1 -1
- package/src/__tests__/video-audio-capability.test.ts +34 -6
- package/src/credit-identifiers.ts +8 -2
- package/src/index.ts +11 -0
- package/src/llm-models.ts +52 -9
- package/src/model-catalog.ts +64 -9
- package/src/model-constants.ts +94 -16
- package/src/node-default-mappings.ts +3 -0
- package/src/video-analysis-pricing.ts +14 -10
- package/src/video-analysis.ts +12 -4
package/src/model-constants.ts
CHANGED
|
@@ -37,6 +37,7 @@ export const IMAGE_PROMPT_MAX = 5000
|
|
|
37
37
|
export const MAX_IMAGE_PROMPT_CHARS_BY_PROVIDER: Record<string, number> = {
|
|
38
38
|
// ── higher than the 5000 default ──
|
|
39
39
|
"nano-banana-2": 20000, // docs.kie.ai/market/google/nano-banana-2
|
|
40
|
+
"nano-banana-2-lite": 20000, // docs.kie.ai/market/google/nano-banana-2-lite
|
|
40
41
|
"nano-banana-pro": 20000, // docs.kie.ai/market/google/pro-image-to-image
|
|
41
42
|
"gpt-image-2-i2i": 20000, // docs.kie.ai/market/gpt/gpt-image-2-image-to-image
|
|
42
43
|
// ── lower than the 5000 default (over-send risk if left at default) ──
|
|
@@ -48,7 +49,8 @@ export const MAX_IMAGE_PROMPT_CHARS_BY_PROVIDER: Record<string, number> = {
|
|
|
48
49
|
"qwen-edit": 2000, // docs.kie.ai/market/qwen/image-edit
|
|
49
50
|
// verified == 5000 default (no entry needed): imagen4(-fast/-ultra), nano-banana,
|
|
50
51
|
// nano-banana-edit, flux, flux-flex, gpt-image-2, ideogram-v3/-edit/-remix,
|
|
51
|
-
// z-image, grok, qwen-i2i
|
|
52
|
+
// z-image, grok, qwen-i2i, seedream-5-pro, seedream-5-pro-i2i
|
|
53
|
+
// (docs.kie.ai/market/seedream/5-pro-text-to-image + 5-pro-image-to-image).
|
|
52
54
|
// grok-i2i: doc states 390000 (78× its t2i sibling) — treated as a KIE schema
|
|
53
55
|
// typo and left at the 5000 default per the sanity-cap decision.
|
|
54
56
|
// UNVERIFIED (no limit stated in schema) → 5000 default: flux-kontext(-max)
|
|
@@ -93,6 +95,18 @@ export const SUNO_TEXT_MAX = 5000
|
|
|
93
95
|
*/
|
|
94
96
|
export const PROMPT_HARD_CEILING = 20000
|
|
95
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Ceiling for LLM TEXT-generation node inputs (the "Generate Text"/llm-chat node
|
|
100
|
+
* + AI Writer + Generate Script `systemPrompt`/`userInput`/`prompt` fields).
|
|
101
|
+
* Distinct from PROMPT_HARD_CEILING (an image/video PROMPT budget): these inputs
|
|
102
|
+
* go straight into an LLM whose context is huge (Claude 200K / GPT 128K+ /
|
|
103
|
+
* Gemini 1M tokens), so the old flat 10000 was a false blocker on pasting a
|
|
104
|
+
* document to summarize or rewrite. 100000 chars (~25K input tokens) covers
|
|
105
|
+
* long-form inputs while still bounding abuse; the OUTPUT stays capped by each
|
|
106
|
+
* route's maxTokens.
|
|
107
|
+
*/
|
|
108
|
+
export const LLM_TEXT_INPUT_MAX = 100_000
|
|
109
|
+
|
|
96
110
|
/**
|
|
97
111
|
* Per-provider maximum VIDEO prompt length (chars), VERIFIED against each model's
|
|
98
112
|
* official docs.kie.ai schema (2026-06). Absent → {@link VIDEO_PROMPT_MAX} (8000)
|
|
@@ -333,6 +347,7 @@ export const MODELS_WITH_REFERENCE_IMAGE_SUPPORT = new Set([
|
|
|
333
347
|
"nano-banana",
|
|
334
348
|
"nano-banana-pro",
|
|
335
349
|
"nano-banana-2",
|
|
350
|
+
"nano-banana-2-lite",
|
|
336
351
|
// T2I providers that auto-route to their i2i sibling when refs are attached
|
|
337
352
|
"gpt-image",
|
|
338
353
|
"gpt-image-2",
|
|
@@ -340,6 +355,7 @@ export const MODELS_WITH_REFERENCE_IMAGE_SUPPORT = new Set([
|
|
|
340
355
|
"qwen",
|
|
341
356
|
"seedream",
|
|
342
357
|
"seedream-5-lite",
|
|
358
|
+
"seedream-5-pro",
|
|
343
359
|
"flux",
|
|
344
360
|
"flux-flex",
|
|
345
361
|
// Image editing / image-to-image (reference = source image)
|
|
@@ -357,6 +373,7 @@ export const MODELS_WITH_REFERENCE_IMAGE_SUPPORT = new Set([
|
|
|
357
373
|
"qwen-edit",
|
|
358
374
|
"seedream-edit",
|
|
359
375
|
"seedream-5-lite-i2i",
|
|
376
|
+
"seedream-5-pro-i2i",
|
|
360
377
|
"grok-i2i",
|
|
361
378
|
// Upscale / background ops (source acts as the reference)
|
|
362
379
|
"recraft-remove-bg",
|
|
@@ -386,6 +403,7 @@ export const T2I_TO_I2I_VARIANT: Record<string, string> = {
|
|
|
386
403
|
"qwen": "qwen-i2i",
|
|
387
404
|
"seedream": "seedream-edit",
|
|
388
405
|
"seedream-5-lite": "seedream-5-lite-i2i",
|
|
406
|
+
"seedream-5-pro": "seedream-5-pro-i2i",
|
|
389
407
|
"flux": "flux-pro-i2i",
|
|
390
408
|
"flux-flex": "flux-i2i",
|
|
391
409
|
}
|
|
@@ -405,6 +423,7 @@ export const REF_IMAGE_MAX_LIMITS: Record<string, number> = {
|
|
|
405
423
|
"nano-banana": 8,
|
|
406
424
|
"nano-banana-pro": 8,
|
|
407
425
|
"nano-banana-2": 4,
|
|
426
|
+
"nano-banana-2-lite": 10,
|
|
408
427
|
"wan-2.7": 9,
|
|
409
428
|
// Image-to-image (multi-source array)
|
|
410
429
|
"nano-banana-edit": 8,
|
|
@@ -414,6 +433,7 @@ export const REF_IMAGE_MAX_LIMITS: Record<string, number> = {
|
|
|
414
433
|
"flux-pro-i2i": 4,
|
|
415
434
|
"seedream-edit": 16,
|
|
416
435
|
"seedream-5-lite-i2i": 16,
|
|
436
|
+
"seedream-5-pro-i2i": 16,
|
|
417
437
|
// Single-source i2i (one input image)
|
|
418
438
|
"flux-kontext": 1,
|
|
419
439
|
"flux-kontext-max": 1,
|
|
@@ -484,6 +504,8 @@ export const VARIABLE_PRICING_MODELS: Record<string, "quality" | "resolution" |
|
|
|
484
504
|
"seedream-edit": "quality",
|
|
485
505
|
"seedream-5-lite": "quality",
|
|
486
506
|
"seedream-5-lite-i2i": "quality",
|
|
507
|
+
"seedream-5-pro": "quality",
|
|
508
|
+
"seedream-5-pro-i2i": "quality",
|
|
487
509
|
"topaz-image-upscale": "resolution",
|
|
488
510
|
"ideogram-edit": "rendering-speed",
|
|
489
511
|
"ideogram-remix": "rendering-speed",
|
|
@@ -495,7 +517,7 @@ export const VARIABLE_PRICING_MODELS: Record<string, "quality" | "resolution" |
|
|
|
495
517
|
|
|
496
518
|
|
|
497
519
|
// Models where quality=high triggers composite credit identifier
|
|
498
|
-
export const HIGH_QUALITY_PROVIDERS = new Set(["gpt-image", "gpt-image-i2i", "seedream", "seedream-edit", "seedream-5-lite", "seedream-5-lite-i2i"])
|
|
520
|
+
export const HIGH_QUALITY_PROVIDERS = new Set(["gpt-image", "gpt-image-i2i", "seedream", "seedream-edit", "seedream-5-lite", "seedream-5-lite-i2i", "seedream-5-pro", "seedream-5-pro-i2i"])
|
|
499
521
|
|
|
500
522
|
// Models where resolution=2K triggers composite credit identifier
|
|
501
523
|
export const TWO_K_RESOLUTION_PROVIDERS = new Set(["flux", "flux-pro-i2i", "flux-flex", "flux-i2i"])
|
|
@@ -522,6 +544,7 @@ export const IMAGE_GEN_PROVIDERS = [
|
|
|
522
544
|
"flux",
|
|
523
545
|
"nano-banana-pro",
|
|
524
546
|
"nano-banana-2",
|
|
547
|
+
"nano-banana-2-lite",
|
|
525
548
|
"grok",
|
|
526
549
|
"gpt-image",
|
|
527
550
|
"gpt-image-2",
|
|
@@ -532,6 +555,7 @@ export const IMAGE_GEN_PROVIDERS = [
|
|
|
532
555
|
"qwen",
|
|
533
556
|
"seedream",
|
|
534
557
|
"seedream-5-lite",
|
|
558
|
+
"seedream-5-pro",
|
|
535
559
|
"flux-flex",
|
|
536
560
|
"flux-kontext",
|
|
537
561
|
"flux-kontext-max",
|
|
@@ -548,6 +572,7 @@ export const IMAGE_GEN_PROVIDERS = [
|
|
|
548
572
|
export const IMAGE_I2I_PROVIDERS = [
|
|
549
573
|
"nano-banana",
|
|
550
574
|
"nano-banana-2",
|
|
575
|
+
"nano-banana-2-lite",
|
|
551
576
|
"nano-banana-pro",
|
|
552
577
|
"grok-i2i",
|
|
553
578
|
"flux-i2i",
|
|
@@ -561,6 +586,7 @@ export const IMAGE_I2I_PROVIDERS = [
|
|
|
561
586
|
"qwen-edit",
|
|
562
587
|
"seedream-edit",
|
|
563
588
|
"seedream-5-lite-i2i",
|
|
589
|
+
"seedream-5-pro-i2i",
|
|
564
590
|
"flux-kontext",
|
|
565
591
|
"flux-kontext-max",
|
|
566
592
|
// Replicate Open (uncensored) — multi-image Kontext via Replicate
|
|
@@ -1003,10 +1029,12 @@ export const IMAGE_MASK_MODE: Record<ImageGenProvider, ImageMaskMode> = {
|
|
|
1003
1029
|
"nano-banana": "prompt",
|
|
1004
1030
|
"nano-banana-pro": "prompt",
|
|
1005
1031
|
"nano-banana-2": "prompt",
|
|
1032
|
+
"nano-banana-2-lite": "prompt",
|
|
1006
1033
|
"gpt-image": "prompt",
|
|
1007
1034
|
"gpt-image-2": "prompt",
|
|
1008
1035
|
"seedream": "prompt",
|
|
1009
1036
|
"seedream-5-lite": "prompt",
|
|
1037
|
+
"seedream-5-pro": "prompt",
|
|
1010
1038
|
"qwen": "prompt",
|
|
1011
1039
|
"flux-kontext": "prompt",
|
|
1012
1040
|
"flux-kontext-max": "prompt",
|
|
@@ -1129,6 +1157,29 @@ export const SEEDANCE_2_REF_LIMITS = {
|
|
|
1129
1157
|
audio: 3,
|
|
1130
1158
|
} as const
|
|
1131
1159
|
|
|
1160
|
+
/**
|
|
1161
|
+
* KIE r2v REFERENCE-VIDEO MINIMUM (seconds) for the Seedance 2.0 family — the
|
|
1162
|
+
* provider hard-rejects shorter reference clips with a 400 BEFORE generation:
|
|
1163
|
+
* "the parameter video duration (seconds) specified in the request must be
|
|
1164
|
+
* greater than or equal to 1.8 for model dreamina-seedance-2-0-fast in r2v"
|
|
1165
|
+
* (2026-07-13, job dbf95612 — every 1.0s continuation tail failed
|
|
1166
|
+
* deterministically). Mirror of the reference-AUDIO maximum below.
|
|
1167
|
+
*/
|
|
1168
|
+
export const SEEDANCE_2_R2V_MIN_REF_VIDEO_SEC = 1.8
|
|
1169
|
+
|
|
1170
|
+
/**
|
|
1171
|
+
* The continuation-reference length (seconds) every Seedance-2 chaining
|
|
1172
|
+
* feature actually cuts — extend-node tails, generate-video-pro segment
|
|
1173
|
+
* tails, edit-video-pro refOut/refIn brackets — AND the length the gvp/evp
|
|
1174
|
+
* credit formulas bill per continuation join. Clears the provider floor
|
|
1175
|
+
* above with margin while staying short enough to keep the model focused on
|
|
1176
|
+
* continuing the boundary motion instead of re-staging the whole clip.
|
|
1177
|
+
* Guarded ≥ floor by model-constants tests; the private-plugin twin
|
|
1178
|
+
* (nodaro-cloud-plugins chain.ts TAIL_SEC / bridge-math.ts MIN_REF) is
|
|
1179
|
+
* guarded by that repo's r2v-ref-floor.test.ts — keep the two in sync.
|
|
1180
|
+
*/
|
|
1181
|
+
export const SEEDANCE_2_CONTINUATION_REF_SEC = 2
|
|
1182
|
+
|
|
1132
1183
|
/**
|
|
1133
1184
|
* Trim-stitch parameters for the seedance-2-extend provider (spike-validated
|
|
1134
1185
|
* 2026-06-11):
|
|
@@ -1147,10 +1198,11 @@ export const SEEDANCE_2_EXTEND_STITCH = {
|
|
|
1147
1198
|
trimHeadFrames: 3,
|
|
1148
1199
|
/** Boundary audio fade length (seconds), timeline-preserving. */
|
|
1149
1200
|
audioFadeSec: 0.15,
|
|
1150
|
-
/** Seconds of the source's TAIL passed as the @video_1 reference —
|
|
1151
|
-
*
|
|
1152
|
-
*
|
|
1153
|
-
|
|
1201
|
+
/** Seconds of the source's TAIL passed as the @video_1 reference — short
|
|
1202
|
+
* keeps the model focused on continuing the boundary motion; the value is
|
|
1203
|
+
* floored by SEEDANCE_2_R2V_MIN_REF_VIDEO_SEC (the original spike's 1s
|
|
1204
|
+
* tail is now provider-rejected). */
|
|
1205
|
+
referenceTailSeconds: SEEDANCE_2_CONTINUATION_REF_SEC,
|
|
1154
1206
|
} as const
|
|
1155
1207
|
|
|
1156
1208
|
/**
|
|
@@ -1341,8 +1393,13 @@ export const AUDIO_ADDON_PROVIDERS = new Set([
|
|
|
1341
1393
|
* lip-synced spoken dialogue. Toggle is offered; the
|
|
1342
1394
|
* pipeline still uses TTS + lip-sync for dialogue.
|
|
1343
1395
|
* "native_speech" — bakes spoken dialogue + lip movement from the prompt
|
|
1344
|
-
* (VEO 3.x
|
|
1345
|
-
*
|
|
1396
|
+
* (VEO 3.x always-on; Kling 2.6/3.0 behind the `sound`
|
|
1397
|
+
* toggle — probe-verified 2026-07-16: scripted lines come
|
|
1398
|
+
* back word-for-word with articulated lips on the KIE
|
|
1399
|
+
* path, matching the official Kling 2.6 audio guide and
|
|
1400
|
+
* Kling 3.0 prompting docs). The pipeline injects the
|
|
1401
|
+
* dialogue line, enables audio, and revoices the clip to
|
|
1402
|
+
* the character's saved voice.
|
|
1346
1403
|
* "audio_driven" — lip-syncs to a supplied reference-audio track (Seedance
|
|
1347
1404
|
* 2.0 multimodal). The pipeline synthesises the character's
|
|
1348
1405
|
* voice first, feeds it as reference audio, and skips the
|
|
@@ -1358,6 +1415,14 @@ export interface VideoAudioCapability {
|
|
|
1358
1415
|
alwaysOn?: boolean
|
|
1359
1416
|
/** Enabling audio raises the credit cost (Kling — see AUDIO_ADDON_PROVIDERS). */
|
|
1360
1417
|
affectsCost?: boolean
|
|
1418
|
+
/**
|
|
1419
|
+
* The model generates audio when the caller expresses NO intent (its own
|
|
1420
|
+
* config default is on — kling-3.0's `sound: true`, kling-3-omni's
|
|
1421
|
+
* `generate_audio: true`). The `:audio` credit suffix mirrors this default
|
|
1422
|
+
* so an intent-less request is billed for the audio it actually produces
|
|
1423
|
+
* (see buildVideoCreditModelIdentifier). Absent ⇒ default off.
|
|
1424
|
+
*/
|
|
1425
|
+
defaultOn?: boolean
|
|
1361
1426
|
}
|
|
1362
1427
|
|
|
1363
1428
|
/**
|
|
@@ -1374,9 +1439,22 @@ export const VIDEO_AUDIO_CAPABILITY: Record<string, VideoAudioCapability> = {
|
|
|
1374
1439
|
veo3: { mode: "native_speech", alwaysOn: true },
|
|
1375
1440
|
"veo3.1": { mode: "native_speech", alwaysOn: true },
|
|
1376
1441
|
veo3_lite: { mode: "native_speech", alwaysOn: true },
|
|
1377
|
-
// Kling 2.6 / 3.0 —
|
|
1378
|
-
|
|
1379
|
-
|
|
1442
|
+
// Kling 2.6 / 3.0 — native spoken dialogue + lip sync behind the `sound`
|
|
1443
|
+
// toggle (probe-verified on the KIE path 2026-07-16: scripted quoted lines
|
|
1444
|
+
// are spoken verbatim with articulated lips; the official Kling 2.6 audio
|
|
1445
|
+
// guide documents speech/dialogue/narration/singing with [Character@Voice]
|
|
1446
|
+
// binding, zh+en voices). Cost-affecting: `:audio` credit suffix.
|
|
1447
|
+
// kling-3.0's model default is sound ON (kie models.ts extraParams +
|
|
1448
|
+
// kling3-client `?? true`) → defaultOn keeps billing aligned with what an
|
|
1449
|
+
// intent-less request actually generates; kling 2.6 defaults OFF.
|
|
1450
|
+
kling: { mode: "native_speech", field: "sound", affectsCost: true },
|
|
1451
|
+
"kling-3.0": { mode: "native_speech", field: "sound", affectsCost: true, defaultOn: true },
|
|
1452
|
+
// Kling 3.0 Omni (Replicate kwaivgi/kling-v3-omni-video) — the Omni tier's
|
|
1453
|
+
// headline feature IS native dialogue (per-character voices, unified audio
|
|
1454
|
+
// timeline). Lever is Replicate's `generate_audio` (default true in our
|
|
1455
|
+
// provider config → defaultOn); audio is priced into the flat per-duration
|
|
1456
|
+
// rate, so NOT cost-affecting (no :audio composite).
|
|
1457
|
+
"kling-3-omni": { mode: "native_speech", field: "generateAudio", defaultOn: true },
|
|
1380
1458
|
// Seedance 1.x — optional ambient audio (generate_audio); not dialogue.
|
|
1381
1459
|
seedance: { mode: "ambient", field: "generateAudio" },
|
|
1382
1460
|
// Seedance 2.0 — multimodal; lip-syncs to a supplied reference-audio track.
|
|
@@ -1405,11 +1483,11 @@ export function videoModelSupportsAudio(model: string | undefined): boolean {
|
|
|
1405
1483
|
|
|
1406
1484
|
/**
|
|
1407
1485
|
* True when the model can produce lip-synced spoken DIALOGUE — either natively
|
|
1408
|
-
* (VEO) or driven by a supplied audio track (Seedance
|
|
1409
|
-
* dialogue auto-pick: in-model speech + character
|
|
1410
|
-
* reference audio (Seedance 2.0) vs.
|
|
1411
|
-
* Ambient-only models (
|
|
1412
|
-
* not speech.
|
|
1486
|
+
* (VEO 3.x, Kling 2.6/3.0/Omni) or driven by a supplied audio track (Seedance
|
|
1487
|
+
* 2.0). Drives the Story→Video dialogue auto-pick: in-model speech + character
|
|
1488
|
+
* revoice (VEO, Kling) / character-voiced reference audio (Seedance 2.0) vs.
|
|
1489
|
+
* the TTS + separate-lip-sync fallback. Ambient-only models (Seedance 1.x)
|
|
1490
|
+
* return `false` — their audio is SFX, not speech.
|
|
1413
1491
|
*/
|
|
1414
1492
|
export function videoModelCanSpeakDialogue(model: string | undefined): boolean {
|
|
1415
1493
|
const mode = getVideoAudioCapability(model).mode
|
|
@@ -174,6 +174,8 @@ const QUALITY_MAP: Record<string, QualityMapping> = {
|
|
|
174
174
|
"seedream-edit": { field: "quality", values: { low: "basic", mid: "basic", high: "high" } },
|
|
175
175
|
"seedream-5-lite": { field: "quality", values: { low: "basic", mid: "basic", high: "high" } },
|
|
176
176
|
"seedream-5-lite-i2i": { field: "quality", values: { low: "basic", mid: "basic", high: "high" } },
|
|
177
|
+
"seedream-5-pro": { field: "quality", values: { low: "basic", mid: "basic", high: "high" } },
|
|
178
|
+
"seedream-5-pro-i2i": { field: "quality", values: { low: "basic", mid: "basic", high: "high" } },
|
|
177
179
|
// Video gen — resolution-style (720p/1080p)
|
|
178
180
|
"veo3": { field: "resolution", values: { low: "720p", mid: "1080p", high: "1080p" } },
|
|
179
181
|
"veo3.1": { field: "resolution", values: { low: "720p", mid: "1080p", high: "1080p" } },
|
|
@@ -248,6 +250,7 @@ const GENERATE_IMAGE_PROVIDER_TO_MODEL: Record<string, string> = {
|
|
|
248
250
|
"nano-banana": "gemini-2.5-flash-image",
|
|
249
251
|
"nano-banana-pro": "gemini-2.5-flash-image",
|
|
250
252
|
"nano-banana-2": "gemini-2.5-flash-image",
|
|
253
|
+
"nano-banana-2-lite": "gemini-3.1-flash-lite-image",
|
|
251
254
|
}
|
|
252
255
|
|
|
253
256
|
export function deriveLinkedFields(
|
|
@@ -10,13 +10,16 @@
|
|
|
10
10
|
* these.
|
|
11
11
|
*
|
|
12
12
|
* The measured-rate constants and the $-derived `videoAnalysisBucketCredits`
|
|
13
|
-
* formula live in
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
13
|
+
* formula that GENERATE these numbers live PRIVATELY in the
|
|
14
|
+
* `@nodaroai/cloud-plugins` package (`src/plugins/video-analysis/cost.ts`) —
|
|
15
|
+
* never in this public repo. They were first moved out of this package
|
|
16
|
+
* (published Apache-2.0 on npm) per the 2026-07-06 public-flip IP audit S5,
|
|
17
|
+
* then out of the app repo entirely alongside the rest of the video-analysis
|
|
18
|
+
* node. A cross-check test in that private package guards this table so the
|
|
19
|
+
* public numbers can't silently drift from the formula.
|
|
17
20
|
*
|
|
18
21
|
* `VIDEO_ANALYSIS_BUCKET_CREDITS` below is the precomputed OUTPUT of that
|
|
19
|
-
*
|
|
22
|
+
* private formula for every (model × bucket) combination — a plain credit
|
|
20
23
|
* lookup table, not a formula, mirroring the same wire-contract pattern
|
|
21
24
|
* `VIDEO_CLIP_CREDITS` uses in `film-pricing.ts`. It is what the frontend's
|
|
22
25
|
* client-side cost preview (`estimateNodeCredits` in
|
|
@@ -34,11 +37,12 @@ const WINDOW_LEN = 150, WINDOW_STRIDE = 145, WINDOW_OVERLAP = 5
|
|
|
34
37
|
export const VIDEO_ANALYSIS_WINDOW = { LEN: WINDOW_LEN, STRIDE: WINDOW_STRIDE, OVERLAP: WINDOW_OVERLAP, SINGLE_MAX: 180 } as const
|
|
35
38
|
|
|
36
39
|
/**
|
|
37
|
-
* Precomputed credit cost per (model, bucket) — the OUTPUT of the
|
|
38
|
-
* `videoAnalysisBucketCredits` formula, not a
|
|
39
|
-
* running that function for every
|
|
40
|
-
* bucket combination whenever the
|
|
41
|
-
* (
|
|
40
|
+
* Precomputed credit cost per (model, bucket) — the OUTPUT of the private
|
|
41
|
+
* `videoAnalysisBucketCredits` formula (in `@nodaroai/cloud-plugins`), not a
|
|
42
|
+
* formula itself. Regenerate by running that function for every
|
|
43
|
+
* `VIDEO_ANALYSIS_LLM_MODELS` × duration bucket combination whenever the
|
|
44
|
+
* underlying rate/token constants change (the plugin's cost test guards drift).
|
|
45
|
+
* Keep in sync with
|
|
42
46
|
* `docs/nodes/processing-video/video-analysis.md`.
|
|
43
47
|
*/
|
|
44
48
|
export const VIDEO_ANALYSIS_BUCKET_CREDITS: Record<string, number> = {
|
package/src/video-analysis.ts
CHANGED
|
@@ -34,11 +34,18 @@ export const entitySlotSchema = z.object({
|
|
|
34
34
|
})
|
|
35
35
|
export type EntitySlot = z.infer<typeof entitySlotSchema>
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
/**
|
|
38
|
+
* One concurrent sound layer in a scene. Real footage stacks sound (music bed
|
|
39
|
+
* under dialogue over ambient sfx), so a scene carries an ARRAY of these — an
|
|
40
|
+
* empty array means genuine silence. `content`: speech = verbatim words;
|
|
41
|
+
* music/sfx = gen-ready description. `voice` is speech-only voice-casting.
|
|
42
|
+
*/
|
|
43
|
+
const audioLayerSchema = z.object({
|
|
44
|
+
mode: z.enum(["speech", "music", "sfx"]),
|
|
45
|
+
content: z.string().min(1),
|
|
40
46
|
voice: z.string().optional(),
|
|
41
47
|
})
|
|
48
|
+
export type AudioLayer = z.infer<typeof audioLayerSchema>
|
|
42
49
|
|
|
43
50
|
const windowSceneBase = z.object({
|
|
44
51
|
startSec: z.number().min(0),
|
|
@@ -48,7 +55,8 @@ const windowSceneBase = z.object({
|
|
|
48
55
|
camera: z.string(),
|
|
49
56
|
visual: z.string().min(1),
|
|
50
57
|
transitionOut: z.enum(["cut", "fade", "wipe", "whip"]).optional(),
|
|
51
|
-
|
|
58
|
+
// Array of concurrent layers (music + speech + sfx together); [] = silence.
|
|
59
|
+
audio: z.array(audioLayerSchema),
|
|
52
60
|
})
|
|
53
61
|
// .strip() (default) drops model-emitted oversized/slotRefs — validator-computed only.
|
|
54
62
|
const windowSceneSchema = windowSceneBase.refine((s) => s.endSec > s.startSec, { message: "endSec must be > startSec" })
|