@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
package/CATALOG.md ADDED
@@ -0,0 +1,387 @@
1
+ <!-- Generated by scripts/generate-catalog-doc.ts. Do not edit by hand. -->
2
+ # Supported catalog
3
+
4
+ 81 models: 37 video, 29 image, 6 text.
5
+
6
+ Every model is served by its vendor's own API — no aggregator sits in between, so
7
+ the key you configure is the account that runs the work and bills it.
8
+
9
+ Providers: byteplus, elevenlabs, google, kling, openai, qwen.
10
+
11
+ Every model here is reachable through one `ai.image`/`ai.video` call with the same
12
+ params. What differs between them is only what this table records: durations,
13
+ resolutions, aspect ratios and capabilities.
14
+
15
+ ## Video (37)
16
+
17
+ ### dreamina-seedance-2-0-260128
18
+
19
+ | id | duration | resolutions | aspect | capabilities | served by |
20
+ |---|---|---|---|---|---|
21
+ | `dreamina-seedance-2-0-260128` | 4–15s | 480p, 720p, 1080p, 4k | 16:9, 4:3, 1:1, 3:4, 9:16, 21:9 | — | byteplus |
22
+
23
+ ### dreamina-seedance-2-0-fast-260128
24
+
25
+ | id | duration | resolutions | aspect | capabilities | served by |
26
+ |---|---|---|---|---|---|
27
+ | `dreamina-seedance-2-0-fast-260128` | 4–15s | 480p, 720p | 16:9, 4:3, 1:1, 3:4, 9:16, 21:9 | — | byteplus |
28
+
29
+ ### dreamina-seedance-2-0-mini-260615
30
+
31
+ | id | duration | resolutions | aspect | capabilities | served by |
32
+ |---|---|---|---|---|---|
33
+ | `dreamina-seedance-2-0-mini-260615` | 4–15s | 480p, 720p | 16:9, 4:3, 1:1, 3:4, 9:16, 21:9 | — | byteplus |
34
+
35
+ ### dreamina-seedance-2-5-260628
36
+
37
+ | id | duration | resolutions | aspect | capabilities | served by |
38
+ |---|---|---|---|---|---|
39
+ | `dreamina-seedance-2-5-260628` | 4–30s | 480p, 720p | 16:9, 4:3, 1:1, 3:4, 9:16, 21:9 | — | byteplus |
40
+
41
+ ### gemini-omni-flash-preview
42
+
43
+ | id | duration | resolutions | aspect | capabilities | served by |
44
+ |---|---|---|---|---|---|
45
+ | `gemini-omni-flash-preview` | 10s | 720p | 16:9, 9:16 | — | google |
46
+
47
+ ### happyhorse-1.0-i2v
48
+
49
+ | id | duration | resolutions | aspect | capabilities | served by |
50
+ |---|---|---|---|---|---|
51
+ | `happyhorse-1.0-i2v` | 3–15s | 480P, 720P, 1080P | — | — | qwen |
52
+
53
+ ### happyhorse-1.0-r2v
54
+
55
+ | id | duration | resolutions | aspect | capabilities | served by |
56
+ |---|---|---|---|---|---|
57
+ | `happyhorse-1.0-r2v` | 3–15s | 480P, 720P, 1080P | — | — | qwen |
58
+
59
+ ### happyhorse-1.0-t2v
60
+
61
+ | id | duration | resolutions | aspect | capabilities | served by |
62
+ |---|---|---|---|---|---|
63
+ | `happyhorse-1.0-t2v` | 3–15s | 480P, 720P, 1080P | — | — | qwen |
64
+
65
+ ### happyhorse-1.0-video-edit
66
+
67
+ | id | duration | resolutions | aspect | capabilities | served by |
68
+ |---|---|---|---|---|---|
69
+ | `happyhorse-1.0-video-edit` | — | 720P, 1080P | — | — | qwen |
70
+
71
+ ### happyhorse-1.1-i2v
72
+
73
+ | id | duration | resolutions | aspect | capabilities | served by |
74
+ |---|---|---|---|---|---|
75
+ | `happyhorse-1.1-i2v` | 3–15s | 480P, 720P, 1080P | — | — | qwen |
76
+
77
+ ### happyhorse-1.1-r2v
78
+
79
+ | id | duration | resolutions | aspect | capabilities | served by |
80
+ |---|---|---|---|---|---|
81
+ | `happyhorse-1.1-r2v` | 3–15s | 480P, 720P, 1080P | — | — | qwen |
82
+
83
+ ### happyhorse-1.1-t2v
84
+
85
+ | id | duration | resolutions | aspect | capabilities | served by |
86
+ |---|---|---|---|---|---|
87
+ | `happyhorse-1.1-t2v` | 3–15s | 480P, 720P, 1080P | — | — | qwen |
88
+
89
+ ### kling
90
+
91
+ | id | duration | resolutions | aspect | capabilities | served by |
92
+ |---|---|---|---|---|---|
93
+ | `kling/v1` | 5, 10s | — | 16:9, 9:16, 1:1 | — | kling |
94
+ | `kling/v1-5` | 5, 10s | — | 16:9, 9:16, 1:1 | — | kling |
95
+ | `kling/v1-6` | 5, 10s | — | 16:9, 9:16, 1:1 | — | kling |
96
+ | `kling/v2-1` | 5, 10s | — | 16:9, 9:16, 1:1 | — | kling |
97
+ | `kling/v2-1-master` | 5, 10s | — | 16:9, 9:16, 1:1 | — | kling |
98
+ | `kling/v2-5-turbo` | 5, 10s | 720p, 1080p | 16:9, 9:16, 1:1 | — | kling |
99
+ | `kling/v2-6` | 5, 10s | 720p, 1080p | 16:9, 9:16, 1:1 | — | kling |
100
+ | `kling/v2-master` | 5, 10s | — | 16:9, 9:16, 1:1 | — | kling |
101
+ | `kling/v3` | 3, 4, 5, 6, 7, 8, 10, 12, 15s | 720p, 1080p, 4k | 16:9, 9:16, 1:1 | — | kling |
102
+ | `kling/v3-turbo` | 3, 4, 5, 6, 7, 8, 10, 12, 15s | 720p, 1080p | 16:9, 9:16, 1:1 | — | kling |
103
+
104
+ ### seedance-1-0-lite-i2v-250428
105
+
106
+ | id | duration | resolutions | aspect | capabilities | served by |
107
+ |---|---|---|---|---|---|
108
+ | `seedance-1-0-lite-i2v-250428` | 2–12s | 480p, 720p, 1080p | 16:9, 4:3, 1:1, 3:4, 9:16, 21:9 | — | byteplus |
109
+
110
+ ### seedance-1-0-lite-t2v-250428
111
+
112
+ | id | duration | resolutions | aspect | capabilities | served by |
113
+ |---|---|---|---|---|---|
114
+ | `seedance-1-0-lite-t2v-250428` | 2–12s | 480p, 720p, 1080p | 16:9, 4:3, 1:1, 3:4, 9:16, 21:9 | — | byteplus |
115
+
116
+ ### seedance-1-0-pro-250528
117
+
118
+ | id | duration | resolutions | aspect | capabilities | served by |
119
+ |---|---|---|---|---|---|
120
+ | `seedance-1-0-pro-250528` | 2–12s | 480p, 720p, 1080p | 16:9, 4:3, 1:1, 3:4, 9:16, 21:9 | — | byteplus |
121
+
122
+ ### seedance-1-0-pro-fast-251015
123
+
124
+ | id | duration | resolutions | aspect | capabilities | served by |
125
+ |---|---|---|---|---|---|
126
+ | `seedance-1-0-pro-fast-251015` | 2–12s | 480p, 720p, 1080p | 16:9, 4:3, 1:1, 3:4, 9:16, 21:9 | — | byteplus |
127
+
128
+ ### seedance-1-5-pro-251215
129
+
130
+ | id | duration | resolutions | aspect | capabilities | served by |
131
+ |---|---|---|---|---|---|
132
+ | `seedance-1-5-pro-251215` | 4–12s | 480p, 720p, 1080p | 16:9, 4:3, 1:1, 3:4, 9:16, 21:9 | — | byteplus |
133
+
134
+ ### veo-3.1-fast-generate-preview
135
+
136
+ | id | duration | resolutions | aspect | capabilities | served by |
137
+ |---|---|---|---|---|---|
138
+ | `veo-3.1-fast-generate-preview` | 4, 6, 8s | 720p, 1080p, 4k | 16:9, 9:16 | — | google |
139
+
140
+ ### veo-3.1-generate-preview
141
+
142
+ | id | duration | resolutions | aspect | capabilities | served by |
143
+ |---|---|---|---|---|---|
144
+ | `veo-3.1-generate-preview` | 4, 6, 8s | 720p, 1080p, 4k | 16:9, 9:16 | — | google |
145
+
146
+ ### veo-3.1-lite-generate-preview
147
+
148
+ | id | duration | resolutions | aspect | capabilities | served by |
149
+ |---|---|---|---|---|---|
150
+ | `veo-3.1-lite-generate-preview` | 4, 6, 8s | 720p, 1080p | 16:9, 9:16 | — | google |
151
+
152
+ ### wan2.2-kf2v-flash
153
+
154
+ | id | duration | resolutions | aspect | capabilities | served by |
155
+ |---|---|---|---|---|---|
156
+ | `wan2.2-kf2v-flash` | 5s | 480P, 720P, 1080P | — | — | qwen |
157
+
158
+ ### wan2.6-i2v
159
+
160
+ | id | duration | resolutions | aspect | capabilities | served by |
161
+ |---|---|---|---|---|---|
162
+ | `wan2.6-i2v` | 2–15s | 720P, 1080P | — | — | qwen |
163
+
164
+ ### wan2.6-i2v-flash
165
+
166
+ | id | duration | resolutions | aspect | capabilities | served by |
167
+ |---|---|---|---|---|---|
168
+ | `wan2.6-i2v-flash` | 2–15s | 720P, 1080P | — | — | qwen |
169
+
170
+ ### wan2.6-r2v
171
+
172
+ | id | duration | resolutions | aspect | capabilities | served by |
173
+ |---|---|---|---|---|---|
174
+ | `wan2.6-r2v` | 2–10s | — | — | — | qwen |
175
+
176
+ ### wan2.6-t2v
177
+
178
+ | id | duration | resolutions | aspect | capabilities | served by |
179
+ |---|---|---|---|---|---|
180
+ | `wan2.6-t2v` | 2–15s | — | — | — | qwen |
181
+
182
+ ### wan2.7-i2v
183
+
184
+ | id | duration | resolutions | aspect | capabilities | served by |
185
+ |---|---|---|---|---|---|
186
+ | `wan2.7-i2v` | 2–15s | 720P, 1080P | — | — | qwen |
187
+
188
+ ### wan2.7-t2v
189
+
190
+ | id | duration | resolutions | aspect | capabilities | served by |
191
+ |---|---|---|---|---|---|
192
+ | `wan2.7-t2v` | 2–15s | 720P, 1080P | — | — | qwen |
193
+
194
+ ## Image (29)
195
+
196
+ ### dola-seedream-5-0-pro-260628
197
+
198
+ | id | resolutions | aspect | input | served by |
199
+ |---|---|---|---|---|
200
+ | `dola-seedream-5-0-pro-260628` | 1K, 2K, 4K | 16:9, 4:3, 1:1, 3:4, 9:16, 21:9 | image_optional | byteplus |
201
+
202
+ ### gemini-2.5-flash-image
203
+
204
+ | id | resolutions | aspect | input | served by |
205
+ |---|---|---|---|---|
206
+ | `gemini-2.5-flash-image` | 1K, 2K | — | image_optional | google |
207
+
208
+ ### gemini-3-pro-image
209
+
210
+ | id | resolutions | aspect | input | served by |
211
+ |---|---|---|---|---|
212
+ | `gemini-3-pro-image` | 1K, 2K, 4K | — | image_optional | google |
213
+
214
+ ### gemini-3.1-flash-image
215
+
216
+ | id | resolutions | aspect | input | served by |
217
+ |---|---|---|---|---|
218
+ | `gemini-3.1-flash-image` | 1K, 2K, 4K | — | image_optional | google |
219
+
220
+ ### gemini-3.1-flash-lite-image
221
+
222
+ | id | resolutions | aspect | input | served by |
223
+ |---|---|---|---|---|
224
+ | `gemini-3.1-flash-lite-image` | 512px, 1K, 2K | — | image_optional | google |
225
+
226
+ ### gpt-image-1
227
+
228
+ | id | resolutions | aspect | input | served by |
229
+ |---|---|---|---|---|
230
+ | `gpt-image-1` | 1024x1024, 1024x1536, 1536x1024, auto | — | image_optional | openai |
231
+
232
+ ### gpt-image-1.5
233
+
234
+ | id | resolutions | aspect | input | served by |
235
+ |---|---|---|---|---|
236
+ | `gpt-image-1.5` | 1024x1024, 1024x1536, 1536x1024, auto | — | image_optional | openai |
237
+
238
+ ### gpt-image-2
239
+
240
+ | id | resolutions | aspect | input | served by |
241
+ |---|---|---|---|---|
242
+ | `gpt-image-2` | — | — | image_optional | openai |
243
+
244
+ ### kling
245
+
246
+ | id | resolutions | aspect | input | served by |
247
+ |---|---|---|---|---|
248
+ | `kling/image-v1` | — | 16:9, 9:16, 1:1 | text_only | kling |
249
+ | `kling/image-v1-5` | — | 16:9, 9:16, 1:1 | text_only | kling |
250
+ | `kling/image-v2` | — | 16:9, 9:16, 1:1 | text_only | kling |
251
+ | `kling/image-v2-1` | — | 16:9, 9:16, 1:1 | text_only | kling |
252
+ | `kling/image-v2-new` | — | 16:9, 9:16, 1:1 | text_only | kling |
253
+
254
+ ### qwen-image-2.0
255
+
256
+ | id | resolutions | aspect | input | served by |
257
+ |---|---|---|---|---|
258
+ | `qwen-image-2.0` | — | — | image_optional | qwen |
259
+
260
+ ### qwen-image-2.0-pro
261
+
262
+ | id | resolutions | aspect | input | served by |
263
+ |---|---|---|---|---|
264
+ | `qwen-image-2.0-pro` | — | — | image_optional | qwen |
265
+
266
+ ### qwen-image-3.0
267
+
268
+ | id | resolutions | aspect | input | served by |
269
+ |---|---|---|---|---|
270
+ | `qwen-image-3.0` | — | — | image_optional | qwen |
271
+
272
+ ### qwen-image-3.0-pro
273
+
274
+ | id | resolutions | aspect | input | served by |
275
+ |---|---|---|---|---|
276
+ | `qwen-image-3.0-pro` | — | — | image_optional | qwen |
277
+
278
+ ### qwen-image-max
279
+
280
+ | id | resolutions | aspect | input | served by |
281
+ |---|---|---|---|---|
282
+ | `qwen-image-max` | — | — | image_optional | qwen |
283
+
284
+ ### seededit-3-0-i2i-250628
285
+
286
+ | id | resolutions | aspect | input | served by |
287
+ |---|---|---|---|---|
288
+ | `seededit-3-0-i2i-250628` | 1K, 2K | 16:9, 4:3, 1:1, 3:4, 9:16, 21:9 | image_required | byteplus |
289
+
290
+ ### seedream-3-0-t2i-250415
291
+
292
+ | id | resolutions | aspect | input | served by |
293
+ |---|---|---|---|---|
294
+ | `seedream-3-0-t2i-250415` | 1K, 2K | 16:9, 4:3, 1:1, 3:4, 9:16, 21:9 | image_optional | byteplus |
295
+
296
+ ### seedream-4-0-20260415
297
+
298
+ | id | resolutions | aspect | input | served by |
299
+ |---|---|---|---|---|
300
+ | `seedream-4-0-20260415` | 1K, 2K, 4K | 16:9, 4:3, 1:1, 3:4, 9:16, 21:9 | image_optional | byteplus |
301
+
302
+ ### seedream-4-0-250828
303
+
304
+ | id | resolutions | aspect | input | served by |
305
+ |---|---|---|---|---|
306
+ | `seedream-4-0-250828` | 1K, 2K, 4K | 16:9, 4:3, 1:1, 3:4, 9:16, 21:9 | image_optional | byteplus |
307
+
308
+ ### seedream-4-5-251128
309
+
310
+ | id | resolutions | aspect | input | served by |
311
+ |---|---|---|---|---|
312
+ | `seedream-4-5-251128` | 1K, 2K, 4K | 16:9, 4:3, 1:1, 3:4, 9:16, 21:9 | image_optional | byteplus |
313
+
314
+ ### seedream-5-0-260128
315
+
316
+ | id | resolutions | aspect | input | served by |
317
+ |---|---|---|---|---|
318
+ | `seedream-5-0-260128` | 1K, 2K, 4K | 16:9, 4:3, 1:1, 3:4, 9:16, 21:9 | image_optional | byteplus |
319
+
320
+ ### wan2.6-image
321
+
322
+ | id | resolutions | aspect | input | served by |
323
+ |---|---|---|---|---|
324
+ | `wan2.6-image` | — | — | image_optional | qwen |
325
+
326
+ ### wan2.6-t2i
327
+
328
+ | id | resolutions | aspect | input | served by |
329
+ |---|---|---|---|---|
330
+ | `wan2.6-t2i` | — | — | image_optional | qwen |
331
+
332
+ ### wan2.7-image
333
+
334
+ | id | resolutions | aspect | input | served by |
335
+ |---|---|---|---|---|
336
+ | `wan2.7-image` | 1K, 2K | — | image_optional | qwen |
337
+
338
+ ### wan2.7-image-pro
339
+
340
+ | id | resolutions | aspect | input | served by |
341
+ |---|---|---|---|---|
342
+ | `wan2.7-image-pro` | 1K, 2K, 4K | — | image_optional | qwen |
343
+
344
+ ### z-image-turbo
345
+
346
+ | id | resolutions | aspect | input | served by |
347
+ |---|---|---|---|---|
348
+ | `z-image-turbo` | — | — | image_optional | qwen |
349
+
350
+ ## Text (6)
351
+
352
+ ### qwen-max
353
+
354
+ | id | resolutions | aspect | input | served by |
355
+ |---|---|---|---|---|
356
+ | `qwen-max` | — | — | text_only | qwen |
357
+
358
+ ### qwen-plus
359
+
360
+ | id | resolutions | aspect | input | served by |
361
+ |---|---|---|---|---|
362
+ | `qwen-plus` | — | — | text_only | qwen |
363
+
364
+ ### qwen-turbo
365
+
366
+ | id | resolutions | aspect | input | served by |
367
+ |---|---|---|---|---|
368
+ | `qwen-turbo` | — | — | text_only | qwen |
369
+
370
+ ### qwen3.7-flash
371
+
372
+ | id | resolutions | aspect | input | served by |
373
+ |---|---|---|---|---|
374
+ | `qwen3.7-flash` | — | — | text_only | qwen |
375
+
376
+ ### qwen3.7-plus
377
+
378
+ | id | resolutions | aspect | input | served by |
379
+ |---|---|---|---|---|
380
+ | `qwen3.7-plus` | — | — | text_only | qwen |
381
+
382
+ ### qwen3.8-max
383
+
384
+ | id | resolutions | aspect | input | served by |
385
+ |---|---|---|---|---|
386
+ | `qwen3.8-max` | — | — | text_only | qwen |
387
+
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Brotu
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,115 @@
1
+ # @brotu/ai
2
+
3
+ One TypeScript client for generative image and video, talking to each vendor's own
4
+ API. You bring the keys; nothing is proxied, and no aggregator sits in between.
5
+
6
+ See [CATALOG.md](./CATALOG.md) for every model, with its durations, resolutions,
7
+ aspect ratios and capabilities. That file is generated from the catalog, so it
8
+ cannot drift from what the code actually supports.
9
+
10
+ ## Use
11
+
12
+ ```ts
13
+ import { brotuClient } from "@brotu/ai";
14
+
15
+ const ai = brotuClient({
16
+ providers: {
17
+ kling: { apiKey: process.env.KLING_API_KEY! },
18
+ },
19
+ });
20
+
21
+ const { data: job, error } = await ai.video.submit({
22
+ model: "kling/v2-6",
23
+ prompt: "a cat wearing sunglasses, cinematic",
24
+ duration: 5,
25
+ aspectRatio: "16:9",
26
+ });
27
+
28
+ if (error) return console.error(error.code, error.message);
29
+ await db.jobs.insert(job); // serializable — put it anywhere
30
+ ```
31
+
32
+ ## Nothing throws
33
+
34
+ Every call returns `{ data, error }`. `data` is unusable until you narrow on
35
+ `error`, so a failure is not something you can forget to handle.
36
+
37
+ ```ts
38
+ const { data, error } = await ai.jobs.wait(job);
39
+ if (error) {
40
+ if (error.code === "timeout") return retryLater(job); // still running
41
+ throw new Error(error.message);
42
+ }
43
+ data.outputs[0].url;
44
+ ```
45
+
46
+ Error codes: `unknown_model`, `missing_key`, `unsupported_provider`,
47
+ `invalid_request`, `provider_error`, `timeout`.
48
+
49
+ ## Jobs, not blocking calls
50
+
51
+ Video generation takes minutes, so the primary API is submit-then-poll. A job
52
+ handle is plain JSON: store it, and any later process can pick it up.
53
+
54
+ ```ts
55
+ const { data: job } = await ai.video.submit({ model: "kling/v2-6", prompt });
56
+
57
+ // later, another process, another day
58
+ const { data: snapshot } = await ai.jobs.poll(job); // one check, no waiting
59
+ const { data: result } = await ai.jobs.wait(job); // poll until it settles
60
+ ```
61
+
62
+ `generate()` exists as the convenient version of the same thing, but it holds the
63
+ call open for the whole run — fine in a script, wrong in a request handler.
64
+
65
+ ## Storage
66
+
67
+ Provider result URLs expire. Give the client a bucket and finished outputs are
68
+ copied into it, with `data.outputs[].url` pointing at your copy and the original
69
+ kept in `sourceUrl`.
70
+
71
+ ```ts
72
+ const ai = brotuClient({
73
+ providers: { kling: { apiKey: process.env.KLING_API_KEY! } },
74
+ storage: {
75
+ bucket: "my-bucket",
76
+ region: "us-east-2",
77
+ accessKeyId: process.env.S3_KEY!,
78
+ secretAccessKey: process.env.S3_SECRET!,
79
+ endpoint: "https://….r2.cloudflarestorage.com", // R2, MinIO, any S3 API
80
+ publicUrl: "https://cdn.example.com", // set it, and nothing is signed
81
+ },
82
+ });
83
+ ```
84
+
85
+ If one output fails to copy it keeps its provider URL rather than failing the
86
+ whole generation. `@aws-sdk/client-s3` is an optional peer dependency, loaded
87
+ only when you configure storage.
88
+
89
+ ## Regions and self-hosting
90
+
91
+ Every provider has a default host. Override it per client:
92
+
93
+ ```ts
94
+ providers: {
95
+ kling: { apiKey, baseUrl: "https://api-beijing.klingai.com" },
96
+ }
97
+ ```
98
+
99
+ ## Adding a model
100
+
101
+ Models are data. Register your own, or patch a built-in one:
102
+
103
+ ```ts
104
+ import { registerModels } from "@brotu/ai";
105
+
106
+ registerModels([
107
+ { id: "kling/v3", provider: "kling", /* … */ },
108
+ ]);
109
+ ```
110
+
111
+ ## Not in here
112
+
113
+ Credits, quotas, accounts and job persistence are product concerns, not client
114
+ concerns. Metering belongs on a server, where it can be trusted — not in an SDK
115
+ running on the caller's machine.
@@ -0,0 +1,51 @@
1
+ import { type Job, type JobSnapshot } from "../lib/jobs";
2
+ import { type AudioGenerationParams, type ContentGeneratorPort, type CostEstimate, type GenerationParams, type GenerationResult, type GenerationType, type ImageGenerationParams, type TextGenerationParams, type VideoGenerationParams } from "../ports/content-generator.port";
3
+ export interface BytePlusAdapterOptions {
4
+ apiKey: string;
5
+ baseUrl?: string;
6
+ maxPollAttempts?: number;
7
+ }
8
+ /**
9
+ * BytePlus ModelArk, home of Seedance.
10
+ *
11
+ * Two things drive the shape of this adapter. Ark 400s on any field the model
12
+ * does not accept instead of ignoring it, so nothing is sent unless the caller
13
+ * asked for it and the family allows it. And a result URL is valid for only 24
14
+ * hours, so configure `storage` on the client unless you are consuming the video
15
+ * immediately.
16
+ */
17
+ export declare class BytePlusAdapter implements ContentGeneratorPort {
18
+ readonly providerName = "byteplus";
19
+ readonly supportedTypes: GenerationType[];
20
+ private readonly opts;
21
+ constructor(opts: BytePlusAdapterOptions);
22
+ private get baseUrl();
23
+ private request;
24
+ private binding;
25
+ private buildBody;
26
+ private validate;
27
+ private outputsFrom;
28
+ private snapshot;
29
+ private run;
30
+ /** Resume a job submitted earlier, possibly by another process. */
31
+ completeJob(job: Job): Promise<JobSnapshot>;
32
+ generateVideo(params: VideoGenerationParams): Promise<GenerationResult>;
33
+ /**
34
+ * Seedream. Unlike video, `/images/generations` answers synchronously — the
35
+ * image is in the response and there is no task to poll, so `submit()` returns
36
+ * an already-settled job for these models.
37
+ */
38
+ generateImage(params: ImageGenerationParams): Promise<GenerationResult>;
39
+ /** Cancel a queued task, or delete the record of a finished one. */
40
+ cancelJob(job: Job): Promise<void>;
41
+ generateAudio(_params: AudioGenerationParams): Promise<GenerationResult>;
42
+ generateText(_params: TextGenerationParams): Promise<GenerationResult>;
43
+ estimateCost(type: GenerationType, params: GenerationParams): Promise<CostEstimate>;
44
+ supportsModel(model: string): boolean;
45
+ getAvailableModels(): {
46
+ id: string;
47
+ name: string;
48
+ type: GenerationType;
49
+ }[];
50
+ }
51
+ //# sourceMappingURL=byteplus.adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"byteplus.adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/byteplus.adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,KAAK,GAAG,EACR,KAAK,WAAW,EAEhB,MAAM,aAAa,CAAC;AACrB,OAAO,EACN,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,YAAY,EAGjB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,MAAM,iCAAiC,CAAC;AASzC,MAAM,WAAW,sBAAsB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAuCD;;;;;;;;GAQG;AACH,qBAAa,eAAgB,YAAW,oBAAoB;IAC3D,QAAQ,CAAC,YAAY,cAAc;IACnC,QAAQ,CAAC,cAAc,EAAE,cAAc,EAAE,CAAsB;IAE/D,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAyB;IAE9C,YAAY,IAAI,EAAE,sBAAsB,EAEvC;IAED,OAAO,KAAK,OAAO,GAElB;YAEa,OAAO;IAuBrB,OAAO,CAAC,OAAO;IAWf,OAAO,CAAC,SAAS;IAmEjB,OAAO,CAAC,QAAQ;IAsChB,OAAO,CAAC,WAAW;IAgBnB,OAAO,CAAC,QAAQ;YAgCF,GAAG;IAmEjB,mEAAmE;IAC7D,WAAW,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC,CAYhD;IAED,aAAa,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAEtE;IAED;;;;OAIG;IACG,aAAa,CAClB,MAAM,EAAE,qBAAqB,GAC3B,OAAO,CAAC,gBAAgB,CAAC,CAwE3B;IAED,oEAAoE;IAC9D,SAAS,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAKvC;IAED,aAAa,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAEvE;IAED,YAAY,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAErE;IAEK,YAAY,CACjB,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,gBAAgB,GACtB,OAAO,CAAC,YAAY,CAAC,CAEvB;IAED,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEpC;IAED,kBAAkB;;;cAKE,cAAc;QAQjC;CACD"}
@@ -0,0 +1,48 @@
1
+ import type { Job, JobSnapshot } from "../lib/jobs";
2
+ import type { AudioGenerationParams, ContentGeneratorPort, CostEstimate, GenerationParams, GenerationResult, GenerationType, ImageGenerationParams, TextGenerationParams, VideoGenerationParams } from "../ports/content-generator.port";
3
+ export interface ElevenLabsAdapterOptions {
4
+ apiKey: string;
5
+ baseUrl?: string;
6
+ /** Used when a request names no voice, since the API has no default. */
7
+ defaultVoiceId?: string;
8
+ }
9
+ export interface ElevenLabsVoice {
10
+ voiceId: string;
11
+ name: string;
12
+ labels?: Record<string, string>;
13
+ }
14
+ /**
15
+ * ElevenLabs speech synthesis.
16
+ *
17
+ * Synchronous, and unusual in two ways that this class exists to absorb: the key
18
+ * travels in `xi-api-key` rather than an Authorization header, and the response
19
+ * body is raw audio rather than JSON. The bytes become a data URI so the output
20
+ * looks like every other provider's, and `storage` copies it if configured.
21
+ */
22
+ export declare class ElevenLabsAdapter implements ContentGeneratorPort {
23
+ readonly providerName = "elevenlabs";
24
+ readonly supportedTypes: GenerationType[];
25
+ private readonly opts;
26
+ constructor(opts: ElevenLabsAdapterOptions);
27
+ private get baseUrl();
28
+ private get headers();
29
+ /**
30
+ * The voices on your account. Voice ids are opaque and account-specific, so
31
+ * there is no list the catalog could ship.
32
+ */
33
+ listVoices(): Promise<ElevenLabsVoice[]>;
34
+ generateAudio(params: AudioGenerationParams): Promise<GenerationResult>;
35
+ generateImage(_params: ImageGenerationParams): Promise<GenerationResult>;
36
+ generateVideo(_params: VideoGenerationParams): Promise<GenerationResult>;
37
+ generateText(_params: TextGenerationParams): Promise<GenerationResult>;
38
+ /** Synchronous provider: there is never a queued job to come back to. */
39
+ completeJob(job: Job): Promise<JobSnapshot>;
40
+ estimateCost(type: GenerationType, params: GenerationParams): Promise<CostEstimate>;
41
+ supportsModel(model: string): boolean;
42
+ getAvailableModels(): {
43
+ id: string;
44
+ name: string;
45
+ type: GenerationType;
46
+ }[];
47
+ }
48
+ //# sourceMappingURL=elevenlabs.adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elevenlabs.adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/elevenlabs.adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,EACX,qBAAqB,EACrB,oBAAoB,EACpB,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,qBAAqB,EACrB,oBAAoB,EACpB,qBAAqB,EACrB,MAAM,iCAAiC,CAAC;AAOzC,MAAM,WAAW,wBAAwB;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,cAAc,CAAC,EAAE,MAAM,CAAC;CACxB;AAID,MAAM,WAAW,eAAe;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED;;;;;;;GAOG;AACH,qBAAa,iBAAkB,YAAW,oBAAoB;IAC7D,QAAQ,CAAC,YAAY,gBAAgB;IACrC,QAAQ,CAAC,cAAc,EAAE,cAAc,EAAE,CAAa;IAEtD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA2B;IAEhD,YAAY,IAAI,EAAE,wBAAwB,EAEzC;IAED,OAAO,KAAK,OAAO,GAElB;IAED,OAAO,KAAK,OAAO,GAGlB;IAED;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,CAuB7C;IAEK,aAAa,CAClB,MAAM,EAAE,qBAAqB,GAC3B,OAAO,CAAC,gBAAgB,CAAC,CAiG3B;IAED,aAAa,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAEvE;IAED,aAAa,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAEvE;IAED,YAAY,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAErE;IAED,yEAAyE;IACnE,WAAW,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC,CAKhD;IAEK,YAAY,CACjB,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,gBAAgB,GACtB,OAAO,CAAC,YAAY,CAAC,CAMvB;IAED,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEpC;IAED,kBAAkB;;;cAIC,cAAc;QAEhC;CACD"}
@@ -0,0 +1,10 @@
1
+ import type { CostEstimate, GenerationParams, GenerationType } from "../ports/content-generator.port";
2
+ /**
3
+ * Count what the provider bills for, and price it only if the catalog carries a
4
+ * verified rate. Every provider here charges your own account, so the SDK's job
5
+ * is to say how much work you are asking for, not to invent a number.
6
+ */
7
+ export declare function estimateFor(provider: string, type: GenerationType, params: GenerationParams, defaults?: {
8
+ durationSeconds?: number;
9
+ }): CostEstimate;
10
+ //# sourceMappingURL=estimate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"estimate.d.ts","sourceRoot":"","sources":["../../src/adapters/estimate.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,MAAM,iCAAiC,CAAC;AAEzC;;;;GAIG;AACH,wBAAgB,WAAW,CAC1B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,gBAAgB,EACxB,QAAQ,CAAC,EAAE;IAAE,eAAe,CAAC,EAAE,MAAM,CAAA;CAAE,GACrC,YAAY,CAiDd"}