@brotu/ai 0.2.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 +53 -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 +11 -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 +574 -47
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +537 -33
- package/dist/lib/webhook.d.ts +28 -0
- package/dist/lib/webhook.d.ts.map +1 -0
- package/dist/ports/content-generator.port.d.ts +6 -0
- package/dist/ports/content-generator.port.d.ts.map +1 -1
- package/dist/types.d.ts +21 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
<p align="center">
|
|
2
2
|
<picture>
|
|
3
|
-
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/Zorbi-Tech/brotu
|
|
4
|
-
<img src="https://raw.githubusercontent.com/Zorbi-Tech/brotu
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/Zorbi-Tech/brotu/main/docs/assets/logo.svg">
|
|
4
|
+
<img src="https://raw.githubusercontent.com/Zorbi-Tech/brotu/main/docs/assets/logo-black.svg" alt="Brotu" width="280">
|
|
5
5
|
</picture>
|
|
6
6
|
</p>
|
|
7
7
|
|
|
8
8
|
<p align="center">
|
|
9
9
|
<strong>One TypeScript client for video, image, speech, text and vendor extras.</strong><br>
|
|
10
|
-
|
|
10
|
+
Your Brotu key. Vendor keys generate on the vendor.
|
|
11
11
|
</p>
|
|
12
12
|
|
|
13
13
|
<p align="center">
|
|
14
14
|
<a href="https://www.npmjs.com/package/@brotu/ai"><img alt="npm version" src="https://img.shields.io/npm/v/@brotu/ai?color=ef5e28"></a>
|
|
15
15
|
<a href="https://www.npmjs.com/package/@brotu/ai"><img alt="npm downloads" src="https://img.shields.io/npm/dm/@brotu/ai?color=ef5e28&label=downloads"></a>
|
|
16
16
|
<a href="https://www.npmjs.com/package/@brotu/ai"><img alt="npm totals" src="https://img.shields.io/npm/dt/@brotu/ai?color=111&label=total"></a>
|
|
17
|
-
<a href="https://github.com/Zorbi-Tech/brotu
|
|
17
|
+
<a href="https://github.com/Zorbi-Tech/brotu/blob/main/LICENSE"><img alt="MIT" src="https://img.shields.io/npm/l/@brotu/ai?color=111"></a>
|
|
18
18
|
</p>
|
|
19
19
|
|
|
20
20
|
<p align="center">
|
|
@@ -23,7 +23,9 @@
|
|
|
23
23
|
<a href="https://x.com/brotuApp">@brotuApp</a>
|
|
24
24
|
</p>
|
|
25
25
|
|
|
26
|
-
Kling, Seedance, Wan, Veo, Gemini, gpt-image and ElevenLabs all speak different HTTP. This package is one `brotuClient` in front of them.
|
|
26
|
+
Kling, Seedance, Wan, Veo, Gemini, gpt-image and ElevenLabs all speak different HTTP. This package is one `brotuClient` in front of them.
|
|
27
|
+
|
|
28
|
+
Get your key (`brotu_sk_…`) at [brotu.app](https://brotu.app). Pass a vendor key you already have and that model hits the vendor. Everything else generates on Brotu.
|
|
27
29
|
|
|
28
30
|
97 models: 37 video, 29 image, 12 speech, 19 text. Full table in [CATALOG.md](./CATALOG.md). That file is generated from the catalog, so it cannot drift from what the code supports.
|
|
29
31
|
|
|
@@ -47,6 +49,7 @@ pnpm add @brotu/ai
|
|
|
47
49
|
import { brotuClient } from "@brotu/ai";
|
|
48
50
|
|
|
49
51
|
const ai = brotuClient({
|
|
52
|
+
apiKey: process.env.BROTU_API_KEY!, // brotu_sk_… from https://brotu.app
|
|
50
53
|
providers: {
|
|
51
54
|
kling: { apiKey: process.env.KLING_API_KEY! },
|
|
52
55
|
byteplus: { apiKey: process.env.ARK_API_KEY! },
|
|
@@ -55,10 +58,14 @@ const ai = brotuClient({
|
|
|
55
58
|
qwen: { apiKey: process.env.QWEN_API_KEY! },
|
|
56
59
|
elevenlabs: { apiKey: process.env.ELEVENLABS_API_KEY! },
|
|
57
60
|
},
|
|
61
|
+
webhook: {
|
|
62
|
+
url: "https://my.app/hooks/brotu",
|
|
63
|
+
secret: process.env.BROTU_WEBHOOK_SECRET,
|
|
64
|
+
},
|
|
58
65
|
});
|
|
59
66
|
```
|
|
60
67
|
|
|
61
|
-
|
|
68
|
+
Your Brotu key opens the catalog. A vendor key, when you have one, generates on that vendor.
|
|
62
69
|
|
|
63
70
|
Every public call returns `{ data, error }`. `data` is unusable until you narrow on `error`.
|
|
64
71
|
|
|
@@ -69,6 +76,7 @@ Every public call returns `{ data, error }`. `data` is unusable until you narrow
|
|
|
69
76
|
| `ai.text` | `submit` / `generate` |
|
|
70
77
|
| `ai.audio` | `submit` / `generate` |
|
|
71
78
|
| `ai.jobs` | `poll` / `wait` |
|
|
79
|
+
| `ai.webhook` | `set` / `clear` / `get` |
|
|
72
80
|
| `ai.estimateCost` | units, and USD when verified |
|
|
73
81
|
| `ai.kling` | `motionControl`, `omniVideo`, `avatar`, `outpainting`, `imageOmni` |
|
|
74
82
|
| `ai.google` | `omniVideo` (conversational refine) |
|
|
@@ -145,6 +153,10 @@ ElevenLabs: you must pass `voice`. There is no default.
|
|
|
145
153
|
|
|
146
154
|
Realtime / Live WebSocket models are not on this surface.
|
|
147
155
|
|
|
156
|
+
## CLI
|
|
157
|
+
|
|
158
|
+
The terminal lives in [`../../cli`](../../cli) (`@brotu/cli`). This package is the library only.
|
|
159
|
+
|
|
148
160
|
## Jobs
|
|
149
161
|
|
|
150
162
|
```ts
|
|
@@ -156,6 +168,41 @@ if (result === undefined && snapshot?.status === "pending") {
|
|
|
156
168
|
}
|
|
157
169
|
```
|
|
158
170
|
|
|
171
|
+
## Webhook
|
|
172
|
+
|
|
173
|
+
Register a URL on the client. When `generate`, `jobs.wait` or a terminal `jobs.poll` settles, the SDK POSTs the result there. A down hook never fails the generation.
|
|
174
|
+
|
|
175
|
+
```ts
|
|
176
|
+
ai.webhook.set("https://my.app/hooks/brotu");
|
|
177
|
+
ai.webhook.clear();
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Per request, if one generation should go somewhere else:
|
|
181
|
+
|
|
182
|
+
```ts
|
|
183
|
+
await ai.video.submit({
|
|
184
|
+
model: "kling/v2-6",
|
|
185
|
+
prompt: "a cat",
|
|
186
|
+
webhook: "https://my.app/hooks/this-one",
|
|
187
|
+
});
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
The POST is JSON. Check `x-brotu-event` and, if you set a secret, `x-brotu-webhook-secret`.
|
|
191
|
+
|
|
192
|
+
```json
|
|
193
|
+
{
|
|
194
|
+
"event": "generation.succeeded",
|
|
195
|
+
"jobId": "task-1",
|
|
196
|
+
"provider": "kling",
|
|
197
|
+
"model": "kling/v2-6",
|
|
198
|
+
"kind": "video",
|
|
199
|
+
"outputs": [{ "url": "https://…", "mimeType": "video/mp4" }],
|
|
200
|
+
"completedAt": "2026-08-16T12:00:00.000Z"
|
|
201
|
+
}
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
`generation.failed` carries `error: { code, message }` and no outputs. Timeouts and routing errors do not fire the hook.
|
|
205
|
+
|
|
159
206
|
Error codes: `unknown_model`, `missing_key`, `unsupported_provider`, `invalid_request`, `provider_error`, `timeout`.
|
|
160
207
|
|
|
161
208
|
## Motion control, avatars, omni
|
|
@@ -0,0 +1,46 @@
|
|
|
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 BrotuAdapterOptions {
|
|
4
|
+
apiKey: string;
|
|
5
|
+
/** Origin only, no trailing slash. Defaults to https://api.brotu.app */
|
|
6
|
+
apiUrl?: string;
|
|
7
|
+
workspaceId?: string;
|
|
8
|
+
maxPollAttempts?: number;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* SDK catalog ids that do not match the platform catalog. Unlisted ids are
|
|
12
|
+
* sent as-is — gpt-image-2 and bytedance/seedance-2-5 already agree.
|
|
13
|
+
*/
|
|
14
|
+
declare const PLATFORM_MODEL_IDS: Record<string, string>;
|
|
15
|
+
export declare class BrotuAdapter implements ContentGeneratorPort {
|
|
16
|
+
private readonly opts;
|
|
17
|
+
readonly providerName = "brotu";
|
|
18
|
+
readonly supportedTypes: GenerationType[];
|
|
19
|
+
private workspaceIdCache?;
|
|
20
|
+
constructor(opts: BrotuAdapterOptions);
|
|
21
|
+
private get origin();
|
|
22
|
+
private headers;
|
|
23
|
+
private workspaceId;
|
|
24
|
+
private studioPath;
|
|
25
|
+
private request;
|
|
26
|
+
private platformModel;
|
|
27
|
+
private startGeneration;
|
|
28
|
+
private imageBody;
|
|
29
|
+
private videoBody;
|
|
30
|
+
private run;
|
|
31
|
+
completeJob(job: Job): Promise<JobSnapshot>;
|
|
32
|
+
private workspaceFromPoll;
|
|
33
|
+
generateImage(params: ImageGenerationParams): Promise<GenerationResult>;
|
|
34
|
+
generateVideo(params: VideoGenerationParams): Promise<GenerationResult>;
|
|
35
|
+
generateText(params: TextGenerationParams): Promise<GenerationResult>;
|
|
36
|
+
generateAudio(params: AudioGenerationParams): Promise<GenerationResult>;
|
|
37
|
+
estimateCost(type: GenerationType, params: GenerationParams): Promise<CostEstimate>;
|
|
38
|
+
supportsModel(): boolean;
|
|
39
|
+
getAvailableModels(): {
|
|
40
|
+
id: string;
|
|
41
|
+
name: string;
|
|
42
|
+
type: GenerationType;
|
|
43
|
+
}[];
|
|
44
|
+
}
|
|
45
|
+
export { PLATFORM_MODEL_IDS };
|
|
46
|
+
//# sourceMappingURL=brotu.adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brotu.adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/brotu.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,EAEjB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,qBAAqB,EAC1B,MAAM,iCAAiC,CAAC;AAGzC,MAAM,WAAW,mBAAmB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAMD;;;GAGG;AACH,QAAA,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAO9C,CAAC;AAuBF,qBAAa,YAAa,YAAW,oBAAoB;IAM5C,OAAO,CAAC,QAAQ,CAAC,IAAI;IALjC,QAAQ,CAAC,YAAY,WAAW;IAChC,QAAQ,CAAC,cAAc,EAAE,cAAc,EAAE,CAAsB;IAE/D,OAAO,CAAC,gBAAgB,CAAC,CAAS;IAElC,YAA6B,IAAI,EAAE,mBAAmB,EAAI;IAE1D,OAAO,KAAK,MAAM,GAEjB;IAED,OAAO,CAAC,OAAO;YAOD,WAAW;IAiBzB,OAAO,CAAC,UAAU;YAKJ,OAAO;IAyBrB,OAAO,CAAC,aAAa;YAIP,eAAe;IAwB7B,OAAO,CAAC,SAAS;IAgBjB,OAAO,CAAC,SAAS;YAqBH,GAAG;IA4DX,WAAW,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,WAAW,CAAC,CAgChD;IAED,OAAO,CAAC,iBAAiB;IAUzB,aAAa,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAEtE;IAED,aAAa,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAEtE;IAEK,YAAY,CAAC,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAU1E;IAEK,aAAa,CAAC,MAAM,EAAE,qBAAqB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAU5E;IAEK,YAAY,CACjB,IAAI,EAAE,cAAc,EACpB,MAAM,EAAE,gBAAgB,GACtB,OAAO,CAAC,YAAY,CAAC,CAuDvB;IAED,aAAa,IAAI,OAAO,CAEvB;IAED,kBAAkB,IAAI;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,cAAc,CAAA;KAAE,EAAE,CAEzE;CACD;AA2BD,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
|
package/dist/catalog.cjs
CHANGED
|
@@ -20,6 +20,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/catalog.ts
|
|
21
21
|
var catalog_exports = {};
|
|
22
22
|
__export(catalog_exports, {
|
|
23
|
+
DEFAULT_BROTU_API_URL: () => DEFAULT_BROTU_API_URL,
|
|
23
24
|
getAvailableModels: () => getAvailableModels,
|
|
24
25
|
getModel: () => getModel,
|
|
25
26
|
getModels: () => getModels,
|
|
@@ -995,8 +996,16 @@ var PROVIDER_BASE_URLS = {
|
|
|
995
996
|
elevenlabs: "https://api.elevenlabs.io",
|
|
996
997
|
google: "https://generativelanguage.googleapis.com",
|
|
997
998
|
openai: "https://api.openai.com",
|
|
998
|
-
qwen: "https://dashscope-intl.aliyuncs.com"
|
|
999
|
+
qwen: "https://dashscope-intl.aliyuncs.com",
|
|
1000
|
+
brotu: "https://api.brotu.app"
|
|
999
1001
|
};
|
|
1002
|
+
var DEFAULT_BROTU_API_URL = PROVIDER_BASE_URLS.brotu;
|
|
1003
|
+
function vendorProviders(options) {
|
|
1004
|
+
return options.providers ?? {};
|
|
1005
|
+
}
|
|
1006
|
+
function brotuApiKey(options) {
|
|
1007
|
+
return options.apiKey?.trim() || void 0;
|
|
1008
|
+
}
|
|
1000
1009
|
var BUILT_IN = [
|
|
1001
1010
|
...KLING_CATALOG,
|
|
1002
1011
|
...KLING_AUDIO_CATALOG,
|
|
@@ -1052,28 +1061,41 @@ function resolveProvider(modelId, options) {
|
|
|
1052
1061
|
`Model "${modelId}" declares no provider, so nothing knows how to run it.`
|
|
1053
1062
|
);
|
|
1054
1063
|
}
|
|
1055
|
-
const configured = options
|
|
1056
|
-
if (
|
|
1057
|
-
const
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1064
|
+
const configured = vendorProviders(options)[id];
|
|
1065
|
+
if (configured) {
|
|
1066
|
+
const baseUrl = configured.baseUrl ?? PROVIDER_BASE_URLS[id];
|
|
1067
|
+
if (!baseUrl) {
|
|
1068
|
+
throw new Error(
|
|
1069
|
+
`Provider "${id}" has no known base URL \u2014 pass providers.${id}.baseUrl.`
|
|
1070
|
+
);
|
|
1071
|
+
}
|
|
1072
|
+
return { id, apiKey: configured.apiKey, baseUrl: baseUrl.replace(/\/$/, "") };
|
|
1061
1073
|
}
|
|
1062
|
-
const
|
|
1063
|
-
if (
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1074
|
+
const platformKey = brotuApiKey(options);
|
|
1075
|
+
if (platformKey) {
|
|
1076
|
+
return {
|
|
1077
|
+
id: "brotu",
|
|
1078
|
+
apiKey: platformKey,
|
|
1079
|
+
baseUrl: (options.apiUrl ?? DEFAULT_BROTU_API_URL).replace(/\/$/, "")
|
|
1080
|
+
};
|
|
1067
1081
|
}
|
|
1068
|
-
|
|
1082
|
+
const owned = Object.keys(vendorProviders(options)).join(", ") || "none";
|
|
1083
|
+
throw new Error(
|
|
1084
|
+
`Model "${modelId}" runs on "${id}", but no API key was given for it (configured: ${owned}). Pass a Brotu key to generate on the platform.`
|
|
1085
|
+
);
|
|
1069
1086
|
}
|
|
1070
1087
|
function getAvailableModels(options) {
|
|
1088
|
+
if (brotuApiKey(options)) {
|
|
1089
|
+
return catalog.filter((model) => Boolean(model.provider));
|
|
1090
|
+
}
|
|
1091
|
+
const vendors = vendorProviders(options);
|
|
1071
1092
|
return catalog.filter(
|
|
1072
|
-
(model) => model.provider && model.provider in
|
|
1093
|
+
(model) => model.provider && model.provider in vendors
|
|
1073
1094
|
);
|
|
1074
1095
|
}
|
|
1075
1096
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1076
1097
|
0 && (module.exports = {
|
|
1098
|
+
DEFAULT_BROTU_API_URL,
|
|
1077
1099
|
getAvailableModels,
|
|
1078
1100
|
getModel,
|
|
1079
1101
|
getModels,
|
package/dist/catalog.d.ts
CHANGED
package/dist/catalog.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAU7D,OAAO,KAAK,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAU7D,OAAO,KAAK,EAAE,cAAc,EAAkB,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAgBhF,eAAO,MAAM,qBAAqB,QAA2B,CAAC;AA+B9D;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,MAAM,GAAE,aAAa,EAAO,GAAG,IAAI,CAUjE;AAED,0EAA0E;AAC1E,wBAAgB,YAAY,IAAI,IAAI,CAGnC;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAEnE;AAED,wBAAgB,SAAS,IAAI,aAAa,EAAE,CAE3C;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEjD;AAED,wDAAwD;AACxD,wBAAgB,YAAY,IAAI,MAAM,EAAE,CAQvC;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAC9B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,cAAc,GACrB,gBAAgB,CAqClB;AAED,wEAAwE;AACxE,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,cAAc,GAAG,aAAa,EAAE,CAQ3E"}
|
package/dist/catalog.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
+
DEFAULT_BROTU_API_URL,
|
|
2
3
|
getAvailableModels,
|
|
3
4
|
getModel,
|
|
4
5
|
getModels,
|
|
@@ -7,8 +8,9 @@ import {
|
|
|
7
8
|
registerModels,
|
|
8
9
|
resetCatalog,
|
|
9
10
|
resolveProvider
|
|
10
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-QOWHHKSI.js";
|
|
11
12
|
export {
|
|
13
|
+
DEFAULT_BROTU_API_URL,
|
|
12
14
|
getAvailableModels,
|
|
13
15
|
getModel,
|
|
14
16
|
getModels,
|
|
@@ -1159,8 +1159,16 @@ var PROVIDER_BASE_URLS = {
|
|
|
1159
1159
|
elevenlabs: "https://api.elevenlabs.io",
|
|
1160
1160
|
google: "https://generativelanguage.googleapis.com",
|
|
1161
1161
|
openai: "https://api.openai.com",
|
|
1162
|
-
qwen: "https://dashscope-intl.aliyuncs.com"
|
|
1162
|
+
qwen: "https://dashscope-intl.aliyuncs.com",
|
|
1163
|
+
brotu: "https://api.brotu.app"
|
|
1163
1164
|
};
|
|
1165
|
+
var DEFAULT_BROTU_API_URL = PROVIDER_BASE_URLS.brotu;
|
|
1166
|
+
function vendorProviders(options) {
|
|
1167
|
+
return options.providers ?? {};
|
|
1168
|
+
}
|
|
1169
|
+
function brotuApiKey(options) {
|
|
1170
|
+
return options.apiKey?.trim() || void 0;
|
|
1171
|
+
}
|
|
1164
1172
|
var BUILT_IN = [
|
|
1165
1173
|
...KLING_CATALOG,
|
|
1166
1174
|
...KLING_AUDIO_CATALOG,
|
|
@@ -1216,24 +1224,36 @@ function resolveProvider(modelId, options) {
|
|
|
1216
1224
|
`Model "${modelId}" declares no provider, so nothing knows how to run it.`
|
|
1217
1225
|
);
|
|
1218
1226
|
}
|
|
1219
|
-
const configured = options
|
|
1220
|
-
if (
|
|
1221
|
-
const
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1227
|
+
const configured = vendorProviders(options)[id];
|
|
1228
|
+
if (configured) {
|
|
1229
|
+
const baseUrl = configured.baseUrl ?? PROVIDER_BASE_URLS[id];
|
|
1230
|
+
if (!baseUrl) {
|
|
1231
|
+
throw new Error(
|
|
1232
|
+
`Provider "${id}" has no known base URL \u2014 pass providers.${id}.baseUrl.`
|
|
1233
|
+
);
|
|
1234
|
+
}
|
|
1235
|
+
return { id, apiKey: configured.apiKey, baseUrl: baseUrl.replace(/\/$/, "") };
|
|
1225
1236
|
}
|
|
1226
|
-
const
|
|
1227
|
-
if (
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1237
|
+
const platformKey = brotuApiKey(options);
|
|
1238
|
+
if (platformKey) {
|
|
1239
|
+
return {
|
|
1240
|
+
id: "brotu",
|
|
1241
|
+
apiKey: platformKey,
|
|
1242
|
+
baseUrl: (options.apiUrl ?? DEFAULT_BROTU_API_URL).replace(/\/$/, "")
|
|
1243
|
+
};
|
|
1231
1244
|
}
|
|
1232
|
-
|
|
1245
|
+
const owned = Object.keys(vendorProviders(options)).join(", ") || "none";
|
|
1246
|
+
throw new Error(
|
|
1247
|
+
`Model "${modelId}" runs on "${id}", but no API key was given for it (configured: ${owned}). Pass a Brotu key to generate on the platform.`
|
|
1248
|
+
);
|
|
1233
1249
|
}
|
|
1234
1250
|
function getAvailableModels(options) {
|
|
1251
|
+
if (brotuApiKey(options)) {
|
|
1252
|
+
return catalog.filter((model) => Boolean(model.provider));
|
|
1253
|
+
}
|
|
1254
|
+
const vendors = vendorProviders(options);
|
|
1235
1255
|
return catalog.filter(
|
|
1236
|
-
(model) => model.provider && model.provider in
|
|
1256
|
+
(model) => model.provider && model.provider in vendors
|
|
1237
1257
|
);
|
|
1238
1258
|
}
|
|
1239
1259
|
|
|
@@ -1266,6 +1286,7 @@ export {
|
|
|
1266
1286
|
QWEN_AUDIO_MODELS,
|
|
1267
1287
|
QWEN_TEXT_MODELS,
|
|
1268
1288
|
QWEN_CATALOG,
|
|
1289
|
+
DEFAULT_BROTU_API_URL,
|
|
1269
1290
|
registerModels,
|
|
1270
1291
|
resetCatalog,
|
|
1271
1292
|
getModel,
|
package/dist/client.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { getModel } from "./catalog";
|
|
|
2
2
|
import type { AIModelConfig } from "./constants/model.types";
|
|
3
3
|
import { type AIError, type Generation, type Result } from "./helpers/result";
|
|
4
4
|
import { type Job, type JobSnapshot } from "./lib/jobs";
|
|
5
|
+
import { type WebhookConfig } from "./lib/webhook";
|
|
5
6
|
import type { AudioGenerationParams, CostEstimate, GenerationOutput, GenerationParams, GenerationType, ImageGenerationParams, TextGenerationParams, VideoGenerationParams } from "./ports/content-generator.port";
|
|
6
7
|
import { type AvatarInput, type ImageOmniInput, type MotionControlInput, type OmniVideoInput, type OutpaintingInput } from "./providers/kling.models";
|
|
7
8
|
import type { BrotuAIOptions } from "./types";
|
|
@@ -35,6 +36,15 @@ export interface BrotuAI {
|
|
|
35
36
|
timeoutMs?: number;
|
|
36
37
|
}): Promise<Result<Generation>>;
|
|
37
38
|
};
|
|
39
|
+
/**
|
|
40
|
+
* URL the client POSTs when a generation settles. Register at construction
|
|
41
|
+
* (`webhook:`) or here later. A down hook never fails the generation.
|
|
42
|
+
*/
|
|
43
|
+
webhook: {
|
|
44
|
+
set(value: string | WebhookConfig): void;
|
|
45
|
+
clear(): void;
|
|
46
|
+
get(): WebhookConfig | undefined;
|
|
47
|
+
};
|
|
38
48
|
/**
|
|
39
49
|
* Google capabilities with no portable equivalent. Present only when a google
|
|
40
50
|
* key is configured.
|
|
@@ -71,7 +81,7 @@ export interface BrotuAI {
|
|
|
71
81
|
/** Compose or edit across up to ten references. */
|
|
72
82
|
imageOmni(input: ImageOmniInput): Promise<Result<Job>>;
|
|
73
83
|
};
|
|
74
|
-
/** Models
|
|
84
|
+
/** Models this client can run. */
|
|
75
85
|
models(): AIModelConfig[];
|
|
76
86
|
/**
|
|
77
87
|
* What this generation will be billed for, before running it. Always reports
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/helpers/result.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { GenerationOutput } from "../ports/content-generator.port";
|
|
|
2
2
|
export type AIErrorCode =
|
|
3
3
|
/** The model id is not in the catalog. */
|
|
4
4
|
"unknown_model"
|
|
5
|
-
/** The model's provider has no
|
|
5
|
+
/** The model's provider has no vendor key and no Brotu key. */
|
|
6
6
|
| "missing_key"
|
|
7
7
|
/** No adapter ships for that provider. */
|
|
8
8
|
| "unsupported_provider"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"result.d.ts","sourceRoot":"","sources":["../../src/helpers/result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAExE,MAAM,MAAM,WAAW;AACtB,0CAA0C;AACxC,eAAe;AACjB
|
|
1
|
+
{"version":3,"file":"result.d.ts","sourceRoot":"","sources":["../../src/helpers/result.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAExE,MAAM,MAAM,WAAW;AACtB,0CAA0C;AACxC,eAAe;AACjB,+DAA+D;GAC7D,aAAa;AACf,0CAA0C;GACxC,sBAAsB;AACxB,kEAAkE;GAChE,iBAAiB;AACnB,yEAAyE;GACvE,gBAAgB;AAClB,2EAA2E;GACzE,SAAS,CAAC;AAEb,MAAM,WAAW,OAAO;IACvB,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wDAAwD;IACxD,KAAK,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,MAAM,CAAC,CAAC,IACjB;IAAE,IAAI,EAAE,CAAC,CAAC;IAAC,KAAK,EAAE,IAAI,CAAA;CAAE,GACxB;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,OAAO,CAAA;CAAE,CAAC;AAElC,wBAAgB,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAExC;AAED,wBAAgB,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,CAEjD;AAED,gFAAgF;AAChF,wBAAgB,QAAQ,CAAC,CAAC,EACzB,IAAI,EAAE,WAAW,EACjB,KAAK,EAAE,OAAO,EACd,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7C,MAAM,CAAC,CAAC,CAAC,CAOX;AAED,iFAAiF;AACjF,MAAM,WAAW,UAAU;IAC1B,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,MAAM,CAAC;IACzB,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC"}
|