@shop-os/modelkit 0.1.5 → 0.1.7
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/README.md +12 -11
- package/dist/index.cjs +1156 -380
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +69 -9
- package/dist/index.d.ts +69 -9
- package/dist/index.js +1155 -380
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -83,6 +83,7 @@ var Catalog = class _Catalog {
|
|
|
83
83
|
|
|
84
84
|
// src/catalog/image.ts
|
|
85
85
|
var IMAGE_USAGE = { unit: "images", modality: "IMAGE" };
|
|
86
|
+
var IMAGE_GENERATE_EDIT = { imageGenerate: true, imageEdit: true };
|
|
86
87
|
var GEMINI_RATIOS = [
|
|
87
88
|
"1:1",
|
|
88
89
|
"2:3",
|
|
@@ -96,7 +97,7 @@ var GEMINI_RATIOS = [
|
|
|
96
97
|
"5:4",
|
|
97
98
|
"adaptive"
|
|
98
99
|
];
|
|
99
|
-
function geminiImage(id, label, aliases, sizes) {
|
|
100
|
+
function geminiImage(id, label, aliases, sizes, display) {
|
|
100
101
|
const model = {
|
|
101
102
|
id,
|
|
102
103
|
aliases,
|
|
@@ -105,25 +106,47 @@ function geminiImage(id, label, aliases, sizes) {
|
|
|
105
106
|
adapter: "google-image",
|
|
106
107
|
providerModelId: id,
|
|
107
108
|
lifecycle: "active",
|
|
108
|
-
constraints: {
|
|
109
|
+
constraints: {
|
|
110
|
+
aspectRatios: [...GEMINI_RATIOS],
|
|
111
|
+
sizes,
|
|
112
|
+
supports: ["safetySettings", "temperature"]
|
|
113
|
+
},
|
|
109
114
|
defaults: { size: "1K", aspectRatio: "1:1" },
|
|
110
115
|
usage: { ...IMAGE_USAGE },
|
|
111
|
-
pricingKind: "image_size"
|
|
116
|
+
pricingKind: "image_size",
|
|
117
|
+
display,
|
|
118
|
+
capabilities: { ...IMAGE_GENERATE_EDIT }
|
|
112
119
|
};
|
|
113
120
|
return model;
|
|
114
121
|
}
|
|
115
122
|
var IMAGE_MODELS = [
|
|
116
|
-
geminiImage("gemini-3-pro-image-preview", "Nano Banana Pro", ["nb-pro"], ["1K", "2K", "4K"]
|
|
123
|
+
geminiImage("gemini-3-pro-image-preview", "Nano Banana Pro", ["nb-pro"], ["1K", "2K", "4K"], {
|
|
124
|
+
provider: "google",
|
|
125
|
+
description: "Create stunning, production-quality visuals with exceptional realism, detail, and typography. Best for campaigns, e-commerce, product photography, and hero creatives.",
|
|
126
|
+
logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png"
|
|
127
|
+
}),
|
|
117
128
|
geminiImage(
|
|
118
129
|
"gemini-3.1-flash-image-preview",
|
|
119
130
|
"Nano Banana Flash",
|
|
120
131
|
["nb-2"],
|
|
121
132
|
// Flash 3.1 is the only Gemini image model with the 512 tier.
|
|
122
|
-
["512", "1K", "2K", "4K"]
|
|
133
|
+
["512", "1K", "2K", "4K"],
|
|
134
|
+
{
|
|
135
|
+
provider: "google",
|
|
136
|
+
description: "Generate high-quality images at speed. Perfect for brainstorming, moodboards, concept testing, creative exploration, and large batch workflows.",
|
|
137
|
+
logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png"
|
|
138
|
+
}
|
|
123
139
|
),
|
|
124
|
-
geminiImage("gemini-3.1-flash-lite-image", "Nano Banana Lite", ["nb-lite"], ["1K"]
|
|
140
|
+
geminiImage("gemini-3.1-flash-lite-image", "Nano Banana Lite", ["nb-lite"], ["1K"], {
|
|
141
|
+
provider: "google",
|
|
142
|
+
description: "The fastest and most affordable image model. Ideal for rapid drafts, bulk exploration, and iterative concept testing at 1K resolution.",
|
|
143
|
+
logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png"
|
|
144
|
+
}),
|
|
125
145
|
// trigger-workflows validates 1K only; pricing seeds 2K/4K rows so allow all three.
|
|
126
|
-
geminiImage("gemini-2.5-flash-image", "Gemini 2.5 Flash Image", [], ["1K", "2K", "4K"]
|
|
146
|
+
geminiImage("gemini-2.5-flash-image", "Gemini 2.5 Flash Image", [], ["1K", "2K", "4K"], {
|
|
147
|
+
provider: "google",
|
|
148
|
+
description: "Nano Banana (legacy Gemini 2.5 Flash Image) native image generation and editing model for high-volume, low-latency creative workflows."
|
|
149
|
+
}),
|
|
127
150
|
{
|
|
128
151
|
// Cowork "auto" lets OpenAI pick the size; the canonical equivalent is adaptive.
|
|
129
152
|
id: "gpt-image-2",
|
|
@@ -141,7 +164,13 @@ var IMAGE_MODELS = [
|
|
|
141
164
|
},
|
|
142
165
|
defaults: { size: "1K", aspectRatio: "adaptive", quality: "auto" },
|
|
143
166
|
usage: { ...IMAGE_USAGE },
|
|
144
|
-
pricingKind: "image_size"
|
|
167
|
+
pricingKind: "image_size",
|
|
168
|
+
display: {
|
|
169
|
+
provider: "openai",
|
|
170
|
+
description: "The most capable model for image editing and complex creative instructions. Excels at text rendering, visual consistency, design generation, and iterative refinement.",
|
|
171
|
+
logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/1204b494-8962-4f7f-af5e-699a8bdc98e3_compressed.png"
|
|
172
|
+
},
|
|
173
|
+
capabilities: { ...IMAGE_GENERATE_EDIT }
|
|
145
174
|
},
|
|
146
175
|
{
|
|
147
176
|
// Same Images API surface as gpt-image-2 plus the "xhigh" and "max" quality tiers.
|
|
@@ -160,7 +189,12 @@ var IMAGE_MODELS = [
|
|
|
160
189
|
},
|
|
161
190
|
defaults: { size: "1K", aspectRatio: "adaptive", quality: "auto" },
|
|
162
191
|
usage: { ...IMAGE_USAGE },
|
|
163
|
-
pricingKind: "image_size"
|
|
192
|
+
pricingKind: "image_size",
|
|
193
|
+
display: {
|
|
194
|
+
provider: "openai",
|
|
195
|
+
description: "OpenAI's most capable GPT Image 2.5 tier, built for editing precision; takes text and image input and outputs images in low, medium, high, xhigh, or max quality."
|
|
196
|
+
},
|
|
197
|
+
capabilities: { ...IMAGE_GENERATE_EDIT }
|
|
164
198
|
},
|
|
165
199
|
{
|
|
166
200
|
// Same Images API surface as gpt-image-2 plus the "xhigh" and "max" quality tiers.
|
|
@@ -179,7 +213,12 @@ var IMAGE_MODELS = [
|
|
|
179
213
|
},
|
|
180
214
|
defaults: { size: "1K", aspectRatio: "adaptive", quality: "auto" },
|
|
181
215
|
usage: { ...IMAGE_USAGE },
|
|
182
|
-
pricingKind: "image_size"
|
|
216
|
+
pricingKind: "image_size",
|
|
217
|
+
display: {
|
|
218
|
+
provider: "openai",
|
|
219
|
+
description: "OpenAI's fastest GPT Image 2.5 tier for high-quality everyday image generation and editing; takes text and image input and outputs images."
|
|
220
|
+
},
|
|
221
|
+
capabilities: { ...IMAGE_GENERATE_EDIT }
|
|
183
222
|
},
|
|
184
223
|
{
|
|
185
224
|
// Cowork allows 7 ratios; trigger-workflows allows 9 (adds 3:2, 9:21, drops 4:5/5:4).
|
|
@@ -211,7 +250,13 @@ var IMAGE_MODELS = [
|
|
|
211
250
|
},
|
|
212
251
|
defaults: { size: "1K", aspectRatio: "1:1", outputFormat: "png", count: 1 },
|
|
213
252
|
usage: { ...IMAGE_USAGE },
|
|
214
|
-
pricingKind: "image_size"
|
|
253
|
+
pricingKind: "image_size",
|
|
254
|
+
display: {
|
|
255
|
+
provider: "meta",
|
|
256
|
+
description: "Meta's image model with built-in world knowledge and strong prompt adherence. Great for concept-rich scenes, realistic compositions, and reference-guided edits.",
|
|
257
|
+
logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/characters/1787909065794-k9a7zz.png"
|
|
258
|
+
},
|
|
259
|
+
capabilities: { ...IMAGE_GENERATE_EDIT }
|
|
215
260
|
},
|
|
216
261
|
{
|
|
217
262
|
id: "seedream-5-0-pro",
|
|
@@ -231,7 +276,12 @@ var IMAGE_MODELS = [
|
|
|
231
276
|
},
|
|
232
277
|
defaults: { size: "1K", aspectRatio: "1:1" },
|
|
233
278
|
usage: { ...IMAGE_USAGE },
|
|
234
|
-
pricingKind: "image_size"
|
|
279
|
+
pricingKind: "image_size",
|
|
280
|
+
display: {
|
|
281
|
+
provider: "bytedance",
|
|
282
|
+
description: "ByteDance Seedream 5.0 Pro text-to-image and multi-reference image-to-image (up to 10 inputs) with region editing; outputs 1K, 1.5K, or 2K."
|
|
283
|
+
},
|
|
284
|
+
capabilities: { ...IMAGE_GENERATE_EDIT }
|
|
235
285
|
},
|
|
236
286
|
{
|
|
237
287
|
id: "seedream-4.5",
|
|
@@ -244,14 +294,31 @@ var IMAGE_MODELS = [
|
|
|
244
294
|
constraints: {
|
|
245
295
|
// 97:30 has no Ark size spelling; the A+ flow pads inputs to 97:30 and
|
|
246
296
|
// omits the ratio instead. Advertise only sizes the adapter can send.
|
|
247
|
-
aspectRatios: [
|
|
248
|
-
|
|
297
|
+
aspectRatios: [
|
|
298
|
+
"1:1",
|
|
299
|
+
"2:3",
|
|
300
|
+
"3:2",
|
|
301
|
+
"4:3",
|
|
302
|
+
"3:4",
|
|
303
|
+
"4:5",
|
|
304
|
+
"5:4",
|
|
305
|
+
"9:16",
|
|
306
|
+
"16:9",
|
|
307
|
+
"21:9",
|
|
308
|
+
"9:21"
|
|
309
|
+
],
|
|
310
|
+
sizes: ["1K", "2K", "4K"],
|
|
249
311
|
references: { images: 10 },
|
|
250
312
|
supports: ["seed"]
|
|
251
313
|
},
|
|
252
314
|
defaults: { size: "1K", aspectRatio: "1:1" },
|
|
253
315
|
usage: { ...IMAGE_USAGE },
|
|
254
|
-
pricingKind: "image_size"
|
|
316
|
+
pricingKind: "image_size",
|
|
317
|
+
display: {
|
|
318
|
+
provider: "bytedance",
|
|
319
|
+
description: "ByteDance Seedream 4.5 text-to-image and image-to-image with up to 14 reference images and batch image-set generation; outputs 2K or 4K."
|
|
320
|
+
},
|
|
321
|
+
capabilities: { ...IMAGE_GENERATE_EDIT }
|
|
255
322
|
},
|
|
256
323
|
{
|
|
257
324
|
id: "flux-2-pro",
|
|
@@ -269,7 +336,12 @@ var IMAGE_MODELS = [
|
|
|
269
336
|
},
|
|
270
337
|
defaults: { size: "1K", aspectRatio: "1:1" },
|
|
271
338
|
usage: { ...IMAGE_USAGE },
|
|
272
|
-
pricingKind: "image_size"
|
|
339
|
+
pricingKind: "image_size",
|
|
340
|
+
display: {
|
|
341
|
+
provider: "black-forest-labs",
|
|
342
|
+
description: "Black Forest Labs FLUX.2 [pro] text-to-image and multi-reference editing model served via Prodia; takes a prompt and up to 8 input images and outputs up to 4096x4096."
|
|
343
|
+
},
|
|
344
|
+
capabilities: { ...IMAGE_GENERATE_EDIT }
|
|
273
345
|
},
|
|
274
346
|
{
|
|
275
347
|
// Prodia's gemini-3-pro jobs take aspect_ratio + resolution (1K/2K/4K), not
|
|
@@ -290,7 +362,12 @@ var IMAGE_MODELS = [
|
|
|
290
362
|
},
|
|
291
363
|
defaults: { size: "1K", aspectRatio: "1:1" },
|
|
292
364
|
usage: { ...IMAGE_USAGE },
|
|
293
|
-
pricingKind: "image_size"
|
|
365
|
+
pricingKind: "image_size",
|
|
366
|
+
display: {
|
|
367
|
+
provider: "google",
|
|
368
|
+
description: "Google Gemini 3 Pro image generation and editing served via Prodia; takes a prompt plus up to 3 reference images and outputs 1K, 2K, or 4K."
|
|
369
|
+
},
|
|
370
|
+
capabilities: { ...IMAGE_GENERATE_EDIT }
|
|
294
371
|
},
|
|
295
372
|
{
|
|
296
373
|
// Nano Banana (img2img.v2) is flat-rate with aspect_ratio only; 3:2, 4:5,
|
|
@@ -310,7 +387,12 @@ var IMAGE_MODELS = [
|
|
|
310
387
|
},
|
|
311
388
|
defaults: { size: "1K", aspectRatio: "1:1" },
|
|
312
389
|
usage: { ...IMAGE_USAGE },
|
|
313
|
-
pricingKind: "image_size"
|
|
390
|
+
pricingKind: "image_size",
|
|
391
|
+
display: {
|
|
392
|
+
provider: "google",
|
|
393
|
+
description: "Google Nano Banana image generation and editing served via Prodia; takes a prompt plus 1-3 input images and matches the first input's aspect ratio in roughly 8 seconds."
|
|
394
|
+
},
|
|
395
|
+
capabilities: { ...IMAGE_GENERATE_EDIT }
|
|
314
396
|
},
|
|
315
397
|
{
|
|
316
398
|
// WAN 2.7 takes `images` (up to 9) and a `size` enum whose exact values
|
|
@@ -331,7 +413,12 @@ var IMAGE_MODELS = [
|
|
|
331
413
|
},
|
|
332
414
|
defaults: { size: "1K", aspectRatio: "1:1" },
|
|
333
415
|
usage: { unit: "compute_seconds", modality: "IMAGE" },
|
|
334
|
-
pricingKind: "image_size"
|
|
416
|
+
pricingKind: "image_size",
|
|
417
|
+
display: {
|
|
418
|
+
provider: "alibaba",
|
|
419
|
+
description: "Alibaba Wan 2.7 Image Pro text-to-image and image-editing model; takes a prompt plus up to 9 reference images and generates up to 4K (4096x4096)."
|
|
420
|
+
},
|
|
421
|
+
capabilities: { ...IMAGE_GENERATE_EDIT }
|
|
335
422
|
},
|
|
336
423
|
{
|
|
337
424
|
// Qwen Image 2 Pro has aspect_ratio but no size input; resolution follows
|
|
@@ -353,7 +440,12 @@ var IMAGE_MODELS = [
|
|
|
353
440
|
},
|
|
354
441
|
defaults: { aspectRatio: "1:1" },
|
|
355
442
|
usage: { unit: "compute_seconds", modality: "IMAGE" },
|
|
356
|
-
pricingKind: "image_size"
|
|
443
|
+
pricingKind: "image_size",
|
|
444
|
+
display: {
|
|
445
|
+
provider: "alibaba",
|
|
446
|
+
description: "Alibaba Qwen Image 2 Pro unified text-to-image and editing model; takes a prompt plus an optional single reference image and generates native 2K output."
|
|
447
|
+
},
|
|
448
|
+
capabilities: { ...IMAGE_GENERATE_EDIT }
|
|
357
449
|
},
|
|
358
450
|
{
|
|
359
451
|
// Qwen Image Edit Plus takes aspect_ratio (or match_input_image) and
|
|
@@ -375,7 +467,12 @@ var IMAGE_MODELS = [
|
|
|
375
467
|
},
|
|
376
468
|
defaults: { outputFormat: "png" },
|
|
377
469
|
usage: { unit: "compute_seconds", modality: "IMAGE" },
|
|
378
|
-
pricingKind: "image_size"
|
|
470
|
+
pricingKind: "image_size",
|
|
471
|
+
display: {
|
|
472
|
+
provider: "alibaba",
|
|
473
|
+
description: "Alibaba Qwen Image Edit Plus with Lightning and a skin-retouching LoRA; takes one or more reference images plus an edit prompt and outputs webp, jpg, or png."
|
|
474
|
+
},
|
|
475
|
+
capabilities: { ...IMAGE_GENERATE_EDIT }
|
|
379
476
|
}
|
|
380
477
|
];
|
|
381
478
|
|
|
@@ -396,7 +493,11 @@ var OTHER_MODELS = [
|
|
|
396
493
|
},
|
|
397
494
|
defaults: {},
|
|
398
495
|
usage: { unit: "images", modality: "AUDIO" },
|
|
399
|
-
pricingKind: "flat"
|
|
496
|
+
pricingKind: "flat",
|
|
497
|
+
display: {
|
|
498
|
+
provider: "google",
|
|
499
|
+
description: "Google Lyria 3 Clip short music clips, loops, and previews; takes text and up to 10 image prompts and returns a fixed 30-second MP3 plus lyrics."
|
|
500
|
+
}
|
|
400
501
|
},
|
|
401
502
|
{
|
|
402
503
|
id: "lyria-3-pro-preview",
|
|
@@ -412,7 +513,11 @@ var OTHER_MODELS = [
|
|
|
412
513
|
},
|
|
413
514
|
defaults: {},
|
|
414
515
|
usage: { unit: "images", modality: "AUDIO" },
|
|
415
|
-
pricingKind: "flat"
|
|
516
|
+
pricingKind: "flat",
|
|
517
|
+
display: {
|
|
518
|
+
provider: "google",
|
|
519
|
+
description: "Google Lyria 3 Pro flagship music model for full-length songs with verses, choruses, and bridges; takes text and up to 10 image prompts and returns MP3 plus lyrics."
|
|
520
|
+
}
|
|
416
521
|
},
|
|
417
522
|
{
|
|
418
523
|
id: "google/lyria-2",
|
|
@@ -428,7 +533,11 @@ var OTHER_MODELS = [
|
|
|
428
533
|
},
|
|
429
534
|
defaults: {},
|
|
430
535
|
usage: { unit: "compute_seconds", modality: "AUDIO" },
|
|
431
|
-
pricingKind: "flat"
|
|
536
|
+
pricingKind: "flat",
|
|
537
|
+
display: {
|
|
538
|
+
provider: "google",
|
|
539
|
+
description: "Lyria 2 music generation on Replicate; produces 30 seconds of 48 kHz stereo audio from a text prompt."
|
|
540
|
+
}
|
|
432
541
|
},
|
|
433
542
|
{
|
|
434
543
|
id: "mmaudio",
|
|
@@ -445,7 +554,11 @@ var OTHER_MODELS = [
|
|
|
445
554
|
},
|
|
446
555
|
defaults: { durationSeconds: 8 },
|
|
447
556
|
usage: { unit: "compute_seconds", modality: "AUDIO" },
|
|
448
|
-
pricingKind: "flat"
|
|
557
|
+
pricingKind: "flat",
|
|
558
|
+
display: {
|
|
559
|
+
provider: "mmaudio",
|
|
560
|
+
description: "MMAudio V2 video-to-audio model on Replicate; takes a source video and prompt and synthesizes synchronized environmental, action, and speech-like audio."
|
|
561
|
+
}
|
|
449
562
|
},
|
|
450
563
|
{
|
|
451
564
|
id: "elevenlabs-music",
|
|
@@ -462,7 +575,11 @@ var OTHER_MODELS = [
|
|
|
462
575
|
defaults: { durationSeconds: 15, instrumental: true },
|
|
463
576
|
// Replicate's run() does not report predict_time; billed by generated length.
|
|
464
577
|
usage: { unit: "seconds", modality: "AUDIO" },
|
|
465
|
-
pricingKind: "flat"
|
|
578
|
+
pricingKind: "flat",
|
|
579
|
+
display: {
|
|
580
|
+
provider: "elevenlabs",
|
|
581
|
+
description: "ElevenLabs Music text-to-music on Replicate; generates full songs, instrumental or with vocals, up to 5 minutes long at up to 44.1 kHz."
|
|
582
|
+
}
|
|
466
583
|
},
|
|
467
584
|
{
|
|
468
585
|
id: "topaz",
|
|
@@ -475,11 +592,16 @@ var OTHER_MODELS = [
|
|
|
475
592
|
constraints: {
|
|
476
593
|
references: { images: 1 },
|
|
477
594
|
requires: ["references"],
|
|
478
|
-
supports: ["scaleFactor", "outputFormat"]
|
|
595
|
+
supports: ["scaleFactor", "outputFormat", "upscale"]
|
|
479
596
|
},
|
|
480
597
|
defaults: { scaleFactor: 2, outputFormat: "png" },
|
|
481
598
|
usage: { unit: "compute_seconds", modality: "IMAGE" },
|
|
482
|
-
pricingKind: "flat"
|
|
599
|
+
pricingKind: "flat",
|
|
600
|
+
display: {
|
|
601
|
+
provider: "topaz",
|
|
602
|
+
description: "Topaz Labs AI image upscaling on Replicate; takes one input image and upscales up to 6x with selectable enhancement models and optional face enhancement."
|
|
603
|
+
},
|
|
604
|
+
capabilities: { imageEdit: true }
|
|
483
605
|
},
|
|
484
606
|
{
|
|
485
607
|
id: "bg-remove",
|
|
@@ -496,7 +618,12 @@ var OTHER_MODELS = [
|
|
|
496
618
|
},
|
|
497
619
|
defaults: {},
|
|
498
620
|
usage: { unit: "images", modality: "IMAGE" },
|
|
499
|
-
pricingKind: "flat"
|
|
621
|
+
pricingKind: "flat",
|
|
622
|
+
display: {
|
|
623
|
+
provider: "prodia",
|
|
624
|
+
description: "Prodia background removal; takes one input image and returns a PNG cut-out of the subject plus an optional black-and-white mask."
|
|
625
|
+
},
|
|
626
|
+
capabilities: { imageEdit: true }
|
|
500
627
|
}
|
|
501
628
|
];
|
|
502
629
|
|
|
@@ -519,22 +646,112 @@ function text(id, label, providerModelId, extra) {
|
|
|
519
646
|
};
|
|
520
647
|
}
|
|
521
648
|
var TEXT_MODELS = [
|
|
522
|
-
text("gpt-4o", "GPT-4o", "gpt-4o"
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
649
|
+
text("gpt-4o", "GPT-4o", "gpt-4o", {
|
|
650
|
+
display: {
|
|
651
|
+
provider: "openai",
|
|
652
|
+
description: "OpenAI GPT-4o flagship multimodal model; text and image input, 128K-token context."
|
|
653
|
+
},
|
|
654
|
+
capabilities: { vision: true, tools: true, structuredOutput: true, contextWindow: 128e3 }
|
|
655
|
+
}),
|
|
656
|
+
text("gpt-4o-mini", "GPT-4o mini", "gpt-4o-mini", {
|
|
657
|
+
display: {
|
|
658
|
+
provider: "openai",
|
|
659
|
+
description: "OpenAI GPT-4o mini fast, low-cost multimodal model; text and image input, 128K-token context."
|
|
660
|
+
},
|
|
661
|
+
capabilities: { vision: true, tools: true, structuredOutput: true, contextWindow: 128e3 }
|
|
662
|
+
}),
|
|
663
|
+
text("gpt-5.1", "GPT-5.1", "gpt-5.1", {
|
|
664
|
+
display: {
|
|
665
|
+
provider: "openai",
|
|
666
|
+
description: "OpenAI GPT-5.1 reasoning model for coding and agentic tasks; text and image input, 400K-token context."
|
|
667
|
+
},
|
|
668
|
+
capabilities: { vision: true, tools: true, structuredOutput: true, contextWindow: 4e5 }
|
|
669
|
+
}),
|
|
670
|
+
text("gpt-5.2", "GPT-5.2", "gpt-5.2", {
|
|
671
|
+
display: {
|
|
672
|
+
provider: "openai",
|
|
673
|
+
description: "OpenAI GPT-5.2 reasoning model for complex professional work; text and image input, 400K-token context."
|
|
674
|
+
},
|
|
675
|
+
capabilities: { vision: true, tools: true, structuredOutput: true, contextWindow: 4e5 }
|
|
676
|
+
}),
|
|
677
|
+
// 1.05M-token context: https://platform.openai.com/docs/models/gpt-5.4
|
|
678
|
+
text("gpt-5.4", "GPT-5.4", "gpt-5.4", {
|
|
679
|
+
display: {
|
|
680
|
+
provider: "openai",
|
|
681
|
+
description: "OpenAI GPT-5.4 flagship reasoning model; text and image input, 1.05M-token context."
|
|
682
|
+
},
|
|
683
|
+
capabilities: {
|
|
684
|
+
vision: true,
|
|
685
|
+
tools: true,
|
|
686
|
+
structuredOutput: true,
|
|
687
|
+
contextWindow: 105e4
|
|
688
|
+
}
|
|
689
|
+
}),
|
|
527
690
|
// OpenAI never shipped gpt-5.1-mini or gpt-5.2-mini; callers that still send them get 5.4 mini.
|
|
528
691
|
text("gpt-5.4-mini", "GPT-5.4 mini", "gpt-5.4-mini", {
|
|
529
|
-
aliases: ["gpt-5.1-mini", "gpt-5.2-mini"]
|
|
692
|
+
aliases: ["gpt-5.1-mini", "gpt-5.2-mini"],
|
|
693
|
+
display: {
|
|
694
|
+
provider: "openai",
|
|
695
|
+
description: "OpenAI GPT-5.4 mini efficient reasoning model for high-volume workloads; text and image input, 400K-token context."
|
|
696
|
+
},
|
|
697
|
+
capabilities: { vision: true, tools: true, structuredOutput: true, contextWindow: 4e5 }
|
|
698
|
+
}),
|
|
699
|
+
text("gpt-5.5", "GPT-5.5", "gpt-5.5", {
|
|
700
|
+
display: {
|
|
701
|
+
provider: "openai",
|
|
702
|
+
description: "OpenAI GPT-5.5 flagship reasoning model for the most complex professional and coding work; text and image input, 1.05M-token context."
|
|
703
|
+
},
|
|
704
|
+
capabilities: {
|
|
705
|
+
vision: true,
|
|
706
|
+
tools: true,
|
|
707
|
+
structuredOutput: true,
|
|
708
|
+
contextWindow: 105e4
|
|
709
|
+
}
|
|
710
|
+
}),
|
|
711
|
+
text("gpt-5.6-luna", "GPT-5.6 Luna", "gpt-5.6-luna", {
|
|
712
|
+
display: {
|
|
713
|
+
provider: "openai",
|
|
714
|
+
description: "OpenAI GPT-5.6 Luna cost-optimized tier of the GPT-5.6 reasoning family; text and image input, 1.05M-token context."
|
|
715
|
+
},
|
|
716
|
+
capabilities: {
|
|
717
|
+
vision: true,
|
|
718
|
+
tools: true,
|
|
719
|
+
structuredOutput: true,
|
|
720
|
+
contextWindow: 105e4
|
|
721
|
+
}
|
|
722
|
+
}),
|
|
723
|
+
text("gpt-5.6-terra", "GPT-5.6 Terra", "gpt-5.6-terra", {
|
|
724
|
+
display: {
|
|
725
|
+
provider: "openai",
|
|
726
|
+
description: "OpenAI GPT-5.6 Terra balanced tier of the GPT-5.6 reasoning family; text and image input, 1.05M-token context."
|
|
727
|
+
},
|
|
728
|
+
capabilities: {
|
|
729
|
+
vision: true,
|
|
730
|
+
tools: true,
|
|
731
|
+
structuredOutput: true,
|
|
732
|
+
contextWindow: 105e4
|
|
733
|
+
}
|
|
734
|
+
}),
|
|
735
|
+
text("gpt-5.6-sol", "GPT-5.6 Sol", "gpt-5.6-sol", {
|
|
736
|
+
display: {
|
|
737
|
+
provider: "openai",
|
|
738
|
+
description: "OpenAI GPT-5.6 Sol flagship tier of the GPT-5.6 reasoning family; text and image input, 1.05M-token context."
|
|
739
|
+
},
|
|
740
|
+
capabilities: {
|
|
741
|
+
vision: true,
|
|
742
|
+
tools: true,
|
|
743
|
+
structuredOutput: true,
|
|
744
|
+
contextWindow: 105e4
|
|
745
|
+
}
|
|
530
746
|
}),
|
|
531
|
-
text("gpt-5.5", "GPT-5.5", "gpt-5.5"),
|
|
532
|
-
text("gpt-5.6-luna", "GPT-5.6 Luna", "gpt-5.6-luna"),
|
|
533
|
-
text("gpt-5.6-terra", "GPT-5.6 Terra", "gpt-5.6-terra"),
|
|
534
|
-
text("gpt-5.6-sol", "GPT-5.6 Sol", "gpt-5.6-sol"),
|
|
535
747
|
// Library key "claude-sonnet-4.5" maps to the SDK id "claude-sonnet-4-5".
|
|
536
748
|
text("claude-sonnet-4-5", "Claude Sonnet 4.5", "claude-sonnet-4-5", {
|
|
537
|
-
aliases: ["claude-sonnet-4.5", "claude-sonnet-4-5-20250929"]
|
|
749
|
+
aliases: ["claude-sonnet-4.5", "claude-sonnet-4-5-20250929"],
|
|
750
|
+
display: {
|
|
751
|
+
provider: "anthropic",
|
|
752
|
+
description: "Anthropic Claude Sonnet 4.5 (legacy) balanced model; text and image input, 200K-token context."
|
|
753
|
+
},
|
|
754
|
+
capabilities: { vision: true, tools: true, structuredOutput: true, contextWindow: 2e5 }
|
|
538
755
|
}),
|
|
539
756
|
// Anthropic retired the dated 4.0 ids; callers that still send them get 4.6.
|
|
540
757
|
text("claude-sonnet-4-6", "Claude Sonnet 4.6", "claude-sonnet-4-6", {
|
|
@@ -543,42 +760,280 @@ var TEXT_MODELS = [
|
|
|
543
760
|
"claude-sonnet-4",
|
|
544
761
|
"claude-sonnet-4.0",
|
|
545
762
|
"claude-sonnet-4-20250514"
|
|
546
|
-
]
|
|
763
|
+
],
|
|
764
|
+
display: {
|
|
765
|
+
provider: "anthropic",
|
|
766
|
+
description: "Anthropic Claude Sonnet 4.6 (legacy) balanced model; text and image input, 1M-token context."
|
|
767
|
+
},
|
|
768
|
+
capabilities: {
|
|
769
|
+
vision: true,
|
|
770
|
+
tools: true,
|
|
771
|
+
structuredOutput: true,
|
|
772
|
+
contextWindow: 1e6
|
|
773
|
+
}
|
|
774
|
+
}),
|
|
775
|
+
text("claude-sonnet-5", "Claude Sonnet 5", "claude-sonnet-5", {
|
|
776
|
+
display: {
|
|
777
|
+
provider: "anthropic",
|
|
778
|
+
description: "Anthropic Claude Sonnet 5 current balanced model; text and image input, 1M-token context."
|
|
779
|
+
},
|
|
780
|
+
capabilities: {
|
|
781
|
+
vision: true,
|
|
782
|
+
tools: true,
|
|
783
|
+
structuredOutput: true,
|
|
784
|
+
contextWindow: 1e6
|
|
785
|
+
}
|
|
547
786
|
}),
|
|
548
|
-
text("claude-sonnet-5", "Claude Sonnet 5", "claude-sonnet-5"),
|
|
549
787
|
text("claude-opus-4-8", "Claude Opus 4.8", "claude-opus-4-8", {
|
|
550
|
-
aliases: ["claude-opus-4.8", "claude-opus-4", "claude-opus-4.0", "claude-opus-4-20250514"]
|
|
788
|
+
aliases: ["claude-opus-4.8", "claude-opus-4", "claude-opus-4.0", "claude-opus-4-20250514"],
|
|
789
|
+
display: {
|
|
790
|
+
provider: "anthropic",
|
|
791
|
+
description: "Anthropic Claude Opus 4.8 (legacy) frontier model; text and image input, 1M-token context."
|
|
792
|
+
},
|
|
793
|
+
capabilities: {
|
|
794
|
+
vision: true,
|
|
795
|
+
tools: true,
|
|
796
|
+
structuredOutput: true,
|
|
797
|
+
contextWindow: 1e6
|
|
798
|
+
}
|
|
551
799
|
}),
|
|
552
800
|
text("claude-haiku-4-5", "Claude Haiku 4.5", "claude-haiku-4-5", {
|
|
553
|
-
aliases: ["claude-haiku-4.5", "claude-haiku-4-5-20251001", "claude-haiku-4"]
|
|
801
|
+
aliases: ["claude-haiku-4.5", "claude-haiku-4-5-20251001", "claude-haiku-4"],
|
|
802
|
+
display: {
|
|
803
|
+
provider: "anthropic",
|
|
804
|
+
description: "Anthropic Claude Haiku 4.5 fast model with near-frontier intelligence; text and image input, 200K-token context."
|
|
805
|
+
},
|
|
806
|
+
capabilities: { vision: true, tools: true, structuredOutput: true, contextWindow: 2e5 }
|
|
554
807
|
}),
|
|
555
808
|
text("claude-opus-5", "Claude Opus 5", "claude-opus-5", {
|
|
556
|
-
aliases: ["claude-opus-5.0"]
|
|
809
|
+
aliases: ["claude-opus-5.0"],
|
|
810
|
+
display: {
|
|
811
|
+
provider: "anthropic",
|
|
812
|
+
description: "Anthropic Claude Opus 5 current frontier model for agentic coding and enterprise work; text and image input, 1M-token context."
|
|
813
|
+
},
|
|
814
|
+
capabilities: {
|
|
815
|
+
vision: true,
|
|
816
|
+
tools: true,
|
|
817
|
+
structuredOutput: true,
|
|
818
|
+
contextWindow: 1e6
|
|
819
|
+
}
|
|
820
|
+
}),
|
|
821
|
+
text("claude-fable-5", "Claude Fable 5", "claude-fable-5", {
|
|
822
|
+
display: {
|
|
823
|
+
provider: "anthropic",
|
|
824
|
+
description: "Anthropic Claude Fable 5 (legacy) model for demanding reasoning and long-horizon agentic work; text and image input, 1M-token context."
|
|
825
|
+
},
|
|
826
|
+
capabilities: {
|
|
827
|
+
vision: true,
|
|
828
|
+
tools: true,
|
|
829
|
+
structuredOutput: true,
|
|
830
|
+
contextWindow: 1e6
|
|
831
|
+
}
|
|
832
|
+
}),
|
|
833
|
+
text("gemini-2.5-flash", "Gemini 2.5 Flash", "gemini-2.5-flash", {
|
|
834
|
+
display: {
|
|
835
|
+
provider: "google",
|
|
836
|
+
description: "Google Gemini 2.5 Flash low-latency multimodal model for high-volume reasoning over text, images, video, and audio; 1M-token context."
|
|
837
|
+
},
|
|
838
|
+
capabilities: {
|
|
839
|
+
vision: true,
|
|
840
|
+
tools: true,
|
|
841
|
+
structuredOutput: true,
|
|
842
|
+
contextWindow: 1048576
|
|
843
|
+
}
|
|
844
|
+
}),
|
|
845
|
+
text("gemini-2.5-pro", "Gemini 2.5 Pro", "gemini-2.5-pro", {
|
|
846
|
+
display: {
|
|
847
|
+
provider: "google",
|
|
848
|
+
description: "Google Gemini 2.5 Pro thinking model for complex reasoning over code, math, and documents; text, image, video, audio, and PDF input, 1M-token context."
|
|
849
|
+
},
|
|
850
|
+
capabilities: {
|
|
851
|
+
vision: true,
|
|
852
|
+
tools: true,
|
|
853
|
+
structuredOutput: true,
|
|
854
|
+
contextWindow: 1048576
|
|
855
|
+
}
|
|
856
|
+
}),
|
|
857
|
+
text("gemini-3.1-pro-preview", "Gemini 3.1 Pro (preview)", "gemini-3.1-pro-preview", {
|
|
858
|
+
display: {
|
|
859
|
+
provider: "google",
|
|
860
|
+
description: "Google Gemini 3.1 Pro preview reasoning model for software engineering, tool use, and reliable agentic workflows; 1M-token context."
|
|
861
|
+
},
|
|
862
|
+
capabilities: {
|
|
863
|
+
vision: true,
|
|
864
|
+
tools: true,
|
|
865
|
+
structuredOutput: true,
|
|
866
|
+
contextWindow: 1048576
|
|
867
|
+
}
|
|
868
|
+
}),
|
|
869
|
+
text("gemini-3.5-flash", "Gemini 3.5 Flash", "gemini-3.5-flash", {
|
|
870
|
+
display: {
|
|
871
|
+
provider: "google",
|
|
872
|
+
description: "Google Gemini 3.5 Flash high-throughput model for frontier-level agentic tasks; text, image, video, audio, and PDF input, 1M-token context."
|
|
873
|
+
},
|
|
874
|
+
capabilities: {
|
|
875
|
+
vision: true,
|
|
876
|
+
tools: true,
|
|
877
|
+
structuredOutput: true,
|
|
878
|
+
contextWindow: 1048576
|
|
879
|
+
}
|
|
880
|
+
}),
|
|
881
|
+
text("gemini-3.6-flash", "Gemini 3.6 Flash", "gemini-3.6-flash", {
|
|
882
|
+
display: {
|
|
883
|
+
provider: "google",
|
|
884
|
+
description: "Google Gemini 3.6 Flash general-purpose multimodal agentic model balancing speed and capability; 1M-token context."
|
|
885
|
+
},
|
|
886
|
+
capabilities: {
|
|
887
|
+
vision: true,
|
|
888
|
+
tools: true,
|
|
889
|
+
structuredOutput: true,
|
|
890
|
+
contextWindow: 1048576
|
|
891
|
+
}
|
|
892
|
+
}),
|
|
893
|
+
text("gemini-3.7-flash", "Gemini 3.7 Flash", "gemini-3.7-flash", {
|
|
894
|
+
display: {
|
|
895
|
+
provider: "google",
|
|
896
|
+
description: "Google Gemini 3.7 Flash natively multimodal reasoning model for coding, agentic workflows, and multi-step execution; 1M-token context."
|
|
897
|
+
},
|
|
898
|
+
capabilities: {
|
|
899
|
+
vision: true,
|
|
900
|
+
tools: true,
|
|
901
|
+
structuredOutput: true,
|
|
902
|
+
contextWindow: 1048576
|
|
903
|
+
}
|
|
904
|
+
}),
|
|
905
|
+
text("gemini-3.8-flash", "Gemini 3.8 Flash", "gemini-3.8-flash", {
|
|
906
|
+
display: {
|
|
907
|
+
provider: "google",
|
|
908
|
+
description: "Google Gemini 3.8 Flash frontier model for long-horizon software engineering, autonomous agents, and enterprise workflows; 1M-token context."
|
|
909
|
+
},
|
|
910
|
+
capabilities: {
|
|
911
|
+
vision: true,
|
|
912
|
+
tools: true,
|
|
913
|
+
structuredOutput: true,
|
|
914
|
+
contextWindow: 1048576
|
|
915
|
+
}
|
|
557
916
|
}),
|
|
558
|
-
text("claude-fable-5", "Claude Fable 5", "claude-fable-5"),
|
|
559
|
-
text("gemini-2.5-flash", "Gemini 2.5 Flash", "gemini-2.5-flash"),
|
|
560
|
-
text("gemini-2.5-pro", "Gemini 2.5 Pro", "gemini-2.5-pro"),
|
|
561
|
-
text("gemini-3.1-pro-preview", "Gemini 3.1 Pro (preview)", "gemini-3.1-pro-preview"),
|
|
562
|
-
text("gemini-3.5-flash", "Gemini 3.5 Flash", "gemini-3.5-flash"),
|
|
563
|
-
text("gemini-3.6-flash", "Gemini 3.6 Flash", "gemini-3.6-flash"),
|
|
564
|
-
text("gemini-3.7-flash", "Gemini 3.7 Flash", "gemini-3.7-flash"),
|
|
565
|
-
text("gemini-3.8-flash", "Gemini 3.8 Flash", "gemini-3.8-flash"),
|
|
566
917
|
// Renamed to gemini-3.6-flash in vibe-shared model-migration.ts.
|
|
567
918
|
text("gemini-3-flash-preview", "Gemini 3 Flash (preview)", "gemini-3-flash-preview", {
|
|
568
919
|
lifecycle: "deprecated",
|
|
569
920
|
replacedBy: "gemini-3.6-flash"
|
|
570
921
|
}),
|
|
571
|
-
text("gemini-3.1-flash-lite", "Gemini 3.1 Flash Lite", "gemini-3.1-flash-lite"
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
922
|
+
text("gemini-3.1-flash-lite", "Gemini 3.1 Flash Lite", "gemini-3.1-flash-lite", {
|
|
923
|
+
display: {
|
|
924
|
+
provider: "google",
|
|
925
|
+
description: "Google Gemini 3.1 Flash-Lite low-latency multimodal model for high-volume agentic, translation, and data-extraction tasks; 1M-token context."
|
|
926
|
+
},
|
|
927
|
+
capabilities: {
|
|
928
|
+
vision: true,
|
|
929
|
+
tools: true,
|
|
930
|
+
structuredOutput: true,
|
|
931
|
+
contextWindow: 1048576
|
|
932
|
+
}
|
|
933
|
+
}),
|
|
934
|
+
text("sonar", "Sonar", "sonar", {
|
|
935
|
+
display: {
|
|
936
|
+
provider: "perplexity",
|
|
937
|
+
description: "Perplexity Sonar lightweight web-grounded search model returning cited answers; 128K-token context."
|
|
938
|
+
},
|
|
939
|
+
capabilities: {
|
|
940
|
+
vision: true,
|
|
941
|
+
tools: false,
|
|
942
|
+
structuredOutput: true,
|
|
943
|
+
contextWindow: 128e3
|
|
944
|
+
}
|
|
945
|
+
}),
|
|
946
|
+
text("sonar-pro", "Sonar Pro", "sonar-pro", {
|
|
947
|
+
display: {
|
|
948
|
+
provider: "perplexity",
|
|
949
|
+
description: "Perplexity Sonar Pro advanced web-grounded search model for complex multi-step queries; 200K-token context."
|
|
950
|
+
},
|
|
951
|
+
capabilities: {
|
|
952
|
+
vision: true,
|
|
953
|
+
tools: false,
|
|
954
|
+
structuredOutput: true,
|
|
955
|
+
contextWindow: 2e5
|
|
956
|
+
}
|
|
957
|
+
}),
|
|
958
|
+
text("sonar-reasoning-pro", "Sonar Reasoning Pro", "sonar-reasoning-pro", {
|
|
959
|
+
display: {
|
|
960
|
+
provider: "perplexity",
|
|
961
|
+
description: "Perplexity Sonar Reasoning Pro chain-of-thought web-grounded search model for complex problem-solving; 128K-token context."
|
|
962
|
+
},
|
|
963
|
+
capabilities: {
|
|
964
|
+
vision: true,
|
|
965
|
+
tools: false,
|
|
966
|
+
structuredOutput: true,
|
|
967
|
+
contextWindow: 128e3
|
|
968
|
+
}
|
|
969
|
+
}),
|
|
970
|
+
text("deepseek-v4-flash", "DeepSeek V4 Flash", "deepseek-v4-flash", {
|
|
971
|
+
display: {
|
|
972
|
+
provider: "deepseek",
|
|
973
|
+
description: "DeepSeek V4 Flash thinking/non-thinking model with vision, tool calls, and JSON output; 1M-token context and up to 384K output tokens."
|
|
974
|
+
},
|
|
975
|
+
capabilities: {
|
|
976
|
+
vision: true,
|
|
977
|
+
tools: true,
|
|
978
|
+
structuredOutput: true,
|
|
979
|
+
contextWindow: 1e6
|
|
980
|
+
}
|
|
981
|
+
}),
|
|
982
|
+
text("deepseek-v4-pro", "DeepSeek V4 Pro", "deepseek-v4-pro", {
|
|
983
|
+
display: {
|
|
984
|
+
provider: "deepseek",
|
|
985
|
+
description: "DeepSeek V4 Pro thinking/non-thinking text model with tool calls and JSON output (no vision); 1M-token context and up to 384K output tokens."
|
|
986
|
+
},
|
|
987
|
+
capabilities: {
|
|
988
|
+
vision: false,
|
|
989
|
+
tools: true,
|
|
990
|
+
structuredOutput: true,
|
|
991
|
+
contextWindow: 1e6
|
|
992
|
+
}
|
|
993
|
+
}),
|
|
994
|
+
// 1M-token context: https://docs.x.ai/docs/models/grok-4.3
|
|
995
|
+
text("grok-4.3", "Grok 4.3", "grok-4.3", {
|
|
996
|
+
display: {
|
|
997
|
+
provider: "xai",
|
|
998
|
+
description: "xAI Grok 4.3 reasoning model with tool calling and structured outputs; text and image input, 1M-token context."
|
|
999
|
+
},
|
|
1000
|
+
capabilities: {
|
|
1001
|
+
vision: true,
|
|
1002
|
+
tools: true,
|
|
1003
|
+
structuredOutput: true,
|
|
1004
|
+
contextWindow: 1e6
|
|
1005
|
+
}
|
|
1006
|
+
}),
|
|
1007
|
+
// Moonshot retired kimi-k2.5 on 2026-08-31 and no longer publishes its specs.
|
|
1008
|
+
text("kimi-k2.5", "Kimi K2.5", "kimi-k2.5", {
|
|
1009
|
+
display: {
|
|
1010
|
+
provider: "moonshot",
|
|
1011
|
+
description: "Moonshot Kimi K2.5; the provider retired the model on 2026-08-31 and calls now return a model-not-found error."
|
|
1012
|
+
},
|
|
1013
|
+
capabilities: {}
|
|
1014
|
+
}),
|
|
1015
|
+
text("kimi-k3", "Kimi K3", "kimi-k3", {
|
|
1016
|
+
display: {
|
|
1017
|
+
provider: "moonshot",
|
|
1018
|
+
description: "Moonshot Kimi K3 flagship model with native visual understanding and always-on thinking; text, image, and video input, 1M-token context."
|
|
1019
|
+
},
|
|
1020
|
+
capabilities: {
|
|
1021
|
+
vision: true,
|
|
1022
|
+
tools: true,
|
|
1023
|
+
structuredOutput: true,
|
|
1024
|
+
contextWindow: 1e6
|
|
1025
|
+
}
|
|
1026
|
+
}),
|
|
580
1027
|
// Cowork calls the provider "MiniMax-M3"; the pricing key is lowercase.
|
|
581
|
-
|
|
1028
|
+
// 1M-token context: https://platform.minimax.io/docs/api-reference/text-openai-api
|
|
1029
|
+
text("minimax-m3", "MiniMax M3", "MiniMax-M3", {
|
|
1030
|
+
aliases: ["MiniMax-M3"],
|
|
1031
|
+
display: {
|
|
1032
|
+
provider: "minimax",
|
|
1033
|
+
description: "MiniMax M3 frontier multimodal model for agentic reasoning, tool use, and coding; text, image, and video input, 1M-token context."
|
|
1034
|
+
},
|
|
1035
|
+
capabilities: { vision: true, tools: true, contextWindow: 1e6 }
|
|
1036
|
+
})
|
|
582
1037
|
];
|
|
583
1038
|
|
|
584
1039
|
// src/catalog/video.ts
|
|
@@ -590,6 +1045,8 @@ var GROK_RATIOS = ["1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3"];
|
|
|
590
1045
|
var H3_RATIOS = ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16"];
|
|
591
1046
|
var H3_REFERENCE_RATIOS = ["adaptive", ...H3_RATIOS];
|
|
592
1047
|
var NEGATIVE_PROMPT = "blur, distort, and low quality";
|
|
1048
|
+
var FRAMES_EXCLUDE_REFERENCES = { framesExcludeReferences: true };
|
|
1049
|
+
var GOOGLE_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
|
|
593
1050
|
var VIDEO_MODELS = [
|
|
594
1051
|
{
|
|
595
1052
|
id: "veo-3.1",
|
|
@@ -613,7 +1070,13 @@ var VIDEO_MODELS = [
|
|
|
613
1070
|
},
|
|
614
1071
|
defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
|
|
615
1072
|
usage: { ...VIDEO_USAGE },
|
|
616
|
-
pricingKind: "video_per_second"
|
|
1073
|
+
pricingKind: "video_per_second",
|
|
1074
|
+
display: {
|
|
1075
|
+
provider: "google",
|
|
1076
|
+
description: "Google's highest-quality video generation model. Supports up to 4K resolution and 8-second clips with reference image conditioning.",
|
|
1077
|
+
logo: GOOGLE_LOGO
|
|
1078
|
+
},
|
|
1079
|
+
capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
|
|
617
1080
|
},
|
|
618
1081
|
{
|
|
619
1082
|
id: "veo-3.1-fast",
|
|
@@ -636,7 +1099,12 @@ var VIDEO_MODELS = [
|
|
|
636
1099
|
},
|
|
637
1100
|
defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
|
|
638
1101
|
usage: { ...VIDEO_USAGE },
|
|
639
|
-
pricingKind: "video_per_second"
|
|
1102
|
+
pricingKind: "video_per_second",
|
|
1103
|
+
display: {
|
|
1104
|
+
provider: "google",
|
|
1105
|
+
description: "Faster variant of Google Veo 3.1; text- and image-to-video with natively generated audio at 4 or 8 seconds."
|
|
1106
|
+
},
|
|
1107
|
+
capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
|
|
640
1108
|
},
|
|
641
1109
|
{
|
|
642
1110
|
id: "veo-3.1-lite",
|
|
@@ -659,7 +1127,12 @@ var VIDEO_MODELS = [
|
|
|
659
1127
|
},
|
|
660
1128
|
defaults: { durationSeconds: 8, resolution: "720p", aspectRatio: "16:9" },
|
|
661
1129
|
usage: { ...VIDEO_USAGE },
|
|
662
|
-
pricingKind: "video_per_second"
|
|
1130
|
+
pricingKind: "video_per_second",
|
|
1131
|
+
display: {
|
|
1132
|
+
provider: "google",
|
|
1133
|
+
description: "Efficiency-focused Google Veo 3.1 Lite for high-volume video generation and editing; text and image input, with no 4K output or video extension."
|
|
1134
|
+
},
|
|
1135
|
+
capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
|
|
663
1136
|
},
|
|
664
1137
|
{
|
|
665
1138
|
id: "gemini-omni-flash",
|
|
@@ -686,7 +1159,13 @@ var VIDEO_MODELS = [
|
|
|
686
1159
|
},
|
|
687
1160
|
defaults: {},
|
|
688
1161
|
usage: { ...VIDEO_USAGE },
|
|
689
|
-
pricingKind: "video_per_second"
|
|
1162
|
+
pricingKind: "video_per_second",
|
|
1163
|
+
display: {
|
|
1164
|
+
provider: "google",
|
|
1165
|
+
description: "Google's conversational video model with native audio, human support, and natural language editing. Aspect ratio only \u2014 resolution and duration are model-determined.",
|
|
1166
|
+
logo: GOOGLE_LOGO
|
|
1167
|
+
},
|
|
1168
|
+
capabilities: { acceptsSourceVideo: true }
|
|
690
1169
|
},
|
|
691
1170
|
{
|
|
692
1171
|
id: "gemini-omni-1.1-flash",
|
|
@@ -705,7 +1184,12 @@ var VIDEO_MODELS = [
|
|
|
705
1184
|
},
|
|
706
1185
|
defaults: {},
|
|
707
1186
|
usage: { ...VIDEO_USAGE },
|
|
708
|
-
pricingKind: "video_per_second"
|
|
1187
|
+
pricingKind: "video_per_second",
|
|
1188
|
+
display: {
|
|
1189
|
+
provider: "google",
|
|
1190
|
+
description: "Google Gemini Omni Flash 1.1 conversational video generation and editing; text, image, and up to 10-second video input, 3-10 second output at up to 4K and 24 FPS."
|
|
1191
|
+
},
|
|
1192
|
+
capabilities: { acceptsSourceVideo: true }
|
|
709
1193
|
},
|
|
710
1194
|
{
|
|
711
1195
|
// vibe-triggers and Space Builder drop the ratio when a frame is wired; Cowork always sends it.
|
|
@@ -722,7 +1206,7 @@ var VIDEO_MODELS = [
|
|
|
722
1206
|
durations: [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
|
|
723
1207
|
references: { images: 9, videos: 3, audios: 3, audioOnly: false },
|
|
724
1208
|
ratioIgnoredWith: ["firstFrame"],
|
|
725
|
-
supports: ["generateAudio", "seed", "lastFrame"]
|
|
1209
|
+
supports: ["generateAudio", "seed", "lastFrame", "watermark"]
|
|
726
1210
|
},
|
|
727
1211
|
defaults: {
|
|
728
1212
|
durationSeconds: 5,
|
|
@@ -731,7 +1215,13 @@ var VIDEO_MODELS = [
|
|
|
731
1215
|
generateAudio: true
|
|
732
1216
|
},
|
|
733
1217
|
usage: { ...VIDEO_USAGE },
|
|
734
|
-
pricingKind: "video_per_second"
|
|
1218
|
+
pricingKind: "video_per_second",
|
|
1219
|
+
display: {
|
|
1220
|
+
provider: "bytedance",
|
|
1221
|
+
description: "High-quality AI video generation with reference image conditioning. Supports 4-15 second clips with human preprocessing.",
|
|
1222
|
+
logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/3bba5d81-4e57-4e71-911b-cdfa05acca2c_compressed.png"
|
|
1223
|
+
},
|
|
1224
|
+
capabilities: { acceptsSourceVideo: true, ...FRAMES_EXCLUDE_REFERENCES }
|
|
735
1225
|
},
|
|
736
1226
|
{
|
|
737
1227
|
id: "seedance-2.0-fast",
|
|
@@ -747,7 +1237,7 @@ var VIDEO_MODELS = [
|
|
|
747
1237
|
durations: [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
|
|
748
1238
|
references: { images: 9, videos: 3, audios: 3, audioOnly: false },
|
|
749
1239
|
ratioIgnoredWith: ["firstFrame"],
|
|
750
|
-
supports: ["generateAudio", "seed", "lastFrame"]
|
|
1240
|
+
supports: ["generateAudio", "seed", "lastFrame", "watermark"]
|
|
751
1241
|
},
|
|
752
1242
|
defaults: {
|
|
753
1243
|
durationSeconds: 5,
|
|
@@ -756,7 +1246,12 @@ var VIDEO_MODELS = [
|
|
|
756
1246
|
generateAudio: true
|
|
757
1247
|
},
|
|
758
1248
|
usage: { ...VIDEO_USAGE },
|
|
759
|
-
pricingKind: "video_per_second"
|
|
1249
|
+
pricingKind: "video_per_second",
|
|
1250
|
+
display: {
|
|
1251
|
+
provider: "bytedance",
|
|
1252
|
+
description: "Speed- and cost-optimized ByteDance Seedance 2.0 Fast; text plus image, video, and audio references to generate or edit 4-15 second clips."
|
|
1253
|
+
},
|
|
1254
|
+
capabilities: { acceptsSourceVideo: true, ...FRAMES_EXCLUDE_REFERENCES }
|
|
760
1255
|
},
|
|
761
1256
|
{
|
|
762
1257
|
// generateAudio defaults to false here (trigger-workflows); Space Builder defaults it to true.
|
|
@@ -773,7 +1268,7 @@ var VIDEO_MODELS = [
|
|
|
773
1268
|
durations: { min: 4, max: 30 },
|
|
774
1269
|
references: { images: 30, videos: 10, audios: 10 },
|
|
775
1270
|
ratioIgnoredWith: ["firstFrame"],
|
|
776
|
-
supports: ["generateAudio", "seed", "lastFrame"]
|
|
1271
|
+
supports: ["generateAudio", "seed", "lastFrame", "watermark"]
|
|
777
1272
|
},
|
|
778
1273
|
defaults: {
|
|
779
1274
|
durationSeconds: 5,
|
|
@@ -782,7 +1277,12 @@ var VIDEO_MODELS = [
|
|
|
782
1277
|
generateAudio: false
|
|
783
1278
|
},
|
|
784
1279
|
usage: { ...VIDEO_USAGE },
|
|
785
|
-
pricingKind: "video_per_second"
|
|
1280
|
+
pricingKind: "video_per_second",
|
|
1281
|
+
display: {
|
|
1282
|
+
provider: "bytedance",
|
|
1283
|
+
description: "ByteDance Seedance 2.5 for long-form storytelling and omni-reference generation/editing; up to 50 reference assets and 4-30 second clips at up to 1080p."
|
|
1284
|
+
},
|
|
1285
|
+
capabilities: { acceptsSourceVideo: true, ...FRAMES_EXCLUDE_REFERENCES }
|
|
786
1286
|
},
|
|
787
1287
|
{
|
|
788
1288
|
// Cowork allows 7 reference images and durations 4/6/8/10; Space Builder allows 5 and 1-15s.
|
|
@@ -800,9 +1300,16 @@ var VIDEO_MODELS = [
|
|
|
800
1300
|
references: { images: 7 },
|
|
801
1301
|
supports: []
|
|
802
1302
|
},
|
|
803
|
-
|
|
1303
|
+
// No resolution default: xAI picks its own unless the caller asks.
|
|
1304
|
+
defaults: { durationSeconds: 8, aspectRatio: "16:9" },
|
|
804
1305
|
usage: { unit: "reported_cost_usd", modality: "VIDEO" },
|
|
805
|
-
pricingKind: "video_per_second"
|
|
1306
|
+
pricingKind: "video_per_second",
|
|
1307
|
+
display: {
|
|
1308
|
+
provider: "xai",
|
|
1309
|
+
description: "xAI's reference-to-video model. Generates short clips conditioned on up to 7 reference images with flexible aspect ratios.",
|
|
1310
|
+
logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/858b7fcc-9bd5-411d-aea1-a7b35ecfffab_compressed.png"
|
|
1311
|
+
},
|
|
1312
|
+
capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
|
|
806
1313
|
},
|
|
807
1314
|
{
|
|
808
1315
|
id: "kling-2.5",
|
|
@@ -825,7 +1332,12 @@ var VIDEO_MODELS = [
|
|
|
825
1332
|
negativePrompt: NEGATIVE_PROMPT
|
|
826
1333
|
},
|
|
827
1334
|
usage: { ...VIDEO_USAGE },
|
|
828
|
-
pricingKind: "video_per_second"
|
|
1335
|
+
pricingKind: "video_per_second",
|
|
1336
|
+
display: {
|
|
1337
|
+
provider: "kuaishou",
|
|
1338
|
+
description: "Kuaishou Kling 2.5 Turbo Pro image-to-video; animates a single input image from a text prompt with an optional end image, 5- or 10-second clips."
|
|
1339
|
+
},
|
|
1340
|
+
capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
|
|
829
1341
|
},
|
|
830
1342
|
{
|
|
831
1343
|
// trigger-workflows validates 5/10 only; Space Builder allows 3-15s (Kling30Input).
|
|
@@ -849,7 +1361,12 @@ var VIDEO_MODELS = [
|
|
|
849
1361
|
negativePrompt: NEGATIVE_PROMPT
|
|
850
1362
|
},
|
|
851
1363
|
usage: { ...VIDEO_USAGE },
|
|
852
|
-
pricingKind: "video_per_second"
|
|
1364
|
+
pricingKind: "video_per_second",
|
|
1365
|
+
display: {
|
|
1366
|
+
provider: "kuaishou",
|
|
1367
|
+
description: "Kuaishou Kling 3.0 Pro image-to-video; a required start image plus a text prompt (or multi-shot prompts) with optional end image and native audio, 3-15 second clips."
|
|
1368
|
+
},
|
|
1369
|
+
capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
|
|
853
1370
|
},
|
|
854
1371
|
{
|
|
855
1372
|
// mode standard/pro selects 720p/1080p; the endpoint takes no separate resolution.
|
|
@@ -880,7 +1397,12 @@ var VIDEO_MODELS = [
|
|
|
880
1397
|
},
|
|
881
1398
|
defaults: { durationSeconds: 5, aspectRatio: "16:9", generateAudio: false, mode: "pro" },
|
|
882
1399
|
usage: { unit: "compute_seconds", modality: "VIDEO" },
|
|
883
|
-
pricingKind: "video_per_second"
|
|
1400
|
+
pricingKind: "video_per_second",
|
|
1401
|
+
display: {
|
|
1402
|
+
provider: "kuaishou",
|
|
1403
|
+
description: "Kuaishou Kling Video 3.0 Omni unified generation and editing from text, start/end images, up to 7 reference images, and reference video; up to 15 seconds at up to 1080p."
|
|
1404
|
+
},
|
|
1405
|
+
capabilities: {}
|
|
884
1406
|
},
|
|
885
1407
|
{
|
|
886
1408
|
id: "minimax-h3",
|
|
@@ -894,7 +1416,7 @@ var VIDEO_MODELS = [
|
|
|
894
1416
|
aspectRatios: [...H3_RATIOS],
|
|
895
1417
|
resolutions: ["480p", "768p", "2k", "4k"],
|
|
896
1418
|
durations: { min: 5, max: 15 },
|
|
897
|
-
supports: ["seed", "promptExpansion"]
|
|
1419
|
+
supports: ["seed", "promptExpansion", "lastFrame", "safetyChecker"]
|
|
898
1420
|
},
|
|
899
1421
|
defaults: {
|
|
900
1422
|
durationSeconds: 5,
|
|
@@ -903,7 +1425,12 @@ var VIDEO_MODELS = [
|
|
|
903
1425
|
promptExpansion: "balanced"
|
|
904
1426
|
},
|
|
905
1427
|
usage: { ...VIDEO_USAGE },
|
|
906
|
-
pricingKind: "video_per_second"
|
|
1428
|
+
pricingKind: "video_per_second",
|
|
1429
|
+
display: {
|
|
1430
|
+
provider: "minimax",
|
|
1431
|
+
description: "MiniMax H3 multimodal video model for text-to-video, image-to-video (first/last frame), and reference-to-video with native audio, up to 2K."
|
|
1432
|
+
},
|
|
1433
|
+
capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
|
|
907
1434
|
},
|
|
908
1435
|
{
|
|
909
1436
|
id: "minimax-h3-max",
|
|
@@ -917,7 +1444,7 @@ var VIDEO_MODELS = [
|
|
|
917
1444
|
aspectRatios: [...H3_RATIOS],
|
|
918
1445
|
resolutions: ["480p", "768p"],
|
|
919
1446
|
durations: { min: 5, max: 15 },
|
|
920
|
-
supports: ["seed", "promptExpansion"]
|
|
1447
|
+
supports: ["seed", "promptExpansion", "lastFrame", "safetyChecker"]
|
|
921
1448
|
},
|
|
922
1449
|
defaults: {
|
|
923
1450
|
durationSeconds: 5,
|
|
@@ -926,7 +1453,12 @@ var VIDEO_MODELS = [
|
|
|
926
1453
|
promptExpansion: "balanced"
|
|
927
1454
|
},
|
|
928
1455
|
usage: { ...VIDEO_USAGE },
|
|
929
|
-
pricingKind: "video_per_second"
|
|
1456
|
+
pricingKind: "video_per_second",
|
|
1457
|
+
display: {
|
|
1458
|
+
provider: "minimax",
|
|
1459
|
+
description: "High-speed MiniMax H3 Max variant for text-to-video and image-to-video (first/last frame) only, up to 768p."
|
|
1460
|
+
},
|
|
1461
|
+
capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
|
|
930
1462
|
},
|
|
931
1463
|
{
|
|
932
1464
|
id: "minimax-h3-reference",
|
|
@@ -941,7 +1473,7 @@ var VIDEO_MODELS = [
|
|
|
941
1473
|
resolutions: ["480p", "768p", "2k", "4k"],
|
|
942
1474
|
durations: { min: 5, max: 15 },
|
|
943
1475
|
references: { images: 9, videos: 3, audios: 3, total: 12, audioOnly: false },
|
|
944
|
-
supports: ["seed", "promptExpansion"]
|
|
1476
|
+
supports: ["seed", "promptExpansion", "safetyChecker"]
|
|
945
1477
|
},
|
|
946
1478
|
defaults: {
|
|
947
1479
|
durationSeconds: 5,
|
|
@@ -950,7 +1482,12 @@ var VIDEO_MODELS = [
|
|
|
950
1482
|
promptExpansion: "balanced"
|
|
951
1483
|
},
|
|
952
1484
|
usage: { ...VIDEO_USAGE },
|
|
953
|
-
pricingKind: "video_per_second"
|
|
1485
|
+
pricingKind: "video_per_second",
|
|
1486
|
+
display: {
|
|
1487
|
+
provider: "minimax",
|
|
1488
|
+
description: "MiniMax H3 reference-to-video mode guided by up to 9 reference images, 3 reference videos, and 3 audio clips; reference and image-to-video inputs cannot be mixed."
|
|
1489
|
+
},
|
|
1490
|
+
capabilities: {}
|
|
954
1491
|
},
|
|
955
1492
|
{
|
|
956
1493
|
id: "minimax-h3-max-reference",
|
|
@@ -965,7 +1502,7 @@ var VIDEO_MODELS = [
|
|
|
965
1502
|
resolutions: ["480p", "768p"],
|
|
966
1503
|
durations: { min: 5, max: 15 },
|
|
967
1504
|
references: { images: 9, videos: 3, audios: 3, total: 12, audioOnly: false },
|
|
968
|
-
supports: ["seed", "promptExpansion"]
|
|
1505
|
+
supports: ["seed", "promptExpansion", "safetyChecker"]
|
|
969
1506
|
},
|
|
970
1507
|
defaults: {
|
|
971
1508
|
durationSeconds: 5,
|
|
@@ -974,7 +1511,12 @@ var VIDEO_MODELS = [
|
|
|
974
1511
|
promptExpansion: "balanced"
|
|
975
1512
|
},
|
|
976
1513
|
usage: { ...VIDEO_USAGE },
|
|
977
|
-
pricingKind: "video_per_second"
|
|
1514
|
+
pricingKind: "video_per_second",
|
|
1515
|
+
display: {
|
|
1516
|
+
provider: "minimax",
|
|
1517
|
+
description: "MiniMax H3 Max reference-to-video on fal; conditions on reference images, videos, and audio. MiniMax's own docs do not list a reference mode for H3 Max."
|
|
1518
|
+
},
|
|
1519
|
+
capabilities: {}
|
|
978
1520
|
},
|
|
979
1521
|
{
|
|
980
1522
|
// Duration 3-10s per trigger-workflows mapDuration; the endpoint takes no resolution.
|
|
@@ -993,7 +1535,12 @@ var VIDEO_MODELS = [
|
|
|
993
1535
|
},
|
|
994
1536
|
defaults: { durationSeconds: 5, aspectRatio: "16:9" },
|
|
995
1537
|
usage: { ...VIDEO_USAGE },
|
|
996
|
-
pricingKind: "video_per_second"
|
|
1538
|
+
pricingKind: "video_per_second",
|
|
1539
|
+
display: {
|
|
1540
|
+
provider: "kuaishou",
|
|
1541
|
+
description: "Kuaishou Kling O1 Reference Video-to-Video; a prompt plus a 3-10 second reference video (optional reference images) generates 3-10 second clips preserving motion and camera language."
|
|
1542
|
+
},
|
|
1543
|
+
capabilities: { acceptsSourceVideo: true }
|
|
997
1544
|
},
|
|
998
1545
|
{
|
|
999
1546
|
id: "hailuo-02",
|
|
@@ -1010,7 +1557,12 @@ var VIDEO_MODELS = [
|
|
|
1010
1557
|
},
|
|
1011
1558
|
defaults: { durationSeconds: 6, resolution: "768p" },
|
|
1012
1559
|
usage: { unit: "compute_seconds", modality: "VIDEO" },
|
|
1013
|
-
pricingKind: "video_per_second"
|
|
1560
|
+
pricingKind: "video_per_second",
|
|
1561
|
+
display: {
|
|
1562
|
+
provider: "minimax",
|
|
1563
|
+
description: "MiniMax Hailuo 02 text-to-video and image-to-video model with realistic physics and strong prompt following; outputs 768p at 6 or 10 seconds."
|
|
1564
|
+
},
|
|
1565
|
+
capabilities: {}
|
|
1014
1566
|
},
|
|
1015
1567
|
{
|
|
1016
1568
|
id: "higgsfield-dop-preview",
|
|
@@ -1026,7 +1578,12 @@ var VIDEO_MODELS = [
|
|
|
1026
1578
|
},
|
|
1027
1579
|
defaults: {},
|
|
1028
1580
|
usage: { ...VIDEO_USAGE },
|
|
1029
|
-
pricingKind: "video_per_second"
|
|
1581
|
+
pricingKind: "video_per_second",
|
|
1582
|
+
display: {
|
|
1583
|
+
provider: "higgsfield",
|
|
1584
|
+
description: "Higgsfield DOP image-to-video model; animates a required first-frame image from a text prompt with an optional last-frame image and motion controls."
|
|
1585
|
+
},
|
|
1586
|
+
capabilities: {}
|
|
1030
1587
|
}
|
|
1031
1588
|
];
|
|
1032
1589
|
|
|
@@ -1093,19 +1650,22 @@ function resolveTier(field, code, requested, supported, order, model, onUnsuppor
|
|
|
1093
1650
|
});
|
|
1094
1651
|
return to;
|
|
1095
1652
|
}
|
|
1096
|
-
function resolveDuration(requested, durations, model, warnings) {
|
|
1653
|
+
function resolveDuration(requested, durations, model, onUnsupported, warnings) {
|
|
1097
1654
|
if (requested === void 0 || !durations) return requested;
|
|
1098
|
-
|
|
1099
|
-
if (
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
if (to === requested) return requested;
|
|
1655
|
+
const inSet = Array.isArray(durations) ? durations.includes(requested) : requested >= durations.min && requested <= durations.max;
|
|
1656
|
+
if (inSet) return requested;
|
|
1657
|
+
if (onUnsupported === "error") {
|
|
1658
|
+
const supported = Array.isArray(durations) ? `Supported: ${durations.join(", ")}.` : `Supported range: ${durations.min}-${durations.max}.`;
|
|
1659
|
+
throw new ModelKitError({
|
|
1660
|
+
code: "unsupported_option",
|
|
1661
|
+
message: `${model.id} does not support durationSeconds ${requested}. ${supported}`,
|
|
1662
|
+
model: model.id
|
|
1663
|
+
});
|
|
1108
1664
|
}
|
|
1665
|
+
const to = Array.isArray(durations) ? durations.reduce(
|
|
1666
|
+
(best, d) => Math.abs(d - requested) < Math.abs(best - requested) ? d : best,
|
|
1667
|
+
durations[0] ?? requested
|
|
1668
|
+
) : Math.min(Math.max(requested, durations.min), durations.max);
|
|
1109
1669
|
warnings.push({
|
|
1110
1670
|
code: "duration_coerced",
|
|
1111
1671
|
field: "durationSeconds",
|
|
@@ -1115,6 +1675,26 @@ function resolveDuration(requested, durations, model, warnings) {
|
|
|
1115
1675
|
});
|
|
1116
1676
|
return to;
|
|
1117
1677
|
}
|
|
1678
|
+
function resolveAspectRatio(requested, supported, model, onUnsupported, warnings) {
|
|
1679
|
+
if (requested === void 0 || requested === "adaptive" || !supported) return requested;
|
|
1680
|
+
if (supported.includes(requested)) return requested;
|
|
1681
|
+
if (onUnsupported === "error") {
|
|
1682
|
+
throw new ModelKitError({
|
|
1683
|
+
code: "unsupported_option",
|
|
1684
|
+
message: `${model.id} does not support aspectRatio "${requested}". Supported: ${supported.join(", ")}.`,
|
|
1685
|
+
model: model.id
|
|
1686
|
+
});
|
|
1687
|
+
}
|
|
1688
|
+
const to = nearestAspectRatio(requested, supported);
|
|
1689
|
+
warnings.push({
|
|
1690
|
+
code: "ratio_coerced",
|
|
1691
|
+
field: "aspectRatio",
|
|
1692
|
+
from: requested,
|
|
1693
|
+
to,
|
|
1694
|
+
message: `aspect ratio ${requested} coerced to ${to} for ${model.id}`
|
|
1695
|
+
});
|
|
1696
|
+
return to;
|
|
1697
|
+
}
|
|
1118
1698
|
function compact(refs) {
|
|
1119
1699
|
return (refs ?? []).filter((r) => Boolean(r));
|
|
1120
1700
|
}
|
|
@@ -1133,17 +1713,14 @@ function resolveImageOptions(model, request, onUnsupported = "error") {
|
|
|
1133
1713
|
const warnings = [];
|
|
1134
1714
|
const c = model.constraints;
|
|
1135
1715
|
const merged = { ...model.defaults, ...stripUndefined(request), model: model.id };
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
});
|
|
1145
|
-
merged.aspectRatio = to;
|
|
1146
|
-
}
|
|
1716
|
+
const aspectRatio = resolveAspectRatio(
|
|
1717
|
+
merged.aspectRatio,
|
|
1718
|
+
c.aspectRatios,
|
|
1719
|
+
model,
|
|
1720
|
+
onUnsupported,
|
|
1721
|
+
warnings
|
|
1722
|
+
);
|
|
1723
|
+
if (aspectRatio !== void 0) merged.aspectRatio = aspectRatio;
|
|
1147
1724
|
const size = resolveTier(
|
|
1148
1725
|
"size",
|
|
1149
1726
|
"size_coerced",
|
|
@@ -1177,7 +1754,9 @@ function resolveImageOptions(model, request, onUnsupported = "error") {
|
|
|
1177
1754
|
"count",
|
|
1178
1755
|
"outputFormat",
|
|
1179
1756
|
"scaleFactor",
|
|
1180
|
-
"safetySettings"
|
|
1757
|
+
"safetySettings",
|
|
1758
|
+
"temperature",
|
|
1759
|
+
"upscale"
|
|
1181
1760
|
]);
|
|
1182
1761
|
return { request: merged, warnings };
|
|
1183
1762
|
}
|
|
@@ -1207,17 +1786,14 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
|
|
|
1207
1786
|
delete merged.aspectRatio;
|
|
1208
1787
|
}
|
|
1209
1788
|
}
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
});
|
|
1219
|
-
merged.aspectRatio = to;
|
|
1220
|
-
}
|
|
1789
|
+
const aspectRatio = resolveAspectRatio(
|
|
1790
|
+
merged.aspectRatio,
|
|
1791
|
+
c.aspectRatios,
|
|
1792
|
+
model,
|
|
1793
|
+
onUnsupported,
|
|
1794
|
+
warnings
|
|
1795
|
+
);
|
|
1796
|
+
if (aspectRatio !== void 0) merged.aspectRatio = aspectRatio;
|
|
1221
1797
|
const resolution = resolveTier(
|
|
1222
1798
|
"resolution",
|
|
1223
1799
|
"resolution_coerced",
|
|
@@ -1229,7 +1805,13 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
|
|
|
1229
1805
|
warnings
|
|
1230
1806
|
);
|
|
1231
1807
|
if (resolution !== void 0) merged.resolution = resolution;
|
|
1232
|
-
const duration = resolveDuration(
|
|
1808
|
+
const duration = resolveDuration(
|
|
1809
|
+
merged.durationSeconds,
|
|
1810
|
+
c.durations,
|
|
1811
|
+
model,
|
|
1812
|
+
onUnsupported,
|
|
1813
|
+
warnings
|
|
1814
|
+
);
|
|
1233
1815
|
if (duration !== void 0) merged.durationSeconds = duration;
|
|
1234
1816
|
const limits = c.references ?? {};
|
|
1235
1817
|
let images = trim(
|
|
@@ -1284,10 +1866,45 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
|
|
|
1284
1866
|
"cfgScale",
|
|
1285
1867
|
"generateAudio",
|
|
1286
1868
|
"promptExpansion",
|
|
1287
|
-
"lastFrame"
|
|
1869
|
+
"lastFrame",
|
|
1870
|
+
"watermark",
|
|
1871
|
+
"safetyChecker"
|
|
1288
1872
|
]);
|
|
1289
1873
|
return { request: merged, warnings };
|
|
1290
1874
|
}
|
|
1875
|
+
function resolveAudioOptions(model, request, onUnsupported = "error") {
|
|
1876
|
+
const warnings = [];
|
|
1877
|
+
const c = model.constraints;
|
|
1878
|
+
const merged = { ...model.defaults, ...stripUndefined(request), model: model.id };
|
|
1879
|
+
for (const input of c.requires ?? []) {
|
|
1880
|
+
const present = input === "references" ? compact(merged.references).length > 0 : input === "sourceVideo" && merged.sourceVideo !== void 0;
|
|
1881
|
+
if (!present)
|
|
1882
|
+
throw new ModelKitError({
|
|
1883
|
+
code: "missing_input",
|
|
1884
|
+
message: `${model.id} requires ${input}`,
|
|
1885
|
+
model: model.id
|
|
1886
|
+
});
|
|
1887
|
+
}
|
|
1888
|
+
const duration = resolveDuration(
|
|
1889
|
+
merged.durationSeconds,
|
|
1890
|
+
c.durations,
|
|
1891
|
+
model,
|
|
1892
|
+
onUnsupported,
|
|
1893
|
+
warnings
|
|
1894
|
+
);
|
|
1895
|
+
if (duration !== void 0) merged.durationSeconds = duration;
|
|
1896
|
+
const references = trim(
|
|
1897
|
+
"references",
|
|
1898
|
+
compact(merged.references),
|
|
1899
|
+
c.references?.images ?? c.references?.total,
|
|
1900
|
+
model,
|
|
1901
|
+
warnings
|
|
1902
|
+
);
|
|
1903
|
+
if (references.length > 0) merged.references = references;
|
|
1904
|
+
else delete merged.references;
|
|
1905
|
+
dropUnsupported(merged, model, warnings, ["seed", "negativePrompt", "instrumental"]);
|
|
1906
|
+
return { request: merged, warnings };
|
|
1907
|
+
}
|
|
1291
1908
|
function dropUnsupported(req, model, warnings, fields) {
|
|
1292
1909
|
const supports = model.constraints.supports ?? [];
|
|
1293
1910
|
for (const field of fields) {
|
|
@@ -1329,6 +1946,9 @@ function hasAll(keys, names) {
|
|
|
1329
1946
|
(n) => Boolean(keys[n]) && (n !== "higgsfield" || Boolean(keys.higgsfieldSecret))
|
|
1330
1947
|
);
|
|
1331
1948
|
}
|
|
1949
|
+
function missingEnterpriseKeys(config, names) {
|
|
1950
|
+
return names.filter((name) => !hasAll(config.keys.enterprise, [name]));
|
|
1951
|
+
}
|
|
1332
1952
|
function resolveKeys(config, names, tier = "pro") {
|
|
1333
1953
|
if (tier === "enterprise" && hasAll(config.keys.enterprise, names))
|
|
1334
1954
|
return config.keys.enterprise;
|
|
@@ -1361,7 +1981,6 @@ function keysFromEnv(env, prefix = "") {
|
|
|
1361
1981
|
set("prodia", pick("PRODIA_API_KEY", "PRODIA_TOKEN"));
|
|
1362
1982
|
set("higgsfield", pick("HIGGSFIELD_API_KEY"));
|
|
1363
1983
|
set("higgsfieldSecret", pick("HIGGSFIELD_API_SECRET"));
|
|
1364
|
-
set("openrouter", pick("OPENROUTER_API_KEY"));
|
|
1365
1984
|
set("cloudflare", pick("CLOUDFLARE_AI_GATEWAY_TOKEN", "CF_AIG_TOKEN"));
|
|
1366
1985
|
return keys;
|
|
1367
1986
|
}
|
|
@@ -1409,7 +2028,9 @@ var textBody = z2.string();
|
|
|
1409
2028
|
function classifyHttpError(status, body, provider, model) {
|
|
1410
2029
|
const asText = textBody.safeParse(body);
|
|
1411
2030
|
const text2 = asText.success ? asText.data : JSON.stringify(body);
|
|
1412
|
-
const blocked = /
|
|
2031
|
+
const blocked = /content_policy_violation|blockReason|PROHIBITED_CONTENT|moderation_blocked|safety(?![_A-Za-z])/i.test(
|
|
2032
|
+
text2
|
|
2033
|
+
);
|
|
1413
2034
|
let code = "provider_rejected";
|
|
1414
2035
|
if (blocked) code = "content_blocked";
|
|
1415
2036
|
else if (status === 401 || status === 403) code = "auth";
|
|
@@ -1430,8 +2051,8 @@ function classifyHttpError(status, body, provider, model) {
|
|
|
1430
2051
|
}
|
|
1431
2052
|
function shouldRetry(err) {
|
|
1432
2053
|
if (err instanceof ModelKitError) return err.retryable;
|
|
1433
|
-
if (err.name === "AbortError"
|
|
1434
|
-
|
|
2054
|
+
if (err.name === "AbortError") return false;
|
|
2055
|
+
if (/ECONNRESET|ETIMEDOUT|fetch failed|socket hang up/i.test(err.message)) return true;
|
|
1435
2056
|
return false;
|
|
1436
2057
|
}
|
|
1437
2058
|
async function withRetry(fn, opts = {}) {
|
|
@@ -1623,6 +2244,12 @@ import { z as z4 } from "zod";
|
|
|
1623
2244
|
function isUrlRef(ref) {
|
|
1624
2245
|
return "url" in ref;
|
|
1625
2246
|
}
|
|
2247
|
+
function abortedError() {
|
|
2248
|
+
return new ModelKitError({ code: "timeout", message: "aborted", retryable: false });
|
|
2249
|
+
}
|
|
2250
|
+
function throwIfAborted(signal) {
|
|
2251
|
+
if (signal?.aborted) throw abortedError();
|
|
2252
|
+
}
|
|
1626
2253
|
function mediaRefToBase64(bytes) {
|
|
1627
2254
|
let binary = "";
|
|
1628
2255
|
const CHUNK = 32768;
|
|
@@ -1637,10 +2264,34 @@ function base64ToBytes(b64) {
|
|
|
1637
2264
|
for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i);
|
|
1638
2265
|
return out;
|
|
1639
2266
|
}
|
|
1640
|
-
|
|
2267
|
+
function mediaRefToDataUrl(ref) {
|
|
2268
|
+
if (isUrlRef(ref)) return ref.url;
|
|
2269
|
+
return `data:${ref.mime};base64,${mediaRefToBase64(ref.bytes)}`;
|
|
2270
|
+
}
|
|
2271
|
+
var refToUrl = mediaRefToDataUrl;
|
|
2272
|
+
async function readBody(res) {
|
|
2273
|
+
const text2 = await res.text().catch(() => "");
|
|
2274
|
+
try {
|
|
2275
|
+
const decoded = JsonValueSchema.safeParse(JSON.parse(text2));
|
|
2276
|
+
return decoded.success ? decoded.data : text2;
|
|
2277
|
+
} catch {
|
|
2278
|
+
return text2;
|
|
2279
|
+
}
|
|
2280
|
+
}
|
|
2281
|
+
async function mediaRefToBytes(ref, fetch, options = {}) {
|
|
1641
2282
|
if (!isUrlRef(ref)) return { bytes: ref.bytes, mime: ref.mime };
|
|
1642
|
-
const
|
|
1643
|
-
if (
|
|
2283
|
+
const init = {};
|
|
2284
|
+
if (options.signal !== void 0) init.signal = options.signal;
|
|
2285
|
+
const res = await fetch(ref.url, init);
|
|
2286
|
+
if (!res.ok) {
|
|
2287
|
+
const text2 = await res.text().catch(() => "");
|
|
2288
|
+
throw classifyHttpError(
|
|
2289
|
+
res.status,
|
|
2290
|
+
text2,
|
|
2291
|
+
options.provider ?? "media-reference",
|
|
2292
|
+
options.model
|
|
2293
|
+
);
|
|
2294
|
+
}
|
|
1644
2295
|
const mime = res.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase() || "image/png";
|
|
1645
2296
|
return { bytes: new Uint8Array(await res.arrayBuffer()), mime };
|
|
1646
2297
|
}
|
|
@@ -1698,16 +2349,6 @@ var GATEWAY_SLUGS = {
|
|
|
1698
2349
|
perplexity: "perplexity-ai",
|
|
1699
2350
|
deepseek: "deepseek"
|
|
1700
2351
|
};
|
|
1701
|
-
var OPENROUTER_VENDORS = {
|
|
1702
|
-
openai: "openai",
|
|
1703
|
-
anthropic: "anthropic",
|
|
1704
|
-
google: "google",
|
|
1705
|
-
xai: "x-ai",
|
|
1706
|
-
perplexity: "perplexity",
|
|
1707
|
-
deepseek: "deepseek",
|
|
1708
|
-
moonshot: "moonshotai",
|
|
1709
|
-
minimax: "minimax"
|
|
1710
|
-
};
|
|
1711
2352
|
function detectTextProvider(modelId) {
|
|
1712
2353
|
const id = modelId.toLowerCase();
|
|
1713
2354
|
if (id.startsWith("claude") || id.includes("anthropic.")) return "anthropic";
|
|
@@ -1724,14 +2365,17 @@ function detectTextProvider(modelId) {
|
|
|
1724
2365
|
message: `ai-sdk-text cannot detect a provider for "${modelId}". Set providerOptions.provider to one of ${TEXT_PROVIDERS.join(", ")}.`
|
|
1725
2366
|
});
|
|
1726
2367
|
}
|
|
1727
|
-
function textKeyName(model,
|
|
1728
|
-
if (routing.text === "openrouter") return "openrouter";
|
|
2368
|
+
function textKeyName(model, _routing) {
|
|
1729
2369
|
return textProviderOf(model);
|
|
1730
2370
|
}
|
|
1731
2371
|
function textProviderOf(model) {
|
|
1732
2372
|
const explicit = model.providerOptions?.["modelkit"]?.["provider"];
|
|
1733
2373
|
return isTextProvider(explicit) ? explicit : detectTextProvider(model.providerModelId);
|
|
1734
2374
|
}
|
|
2375
|
+
function textUsesCloudflareGateway(model, routing) {
|
|
2376
|
+
if (routing.text !== "cloudflare") return false;
|
|
2377
|
+
return GATEWAY_SLUGS[textProviderOf(model)] !== void 0;
|
|
2378
|
+
}
|
|
1735
2379
|
function nativeClientFor(provider) {
|
|
1736
2380
|
switch (provider) {
|
|
1737
2381
|
case "openai":
|
|
@@ -1764,16 +2408,6 @@ function resolveTextRoute(ctx) {
|
|
|
1764
2408
|
retryable: false
|
|
1765
2409
|
});
|
|
1766
2410
|
}
|
|
1767
|
-
if (mode === "openrouter") {
|
|
1768
|
-
const modelId = ctx.model.providerModelId.includes("/") ? ctx.model.providerModelId : `${OPENROUTER_VENDORS[provider]}/${ctx.model.providerModelId}`;
|
|
1769
|
-
return {
|
|
1770
|
-
provider,
|
|
1771
|
-
client: "openai-compatible",
|
|
1772
|
-
modelId,
|
|
1773
|
-
keyName: "openrouter",
|
|
1774
|
-
baseURL: "https://openrouter.ai/api/v1"
|
|
1775
|
-
};
|
|
1776
|
-
}
|
|
1777
2411
|
const compatBase = OPENAI_COMPATIBLE_BASE_URLS[provider];
|
|
1778
2412
|
const route2 = {
|
|
1779
2413
|
provider,
|
|
@@ -1841,7 +2475,7 @@ var aiSdkTextAdapter = {
|
|
|
1841
2475
|
case "openai-compatible":
|
|
1842
2476
|
return createOpenAI({
|
|
1843
2477
|
...settings,
|
|
1844
|
-
name: route2.provider
|
|
2478
|
+
name: route2.provider
|
|
1845
2479
|
}).chat(route2.modelId);
|
|
1846
2480
|
case "openai":
|
|
1847
2481
|
return createOpenAI(settings)(route2.modelId);
|
|
@@ -1854,8 +2488,9 @@ function requiredKeys(model, config) {
|
|
|
1854
2488
|
if (model.adapter === "fal" && config.routing?.fal === "cloudflare-passthrough")
|
|
1855
2489
|
return ["cloudflare"];
|
|
1856
2490
|
if (model.adapter === "ai-sdk-text") {
|
|
1857
|
-
const
|
|
1858
|
-
|
|
2491
|
+
const routing = config.routing ?? {};
|
|
2492
|
+
const names = [textKeyName(model, routing)];
|
|
2493
|
+
if (textUsesCloudflareGateway(model, routing)) names.push("cloudflare");
|
|
1859
2494
|
return names;
|
|
1860
2495
|
}
|
|
1861
2496
|
return ADAPTER_KEYS[model.adapter];
|
|
@@ -1929,6 +2564,11 @@ function pushIgnored(warnings, field, from, modelId) {
|
|
|
1929
2564
|
message: `${modelId} provider instance does not support ${field}; ignored`
|
|
1930
2565
|
});
|
|
1931
2566
|
}
|
|
2567
|
+
function withoutModelkit(options) {
|
|
2568
|
+
if (!options) return {};
|
|
2569
|
+
const { modelkit: _modelkit, ...rest } = options;
|
|
2570
|
+
return rest;
|
|
2571
|
+
}
|
|
1932
2572
|
function logCoercions(logger, modelId, warnings) {
|
|
1933
2573
|
if (warnings.length === 0) return;
|
|
1934
2574
|
logger.warn(`[modelkit] ${modelId} request coerced`, { model: modelId, warnings });
|
|
@@ -1945,7 +2585,16 @@ function createModelKit(config, adapters) {
|
|
|
1945
2585
|
message: `No adapter registered for ${model.adapter}`,
|
|
1946
2586
|
model: model.id
|
|
1947
2587
|
});
|
|
1948
|
-
const
|
|
2588
|
+
const names = requiredKeys(model, config);
|
|
2589
|
+
if (call.tier === "enterprise") {
|
|
2590
|
+
const missing = missingEnterpriseKeys(config, names);
|
|
2591
|
+
if (missing.length > 0)
|
|
2592
|
+
logger.warn(
|
|
2593
|
+
`[modelkit] enterprise keys incomplete for ${model.adapter}; using pro`,
|
|
2594
|
+
{ missing }
|
|
2595
|
+
);
|
|
2596
|
+
}
|
|
2597
|
+
const keys = resolveKeys(config, names, call.tier);
|
|
1949
2598
|
const ctx = {
|
|
1950
2599
|
model,
|
|
1951
2600
|
keys,
|
|
@@ -2266,8 +2915,15 @@ function createModelKit(config, adapters) {
|
|
|
2266
2915
|
model: model.id
|
|
2267
2916
|
});
|
|
2268
2917
|
}
|
|
2269
|
-
const
|
|
2270
|
-
const {
|
|
2918
|
+
const { abortSignal: _signal, ...request } = req;
|
|
2919
|
+
const { request: resolved, warnings } = resolveAudioOptions(
|
|
2920
|
+
model,
|
|
2921
|
+
request,
|
|
2922
|
+
call.onUnsupported ?? "error"
|
|
2923
|
+
);
|
|
2924
|
+
logCoercions(logger, model.id, warnings);
|
|
2925
|
+
const signal = combineSignals(req.abortSignal, call.signal);
|
|
2926
|
+
const { adapter, ctx } = context(model, signal ? { ...call, signal } : call, warnings);
|
|
2271
2927
|
if (!adapter.generateAudio) {
|
|
2272
2928
|
throw new ModelKitError({
|
|
2273
2929
|
code: "unsupported_option",
|
|
@@ -2275,11 +2931,7 @@ function createModelKit(config, adapters) {
|
|
|
2275
2931
|
model: model.id
|
|
2276
2932
|
});
|
|
2277
2933
|
}
|
|
2278
|
-
const result = await adapter.generateAudio(
|
|
2279
|
-
{ ...model.defaults, ...req, model: model.id },
|
|
2280
|
-
ctx
|
|
2281
|
-
);
|
|
2282
|
-
logCoercions(logger, model.id, warnings);
|
|
2934
|
+
const result = await adapter.generateAudio(resolved, ctx);
|
|
2283
2935
|
await emit({ ...result.usage, model: model.id, unit: model.usage.unit });
|
|
2284
2936
|
return result;
|
|
2285
2937
|
},
|
|
@@ -2300,7 +2952,7 @@ function createModelKit(config, adapters) {
|
|
|
2300
2952
|
});
|
|
2301
2953
|
return {
|
|
2302
2954
|
model,
|
|
2303
|
-
providerOptions: entry.providerOptions
|
|
2955
|
+
providerOptions: withoutModelkit(entry.providerOptions),
|
|
2304
2956
|
catalog: entry
|
|
2305
2957
|
};
|
|
2306
2958
|
},
|
|
@@ -2336,7 +2988,9 @@ function createModelKit(config, adapters) {
|
|
|
2336
2988
|
...textAbortOptions(options.abortSignal, call.signal),
|
|
2337
2989
|
model: target.languageModel,
|
|
2338
2990
|
providerOptions: {},
|
|
2339
|
-
prepareStep: steps.wrap(
|
|
2991
|
+
prepareStep: steps.wrap(
|
|
2992
|
+
options.prepareStep ?? options.experimental_prepareStep
|
|
2993
|
+
),
|
|
2340
2994
|
onFinish: async (event) => {
|
|
2341
2995
|
for (const usage2 of steps.usage(event.steps)) await emit(withRowUnit(usage2));
|
|
2342
2996
|
await callerOnFinish?.(event);
|
|
@@ -2393,6 +3047,7 @@ var SEEDREAM_SIZES = {
|
|
|
2393
3047
|
"3:2": "1248x832",
|
|
2394
3048
|
"2:3": "832x1248",
|
|
2395
3049
|
"21:9": "1568x672",
|
|
3050
|
+
"9:21": "672x1568",
|
|
2396
3051
|
"4:5": "864x1080",
|
|
2397
3052
|
"5:4": "1080x864"
|
|
2398
3053
|
},
|
|
@@ -2405,16 +3060,34 @@ var SEEDREAM_SIZES = {
|
|
|
2405
3060
|
"3:2": "2496x1664",
|
|
2406
3061
|
"2:3": "1664x2496",
|
|
2407
3062
|
"21:9": "3136x1344",
|
|
3063
|
+
"9:21": "1344x3136",
|
|
2408
3064
|
"4:5": "1728x2160",
|
|
2409
3065
|
"5:4": "2160x1728"
|
|
3066
|
+
},
|
|
3067
|
+
// 4K keeps the long edge at Ark's 4096 cap (a doubled 2K entry would exceed
|
|
3068
|
+
// it); sides are multiples of 16.
|
|
3069
|
+
"4K": {
|
|
3070
|
+
"1:1": "4096x4096",
|
|
3071
|
+
"4:3": "4096x3072",
|
|
3072
|
+
"3:4": "3072x4096",
|
|
3073
|
+
"16:9": "4096x2304",
|
|
3074
|
+
"9:16": "2304x4096",
|
|
3075
|
+
"3:2": "4096x2736",
|
|
3076
|
+
"2:3": "2736x4096",
|
|
3077
|
+
"21:9": "4096x1760",
|
|
3078
|
+
"9:21": "1760x4096",
|
|
3079
|
+
"4:5": "3280x4096",
|
|
3080
|
+
"5:4": "4096x3280"
|
|
2410
3081
|
}
|
|
2411
3082
|
};
|
|
2412
3083
|
var arkAdapter = {
|
|
2413
3084
|
id: "ark",
|
|
2414
3085
|
async generateImage(req, ctx) {
|
|
3086
|
+
throwIfAborted(ctx.signal);
|
|
2415
3087
|
return generateSeedreamImage(req, ctx);
|
|
2416
3088
|
},
|
|
2417
3089
|
async generateVideo(req, ctx) {
|
|
3090
|
+
throwIfAborted(ctx.signal);
|
|
2418
3091
|
return generateSeedanceVideo(req, ctx);
|
|
2419
3092
|
}
|
|
2420
3093
|
};
|
|
@@ -2434,7 +3107,7 @@ function arkKey(ctx) {
|
|
|
2434
3107
|
function throwArkError(status, body, model) {
|
|
2435
3108
|
const parsed = z5.string().safeParse(body);
|
|
2436
3109
|
const text2 = parsed.success ? parsed.data : JSON.stringify(body ?? "");
|
|
2437
|
-
if (/sensitive.?content|
|
|
3110
|
+
if (/sensitive.?content|human.?face/i.test(text2)) {
|
|
2438
3111
|
const init = {
|
|
2439
3112
|
code: "content_blocked",
|
|
2440
3113
|
message: `ark rejected the request: ${text2.slice(0, 500)}`,
|
|
@@ -2459,7 +3132,7 @@ function throwArkError(status, body, model) {
|
|
|
2459
3132
|
throw classifyHttpError(status, body, "ark", model);
|
|
2460
3133
|
}
|
|
2461
3134
|
function seedreamSize(aspect, size) {
|
|
2462
|
-
const tier = size === "
|
|
3135
|
+
const tier = size === "4K" || size === "1K" ? size : "2K";
|
|
2463
3136
|
const table = SEEDREAM_SIZES[tier];
|
|
2464
3137
|
return table[aspect ?? ""] ?? table["1:1"] ?? "2048x2048";
|
|
2465
3138
|
}
|
|
@@ -2470,10 +3143,6 @@ function sniffedImageMime(bytes) {
|
|
|
2470
3143
|
return "image/webp";
|
|
2471
3144
|
return "image/jpeg";
|
|
2472
3145
|
}
|
|
2473
|
-
function arkUrl(ref) {
|
|
2474
|
-
if ("url" in ref) return ref.url;
|
|
2475
|
-
return `data:${ref.mime};base64,${Buffer.from(ref.bytes).toString("base64")}`;
|
|
2476
|
-
}
|
|
2477
3146
|
var SeedreamImageSchema = z5.object({
|
|
2478
3147
|
url: z5.string().optional(),
|
|
2479
3148
|
b64_json: z5.string().optional()
|
|
@@ -2500,7 +3169,7 @@ async function generateSeedreamImage(req, ctx) {
|
|
|
2500
3169
|
const key = arkKey(ctx);
|
|
2501
3170
|
const modelId = ctx.model.id;
|
|
2502
3171
|
const size = seedreamSize(req.aspectRatio, req.size);
|
|
2503
|
-
const refs = (req.references ?? []).map(
|
|
3172
|
+
const refs = (req.references ?? []).map(refToUrl);
|
|
2504
3173
|
const body = {
|
|
2505
3174
|
model: ctx.model.providerModelId,
|
|
2506
3175
|
prompt: req.prompt,
|
|
@@ -2552,10 +3221,18 @@ async function generateSeedreamImage(req, ctx) {
|
|
|
2552
3221
|
if (req.quality !== void 0) usage2.imageQuality = req.quality;
|
|
2553
3222
|
return { images: [{ bytes, mime: sniffedImageMime(bytes) }], usage: usage2, raw: data };
|
|
2554
3223
|
}
|
|
3224
|
+
var SeedanceUsageSchema = z5.object({
|
|
3225
|
+
total_tokens: z5.number().optional(),
|
|
3226
|
+
completion_tokens: z5.number().optional()
|
|
3227
|
+
});
|
|
2555
3228
|
var SeedanceResponseSchema = z5.object({
|
|
2556
3229
|
id: z5.string().optional(),
|
|
2557
3230
|
status: z5.string().optional(),
|
|
2558
3231
|
content: z5.object({ video_url: z5.string().optional() }).optional(),
|
|
3232
|
+
usage: SeedanceUsageSchema.optional(),
|
|
3233
|
+
duration: z5.number().optional(),
|
|
3234
|
+
framespersecond: z5.number().optional(),
|
|
3235
|
+
resolution: z5.string().optional(),
|
|
2559
3236
|
error: z5.union([z5.string(), z5.object({ message: z5.string().optional() })]).optional()
|
|
2560
3237
|
});
|
|
2561
3238
|
var SeedanceErrorMessageSchema = z5.object({ message: z5.string().optional() });
|
|
@@ -2587,42 +3264,42 @@ async function generateSeedanceVideo(req, ctx) {
|
|
|
2587
3264
|
if (req.firstFrame) {
|
|
2588
3265
|
content.push({
|
|
2589
3266
|
type: "image_url",
|
|
2590
|
-
image_url: { url:
|
|
3267
|
+
image_url: { url: refToUrl(req.firstFrame) },
|
|
2591
3268
|
role: "first_frame"
|
|
2592
3269
|
});
|
|
2593
3270
|
}
|
|
2594
3271
|
if (req.lastFrame) {
|
|
2595
3272
|
content.push({
|
|
2596
3273
|
type: "image_url",
|
|
2597
|
-
image_url: { url:
|
|
3274
|
+
image_url: { url: refToUrl(req.lastFrame) },
|
|
2598
3275
|
role: "last_frame"
|
|
2599
3276
|
});
|
|
2600
3277
|
}
|
|
2601
3278
|
for (const ref of req.referenceImages ?? []) {
|
|
2602
3279
|
content.push({
|
|
2603
3280
|
type: "image_url",
|
|
2604
|
-
image_url: { url:
|
|
3281
|
+
image_url: { url: refToUrl(ref) },
|
|
2605
3282
|
role: "reference_image"
|
|
2606
3283
|
});
|
|
2607
3284
|
}
|
|
2608
3285
|
if (req.sourceVideo) {
|
|
2609
3286
|
content.push({
|
|
2610
3287
|
type: "video_url",
|
|
2611
|
-
video_url: { url:
|
|
3288
|
+
video_url: { url: refToUrl(req.sourceVideo) },
|
|
2612
3289
|
role: "reference_video"
|
|
2613
3290
|
});
|
|
2614
3291
|
}
|
|
2615
3292
|
for (const ref of req.referenceVideos ?? []) {
|
|
2616
3293
|
content.push({
|
|
2617
3294
|
type: "video_url",
|
|
2618
|
-
video_url: { url:
|
|
3295
|
+
video_url: { url: refToUrl(ref) },
|
|
2619
3296
|
role: "reference_video"
|
|
2620
3297
|
});
|
|
2621
3298
|
}
|
|
2622
3299
|
for (const ref of req.referenceAudios ?? []) {
|
|
2623
3300
|
content.push({
|
|
2624
3301
|
type: "audio_url",
|
|
2625
|
-
audio_url: { url:
|
|
3302
|
+
audio_url: { url: refToUrl(ref) },
|
|
2626
3303
|
role: "reference_audio"
|
|
2627
3304
|
});
|
|
2628
3305
|
}
|
|
@@ -2636,6 +3313,7 @@ async function generateSeedanceVideo(req, ctx) {
|
|
|
2636
3313
|
if (!hasFrameAnchor && req.aspectRatio !== void 0) body.ratio = req.aspectRatio;
|
|
2637
3314
|
if (req.generateAudio !== void 0) body.generate_audio = req.generateAudio;
|
|
2638
3315
|
if (req.seed !== void 0) body.seed = req.seed;
|
|
3316
|
+
if (req.watermark !== void 0) body.watermark = req.watermark;
|
|
2639
3317
|
const submit = await withRetry(async () => {
|
|
2640
3318
|
const res = await arkFetch(ctx, `${arkBaseUrl(ctx)}${SUBMIT_PATH}`, {
|
|
2641
3319
|
method: "POST",
|
|
@@ -2699,6 +3377,11 @@ async function generateSeedanceVideo(req, ctx) {
|
|
|
2699
3377
|
"Seedance task succeeded but returned no video_url",
|
|
2700
3378
|
modelId
|
|
2701
3379
|
);
|
|
3380
|
+
const tokens = polled.usage;
|
|
3381
|
+
if (tokens?.total_tokens !== void 0 && tokens.completion_tokens !== void 0) {
|
|
3382
|
+
usage2.inputTokens = tokens.total_tokens - tokens.completion_tokens;
|
|
3383
|
+
usage2.outputTokens = tokens.completion_tokens;
|
|
3384
|
+
}
|
|
2702
3385
|
return {
|
|
2703
3386
|
video: { url, expiresAt: new Date(Date.now() + VIDEO_URL_TTL_MS) },
|
|
2704
3387
|
usage: usage2,
|
|
@@ -2762,24 +3445,17 @@ var defaultDeps = { createFalClient: defaultCreateFalClient };
|
|
|
2762
3445
|
function createFalAdapter(deps = defaultDeps) {
|
|
2763
3446
|
return {
|
|
2764
3447
|
id: "fal",
|
|
2765
|
-
generateImage: (req, ctx) =>
|
|
2766
|
-
|
|
3448
|
+
generateImage: (req, ctx) => {
|
|
3449
|
+
throwIfAborted(ctx.signal);
|
|
3450
|
+
return generateMuseImage(req, ctx, deps);
|
|
3451
|
+
},
|
|
3452
|
+
generateVideo: (req, ctx) => {
|
|
3453
|
+
throwIfAborted(ctx.signal);
|
|
3454
|
+
return generateFalVideo(req, ctx, deps);
|
|
3455
|
+
}
|
|
2767
3456
|
};
|
|
2768
3457
|
}
|
|
2769
3458
|
var falAdapter = createFalAdapter();
|
|
2770
|
-
function refToUrl(ref) {
|
|
2771
|
-
if ("url" in ref) return ref.url;
|
|
2772
|
-
return `data:${ref.mime};base64,${Buffer.from(ref.bytes).toString("base64")}`;
|
|
2773
|
-
}
|
|
2774
|
-
async function readBody(res) {
|
|
2775
|
-
const text2 = await res.text().catch(() => "");
|
|
2776
|
-
try {
|
|
2777
|
-
const decoded = JsonValueSchema.safeParse(JSON.parse(text2));
|
|
2778
|
-
return decoded.success ? decoded.data : text2;
|
|
2779
|
-
} catch {
|
|
2780
|
-
return text2;
|
|
2781
|
-
}
|
|
2782
|
-
}
|
|
2783
3459
|
var falDetailSchema = z6.object({ detail: JsonValueSchema });
|
|
2784
3460
|
function liftDetail(body) {
|
|
2785
3461
|
const parsed = falDetailSchema.safeParse(body);
|
|
@@ -3016,8 +3692,12 @@ async function generateMuseImage(req, ctx, deps) {
|
|
|
3016
3692
|
raw: payload
|
|
3017
3693
|
};
|
|
3018
3694
|
}
|
|
3695
|
+
var H3_MAX_MODEL_IDS = /* @__PURE__ */ new Set([
|
|
3696
|
+
"minimax/h3-max",
|
|
3697
|
+
"minimax/h3-max/reference-to-video"
|
|
3698
|
+
]);
|
|
3019
3699
|
function minimaxFamily(providerModelId) {
|
|
3020
|
-
return providerModelId.toLowerCase()
|
|
3700
|
+
return H3_MAX_MODEL_IDS.has(providerModelId.toLowerCase()) ? "h3-max" : "h3";
|
|
3021
3701
|
}
|
|
3022
3702
|
function minimaxBase(req, family) {
|
|
3023
3703
|
const resolution = (family === "h3-max" ? req.resolution ?? "768p" : req.resolution ?? "2k").toUpperCase();
|
|
@@ -3025,14 +3705,17 @@ function minimaxBase(req, family) {
|
|
|
3025
3705
|
prompt: req.prompt.trim(),
|
|
3026
3706
|
duration: req.durationSeconds ?? 5,
|
|
3027
3707
|
resolution,
|
|
3028
|
-
prompt_expansion_mode: req.promptExpansion ?? "balanced"
|
|
3029
|
-
enable_safety_checker: true
|
|
3708
|
+
prompt_expansion_mode: req.promptExpansion ?? "balanced"
|
|
3030
3709
|
};
|
|
3710
|
+
if (req.safetyChecker !== void 0) input.enable_safety_checker = req.safetyChecker;
|
|
3031
3711
|
if (req.seed !== void 0) input.seed = req.seed;
|
|
3032
3712
|
return input;
|
|
3033
3713
|
}
|
|
3714
|
+
var KLING_MODEL_IDS = /* @__PURE__ */ new Set([
|
|
3715
|
+
"fal-ai/kling-video/o1/video-to-video/reference"
|
|
3716
|
+
]);
|
|
3034
3717
|
function isKling(providerModelId) {
|
|
3035
|
-
return providerModelId.toLowerCase()
|
|
3718
|
+
return KLING_MODEL_IDS.has(providerModelId.toLowerCase());
|
|
3036
3719
|
}
|
|
3037
3720
|
function klingO1Input(req) {
|
|
3038
3721
|
const source = req.sourceVideo ? refToUrl(req.sourceVideo) : void 0;
|
|
@@ -3105,7 +3788,9 @@ async function generateFalVideo(req, ctx, deps) {
|
|
|
3105
3788
|
if (lastFrame) base.end_image_url = lastFrame;
|
|
3106
3789
|
} else {
|
|
3107
3790
|
endpoint = `minimax/${family}/text-to-video`;
|
|
3108
|
-
|
|
3791
|
+
if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive") {
|
|
3792
|
+
base.aspect_ratio = req.aspectRatio;
|
|
3793
|
+
}
|
|
3109
3794
|
}
|
|
3110
3795
|
if (ctx.routing.fal === "cloudflare-passthrough") {
|
|
3111
3796
|
return await passthroughVideoJob(ctx, req, endpoint, base);
|
|
@@ -3593,6 +4278,14 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
|
|
|
3593
4278
|
model: modelId
|
|
3594
4279
|
});
|
|
3595
4280
|
}
|
|
4281
|
+
if (req.lastFrame !== void 0 && req.firstFrame === void 0) {
|
|
4282
|
+
throw new ModelKitError({
|
|
4283
|
+
code: "missing_input",
|
|
4284
|
+
message: `${modelId} requires firstFrame when lastFrame is set`,
|
|
4285
|
+
provider: "google-genai",
|
|
4286
|
+
model: modelId
|
|
4287
|
+
});
|
|
4288
|
+
}
|
|
3596
4289
|
const duration = req.durationSeconds ?? 8;
|
|
3597
4290
|
const personGeneration = req.firstFrame ?? refs.length > 0 ? "allow_adult" : "allow_all";
|
|
3598
4291
|
let image;
|
|
@@ -3659,7 +4352,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
|
|
|
3659
4352
|
throwSdkError(cause, modelId);
|
|
3660
4353
|
}
|
|
3661
4354
|
};
|
|
3662
|
-
const jobId = operation.name ??
|
|
4355
|
+
const jobId = operation.name ?? crypto.randomUUID();
|
|
3663
4356
|
const usage2 = videoUsage2(ctx, req, duration);
|
|
3664
4357
|
return {
|
|
3665
4358
|
jobId,
|
|
@@ -3798,6 +4491,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
|
|
|
3798
4491
|
});
|
|
3799
4492
|
}
|
|
3800
4493
|
for (const ref of videos) {
|
|
4494
|
+
if (ref.label !== void 0) parts.push({ type: "text", text: ref.label });
|
|
3801
4495
|
const media = await resolveMedia(ref, ctx.fetch, ctx.signal, "video/mp4", modelId);
|
|
3802
4496
|
parts.push({
|
|
3803
4497
|
type: "video",
|
|
@@ -3806,6 +4500,8 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
|
|
|
3806
4500
|
});
|
|
3807
4501
|
}
|
|
3808
4502
|
if (req.firstFrame) {
|
|
4503
|
+
if (req.firstFrame.label !== void 0)
|
|
4504
|
+
parts.push({ type: "text", text: req.firstFrame.label });
|
|
3809
4505
|
const media = await resolveMedia(
|
|
3810
4506
|
req.firstFrame,
|
|
3811
4507
|
ctx.fetch,
|
|
@@ -3824,6 +4520,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
|
|
|
3824
4520
|
}
|
|
3825
4521
|
}
|
|
3826
4522
|
for (const ref of images) {
|
|
4523
|
+
if (ref.label !== void 0) parts.push({ type: "text", text: ref.label });
|
|
3827
4524
|
const media = await resolveMedia(ref, ctx.fetch, ctx.signal, "image/png", modelId);
|
|
3828
4525
|
if (media.bytes.length > OMNI_INLINE_LIMIT_BYTES) {
|
|
3829
4526
|
parts.push({
|
|
@@ -3867,7 +4564,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
|
|
|
3867
4564
|
} finally {
|
|
3868
4565
|
await cleanupUploads();
|
|
3869
4566
|
}
|
|
3870
|
-
const jobId = interaction.id ??
|
|
4567
|
+
const jobId = interaction.id ?? crypto.randomUUID();
|
|
3871
4568
|
const usage2 = videoUsage2(ctx, req, duration);
|
|
3872
4569
|
const getInteraction = async () => {
|
|
3873
4570
|
try {
|
|
@@ -4093,11 +4790,11 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
|
|
|
4093
4790
|
const model = google(ctx.model.providerModelId);
|
|
4094
4791
|
const content = [];
|
|
4095
4792
|
for (const ref of req.references ?? []) {
|
|
4793
|
+
if (ref.label !== void 0) content.push({ type: "text", text: ref.label });
|
|
4096
4794
|
if ("url" in ref) content.push({ type: "image", image: ref.url });
|
|
4097
4795
|
else content.push({ type: "image", image: ref.bytes, mediaType: ref.mime });
|
|
4098
4796
|
}
|
|
4099
4797
|
content.push({ type: "text", text: req.prompt });
|
|
4100
|
-
void ctx.call.postCropToAspect;
|
|
4101
4798
|
const imageConfig = {};
|
|
4102
4799
|
if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive")
|
|
4103
4800
|
imageConfig.aspectRatio = req.aspectRatio;
|
|
@@ -4113,7 +4810,7 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
|
|
|
4113
4810
|
const timeout = AbortSignal.timeout(GEMINI_IMAGE_TIMEOUT_MS);
|
|
4114
4811
|
const signal = ctx.signal !== void 0 ? AbortSignal.any([ctx.signal, timeout]) : timeout;
|
|
4115
4812
|
try {
|
|
4116
|
-
|
|
4813
|
+
const genOptions = {
|
|
4117
4814
|
model,
|
|
4118
4815
|
messages: [{ role: "user", content }],
|
|
4119
4816
|
maxRetries: 0,
|
|
@@ -4121,7 +4818,9 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
|
|
|
4121
4818
|
google: googleOptions
|
|
4122
4819
|
},
|
|
4123
4820
|
abortSignal: signal
|
|
4124
|
-
}
|
|
4821
|
+
};
|
|
4822
|
+
if (req.temperature !== void 0) genOptions.temperature = req.temperature;
|
|
4823
|
+
return await deps.runTextGeneration(genOptions);
|
|
4125
4824
|
} catch (cause) {
|
|
4126
4825
|
throw toProviderError(cause, ctx);
|
|
4127
4826
|
}
|
|
@@ -4325,26 +5024,14 @@ function headers(ctx) {
|
|
|
4325
5024
|
const { key, secret } = credentials(ctx);
|
|
4326
5025
|
return { "Content-Type": "application/json", "hf-api-key": key, "hf-secret": secret };
|
|
4327
5026
|
}
|
|
4328
|
-
function refToUrl2(ref) {
|
|
4329
|
-
if ("url" in ref) return ref.url;
|
|
4330
|
-
return `data:${ref.mime};base64,${Buffer.from(ref.bytes).toString("base64")}`;
|
|
4331
|
-
}
|
|
4332
|
-
async function readBody2(res) {
|
|
4333
|
-
const text2 = await res.text().catch(() => "");
|
|
4334
|
-
try {
|
|
4335
|
-
const decoded = JsonValueSchema.safeParse(JSON.parse(text2));
|
|
4336
|
-
return decoded.success ? decoded.data : text2;
|
|
4337
|
-
} catch {
|
|
4338
|
-
return text2;
|
|
4339
|
-
}
|
|
4340
|
-
}
|
|
4341
5027
|
function klingEndpoint(providerModelId) {
|
|
4342
5028
|
if (providerModelId.startsWith("http")) return providerModelId;
|
|
4343
5029
|
const path = providerModelId.startsWith("/") ? providerModelId.slice(1) : providerModelId;
|
|
4344
5030
|
return `${PLATFORM}/${path}`;
|
|
4345
5031
|
}
|
|
4346
|
-
|
|
4347
|
-
|
|
5032
|
+
var DOP_MODEL_IDS = /* @__PURE__ */ new Set(["dop", "dop-preview"]);
|
|
5033
|
+
function higgsfieldVideoKind(providerModelId) {
|
|
5034
|
+
return DOP_MODEL_IDS.has(providerModelId.toLowerCase()) ? "dop" : "kling";
|
|
4348
5035
|
}
|
|
4349
5036
|
function videoUsage3(ctx, req, duration) {
|
|
4350
5037
|
const event = {
|
|
@@ -4388,12 +5075,12 @@ async function createRequest(ctx, url, init) {
|
|
|
4388
5075
|
throw classifyThrown("higgsfield", cause, ctx.model.id);
|
|
4389
5076
|
}
|
|
4390
5077
|
if (!res.ok) {
|
|
4391
|
-
throw classifyHttpError(res.status, await
|
|
5078
|
+
throw classifyHttpError(res.status, await readBody(res), "higgsfield", ctx.model.id);
|
|
4392
5079
|
}
|
|
4393
5080
|
return res;
|
|
4394
5081
|
}
|
|
4395
5082
|
async function generateKlingVideo(req, ctx) {
|
|
4396
|
-
const firstFrame = req.firstFrame ?
|
|
5083
|
+
const firstFrame = req.firstFrame ? refToUrl(req.firstFrame) : void 0;
|
|
4397
5084
|
if (!firstFrame) {
|
|
4398
5085
|
throw new ModelKitError({
|
|
4399
5086
|
code: "missing_input",
|
|
@@ -4412,7 +5099,7 @@ async function generateKlingVideo(req, ctx) {
|
|
|
4412
5099
|
if (req.durationSeconds !== void 0) body.duration = req.durationSeconds;
|
|
4413
5100
|
if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive")
|
|
4414
5101
|
body.aspect_ratio = req.aspectRatio;
|
|
4415
|
-
if (req.lastFrame) body.last_image_url =
|
|
5102
|
+
if (req.lastFrame) body.last_image_url = refToUrl(req.lastFrame);
|
|
4416
5103
|
const endpoint = klingEndpoint(ctx.model.providerModelId);
|
|
4417
5104
|
const retryOptions = {};
|
|
4418
5105
|
if (ctx.signal !== void 0) retryOptions.signal = ctx.signal;
|
|
@@ -4438,9 +5125,9 @@ async function generateKlingVideo(req, ctx) {
|
|
|
4438
5125
|
} catch {
|
|
4439
5126
|
return void 0;
|
|
4440
5127
|
}
|
|
4441
|
-
if (res.status >= 500) return void 0;
|
|
5128
|
+
if (res.status === 429 || res.status >= 500) return void 0;
|
|
4442
5129
|
if (!res.ok) {
|
|
4443
|
-
throw classifyHttpError(res.status, await
|
|
5130
|
+
throw classifyHttpError(res.status, await readBody(res), "higgsfield", ctx.model.id);
|
|
4444
5131
|
}
|
|
4445
5132
|
const payload = JsonValueSchema.parse(await res.json());
|
|
4446
5133
|
const parsed = klingStatusSchema.safeParse(payload);
|
|
@@ -4547,7 +5234,7 @@ function dopUrl(body) {
|
|
|
4547
5234
|
var dopCreateSchema = z10.object({ id: z10.string() });
|
|
4548
5235
|
var dopStatusSchema = z10.object({ status: z10.string().optional() });
|
|
4549
5236
|
async function generateDopVideo(req, ctx) {
|
|
4550
|
-
const firstFrame = req.firstFrame ?
|
|
5237
|
+
const firstFrame = req.firstFrame ? refToUrl(req.firstFrame) : void 0;
|
|
4551
5238
|
if (!firstFrame) {
|
|
4552
5239
|
throw new ModelKitError({
|
|
4553
5240
|
code: "missing_input",
|
|
@@ -4567,7 +5254,7 @@ async function generateDopVideo(req, ctx) {
|
|
|
4567
5254
|
webhook: null
|
|
4568
5255
|
};
|
|
4569
5256
|
if (req.lastFrame) {
|
|
4570
|
-
params.input_images_end = [{ type: "image_url", image_url:
|
|
5257
|
+
params.input_images_end = [{ type: "image_url", image_url: refToUrl(req.lastFrame) }];
|
|
4571
5258
|
}
|
|
4572
5259
|
if (req.seed !== void 0) params.seed = req.seed;
|
|
4573
5260
|
const retryOptions = {};
|
|
@@ -4657,7 +5344,10 @@ async function generateDopVideo(req, ctx) {
|
|
|
4657
5344
|
}
|
|
4658
5345
|
var higgsfieldAdapter = {
|
|
4659
5346
|
id: "higgsfield",
|
|
4660
|
-
generateVideo: (req, ctx) =>
|
|
5347
|
+
generateVideo: (req, ctx) => {
|
|
5348
|
+
throwIfAborted(ctx.signal);
|
|
5349
|
+
return higgsfieldVideoKind(ctx.model.providerModelId) === "dop" ? generateDopVideo(req, ctx) : generateKlingVideo(req, ctx);
|
|
5350
|
+
}
|
|
4661
5351
|
};
|
|
4662
5352
|
|
|
4663
5353
|
// src/adapters/openai-image.ts
|
|
@@ -4752,6 +5442,7 @@ var openaiUsageSchema = z11.object({
|
|
|
4752
5442
|
var openaiImageAdapter = {
|
|
4753
5443
|
id: "openai-image",
|
|
4754
5444
|
async generateImage(req, ctx) {
|
|
5445
|
+
throwIfAborted(ctx.signal);
|
|
4755
5446
|
const apiKey = ctx.keys.openai;
|
|
4756
5447
|
if (!apiKey)
|
|
4757
5448
|
throw new ModelKitError({
|
|
@@ -4761,6 +5452,13 @@ var openaiImageAdapter = {
|
|
|
4761
5452
|
model: ctx.model.id,
|
|
4762
5453
|
retryable: false
|
|
4763
5454
|
});
|
|
5455
|
+
if ((req.references ?? []).some((ref) => ref.label !== void 0)) {
|
|
5456
|
+
ctx.warnings.push({
|
|
5457
|
+
code: "option_ignored",
|
|
5458
|
+
field: "references.label",
|
|
5459
|
+
message: "openai-image cannot express reference labels; ignoring them"
|
|
5460
|
+
});
|
|
5461
|
+
}
|
|
4764
5462
|
const client2 = new OpenAI({ apiKey, fetch: ctx.fetch, maxRetries: 0 });
|
|
4765
5463
|
const size = req.exactSize !== void 0 ? req.exactSize : req.aspectRatio === void 0 || req.aspectRatio === "adaptive" ? void 0 : aspectRatioToSize(req.aspectRatio, req.size ?? "1K");
|
|
4766
5464
|
const refs = req.references ?? [];
|
|
@@ -4774,24 +5472,34 @@ var openaiImageAdapter = {
|
|
|
4774
5472
|
try {
|
|
4775
5473
|
if (!isEdit) {
|
|
4776
5474
|
if (size !== void 0) {
|
|
4777
|
-
return await client2.images.generate(
|
|
5475
|
+
return await client2.images.generate(
|
|
5476
|
+
{
|
|
5477
|
+
model: ctx.model.providerModelId,
|
|
5478
|
+
prompt: req.prompt,
|
|
5479
|
+
size,
|
|
5480
|
+
quality: sdkQuality,
|
|
5481
|
+
...count
|
|
5482
|
+
},
|
|
5483
|
+
{ signal: ctx.signal }
|
|
5484
|
+
);
|
|
5485
|
+
}
|
|
5486
|
+
return await client2.images.generate(
|
|
5487
|
+
{
|
|
4778
5488
|
model: ctx.model.providerModelId,
|
|
4779
5489
|
prompt: req.prompt,
|
|
4780
|
-
size,
|
|
4781
5490
|
quality: sdkQuality,
|
|
4782
5491
|
...count
|
|
4783
|
-
}
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
model: ctx.model.providerModelId,
|
|
4787
|
-
prompt: req.prompt,
|
|
4788
|
-
quality: sdkQuality,
|
|
4789
|
-
...count
|
|
4790
|
-
});
|
|
5492
|
+
},
|
|
5493
|
+
{ signal: ctx.signal }
|
|
5494
|
+
);
|
|
4791
5495
|
}
|
|
4792
5496
|
const files = await Promise.all(
|
|
4793
5497
|
refs.slice(0, MAX_EDIT_REFERENCES).map(async (ref, i) => {
|
|
4794
|
-
const { bytes, mime } = await mediaRefToBytes(ref, ctx.fetch
|
|
5498
|
+
const { bytes, mime } = await mediaRefToBytes(ref, ctx.fetch, {
|
|
5499
|
+
signal: ctx.signal,
|
|
5500
|
+
provider: "openai-image",
|
|
5501
|
+
model: ctx.model.id
|
|
5502
|
+
});
|
|
4795
5503
|
const ext = mime.includes("jpeg") ? "jpg" : mime.includes("webp") ? "webp" : "png";
|
|
4796
5504
|
return new File([bytes], `ref-${i}.${ext}`, { type: mime });
|
|
4797
5505
|
})
|
|
@@ -4799,22 +5507,28 @@ var openaiImageAdapter = {
|
|
|
4799
5507
|
const single = files.length === 1 ? files[0] : void 0;
|
|
4800
5508
|
const imageInput = single ?? files;
|
|
4801
5509
|
if (size !== void 0) {
|
|
4802
|
-
return await client2.images.edit(
|
|
5510
|
+
return await client2.images.edit(
|
|
5511
|
+
{
|
|
5512
|
+
model: ctx.model.providerModelId,
|
|
5513
|
+
image: imageInput,
|
|
5514
|
+
prompt: req.prompt,
|
|
5515
|
+
size,
|
|
5516
|
+
quality: sdkQuality,
|
|
5517
|
+
...count
|
|
5518
|
+
},
|
|
5519
|
+
{ signal: ctx.signal }
|
|
5520
|
+
);
|
|
5521
|
+
}
|
|
5522
|
+
return await client2.images.edit(
|
|
5523
|
+
{
|
|
4803
5524
|
model: ctx.model.providerModelId,
|
|
4804
5525
|
image: imageInput,
|
|
4805
5526
|
prompt: req.prompt,
|
|
4806
|
-
size,
|
|
4807
5527
|
quality: sdkQuality,
|
|
4808
5528
|
...count
|
|
4809
|
-
}
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
model: ctx.model.providerModelId,
|
|
4813
|
-
image: imageInput,
|
|
4814
|
-
prompt: req.prompt,
|
|
4815
|
-
quality: sdkQuality,
|
|
4816
|
-
...count
|
|
4817
|
-
});
|
|
5529
|
+
},
|
|
5530
|
+
{ signal: ctx.signal }
|
|
5531
|
+
);
|
|
4818
5532
|
} catch (cause) {
|
|
4819
5533
|
throw toProviderError2(cause, ctx);
|
|
4820
5534
|
}
|
|
@@ -4896,7 +5610,7 @@ async function refToBytes(ctx, ref) {
|
|
|
4896
5610
|
if ("bytes" in ref) return { bytes: ref.bytes, mime: ref.mime };
|
|
4897
5611
|
let res;
|
|
4898
5612
|
try {
|
|
4899
|
-
res = await ctx.fetch(ref.url);
|
|
5613
|
+
res = await ctx.fetch(ref.url, ctx.signal ? { signal: ctx.signal } : {});
|
|
4900
5614
|
} catch (cause) {
|
|
4901
5615
|
throw classifyThrown("prodia", cause, ctx.model.id);
|
|
4902
5616
|
}
|
|
@@ -4942,6 +5656,12 @@ function emptyImage() {
|
|
|
4942
5656
|
retryable: false
|
|
4943
5657
|
});
|
|
4944
5658
|
}
|
|
5659
|
+
function inputExtension(mime) {
|
|
5660
|
+
if (mime.includes("jpeg") || mime.includes("jpg")) return "jpg";
|
|
5661
|
+
if (mime.includes("webp")) return "webp";
|
|
5662
|
+
if (mime.includes("gif")) return "gif";
|
|
5663
|
+
return "png";
|
|
5664
|
+
}
|
|
4945
5665
|
function isBgRemove(providerModelId) {
|
|
4946
5666
|
const id = providerModelId.toLowerCase();
|
|
4947
5667
|
return id.includes("remove-background") || id.includes("bg-remove");
|
|
@@ -4950,6 +5670,7 @@ function isKlein(providerModelId) {
|
|
|
4950
5670
|
return providerModelId.toLowerCase().includes("klein");
|
|
4951
5671
|
}
|
|
4952
5672
|
async function generateProdiaImage(req, ctx) {
|
|
5673
|
+
throwIfAborted(ctx.signal);
|
|
4953
5674
|
const key = ctx.keys.prodia;
|
|
4954
5675
|
if (!key) {
|
|
4955
5676
|
throw new ModelKitError({
|
|
@@ -5048,7 +5769,9 @@ async function generateProdiaImage(req, ctx) {
|
|
|
5048
5769
|
"input",
|
|
5049
5770
|
// Uint8Array<ArrayBufferLike> is not a valid BlobPart under the
|
|
5050
5771
|
// strict lib types; copy into a fresh ArrayBuffer-backed view.
|
|
5051
|
-
new File([new Uint8Array(input.bytes)], `input-${i}.
|
|
5772
|
+
new File([new Uint8Array(input.bytes)], `input-${i}.${inputExtension(input.mime)}`, {
|
|
5773
|
+
type: input.mime
|
|
5774
|
+
})
|
|
5052
5775
|
);
|
|
5053
5776
|
});
|
|
5054
5777
|
const retryOpts = {
|
|
@@ -5063,11 +5786,13 @@ async function generateProdiaImage(req, ctx) {
|
|
|
5063
5786
|
res = await withRetry(async () => {
|
|
5064
5787
|
let attemptRes;
|
|
5065
5788
|
try {
|
|
5066
|
-
|
|
5789
|
+
const init = {
|
|
5067
5790
|
method: "POST",
|
|
5068
5791
|
headers: { Authorization: `Bearer ${key}`, Accept: accept },
|
|
5069
5792
|
body: form
|
|
5070
|
-
}
|
|
5793
|
+
};
|
|
5794
|
+
if (ctx.signal !== void 0) init.signal = ctx.signal;
|
|
5795
|
+
attemptRes = await ctx.fetch(PRODIA_JOB_URL, init);
|
|
5071
5796
|
} catch (err) {
|
|
5072
5797
|
throw classifyThrown("prodia", err, ctx.model.id);
|
|
5073
5798
|
}
|
|
@@ -5128,11 +5853,7 @@ function client(ctx, deps) {
|
|
|
5128
5853
|
retryable: false
|
|
5129
5854
|
});
|
|
5130
5855
|
}
|
|
5131
|
-
return deps.createReplicateClient({ auth: token });
|
|
5132
|
-
}
|
|
5133
|
-
function refToUrl3(ref) {
|
|
5134
|
-
if ("url" in ref) return ref.url;
|
|
5135
|
-
return `data:${ref.mime};base64,${Buffer.from(ref.bytes).toString("base64")}`;
|
|
5856
|
+
return deps.createReplicateClient({ auth: token, fetch: ctx.fetch });
|
|
5136
5857
|
}
|
|
5137
5858
|
function route(providerModelId) {
|
|
5138
5859
|
if (providerModelId.includes(":")) {
|
|
@@ -5152,8 +5873,9 @@ function replicateError(cause, ctx) {
|
|
|
5152
5873
|
const status = info.status ?? (nested.success ? nested.data.response?.status : void 0);
|
|
5153
5874
|
return classifyThrown("replicate", cause, ctx.model.id, { status, body: info.body });
|
|
5154
5875
|
}
|
|
5155
|
-
function
|
|
5156
|
-
|
|
5876
|
+
function baseModelId(providerModelId) {
|
|
5877
|
+
const colon = providerModelId.indexOf(":");
|
|
5878
|
+
return colon === -1 ? providerModelId : providerModelId.slice(0, colon);
|
|
5157
5879
|
}
|
|
5158
5880
|
function predictionErrorBody(cause) {
|
|
5159
5881
|
const parsed = JsonValueSchema.safeParse(cause);
|
|
@@ -5201,6 +5923,7 @@ function noOutput() {
|
|
|
5201
5923
|
});
|
|
5202
5924
|
}
|
|
5203
5925
|
async function runPrediction(ctx, input, deps) {
|
|
5926
|
+
throwIfAborted(ctx.signal);
|
|
5204
5927
|
const api = client(ctx, deps);
|
|
5205
5928
|
const createOptions = { ...route(ctx.model.providerModelId), input };
|
|
5206
5929
|
let prediction;
|
|
@@ -5208,12 +5931,14 @@ async function runPrediction(ctx, input, deps) {
|
|
|
5208
5931
|
prediction = await withRetry(
|
|
5209
5932
|
async () => {
|
|
5210
5933
|
try {
|
|
5211
|
-
return await api.predictions.create(
|
|
5934
|
+
return await api.predictions.create(
|
|
5935
|
+
ctx.signal ? { ...createOptions, signal: ctx.signal } : createOptions
|
|
5936
|
+
);
|
|
5212
5937
|
} catch (cause) {
|
|
5213
5938
|
throw replicateError(cause, ctx);
|
|
5214
5939
|
}
|
|
5215
5940
|
},
|
|
5216
|
-
|
|
5941
|
+
{ attempts: 1 }
|
|
5217
5942
|
);
|
|
5218
5943
|
} catch (cause) {
|
|
5219
5944
|
throw replicateError(cause, ctx);
|
|
@@ -5226,7 +5951,10 @@ async function runPrediction(ctx, input, deps) {
|
|
|
5226
5951
|
const done = await pollUntil(async () => {
|
|
5227
5952
|
let current;
|
|
5228
5953
|
try {
|
|
5229
|
-
current = await api.predictions.get(
|
|
5954
|
+
current = await api.predictions.get(
|
|
5955
|
+
prediction.id,
|
|
5956
|
+
ctx.signal ? { signal: ctx.signal } : void 0
|
|
5957
|
+
);
|
|
5230
5958
|
} catch (cause) {
|
|
5231
5959
|
throw replicateError(cause, ctx);
|
|
5232
5960
|
}
|
|
@@ -5293,21 +6021,32 @@ async function download(ctx, url) {
|
|
|
5293
6021
|
const mime = res.headers.get("content-type") ?? "image/png";
|
|
5294
6022
|
return { bytes: new Uint8Array(await res.arrayBuffer()), mime };
|
|
5295
6023
|
}
|
|
5296
|
-
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
}
|
|
5303
|
-
function
|
|
5304
|
-
return
|
|
5305
|
-
}
|
|
5306
|
-
|
|
5307
|
-
|
|
6024
|
+
var REPLICATE_IMAGE_KINDS = {
|
|
6025
|
+
"topazlabs/image-upscale": "topaz",
|
|
6026
|
+
"philz1337x/crystal-upscaler": "upscaler",
|
|
6027
|
+
"wan-video/wan-2.7-image-pro": "wan",
|
|
6028
|
+
"qwen/qwen-image-2-pro": "qwen-image",
|
|
6029
|
+
"qwen-edit-apps/qwen-image-edit-plus-lora-skin": "qwen-edit"
|
|
6030
|
+
};
|
|
6031
|
+
function imageKind(providerModelId) {
|
|
6032
|
+
return REPLICATE_IMAGE_KINDS[baseModelId(providerModelId)] ?? "generic";
|
|
6033
|
+
}
|
|
6034
|
+
var REPLICATE_VIDEO_KINDS = {
|
|
6035
|
+
"kling-video/v2.5-turbo/pro/image-to-video": "kling",
|
|
6036
|
+
"kling-video/v3.0/pro/image-to-video": "kling",
|
|
6037
|
+
"kwaivgi/kling-v3-video": "kling",
|
|
6038
|
+
"kwaivgi/kling-v3-omni-video": "kling-omni",
|
|
6039
|
+
"minimax/hailuo-02": "hailuo"
|
|
6040
|
+
};
|
|
6041
|
+
function videoKind(providerModelId) {
|
|
6042
|
+
return REPLICATE_VIDEO_KINDS[baseModelId(providerModelId)] ?? "wan";
|
|
5308
6043
|
}
|
|
5309
|
-
|
|
5310
|
-
|
|
6044
|
+
var REPLICATE_AUDIO_KINDS = {
|
|
6045
|
+
"zsxkib/mmaudio": "mmaudio",
|
|
6046
|
+
"elevenlabs/music": "elevenlabs"
|
|
6047
|
+
};
|
|
6048
|
+
function audioKind(providerModelId) {
|
|
6049
|
+
return REPLICATE_AUDIO_KINDS[baseModelId(providerModelId)] ?? "lyria";
|
|
5311
6050
|
}
|
|
5312
6051
|
var QWEN_IMAGE_RATIOS = /* @__PURE__ */ new Set([
|
|
5313
6052
|
"1:1",
|
|
@@ -5350,87 +6089,113 @@ function wanImageSize(aspectRatio, size) {
|
|
|
5350
6089
|
async function generateReplicateImage(req, ctx, deps) {
|
|
5351
6090
|
const id = ctx.model.providerModelId;
|
|
5352
6091
|
let input;
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
6092
|
+
switch (imageKind(id)) {
|
|
6093
|
+
case "topaz": {
|
|
6094
|
+
const first = (req.references ?? [])[0];
|
|
6095
|
+
if (!first) {
|
|
6096
|
+
throw new ModelKitError({
|
|
6097
|
+
code: "missing_input",
|
|
6098
|
+
message: `${ctx.model.id} requires a reference image to upscale`,
|
|
6099
|
+
provider: "replicate",
|
|
6100
|
+
model: ctx.model.id,
|
|
6101
|
+
retryable: false
|
|
6102
|
+
});
|
|
6103
|
+
}
|
|
6104
|
+
let format = req.outputFormat === "jpeg" ? "jpg" : req.outputFormat ?? "png";
|
|
6105
|
+
if (format !== "png" && format !== "jpg") {
|
|
6106
|
+
ctx.warnings.push({
|
|
6107
|
+
code: "option_ignored",
|
|
6108
|
+
field: "outputFormat",
|
|
6109
|
+
from: format,
|
|
6110
|
+
message: "topazlabs/image-upscale supports only png and jpg; using png"
|
|
6111
|
+
});
|
|
6112
|
+
format = "png";
|
|
6113
|
+
}
|
|
6114
|
+
const upscale = req.upscale;
|
|
6115
|
+
const topaz = {
|
|
6116
|
+
image: refToUrl(first),
|
|
6117
|
+
enhance_model: upscale?.enhanceModel ?? "Standard V2",
|
|
6118
|
+
output_format: format,
|
|
6119
|
+
upscale_factor: `${req.scaleFactor ?? 2}x`,
|
|
6120
|
+
face_enhancement: upscale?.faceEnhancement ?? false
|
|
6121
|
+
};
|
|
6122
|
+
if (upscale?.subjectDetection !== void 0)
|
|
6123
|
+
topaz.subject_detection = upscale.subjectDetection;
|
|
6124
|
+
if (upscale?.faceEnhancementCreativity !== void 0)
|
|
6125
|
+
topaz.face_enhancement_creativity = upscale.faceEnhancementCreativity;
|
|
6126
|
+
if (upscale?.faceEnhancementStrength !== void 0)
|
|
6127
|
+
topaz.face_enhancement_strength = upscale.faceEnhancementStrength;
|
|
6128
|
+
input = topaz;
|
|
6129
|
+
break;
|
|
5363
6130
|
}
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
|
|
6131
|
+
case "upscaler": {
|
|
6132
|
+
const first = (req.references ?? [])[0];
|
|
6133
|
+
if (!first) {
|
|
6134
|
+
throw new ModelKitError({
|
|
6135
|
+
code: "missing_input",
|
|
6136
|
+
message: `${ctx.model.id} requires a reference image to upscale`,
|
|
6137
|
+
provider: "replicate",
|
|
6138
|
+
model: ctx.model.id,
|
|
6139
|
+
retryable: false
|
|
6140
|
+
});
|
|
6141
|
+
}
|
|
6142
|
+
const imageInput = { prompt: req.prompt };
|
|
6143
|
+
imageInput.image = refToUrl(first);
|
|
6144
|
+
imageInput.creativity = 0;
|
|
6145
|
+
imageInput.scale_factor = 2;
|
|
6146
|
+
imageInput.output_format = "png";
|
|
6147
|
+
input = imageInput;
|
|
6148
|
+
break;
|
|
5373
6149
|
}
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
} else if (isUpscaler(id)) {
|
|
5382
|
-
const refs = req.references ?? [];
|
|
5383
|
-
const first = refs[0];
|
|
5384
|
-
if (!first) {
|
|
5385
|
-
throw new ModelKitError({
|
|
5386
|
-
code: "missing_input",
|
|
5387
|
-
message: `${ctx.model.id} requires a reference image to upscale`,
|
|
5388
|
-
provider: "replicate",
|
|
5389
|
-
model: ctx.model.id,
|
|
5390
|
-
retryable: false
|
|
5391
|
-
});
|
|
6150
|
+
case "wan": {
|
|
6151
|
+
const refs = (req.references ?? []).map(refToUrl);
|
|
6152
|
+
const imageInput = { prompt: req.prompt };
|
|
6153
|
+
if (refs.length > 0) imageInput.images = refs;
|
|
6154
|
+
imageInput.size = wanImageSize(req.aspectRatio, req.size);
|
|
6155
|
+
input = imageInput;
|
|
6156
|
+
break;
|
|
5392
6157
|
}
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
} else if (isQwen(id)) {
|
|
5406
|
-
const refs = (req.references ?? []).map(refToUrl3);
|
|
5407
|
-
const firstUrl = refs[0];
|
|
5408
|
-
const imageInput = { prompt: req.prompt };
|
|
5409
|
-
if (firstUrl !== void 0) {
|
|
5410
|
-
imageInput.image = firstUrl;
|
|
5411
|
-
if (!isQwenEditPlus(id)) imageInput.match_input_image = true;
|
|
6158
|
+
case "qwen-image": {
|
|
6159
|
+
const refs = (req.references ?? []).map(refToUrl);
|
|
6160
|
+
const firstUrl = refs[0];
|
|
6161
|
+
const imageInput = { prompt: req.prompt };
|
|
6162
|
+
if (firstUrl !== void 0) {
|
|
6163
|
+
imageInput.image = firstUrl;
|
|
6164
|
+
imageInput.match_input_image = true;
|
|
6165
|
+
} else if (req.aspectRatio !== void 0 && QWEN_IMAGE_RATIOS.has(req.aspectRatio)) {
|
|
6166
|
+
imageInput.aspect_ratio = req.aspectRatio;
|
|
6167
|
+
}
|
|
6168
|
+
input = imageInput;
|
|
6169
|
+
break;
|
|
5412
6170
|
}
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
6171
|
+
case "qwen-edit": {
|
|
6172
|
+
const refs = (req.references ?? []).map(refToUrl);
|
|
6173
|
+
const firstUrl = refs[0];
|
|
6174
|
+
const imageInput = { prompt: req.prompt };
|
|
6175
|
+
if (firstUrl !== void 0) imageInput.image = firstUrl;
|
|
6176
|
+
if (req.aspectRatio !== void 0) {
|
|
6177
|
+
if (QWEN_EDIT_RATIOS.has(req.aspectRatio))
|
|
6178
|
+
imageInput.aspect_ratio = req.aspectRatio;
|
|
6179
|
+
else
|
|
6180
|
+
ctx.warnings.push({
|
|
6181
|
+
code: "option_ignored",
|
|
6182
|
+
field: "aspectRatio",
|
|
6183
|
+
from: req.aspectRatio,
|
|
6184
|
+
message: `${id} has no ${req.aspectRatio} aspect_ratio; using the provider default`
|
|
6185
|
+
});
|
|
6186
|
+
}
|
|
6187
|
+
if (req.outputFormat !== void 0) {
|
|
6188
|
+
imageInput.output_format = req.outputFormat === "jpeg" ? "jpg" : req.outputFormat;
|
|
6189
|
+
}
|
|
6190
|
+
input = imageInput;
|
|
6191
|
+
break;
|
|
5423
6192
|
}
|
|
5424
|
-
|
|
5425
|
-
|
|
6193
|
+
default: {
|
|
6194
|
+
const first = (req.references ?? [])[0];
|
|
6195
|
+
const imageInput = { prompt: req.prompt };
|
|
6196
|
+
if (first) imageInput.image = refToUrl(first);
|
|
6197
|
+
input = imageInput;
|
|
5426
6198
|
}
|
|
5427
|
-
input = imageInput;
|
|
5428
|
-
} else {
|
|
5429
|
-
const refs = req.references ?? [];
|
|
5430
|
-
const first = refs[0];
|
|
5431
|
-
const imageInput = { prompt: req.prompt };
|
|
5432
|
-
if (first) imageInput.image = refToUrl3(first);
|
|
5433
|
-
input = imageInput;
|
|
5434
6199
|
}
|
|
5435
6200
|
const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
|
|
5436
6201
|
const file = await download(ctx, url);
|
|
@@ -5447,8 +6212,8 @@ function wanSize(aspectRatio) {
|
|
|
5447
6212
|
return w > h ? "2048*1152" : "1536*2048";
|
|
5448
6213
|
}
|
|
5449
6214
|
function klingInput(req) {
|
|
5450
|
-
const images = (req.firstFrame ? [req.firstFrame] : []).map(
|
|
5451
|
-
if (req.lastFrame) images.push(
|
|
6215
|
+
const images = (req.firstFrame ? [req.firstFrame] : []).map(refToUrl);
|
|
6216
|
+
if (req.lastFrame) images.push(refToUrl(req.lastFrame));
|
|
5452
6217
|
const input = {
|
|
5453
6218
|
prompt: req.prompt,
|
|
5454
6219
|
duration: req.durationSeconds ?? 10,
|
|
@@ -5466,13 +6231,18 @@ function klingInput(req) {
|
|
|
5466
6231
|
if (req.negativePrompt !== void 0) input.negative_prompt = req.negativePrompt;
|
|
5467
6232
|
return input;
|
|
5468
6233
|
}
|
|
6234
|
+
function klingOmniMode(req) {
|
|
6235
|
+
if (req.resolution === "1080p") return "pro";
|
|
6236
|
+
if (req.resolution === "720p") return "standard";
|
|
6237
|
+
return req.mode ?? "standard";
|
|
6238
|
+
}
|
|
5469
6239
|
function klingOmniInput(req) {
|
|
5470
|
-
const images = (req.firstFrame ? [req.firstFrame] : []).map(
|
|
5471
|
-
if (req.lastFrame) images.push(
|
|
6240
|
+
const images = (req.firstFrame ? [req.firstFrame] : []).map(refToUrl);
|
|
6241
|
+
if (req.lastFrame) images.push(refToUrl(req.lastFrame));
|
|
5472
6242
|
const input = {
|
|
5473
6243
|
prompt: req.prompt,
|
|
5474
6244
|
duration: req.durationSeconds ?? 10,
|
|
5475
|
-
mode: req
|
|
6245
|
+
mode: klingOmniMode(req),
|
|
5476
6246
|
generate_audio: req.generateAudio ?? false
|
|
5477
6247
|
};
|
|
5478
6248
|
const startImage = images[0];
|
|
@@ -5483,7 +6253,7 @@ function klingOmniInput(req) {
|
|
|
5483
6253
|
} else if (req.aspectRatio !== "adaptive") {
|
|
5484
6254
|
input.aspect_ratio = req.aspectRatio ?? "16:9";
|
|
5485
6255
|
}
|
|
5486
|
-
const refs = (req.referenceImages ?? []).map(
|
|
6256
|
+
const refs = (req.referenceImages ?? []).map(refToUrl);
|
|
5487
6257
|
if (refs.length > 0) input.reference_images = refs;
|
|
5488
6258
|
return input;
|
|
5489
6259
|
}
|
|
@@ -5494,8 +6264,8 @@ function hailuoInput(req) {
|
|
|
5494
6264
|
resolution: req.resolution ?? "768p",
|
|
5495
6265
|
prompt_optimizer: true
|
|
5496
6266
|
};
|
|
5497
|
-
if (req.firstFrame) input.first_frame_image =
|
|
5498
|
-
if (req.lastFrame) input.last_frame_image =
|
|
6267
|
+
if (req.firstFrame) input.first_frame_image = refToUrl(req.firstFrame);
|
|
6268
|
+
if (req.lastFrame) input.last_frame_image = refToUrl(req.lastFrame);
|
|
5499
6269
|
return input;
|
|
5500
6270
|
}
|
|
5501
6271
|
function wanInput(req) {
|
|
@@ -5504,12 +6274,13 @@ function wanInput(req) {
|
|
|
5504
6274
|
duration: req.durationSeconds ?? 5,
|
|
5505
6275
|
size: wanSize(req.aspectRatio)
|
|
5506
6276
|
};
|
|
5507
|
-
if (req.firstFrame) input.image =
|
|
6277
|
+
if (req.firstFrame) input.image = refToUrl(req.firstFrame);
|
|
5508
6278
|
return input;
|
|
5509
6279
|
}
|
|
5510
6280
|
async function generateReplicateVideo(req, ctx, deps) {
|
|
5511
|
-
|
|
5512
|
-
const
|
|
6281
|
+
throwIfAborted(ctx.signal);
|
|
6282
|
+
const kind = videoKind(ctx.model.providerModelId);
|
|
6283
|
+
const input = kind === "kling" ? klingInput(req) : kind === "kling-omni" ? klingOmniInput(req) : kind === "hailuo" ? hailuoInput(req) : wanInput(req);
|
|
5513
6284
|
const api = client(ctx, deps);
|
|
5514
6285
|
const createOptions = { ...route(ctx.model.providerModelId), input };
|
|
5515
6286
|
let prediction;
|
|
@@ -5517,12 +6288,14 @@ async function generateReplicateVideo(req, ctx, deps) {
|
|
|
5517
6288
|
prediction = await withRetry(
|
|
5518
6289
|
async () => {
|
|
5519
6290
|
try {
|
|
5520
|
-
return await api.predictions.create(
|
|
6291
|
+
return await api.predictions.create(
|
|
6292
|
+
ctx.signal ? { ...createOptions, signal: ctx.signal } : createOptions
|
|
6293
|
+
);
|
|
5521
6294
|
} catch (cause) {
|
|
5522
6295
|
throw replicateError(cause, ctx);
|
|
5523
6296
|
}
|
|
5524
6297
|
},
|
|
5525
|
-
|
|
6298
|
+
{ attempts: 1 }
|
|
5526
6299
|
);
|
|
5527
6300
|
} catch (cause) {
|
|
5528
6301
|
throw replicateError(cause, ctx);
|
|
@@ -5531,7 +6304,10 @@ async function generateReplicateVideo(req, ctx, deps) {
|
|
|
5531
6304
|
const check = async () => {
|
|
5532
6305
|
let current;
|
|
5533
6306
|
try {
|
|
5534
|
-
current = await api.predictions.get(
|
|
6307
|
+
current = await api.predictions.get(
|
|
6308
|
+
jobId,
|
|
6309
|
+
ctx.signal ? { signal: ctx.signal } : void 0
|
|
6310
|
+
);
|
|
5535
6311
|
} catch (cause) {
|
|
5536
6312
|
throw replicateError(cause, ctx);
|
|
5537
6313
|
}
|
|
@@ -5632,7 +6408,7 @@ function mmaudioInput(req, ctx) {
|
|
|
5632
6408
|
});
|
|
5633
6409
|
}
|
|
5634
6410
|
const input = {
|
|
5635
|
-
video:
|
|
6411
|
+
video: refToUrl(video),
|
|
5636
6412
|
duration: req.durationSeconds ?? 8,
|
|
5637
6413
|
seed: req.seed ?? -1
|
|
5638
6414
|
};
|
|
@@ -5651,8 +6427,8 @@ function predictionRaw(prediction) {
|
|
|
5651
6427
|
return raw;
|
|
5652
6428
|
}
|
|
5653
6429
|
async function generateReplicateAudio(req, ctx, deps) {
|
|
5654
|
-
const
|
|
5655
|
-
const input =
|
|
6430
|
+
const kind = audioKind(ctx.model.providerModelId);
|
|
6431
|
+
const input = kind === "mmaudio" ? mmaudioInput(req, ctx) : kind === "elevenlabs" ? elevenLabsMusicInput(req, ctx) : lyriaAudioInput(req, ctx);
|
|
5656
6432
|
const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
|
|
5657
6433
|
const usage2 = audioUsage(ctx, req);
|
|
5658
6434
|
if (ctx.model.usage.unit === "seconds") {
|
|
@@ -5681,10 +6457,6 @@ function createXaiVideoAdapter(deps = defaultXaiDeps) {
|
|
|
5681
6457
|
};
|
|
5682
6458
|
}
|
|
5683
6459
|
var xaiVideoAdapter = createXaiVideoAdapter();
|
|
5684
|
-
function refToUrl4(ref) {
|
|
5685
|
-
if ("url" in ref) return ref.url;
|
|
5686
|
-
return `data:${ref.mime};base64,${Buffer.from(ref.bytes).toString("base64")}`;
|
|
5687
|
-
}
|
|
5688
6460
|
var xaiResponseStatusSchema = z13.object({
|
|
5689
6461
|
response: z13.object({ status: z13.number() }).partial()
|
|
5690
6462
|
});
|
|
@@ -5716,13 +6488,14 @@ async function generateXaiVideo(req, ctx, deps) {
|
|
|
5716
6488
|
retryable: false
|
|
5717
6489
|
});
|
|
5718
6490
|
}
|
|
5719
|
-
const refUrls = (req.referenceImages ?? []).map(
|
|
5720
|
-
const resolution = req.resolution === "480p" ? "480p" : "720p";
|
|
6491
|
+
const refUrls = (req.referenceImages ?? []).map(refToUrl).slice(0, 7);
|
|
5721
6492
|
const xaiOptions = {
|
|
5722
|
-
resolution,
|
|
5723
6493
|
pollIntervalMs: POLL_INTERVAL_MS2,
|
|
5724
6494
|
pollTimeoutMs: POLL_TIMEOUT_MS2
|
|
5725
6495
|
};
|
|
6496
|
+
if (req.resolution === "480p" || req.resolution === "720p" || req.resolution === "1080p") {
|
|
6497
|
+
xaiOptions.resolution = req.resolution;
|
|
6498
|
+
}
|
|
5726
6499
|
if (refUrls.length > 0) {
|
|
5727
6500
|
xaiOptions.mode = "reference-to-video";
|
|
5728
6501
|
xaiOptions.referenceImageUrls = refUrls;
|
|
@@ -5742,7 +6515,7 @@ async function generateXaiVideo(req, ctx, deps) {
|
|
|
5742
6515
|
providerOptions: { xai: xaiOptions }
|
|
5743
6516
|
};
|
|
5744
6517
|
if (req.firstFrame) {
|
|
5745
|
-
callBody.frameImages = [{ image:
|
|
6518
|
+
callBody.frameImages = [{ image: refToUrl(req.firstFrame), frameType: "first_frame" }];
|
|
5746
6519
|
}
|
|
5747
6520
|
if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive") {
|
|
5748
6521
|
callBody.aspectRatio = req.aspectRatio;
|
|
@@ -5778,7 +6551,8 @@ async function generateXaiVideo(req, ctx, deps) {
|
|
|
5778
6551
|
return settled;
|
|
5779
6552
|
};
|
|
5780
6553
|
return {
|
|
5781
|
-
|
|
6554
|
+
// xAI exposes no request id on the synchronous handle, so each job gets a fresh one.
|
|
6555
|
+
jobId: crypto.randomUUID(),
|
|
5782
6556
|
async poll() {
|
|
5783
6557
|
if (failed !== void 0) return { status: "failed" };
|
|
5784
6558
|
return settled ? { status: "succeeded" } : { status: "pending" };
|
|
@@ -5912,6 +6686,7 @@ export {
|
|
|
5912
6686
|
prodiaAdapter,
|
|
5913
6687
|
readErrorBody,
|
|
5914
6688
|
replicateAdapter,
|
|
6689
|
+
resolveAudioOptions,
|
|
5915
6690
|
resolveImageOptions,
|
|
5916
6691
|
resolveKeys,
|
|
5917
6692
|
resolveVideoOptions,
|