@brotu/ai 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/CATALOG.md +387 -0
  2. package/LICENSE +21 -0
  3. package/README.md +115 -0
  4. package/dist/adapters/byteplus.adapter.d.ts +51 -0
  5. package/dist/adapters/byteplus.adapter.d.ts.map +1 -0
  6. package/dist/adapters/elevenlabs.adapter.d.ts +48 -0
  7. package/dist/adapters/elevenlabs.adapter.d.ts.map +1 -0
  8. package/dist/adapters/estimate.d.ts +10 -0
  9. package/dist/adapters/estimate.d.ts.map +1 -0
  10. package/dist/adapters/google.adapter.d.ts +52 -0
  11. package/dist/adapters/google.adapter.d.ts.map +1 -0
  12. package/dist/adapters/kling.adapter.d.ts +57 -0
  13. package/dist/adapters/kling.adapter.d.ts.map +1 -0
  14. package/dist/adapters/openai.adapter.d.ts +40 -0
  15. package/dist/adapters/openai.adapter.d.ts.map +1 -0
  16. package/dist/adapters/qwen.adapter.d.ts +53 -0
  17. package/dist/adapters/qwen.adapter.d.ts.map +1 -0
  18. package/dist/catalog.cjs +988 -0
  19. package/dist/catalog.d.ts +27 -0
  20. package/dist/catalog.d.ts.map +1 -0
  21. package/dist/catalog.js +20 -0
  22. package/dist/chunk-GKLTQ55S.js +1176 -0
  23. package/dist/client.d.ts +86 -0
  24. package/dist/client.d.ts.map +1 -0
  25. package/dist/constants/model.types.d.ts +118 -0
  26. package/dist/constants/model.types.d.ts.map +1 -0
  27. package/dist/helpers/result.d.ts +54 -0
  28. package/dist/helpers/result.d.ts.map +1 -0
  29. package/dist/index.cjs +3568 -0
  30. package/dist/index.d.ts +29 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +2386 -0
  33. package/dist/lib/jobs.d.ts +46 -0
  34. package/dist/lib/jobs.d.ts.map +1 -0
  35. package/dist/lib/storage.d.ts +33 -0
  36. package/dist/lib/storage.d.ts.map +1 -0
  37. package/dist/ports/content-generator.port.d.ts +170 -0
  38. package/dist/ports/content-generator.port.d.ts.map +1 -0
  39. package/dist/providers/byteplus.models.d.ts +51 -0
  40. package/dist/providers/byteplus.models.d.ts.map +1 -0
  41. package/dist/providers/elevenlabs.models.d.ts +27 -0
  42. package/dist/providers/elevenlabs.models.d.ts.map +1 -0
  43. package/dist/providers/google.models.d.ts +42 -0
  44. package/dist/providers/google.models.d.ts.map +1 -0
  45. package/dist/providers/kling.models.d.ts +159 -0
  46. package/dist/providers/kling.models.d.ts.map +1 -0
  47. package/dist/providers/openai.models.d.ts +27 -0
  48. package/dist/providers/openai.models.d.ts.map +1 -0
  49. package/dist/providers/qwen.models.d.ts +88 -0
  50. package/dist/providers/qwen.models.d.ts.map +1 -0
  51. package/dist/types.d.ts +55 -0
  52. package/dist/types.d.ts.map +1 -0
  53. package/package.json +72 -0
@@ -0,0 +1,1176 @@
1
+ // src/providers/byteplus.models.ts
2
+ var FPS = 24;
3
+ var PIXELS = {
4
+ "480p": [854, 480],
5
+ "720p": [1280, 720],
6
+ "1080p": [1920, 1080],
7
+ "4k": [3840, 2160]
8
+ };
9
+ function usdPerSecond(usdPerMillionTokens) {
10
+ const out = {};
11
+ for (const [resolution, rate] of Object.entries(usdPerMillionTokens)) {
12
+ const [w, h] = PIXELS[resolution] ?? [0, 0];
13
+ const tokensPerSecond = w * h * FPS / 1024;
14
+ out[resolution] = Number((tokensPerSecond * rate / 1e6).toFixed(4));
15
+ }
16
+ return out;
17
+ }
18
+ var TOKEN_RATES = {
19
+ "dreamina-seedance-2-5-260628": { "480p": 10.7, "720p": 10.7, "1080p": 11.7 },
20
+ "dreamina-seedance-2-0-260128": {
21
+ "480p": 7,
22
+ "720p": 7,
23
+ "1080p": 7.7,
24
+ "4k": 4
25
+ },
26
+ "dreamina-seedance-2-0-fast-260128": { "480p": 5.6, "720p": 5.6 },
27
+ "dreamina-seedance-2-0-mini-260615": { "480p": 3.5, "720p": 3.5 }
28
+ };
29
+ var IMAGE_USD = {
30
+ "dola-seedream-5-0-pro-260628": 0.045,
31
+ "seedream-5-0-260128": 0.035,
32
+ "seedream-4-5-251128": 0.04,
33
+ "seedream-4-0-250828": 0.03,
34
+ "seedream-4-0-20260415": 0.03,
35
+ "seededit-3-0-i2i-250628": 0.03
36
+ };
37
+ var RATIOS = ["16:9", "4:3", "1:1", "3:4", "9:16", "21:9"];
38
+ var BYTEPLUS_MODELS = {
39
+ "seedance-1-0-lite-t2v-250428": {
40
+ family: "1.0",
41
+ textToVideo: true,
42
+ imageToVideo: false,
43
+ lastFrame: false,
44
+ referenceImages: 0,
45
+ referenceMedia: false,
46
+ durations: { min: 2, max: 12 },
47
+ resolutions: ["480p", "720p", "1080p"],
48
+ defaultResolution: "720p"
49
+ },
50
+ "seedance-1-0-lite-i2v-250428": {
51
+ family: "1.0",
52
+ textToVideo: false,
53
+ imageToVideo: true,
54
+ lastFrame: true,
55
+ referenceImages: 4,
56
+ referenceMedia: false,
57
+ durations: { min: 2, max: 12 },
58
+ resolutions: ["480p", "720p", "1080p"],
59
+ defaultResolution: "720p"
60
+ },
61
+ "seedance-1-0-pro-250528": {
62
+ family: "1.0",
63
+ textToVideo: true,
64
+ imageToVideo: true,
65
+ lastFrame: true,
66
+ referenceImages: 0,
67
+ referenceMedia: false,
68
+ durations: { min: 2, max: 12 },
69
+ resolutions: ["480p", "720p", "1080p"],
70
+ defaultResolution: "1080p"
71
+ },
72
+ // Verified in the docs: this one alone drops last-frame support.
73
+ "seedance-1-0-pro-fast-251015": {
74
+ family: "1.0",
75
+ textToVideo: true,
76
+ imageToVideo: true,
77
+ lastFrame: false,
78
+ referenceImages: 0,
79
+ referenceMedia: false,
80
+ durations: { min: 2, max: 12 },
81
+ resolutions: ["480p", "720p", "1080p"],
82
+ defaultResolution: "1080p"
83
+ },
84
+ "seedance-1-5-pro-251215": {
85
+ family: "1.5",
86
+ textToVideo: true,
87
+ imageToVideo: true,
88
+ lastFrame: true,
89
+ referenceImages: 0,
90
+ referenceMedia: false,
91
+ durations: { min: 4, max: 12 },
92
+ resolutions: ["480p", "720p", "1080p"],
93
+ defaultResolution: "720p"
94
+ },
95
+ "dreamina-seedance-2-0-260128": {
96
+ family: "2.x",
97
+ textToVideo: true,
98
+ imageToVideo: true,
99
+ lastFrame: true,
100
+ referenceImages: 9,
101
+ referenceMedia: true,
102
+ durations: { min: 4, max: 15 },
103
+ // The only Seedance model with a 4k tier. It is 10-bit HEVC, so a browser
104
+ // may refuse to play it inline.
105
+ resolutions: ["480p", "720p", "1080p", "4k"],
106
+ defaultResolution: "720p"
107
+ },
108
+ "dreamina-seedance-2-0-fast-260128": {
109
+ family: "2.x",
110
+ textToVideo: true,
111
+ imageToVideo: true,
112
+ lastFrame: true,
113
+ referenceImages: 9,
114
+ referenceMedia: true,
115
+ durations: { min: 4, max: 15 },
116
+ resolutions: ["480p", "720p"],
117
+ defaultResolution: "720p"
118
+ },
119
+ "dreamina-seedance-2-0-mini-260615": {
120
+ family: "2.x",
121
+ textToVideo: true,
122
+ imageToVideo: true,
123
+ lastFrame: true,
124
+ referenceImages: 9,
125
+ referenceMedia: true,
126
+ durations: { min: 4, max: 15 },
127
+ resolutions: ["480p", "720p"],
128
+ defaultResolution: "720p"
129
+ },
130
+ "dreamina-seedance-2-5-260628": {
131
+ family: "2.x",
132
+ textToVideo: true,
133
+ imageToVideo: true,
134
+ lastFrame: true,
135
+ referenceImages: 30,
136
+ referenceMedia: true,
137
+ durations: { min: 4, max: 30 },
138
+ resolutions: ["480p", "720p"],
139
+ defaultResolution: "720p"
140
+ }
141
+ };
142
+ function fieldsFor(family) {
143
+ return {
144
+ seed: family !== "2.x",
145
+ cameraFixed: family !== "2.x",
146
+ generateAudio: family !== "1.0",
147
+ priority: family === "2.x"
148
+ };
149
+ }
150
+ var BYTEPLUS_IMAGE_MODELS = {
151
+ "seedream-3-0-t2i-250415": { sizes: ["1K", "2K"] },
152
+ "seededit-3-0-i2i-250628": { sizes: ["1K", "2K"] },
153
+ "seedream-4-0-250828": { sizes: ["1K", "2K", "4K"] },
154
+ "seedream-4-0-20260415": { sizes: ["1K", "2K", "4K"] },
155
+ "seedream-4-5-251128": { sizes: ["1K", "2K", "4K"] },
156
+ "seedream-5-0-260128": { sizes: ["1K", "2K", "4K"] },
157
+ "dola-seedream-5-0-pro-260628": { sizes: ["1K", "2K", "4K"] }
158
+ };
159
+ var BYTEPLUS_IMAGE_CATALOG = Object.entries(
160
+ BYTEPLUS_IMAGE_MODELS
161
+ ).map(([id, spec]) => ({
162
+ id,
163
+ name: id.replace(/-\d{6,}$/, "").replace(/-/g, " "),
164
+ category: "image",
165
+ inputType: id.includes("i2i") ? "image_required" : "image_optional",
166
+ nodeTypes: ["image_gen"],
167
+ creditsPerUnit: 0,
168
+ creditUnit: "image",
169
+ supportedResolutions: spec.sizes,
170
+ supportedAspectRatios: RATIOS,
171
+ provider: "byteplus",
172
+ pricing: IMAGE_USD[id] ? { unit: "image", usdPerUnit: IMAGE_USD[id] } : void 0
173
+ }));
174
+ var BYTEPLUS_CATALOG = Object.entries(
175
+ BYTEPLUS_MODELS
176
+ ).map(([id, binding]) => ({
177
+ id,
178
+ name: id.replace(/-\d{6,}$/, "").replace(/^dreamina-/, "").replace(/-/g, " "),
179
+ category: "video",
180
+ inputType: binding.textToVideo ? binding.imageToVideo ? "image_optional" : "text_only" : "image_required",
181
+ nodeTypes: ["video_gen"],
182
+ // BytePlus bills your own Ark account per output token.
183
+ creditsPerUnit: 0,
184
+ creditUnit: "second",
185
+ minDuration: binding.durations.min,
186
+ maxDuration: binding.durations.max,
187
+ supportedResolutions: binding.resolutions,
188
+ supportedAspectRatios: RATIOS,
189
+ provider: "byteplus",
190
+ pricing: TOKEN_RATES[id] ? {
191
+ unit: "second",
192
+ byResolution: usdPerSecond(TOKEN_RATES[id]),
193
+ usdPerUnit: usdPerSecond(TOKEN_RATES[id])[binding.defaultResolution] ?? 0
194
+ } : void 0
195
+ }));
196
+
197
+ // src/providers/elevenlabs.models.ts
198
+ var ELEVENLABS_MODELS = {
199
+ eleven_v3: {
200
+ maxCharacters: 5e3,
201
+ languages: 70,
202
+ note: "Most expressive; widest language coverage."
203
+ },
204
+ eleven_multilingual_v2: {
205
+ maxCharacters: 1e4,
206
+ languages: 29,
207
+ note: "Lifelike and consistent across languages. The API default."
208
+ },
209
+ eleven_flash_v2_5: {
210
+ maxCharacters: 4e4,
211
+ languages: 32,
212
+ note: "~75ms latency, for real-time and agent use."
213
+ }
214
+ };
215
+ var ELEVENLABS_OUTPUT_FORMATS = [
216
+ "mp3_22050_32",
217
+ "mp3_44100_32",
218
+ "mp3_44100_64",
219
+ "mp3_44100_96",
220
+ "mp3_44100_128",
221
+ "mp3_44100_192",
222
+ "pcm_16000",
223
+ "pcm_22050",
224
+ "pcm_24000",
225
+ "pcm_44100",
226
+ "ulaw_8000"
227
+ ];
228
+ var ELEVENLABS_CATALOG = Object.entries(
229
+ ELEVENLABS_MODELS
230
+ ).map(([id, binding]) => ({
231
+ id,
232
+ name: id,
233
+ category: "audio",
234
+ inputType: "text_only",
235
+ nodeTypes: ["text"],
236
+ creditsPerUnit: 0,
237
+ creditUnit: "character",
238
+ provider: "elevenlabs",
239
+ // Billed in credits whose dollar value depends on your plan, so no verified
240
+ // per-character rate goes in the catalog.
241
+ description: `${binding.note} Up to ${binding.maxCharacters.toLocaleString()} characters, ${binding.languages} languages.`
242
+ }));
243
+
244
+ // src/providers/google.models.ts
245
+ var GOOGLE_IMAGE_MODELS = {
246
+ // Google's recommended default.
247
+ "gemini-3.1-flash-image": { sizes: ["1K", "2K", "4K"], usdAt1K: 0.067 },
248
+ "gemini-3.1-flash-lite-image": {
249
+ // The only model that takes 512px, and note the lowercase "px" against
250
+ // the uppercase "K" of every other value.
251
+ sizes: ["512px", "1K", "2K"],
252
+ usdAt1K: 0.0336
253
+ },
254
+ "gemini-3-pro-image": { sizes: ["1K", "2K", "4K"], usdAt1K: 0.134 },
255
+ "gemini-2.5-flash-image": { sizes: ["1K", "2K"], usdAt1K: 0.039 }
256
+ };
257
+ var GOOGLE_VIDEO_MODELS = {
258
+ // Every current Veo id carries the -preview suffix; the bare name 404s.
259
+ "veo-3.1-generate-preview": {
260
+ api: "predict",
261
+ usdByResolution: { "720p": 0.4, "1080p": 0.4, "4k": 0.6 },
262
+ resolutions: ["720p", "1080p", "4k"],
263
+ durations: ["4", "6", "8"],
264
+ referenceImages: true,
265
+ usdPerSecond: 0.4
266
+ },
267
+ "veo-3.1-fast-generate-preview": {
268
+ api: "predict",
269
+ usdByResolution: { "720p": 0.1, "1080p": 0.12, "4k": 0.3 },
270
+ resolutions: ["720p", "1080p", "4k"],
271
+ durations: ["4", "6", "8"],
272
+ referenceImages: true,
273
+ usdPerSecond: 0.1
274
+ },
275
+ "veo-3.1-lite-generate-preview": {
276
+ api: "predict",
277
+ usdByResolution: { "720p": 0.05, "1080p": 0.08 },
278
+ resolutions: ["720p", "1080p"],
279
+ durations: ["4", "6", "8"],
280
+ referenceImages: false,
281
+ usdPerSecond: 0.05
282
+ },
283
+ /**
284
+ * Omni: text, image, audio and video in, video out, and results you refine by
285
+ * talking to them. It sits on the Interactions API rather than Veo's predict
286
+ * endpoint, which is why the binding carries `api`.
287
+ *
288
+ * No published rate — the pricing page lists Veo but not this, so the catalog
289
+ * leaves it unset rather than guessing.
290
+ */
291
+ "gemini-omni-flash-preview": {
292
+ api: "interactions",
293
+ resolutions: ["720p"],
294
+ durations: ["10"],
295
+ referenceImages: true,
296
+ conversationalEditing: true
297
+ }
298
+ };
299
+ var GOOGLE_CATALOG = [
300
+ ...Object.entries(GOOGLE_IMAGE_MODELS).map(
301
+ ([id, binding]) => ({
302
+ id,
303
+ name: id,
304
+ category: "image",
305
+ inputType: "image_optional",
306
+ nodeTypes: ["image_gen"],
307
+ creditsPerUnit: 0,
308
+ creditUnit: "image",
309
+ supportedResolutions: binding.sizes,
310
+ provider: "google",
311
+ pricing: { usdPerUnit: binding.usdAt1K, unit: "image" }
312
+ })
313
+ ),
314
+ ...Object.entries(GOOGLE_VIDEO_MODELS).map(
315
+ ([id, binding]) => ({
316
+ id,
317
+ name: id,
318
+ category: "video",
319
+ inputType: "image_optional",
320
+ nodeTypes: ["video_gen"],
321
+ creditsPerUnit: 0,
322
+ creditUnit: "second",
323
+ durationOptions: binding.durations.map(Number),
324
+ minDuration: Number(binding.durations[0]),
325
+ maxDuration: Number(binding.durations[binding.durations.length - 1]),
326
+ supportedResolutions: binding.resolutions,
327
+ supportedAspectRatios: ["16:9", "9:16"],
328
+ provider: "google",
329
+ pricing: binding.usdPerSecond === void 0 ? void 0 : {
330
+ unit: "second",
331
+ usdPerUnit: binding.usdPerSecond,
332
+ byResolution: binding.usdByResolution
333
+ }
334
+ })
335
+ )
336
+ ];
337
+
338
+ // src/providers/kling.models.ts
339
+ var V1_DURATIONS = [5, 10];
340
+ var NEXT_DURATIONS = [3, 4, 5, 6, 7, 8, 10, 12, 15];
341
+ var HD = ["720p", "1080p"];
342
+ var UHD = ["720p", "1080p", "4k"];
343
+ var USD_PER_SECOND = {
344
+ "kling/v1-5": { "720p": 0.056, "1080p": 0.098 },
345
+ "kling/v1-6": { "720p": 0.056, "1080p": 0.098 },
346
+ "kling/v2-master": { "1080p": 0.28 },
347
+ "kling/v2-1": { "720p": 0.056, "1080p": 0.098 },
348
+ "kling/v2-1-master": { "1080p": 0.28 },
349
+ "kling/v2-5-turbo": { "720p": 0.042, "1080p": 0.07 },
350
+ "kling/v2-6": { "720p": 0.042, "1080p": 0.07 },
351
+ "kling/v3": { "720p": 0.084, "1080p": 0.112, "4k": 0.42 },
352
+ "kling/v3-turbo": { "720p": 0.112, "1080p": 0.14 }
353
+ };
354
+ var ASPECT_RATIOS = ["16:9", "9:16", "1:1"];
355
+ var KLING_MODELS = {
356
+ // ---- legacy API ----
357
+ "kling/v1": {
358
+ modelName: "kling-v1",
359
+ api: "v1",
360
+ kind: "video",
361
+ textToVideo: true,
362
+ imageToVideo: true,
363
+ durations: V1_DURATIONS
364
+ },
365
+ "kling/v1-5": {
366
+ modelName: "kling-v1-5",
367
+ api: "v1",
368
+ kind: "video",
369
+ textToVideo: true,
370
+ imageToVideo: true,
371
+ durations: V1_DURATIONS,
372
+ modes: ["pro"]
373
+ },
374
+ "kling/v1-6": {
375
+ modelName: "kling-v1-6",
376
+ api: "v1",
377
+ kind: "video",
378
+ textToVideo: true,
379
+ imageToVideo: true,
380
+ durations: V1_DURATIONS
381
+ },
382
+ "kling/v2-master": {
383
+ modelName: "kling-v2-master",
384
+ api: "v1",
385
+ kind: "video",
386
+ textToVideo: true,
387
+ imageToVideo: true,
388
+ durations: V1_DURATIONS
389
+ },
390
+ // Verified: rejected on text2video, accepted on image2video.
391
+ "kling/v2-1": {
392
+ modelName: "kling-v2-1",
393
+ api: "v1",
394
+ kind: "video",
395
+ imageToVideo: true,
396
+ durations: V1_DURATIONS
397
+ },
398
+ "kling/v2-1-master": {
399
+ modelName: "kling-v2-1-master",
400
+ api: "v1",
401
+ kind: "video",
402
+ textToVideo: true,
403
+ imageToVideo: true,
404
+ durations: V1_DURATIONS
405
+ },
406
+ // ---- path-versioned API ----
407
+ "kling/v2-5-turbo": {
408
+ modelName: "kling-2.5-turbo",
409
+ api: "next",
410
+ kind: "video",
411
+ textToVideo: true,
412
+ imageToVideo: true,
413
+ durations: V1_DURATIONS,
414
+ resolutions: HD
415
+ },
416
+ "kling/v2-6": {
417
+ modelName: "kling-2.6",
418
+ api: "next",
419
+ kind: "video",
420
+ textToVideo: true,
421
+ imageToVideo: true,
422
+ durations: V1_DURATIONS,
423
+ resolutions: HD
424
+ },
425
+ "kling/v3": {
426
+ modelName: "kling-3.0",
427
+ api: "next",
428
+ kind: "video",
429
+ textToVideo: true,
430
+ imageToVideo: true,
431
+ durations: NEXT_DURATIONS,
432
+ resolutions: UHD
433
+ },
434
+ "kling/v3-turbo": {
435
+ modelName: "kling-3.0-turbo",
436
+ api: "next",
437
+ kind: "video",
438
+ textToVideo: true,
439
+ imageToVideo: true,
440
+ durations: NEXT_DURATIONS,
441
+ // 3.0-turbo caps at 1080p, unlike 3.0.
442
+ resolutions: HD,
443
+ lastFrame: false
444
+ },
445
+ // ---- images, legacy API ----
446
+ "kling/image-v1": { modelName: "kling-v1", api: "v1", kind: "image" },
447
+ "kling/image-v1-5": { modelName: "kling-v1-5", api: "v1", kind: "image" },
448
+ "kling/image-v2": { modelName: "kling-v2", api: "v1", kind: "image" },
449
+ "kling/image-v2-new": { modelName: "kling-v2-new", api: "v1", kind: "image" },
450
+ "kling/image-v2-1": { modelName: "kling-v2-1", api: "v1", kind: "image" }
451
+ };
452
+ var KLING_VOICES = [
453
+ "genshin_vindi2",
454
+ "zhinen_xuesheng",
455
+ "ai_shatang",
456
+ "genshin_klee2",
457
+ "genshin_kirara",
458
+ "ai_kaiya",
459
+ "chat1_female_new-3",
460
+ "cartoon-boy-07",
461
+ "cartoon-girl-01",
462
+ "uk_boy1",
463
+ "uk_man2",
464
+ "PeppaPig_platform",
465
+ "ai_huangzhong_712",
466
+ "ai_huangyaoshi_712",
467
+ "ai_laoguowang_712",
468
+ "chengshu_jiejie",
469
+ "you_pingjing",
470
+ "calm_story1",
471
+ "laopopo_speech02",
472
+ "heainainai_speech02"
473
+ ];
474
+ var KLING_AUDIO_MODEL = "kling/tts";
475
+ var KLING_AUDIO_CATALOG = [
476
+ {
477
+ id: KLING_AUDIO_MODEL,
478
+ name: "Kling TTS",
479
+ category: "audio",
480
+ inputType: "text_only",
481
+ nodeTypes: ["text"],
482
+ creditsPerUnit: 0,
483
+ creditUnit: "character",
484
+ provider: "kling",
485
+ description: `Preset voices: ${KLING_VOICES.join(", ")}. Cloned voices from your account work too.`
486
+ }
487
+ ];
488
+ function label(id) {
489
+ const name = KLING_MODELS[id]?.modelName ?? id;
490
+ return `Kling ${name.replace(/^kling-v?/, "")}`;
491
+ }
492
+ var KLING_CATALOG = Object.entries(KLING_MODELS).map(
493
+ ([id, binding]) => {
494
+ if (binding.kind === "image") {
495
+ return {
496
+ id,
497
+ name: `${label(id)} (image)`,
498
+ category: "image",
499
+ inputType: "text_only",
500
+ nodeTypes: ["image_gen"],
501
+ // Kling bills its own account, so there is nothing for us to price.
502
+ creditsPerUnit: 0,
503
+ creditUnit: "image",
504
+ supportedAspectRatios: ASPECT_RATIOS,
505
+ provider: "kling"
506
+ };
507
+ }
508
+ const durations = binding.durations ?? V1_DURATIONS;
509
+ return {
510
+ id,
511
+ name: label(id),
512
+ category: "video",
513
+ inputType: binding.textToVideo ? binding.imageToVideo ? "image_optional" : "text_only" : "image_required",
514
+ nodeTypes: ["video_gen"],
515
+ creditsPerUnit: 0,
516
+ creditUnit: "second",
517
+ minDuration: durations[0],
518
+ maxDuration: durations[durations.length - 1],
519
+ durationOptions: durations,
520
+ supportedResolutions: binding.resolutions,
521
+ supportedAspectRatios: ASPECT_RATIOS,
522
+ provider: "kling",
523
+ pricing: USD_PER_SECOND[id] ? {
524
+ unit: "second",
525
+ byResolution: USD_PER_SECOND[id],
526
+ usdPerUnit: USD_PER_SECOND[id]["720p"] ?? USD_PER_SECOND[id]["1080p"] ?? 0
527
+ } : void 0
528
+ };
529
+ }
530
+ );
531
+ function optionsBlock(options) {
532
+ if (!options) return void 0;
533
+ const block = {};
534
+ if (options.callbackUrl) block.callback_url = options.callbackUrl;
535
+ if (options.externalTaskId) block.external_task_id = options.externalTaskId;
536
+ if (options.watermark !== void 0) {
537
+ block.watermark_info = { enabled: options.watermark };
538
+ }
539
+ return Object.keys(block).length > 0 ? block : void 0;
540
+ }
541
+ var motionControl = {
542
+ api: "next",
543
+ kind: "video",
544
+ results: "outputs",
545
+ path: (input) => `/motion-control/${input.model ?? "kling-2.6"}`,
546
+ body: (input) => {
547
+ const contents = [];
548
+ if (input.prompt) contents.push({ type: "prompt", text: input.prompt });
549
+ contents.push({ type: "image", url: input.imageUrl });
550
+ contents.push({ type: "video", url: input.videoUrl });
551
+ const settings = {
552
+ character_orientation: input.characterOrientation
553
+ };
554
+ if (input.resolution) settings.resolution = input.resolution;
555
+ if (input.audio) settings.audio = input.audio;
556
+ const options = optionsBlock(input.options);
557
+ return options ? { contents, settings, options } : { contents, settings };
558
+ }
559
+ };
560
+ var omniVideo = {
561
+ api: "next",
562
+ kind: "video",
563
+ results: "outputs",
564
+ path: (input) => `/omni-video/${input.model ?? "kling-3.0-omni"}`,
565
+ body: (input) => {
566
+ const contents = [
567
+ { type: "prompt", text: input.prompt }
568
+ ];
569
+ for (const reference of input.references ?? []) {
570
+ contents.push({
571
+ type: reference.type,
572
+ url: reference.url,
573
+ ...reference.id ? { id: reference.id } : {}
574
+ });
575
+ }
576
+ for (const element of input.elements ?? []) {
577
+ contents.push({
578
+ type: "element",
579
+ element_id: element.elementId,
580
+ id: element.id
581
+ });
582
+ }
583
+ const settings = {};
584
+ if (input.resolution) settings.resolution = input.resolution;
585
+ if (input.duration) settings.duration = input.duration;
586
+ if (input.audio) settings.audio = input.audio;
587
+ if (input.aspectRatio) settings.aspect_ratio = input.aspectRatio;
588
+ if (input.multiShot !== void 0) settings.multi_shot = input.multiShot;
589
+ const options = optionsBlock(input.options);
590
+ return {
591
+ contents,
592
+ ...Object.keys(settings).length > 0 ? { settings } : {},
593
+ ...options ? { options } : {}
594
+ };
595
+ }
596
+ };
597
+ var avatar = {
598
+ api: "v1",
599
+ kind: "video",
600
+ results: "videos",
601
+ path: () => "/v1/videos/avatar/image2video",
602
+ body: (input) => {
603
+ if (Boolean(input.audioId) === Boolean(input.soundFileUrl)) {
604
+ throw new Error(
605
+ "Avatar needs exactly one of audioId or soundFileUrl, not both and not neither."
606
+ );
607
+ }
608
+ const body = { image: input.imageUrl };
609
+ if (input.audioId) body.audio_id = input.audioId;
610
+ if (input.soundFileUrl) body.sound_file = input.soundFileUrl;
611
+ if (input.prompt) body.prompt = input.prompt;
612
+ if (input.mode) body.mode = input.mode;
613
+ if (input.options?.callbackUrl)
614
+ body.callback_url = input.options.callbackUrl;
615
+ if (input.options?.externalTaskId) {
616
+ body.external_task_id = input.options.externalTaskId;
617
+ }
618
+ if (input.options?.watermark !== void 0) {
619
+ body.watermark_info = { enabled: input.options.watermark };
620
+ }
621
+ return body;
622
+ }
623
+ };
624
+ var outpainting = {
625
+ api: "v1",
626
+ kind: "image",
627
+ results: "images",
628
+ path: () => "/v1/images/editing/expand",
629
+ body: (input) => {
630
+ for (const [name, value] of [
631
+ ["up", input.up],
632
+ ["down", input.down],
633
+ ["left", input.left],
634
+ ["right", input.right]
635
+ ]) {
636
+ if (value < 0 || value > 2) {
637
+ throw new Error(
638
+ `Outpainting ${name} must be between 0 and 2, got ${value}.`
639
+ );
640
+ }
641
+ }
642
+ const body = {
643
+ image: input.imageUrl,
644
+ up_expansion_ratio: input.up,
645
+ down_expansion_ratio: input.down,
646
+ left_expansion_ratio: input.left,
647
+ right_expansion_ratio: input.right
648
+ };
649
+ if (input.prompt) body.prompt = input.prompt;
650
+ if (input.n) body.n = input.n;
651
+ if (input.options?.watermark !== void 0) {
652
+ body.watermark_info = { enabled: input.options.watermark };
653
+ }
654
+ return body;
655
+ }
656
+ };
657
+ var imageOmni = {
658
+ api: "v1",
659
+ kind: "image",
660
+ results: "images",
661
+ path: () => "/v1/images/omni-image",
662
+ body: (input) => {
663
+ const images = input.imageUrls ?? [];
664
+ const elements = input.elementIds ?? [];
665
+ if (images.length + elements.length > 10) {
666
+ throw new Error(
667
+ `Image-omni takes at most 10 references in total, got ${images.length + elements.length}.`
668
+ );
669
+ }
670
+ const body = {
671
+ model_name: input.model ?? "kling-image-o1",
672
+ prompt: input.prompt
673
+ };
674
+ if (images.length > 0) {
675
+ body.image_list = images.map((image) => ({ image }));
676
+ }
677
+ if (elements.length > 0) {
678
+ body.element_list = elements.map((id) => ({ element_id: id }));
679
+ }
680
+ if (input.resolution) body.resolution = input.resolution;
681
+ if (input.resultType) body.result_type = input.resultType;
682
+ if (input.seriesAmount) body.series_amount = input.seriesAmount;
683
+ if (input.n) body.n = input.n;
684
+ if (input.aspectRatio) body.aspect_ratio = input.aspectRatio;
685
+ if (input.options?.watermark !== void 0) {
686
+ body.watermark_info = { enabled: input.options.watermark };
687
+ }
688
+ return body;
689
+ }
690
+ };
691
+ var KLING_CAPABILITIES = {
692
+ motionControl,
693
+ omniVideo,
694
+ avatar,
695
+ outpainting,
696
+ imageOmni
697
+ };
698
+
699
+ // src/providers/openai.models.ts
700
+ var CLASSIC_SIZES = ["1024x1024", "1024x1536", "1536x1024", "auto"];
701
+ var OPENAI_IMAGE_MODELS = {
702
+ "gpt-image-2": {
703
+ // Arbitrary WxH: max edge 3840, both edges divisible by 16, ratio up to 3:1.
704
+ sizes: "any",
705
+ qualities: ["low", "medium", "high"],
706
+ // A real capability regression against the older model.
707
+ transparentBackground: false,
708
+ usd: { low: 6e-3, medium: 0.053, high: 0.211 }
709
+ },
710
+ "gpt-image-1.5": {
711
+ sizes: CLASSIC_SIZES,
712
+ qualities: ["low", "medium", "high"],
713
+ transparentBackground: true,
714
+ shutdownOn: "2026-12-01",
715
+ usd: { low: 9e-3, medium: 0.04, high: 0.2 }
716
+ },
717
+ "gpt-image-1": {
718
+ sizes: CLASSIC_SIZES,
719
+ qualities: ["low", "medium", "high"],
720
+ // The only one left that can do transparency.
721
+ transparentBackground: true,
722
+ usd: { low: 0.011, medium: 0.042, high: 0.167 }
723
+ }
724
+ };
725
+ var OPENAI_CATALOG = Object.entries(
726
+ OPENAI_IMAGE_MODELS
727
+ ).map(([id, binding]) => ({
728
+ id,
729
+ name: id,
730
+ category: "image",
731
+ inputType: "image_optional",
732
+ nodeTypes: ["image_gen"],
733
+ creditsPerUnit: 0,
734
+ creditUnit: "image",
735
+ supportedResolutions: binding.sizes === "any" ? void 0 : binding.sizes,
736
+ provider: "openai",
737
+ // Medium is the sane middle; `quality: auto` can silently pick high, which
738
+ // is 35x the low tier.
739
+ pricing: { usdPerUnit: binding.usd.medium, unit: "image" },
740
+ description: binding.shutdownOn ? `Deprecated \u2014 OpenAI shuts this down on ${binding.shutdownOn}.` : void 0
741
+ }));
742
+
743
+ // src/providers/qwen.models.ts
744
+ var VIDEO_PATH = "/api/v1/services/aigc/video-generation/video-synthesis";
745
+ var KF2V_PATH = "/api/v1/services/aigc/image2video/video-synthesis";
746
+ var HD2 = ["480P", "720P", "1080P"];
747
+ var QWEN_VIDEO_MODELS = {
748
+ // --- wan 2.7: media objects, resolution + ratio ---
749
+ "wan2.7-t2v": {
750
+ mode: "t2v",
751
+ shape: "media",
752
+ sizing: "resolution",
753
+ durations: { min: 2, max: 15 },
754
+ resolutions: ["720P", "1080P"]
755
+ },
756
+ "wan2.7-i2v": {
757
+ mode: "i2v",
758
+ shape: "media",
759
+ sizing: "resolution",
760
+ durations: { min: 2, max: 15 },
761
+ resolutions: ["720P", "1080P"]
762
+ },
763
+ // --- wan 2.6: img_url string, size ---
764
+ "wan2.6-t2v": {
765
+ mode: "t2v",
766
+ shape: "media",
767
+ sizing: "size",
768
+ durations: { min: 2, max: 15 },
769
+ watermarkOnByDefault: true
770
+ },
771
+ "wan2.6-i2v": {
772
+ mode: "i2v",
773
+ shape: "img_url",
774
+ sizing: "resolution",
775
+ durations: { min: 2, max: 15 },
776
+ resolutions: ["720P", "1080P"]
777
+ },
778
+ "wan2.6-i2v-flash": {
779
+ mode: "i2v",
780
+ shape: "img_url",
781
+ sizing: "resolution",
782
+ durations: { min: 2, max: 15 },
783
+ resolutions: ["720P", "1080P"]
784
+ },
785
+ "wan2.6-r2v": {
786
+ mode: "r2v",
787
+ shape: "reference_urls",
788
+ sizing: "size",
789
+ durations: { min: 2, max: 10 }
790
+ },
791
+ // --- keyframe: different path, fixed duration, its own fields ---
792
+ "wan2.2-kf2v-flash": {
793
+ mode: "kf2v",
794
+ shape: "kf2v",
795
+ sizing: "resolution",
796
+ path: KF2V_PATH,
797
+ durations: [5],
798
+ resolutions: HD2
799
+ },
800
+ // --- happyhorse: media objects, minimum duration 3, watermark on ---
801
+ "happyhorse-1.1-t2v": {
802
+ mode: "t2v",
803
+ shape: "media",
804
+ sizing: "resolution",
805
+ durations: { min: 3, max: 15 },
806
+ resolutions: HD2,
807
+ watermarkOnByDefault: true
808
+ },
809
+ "happyhorse-1.1-i2v": {
810
+ mode: "i2v",
811
+ shape: "media",
812
+ sizing: "resolution",
813
+ durations: { min: 3, max: 15 },
814
+ resolutions: HD2,
815
+ watermarkOnByDefault: true
816
+ },
817
+ "happyhorse-1.1-r2v": {
818
+ mode: "r2v",
819
+ shape: "media",
820
+ sizing: "resolution",
821
+ durations: { min: 3, max: 15 },
822
+ resolutions: HD2,
823
+ watermarkOnByDefault: true
824
+ },
825
+ "happyhorse-1.0-t2v": {
826
+ mode: "t2v",
827
+ shape: "media",
828
+ sizing: "resolution",
829
+ durations: { min: 3, max: 15 },
830
+ resolutions: HD2,
831
+ watermarkOnByDefault: true
832
+ },
833
+ "happyhorse-1.0-i2v": {
834
+ mode: "i2v",
835
+ shape: "media",
836
+ sizing: "resolution",
837
+ durations: { min: 3, max: 15 },
838
+ resolutions: HD2,
839
+ watermarkOnByDefault: true
840
+ },
841
+ "happyhorse-1.0-r2v": {
842
+ mode: "r2v",
843
+ shape: "media",
844
+ sizing: "resolution",
845
+ durations: { min: 3, max: 15 },
846
+ resolutions: HD2,
847
+ watermarkOnByDefault: true
848
+ },
849
+ "happyhorse-1.0-video-edit": {
850
+ mode: "video-edit",
851
+ shape: "media",
852
+ sizing: "resolution",
853
+ resolutions: ["720P", "1080P"],
854
+ watermarkOnByDefault: true
855
+ }
856
+ };
857
+ function videoPathFor(binding) {
858
+ return binding.path ?? VIDEO_PATH;
859
+ }
860
+ var QWEN_IMAGE_PATHS = {
861
+ multimodal: "/api/v1/services/aigc/multimodal-generation/generation",
862
+ "image-generation": "/api/v1/services/aigc/image-generation/generation",
863
+ text2image: "/api/v1/services/aigc/text2image/image-synthesis"
864
+ };
865
+ var QWEN_IMAGE_MODELS = {
866
+ // Sync and async both available; async uses the newer image-generation path.
867
+ "qwen-image-3.0-pro": {
868
+ sync: true,
869
+ path: "multimodal",
870
+ body: "messages",
871
+ maxN: 6
872
+ },
873
+ "qwen-image-3.0": {
874
+ sync: true,
875
+ path: "multimodal",
876
+ body: "messages",
877
+ maxN: 6
878
+ },
879
+ // Sync only — the async header would 429 these.
880
+ "qwen-image-2.0-pro": {
881
+ sync: true,
882
+ path: "multimodal",
883
+ body: "messages",
884
+ maxN: 6
885
+ },
886
+ "qwen-image-2.0": {
887
+ sync: true,
888
+ path: "multimodal",
889
+ body: "messages",
890
+ maxN: 6
891
+ },
892
+ "qwen-image-max": {
893
+ sync: true,
894
+ path: "multimodal",
895
+ body: "messages",
896
+ maxN: 1
897
+ },
898
+ "z-image-turbo": {
899
+ sync: true,
900
+ path: "multimodal",
901
+ body: "messages",
902
+ maxN: 1
903
+ },
904
+ "wan2.7-image-pro": {
905
+ sync: true,
906
+ path: "multimodal",
907
+ body: "messages",
908
+ maxN: 4,
909
+ resolutions: ["1K", "2K", "4K"]
910
+ },
911
+ "wan2.7-image": {
912
+ sync: true,
913
+ path: "multimodal",
914
+ body: "messages",
915
+ maxN: 4,
916
+ resolutions: ["1K", "2K"]
917
+ },
918
+ "wan2.6-image": {
919
+ sync: true,
920
+ path: "multimodal",
921
+ body: "messages",
922
+ maxN: 4
923
+ },
924
+ "wan2.6-t2i": { sync: true, path: "multimodal", body: "messages", maxN: 4 }
925
+ };
926
+ var VIDEO_USD_PER_SECOND = {
927
+ "happyhorse-1.1-t2v": { "480P": 0.07, "720P": 0.14, "1080P": 0.18 },
928
+ "happyhorse-1.1-i2v": { "480P": 0.07, "720P": 0.14, "1080P": 0.18 },
929
+ "happyhorse-1.1-r2v": { "480P": 0.07, "720P": 0.14, "1080P": 0.18 },
930
+ "happyhorse-1.0-video-edit": { "720P": 0.14, "1080P": 0.24 }
931
+ };
932
+ var IMAGE_USD2 = {
933
+ "qwen-image-3.0-pro": 0.04,
934
+ "qwen-image-3.0": 0.03,
935
+ "qwen-image-2.0-pro": 0.075,
936
+ "qwen-image-2.0": 0.035,
937
+ "wan2.7-image-pro": 0.075
938
+ };
939
+ var QWEN_VOICES = [
940
+ "Cherry",
941
+ "Ethan",
942
+ "Jennifer",
943
+ "Ryan",
944
+ "Dylan",
945
+ "Sunny",
946
+ "Nofish"
947
+ ];
948
+ var QWEN_AUDIO_MODELS = {
949
+ "qwen3-tts-flash": { voices: QWEN_VOICES, usdPerCharacter: 15e-6 },
950
+ "qwen3-tts-instruct-flash": {
951
+ voices: QWEN_VOICES,
952
+ usdPerCharacter: 15e-6
953
+ },
954
+ "qwen-audio-3.0-tts-flash": {
955
+ voices: QWEN_VOICES,
956
+ usdPerCharacter: 15e-6
957
+ },
958
+ "qwen-audio-3.0-tts-plus": { voices: QWEN_VOICES, usdPerCharacter: 3e-5 },
959
+ "cosyvoice-v3-flash": { voices: QWEN_VOICES, usdPerCharacter: 15e-6 }
960
+ };
961
+ var QWEN_TEXT_MODELS = {
962
+ "qwen3.8-max": { usdPerMillionOutput: 6 },
963
+ "qwen3.7-plus": { usdPerMillionOutput: 1.6 },
964
+ "qwen3.7-flash": { usdPerMillionOutput: 0.13 },
965
+ "qwen-max": { usdPerMillionOutput: 7.5 },
966
+ "qwen-plus": { usdPerMillionOutput: 3 },
967
+ "qwen-turbo": { usdPerMillionOutput: 0.4 }
968
+ };
969
+ function inputTypeFor(mode) {
970
+ if (mode === "t2v") return "text_only";
971
+ if (mode === "video-edit") return "video_required";
972
+ return "image_required";
973
+ }
974
+ function durationsOf(binding) {
975
+ if (Array.isArray(binding.durations)) {
976
+ return {
977
+ options: binding.durations,
978
+ min: binding.durations[0],
979
+ max: binding.durations[binding.durations.length - 1]
980
+ };
981
+ }
982
+ return {
983
+ options: void 0,
984
+ min: binding.durations?.min,
985
+ max: binding.durations?.max
986
+ };
987
+ }
988
+ var QWEN_CATALOG = [
989
+ ...Object.entries(QWEN_AUDIO_MODELS).map(
990
+ ([id, binding]) => ({
991
+ id,
992
+ name: id,
993
+ category: "audio",
994
+ inputType: "text_only",
995
+ nodeTypes: ["text"],
996
+ creditsPerUnit: 0,
997
+ creditUnit: "character",
998
+ provider: "qwen",
999
+ pricing: { unit: "character", usdPerUnit: binding.usdPerCharacter },
1000
+ description: `Voices: ${binding.voices.join(", ")}`
1001
+ })
1002
+ ),
1003
+ ...Object.entries(QWEN_TEXT_MODELS).map(
1004
+ ([id, binding]) => ({
1005
+ id,
1006
+ name: id,
1007
+ category: "text",
1008
+ inputType: "text_only",
1009
+ nodeTypes: ["text"],
1010
+ creditsPerUnit: 0,
1011
+ creditUnit: "token",
1012
+ provider: "qwen",
1013
+ pricing: {
1014
+ unit: "token",
1015
+ usdPerUnit: binding.usdPerMillionOutput / 1e6
1016
+ }
1017
+ })
1018
+ ),
1019
+ ...Object.entries(QWEN_VIDEO_MODELS).map(([id, binding]) => {
1020
+ const duration = durationsOf(binding);
1021
+ return {
1022
+ id,
1023
+ name: id,
1024
+ category: "video",
1025
+ inputType: inputTypeFor(binding.mode),
1026
+ nodeTypes: ["video_gen"],
1027
+ // Qwen bills your own DashScope account.
1028
+ creditsPerUnit: 0,
1029
+ creditUnit: "second",
1030
+ durationOptions: duration.options,
1031
+ minDuration: duration.min,
1032
+ maxDuration: duration.max,
1033
+ supportedResolutions: binding.resolutions,
1034
+ provider: "qwen",
1035
+ pricing: VIDEO_USD_PER_SECOND[id] ? {
1036
+ unit: "second",
1037
+ byResolution: VIDEO_USD_PER_SECOND[id],
1038
+ usdPerUnit: VIDEO_USD_PER_SECOND[id]["720P"] ?? 0
1039
+ } : void 0
1040
+ };
1041
+ }),
1042
+ ...Object.entries(QWEN_IMAGE_MODELS).map(
1043
+ ([id, binding]) => ({
1044
+ id,
1045
+ name: id,
1046
+ category: "image",
1047
+ inputType: "image_optional",
1048
+ nodeTypes: ["image_gen"],
1049
+ creditsPerUnit: 0,
1050
+ creditUnit: "image",
1051
+ supportedResolutions: binding.resolutions,
1052
+ provider: "qwen",
1053
+ pricing: IMAGE_USD2[id] ? { unit: "image", usdPerUnit: IMAGE_USD2[id] } : void 0
1054
+ })
1055
+ )
1056
+ ];
1057
+
1058
+ // src/catalog.ts
1059
+ var PROVIDER_BASE_URLS = {
1060
+ byteplus: "https://ark.ap-southeast.bytepluses.com",
1061
+ kling: "https://api-singapore.klingai.com",
1062
+ elevenlabs: "https://api.elevenlabs.io",
1063
+ google: "https://generativelanguage.googleapis.com",
1064
+ openai: "https://api.openai.com",
1065
+ qwen: "https://dashscope-intl.aliyuncs.com"
1066
+ };
1067
+ var BUILT_IN = [
1068
+ ...KLING_CATALOG,
1069
+ ...KLING_AUDIO_CATALOG,
1070
+ ...BYTEPLUS_CATALOG,
1071
+ ...BYTEPLUS_IMAGE_CATALOG,
1072
+ ...QWEN_CATALOG,
1073
+ ...OPENAI_CATALOG,
1074
+ ...GOOGLE_CATALOG,
1075
+ ...ELEVENLABS_CATALOG
1076
+ ];
1077
+ var catalog = BUILT_IN;
1078
+ var catalogMap = byId(BUILT_IN);
1079
+ function byId(models) {
1080
+ return Object.fromEntries(models.map((model) => [model.id, model]));
1081
+ }
1082
+ function registerModels(models = []) {
1083
+ if (models.length === 0) return;
1084
+ const merged = { ...catalogMap };
1085
+ for (const model of models) {
1086
+ merged[model.id] = { ...merged[model.id], ...model };
1087
+ }
1088
+ catalogMap = merged;
1089
+ catalog = Object.values(merged);
1090
+ }
1091
+ function resetCatalog() {
1092
+ catalog = BUILT_IN;
1093
+ catalogMap = byId(BUILT_IN);
1094
+ }
1095
+ function getModel(modelId) {
1096
+ return catalogMap[modelId];
1097
+ }
1098
+ function getModels() {
1099
+ return catalog;
1100
+ }
1101
+ function hasModel(modelId) {
1102
+ return modelId in catalogMap;
1103
+ }
1104
+ function getProviders() {
1105
+ return [
1106
+ ...new Set(
1107
+ catalog.map((model) => model.provider).filter((provider) => Boolean(provider))
1108
+ )
1109
+ ].sort();
1110
+ }
1111
+ function resolveProvider(modelId, options) {
1112
+ const model = getModel(modelId);
1113
+ if (!model) {
1114
+ throw new Error(`Unknown model "${modelId}".`);
1115
+ }
1116
+ const id = model.provider;
1117
+ if (!id) {
1118
+ throw new Error(
1119
+ `Model "${modelId}" declares no provider, so nothing knows how to run it.`
1120
+ );
1121
+ }
1122
+ const configured = options.providers[id];
1123
+ if (!configured) {
1124
+ const owned = Object.keys(options.providers).join(", ") || "none";
1125
+ throw new Error(
1126
+ `Model "${modelId}" runs on "${id}", but no API key was given for it (configured: ${owned}).`
1127
+ );
1128
+ }
1129
+ const baseUrl = configured.baseUrl ?? PROVIDER_BASE_URLS[id];
1130
+ if (!baseUrl) {
1131
+ throw new Error(
1132
+ `Provider "${id}" has no known base URL \u2014 pass providers.${id}.baseUrl.`
1133
+ );
1134
+ }
1135
+ return { id, apiKey: configured.apiKey, baseUrl: baseUrl.replace(/\/$/, "") };
1136
+ }
1137
+ function getAvailableModels(options) {
1138
+ return catalog.filter(
1139
+ (model) => model.provider && model.provider in options.providers
1140
+ );
1141
+ }
1142
+
1143
+ export {
1144
+ BYTEPLUS_MODELS,
1145
+ fieldsFor,
1146
+ BYTEPLUS_IMAGE_MODELS,
1147
+ BYTEPLUS_CATALOG,
1148
+ ELEVENLABS_MODELS,
1149
+ ELEVENLABS_OUTPUT_FORMATS,
1150
+ ELEVENLABS_CATALOG,
1151
+ GOOGLE_IMAGE_MODELS,
1152
+ GOOGLE_VIDEO_MODELS,
1153
+ GOOGLE_CATALOG,
1154
+ KLING_MODELS,
1155
+ KLING_VOICES,
1156
+ KLING_AUDIO_MODEL,
1157
+ KLING_CATALOG,
1158
+ KLING_CAPABILITIES,
1159
+ OPENAI_IMAGE_MODELS,
1160
+ OPENAI_CATALOG,
1161
+ QWEN_VIDEO_MODELS,
1162
+ videoPathFor,
1163
+ QWEN_IMAGE_PATHS,
1164
+ QWEN_IMAGE_MODELS,
1165
+ QWEN_AUDIO_MODELS,
1166
+ QWEN_TEXT_MODELS,
1167
+ QWEN_CATALOG,
1168
+ registerModels,
1169
+ resetCatalog,
1170
+ getModel,
1171
+ getModels,
1172
+ hasModel,
1173
+ getProviders,
1174
+ resolveProvider,
1175
+ getAvailableModels
1176
+ };