@nodaro/shared 2.17.0 → 2.19.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 +260 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +111 -6
- package/dist/index.d.ts +111 -6
- package/dist/index.js +251 -15
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/apply-video-negative-prompt.test.ts +38 -1
- package/src/__tests__/credit-identifiers.test.ts +47 -0
- package/src/__tests__/gvp-supported-providers.test.ts +22 -1
- package/src/__tests__/prompt-length-limits.test.ts +4 -0
- package/src/__tests__/video-audio-capability.test.ts +43 -0
- package/src/__tests__/video-mode-for-inputs.test.ts +1 -1
- package/src/__tests__/wan-3-catalog.test.ts +243 -0
- package/src/credit-identifiers.ts +42 -9
- package/src/i18n/held-prop.ar.ts +2 -0
- package/src/i18n/held-prop.de.ts +3 -0
- package/src/i18n/held-prop.es.ts +3 -0
- package/src/i18n/held-prop.fr.ts +2 -0
- package/src/i18n/held-prop.he.ts +3 -0
- package/src/i18n/held-prop.hi.ts +2 -0
- package/src/i18n/held-prop.ja.ts +3 -0
- package/src/i18n/held-prop.ko.ts +3 -0
- package/src/i18n/held-prop.pt-BR.ts +3 -0
- package/src/i18n/held-prop.ru.ts +2 -0
- package/src/i18n/held-prop.zh-CN.ts +3 -0
- package/src/i18n/person.ar.ts +3 -0
- package/src/i18n/person.de.ts +4 -0
- package/src/i18n/person.es.ts +4 -0
- package/src/i18n/person.fr.ts +3 -0
- package/src/i18n/person.he.ts +4 -0
- package/src/i18n/person.hi.ts +3 -0
- package/src/i18n/person.ja.ts +4 -0
- package/src/i18n/person.ko.ts +4 -0
- package/src/i18n/person.pt-BR.ts +4 -0
- package/src/i18n/person.ru.ts +3 -0
- package/src/i18n/person.zh-CN.ts +4 -0
- package/src/i18n/setting.ar.ts +2 -0
- package/src/i18n/setting.de.ts +3 -0
- package/src/i18n/setting.es.ts +3 -0
- package/src/i18n/setting.fr.ts +2 -0
- package/src/i18n/setting.he.ts +3 -0
- package/src/i18n/setting.hi.ts +2 -0
- package/src/i18n/setting.ja.ts +3 -0
- package/src/i18n/setting.ko.ts +3 -0
- package/src/i18n/setting.pt-BR.ts +3 -0
- package/src/i18n/setting.ru.ts +2 -0
- package/src/i18n/setting.zh-CN.ts +3 -0
- package/src/i18n/style.ar.ts +2 -0
- package/src/i18n/style.de.ts +3 -0
- package/src/i18n/style.es.ts +3 -0
- package/src/i18n/style.fr.ts +2 -0
- package/src/i18n/style.he.ts +3 -0
- package/src/i18n/style.hi.ts +2 -0
- package/src/i18n/style.ja.ts +3 -0
- package/src/i18n/style.ko.ts +3 -0
- package/src/i18n/style.pt-BR.ts +3 -0
- package/src/i18n/style.ru.ts +2 -0
- package/src/i18n/style.zh-CN.ts +3 -0
- package/src/i18n/styling.ar.ts +4 -0
- package/src/i18n/styling.de.ts +5 -0
- package/src/i18n/styling.es.ts +5 -0
- package/src/i18n/styling.fr.ts +4 -0
- package/src/i18n/styling.he.ts +5 -0
- package/src/i18n/styling.hi.ts +4 -0
- package/src/i18n/styling.ja.ts +5 -0
- package/src/i18n/styling.ko.ts +5 -0
- package/src/i18n/styling.pt-BR.ts +5 -0
- package/src/i18n/styling.ru.ts +4 -0
- package/src/i18n/styling.zh-CN.ts +5 -0
- package/src/index.ts +10 -0
- package/src/model-catalog.ts +101 -0
- package/src/model-constants.ts +217 -8
- package/src/node-default-mappings.ts +5 -0
- package/src/video-ui-defaults.ts +66 -0
package/src/model-catalog.ts
CHANGED
|
@@ -228,6 +228,12 @@ const VIDEO_RATIOS_SEEDANCE_2 = ["16:9", "9:16", "1:1", "4:3", "3:4", "21:9", "a
|
|
|
228
228
|
// portrait-social and 21:9/9:21 cinematic (docs.kie.ai/market/happyhorse-1-1).
|
|
229
229
|
// Kept separate so the wider set can't leak to models that don't support it.
|
|
230
230
|
const VIDEO_RATIOS_HAPPYHORSE_11 = ["16:9", "9:16", "1:1", "4:3", "3:4", "4:5", "5:4", "21:9", "9:21"] as const
|
|
231
|
+
// Wan 3.0 (standard + Prime) — the model's own six-ratio enum, `adaptive` first
|
|
232
|
+
// because that is the KIE default ("automatically selects the ratio based on the
|
|
233
|
+
// input media and intent"). Deliberately NO 21:9 — the Wan 3.0 enum rejects it,
|
|
234
|
+
// so VIDEO_RATIOS_SEEDANCE_2 must NOT be reused here
|
|
235
|
+
// (docs.kie.ai/market/wan/3-0-video and /3-0-video-prime — identical schemas).
|
|
236
|
+
const VIDEO_RATIOS_WAN_3 = ["adaptive", "16:9", "4:3", "1:1", "3:4", "9:16"] as const
|
|
231
237
|
|
|
232
238
|
// =============================================================================
|
|
233
239
|
// IMAGE MODELS
|
|
@@ -1179,6 +1185,41 @@ const VIDEO_MODELS: Record<string, ModelCatalogEntry> = {
|
|
|
1179
1185
|
{ identifier: "gemini-omni-video:4k:vref", credits: 900, note: "video-edit 4K" },
|
|
1180
1186
|
],
|
|
1181
1187
|
},
|
|
1188
|
+
// Gemini Omni Flash 1.1 — the faster/cheaper Omni SKU (KIE
|
|
1189
|
+
// `google/gemini-omni-flash-1-1`). Identical request surface to
|
|
1190
|
+
// gemini-omni-video, so every capability below is deliberate PARITY with the
|
|
1191
|
+
// sibling: same 4/6/8/10s ladder, same 720p/1080p + 4K bands, same
|
|
1192
|
+
// features (the KIE schema also exposes first/last frame, but the pro
|
|
1193
|
+
// sibling's frame path is unwired here too — no "end-frame" until it is).
|
|
1194
|
+
// 360p is on the KIE enum but NOT exposed: it sits in the same credit band as
|
|
1195
|
+
// 720p/1080p, so it could only hand the user a worse render at the same price.
|
|
1196
|
+
"gemini-omni-flash": {
|
|
1197
|
+
id: "gemini-omni-flash",
|
|
1198
|
+
kind: "video",
|
|
1199
|
+
modes: ["i2v", "t2v"] as const, // V2V is served via the i2v handle, not a catalog mode
|
|
1200
|
+
family: "Google",
|
|
1201
|
+
label: "Gemini Omni Flash",
|
|
1202
|
+
series: "Gemini",
|
|
1203
|
+
description: "Google Gemini Omni Flash — faster/cheaper Omni tier: multimodal video with native audio, text/image-to-video + video-edit.",
|
|
1204
|
+
useCases: ["cinematic", "fast"],
|
|
1205
|
+
features: ["audio", "reference-image"],
|
|
1206
|
+
aspectRatios: VIDEO_RATIOS_HV,
|
|
1207
|
+
resolutions: ["720p", "1080p", "4k"],
|
|
1208
|
+
durations: [4, 6, 8, 10],
|
|
1209
|
+
pricing: [
|
|
1210
|
+
{ identifier: "gemini-omni-flash", credits: 270, note: "default — 8s 720p/1080p (the credit builder's duration fallback)" },
|
|
1211
|
+
{ identifier: "gemini-omni-flash:4", credits: 160, note: "720p/1080p 4s" },
|
|
1212
|
+
{ identifier: "gemini-omni-flash:6", credits: 210, note: "720p/1080p 6s" },
|
|
1213
|
+
{ identifier: "gemini-omni-flash:8", credits: 270, note: "720p/1080p 8s" },
|
|
1214
|
+
{ identifier: "gemini-omni-flash:10", credits: 320, note: "720p/1080p 10s" },
|
|
1215
|
+
{ identifier: "gemini-omni-flash:4k:4", credits: 370, note: "4K 4s" },
|
|
1216
|
+
{ identifier: "gemini-omni-flash:4k:6", credits: 420, note: "4K 6s" },
|
|
1217
|
+
{ identifier: "gemini-omni-flash:4k:8", credits: 480, note: "4K 8s" },
|
|
1218
|
+
{ identifier: "gemini-omni-flash:4k:10", credits: 530, note: "4K 10s" },
|
|
1219
|
+
{ identifier: "gemini-omni-flash:vref", credits: 420, note: "video-edit 720p/1080p" },
|
|
1220
|
+
{ identifier: "gemini-omni-flash:4k:vref", credits: 630, note: "video-edit 4K" },
|
|
1221
|
+
],
|
|
1222
|
+
},
|
|
1182
1223
|
|
|
1183
1224
|
// ── Kling ──
|
|
1184
1225
|
"kling": {
|
|
@@ -1450,6 +1491,66 @@ const VIDEO_MODELS: Record<string, ModelCatalogEntry> = {
|
|
|
1450
1491
|
},
|
|
1451
1492
|
|
|
1452
1493
|
// ── Wan ──
|
|
1494
|
+
// Wan 3.0 (standard + Prime) — a NEW generation, not a tier of the 2.x ladder.
|
|
1495
|
+
// One id per SKU serves BOTH modes (no t2v twin, no alias): first/last frame
|
|
1496
|
+
// OR an all-purpose reference mode (images/videos/audio, bound in the prompt
|
|
1497
|
+
// as Image1/Video1/Audio1 — no space, unlike Wan 2.x), native audio behind a
|
|
1498
|
+
// boolean `audio` lever, 2-30s at 480p/720p/1080p.
|
|
1499
|
+
// `video-reference` is deliberately NOT declared: KIE accepts reference videos,
|
|
1500
|
+
// but the extend chain is unwired and KIE caps input-video + output at 30s,
|
|
1501
|
+
// which the segment bounds cannot express. Precedent: gemini-omni-video carries
|
|
1502
|
+
// ref limits without the feature. The ref CAPS still live in
|
|
1503
|
+
// VIDEO_REF_LIMITS_BY_PROVIDER (model-constants).
|
|
1504
|
+
// `resolutions` is ascending (repo convention); the DEFAULT tier (720p) is
|
|
1505
|
+
// declared explicitly in PRICING_DEFAULT_RESOLUTION, never by array position.
|
|
1506
|
+
"wan-3": {
|
|
1507
|
+
id: "wan-3",
|
|
1508
|
+
kind: "video",
|
|
1509
|
+
modes: ["i2v", "t2v"] as const,
|
|
1510
|
+
family: "Alibaba",
|
|
1511
|
+
label: "Wan 3.0",
|
|
1512
|
+
series: "Wan",
|
|
1513
|
+
description: "Wan 3.0 — multimodal: first/last frame or image/video/audio references, native audio, 2-30s at 480p/720p/1080p.",
|
|
1514
|
+
useCases: ["motion", "narrative", "long-form"],
|
|
1515
|
+
features: ["end-frame", "audio", "reference-image"],
|
|
1516
|
+
aspectRatios: VIDEO_RATIOS_WAN_3,
|
|
1517
|
+
durations: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
|
|
1518
|
+
resolutions: ["480p", "720p", "1080p"],
|
|
1519
|
+
pricing: [
|
|
1520
|
+
{ identifier: "wan-3", credits: 200, note: "default 5s 720p — see :Ns:res variants for exact" },
|
|
1521
|
+
{ identifier: "wan-3:5s:720p", credits: 200, note: "5s 720p (the default tier)" },
|
|
1522
|
+
{ identifier: "wan-3:8s:480p", credits: 160, note: "8s 480p" },
|
|
1523
|
+
{ identifier: "wan-3:8s:720p", credits: 320, note: "8s 720p" },
|
|
1524
|
+
{ identifier: "wan-3:8s:1080p", credits: 640, note: "8s 1080p" },
|
|
1525
|
+
{ identifier: "wan-3:30s:480p", credits: 600, note: "30s 480p (max)" },
|
|
1526
|
+
{ identifier: "wan-3:30s:720p", credits: 1200, note: "30s 720p (max)" },
|
|
1527
|
+
{ identifier: "wan-3:30s:1080p", credits: 2400, note: "30s 1080p (max)" },
|
|
1528
|
+
],
|
|
1529
|
+
},
|
|
1530
|
+
"wan-3-prime": {
|
|
1531
|
+
id: "wan-3-prime",
|
|
1532
|
+
kind: "video",
|
|
1533
|
+
modes: ["i2v", "t2v"] as const,
|
|
1534
|
+
family: "Alibaba",
|
|
1535
|
+
label: "Wan 3.0 Prime",
|
|
1536
|
+
series: "Wan",
|
|
1537
|
+
description: "Wan 3.0 Prime — Alibaba's high-speed Wan 3.0 tier: same multimodal surface and 2-30s range, faster turnaround at a higher per-second rate.",
|
|
1538
|
+
useCases: ["fast", "motion", "narrative"],
|
|
1539
|
+
features: ["end-frame", "audio", "reference-image"],
|
|
1540
|
+
aspectRatios: VIDEO_RATIOS_WAN_3,
|
|
1541
|
+
durations: [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
|
|
1542
|
+
resolutions: ["480p", "720p", "1080p"],
|
|
1543
|
+
pricing: [
|
|
1544
|
+
{ identifier: "wan-3-prime", credits: 320, note: "default 5s 720p — see :Ns:res variants for exact" },
|
|
1545
|
+
{ identifier: "wan-3-prime:5s:720p", credits: 320, note: "5s 720p (the default tier)" },
|
|
1546
|
+
{ identifier: "wan-3-prime:8s:480p", credits: 250, note: "8s 480p" },
|
|
1547
|
+
{ identifier: "wan-3-prime:8s:720p", credits: 510, note: "8s 720p" },
|
|
1548
|
+
{ identifier: "wan-3-prime:8s:1080p", credits: 1010, note: "8s 1080p" },
|
|
1549
|
+
{ identifier: "wan-3-prime:30s:480p", credits: 920, note: "30s 480p (max)" },
|
|
1550
|
+
{ identifier: "wan-3-prime:30s:720p", credits: 1890, note: "30s 720p (max)" },
|
|
1551
|
+
{ identifier: "wan-3-prime:30s:1080p", credits: 3780, note: "30s 1080p (max)" },
|
|
1552
|
+
],
|
|
1553
|
+
},
|
|
1453
1554
|
"wan-i2v": {
|
|
1454
1555
|
id: "wan-i2v",
|
|
1455
1556
|
kind: "video",
|
package/src/model-constants.ts
CHANGED
|
@@ -139,6 +139,13 @@ export const MAX_VIDEO_PROMPT_CHARS_BY_PROVIDER: Record<string, number> = {
|
|
|
139
139
|
// (docs.kie.ai/market/bytedance/seedance-2-5).
|
|
140
140
|
"seedance-2-5": 30000,
|
|
141
141
|
"gemini-omni-video": 20000,
|
|
142
|
+
// Gemini Omni Flash 1.1 — same 20000-char prompt surface as the pro sibling
|
|
143
|
+
// (docs.kie.ai/market/google/gemini-omni-flash-1-1).
|
|
144
|
+
"gemini-omni-flash": 20000,
|
|
145
|
+
// Wan 3.0 / 3.0 Prime — 20000 chars, excess truncated by the provider
|
|
146
|
+
// (docs.kie.ai/market/wan/3-0-video and /3-0-video-prime).
|
|
147
|
+
"wan-3": 20000,
|
|
148
|
+
"wan-3-prime": 20000,
|
|
142
149
|
"bytedance-lite": 10000,
|
|
143
150
|
"bytedance-pro": 10000,
|
|
144
151
|
"bytedance-pro-fast": 10000,
|
|
@@ -295,6 +302,35 @@ export const NATIVE_NEGATIVE_VIDEO_PROVIDERS = new Set<string>([
|
|
|
295
302
|
"wan-s2v",
|
|
296
303
|
])
|
|
297
304
|
|
|
305
|
+
/**
|
|
306
|
+
* The `[style]` section header, verbatim. A composed prompt that ends with that
|
|
307
|
+
* section has NO terminator (`@nodaro/prompts`' `prompt-style-section.ts` owns
|
|
308
|
+
* the shape and the reasoning), so a `"\n"`-joined `Avoid:` would read as one
|
|
309
|
+
* more look clause under its header. Duplicated rather than imported because
|
|
310
|
+
* `@nodaro/prompts` depends on THIS package and never the reverse; the two are
|
|
311
|
+
* pinned together behaviourally by that package's
|
|
312
|
+
* `__tests__/style-section-boundary.test.ts`, which runs the real composer
|
|
313
|
+
* through this clamp.
|
|
314
|
+
*/
|
|
315
|
+
const STYLE_SECTION_HEADER_LINE = "[style]:\n"
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* The `Avoid: …` suffix `applyVideoNegativePrompt` folds into a prompt, with the
|
|
319
|
+
* separator the base prompt calls for: a blank line when the base ends INSIDE an
|
|
320
|
+
* unterminated `[style]` section, a single newline otherwise.
|
|
321
|
+
*
|
|
322
|
+
* `base` omitted = the WIDEST form, which is what a caller reserving room before
|
|
323
|
+
* the prompt exists must budget for (`effectiveVideoPromptCeiling`).
|
|
324
|
+
*/
|
|
325
|
+
export function videoNegativeSuffix(negativePrompt: string, base?: string): string {
|
|
326
|
+
const gapAt = base?.lastIndexOf("\n\n") ?? -1
|
|
327
|
+
const lastBlock = base === undefined ? undefined : (gapAt >= 0 ? base.slice(gapAt + 2) : base)
|
|
328
|
+
const separator = lastBlock === undefined || lastBlock.startsWith(STYLE_SECTION_HEADER_LINE)
|
|
329
|
+
? "\n\n"
|
|
330
|
+
: "\n"
|
|
331
|
+
return `${separator}Avoid: ${negativePrompt}`
|
|
332
|
+
}
|
|
333
|
+
|
|
298
334
|
/**
|
|
299
335
|
* Apply the negative prompt to a video-provider request.
|
|
300
336
|
*
|
|
@@ -306,6 +342,8 @@ export const NATIVE_NEGATIVE_VIDEO_PROVIDERS = new Set<string>([
|
|
|
306
342
|
* Otherwise, the helper appends `Avoid: <negativePrompt>` to the prompt
|
|
307
343
|
* (consistent with `buildImagePrompt` in `prompt-builder.ts`) so the model
|
|
308
344
|
* still sees the negative intent, and returns `nativeNegativePrompt = undefined`.
|
|
345
|
+
* The line is separated by {@link videoNegativeSuffix}, which closes an open
|
|
346
|
+
* `[style]` section with a blank line rather than reading as a look clause.
|
|
309
347
|
*
|
|
310
348
|
* Empty / missing negative is a no-op.
|
|
311
349
|
*
|
|
@@ -338,7 +376,10 @@ export function applyVideoNegativePrompt(
|
|
|
338
376
|
// assembler), then clamp the whole to the model cap.
|
|
339
377
|
const base = prompt && prompt.trim().length > 0 ? prompt : ""
|
|
340
378
|
if (!base) return { prompt: `Avoid: ${neg}`.slice(0, promptMax), nativeNegativePrompt: undefined }
|
|
341
|
-
|
|
379
|
+
// The separator is decided on the WHOLE base: the clamp below can only cut the
|
|
380
|
+
// tail, and a cut either leaves the `[style]` section behind or lands inside
|
|
381
|
+
// it, so the suffix never needs to grow after the reservation.
|
|
382
|
+
const avoid = videoNegativeSuffix(neg, base)
|
|
342
383
|
const room = Math.max(0, promptMax - avoid.length)
|
|
343
384
|
const injected = `${base.slice(0, room)}${avoid}`.slice(0, promptMax)
|
|
344
385
|
return { prompt: injected, nativeNegativePrompt: undefined }
|
|
@@ -716,6 +757,11 @@ export const IMAGE_TO_VIDEO_PROVIDERS = [
|
|
|
716
757
|
"runway-kie",
|
|
717
758
|
"kling-3-omni",
|
|
718
759
|
"gemini-omni-video",
|
|
760
|
+
"gemini-omni-flash",
|
|
761
|
+
// Wan 3.0 family — one id per SKU serves BOTH modes (no t2v twin, no alias),
|
|
762
|
+
// so each id is listed in this array AND in TEXT_TO_VIDEO_PROVIDERS.
|
|
763
|
+
"wan-3",
|
|
764
|
+
"wan-3-prime",
|
|
719
765
|
"ltx-2.3-pro",
|
|
720
766
|
"ltx-2.3-fast",
|
|
721
767
|
// xAI Grok Imagine Video 1.5 — KIE i2v (image_urls required). Also listed in
|
|
@@ -754,6 +800,12 @@ export const TEXT_TO_VIDEO_PROVIDERS = [
|
|
|
754
800
|
"happyhorse",
|
|
755
801
|
"runway-kie",
|
|
756
802
|
"gemini-omni-video",
|
|
803
|
+
"gemini-omni-flash",
|
|
804
|
+
// Wan 3.0 family — REAL t2v (prompt-only runs are the documented default
|
|
805
|
+
// mode), so they belong in this main section and must NOT be gated by
|
|
806
|
+
// VIDEO_PROVIDERS_REQUIRING_IMAGE.
|
|
807
|
+
"wan-3",
|
|
808
|
+
"wan-3-prime",
|
|
757
809
|
"ltx-2.3-pro",
|
|
758
810
|
"ltx-2.3-fast",
|
|
759
811
|
// ── i2v-only providers (image required) ──────────────────────────────────
|
|
@@ -1211,6 +1263,12 @@ export const DURATION_PRICED_PROVIDERS = new Set([
|
|
|
1211
1263
|
"happyhorse",
|
|
1212
1264
|
"happyhorse-i2v",
|
|
1213
1265
|
"happyhorse-ref2v",
|
|
1266
|
+
// Wan 3.0 family — per-second billing at three resolution rates. NOTE:
|
|
1267
|
+
// gemini-omni-flash is deliberately ABSENT (like gemini-omni-video): the
|
|
1268
|
+
// Gemini Omni branch in buildVideoCreditModelIdentifier early-returns before
|
|
1269
|
+
// this gate is consulted.
|
|
1270
|
+
"wan-3",
|
|
1271
|
+
"wan-3-prime",
|
|
1214
1272
|
])
|
|
1215
1273
|
|
|
1216
1274
|
/**
|
|
@@ -1268,6 +1326,75 @@ export function normalizeMinimaxH3Resolution(resolution: string | undefined): "7
|
|
|
1268
1326
|
return resolution?.trim().toLowerCase() === "768p" ? "768P" : MINIMAX_H3_DEFAULT_RESOLUTION
|
|
1269
1327
|
}
|
|
1270
1328
|
|
|
1329
|
+
/**
|
|
1330
|
+
* Wan 3.0 family — the KIE "wan/3-0-video" market model and its high-speed
|
|
1331
|
+
* "wan/3-0-video-prime" sibling. The two share a BYTE-IDENTICAL input schema
|
|
1332
|
+
* (first/last frame OR an all-purpose reference mode with images/videos/audio,
|
|
1333
|
+
* native `audio` boolean, 2-30s, 480P/720P/1080P, six aspect ratios with
|
|
1334
|
+
* `adaptive` as the default); only the per-second rate differs. Prime is the
|
|
1335
|
+
* FASTER tier at a higher rate — never describe it as "higher quality".
|
|
1336
|
+
*
|
|
1337
|
+
* Exact-membership set — NEVER match on a "wan" prefix: "wan", "wan-i2v",
|
|
1338
|
+
* "wan-turbo", "wan-flash", "wan-videoedit" and the "wan-2.7-*" ids are
|
|
1339
|
+
* unrelated 2.x models with a different surface (and a different reference
|
|
1340
|
+
* token format — see WAN_3_DOCTRINE in @nodaro/prompts).
|
|
1341
|
+
*/
|
|
1342
|
+
export const WAN_3_PROVIDERS = new Set<string>([
|
|
1343
|
+
"wan-3",
|
|
1344
|
+
"wan-3-prime",
|
|
1345
|
+
])
|
|
1346
|
+
|
|
1347
|
+
export function isWan3Provider(provider: string | undefined): boolean {
|
|
1348
|
+
return !!provider && WAN_3_PROVIDERS.has(provider)
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
/** Wan 3.0 resolution the PLATFORM renders when the param is omitted or unknown.
|
|
1352
|
+
* Deliberately NOT KIE's own default (1080P): 720p is the tier the bare credit
|
|
1353
|
+
* identifier prices, so the provider layer pins it to keep render == billed. */
|
|
1354
|
+
export const WAN_3_DEFAULT_RESOLUTION = "720P"
|
|
1355
|
+
|
|
1356
|
+
/**
|
|
1357
|
+
* SINGLE normalization for the Wan 3.0 resolution lever (KIE wire enum
|
|
1358
|
+
* "480P" | "720P" | "1080P"). Everything INTERNAL — the catalog, QUALITY_MAP,
|
|
1359
|
+
* dropdowns, RESOLUTION_DURATION_PRICING keys and every emitted credit
|
|
1360
|
+
* identifier — stays LOWERCASE; this helper is the ONE place the uppercase wire
|
|
1361
|
+
* form is produced (backend KIE payload build), the twin of
|
|
1362
|
+
* {@link normalizeMinimaxH3Resolution}.
|
|
1363
|
+
*
|
|
1364
|
+
* Case-insensitive. Anything else (undefined, garbage, a stale "4k") collapses
|
|
1365
|
+
* to {@link WAN_3_DEFAULT_RESOLUTION} — the tier the default credit identifier
|
|
1366
|
+
* reserves — so the billed tier can never undercut the rendered one.
|
|
1367
|
+
*/
|
|
1368
|
+
export function normalizeWan3Resolution(resolution: string | undefined): "480P" | "720P" | "1080P" {
|
|
1369
|
+
switch (resolution?.trim().toLowerCase()) {
|
|
1370
|
+
case "480p": return "480P"
|
|
1371
|
+
case "1080p": return "1080P"
|
|
1372
|
+
case "720p": return "720P"
|
|
1373
|
+
default: return WAN_3_DEFAULT_RESOLUTION
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
/**
|
|
1378
|
+
* Google Gemini Omni family — the KIE "gemini-omni-video" market model and its
|
|
1379
|
+
* faster/cheaper "google/gemini-omni-flash-1-1" sibling. Both take the SAME
|
|
1380
|
+
* request shape (prompt + image_urls references, video-edit through the i2v
|
|
1381
|
+
* handle, 4/6/8/10s, 720p/1080p or a 4K band) and are dispatched through the
|
|
1382
|
+
* same runner, so every behavioural branch that used to compare against the
|
|
1383
|
+
* literal "gemini-omni-video" must ask this predicate instead — V2V routing,
|
|
1384
|
+
* the 7-slot reference quota, the mode swap and the aspect-ratio panels.
|
|
1385
|
+
*
|
|
1386
|
+
* Exact-membership set — NEVER match on a "gemini" prefix (the Gemini LLM ids
|
|
1387
|
+
* would collide).
|
|
1388
|
+
*/
|
|
1389
|
+
export const GEMINI_OMNI_PROVIDERS = new Set<string>([
|
|
1390
|
+
"gemini-omni-video",
|
|
1391
|
+
"gemini-omni-flash",
|
|
1392
|
+
])
|
|
1393
|
+
|
|
1394
|
+
export function isGeminiOmniProvider(provider: string | undefined): boolean {
|
|
1395
|
+
return !!provider && GEMINI_OMNI_PROVIDERS.has(provider)
|
|
1396
|
+
}
|
|
1397
|
+
|
|
1271
1398
|
/**
|
|
1272
1399
|
* Video models that are CATALOGUED and priced but have NO working dispatch
|
|
1273
1400
|
* path today — selecting one fails at the router, not at validation.
|
|
@@ -1519,9 +1646,15 @@ export function maxSegmentsFor(provider: string | undefined, capSec: number): nu
|
|
|
1519
1646
|
* param at all (inferred from the frame). Only the pure-t2v endpoint requires
|
|
1520
1647
|
* a concrete ratio — the KIE provider layer coerces `adaptive` → `16:9` there
|
|
1521
1648
|
* (see applyMinimaxH3Params in backend kie/video.ts).
|
|
1649
|
+
*
|
|
1650
|
+
* Wan 3.0 also defaults to `adaptive` — it is the model's own KIE default and
|
|
1651
|
+
* the first value in its aspect enum, so an un-set node must not silently run
|
|
1652
|
+
* at 16:9 while the panel displays Adaptive.
|
|
1522
1653
|
*/
|
|
1523
1654
|
export function defaultVideoAspectRatio(provider: string | undefined): string {
|
|
1524
|
-
return isSeedance2Provider(provider) || isMinimaxH3Provider(provider)
|
|
1655
|
+
return isSeedance2Provider(provider) || isMinimaxH3Provider(provider) || isWan3Provider(provider)
|
|
1656
|
+
? "adaptive"
|
|
1657
|
+
: "16:9"
|
|
1525
1658
|
}
|
|
1526
1659
|
|
|
1527
1660
|
/**
|
|
@@ -1622,6 +1755,10 @@ export const SEEDANCE_2_R2V_MAX_AUDIO_SEC_BY_PROVIDER: Record<string, number> =
|
|
|
1622
1755
|
// MiniMax Hailuo 3 — documented hard limit: each reference audio segment
|
|
1623
1756
|
// 2-15s, ≤15s total (docs.kie.ai/market/minimax-h3/reference-to-video).
|
|
1624
1757
|
"minimax-h3": 15,
|
|
1758
|
+
// Wan 3.0 family — documented hard limit: each reference audio clip 1-15s,
|
|
1759
|
+
// ≤15s combined (docs.kie.ai/market/wan/3-0-video).
|
|
1760
|
+
"wan-3": 15,
|
|
1761
|
+
"wan-3-prime": 15,
|
|
1625
1762
|
}
|
|
1626
1763
|
|
|
1627
1764
|
/** The verified r2v reference-audio cap (seconds) for a provider, or null when
|
|
@@ -1677,8 +1814,17 @@ export const VIDEO_REF_LIMITS_BY_PROVIDER: Record<
|
|
|
1677
1814
|
// bills input images beyond the first 5 (11 KIE cr each) — see the
|
|
1678
1815
|
// minimax-h3 credit helper in backend ee/billing.
|
|
1679
1816
|
"minimax-h3": { ...SEEDANCE_2_REF_LIMITS },
|
|
1817
|
+
// Wan 3.0 family — all-purpose reference mode: up to 10 images / 5 videos
|
|
1818
|
+
// (each 1-15s, ≤15s combined) / 5 audio clips (each 1-15s, ≤15s combined).
|
|
1819
|
+
// The reference arrays are mutually EXCLUSIVE with first/last frame at the
|
|
1820
|
+
// provider (docs.kie.ai/market/wan/3-0-video).
|
|
1821
|
+
"wan-3": { images: 10, videos: 5, audio: 5 },
|
|
1822
|
+
"wan-3-prime": { images: 10, videos: 5, audio: 5 },
|
|
1680
1823
|
// Multi-image reference providers.
|
|
1681
1824
|
"gemini-omni-video": { images: 7, videos: 1 },
|
|
1825
|
+
// Gemini Omni Flash 1.1 — identical quota to the pro sibling
|
|
1826
|
+
// (images + 2×videos + character_ids ≤ 7).
|
|
1827
|
+
"gemini-omni-flash": { images: 7, videos: 1 },
|
|
1682
1828
|
"kling-3-omni": { images: 7 }, // catalog/docs: "end frame + up to 7 reference images"
|
|
1683
1829
|
"grok-i2v": { images: 7 }, // backend kie/models.ts maxRefImages: 7
|
|
1684
1830
|
"happyhorse-ref2v": { images: 9 }, // backend kie/models.ts maxRefImages: 9
|
|
@@ -1704,10 +1850,15 @@ export const RESOLUTION_VIDEO_REF_PRICING = SEEDANCE_2_PROVIDERS
|
|
|
1704
1850
|
/**
|
|
1705
1851
|
* Video models priced by (duration × resolution) WITHOUT a video-ref dimension.
|
|
1706
1852
|
* Identifier suffix: `:{resolution}`, appended after the duration tier; value =
|
|
1707
|
-
* the provider's PRICED resolution tiers.
|
|
1708
|
-
*
|
|
1709
|
-
*
|
|
1710
|
-
*
|
|
1853
|
+
* the provider's PRICED resolution tiers.
|
|
1854
|
+
*
|
|
1855
|
+
* Any resolution outside the list (or undefined) collapses to the provider's
|
|
1856
|
+
* DEFAULT tier, so the builder can never emit an unpriced composite (the
|
|
1857
|
+
* hard-fail guard fuzzes the full resolution space). That default is
|
|
1858
|
+
* {@link PRICING_DEFAULT_RESOLUTION} when the provider declares one, and
|
|
1859
|
+
* otherwise the FIRST entry here — so a member with a declared default (wan-3)
|
|
1860
|
+
* can list its tiers in the repo-standard ascending order without index 0
|
|
1861
|
+
* silently becoming the billed default. Distinct from
|
|
1711
1862
|
* RESOLUTION_VIDEO_REF_PRICING (Seedance gen), which also adds `-ref` variants.
|
|
1712
1863
|
*/
|
|
1713
1864
|
export const RESOLUTION_DURATION_PRICING: Record<string, readonly string[]> = {
|
|
@@ -1723,6 +1874,12 @@ export const RESOLUTION_DURATION_PRICING: Record<string, readonly string[]> = {
|
|
|
1723
1874
|
"happyhorse": ["720p", "1080p"],
|
|
1724
1875
|
"happyhorse-i2v": ["720p", "1080p"],
|
|
1725
1876
|
"happyhorse-ref2v": ["720p", "1080p"],
|
|
1877
|
+
// Wan 3.0 / Prime — per-second billing at three published resolution rates.
|
|
1878
|
+
// Ascending, matching the catalog; the BILLED default is declared explicitly
|
|
1879
|
+
// in PRICING_DEFAULT_RESOLUTION ("720p") rather than carried by index 0, and
|
|
1880
|
+
// the provider layer pins the same 720P so render == billed.
|
|
1881
|
+
"wan-3": ["480p", "720p", "1080p"],
|
|
1882
|
+
"wan-3-prime": ["480p", "720p", "1080p"],
|
|
1726
1883
|
}
|
|
1727
1884
|
|
|
1728
1885
|
/**
|
|
@@ -1745,6 +1902,13 @@ export const NATIVE_ADAPTIVE_ASPECT: Record<string, string> = {
|
|
|
1745
1902
|
"seedance-2-fast": "adaptive",
|
|
1746
1903
|
"seedance-2-mini": "adaptive",
|
|
1747
1904
|
"seedance-2-5": "adaptive",
|
|
1905
|
+
// Wan 3.0 family: `adaptive` is the enum DEFAULT and KIE documents it as
|
|
1906
|
+
// "automatically selects the ratio based on the input media and intent"
|
|
1907
|
+
// (docs.kie.ai/market/wan/3-0-video) — i.e. match-the-input, not merely
|
|
1908
|
+
// "provider default" (the grok `auto` trap). DOC-verified only; re-confirm
|
|
1909
|
+
// with a live job before relying on it for off-catalog ratios.
|
|
1910
|
+
"wan-3": "adaptive",
|
|
1911
|
+
"wan-3-prime": "adaptive",
|
|
1748
1912
|
}
|
|
1749
1913
|
|
|
1750
1914
|
/**
|
|
@@ -1843,8 +2007,9 @@ export type VideoAudioMode = "none" | "ambient" | "native_speech" | "audio_drive
|
|
|
1843
2007
|
|
|
1844
2008
|
export interface VideoAudioCapability {
|
|
1845
2009
|
mode: VideoAudioMode
|
|
1846
|
-
/** Provider-option field carrying the on/off toggle, when user-controllable.
|
|
1847
|
-
|
|
2010
|
+
/** Provider-option field carrying the on/off toggle, when user-controllable.
|
|
2011
|
+
* `audio` is Wan 3.0's own boolean lever (KIE `input.audio`, default true). */
|
|
2012
|
+
field?: "generateAudio" | "sound" | "audio"
|
|
1848
2013
|
/** Audio is always produced and can't be turned off by the user (VEO 3.x). */
|
|
1849
2014
|
alwaysOn?: boolean
|
|
1850
2015
|
/** Enabling audio raises the credit cost (Kling — see AUDIO_ADDON_PROVIDERS). */
|
|
@@ -1903,6 +2068,19 @@ export const VIDEO_AUDIO_CAPABILITY: Record<string, VideoAudioCapability> = {
|
|
|
1903
2068
|
// KIE API exposes NO audio on/off parameter (audio is always produced), so
|
|
1904
2069
|
// there is no toggle field — alwaysOn, like VEO.
|
|
1905
2070
|
"minimax-h3": { mode: "audio_driven", alwaysOn: true },
|
|
2071
|
+
// Wan 3.0 family — a single boolean `audio` lever (KIE default true) produces
|
|
2072
|
+
// an ambient/SFX track with the clip. Classified "ambient", NOT
|
|
2073
|
+
// "native_speech" or "audio_driven": the schema documents no dialogue
|
|
2074
|
+
// guarantee, and reference audio is a generic conditioning array, not a
|
|
2075
|
+
// verified lip-sync transport. Upgrade only on a live probe (the kling-3.0
|
|
2076
|
+
// standard) — `audio_driven` would reroute the Story→Video dialogue pipeline
|
|
2077
|
+
// and skip the lip-sync pass. `defaultOn` mirrors the KIE default so an
|
|
2078
|
+
// intent-less request is described honestly; audio is priced into the uniform
|
|
2079
|
+
// per-second rate, so NOT cost-affecting (no `:audio` composite).
|
|
2080
|
+
// gemini-omni-flash is deliberately ABSENT — gemini-omni-video is absent too
|
|
2081
|
+
// (mode "none"), and the siblings must not disagree.
|
|
2082
|
+
"wan-3": { mode: "ambient", field: "audio", defaultOn: true },
|
|
2083
|
+
"wan-3-prime": { mode: "ambient", field: "audio", defaultOn: true },
|
|
1906
2084
|
}
|
|
1907
2085
|
|
|
1908
2086
|
const VIDEO_AUDIO_NONE: VideoAudioCapability = { mode: "none" }
|
|
@@ -1974,6 +2152,7 @@ export function applyVideoAudioToggle(
|
|
|
1974
2152
|
const enabled = cap.affectsCost ? opts?.sound : (opts?.sound ?? opts?.generateAudio)
|
|
1975
2153
|
if (enabled === undefined) return // no intent — keep the model's own default
|
|
1976
2154
|
if (cap.field === "generateAudio") input.generate_audio = enabled
|
|
2155
|
+
else if (cap.field === "audio") input.audio = enabled
|
|
1977
2156
|
else input.sound = enabled
|
|
1978
2157
|
}
|
|
1979
2158
|
|
|
@@ -2029,6 +2208,11 @@ export const VIDEO_VARIABLE_PRICING: Record<string, "duration" | "duration+audio
|
|
|
2029
2208
|
"minimax-h3": "duration+resolution",
|
|
2030
2209
|
// Grok Imagine Video 1.5 — per-second billing split 480p/720p (no video-ref dimension).
|
|
2031
2210
|
"grok-imagine-video-1.5": "duration+resolution",
|
|
2211
|
+
// Wan 3.0 family — per-second billing at three resolution rates (no video-ref
|
|
2212
|
+
// dimension: reference runs bill output seconds only). No gemini-omni-flash
|
|
2213
|
+
// entry, mirroring gemini-omni-video which has none either.
|
|
2214
|
+
"wan-3": "duration+resolution",
|
|
2215
|
+
"wan-3-prime": "duration+resolution",
|
|
2032
2216
|
}
|
|
2033
2217
|
|
|
2034
2218
|
/**
|
|
@@ -2064,6 +2248,14 @@ export const PRICING_DEFAULT_DURATION_SEC: Record<string, number> = {
|
|
|
2064
2248
|
export const PRICING_DEFAULT_RESOLUTION: Record<string, string> = {
|
|
2065
2249
|
// KIE renders 720p when `resolution` is omitted (kie/models.ts extraParams).
|
|
2066
2250
|
"seedance-2-5": "720p",
|
|
2251
|
+
// Wan 3.0 family — KIE's OWN default is 1080P, but the provider layer pins
|
|
2252
|
+
// 720P (normalizeWan3Resolution / WAN_3_DEFAULT_RESOLUTION) so the rendered
|
|
2253
|
+
// tier equals the tier the bare identifier bills. This declaration is what
|
|
2254
|
+
// makes the billed default explicit instead of an array ordering: the
|
|
2255
|
+
// RESOLUTION_DURATION_PRICING branch consults it before falling back to the
|
|
2256
|
+
// first tier, so the catalog can stay ascending without repricing anything.
|
|
2257
|
+
"wan-3": "720p",
|
|
2258
|
+
"wan-3-prime": "720p",
|
|
2067
2259
|
}
|
|
2068
2260
|
|
|
2069
2261
|
/** HappyHorse 1.1 per-second tiers — one per allowed duration (3–15s), shared
|
|
@@ -2088,6 +2280,21 @@ const SEEDANCE_2_5_DURATION_TIERS: Array<{ maxSeconds: number; suffix: string }>
|
|
|
2088
2280
|
(_, i) => ({ maxSeconds: i + 4, suffix: `${i + 4}s` }),
|
|
2089
2281
|
)
|
|
2090
2282
|
|
|
2283
|
+
/**
|
|
2284
|
+
* Wan 3.0 per-second tiers — one per allowed duration (2-30s), shared by both
|
|
2285
|
+
* SKUs (the ladder shape is identical; only the seeded rates differ).
|
|
2286
|
+
*
|
|
2287
|
+
* Per-second is REQUIRED, not a nicety: the ladder snaps a request UP to the
|
|
2288
|
+
* first tier whose `maxSeconds` covers it and falls back to the LAST tier when
|
|
2289
|
+
* none does, so a coarse ladder over a 29-value range would reserve a
|
|
2290
|
+
* short-clip price for a 30s render. `commit_credits` only ever refunds a
|
|
2291
|
+
* surplus and can never collect an upward delta.
|
|
2292
|
+
*/
|
|
2293
|
+
const WAN_3_DURATION_TIERS: Array<{ maxSeconds: number; suffix: string }> = Array.from(
|
|
2294
|
+
{ length: 29 },
|
|
2295
|
+
(_, i) => ({ maxSeconds: i + 2, suffix: `${i + 2}s` }),
|
|
2296
|
+
)
|
|
2297
|
+
|
|
2091
2298
|
/**
|
|
2092
2299
|
* Duration tier breakpoints for variable-priced video models.
|
|
2093
2300
|
* Maps provider → array of { maxSeconds, suffix } in ascending order.
|
|
@@ -2168,6 +2375,8 @@ export const VIDEO_DURATION_TIERS: Record<string, Array<{ maxSeconds: number; su
|
|
|
2168
2375
|
{ maxSeconds: 15, suffix: "15s" },
|
|
2169
2376
|
],
|
|
2170
2377
|
"seedance-2-5": SEEDANCE_2_5_DURATION_TIERS,
|
|
2378
|
+
"wan-3": WAN_3_DURATION_TIERS,
|
|
2379
|
+
"wan-3-prime": WAN_3_DURATION_TIERS,
|
|
2171
2380
|
// MiniMax Hailuo 3 — true per-second billing (KIE 36.5 cr/s @2K, 22.5 cr/s
|
|
2172
2381
|
// @768P). One tier per allowed second (4-15s) so the composite identifier
|
|
2173
2382
|
// maps 1:1 to the seeded price — no rounding/overcharge for any on-menu
|
|
@@ -187,6 +187,10 @@ const QUALITY_MAP: Record<string, QualityMapping> = {
|
|
|
187
187
|
// Seedance 2.5 spans 480p/720p/1080p on KIE (1080p accepted since the
|
|
188
188
|
// 2026-08-17 re-probe; 4k still rejected), so each quality rung gets its own tier.
|
|
189
189
|
"seedance-2-5": { field: "resolution", values: { low: "480p", mid: "720p", high: "1080p" } },
|
|
190
|
+
// Wan 3.0 family — 480p / 720p / 1080p (lowercase catalog spellings; the
|
|
191
|
+
// uppercase KIE wire form is produced only by normalizeWan3Resolution).
|
|
192
|
+
"wan-3": { field: "resolution", values: { low: "480p", mid: "720p", high: "1080p" } },
|
|
193
|
+
"wan-3-prime": { field: "resolution", values: { low: "480p", mid: "720p", high: "1080p" } },
|
|
190
194
|
"wan-2.7-i2v": { field: "resolution", values: { low: "720p", mid: "1080p", high: "1080p" } },
|
|
191
195
|
"wan-2.7-t2v": { field: "resolution", values: { low: "720p", mid: "1080p", high: "1080p" } },
|
|
192
196
|
"happyhorse": { field: "resolution", values: { low: "720p", mid: "1080p", high: "1080p" } },
|
|
@@ -200,6 +204,7 @@ const QUALITY_MAP: Record<string, QualityMapping> = {
|
|
|
200
204
|
"ltx-2.3-pro": { field: "resolution", values: { low: "1080p", mid: "2k", high: "4k" } },
|
|
201
205
|
"ltx-2.3-fast": { field: "resolution", values: { low: "1080p", mid: "2k", high: "4k" } },
|
|
202
206
|
"gemini-omni-video": { field: "resolution", values: { low: "720p", mid: "1080p", high: "4k" } },
|
|
207
|
+
"gemini-omni-flash": { field: "resolution", values: { low: "720p", mid: "1080p", high: "4k" } },
|
|
203
208
|
// Grok Imagine Video 1.5 — only 480p/720p (no 1080p tier); high clamps to 720p.
|
|
204
209
|
"grok-imagine-video-1.5": { field: "resolution", values: { low: "480p", mid: "720p", high: "720p" } },
|
|
205
210
|
// Replicate Flux 2 family — MP-based resolution (matching IMAGE_RESOLUTION_OPTIONS["flux-2-*"]).
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* UI-default fills for the unified video nodes — the ONE source of truth shared
|
|
3
|
+
* by the backend DAG payload builder, the config-panel fail-safe snaps and the
|
|
4
|
+
* node's hover/run strip.
|
|
5
|
+
*
|
|
6
|
+
* Several config panels RENDER a default without persisting it to node data, so
|
|
7
|
+
* an untouched node submits `aspectRatio` / `resolution` undefined and the
|
|
8
|
+
* enqueued job row (and the /v1/jobs echo) then disagrees with what actually
|
|
9
|
+
* renders. Worse, the panels' generic snap writes `resolutions[0]` for a stale
|
|
10
|
+
* value, which is the CHEAPEST tier under the repo's ascending-resolution
|
|
11
|
+
* convention — not necessarily the tier the model renders and bills.
|
|
12
|
+
*
|
|
13
|
+
* These helpers were local to `backend/src/services/workflow-engine/payload-builder.ts`
|
|
14
|
+
* until the Wan 3.0 launch gave the platform its first provider whose declared
|
|
15
|
+
* billing default differs from `resolutions[0]`; three surfaces then had to
|
|
16
|
+
* agree, so they live here.
|
|
17
|
+
*
|
|
18
|
+
* The resolution fill is per-family ON PURPOSE. Wan 3.0 reads its DECLARED
|
|
19
|
+
* billing default (PRICING_DEFAULT_RESOLUTION = 720p) because its catalog list
|
|
20
|
+
* is ascending, so an index-0 fill would write 480p — a tier both `runWan3`
|
|
21
|
+
* (which renders 720P) and the credit identifier (which bills the 720p row)
|
|
22
|
+
* disagree with. The Seedance family keeps its historical first-catalog-tier
|
|
23
|
+
* fill, deliberately: switching it to PRICING_DEFAULT_RESOLUTION would reprice
|
|
24
|
+
* live seedance-2-5 runs, whose declared default (720p) differs from the 480p
|
|
25
|
+
* this has always filled. That 480p-fill vs 720p-billing-default divergence on
|
|
26
|
+
* seedance-2-5 is a KNOWN pre-existing gap, out of scope here — do not "align"
|
|
27
|
+
* the branches without repricing it deliberately.
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
import {
|
|
31
|
+
PRICING_DEFAULT_RESOLUTION,
|
|
32
|
+
isSeedance2Provider,
|
|
33
|
+
isMinimaxH3Provider,
|
|
34
|
+
isWan3Provider,
|
|
35
|
+
isGeminiOmniProvider,
|
|
36
|
+
} from "./model-constants.js"
|
|
37
|
+
import { MODEL_CATALOG } from "./model-catalog.js"
|
|
38
|
+
|
|
39
|
+
/** `adaptive` is the aspect default for Seedance 2, MiniMax H3 and Wan 3.0. */
|
|
40
|
+
export function uiAspectRatioFill(provider: string): string | undefined {
|
|
41
|
+
return isSeedance2Provider(provider) || isMinimaxH3Provider(provider) || isWan3Provider(provider)
|
|
42
|
+
? "adaptive"
|
|
43
|
+
: undefined
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** See the file docstring — per-family on purpose; never a generic
|
|
47
|
+
* PRICING_DEFAULT_RESOLUTION read (that would reprice seedance-2-5). */
|
|
48
|
+
export function uiResolutionFill(provider: string): string | undefined {
|
|
49
|
+
if (isWan3Provider(provider)) return PRICING_DEFAULT_RESOLUTION[provider]
|
|
50
|
+
if (isSeedance2Provider(provider)) return MODEL_CATALOG[provider]?.resolutions?.[0]
|
|
51
|
+
return undefined
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Duration the node RENDERS and BILLS when `data.duration` is unset, for the
|
|
56
|
+
* families whose credit identifier declares a duration fallback that is NOT
|
|
57
|
+
* `durations[0]`. Wan 3.0's bare identifier is the 5s tier while its ladder
|
|
58
|
+
* starts at 2s; the Gemini Omni family's is the 8s tier while its ladder starts
|
|
59
|
+
* at 4s. Everyone else falls back to the first listed duration, so this returns
|
|
60
|
+
* undefined and the caller keeps `durations[0]`.
|
|
61
|
+
*/
|
|
62
|
+
export function uiDurationFill(provider: string): number | undefined {
|
|
63
|
+
if (isWan3Provider(provider)) return 5
|
|
64
|
+
if (isGeminiOmniProvider(provider)) return 8
|
|
65
|
+
return undefined
|
|
66
|
+
}
|