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