@brotu/ai 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -6
- package/dist/adapters/brotu.adapter.d.ts +46 -0
- package/dist/adapters/brotu.adapter.d.ts.map +1 -0
- package/dist/catalog.cjs +36 -14
- package/dist/catalog.d.ts +1 -0
- package/dist/catalog.d.ts.map +1 -1
- package/dist/catalog.js +3 -1
- package/dist/{chunk-PL534BFN.js → chunk-QOWHHKSI.js} +35 -14
- package/dist/client.d.ts +1 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/helpers/result.d.ts +1 -1
- package/dist/helpers/result.d.ts.map +1 -1
- package/dist/index.cjs +376 -36
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +342 -23
- package/dist/types.d.ts +14 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
BYTEPLUS_CATALOG,
|
|
3
3
|
BYTEPLUS_IMAGE_MODELS,
|
|
4
4
|
BYTEPLUS_MODELS,
|
|
5
|
+
DEFAULT_BROTU_API_URL,
|
|
5
6
|
ELEVENLABS_CATALOG,
|
|
6
7
|
ELEVENLABS_MODELS,
|
|
7
8
|
ELEVENLABS_OUTPUT_FORMATS,
|
|
@@ -35,7 +36,7 @@ import {
|
|
|
35
36
|
resetCatalog,
|
|
36
37
|
resolveProvider,
|
|
37
38
|
videoPathFor
|
|
38
|
-
} from "./chunk-
|
|
39
|
+
} from "./chunk-QOWHHKSI.js";
|
|
39
40
|
|
|
40
41
|
// src/lib/jobs.ts
|
|
41
42
|
import { AsyncLocalStorage } from "async_hooks";
|
|
@@ -91,12 +92,316 @@ function estimateFor(provider, type, params, defaults) {
|
|
|
91
92
|
};
|
|
92
93
|
}
|
|
93
94
|
|
|
95
|
+
// src/adapters/brotu.adapter.ts
|
|
96
|
+
var DEFAULT_API_URL = "https://api.brotu.app";
|
|
97
|
+
var POLL_INTERVAL_MS = 3e3;
|
|
98
|
+
var DEFAULT_MAX_POLL_ATTEMPTS = 400;
|
|
99
|
+
var PLATFORM_MODEL_IDS = {
|
|
100
|
+
"kling/v2-6": "kling-2.6",
|
|
101
|
+
"kling/v3": "kling-3.0/video",
|
|
102
|
+
"dreamina-seedance-2-5-260628": "bytedance/seedance-2-5",
|
|
103
|
+
"dreamina-seedance-2-0-260128": "bytedance/seedance-2",
|
|
104
|
+
"dreamina-seedance-2-0-fast-260128": "bytedance/seedance-2-fast",
|
|
105
|
+
"gpt-image-1.5": "gpt-image/1.5"
|
|
106
|
+
};
|
|
107
|
+
var UNSUPPORTED_VIA_CREDITS = "Speech and text generate on the vendor. Pass that provider's key.";
|
|
108
|
+
var BrotuAdapter = class {
|
|
109
|
+
constructor(opts) {
|
|
110
|
+
this.opts = opts;
|
|
111
|
+
}
|
|
112
|
+
opts;
|
|
113
|
+
providerName = "brotu";
|
|
114
|
+
supportedTypes = ["image", "video"];
|
|
115
|
+
workspaceIdCache;
|
|
116
|
+
get origin() {
|
|
117
|
+
return (this.opts.apiUrl ?? DEFAULT_API_URL).replace(/\/$/, "");
|
|
118
|
+
}
|
|
119
|
+
headers() {
|
|
120
|
+
return {
|
|
121
|
+
Authorization: `Bearer ${this.opts.apiKey}`,
|
|
122
|
+
"Content-Type": "application/json"
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
async workspaceId() {
|
|
126
|
+
if (this.opts.workspaceId) return this.opts.workspaceId;
|
|
127
|
+
if (this.workspaceIdCache) return this.workspaceIdCache;
|
|
128
|
+
const payload = await this.request("/api/v1/studio/default-workspace");
|
|
129
|
+
const id = payload.workspaceId?.trim();
|
|
130
|
+
if (!id) {
|
|
131
|
+
throw new Error(
|
|
132
|
+
"This Brotu account has no workspace. Open https://brotu.app and create one."
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
this.workspaceIdCache = id;
|
|
136
|
+
return id;
|
|
137
|
+
}
|
|
138
|
+
studioPath(path, workspaceId) {
|
|
139
|
+
const joiner = path.includes("?") ? "&" : "?";
|
|
140
|
+
return `${path}${joiner}workspaceId=${encodeURIComponent(workspaceId)}`;
|
|
141
|
+
}
|
|
142
|
+
async request(path, init) {
|
|
143
|
+
const response = await fetch(`${this.origin}${path}`, {
|
|
144
|
+
...init,
|
|
145
|
+
headers: { ...this.headers(), ...init?.headers }
|
|
146
|
+
});
|
|
147
|
+
const text = await response.text();
|
|
148
|
+
let body = void 0;
|
|
149
|
+
if (text) {
|
|
150
|
+
try {
|
|
151
|
+
body = JSON.parse(text);
|
|
152
|
+
} catch {
|
|
153
|
+
body = text;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
if (!response.ok) {
|
|
157
|
+
const parsed = body;
|
|
158
|
+
const message = parsed && typeof parsed === "object" ? parsed.error?.message || parsed.message || text : text;
|
|
159
|
+
throw new Error(message || `Brotu API ${response.status}`);
|
|
160
|
+
}
|
|
161
|
+
return body;
|
|
162
|
+
}
|
|
163
|
+
platformModel(modelId) {
|
|
164
|
+
return PLATFORM_MODEL_IDS[modelId] ?? modelId;
|
|
165
|
+
}
|
|
166
|
+
async startGeneration(kind, params) {
|
|
167
|
+
const modelId = params.model ?? "";
|
|
168
|
+
const workspaceId = await this.workspaceId();
|
|
169
|
+
const path = kind === "video" ? "/api/v1/studio/videos" : "/api/v1/studio/images";
|
|
170
|
+
const body = kind === "video" ? this.videoBody(params, modelId) : this.imageBody(params, modelId);
|
|
171
|
+
const result = await this.request(
|
|
172
|
+
this.studioPath(path, workspaceId),
|
|
173
|
+
{ method: "POST", body: JSON.stringify(body) }
|
|
174
|
+
);
|
|
175
|
+
const generationId = result.generationId?.trim();
|
|
176
|
+
if (!generationId) {
|
|
177
|
+
throw new Error("Brotu accepted the request but returned no generation id.");
|
|
178
|
+
}
|
|
179
|
+
return { generationId, workspaceId };
|
|
180
|
+
}
|
|
181
|
+
imageBody(params, modelId) {
|
|
182
|
+
return {
|
|
183
|
+
prompt: params.prompt,
|
|
184
|
+
model: this.platformModel(modelId),
|
|
185
|
+
aspectRatio: params.aspectRatio,
|
|
186
|
+
resolution: params.resolution,
|
|
187
|
+
negativePrompt: params.negativePrompt,
|
|
188
|
+
outputFormat: params.outputFormat,
|
|
189
|
+
seed: params.seed,
|
|
190
|
+
referenceImages: params.referenceImages
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
videoBody(params, modelId) {
|
|
194
|
+
return {
|
|
195
|
+
prompt: params.prompt,
|
|
196
|
+
model: this.platformModel(modelId),
|
|
197
|
+
duration: params.duration,
|
|
198
|
+
resolution: params.resolution,
|
|
199
|
+
aspectRatio: params.aspectRatio,
|
|
200
|
+
mode: params.mode,
|
|
201
|
+
withAudio: params.withAudio,
|
|
202
|
+
seed: params.seed,
|
|
203
|
+
imageUrl: params.imageUrl,
|
|
204
|
+
imageUrls: params.imageUrls,
|
|
205
|
+
videoUrl: params.videoUrl,
|
|
206
|
+
videoUrls: params.videoUrls,
|
|
207
|
+
referenceImages: params.referenceImages
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
async run(kind, params) {
|
|
211
|
+
const startedAt = Date.now();
|
|
212
|
+
const modelId = params.model ?? "(none)";
|
|
213
|
+
const failure = (error) => ({
|
|
214
|
+
success: false,
|
|
215
|
+
outputs: [],
|
|
216
|
+
creditsUsed: 0,
|
|
217
|
+
provider: this.providerName,
|
|
218
|
+
model: modelId,
|
|
219
|
+
processingTimeMs: Date.now() - startedAt,
|
|
220
|
+
error
|
|
221
|
+
});
|
|
222
|
+
let submitted;
|
|
223
|
+
try {
|
|
224
|
+
submitted = await this.startGeneration(kind, params);
|
|
225
|
+
} catch (error) {
|
|
226
|
+
return failure(error instanceof Error ? error.message : String(error));
|
|
227
|
+
}
|
|
228
|
+
const pollEndpoint = this.studioPath(
|
|
229
|
+
`/api/v1/studio/generations/${submitted.generationId}`,
|
|
230
|
+
submitted.workspaceId
|
|
231
|
+
);
|
|
232
|
+
if (isSubmitMode()) {
|
|
233
|
+
throw new PendingJob(submitted.generationId, pollEndpoint);
|
|
234
|
+
}
|
|
235
|
+
const job = {
|
|
236
|
+
id: submitted.generationId,
|
|
237
|
+
provider: this.providerName,
|
|
238
|
+
model: modelId,
|
|
239
|
+
kind,
|
|
240
|
+
pollEndpoint,
|
|
241
|
+
params,
|
|
242
|
+
submittedAt: new Date(startedAt).toISOString()
|
|
243
|
+
};
|
|
244
|
+
const maxAttempts = this.opts.maxPollAttempts ?? DEFAULT_MAX_POLL_ATTEMPTS;
|
|
245
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
246
|
+
const snapshot = await this.completeJob(job);
|
|
247
|
+
if (snapshot.status === "failed") {
|
|
248
|
+
return failure(snapshot.error ?? "Brotu generation failed.");
|
|
249
|
+
}
|
|
250
|
+
if (snapshot.status === "succeeded" && snapshot.result) {
|
|
251
|
+
return { ...snapshot.result, processingTimeMs: Date.now() - startedAt };
|
|
252
|
+
}
|
|
253
|
+
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
|
|
254
|
+
}
|
|
255
|
+
return failure(
|
|
256
|
+
`Brotu generation ${submitted.generationId} did not finish after ${maxAttempts} checks.`
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
async completeJob(job) {
|
|
260
|
+
const workspaceId = this.workspaceFromPoll(job.pollEndpoint) ?? await this.workspaceId();
|
|
261
|
+
const path = this.studioPath(
|
|
262
|
+
`/api/v1/studio/generations/${job.id}`,
|
|
263
|
+
workspaceId
|
|
264
|
+
);
|
|
265
|
+
const generation = await this.request(path);
|
|
266
|
+
const status = (generation.status ?? "").toLowerCase();
|
|
267
|
+
if (status === "failed") {
|
|
268
|
+
return {
|
|
269
|
+
status: "failed",
|
|
270
|
+
error: generation.errorMessage ?? "Brotu generation failed."
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
if (status !== "completed") {
|
|
274
|
+
return { status: "pending" };
|
|
275
|
+
}
|
|
276
|
+
const outputs = outputsFrom(generation, job.kind);
|
|
277
|
+
return {
|
|
278
|
+
status: "succeeded",
|
|
279
|
+
result: {
|
|
280
|
+
success: true,
|
|
281
|
+
outputs,
|
|
282
|
+
creditsUsed: generation.creditsUsed ?? 0,
|
|
283
|
+
provider: this.providerName,
|
|
284
|
+
model: job.model,
|
|
285
|
+
processingTimeMs: 0
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
workspaceFromPoll(pollEndpoint) {
|
|
290
|
+
if (!pollEndpoint) return void 0;
|
|
291
|
+
try {
|
|
292
|
+
const url = new URL(pollEndpoint, "https://brotu.invalid");
|
|
293
|
+
return url.searchParams.get("workspaceId") ?? void 0;
|
|
294
|
+
} catch {
|
|
295
|
+
return void 0;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
generateImage(params) {
|
|
299
|
+
return this.run("image", params);
|
|
300
|
+
}
|
|
301
|
+
generateVideo(params) {
|
|
302
|
+
return this.run("video", params);
|
|
303
|
+
}
|
|
304
|
+
async generateText(params) {
|
|
305
|
+
return {
|
|
306
|
+
success: false,
|
|
307
|
+
outputs: [],
|
|
308
|
+
creditsUsed: 0,
|
|
309
|
+
provider: this.providerName,
|
|
310
|
+
model: params.model ?? "(none)",
|
|
311
|
+
processingTimeMs: 0,
|
|
312
|
+
error: UNSUPPORTED_VIA_CREDITS
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
async generateAudio(params) {
|
|
316
|
+
return {
|
|
317
|
+
success: false,
|
|
318
|
+
outputs: [],
|
|
319
|
+
creditsUsed: 0,
|
|
320
|
+
provider: this.providerName,
|
|
321
|
+
model: params.model ?? "(none)",
|
|
322
|
+
processingTimeMs: 0,
|
|
323
|
+
error: UNSUPPORTED_VIA_CREDITS
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
async estimateCost(type, params) {
|
|
327
|
+
if (type === "audio" || type === "text") {
|
|
328
|
+
const estimate = estimateFor(this.providerName, type, params);
|
|
329
|
+
return {
|
|
330
|
+
...estimate,
|
|
331
|
+
usd: null,
|
|
332
|
+
note: UNSUPPORTED_VIA_CREDITS
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
try {
|
|
336
|
+
const workspaceId = await this.workspaceId();
|
|
337
|
+
const video = params;
|
|
338
|
+
const image = params;
|
|
339
|
+
const payload = await this.request(
|
|
340
|
+
this.studioPath("/api/v1/studio/estimate", workspaceId),
|
|
341
|
+
{
|
|
342
|
+
method: "POST",
|
|
343
|
+
body: JSON.stringify({
|
|
344
|
+
model: this.platformModel(params.model ?? ""),
|
|
345
|
+
duration: video.duration,
|
|
346
|
+
resolution: video.resolution ?? image.resolution,
|
|
347
|
+
aspectRatio: video.aspectRatio ?? image.aspectRatio,
|
|
348
|
+
withAudio: video.withAudio,
|
|
349
|
+
hasReferenceImage: Boolean(
|
|
350
|
+
video.imageUrl || video.imageUrls?.length || video.referenceImages?.length || image.referenceImages?.length
|
|
351
|
+
),
|
|
352
|
+
hasReferenceVideo: Boolean(video.videoUrl || video.videoUrls?.length),
|
|
353
|
+
quality: image.quality
|
|
354
|
+
})
|
|
355
|
+
}
|
|
356
|
+
);
|
|
357
|
+
const credits = payload.estimatedCredits ?? 0;
|
|
358
|
+
return {
|
|
359
|
+
unit: type === "video" ? "second" : "image",
|
|
360
|
+
units: credits,
|
|
361
|
+
usd: null,
|
|
362
|
+
note: `${credits} Brotu credit${credits === 1 ? "" : "s"}. A vendor key generates on that provider.`,
|
|
363
|
+
provider: this.providerName,
|
|
364
|
+
model: params.model ?? ""
|
|
365
|
+
};
|
|
366
|
+
} catch (error) {
|
|
367
|
+
const estimate = estimateFor(this.providerName, type, params);
|
|
368
|
+
return {
|
|
369
|
+
...estimate,
|
|
370
|
+
usd: null,
|
|
371
|
+
note: error instanceof Error ? error.message : "Could not estimate Brotu credits."
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
supportsModel() {
|
|
376
|
+
return true;
|
|
377
|
+
}
|
|
378
|
+
getAvailableModels() {
|
|
379
|
+
return [];
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
function outputsFrom(generation, kind) {
|
|
383
|
+
const bucket = generation.outputs;
|
|
384
|
+
const urls = kind === "video" ? bucket?.videos ?? bucket?.images ?? [] : bucket?.images ?? bucket?.videos ?? [];
|
|
385
|
+
const copies = bucket?.copies ?? [];
|
|
386
|
+
const mimeType = kind === "video" ? "video/mp4" : "image/png";
|
|
387
|
+
const fromUrls = urls.filter(Boolean).map((url) => ({
|
|
388
|
+
url,
|
|
389
|
+
mimeType
|
|
390
|
+
}));
|
|
391
|
+
if (fromUrls.length > 0) return fromUrls;
|
|
392
|
+
return copies.filter(Boolean).map((url) => ({
|
|
393
|
+
url,
|
|
394
|
+
mimeType: "text/plain",
|
|
395
|
+
raw: { text: url }
|
|
396
|
+
}));
|
|
397
|
+
}
|
|
398
|
+
|
|
94
399
|
// src/adapters/byteplus.adapter.ts
|
|
95
400
|
var DEFAULT_BASE_URL = "https://ark.ap-southeast.bytepluses.com";
|
|
96
401
|
var TASKS_PATH = "/api/v3/contents/generations/tasks";
|
|
97
402
|
var IMAGES_PATH = "/api/v3/images/generations";
|
|
98
|
-
var
|
|
99
|
-
var
|
|
403
|
+
var POLL_INTERVAL_MS2 = 5e3;
|
|
404
|
+
var DEFAULT_MAX_POLL_ATTEMPTS2 = 240;
|
|
100
405
|
var BytePlusAdapter = class {
|
|
101
406
|
providerName = "byteplus";
|
|
102
407
|
supportedTypes = ["image", "video"];
|
|
@@ -296,7 +601,7 @@ var BytePlusAdapter = class {
|
|
|
296
601
|
params,
|
|
297
602
|
submittedAt: new Date(startedAt).toISOString()
|
|
298
603
|
};
|
|
299
|
-
const maxAttempts = this.opts.maxPollAttempts ??
|
|
604
|
+
const maxAttempts = this.opts.maxPollAttempts ?? DEFAULT_MAX_POLL_ATTEMPTS2;
|
|
300
605
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
301
606
|
const snapshot = await this.completeJob(job);
|
|
302
607
|
if (snapshot.status === "failed") {
|
|
@@ -305,7 +610,7 @@ var BytePlusAdapter = class {
|
|
|
305
610
|
if (snapshot.status === "succeeded" && snapshot.result) {
|
|
306
611
|
return { ...snapshot.result, processingTimeMs: Date.now() - startedAt };
|
|
307
612
|
}
|
|
308
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
613
|
+
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS2));
|
|
309
614
|
}
|
|
310
615
|
return failure(
|
|
311
616
|
`Ark task ${taskId} did not finish after ${maxAttempts} checks.`
|
|
@@ -582,8 +887,8 @@ var ElevenLabsAdapter = class {
|
|
|
582
887
|
// src/adapters/google.adapter.ts
|
|
583
888
|
var DEFAULT_BASE_URL3 = "https://generativelanguage.googleapis.com";
|
|
584
889
|
var INTERACTIONS_PATH = "/v1beta/interactions";
|
|
585
|
-
var
|
|
586
|
-
var
|
|
890
|
+
var POLL_INTERVAL_MS3 = 1e4;
|
|
891
|
+
var DEFAULT_MAX_POLL_ATTEMPTS3 = 120;
|
|
587
892
|
var GoogleAdapter = class {
|
|
588
893
|
providerName = "google";
|
|
589
894
|
supportedTypes = [
|
|
@@ -855,7 +1160,7 @@ var GoogleAdapter = class {
|
|
|
855
1160
|
params,
|
|
856
1161
|
submittedAt: new Date(startedAt).toISOString()
|
|
857
1162
|
};
|
|
858
|
-
const maxAttempts = this.opts.maxPollAttempts ??
|
|
1163
|
+
const maxAttempts = this.opts.maxPollAttempts ?? DEFAULT_MAX_POLL_ATTEMPTS3;
|
|
859
1164
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
860
1165
|
const snapshot = await this.completeJob(job);
|
|
861
1166
|
if (snapshot.status === "failed") {
|
|
@@ -864,7 +1169,7 @@ var GoogleAdapter = class {
|
|
|
864
1169
|
if (snapshot.status === "succeeded" && snapshot.result) {
|
|
865
1170
|
return { ...snapshot.result, processingTimeMs: Date.now() - startedAt };
|
|
866
1171
|
}
|
|
867
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
1172
|
+
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS3));
|
|
868
1173
|
}
|
|
869
1174
|
return failure(`Veo operation ${operation} did not finish in time.`);
|
|
870
1175
|
}
|
|
@@ -1079,8 +1384,8 @@ var GoogleAdapter = class {
|
|
|
1079
1384
|
|
|
1080
1385
|
// src/adapters/kling.adapter.ts
|
|
1081
1386
|
var DEFAULT_BASE_URL4 = "https://api-singapore.klingai.com";
|
|
1082
|
-
var
|
|
1083
|
-
var
|
|
1387
|
+
var POLL_INTERVAL_MS4 = 5e3;
|
|
1388
|
+
var DEFAULT_MAX_POLL_ATTEMPTS4 = 240;
|
|
1084
1389
|
function stateOf(task) {
|
|
1085
1390
|
const raw = (task.status ?? task.task_status ?? "").toLowerCase();
|
|
1086
1391
|
if (raw === "failed") return "failed";
|
|
@@ -1277,7 +1582,7 @@ var KlingAdapter = class {
|
|
|
1277
1582
|
params,
|
|
1278
1583
|
submittedAt: new Date(startedAt).toISOString()
|
|
1279
1584
|
};
|
|
1280
|
-
const maxAttempts = this.opts.maxPollAttempts ??
|
|
1585
|
+
const maxAttempts = this.opts.maxPollAttempts ?? DEFAULT_MAX_POLL_ATTEMPTS4;
|
|
1281
1586
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
1282
1587
|
const snapshot = await this.completeJob(job);
|
|
1283
1588
|
if (snapshot.status === "failed") {
|
|
@@ -1286,7 +1591,7 @@ var KlingAdapter = class {
|
|
|
1286
1591
|
if (snapshot.status === "succeeded" && snapshot.result) {
|
|
1287
1592
|
return { ...snapshot.result, processingTimeMs: Date.now() - startedAt };
|
|
1288
1593
|
}
|
|
1289
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
1594
|
+
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS4));
|
|
1290
1595
|
}
|
|
1291
1596
|
return failure(
|
|
1292
1597
|
`Kling task ${submitted.taskId} did not finish after ${maxAttempts} checks.`
|
|
@@ -1657,8 +1962,8 @@ var OpenAIAdapter = class {
|
|
|
1657
1962
|
// src/adapters/qwen.adapter.ts
|
|
1658
1963
|
var DEFAULT_BASE_URL6 = "https://dashscope-intl.aliyuncs.com";
|
|
1659
1964
|
var TASKS_PATH2 = "/api/v1/tasks";
|
|
1660
|
-
var
|
|
1661
|
-
var
|
|
1965
|
+
var POLL_INTERVAL_MS5 = 5e3;
|
|
1966
|
+
var DEFAULT_MAX_POLL_ATTEMPTS5 = 240;
|
|
1662
1967
|
var QwenAdapter = class {
|
|
1663
1968
|
providerName = "qwen";
|
|
1664
1969
|
supportedTypes = ["image", "video"];
|
|
@@ -1865,7 +2170,7 @@ var QwenAdapter = class {
|
|
|
1865
2170
|
params,
|
|
1866
2171
|
submittedAt: new Date(startedAt).toISOString()
|
|
1867
2172
|
};
|
|
1868
|
-
const maxAttempts = this.opts.maxPollAttempts ??
|
|
2173
|
+
const maxAttempts = this.opts.maxPollAttempts ?? DEFAULT_MAX_POLL_ATTEMPTS5;
|
|
1869
2174
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
1870
2175
|
const snapshot = await this.completeJob(job);
|
|
1871
2176
|
if (snapshot.status === "failed") {
|
|
@@ -1874,7 +2179,7 @@ var QwenAdapter = class {
|
|
|
1874
2179
|
if (snapshot.status === "succeeded" && snapshot.result) {
|
|
1875
2180
|
return { ...snapshot.result, processingTimeMs: Date.now() - startedAt };
|
|
1876
2181
|
}
|
|
1877
|
-
await new Promise((resolve) => setTimeout(resolve,
|
|
2182
|
+
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS5));
|
|
1878
2183
|
}
|
|
1879
2184
|
return failure(
|
|
1880
2185
|
`DashScope task ${taskId} did not finish after ${maxAttempts} checks.`
|
|
@@ -2305,9 +2610,14 @@ var NATIVE_PROVIDERS = [
|
|
|
2305
2610
|
"qwen"
|
|
2306
2611
|
];
|
|
2307
2612
|
function brotuClient(options) {
|
|
2308
|
-
|
|
2309
|
-
|
|
2613
|
+
const apiKey = options.apiKey?.trim();
|
|
2614
|
+
if (!apiKey) {
|
|
2615
|
+
throw new Error(
|
|
2616
|
+
"Pass a Brotu API key (brotu_sk_\u2026). Get one at https://brotu.app."
|
|
2617
|
+
);
|
|
2310
2618
|
}
|
|
2619
|
+
const optionsWithKey = { ...options, apiKey };
|
|
2620
|
+
const vendors = optionsWithKey.providers ?? {};
|
|
2311
2621
|
registerModels(options.models);
|
|
2312
2622
|
let registeredWebhook = resolveWebhook(options.webhook);
|
|
2313
2623
|
const notifiedJobIds = /* @__PURE__ */ new Set();
|
|
@@ -2331,7 +2641,7 @@ function brotuClient(options) {
|
|
|
2331
2641
|
}
|
|
2332
2642
|
let provider;
|
|
2333
2643
|
try {
|
|
2334
|
-
provider = resolveProvider(modelId,
|
|
2644
|
+
provider = resolveProvider(modelId, optionsWithKey);
|
|
2335
2645
|
} catch (error) {
|
|
2336
2646
|
return failFrom("missing_key", error, { model: modelId });
|
|
2337
2647
|
}
|
|
@@ -2352,6 +2662,13 @@ function brotuClient(options) {
|
|
|
2352
2662
|
return ok({ adapter, provider: provider.id, model: modelId });
|
|
2353
2663
|
}
|
|
2354
2664
|
function buildAdapter(provider) {
|
|
2665
|
+
if (provider.id === "brotu") {
|
|
2666
|
+
return new BrotuAdapter({
|
|
2667
|
+
apiKey,
|
|
2668
|
+
apiUrl: optionsWithKey.apiUrl,
|
|
2669
|
+
workspaceId: optionsWithKey.workspaceId
|
|
2670
|
+
});
|
|
2671
|
+
}
|
|
2355
2672
|
if (provider.id === "kling") {
|
|
2356
2673
|
return new KlingAdapter({
|
|
2357
2674
|
apiKey: provider.apiKey,
|
|
@@ -2626,7 +2943,7 @@ function brotuClient(options) {
|
|
|
2626
2943
|
}
|
|
2627
2944
|
}
|
|
2628
2945
|
function klingNamespace() {
|
|
2629
|
-
const configured =
|
|
2946
|
+
const configured = vendors.kling;
|
|
2630
2947
|
if (!configured) return void 0;
|
|
2631
2948
|
const adapter = new KlingAdapter({
|
|
2632
2949
|
apiKey: configured.apiKey,
|
|
@@ -2651,7 +2968,7 @@ function brotuClient(options) {
|
|
|
2651
2968
|
};
|
|
2652
2969
|
}
|
|
2653
2970
|
function googleNamespace() {
|
|
2654
|
-
const configured =
|
|
2971
|
+
const configured = vendors.google;
|
|
2655
2972
|
if (!configured) return void 0;
|
|
2656
2973
|
const adapter = new GoogleAdapter({
|
|
2657
2974
|
apiKey: configured.apiKey,
|
|
@@ -2734,7 +3051,7 @@ function brotuClient(options) {
|
|
|
2734
3051
|
}
|
|
2735
3052
|
}
|
|
2736
3053
|
},
|
|
2737
|
-
models: () => getAvailableModels(
|
|
3054
|
+
models: () => getAvailableModels(optionsWithKey),
|
|
2738
3055
|
estimateCost: async (type, params) => {
|
|
2739
3056
|
const routed = route(params.model);
|
|
2740
3057
|
if (routed.error) return fail(routed.error);
|
|
@@ -2752,7 +3069,9 @@ function brotuClient(options) {
|
|
|
2752
3069
|
export {
|
|
2753
3070
|
BYTEPLUS_CATALOG,
|
|
2754
3071
|
BYTEPLUS_MODELS,
|
|
3072
|
+
BrotuAdapter,
|
|
2755
3073
|
BytePlusAdapter,
|
|
3074
|
+
DEFAULT_BROTU_API_URL,
|
|
2756
3075
|
ELEVENLABS_CATALOG,
|
|
2757
3076
|
ELEVENLABS_MODELS,
|
|
2758
3077
|
ELEVENLABS_OUTPUT_FORMATS,
|
package/dist/types.d.ts
CHANGED
|
@@ -12,8 +12,20 @@ export interface ReferenceVideoInfo {
|
|
|
12
12
|
height?: number;
|
|
13
13
|
}
|
|
14
14
|
export interface BrotuAIOptions {
|
|
15
|
-
/**
|
|
16
|
-
|
|
15
|
+
/**
|
|
16
|
+
* Your Brotu key (`brotu_sk_…`), from https://brotu.app.
|
|
17
|
+
* Vendor keys below generate on the vendor; everything else generates on Brotu.
|
|
18
|
+
*/
|
|
19
|
+
apiKey: string;
|
|
20
|
+
/** Brotu API origin. Defaults to `https://api.brotu.app`. */
|
|
21
|
+
apiUrl?: string;
|
|
22
|
+
/**
|
|
23
|
+
* Workspace billed on Brotu generations. Resolved via
|
|
24
|
+
* `GET /studio/default-workspace` when omitted.
|
|
25
|
+
*/
|
|
26
|
+
workspaceId?: string;
|
|
27
|
+
/** Vendor keys you already have. Those models generate on the vendor. */
|
|
28
|
+
providers?: Record<string, ProviderConfig>;
|
|
17
29
|
/** Provider used by catalog entries that do not declare one. Defaults to "kie". */
|
|
18
30
|
defaultProvider?: string;
|
|
19
31
|
/**
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,MAAM,WAAW,cAAc;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IAClC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC9B,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,MAAM,WAAW,cAAc;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,kBAAkB;IAClC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,cAAc;IAC9B;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC3C,mFAAmF;IACnF,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC9C;;;;OAIG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC1D;;;;OAIG;IACH,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B;;;OAGG;IACH,WAAW,CAAC,EAAE,CACb,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,KACZ,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iEAAiE;IACjE,MAAM,CAAC,EAAE,aAAa,EAAE,CAAC;IACzB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC;CACjC;AAED,yEAAyE;AACzE,MAAM,WAAW,gBAAgB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CAChB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brotu/ai",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.cjs",
|
|
6
6
|
"exports": {
|
|
@@ -66,11 +66,11 @@
|
|
|
66
66
|
"module": "./dist/index.js",
|
|
67
67
|
"repository": {
|
|
68
68
|
"type": "git",
|
|
69
|
-
"url": "git+https://github.com/Zorbi-Tech/brotu
|
|
69
|
+
"url": "git+https://github.com/Zorbi-Tech/brotu.git",
|
|
70
70
|
"directory": "sdks/node"
|
|
71
71
|
},
|
|
72
|
-
"homepage": "https://github.com/Zorbi-Tech/brotu
|
|
72
|
+
"homepage": "https://github.com/Zorbi-Tech/brotu",
|
|
73
73
|
"bugs": {
|
|
74
|
-
"url": "https://github.com/Zorbi-Tech/brotu
|
|
74
|
+
"url": "https://github.com/Zorbi-Tech/brotu/issues"
|
|
75
75
|
}
|
|
76
76
|
}
|