@ai-sdk/black-forest-labs 0.0.1

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/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ # @ai-sdk/black-forest-labs
2
+
3
+ ## 0.0.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 79fcc84: feat(black-forest-labs): initial version
package/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2023 Vercel, Inc.
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
package/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # AI SDK - Black Forest Labs Provider
2
+
3
+ The **[Black Forest Labs provider](https://ai-sdk.dev/providers/ai-sdk-providers/black-forest-labs)** for the [AI SDK](https://ai-sdk.dev/docs) adds image model support for the [Black Forest Labs API](https://docs.bfl.ai/).
4
+
5
+ ## Setup
6
+
7
+ The Black Forest Labs provider is available in the `@ai-sdk/black-forest-labs` module. You can install it with
8
+
9
+ ```bash
10
+ pnpm add @ai-sdk/black-forest-labs
11
+ ```
12
+
13
+ ## Provider Instance
14
+
15
+ You can import the default provider instance `blackForestLabs` from `@ai-sdk/black-forest-labs`:
16
+
17
+ ```ts
18
+ import { blackForestLabs } from '@ai-sdk/black-forest-labs';
19
+ ```
20
+
21
+ ## Image Generation Example
22
+
23
+ ```ts
24
+ import fs from 'node:fs';
25
+ import { blackForestLabs } from '@ai-sdk/black-forest-labs';
26
+ import { experimental_generateImage as generateImage } from 'ai';
27
+
28
+ const { image } = await generateImage({
29
+ model: blackForestLabs.image('flux-pro-1.1'),
30
+ prompt: 'A cat wearing a intricate robe',
31
+ });
32
+
33
+ const filename = `image-${Date.now()}.png`;
34
+ fs.writeFileSync(filename, image.uint8Array);
35
+ console.log(`Image saved to ${filename}`);
36
+ ```
37
+
38
+ ## Additional Options
39
+
40
+ If you want to pass additional inputs to the model besides the prompt, use the `providerOptions.blackForestLabs` property:
41
+
42
+ ```ts
43
+ import {
44
+ blackForestLabs,
45
+ type BlackForestLabsImageProviderOptions,
46
+ } from '@ai-sdk/black-forest-labs';
47
+ import { experimental_generateImage as generateImage } from 'ai';
48
+
49
+ const { image } = await generateImage({
50
+ model: blackForestLabs.image('flux-pro-1.1'),
51
+ prompt: 'A cat wearing an intricate robe',
52
+ aspectRatio: '16:9',
53
+ providerOptions: {
54
+ blackForestLabs: {
55
+ seed: 42,
56
+ } satisfies BlackForestLabsImageProviderOptions,
57
+ },
58
+ });
59
+ ```
60
+
61
+ ## Configuring Base URL
62
+
63
+ By default, the provider uses `https://api.bfl.ai/v1`. You can override this to use regional or legacy endpoints:
64
+
65
+ ```ts
66
+ import { createBlackForestLabs } from '@ai-sdk/black-forest-labs';
67
+
68
+ const blackForestLabs = createBlackForestLabs({
69
+ baseURL: 'https://api.eu.bfl.ai/v1',
70
+ apiKey: process.env.BFL_API_KEY,
71
+ });
72
+ ```
73
+
74
+ ## Documentation
75
+
76
+ See the [Black Forest Labs provider](https://ai-sdk.dev/providers/ai-sdk-providers/black-forest-labs) for more information.
@@ -0,0 +1,55 @@
1
+ import { ProviderV2, ImageModelV2 } from '@ai-sdk/provider';
2
+ import * as _ai_sdk_provider_utils from '@ai-sdk/provider-utils';
3
+ import { FetchFunction, InferValidator } from '@ai-sdk/provider-utils';
4
+
5
+ type BlackForestLabsImageModelId = 'flux-kontext-pro' | 'flux-kontext-max' | 'flux-pro-1.1-ultra' | 'flux-pro-1.1' | 'flux-pro-1.0-fill' | (string & {});
6
+ type BlackForestLabsAspectRatio = `${number}:${number}`;
7
+
8
+ interface BlackForestLabsProviderSettings {
9
+ /**
10
+ Black Forest Labs API key. Default value is taken from the `BFL_API_KEY` environment variable.
11
+ */
12
+ apiKey?: string;
13
+ /**
14
+ Base URL for the API calls. Defaults to `https://api.bfl.ai/v1`.
15
+ */
16
+ baseURL?: string;
17
+ /**
18
+ Custom headers to include in the requests.
19
+ */
20
+ headers?: Record<string, string>;
21
+ /**
22
+ Custom fetch implementation. You can use it as a middleware to intercept
23
+ requests, or to provide a custom fetch implementation for e.g. testing.
24
+ */
25
+ fetch?: FetchFunction;
26
+ }
27
+ interface BlackForestLabsProvider extends ProviderV2 {
28
+ /**
29
+ Creates a model for image generation.
30
+ */
31
+ image(modelId: BlackForestLabsImageModelId): ImageModelV2;
32
+ /**
33
+ Creates a model for image generation.
34
+ */
35
+ imageModel(modelId: BlackForestLabsImageModelId): ImageModelV2;
36
+ }
37
+ declare function createBlackForestLabs(options?: BlackForestLabsProviderSettings): BlackForestLabsProvider;
38
+ declare const blackForestLabs: BlackForestLabsProvider;
39
+
40
+ declare const blackForestLabsImageProviderOptionsSchema: _ai_sdk_provider_utils.LazySchema<{
41
+ imagePrompt?: string | undefined;
42
+ imagePromptStrength?: number | undefined;
43
+ inputImage?: string | undefined;
44
+ outputFormat?: "jpeg" | "png" | undefined;
45
+ promptUpsampling?: boolean | undefined;
46
+ raw?: boolean | undefined;
47
+ safetyTolerance?: number | undefined;
48
+ webhookSecret?: string | undefined;
49
+ webhookUrl?: string | undefined;
50
+ }>;
51
+ type BlackForestLabsImageProviderOptions = InferValidator<typeof blackForestLabsImageProviderOptionsSchema>;
52
+
53
+ declare const VERSION: string;
54
+
55
+ export { type BlackForestLabsAspectRatio, type BlackForestLabsImageModelId, type BlackForestLabsImageProviderOptions, type BlackForestLabsProvider, type BlackForestLabsProviderSettings, VERSION, blackForestLabs, createBlackForestLabs };
@@ -0,0 +1,55 @@
1
+ import { ProviderV2, ImageModelV2 } from '@ai-sdk/provider';
2
+ import * as _ai_sdk_provider_utils from '@ai-sdk/provider-utils';
3
+ import { FetchFunction, InferValidator } from '@ai-sdk/provider-utils';
4
+
5
+ type BlackForestLabsImageModelId = 'flux-kontext-pro' | 'flux-kontext-max' | 'flux-pro-1.1-ultra' | 'flux-pro-1.1' | 'flux-pro-1.0-fill' | (string & {});
6
+ type BlackForestLabsAspectRatio = `${number}:${number}`;
7
+
8
+ interface BlackForestLabsProviderSettings {
9
+ /**
10
+ Black Forest Labs API key. Default value is taken from the `BFL_API_KEY` environment variable.
11
+ */
12
+ apiKey?: string;
13
+ /**
14
+ Base URL for the API calls. Defaults to `https://api.bfl.ai/v1`.
15
+ */
16
+ baseURL?: string;
17
+ /**
18
+ Custom headers to include in the requests.
19
+ */
20
+ headers?: Record<string, string>;
21
+ /**
22
+ Custom fetch implementation. You can use it as a middleware to intercept
23
+ requests, or to provide a custom fetch implementation for e.g. testing.
24
+ */
25
+ fetch?: FetchFunction;
26
+ }
27
+ interface BlackForestLabsProvider extends ProviderV2 {
28
+ /**
29
+ Creates a model for image generation.
30
+ */
31
+ image(modelId: BlackForestLabsImageModelId): ImageModelV2;
32
+ /**
33
+ Creates a model for image generation.
34
+ */
35
+ imageModel(modelId: BlackForestLabsImageModelId): ImageModelV2;
36
+ }
37
+ declare function createBlackForestLabs(options?: BlackForestLabsProviderSettings): BlackForestLabsProvider;
38
+ declare const blackForestLabs: BlackForestLabsProvider;
39
+
40
+ declare const blackForestLabsImageProviderOptionsSchema: _ai_sdk_provider_utils.LazySchema<{
41
+ imagePrompt?: string | undefined;
42
+ imagePromptStrength?: number | undefined;
43
+ inputImage?: string | undefined;
44
+ outputFormat?: "jpeg" | "png" | undefined;
45
+ promptUpsampling?: boolean | undefined;
46
+ raw?: boolean | undefined;
47
+ safetyTolerance?: number | undefined;
48
+ webhookSecret?: string | undefined;
49
+ webhookUrl?: string | undefined;
50
+ }>;
51
+ type BlackForestLabsImageProviderOptions = InferValidator<typeof blackForestLabsImageProviderOptionsSchema>;
52
+
53
+ declare const VERSION: string;
54
+
55
+ export { type BlackForestLabsAspectRatio, type BlackForestLabsImageModelId, type BlackForestLabsImageProviderOptions, type BlackForestLabsProvider, type BlackForestLabsProviderSettings, VERSION, blackForestLabs, createBlackForestLabs };
package/dist/index.js ADDED
@@ -0,0 +1,353 @@
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/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ VERSION: () => VERSION,
24
+ blackForestLabs: () => blackForestLabs,
25
+ createBlackForestLabs: () => createBlackForestLabs
26
+ });
27
+ module.exports = __toCommonJS(src_exports);
28
+
29
+ // src/black-forest-labs-provider.ts
30
+ var import_provider = require("@ai-sdk/provider");
31
+ var import_provider_utils2 = require("@ai-sdk/provider-utils");
32
+
33
+ // src/black-forest-labs-image-model.ts
34
+ var import_provider_utils = require("@ai-sdk/provider-utils");
35
+ var import_v4 = require("zod/v4");
36
+ var DEFAULT_POLL_INTERVAL_MILLIS = 500;
37
+ var DEFAULT_MAX_POLL_ATTEMPTS = 6e4 / DEFAULT_POLL_INTERVAL_MILLIS;
38
+ var BlackForestLabsImageModel = class {
39
+ constructor(modelId, config) {
40
+ this.modelId = modelId;
41
+ this.config = config;
42
+ this.specificationVersion = "v2";
43
+ this.maxImagesPerCall = 1;
44
+ }
45
+ get provider() {
46
+ return this.config.provider;
47
+ }
48
+ async getArgs({
49
+ prompt,
50
+ size,
51
+ aspectRatio,
52
+ seed,
53
+ providerOptions
54
+ }) {
55
+ var _a;
56
+ const warnings = [];
57
+ const finalAspectRatio = aspectRatio != null ? aspectRatio : size ? convertSizeToAspectRatio(size) : void 0;
58
+ if (size && !aspectRatio) {
59
+ warnings.push({
60
+ type: "unsupported-setting",
61
+ setting: "size",
62
+ details: "Deriving aspect_ratio from size."
63
+ });
64
+ } else if (size && aspectRatio) {
65
+ warnings.push({
66
+ type: "unsupported-setting",
67
+ setting: "size",
68
+ details: "Black Forest Labs ignores size when aspectRatio is provided."
69
+ });
70
+ }
71
+ const bflOptions = await (0, import_provider_utils.parseProviderOptions)({
72
+ provider: "blackForestLabs",
73
+ providerOptions,
74
+ schema: blackForestLabsImageProviderOptionsSchema
75
+ });
76
+ const [widthStr, heightStr] = (_a = size == null ? void 0 : size.split("x")) != null ? _a : [];
77
+ const body = {
78
+ prompt,
79
+ seed,
80
+ aspect_ratio: finalAspectRatio,
81
+ ...size && { width: Number(widthStr), height: Number(heightStr) },
82
+ image_prompt_strength: bflOptions == null ? void 0 : bflOptions.imagePromptStrength,
83
+ image_prompt: bflOptions == null ? void 0 : bflOptions.imagePrompt,
84
+ input_image: bflOptions == null ? void 0 : bflOptions.inputImage,
85
+ output_format: bflOptions == null ? void 0 : bflOptions.outputFormat,
86
+ prompt_upsampling: bflOptions == null ? void 0 : bflOptions.promptUpsampling,
87
+ raw: bflOptions == null ? void 0 : bflOptions.raw,
88
+ safety_tolerance: bflOptions == null ? void 0 : bflOptions.safetyTolerance,
89
+ webhook_secret: bflOptions == null ? void 0 : bflOptions.webhookSecret,
90
+ webhook_url: bflOptions == null ? void 0 : bflOptions.webhookUrl
91
+ };
92
+ return { body, warnings };
93
+ }
94
+ async doGenerate({
95
+ prompt,
96
+ size,
97
+ aspectRatio,
98
+ seed,
99
+ providerOptions,
100
+ headers,
101
+ abortSignal
102
+ }) {
103
+ var _a, _b, _c;
104
+ const { body, warnings } = await this.getArgs({
105
+ prompt,
106
+ size,
107
+ aspectRatio,
108
+ seed,
109
+ providerOptions,
110
+ n: 1,
111
+ headers,
112
+ abortSignal
113
+ });
114
+ const currentDate = (_c = (_b = (_a = this.config._internal) == null ? void 0 : _a.currentDate) == null ? void 0 : _b.call(_a)) != null ? _c : /* @__PURE__ */ new Date();
115
+ const combinedHeaders = (0, import_provider_utils.combineHeaders)(
116
+ await (0, import_provider_utils.resolve)(this.config.headers),
117
+ headers
118
+ );
119
+ const submit = await (0, import_provider_utils.postJsonToApi)({
120
+ url: `${this.config.baseURL}/${this.modelId}`,
121
+ headers: combinedHeaders,
122
+ body,
123
+ failedResponseHandler: bflFailedResponseHandler,
124
+ successfulResponseHandler: (0, import_provider_utils.createJsonResponseHandler)(bflSubmitSchema),
125
+ abortSignal,
126
+ fetch: this.config.fetch
127
+ });
128
+ const pollUrl = submit.value.polling_url;
129
+ const requestId = submit.value.id;
130
+ const {
131
+ imageUrl,
132
+ seed: resultSeed,
133
+ start_time: resultStartTime,
134
+ end_time: resultEndTime,
135
+ duration: resultDuration
136
+ } = await this.pollForImageUrl({
137
+ pollUrl,
138
+ requestId,
139
+ headers: combinedHeaders,
140
+ abortSignal
141
+ });
142
+ const { value: imageBytes, responseHeaders } = await (0, import_provider_utils.getFromApi)({
143
+ url: imageUrl,
144
+ headers: combinedHeaders,
145
+ abortSignal,
146
+ failedResponseHandler: (0, import_provider_utils.createStatusCodeErrorResponseHandler)(),
147
+ successfulResponseHandler: (0, import_provider_utils.createBinaryResponseHandler)(),
148
+ fetch: this.config.fetch
149
+ });
150
+ return {
151
+ images: [imageBytes],
152
+ warnings,
153
+ providerMetadata: {
154
+ blackForestLabs: {
155
+ images: [
156
+ {
157
+ ...resultSeed != null && { seed: resultSeed },
158
+ ...resultStartTime != null && { start_time: resultStartTime },
159
+ ...resultEndTime != null && { end_time: resultEndTime },
160
+ ...resultDuration != null && { duration: resultDuration }
161
+ }
162
+ ]
163
+ }
164
+ },
165
+ response: {
166
+ modelId: this.modelId,
167
+ timestamp: currentDate,
168
+ headers: responseHeaders
169
+ }
170
+ };
171
+ }
172
+ async pollForImageUrl({
173
+ pollUrl,
174
+ requestId,
175
+ headers,
176
+ abortSignal
177
+ }) {
178
+ var _a, _b, _c, _d, _e;
179
+ const url = new URL(pollUrl);
180
+ if (!url.searchParams.has("id")) {
181
+ url.searchParams.set("id", requestId);
182
+ }
183
+ for (let i = 0; i < DEFAULT_MAX_POLL_ATTEMPTS; i++) {
184
+ const { value } = await (0, import_provider_utils.getFromApi)({
185
+ url: url.toString(),
186
+ headers,
187
+ failedResponseHandler: bflFailedResponseHandler,
188
+ successfulResponseHandler: (0, import_provider_utils.createJsonResponseHandler)(bflPollSchema),
189
+ abortSignal,
190
+ fetch: this.config.fetch
191
+ });
192
+ const status = value.status;
193
+ if (status === "Ready") {
194
+ if (typeof ((_a = value.result) == null ? void 0 : _a.sample) === "string") {
195
+ return {
196
+ imageUrl: value.result.sample,
197
+ seed: (_b = value.result.seed) != null ? _b : void 0,
198
+ start_time: (_c = value.result.start_time) != null ? _c : void 0,
199
+ end_time: (_d = value.result.end_time) != null ? _d : void 0,
200
+ duration: (_e = value.result.duration) != null ? _e : void 0
201
+ };
202
+ }
203
+ throw new Error(
204
+ "Black Forest Labs poll response is Ready but missing result.sample"
205
+ );
206
+ }
207
+ if (status === "Error" || status === "Failed") {
208
+ throw new Error("Black Forest Labs generation failed.");
209
+ }
210
+ await (0, import_provider_utils.delay)(DEFAULT_POLL_INTERVAL_MILLIS);
211
+ }
212
+ throw new Error("Black Forest Labs generation timed out.");
213
+ }
214
+ };
215
+ var blackForestLabsImageProviderOptionsSchema = (0, import_provider_utils.lazySchema)(
216
+ () => (0, import_provider_utils.zodSchema)(
217
+ import_v4.z.object({
218
+ imagePrompt: import_v4.z.string().optional(),
219
+ imagePromptStrength: import_v4.z.number().min(0).max(1).optional(),
220
+ inputImage: import_v4.z.string().optional(),
221
+ outputFormat: import_v4.z.enum(["jpeg", "png"]).optional(),
222
+ promptUpsampling: import_v4.z.boolean().optional(),
223
+ raw: import_v4.z.boolean().optional(),
224
+ safetyTolerance: import_v4.z.number().int().min(0).max(6).optional(),
225
+ webhookSecret: import_v4.z.string().optional(),
226
+ webhookUrl: import_v4.z.url().optional()
227
+ })
228
+ )
229
+ );
230
+ function convertSizeToAspectRatio(size) {
231
+ const [wStr, hStr] = size.split("x");
232
+ const width = Number(wStr);
233
+ const height = Number(hStr);
234
+ if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
235
+ return void 0;
236
+ }
237
+ const g = gcd(width, height);
238
+ return `${Math.round(width / g)}:${Math.round(height / g)}`;
239
+ }
240
+ function gcd(a, b) {
241
+ let x = Math.abs(a);
242
+ let y = Math.abs(b);
243
+ while (y !== 0) {
244
+ const t = y;
245
+ y = x % y;
246
+ x = t;
247
+ }
248
+ return x;
249
+ }
250
+ var bflSubmitSchema = import_v4.z.object({
251
+ id: import_v4.z.string(),
252
+ polling_url: import_v4.z.url()
253
+ });
254
+ var bflStatus = import_v4.z.union([
255
+ import_v4.z.literal("Pending"),
256
+ import_v4.z.literal("Ready"),
257
+ import_v4.z.literal("Error"),
258
+ import_v4.z.literal("Failed")
259
+ ]);
260
+ var bflPollSchema = import_v4.z.object({
261
+ status: bflStatus.optional(),
262
+ state: bflStatus.optional(),
263
+ result: import_v4.z.object({
264
+ sample: import_v4.z.url(),
265
+ seed: import_v4.z.number().optional(),
266
+ start_time: import_v4.z.number().optional(),
267
+ end_time: import_v4.z.number().optional(),
268
+ duration: import_v4.z.number().optional()
269
+ }).nullish()
270
+ }).refine((v) => v.status != null || v.state != null, {
271
+ message: "Missing status in Black Forest Labs poll response"
272
+ }).transform((v) => {
273
+ var _a;
274
+ return {
275
+ status: (_a = v.status) != null ? _a : v.state,
276
+ result: v.result
277
+ };
278
+ });
279
+ var bflErrorSchema = import_v4.z.object({
280
+ message: import_v4.z.string().optional(),
281
+ detail: import_v4.z.any().optional()
282
+ });
283
+ var bflFailedResponseHandler = (0, import_provider_utils.createJsonErrorResponseHandler)({
284
+ errorSchema: bflErrorSchema,
285
+ errorToMessage: (error) => {
286
+ var _a;
287
+ return (_a = bflErrorToMessage(error)) != null ? _a : "Unknown Black Forest Labs error";
288
+ }
289
+ });
290
+ function bflErrorToMessage(error) {
291
+ const parsed = bflErrorSchema.safeParse(error);
292
+ if (!parsed.success) return void 0;
293
+ const { message, detail } = parsed.data;
294
+ if (typeof detail === "string") return detail;
295
+ if (detail != null) {
296
+ try {
297
+ return JSON.stringify(detail);
298
+ } catch (e) {
299
+ }
300
+ }
301
+ return message;
302
+ }
303
+
304
+ // src/version.ts
305
+ var VERSION = true ? "0.0.1" : "0.0.0-test";
306
+
307
+ // src/black-forest-labs-provider.ts
308
+ var defaultBaseURL = "https://api.bfl.ai/v1";
309
+ function createBlackForestLabs(options = {}) {
310
+ var _a;
311
+ const baseURL = (0, import_provider_utils2.withoutTrailingSlash)((_a = options.baseURL) != null ? _a : defaultBaseURL);
312
+ const getHeaders = () => (0, import_provider_utils2.withUserAgentSuffix)(
313
+ {
314
+ "x-key": (0, import_provider_utils2.loadApiKey)({
315
+ apiKey: options.apiKey,
316
+ environmentVariableName: "BFL_API_KEY",
317
+ description: "Black Forest Labs"
318
+ }),
319
+ ...options.headers
320
+ },
321
+ `ai-sdk/black-forest-labs/${VERSION}`
322
+ );
323
+ const createImageModel = (modelId) => new BlackForestLabsImageModel(modelId, {
324
+ provider: "black-forest-labs.image",
325
+ baseURL: baseURL != null ? baseURL : defaultBaseURL,
326
+ headers: getHeaders,
327
+ fetch: options.fetch
328
+ });
329
+ return {
330
+ imageModel: createImageModel,
331
+ image: createImageModel,
332
+ languageModel: () => {
333
+ throw new import_provider.NoSuchModelError({
334
+ modelId: "languageModel",
335
+ modelType: "languageModel"
336
+ });
337
+ },
338
+ textEmbeddingModel: () => {
339
+ throw new import_provider.NoSuchModelError({
340
+ modelId: "textEmbeddingModel",
341
+ modelType: "textEmbeddingModel"
342
+ });
343
+ }
344
+ };
345
+ }
346
+ var blackForestLabs = createBlackForestLabs();
347
+ // Annotate the CommonJS export names for ESM import in node:
348
+ 0 && (module.exports = {
349
+ VERSION,
350
+ blackForestLabs,
351
+ createBlackForestLabs
352
+ });
353
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/black-forest-labs-provider.ts","../src/black-forest-labs-image-model.ts","../src/version.ts"],"sourcesContent":["export {\n createBlackForestLabs,\n blackForestLabs,\n} from './black-forest-labs-provider';\nexport type {\n BlackForestLabsProvider,\n BlackForestLabsProviderSettings,\n} from './black-forest-labs-provider';\nexport type {\n BlackForestLabsImageModelId,\n BlackForestLabsAspectRatio,\n} from './black-forest-labs-image-settings';\nexport type { BlackForestLabsImageProviderOptions } from './black-forest-labs-image-model';\nexport { VERSION } from './version';\n","import { ImageModelV2, NoSuchModelError, ProviderV2 } from '@ai-sdk/provider';\nimport type { FetchFunction } from '@ai-sdk/provider-utils';\nimport {\n loadApiKey,\n withoutTrailingSlash,\n withUserAgentSuffix,\n} from '@ai-sdk/provider-utils';\nimport { BlackForestLabsImageModel } from './black-forest-labs-image-model';\nimport { BlackForestLabsImageModelId } from './black-forest-labs-image-settings';\nimport { VERSION } from './version';\n\nexport interface BlackForestLabsProviderSettings {\n /**\nBlack Forest Labs API key. Default value is taken from the `BFL_API_KEY` environment variable.\n */\n apiKey?: string;\n\n /**\nBase URL for the API calls. Defaults to `https://api.bfl.ai/v1`. \n */\n baseURL?: string;\n\n /**\nCustom headers to include in the requests.\n */\n headers?: Record<string, string>;\n\n /**\nCustom fetch implementation. You can use it as a middleware to intercept\nrequests, or to provide a custom fetch implementation for e.g. testing.\n */\n fetch?: FetchFunction;\n}\n\nexport interface BlackForestLabsProvider extends ProviderV2 {\n /**\nCreates a model for image generation.\n */\n image(modelId: BlackForestLabsImageModelId): ImageModelV2;\n\n /**\nCreates a model for image generation.\n */\n imageModel(modelId: BlackForestLabsImageModelId): ImageModelV2;\n}\n\nconst defaultBaseURL = 'https://api.bfl.ai/v1';\n\nexport function createBlackForestLabs(\n options: BlackForestLabsProviderSettings = {},\n): BlackForestLabsProvider {\n const baseURL = withoutTrailingSlash(options.baseURL ?? defaultBaseURL);\n const getHeaders = () =>\n withUserAgentSuffix(\n {\n 'x-key': loadApiKey({\n apiKey: options.apiKey,\n environmentVariableName: 'BFL_API_KEY',\n description: 'Black Forest Labs',\n }),\n ...options.headers,\n },\n `ai-sdk/black-forest-labs/${VERSION}`,\n );\n\n const createImageModel = (modelId: BlackForestLabsImageModelId) =>\n new BlackForestLabsImageModel(modelId, {\n provider: 'black-forest-labs.image',\n baseURL: baseURL ?? defaultBaseURL,\n headers: getHeaders,\n fetch: options.fetch,\n });\n\n return {\n imageModel: createImageModel,\n image: createImageModel,\n languageModel: () => {\n throw new NoSuchModelError({\n modelId: 'languageModel',\n modelType: 'languageModel',\n });\n },\n textEmbeddingModel: () => {\n throw new NoSuchModelError({\n modelId: 'textEmbeddingModel',\n modelType: 'textEmbeddingModel',\n });\n },\n };\n}\n\nexport const blackForestLabs = createBlackForestLabs();\n","import type { ImageModelV2, ImageModelV2CallWarning } from '@ai-sdk/provider';\nimport type { InferValidator, Resolvable } from '@ai-sdk/provider-utils';\nimport {\n FetchFunction,\n combineHeaders,\n createBinaryResponseHandler,\n createJsonErrorResponseHandler,\n createJsonResponseHandler,\n createStatusCodeErrorResponseHandler,\n delay,\n getFromApi,\n lazySchema,\n parseProviderOptions,\n postJsonToApi,\n resolve,\n zodSchema,\n} from '@ai-sdk/provider-utils';\nimport { z } from 'zod/v4';\nimport type { BlackForestLabsAspectRatio } from './black-forest-labs-image-settings';\nimport { BlackForestLabsImageModelId } from './black-forest-labs-image-settings';\n\nconst DEFAULT_POLL_INTERVAL_MILLIS = 500;\nconst DEFAULT_MAX_POLL_ATTEMPTS = 60000 / DEFAULT_POLL_INTERVAL_MILLIS;\n\ninterface BlackForestLabsImageModelConfig {\n provider: string;\n baseURL: string;\n headers?: Resolvable<Record<string, string | undefined>>;\n fetch?: FetchFunction;\n _internal?: {\n currentDate?: () => Date;\n };\n}\n\nexport class BlackForestLabsImageModel implements ImageModelV2 {\n readonly specificationVersion = 'v2';\n readonly maxImagesPerCall = 1;\n\n get provider(): string {\n return this.config.provider;\n }\n\n constructor(\n readonly modelId: BlackForestLabsImageModelId,\n private readonly config: BlackForestLabsImageModelConfig,\n ) {}\n\n private async getArgs({\n prompt,\n size,\n aspectRatio,\n seed,\n providerOptions,\n }: Parameters<ImageModelV2['doGenerate']>[0]) {\n const warnings: Array<ImageModelV2CallWarning> = [];\n\n const finalAspectRatio =\n aspectRatio ?? (size ? convertSizeToAspectRatio(size) : undefined);\n\n if (size && !aspectRatio) {\n warnings.push({\n type: 'unsupported-setting',\n setting: 'size',\n details: 'Deriving aspect_ratio from size.',\n });\n } else if (size && aspectRatio) {\n warnings.push({\n type: 'unsupported-setting',\n setting: 'size',\n details: 'Black Forest Labs ignores size when aspectRatio is provided.',\n });\n }\n\n const bflOptions = await parseProviderOptions({\n provider: 'blackForestLabs',\n providerOptions,\n schema: blackForestLabsImageProviderOptionsSchema,\n });\n\n const [widthStr, heightStr] = size?.split('x') ?? [];\n\n const body: Record<string, unknown> = {\n prompt,\n seed,\n aspect_ratio: finalAspectRatio,\n ...(size && { width: Number(widthStr), height: Number(heightStr) }),\n image_prompt_strength: bflOptions?.imagePromptStrength,\n image_prompt: bflOptions?.imagePrompt,\n input_image: bflOptions?.inputImage,\n output_format: bflOptions?.outputFormat,\n prompt_upsampling: bflOptions?.promptUpsampling,\n raw: bflOptions?.raw,\n safety_tolerance: bflOptions?.safetyTolerance,\n webhook_secret: bflOptions?.webhookSecret,\n webhook_url: bflOptions?.webhookUrl,\n };\n\n return { body, warnings };\n }\n\n async doGenerate({\n prompt,\n size,\n aspectRatio,\n seed,\n providerOptions,\n headers,\n abortSignal,\n }: Parameters<ImageModelV2['doGenerate']>[0]): Promise<\n Awaited<ReturnType<ImageModelV2['doGenerate']>>\n > {\n const { body, warnings } = await this.getArgs({\n prompt,\n size,\n aspectRatio,\n seed,\n providerOptions,\n n: 1,\n headers,\n abortSignal,\n } as Parameters<ImageModelV2['doGenerate']>[0]);\n\n const currentDate = this.config._internal?.currentDate?.() ?? new Date();\n const combinedHeaders = combineHeaders(\n await resolve(this.config.headers),\n headers,\n );\n\n const submit = await postJsonToApi({\n url: `${this.config.baseURL}/${this.modelId}`,\n headers: combinedHeaders,\n body,\n failedResponseHandler: bflFailedResponseHandler,\n successfulResponseHandler: createJsonResponseHandler(bflSubmitSchema),\n abortSignal,\n fetch: this.config.fetch,\n });\n\n const pollUrl = submit.value.polling_url;\n const requestId = submit.value.id;\n\n const {\n imageUrl,\n seed: resultSeed,\n start_time: resultStartTime,\n end_time: resultEndTime,\n duration: resultDuration,\n } = await this.pollForImageUrl({\n pollUrl,\n requestId,\n headers: combinedHeaders,\n abortSignal,\n });\n\n const { value: imageBytes, responseHeaders } = await getFromApi({\n url: imageUrl,\n headers: combinedHeaders,\n abortSignal,\n failedResponseHandler: createStatusCodeErrorResponseHandler(),\n successfulResponseHandler: createBinaryResponseHandler(),\n fetch: this.config.fetch,\n });\n\n return {\n images: [imageBytes],\n warnings,\n providerMetadata: {\n blackForestLabs: {\n images: [\n {\n ...(resultSeed != null && { seed: resultSeed }),\n ...(resultStartTime != null && { start_time: resultStartTime }),\n ...(resultEndTime != null && { end_time: resultEndTime }),\n ...(resultDuration != null && { duration: resultDuration }),\n },\n ],\n },\n },\n response: {\n modelId: this.modelId,\n timestamp: currentDate,\n headers: responseHeaders,\n },\n };\n }\n\n private async pollForImageUrl({\n pollUrl,\n requestId,\n headers,\n abortSignal,\n }: {\n pollUrl: string;\n requestId: string;\n headers: Record<string, string | undefined>;\n abortSignal: AbortSignal | undefined;\n }): Promise<{\n imageUrl: string;\n seed?: number;\n start_time?: number;\n end_time?: number;\n duration?: number;\n }> {\n const url = new URL(pollUrl);\n if (!url.searchParams.has('id')) {\n url.searchParams.set('id', requestId);\n }\n\n for (let i = 0; i < DEFAULT_MAX_POLL_ATTEMPTS; i++) {\n const { value } = await getFromApi({\n url: url.toString(),\n headers,\n failedResponseHandler: bflFailedResponseHandler,\n successfulResponseHandler: createJsonResponseHandler(bflPollSchema),\n abortSignal,\n fetch: this.config.fetch,\n });\n\n const status = value.status;\n if (status === 'Ready') {\n if (typeof value.result?.sample === 'string') {\n return {\n imageUrl: value.result.sample,\n seed: value.result.seed ?? undefined,\n start_time: value.result.start_time ?? undefined,\n end_time: value.result.end_time ?? undefined,\n duration: value.result.duration ?? undefined,\n };\n }\n throw new Error(\n 'Black Forest Labs poll response is Ready but missing result.sample',\n );\n }\n if (status === 'Error' || status === 'Failed') {\n throw new Error('Black Forest Labs generation failed.');\n }\n\n await delay(DEFAULT_POLL_INTERVAL_MILLIS);\n }\n\n throw new Error('Black Forest Labs generation timed out.');\n }\n}\n\nexport const blackForestLabsImageProviderOptionsSchema = lazySchema(() =>\n zodSchema(\n z.object({\n imagePrompt: z.string().optional(),\n imagePromptStrength: z.number().min(0).max(1).optional(),\n inputImage: z.string().optional(),\n outputFormat: z.enum(['jpeg', 'png']).optional(),\n promptUpsampling: z.boolean().optional(),\n raw: z.boolean().optional(),\n safetyTolerance: z.number().int().min(0).max(6).optional(),\n webhookSecret: z.string().optional(),\n webhookUrl: z.url().optional(),\n }),\n ),\n);\n\nexport type BlackForestLabsImageProviderOptions = InferValidator<\n typeof blackForestLabsImageProviderOptionsSchema\n>;\n\nfunction convertSizeToAspectRatio(\n size: string,\n): BlackForestLabsAspectRatio | undefined {\n const [wStr, hStr] = size.split('x');\n const width = Number(wStr);\n const height = Number(hStr);\n if (\n !Number.isFinite(width) ||\n !Number.isFinite(height) ||\n width <= 0 ||\n height <= 0\n ) {\n return undefined;\n }\n const g = gcd(width, height);\n return `${Math.round(width / g)}:${Math.round(height / g)}`;\n}\n\nfunction gcd(a: number, b: number): number {\n let x = Math.abs(a);\n let y = Math.abs(b);\n while (y !== 0) {\n const t = y;\n y = x % y;\n x = t;\n }\n return x;\n}\n\nconst bflSubmitSchema = z.object({\n id: z.string(),\n polling_url: z.url(),\n});\n\nconst bflStatus = z.union([\n z.literal('Pending'),\n z.literal('Ready'),\n z.literal('Error'),\n z.literal('Failed'),\n]);\n\nconst bflPollSchema = z\n .object({\n status: bflStatus.optional(),\n state: bflStatus.optional(),\n result: z\n .object({\n sample: z.url(),\n seed: z.number().optional(),\n start_time: z.number().optional(),\n end_time: z.number().optional(),\n duration: z.number().optional(),\n })\n .nullish(),\n })\n .refine(v => v.status != null || v.state != null, {\n message: 'Missing status in Black Forest Labs poll response',\n })\n .transform(v => ({\n status: (v.status ?? v.state)!,\n result: v.result,\n }));\n\nconst bflErrorSchema = z.object({\n message: z.string().optional(),\n detail: z.any().optional(),\n});\n\nconst bflFailedResponseHandler = createJsonErrorResponseHandler({\n errorSchema: bflErrorSchema,\n errorToMessage: error =>\n bflErrorToMessage(error) ?? 'Unknown Black Forest Labs error',\n});\n\nfunction bflErrorToMessage(error: unknown): string | undefined {\n const parsed = bflErrorSchema.safeParse(error);\n if (!parsed.success) return undefined;\n const { message, detail } = parsed.data;\n if (typeof detail === 'string') return detail;\n if (detail != null) {\n try {\n return JSON.stringify(detail);\n } catch {\n // ignore\n }\n }\n return message;\n}\n","// Version string of this package injected at build time.\ndeclare const __PACKAGE_VERSION__: string | undefined;\nexport const VERSION: string =\n typeof __PACKAGE_VERSION__ !== 'undefined'\n ? __PACKAGE_VERSION__\n : '0.0.0-test';\n"],"mappings":"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","names":["import_provider_utils"]}
package/dist/index.mjs ADDED
@@ -0,0 +1,341 @@
1
+ // src/black-forest-labs-provider.ts
2
+ import { NoSuchModelError } from "@ai-sdk/provider";
3
+ import {
4
+ loadApiKey,
5
+ withoutTrailingSlash,
6
+ withUserAgentSuffix
7
+ } from "@ai-sdk/provider-utils";
8
+
9
+ // src/black-forest-labs-image-model.ts
10
+ import {
11
+ combineHeaders,
12
+ createBinaryResponseHandler,
13
+ createJsonErrorResponseHandler,
14
+ createJsonResponseHandler,
15
+ createStatusCodeErrorResponseHandler,
16
+ delay,
17
+ getFromApi,
18
+ lazySchema,
19
+ parseProviderOptions,
20
+ postJsonToApi,
21
+ resolve,
22
+ zodSchema
23
+ } from "@ai-sdk/provider-utils";
24
+ import { z } from "zod/v4";
25
+ var DEFAULT_POLL_INTERVAL_MILLIS = 500;
26
+ var DEFAULT_MAX_POLL_ATTEMPTS = 6e4 / DEFAULT_POLL_INTERVAL_MILLIS;
27
+ var BlackForestLabsImageModel = class {
28
+ constructor(modelId, config) {
29
+ this.modelId = modelId;
30
+ this.config = config;
31
+ this.specificationVersion = "v2";
32
+ this.maxImagesPerCall = 1;
33
+ }
34
+ get provider() {
35
+ return this.config.provider;
36
+ }
37
+ async getArgs({
38
+ prompt,
39
+ size,
40
+ aspectRatio,
41
+ seed,
42
+ providerOptions
43
+ }) {
44
+ var _a;
45
+ const warnings = [];
46
+ const finalAspectRatio = aspectRatio != null ? aspectRatio : size ? convertSizeToAspectRatio(size) : void 0;
47
+ if (size && !aspectRatio) {
48
+ warnings.push({
49
+ type: "unsupported-setting",
50
+ setting: "size",
51
+ details: "Deriving aspect_ratio from size."
52
+ });
53
+ } else if (size && aspectRatio) {
54
+ warnings.push({
55
+ type: "unsupported-setting",
56
+ setting: "size",
57
+ details: "Black Forest Labs ignores size when aspectRatio is provided."
58
+ });
59
+ }
60
+ const bflOptions = await parseProviderOptions({
61
+ provider: "blackForestLabs",
62
+ providerOptions,
63
+ schema: blackForestLabsImageProviderOptionsSchema
64
+ });
65
+ const [widthStr, heightStr] = (_a = size == null ? void 0 : size.split("x")) != null ? _a : [];
66
+ const body = {
67
+ prompt,
68
+ seed,
69
+ aspect_ratio: finalAspectRatio,
70
+ ...size && { width: Number(widthStr), height: Number(heightStr) },
71
+ image_prompt_strength: bflOptions == null ? void 0 : bflOptions.imagePromptStrength,
72
+ image_prompt: bflOptions == null ? void 0 : bflOptions.imagePrompt,
73
+ input_image: bflOptions == null ? void 0 : bflOptions.inputImage,
74
+ output_format: bflOptions == null ? void 0 : bflOptions.outputFormat,
75
+ prompt_upsampling: bflOptions == null ? void 0 : bflOptions.promptUpsampling,
76
+ raw: bflOptions == null ? void 0 : bflOptions.raw,
77
+ safety_tolerance: bflOptions == null ? void 0 : bflOptions.safetyTolerance,
78
+ webhook_secret: bflOptions == null ? void 0 : bflOptions.webhookSecret,
79
+ webhook_url: bflOptions == null ? void 0 : bflOptions.webhookUrl
80
+ };
81
+ return { body, warnings };
82
+ }
83
+ async doGenerate({
84
+ prompt,
85
+ size,
86
+ aspectRatio,
87
+ seed,
88
+ providerOptions,
89
+ headers,
90
+ abortSignal
91
+ }) {
92
+ var _a, _b, _c;
93
+ const { body, warnings } = await this.getArgs({
94
+ prompt,
95
+ size,
96
+ aspectRatio,
97
+ seed,
98
+ providerOptions,
99
+ n: 1,
100
+ headers,
101
+ abortSignal
102
+ });
103
+ const currentDate = (_c = (_b = (_a = this.config._internal) == null ? void 0 : _a.currentDate) == null ? void 0 : _b.call(_a)) != null ? _c : /* @__PURE__ */ new Date();
104
+ const combinedHeaders = combineHeaders(
105
+ await resolve(this.config.headers),
106
+ headers
107
+ );
108
+ const submit = await postJsonToApi({
109
+ url: `${this.config.baseURL}/${this.modelId}`,
110
+ headers: combinedHeaders,
111
+ body,
112
+ failedResponseHandler: bflFailedResponseHandler,
113
+ successfulResponseHandler: createJsonResponseHandler(bflSubmitSchema),
114
+ abortSignal,
115
+ fetch: this.config.fetch
116
+ });
117
+ const pollUrl = submit.value.polling_url;
118
+ const requestId = submit.value.id;
119
+ const {
120
+ imageUrl,
121
+ seed: resultSeed,
122
+ start_time: resultStartTime,
123
+ end_time: resultEndTime,
124
+ duration: resultDuration
125
+ } = await this.pollForImageUrl({
126
+ pollUrl,
127
+ requestId,
128
+ headers: combinedHeaders,
129
+ abortSignal
130
+ });
131
+ const { value: imageBytes, responseHeaders } = await getFromApi({
132
+ url: imageUrl,
133
+ headers: combinedHeaders,
134
+ abortSignal,
135
+ failedResponseHandler: createStatusCodeErrorResponseHandler(),
136
+ successfulResponseHandler: createBinaryResponseHandler(),
137
+ fetch: this.config.fetch
138
+ });
139
+ return {
140
+ images: [imageBytes],
141
+ warnings,
142
+ providerMetadata: {
143
+ blackForestLabs: {
144
+ images: [
145
+ {
146
+ ...resultSeed != null && { seed: resultSeed },
147
+ ...resultStartTime != null && { start_time: resultStartTime },
148
+ ...resultEndTime != null && { end_time: resultEndTime },
149
+ ...resultDuration != null && { duration: resultDuration }
150
+ }
151
+ ]
152
+ }
153
+ },
154
+ response: {
155
+ modelId: this.modelId,
156
+ timestamp: currentDate,
157
+ headers: responseHeaders
158
+ }
159
+ };
160
+ }
161
+ async pollForImageUrl({
162
+ pollUrl,
163
+ requestId,
164
+ headers,
165
+ abortSignal
166
+ }) {
167
+ var _a, _b, _c, _d, _e;
168
+ const url = new URL(pollUrl);
169
+ if (!url.searchParams.has("id")) {
170
+ url.searchParams.set("id", requestId);
171
+ }
172
+ for (let i = 0; i < DEFAULT_MAX_POLL_ATTEMPTS; i++) {
173
+ const { value } = await getFromApi({
174
+ url: url.toString(),
175
+ headers,
176
+ failedResponseHandler: bflFailedResponseHandler,
177
+ successfulResponseHandler: createJsonResponseHandler(bflPollSchema),
178
+ abortSignal,
179
+ fetch: this.config.fetch
180
+ });
181
+ const status = value.status;
182
+ if (status === "Ready") {
183
+ if (typeof ((_a = value.result) == null ? void 0 : _a.sample) === "string") {
184
+ return {
185
+ imageUrl: value.result.sample,
186
+ seed: (_b = value.result.seed) != null ? _b : void 0,
187
+ start_time: (_c = value.result.start_time) != null ? _c : void 0,
188
+ end_time: (_d = value.result.end_time) != null ? _d : void 0,
189
+ duration: (_e = value.result.duration) != null ? _e : void 0
190
+ };
191
+ }
192
+ throw new Error(
193
+ "Black Forest Labs poll response is Ready but missing result.sample"
194
+ );
195
+ }
196
+ if (status === "Error" || status === "Failed") {
197
+ throw new Error("Black Forest Labs generation failed.");
198
+ }
199
+ await delay(DEFAULT_POLL_INTERVAL_MILLIS);
200
+ }
201
+ throw new Error("Black Forest Labs generation timed out.");
202
+ }
203
+ };
204
+ var blackForestLabsImageProviderOptionsSchema = lazySchema(
205
+ () => zodSchema(
206
+ z.object({
207
+ imagePrompt: z.string().optional(),
208
+ imagePromptStrength: z.number().min(0).max(1).optional(),
209
+ inputImage: z.string().optional(),
210
+ outputFormat: z.enum(["jpeg", "png"]).optional(),
211
+ promptUpsampling: z.boolean().optional(),
212
+ raw: z.boolean().optional(),
213
+ safetyTolerance: z.number().int().min(0).max(6).optional(),
214
+ webhookSecret: z.string().optional(),
215
+ webhookUrl: z.url().optional()
216
+ })
217
+ )
218
+ );
219
+ function convertSizeToAspectRatio(size) {
220
+ const [wStr, hStr] = size.split("x");
221
+ const width = Number(wStr);
222
+ const height = Number(hStr);
223
+ if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
224
+ return void 0;
225
+ }
226
+ const g = gcd(width, height);
227
+ return `${Math.round(width / g)}:${Math.round(height / g)}`;
228
+ }
229
+ function gcd(a, b) {
230
+ let x = Math.abs(a);
231
+ let y = Math.abs(b);
232
+ while (y !== 0) {
233
+ const t = y;
234
+ y = x % y;
235
+ x = t;
236
+ }
237
+ return x;
238
+ }
239
+ var bflSubmitSchema = z.object({
240
+ id: z.string(),
241
+ polling_url: z.url()
242
+ });
243
+ var bflStatus = z.union([
244
+ z.literal("Pending"),
245
+ z.literal("Ready"),
246
+ z.literal("Error"),
247
+ z.literal("Failed")
248
+ ]);
249
+ var bflPollSchema = z.object({
250
+ status: bflStatus.optional(),
251
+ state: bflStatus.optional(),
252
+ result: z.object({
253
+ sample: z.url(),
254
+ seed: z.number().optional(),
255
+ start_time: z.number().optional(),
256
+ end_time: z.number().optional(),
257
+ duration: z.number().optional()
258
+ }).nullish()
259
+ }).refine((v) => v.status != null || v.state != null, {
260
+ message: "Missing status in Black Forest Labs poll response"
261
+ }).transform((v) => {
262
+ var _a;
263
+ return {
264
+ status: (_a = v.status) != null ? _a : v.state,
265
+ result: v.result
266
+ };
267
+ });
268
+ var bflErrorSchema = z.object({
269
+ message: z.string().optional(),
270
+ detail: z.any().optional()
271
+ });
272
+ var bflFailedResponseHandler = createJsonErrorResponseHandler({
273
+ errorSchema: bflErrorSchema,
274
+ errorToMessage: (error) => {
275
+ var _a;
276
+ return (_a = bflErrorToMessage(error)) != null ? _a : "Unknown Black Forest Labs error";
277
+ }
278
+ });
279
+ function bflErrorToMessage(error) {
280
+ const parsed = bflErrorSchema.safeParse(error);
281
+ if (!parsed.success) return void 0;
282
+ const { message, detail } = parsed.data;
283
+ if (typeof detail === "string") return detail;
284
+ if (detail != null) {
285
+ try {
286
+ return JSON.stringify(detail);
287
+ } catch (e) {
288
+ }
289
+ }
290
+ return message;
291
+ }
292
+
293
+ // src/version.ts
294
+ var VERSION = true ? "0.0.1" : "0.0.0-test";
295
+
296
+ // src/black-forest-labs-provider.ts
297
+ var defaultBaseURL = "https://api.bfl.ai/v1";
298
+ function createBlackForestLabs(options = {}) {
299
+ var _a;
300
+ const baseURL = withoutTrailingSlash((_a = options.baseURL) != null ? _a : defaultBaseURL);
301
+ const getHeaders = () => withUserAgentSuffix(
302
+ {
303
+ "x-key": loadApiKey({
304
+ apiKey: options.apiKey,
305
+ environmentVariableName: "BFL_API_KEY",
306
+ description: "Black Forest Labs"
307
+ }),
308
+ ...options.headers
309
+ },
310
+ `ai-sdk/black-forest-labs/${VERSION}`
311
+ );
312
+ const createImageModel = (modelId) => new BlackForestLabsImageModel(modelId, {
313
+ provider: "black-forest-labs.image",
314
+ baseURL: baseURL != null ? baseURL : defaultBaseURL,
315
+ headers: getHeaders,
316
+ fetch: options.fetch
317
+ });
318
+ return {
319
+ imageModel: createImageModel,
320
+ image: createImageModel,
321
+ languageModel: () => {
322
+ throw new NoSuchModelError({
323
+ modelId: "languageModel",
324
+ modelType: "languageModel"
325
+ });
326
+ },
327
+ textEmbeddingModel: () => {
328
+ throw new NoSuchModelError({
329
+ modelId: "textEmbeddingModel",
330
+ modelType: "textEmbeddingModel"
331
+ });
332
+ }
333
+ };
334
+ }
335
+ var blackForestLabs = createBlackForestLabs();
336
+ export {
337
+ VERSION,
338
+ blackForestLabs,
339
+ createBlackForestLabs
340
+ };
341
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/black-forest-labs-provider.ts","../src/black-forest-labs-image-model.ts","../src/version.ts"],"sourcesContent":["import { ImageModelV2, NoSuchModelError, ProviderV2 } from '@ai-sdk/provider';\nimport type { FetchFunction } from '@ai-sdk/provider-utils';\nimport {\n loadApiKey,\n withoutTrailingSlash,\n withUserAgentSuffix,\n} from '@ai-sdk/provider-utils';\nimport { BlackForestLabsImageModel } from './black-forest-labs-image-model';\nimport { BlackForestLabsImageModelId } from './black-forest-labs-image-settings';\nimport { VERSION } from './version';\n\nexport interface BlackForestLabsProviderSettings {\n /**\nBlack Forest Labs API key. Default value is taken from the `BFL_API_KEY` environment variable.\n */\n apiKey?: string;\n\n /**\nBase URL for the API calls. Defaults to `https://api.bfl.ai/v1`. \n */\n baseURL?: string;\n\n /**\nCustom headers to include in the requests.\n */\n headers?: Record<string, string>;\n\n /**\nCustom fetch implementation. You can use it as a middleware to intercept\nrequests, or to provide a custom fetch implementation for e.g. testing.\n */\n fetch?: FetchFunction;\n}\n\nexport interface BlackForestLabsProvider extends ProviderV2 {\n /**\nCreates a model for image generation.\n */\n image(modelId: BlackForestLabsImageModelId): ImageModelV2;\n\n /**\nCreates a model for image generation.\n */\n imageModel(modelId: BlackForestLabsImageModelId): ImageModelV2;\n}\n\nconst defaultBaseURL = 'https://api.bfl.ai/v1';\n\nexport function createBlackForestLabs(\n options: BlackForestLabsProviderSettings = {},\n): BlackForestLabsProvider {\n const baseURL = withoutTrailingSlash(options.baseURL ?? defaultBaseURL);\n const getHeaders = () =>\n withUserAgentSuffix(\n {\n 'x-key': loadApiKey({\n apiKey: options.apiKey,\n environmentVariableName: 'BFL_API_KEY',\n description: 'Black Forest Labs',\n }),\n ...options.headers,\n },\n `ai-sdk/black-forest-labs/${VERSION}`,\n );\n\n const createImageModel = (modelId: BlackForestLabsImageModelId) =>\n new BlackForestLabsImageModel(modelId, {\n provider: 'black-forest-labs.image',\n baseURL: baseURL ?? defaultBaseURL,\n headers: getHeaders,\n fetch: options.fetch,\n });\n\n return {\n imageModel: createImageModel,\n image: createImageModel,\n languageModel: () => {\n throw new NoSuchModelError({\n modelId: 'languageModel',\n modelType: 'languageModel',\n });\n },\n textEmbeddingModel: () => {\n throw new NoSuchModelError({\n modelId: 'textEmbeddingModel',\n modelType: 'textEmbeddingModel',\n });\n },\n };\n}\n\nexport const blackForestLabs = createBlackForestLabs();\n","import type { ImageModelV2, ImageModelV2CallWarning } from '@ai-sdk/provider';\nimport type { InferValidator, Resolvable } from '@ai-sdk/provider-utils';\nimport {\n FetchFunction,\n combineHeaders,\n createBinaryResponseHandler,\n createJsonErrorResponseHandler,\n createJsonResponseHandler,\n createStatusCodeErrorResponseHandler,\n delay,\n getFromApi,\n lazySchema,\n parseProviderOptions,\n postJsonToApi,\n resolve,\n zodSchema,\n} from '@ai-sdk/provider-utils';\nimport { z } from 'zod/v4';\nimport type { BlackForestLabsAspectRatio } from './black-forest-labs-image-settings';\nimport { BlackForestLabsImageModelId } from './black-forest-labs-image-settings';\n\nconst DEFAULT_POLL_INTERVAL_MILLIS = 500;\nconst DEFAULT_MAX_POLL_ATTEMPTS = 60000 / DEFAULT_POLL_INTERVAL_MILLIS;\n\ninterface BlackForestLabsImageModelConfig {\n provider: string;\n baseURL: string;\n headers?: Resolvable<Record<string, string | undefined>>;\n fetch?: FetchFunction;\n _internal?: {\n currentDate?: () => Date;\n };\n}\n\nexport class BlackForestLabsImageModel implements ImageModelV2 {\n readonly specificationVersion = 'v2';\n readonly maxImagesPerCall = 1;\n\n get provider(): string {\n return this.config.provider;\n }\n\n constructor(\n readonly modelId: BlackForestLabsImageModelId,\n private readonly config: BlackForestLabsImageModelConfig,\n ) {}\n\n private async getArgs({\n prompt,\n size,\n aspectRatio,\n seed,\n providerOptions,\n }: Parameters<ImageModelV2['doGenerate']>[0]) {\n const warnings: Array<ImageModelV2CallWarning> = [];\n\n const finalAspectRatio =\n aspectRatio ?? (size ? convertSizeToAspectRatio(size) : undefined);\n\n if (size && !aspectRatio) {\n warnings.push({\n type: 'unsupported-setting',\n setting: 'size',\n details: 'Deriving aspect_ratio from size.',\n });\n } else if (size && aspectRatio) {\n warnings.push({\n type: 'unsupported-setting',\n setting: 'size',\n details: 'Black Forest Labs ignores size when aspectRatio is provided.',\n });\n }\n\n const bflOptions = await parseProviderOptions({\n provider: 'blackForestLabs',\n providerOptions,\n schema: blackForestLabsImageProviderOptionsSchema,\n });\n\n const [widthStr, heightStr] = size?.split('x') ?? [];\n\n const body: Record<string, unknown> = {\n prompt,\n seed,\n aspect_ratio: finalAspectRatio,\n ...(size && { width: Number(widthStr), height: Number(heightStr) }),\n image_prompt_strength: bflOptions?.imagePromptStrength,\n image_prompt: bflOptions?.imagePrompt,\n input_image: bflOptions?.inputImage,\n output_format: bflOptions?.outputFormat,\n prompt_upsampling: bflOptions?.promptUpsampling,\n raw: bflOptions?.raw,\n safety_tolerance: bflOptions?.safetyTolerance,\n webhook_secret: bflOptions?.webhookSecret,\n webhook_url: bflOptions?.webhookUrl,\n };\n\n return { body, warnings };\n }\n\n async doGenerate({\n prompt,\n size,\n aspectRatio,\n seed,\n providerOptions,\n headers,\n abortSignal,\n }: Parameters<ImageModelV2['doGenerate']>[0]): Promise<\n Awaited<ReturnType<ImageModelV2['doGenerate']>>\n > {\n const { body, warnings } = await this.getArgs({\n prompt,\n size,\n aspectRatio,\n seed,\n providerOptions,\n n: 1,\n headers,\n abortSignal,\n } as Parameters<ImageModelV2['doGenerate']>[0]);\n\n const currentDate = this.config._internal?.currentDate?.() ?? new Date();\n const combinedHeaders = combineHeaders(\n await resolve(this.config.headers),\n headers,\n );\n\n const submit = await postJsonToApi({\n url: `${this.config.baseURL}/${this.modelId}`,\n headers: combinedHeaders,\n body,\n failedResponseHandler: bflFailedResponseHandler,\n successfulResponseHandler: createJsonResponseHandler(bflSubmitSchema),\n abortSignal,\n fetch: this.config.fetch,\n });\n\n const pollUrl = submit.value.polling_url;\n const requestId = submit.value.id;\n\n const {\n imageUrl,\n seed: resultSeed,\n start_time: resultStartTime,\n end_time: resultEndTime,\n duration: resultDuration,\n } = await this.pollForImageUrl({\n pollUrl,\n requestId,\n headers: combinedHeaders,\n abortSignal,\n });\n\n const { value: imageBytes, responseHeaders } = await getFromApi({\n url: imageUrl,\n headers: combinedHeaders,\n abortSignal,\n failedResponseHandler: createStatusCodeErrorResponseHandler(),\n successfulResponseHandler: createBinaryResponseHandler(),\n fetch: this.config.fetch,\n });\n\n return {\n images: [imageBytes],\n warnings,\n providerMetadata: {\n blackForestLabs: {\n images: [\n {\n ...(resultSeed != null && { seed: resultSeed }),\n ...(resultStartTime != null && { start_time: resultStartTime }),\n ...(resultEndTime != null && { end_time: resultEndTime }),\n ...(resultDuration != null && { duration: resultDuration }),\n },\n ],\n },\n },\n response: {\n modelId: this.modelId,\n timestamp: currentDate,\n headers: responseHeaders,\n },\n };\n }\n\n private async pollForImageUrl({\n pollUrl,\n requestId,\n headers,\n abortSignal,\n }: {\n pollUrl: string;\n requestId: string;\n headers: Record<string, string | undefined>;\n abortSignal: AbortSignal | undefined;\n }): Promise<{\n imageUrl: string;\n seed?: number;\n start_time?: number;\n end_time?: number;\n duration?: number;\n }> {\n const url = new URL(pollUrl);\n if (!url.searchParams.has('id')) {\n url.searchParams.set('id', requestId);\n }\n\n for (let i = 0; i < DEFAULT_MAX_POLL_ATTEMPTS; i++) {\n const { value } = await getFromApi({\n url: url.toString(),\n headers,\n failedResponseHandler: bflFailedResponseHandler,\n successfulResponseHandler: createJsonResponseHandler(bflPollSchema),\n abortSignal,\n fetch: this.config.fetch,\n });\n\n const status = value.status;\n if (status === 'Ready') {\n if (typeof value.result?.sample === 'string') {\n return {\n imageUrl: value.result.sample,\n seed: value.result.seed ?? undefined,\n start_time: value.result.start_time ?? undefined,\n end_time: value.result.end_time ?? undefined,\n duration: value.result.duration ?? undefined,\n };\n }\n throw new Error(\n 'Black Forest Labs poll response is Ready but missing result.sample',\n );\n }\n if (status === 'Error' || status === 'Failed') {\n throw new Error('Black Forest Labs generation failed.');\n }\n\n await delay(DEFAULT_POLL_INTERVAL_MILLIS);\n }\n\n throw new Error('Black Forest Labs generation timed out.');\n }\n}\n\nexport const blackForestLabsImageProviderOptionsSchema = lazySchema(() =>\n zodSchema(\n z.object({\n imagePrompt: z.string().optional(),\n imagePromptStrength: z.number().min(0).max(1).optional(),\n inputImage: z.string().optional(),\n outputFormat: z.enum(['jpeg', 'png']).optional(),\n promptUpsampling: z.boolean().optional(),\n raw: z.boolean().optional(),\n safetyTolerance: z.number().int().min(0).max(6).optional(),\n webhookSecret: z.string().optional(),\n webhookUrl: z.url().optional(),\n }),\n ),\n);\n\nexport type BlackForestLabsImageProviderOptions = InferValidator<\n typeof blackForestLabsImageProviderOptionsSchema\n>;\n\nfunction convertSizeToAspectRatio(\n size: string,\n): BlackForestLabsAspectRatio | undefined {\n const [wStr, hStr] = size.split('x');\n const width = Number(wStr);\n const height = Number(hStr);\n if (\n !Number.isFinite(width) ||\n !Number.isFinite(height) ||\n width <= 0 ||\n height <= 0\n ) {\n return undefined;\n }\n const g = gcd(width, height);\n return `${Math.round(width / g)}:${Math.round(height / g)}`;\n}\n\nfunction gcd(a: number, b: number): number {\n let x = Math.abs(a);\n let y = Math.abs(b);\n while (y !== 0) {\n const t = y;\n y = x % y;\n x = t;\n }\n return x;\n}\n\nconst bflSubmitSchema = z.object({\n id: z.string(),\n polling_url: z.url(),\n});\n\nconst bflStatus = z.union([\n z.literal('Pending'),\n z.literal('Ready'),\n z.literal('Error'),\n z.literal('Failed'),\n]);\n\nconst bflPollSchema = z\n .object({\n status: bflStatus.optional(),\n state: bflStatus.optional(),\n result: z\n .object({\n sample: z.url(),\n seed: z.number().optional(),\n start_time: z.number().optional(),\n end_time: z.number().optional(),\n duration: z.number().optional(),\n })\n .nullish(),\n })\n .refine(v => v.status != null || v.state != null, {\n message: 'Missing status in Black Forest Labs poll response',\n })\n .transform(v => ({\n status: (v.status ?? v.state)!,\n result: v.result,\n }));\n\nconst bflErrorSchema = z.object({\n message: z.string().optional(),\n detail: z.any().optional(),\n});\n\nconst bflFailedResponseHandler = createJsonErrorResponseHandler({\n errorSchema: bflErrorSchema,\n errorToMessage: error =>\n bflErrorToMessage(error) ?? 'Unknown Black Forest Labs error',\n});\n\nfunction bflErrorToMessage(error: unknown): string | undefined {\n const parsed = bflErrorSchema.safeParse(error);\n if (!parsed.success) return undefined;\n const { message, detail } = parsed.data;\n if (typeof detail === 'string') return detail;\n if (detail != null) {\n try {\n return JSON.stringify(detail);\n } catch {\n // ignore\n }\n }\n return message;\n}\n","// Version string of this package injected at build time.\ndeclare const __PACKAGE_VERSION__: string | undefined;\nexport const VERSION: string =\n typeof __PACKAGE_VERSION__ !== 'undefined'\n ? __PACKAGE_VERSION__\n : '0.0.0-test';\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,66 @@
1
+ {
2
+ "name": "@ai-sdk/black-forest-labs",
3
+ "version": "0.0.1",
4
+ "license": "Apache-2.0",
5
+ "sideEffects": false,
6
+ "main": "./dist/index.js",
7
+ "module": "./dist/index.mjs",
8
+ "types": "./dist/index.d.ts",
9
+ "files": [
10
+ "dist/**/*",
11
+ "CHANGELOG.md"
12
+ ],
13
+ "exports": {
14
+ "./package.json": "./package.json",
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "import": "./dist/index.mjs",
18
+ "require": "./dist/index.js"
19
+ }
20
+ },
21
+ "dependencies": {
22
+ "@ai-sdk/provider": "2.0.0",
23
+ "@ai-sdk/provider-utils": "3.0.17"
24
+ },
25
+ "devDependencies": {
26
+ "@types/node": "20.17.24",
27
+ "tsup": "^8",
28
+ "typescript": "5.8.3",
29
+ "zod": "3.25.76",
30
+ "@ai-sdk/test-server": "0.0.1",
31
+ "@vercel/ai-tsconfig": "0.0.0"
32
+ },
33
+ "peerDependencies": {
34
+ "zod": "^3.25.76 || ^4.1.8"
35
+ },
36
+ "engines": {
37
+ "node": ">=18"
38
+ },
39
+ "publishConfig": {
40
+ "access": "public"
41
+ },
42
+ "homepage": "https://ai-sdk.dev/docs",
43
+ "repository": {
44
+ "type": "git",
45
+ "url": "git+https://github.com/vercel/ai.git"
46
+ },
47
+ "bugs": {
48
+ "url": "https://github.com/vercel/ai/issues"
49
+ },
50
+ "keywords": [
51
+ "ai"
52
+ ],
53
+ "scripts": {
54
+ "build": "pnpm clean && tsup --tsconfig tsconfig.build.json",
55
+ "build:watch": "pnpm clean && tsup --watch",
56
+ "clean": "del-cli dist *.tsbuildinfo",
57
+ "lint": "eslint \"./**/*.ts*\"",
58
+ "type-check": "tsc --build",
59
+ "prettier-check": "prettier --check \"./**/*.ts*\"",
60
+ "test": "pnpm test:node && pnpm test:edge",
61
+ "test:update": "pnpm test:node -u",
62
+ "test:watch": "vitest --config vitest.node.config.js",
63
+ "test:edge": "vitest --config vitest.edge.config.js --run",
64
+ "test:node": "vitest --config vitest.node.config.js --run"
65
+ }
66
+ }