@nodaro/shared 1.7.0 → 1.10.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 +272 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +148 -40
- package/dist/index.d.ts +148 -40
- package/dist/index.js +259 -29
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/credit-identifiers.test.ts +2 -0
- package/src/__tests__/image-ref-limit.test.ts +2 -0
- package/src/__tests__/llm-models.test.ts +101 -9
- 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/index.ts +16 -0
- package/src/llm-models.ts +191 -15
- package/src/model-catalog.ts +64 -9
- package/src/model-constants.ts +62 -4
- package/src/node-default-mappings.ts +3 -0
- package/src/node-mappable-fields.ts +6 -0
- package/src/producer-types.ts +10 -0
- package/src/selector.ts +10 -1
- package/src/video-analysis-pricing.ts +14 -10
- package/src/video-analysis.ts +12 -4
package/src/model-catalog.ts
CHANGED
|
@@ -146,7 +146,7 @@ export const MODEL_RECOMMENDATIONS: readonly ModelRecommendation[] = [
|
|
|
146
146
|
{ intent: "best for typography / logos / text-heavy", modelIds: ["nano-banana-pro", "gpt-image-2"], note: "Nano Banana Pro for diagrams / complex text; GPT Image 2 for logos and short copy." },
|
|
147
147
|
{ intent: "cheapest realistic image", modelIds: ["z-image", "qwen", "imagen4-fast"], note: "Z-Image is the cheapest at 1 credit. Qwen / Imagen4 Fast for slightly higher quality." },
|
|
148
148
|
{ intent: "highest fidelity image", modelIds: ["nano-banana-pro", "imagen4-ultra", "flux-flex"], note: "Pick by family preference; all three are premium tiers." },
|
|
149
|
-
{ intent: "image edit / restyle", modelIds: ["flux-kontext", "ideogram-remix", "seedream-5-
|
|
149
|
+
{ intent: "image edit / restyle", modelIds: ["flux-kontext", "ideogram-remix", "seedream-5-pro-i2i"], note: "Flux Kontext preserves identity; Ideogram Remix is character-aware; Seedream 5 Pro for instruction-based edits (5 Lite is the budget option)." },
|
|
150
150
|
{ intent: "highest-resolution image (4K / 8K)", modelIds: ["topaz-image-upscale", "nano-banana-pro", "gpt-image-2"], note: "Generate at native then Topaz upscale for 8K." },
|
|
151
151
|
{ intent: "background removal / cutout", modelIds: ["recraft-remove-bg"], note: "1 credit, no prompt needed." },
|
|
152
152
|
// video
|
|
@@ -165,6 +165,11 @@ export const MODEL_RECOMMENDATIONS: readonly ModelRecommendation[] = [
|
|
|
165
165
|
// can consume them. Keep in sync when adding a new ratio set.)
|
|
166
166
|
// =============================================================================
|
|
167
167
|
const NANO_BANANA_RATIOS = ["1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3", "4:5", "5:4", "21:9"] as const
|
|
168
|
+
// Nano Banana 2 Lite only — the model's full documented enum incl. `auto`
|
|
169
|
+
// (native default) and extreme banner ratios (docs.kie.ai/market/google/
|
|
170
|
+
// nano-banana-2-lite). Kept separate so the wider set can't leak to the
|
|
171
|
+
// rest of the family.
|
|
172
|
+
const NANO_BANANA_2_LITE_RATIOS = ["auto", "1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3", "4:5", "5:4", "21:9", "4:1", "1:4", "8:1", "1:8"] as const
|
|
168
173
|
// Note: these arrays are synchronized with the frontend's
|
|
169
174
|
// `model-options.ts` constants of the same names. The frontend now imports
|
|
170
175
|
// them via the `getAspectRatioOptions(modelId)` helper; if you update one
|
|
@@ -233,6 +238,22 @@ const IMAGE_MODELS: Record<string, ModelCatalogEntry> = {
|
|
|
233
238
|
{ identifier: "nano-banana-2:4K", credits: 5, note: "4K" },
|
|
234
239
|
],
|
|
235
240
|
},
|
|
241
|
+
"nano-banana-2-lite": {
|
|
242
|
+
id: "nano-banana-2-lite",
|
|
243
|
+
kind: "image",
|
|
244
|
+
// Same single-id shape as nano-banana-2: optional input images on the one
|
|
245
|
+
// endpoint (via image_urls, up to 10), so reachable for both t2i and i2i.
|
|
246
|
+
modes: ["t2i", "i2i"] as const,
|
|
247
|
+
family: "Google",
|
|
248
|
+
label: "Nano Banana 2 Lite",
|
|
249
|
+
series: "Nano Banana",
|
|
250
|
+
description: "Lightweight Nano Banana 2 (Gemini 3.1 Flash-Lite) — fast, low-cost 1K generation and editing.",
|
|
251
|
+
useCases: ["realistic", "drafts", "iteration"],
|
|
252
|
+
features: ["reference-image"],
|
|
253
|
+
aspectRatios: NANO_BANANA_2_LITE_RATIOS,
|
|
254
|
+
// 1K only — no resolution lever, flat pricing.
|
|
255
|
+
pricing: [{ identifier: "nano-banana-2-lite", credits: 2, note: "1K flat" }],
|
|
256
|
+
},
|
|
236
257
|
"nano-banana-pro": {
|
|
237
258
|
id: "nano-banana-pro",
|
|
238
259
|
kind: "image",
|
|
@@ -691,6 +712,40 @@ const IMAGE_MODELS: Record<string, ModelCatalogEntry> = {
|
|
|
691
712
|
{ identifier: "seedream-5-lite-i2i:high", credits: 5, note: "high quality" },
|
|
692
713
|
],
|
|
693
714
|
},
|
|
715
|
+
"seedream-5-pro": {
|
|
716
|
+
id: "seedream-5-pro",
|
|
717
|
+
kind: "image",
|
|
718
|
+
modes: ["t2i"] as const,
|
|
719
|
+
family: "Bytedance",
|
|
720
|
+
label: "Seedream 5 Pro",
|
|
721
|
+
series: "Seedream",
|
|
722
|
+
description: "Flagship Seedream 5 Pro — strongest instruction following and visual reasoning. Basic = 1K, high = 2K.",
|
|
723
|
+
useCases: ["realistic", "instruction"],
|
|
724
|
+
features: ["reference-image"],
|
|
725
|
+
aspectRatios: SEEDREAM_RATIOS,
|
|
726
|
+
qualities: ["basic", "high"],
|
|
727
|
+
pricing: [
|
|
728
|
+
{ identifier: "seedream-5-pro", credits: 3, note: "basic / 1K default" },
|
|
729
|
+
{ identifier: "seedream-5-pro:high", credits: 6, note: "high / 2K" },
|
|
730
|
+
],
|
|
731
|
+
},
|
|
732
|
+
"seedream-5-pro-i2i": {
|
|
733
|
+
id: "seedream-5-pro-i2i",
|
|
734
|
+
kind: "image",
|
|
735
|
+
modes: ["i2i"] as const,
|
|
736
|
+
family: "Bytedance",
|
|
737
|
+
label: "Seedream 5 Pro (I2I)",
|
|
738
|
+
series: "Seedream",
|
|
739
|
+
description: "Image-to-image with Seedream 5 Pro — multi-reference instruction edits. Basic = 1K, high = 2K.",
|
|
740
|
+
useCases: ["edit", "instruction"],
|
|
741
|
+
features: ["reference-image"],
|
|
742
|
+
aspectRatios: SEEDREAM_RATIOS,
|
|
743
|
+
qualities: ["basic", "high"],
|
|
744
|
+
pricing: [
|
|
745
|
+
{ identifier: "seedream-5-pro-i2i", credits: 3, note: "basic / 1K default" },
|
|
746
|
+
{ identifier: "seedream-5-pro-i2i:high", credits: 6, note: "high / 2K" },
|
|
747
|
+
],
|
|
748
|
+
},
|
|
694
749
|
|
|
695
750
|
// ── Alibaba Qwen ──
|
|
696
751
|
"qwen": {
|
|
@@ -1754,10 +1809,10 @@ const VIDEO_MODELS: Record<string, ModelCatalogEntry> = {
|
|
|
1754
1809
|
id: "gemini-3-flash-video-analysis",
|
|
1755
1810
|
kind: "video",
|
|
1756
1811
|
modes: ["video-analysis"] as const,
|
|
1757
|
-
family: "
|
|
1758
|
-
label: "Video Analysis (
|
|
1759
|
-
series: "
|
|
1760
|
-
description: "Analyze a video into a structured shot list (scenes, camera, audio) — fast
|
|
1812
|
+
family: "Nodaro",
|
|
1813
|
+
label: "Video Analysis (Fast)",
|
|
1814
|
+
series: "Video Analysis",
|
|
1815
|
+
description: "Analyze a video into a structured shot list (scenes, camera, audio) — fast, economy tier. Billed per duration bucket.",
|
|
1761
1816
|
useCases: ["video-analysis", "shot-list", "fast"],
|
|
1762
1817
|
pricing: [
|
|
1763
1818
|
{ identifier: "video-analysis:gemini-3-flash", credits: 3, note: "10-min ceiling (no duration given)" },
|
|
@@ -1771,10 +1826,10 @@ const VIDEO_MODELS: Record<string, ModelCatalogEntry> = {
|
|
|
1771
1826
|
id: "gemini-3.1-pro-video-analysis",
|
|
1772
1827
|
kind: "video",
|
|
1773
1828
|
modes: ["video-analysis"] as const,
|
|
1774
|
-
family: "
|
|
1775
|
-
label: "Video Analysis (
|
|
1776
|
-
series: "
|
|
1777
|
-
description: "Analyze a video into a structured shot list (scenes, camera, audio) —
|
|
1829
|
+
family: "Nodaro",
|
|
1830
|
+
label: "Video Analysis (Pro)",
|
|
1831
|
+
series: "Video Analysis",
|
|
1832
|
+
description: "Analyze a video into a structured shot list (scenes, camera, audio) — higher-fidelity, default tier. Billed per duration bucket.",
|
|
1778
1833
|
useCases: ["video-analysis", "shot-list", "cinematic"],
|
|
1779
1834
|
pricing: [
|
|
1780
1835
|
{ identifier: "video-analysis:gemini-3.1-pro", credits: 11, note: "10-min ceiling (no duration given)" },
|
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):
|
|
@@ -1139,12 +1190,19 @@ export const SEEDANCE_2_REF_LIMITS = {
|
|
|
1139
1190
|
* boundary clicks without shifting sync (combineVideos cut+crossfade path).
|
|
1140
1191
|
*/
|
|
1141
1192
|
export const SEEDANCE_2_EXTEND_STITCH = {
|
|
1142
|
-
/** Frames dropped from the END of the source clip
|
|
1193
|
+
/** Frames dropped from the END of the source clip (smart-cut FALLBACK —
|
|
1194
|
+
* used only when the PSNR boundary matcher finds no genuine match). */
|
|
1143
1195
|
trimTailFrames: 4,
|
|
1144
|
-
/** Frames dropped from the START of the generated extension
|
|
1196
|
+
/** Frames dropped from the START of the generated extension (smart-cut
|
|
1197
|
+
* fallback, see above). */
|
|
1145
1198
|
trimHeadFrames: 3,
|
|
1146
1199
|
/** Boundary audio fade length (seconds), timeline-preserving. */
|
|
1147
1200
|
audioFadeSec: 0.15,
|
|
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,
|
|
1148
1206
|
} as const
|
|
1149
1207
|
|
|
1150
1208
|
/**
|
|
@@ -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(
|
|
@@ -15,6 +15,12 @@ export const NODE_MAPPABLE_FIELDS: Readonly<Record<string, readonly string[]>> =
|
|
|
15
15
|
// for back-compat with un-migrated workflow JSON). Mirrors text-to-video so
|
|
16
16
|
// fieldMappings/{} injection AND missing-ref detection work on the live node.
|
|
17
17
|
"generate-video": ["prompt", "negativePrompt"],
|
|
18
|
+
// Trimmed multi-segment stitch variant of generate-video — prompt only, no
|
|
19
|
+
// negativePrompt field on the node.
|
|
20
|
+
"generate-video-pro": ["prompt"],
|
|
21
|
+
// Span-replace sibling of generate-video-pro — prompt only, no
|
|
22
|
+
// negativePrompt field on the node.
|
|
23
|
+
"edit-video-pro": ["prompt"],
|
|
18
24
|
"video-analysis": ["analysisFocus", "youtubeUrl"],
|
|
19
25
|
"video-to-video": ["prompt"],
|
|
20
26
|
"text-to-speech": ["directText"],
|
package/src/producer-types.ts
CHANGED
|
@@ -30,6 +30,16 @@ export const VIDEO_PRODUCER_TYPES: ReadonlySet<string> = new Set([
|
|
|
30
30
|
// through to the imageUrl/videoUrl/audioUrl/text default and downstream consumers
|
|
31
31
|
// could silently misroute the output.
|
|
32
32
|
"generate-video",
|
|
33
|
+
// Generate Video Pro — Seedance-2-family multi-segment stitch variant of
|
|
34
|
+
// generate-video (same "emits videoUrl" contract; a trimmed provider +
|
|
35
|
+
// handle set). Must mirror generate-video here or its output can't connect
|
|
36
|
+
// downstream (the recurring "cannot connect the outputs" bug class).
|
|
37
|
+
"generate-video-pro",
|
|
38
|
+
// Edit Video Pro — Seedance-2-family span-replace sibling of generate-
|
|
39
|
+
// video-pro (same "emits videoUrl" contract; source video + prompt in,
|
|
40
|
+
// ONE video out). Must mirror generate-video-pro here or its output can't
|
|
41
|
+
// connect downstream (the recurring "cannot connect the outputs" bug class).
|
|
42
|
+
"edit-video-pro",
|
|
33
43
|
"upload-video",
|
|
34
44
|
"youtube-video",
|
|
35
45
|
"combine-videos",
|
package/src/selector.ts
CHANGED
|
@@ -706,7 +706,16 @@ export function applyRangeIndices(
|
|
|
706
706
|
return result
|
|
707
707
|
}
|
|
708
708
|
|
|
709
|
-
/** mulberry32 PRNG — deterministic given a seed (any 32-bit signed integer).
|
|
709
|
+
/** mulberry32 PRNG — deterministic given a seed (any 32-bit signed integer).
|
|
710
|
+
*
|
|
711
|
+
* TWIN WARNING: backend/src/providers/video/audio-fx.ts carries its own
|
|
712
|
+
* private mulberry32 (cosmetically different — `>>> 0` seed masking — but the
|
|
713
|
+
* same sequence). The two are deliberately INDEPENDENT and both frozen: the
|
|
714
|
+
* audio-fx copy seeds every reverb impulse response that the committed
|
|
715
|
+
* characterization goldens (and every customer's rendered reverb waveform)
|
|
716
|
+
* are pinned to. Do NOT "deduplicate" them into one shared export or "sync"
|
|
717
|
+
* one to match the other — a change to either sequence is a silent behavior
|
|
718
|
+
* change in its domain. */
|
|
710
719
|
function mulberry32(seed: number): () => number {
|
|
711
720
|
let a = seed | 0
|
|
712
721
|
return () => {
|
|
@@ -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" })
|