@ai-sdk/black-forest-labs 2.0.19 → 2.0.21
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 +15 -0
- package/README.md +16 -2
- package/dist/index.d.ts +27 -4
- package/dist/index.js +745 -80
- package/dist/index.js.map +1 -1
- package/docs/12-black-forest-labs.mdx +250 -3
- package/package.json +2 -2
- package/src/black-forest-labs-api.ts +58 -0
- package/src/black-forest-labs-image-model.ts +4 -51
- package/src/black-forest-labs-provider.ts +29 -2
- package/src/black-forest-labs-video-model-options.ts +92 -0
- package/src/black-forest-labs-video-model.ts +778 -0
- package/src/black-forest-labs-video-settings.ts +22 -0
- package/src/index.ts +2 -0
|
@@ -2,12 +2,10 @@ import type { ImageModelV4, SharedV4Warning } from '@ai-sdk/provider';
|
|
|
2
2
|
import {
|
|
3
3
|
combineHeaders,
|
|
4
4
|
createBinaryResponseHandler,
|
|
5
|
-
createJsonErrorResponseHandler,
|
|
6
5
|
createJsonResponseHandler,
|
|
7
6
|
createStatusCodeErrorResponseHandler,
|
|
8
7
|
delay,
|
|
9
8
|
getFromApi,
|
|
10
|
-
isSameOrigin,
|
|
11
9
|
parseProviderOptions,
|
|
12
10
|
postJsonToApi,
|
|
13
11
|
resolve,
|
|
@@ -18,6 +16,10 @@ import {
|
|
|
18
16
|
type FetchFunction,
|
|
19
17
|
} from '@ai-sdk/provider-utils';
|
|
20
18
|
import { z } from 'zod/v4';
|
|
19
|
+
import {
|
|
20
|
+
bflFailedResponseHandler,
|
|
21
|
+
isTrustedUrl,
|
|
22
|
+
} from './black-forest-labs-api';
|
|
21
23
|
import { blackForestLabsImageModelOptionsSchema } from './black-forest-labs-image-model-options';
|
|
22
24
|
import type {
|
|
23
25
|
BlackForestLabsAspectRatio,
|
|
@@ -362,29 +364,6 @@ export class BlackForestLabsImageModel implements ImageModelV4 {
|
|
|
362
364
|
}
|
|
363
365
|
}
|
|
364
366
|
|
|
365
|
-
/**
|
|
366
|
-
* Black Forest Labs returns response-supplied URLs (polling and delivery) on
|
|
367
|
-
* sibling cluster hosts of the API origin (e.g. `api.us1.bfl.ai` for a base
|
|
368
|
-
* URL on `api.bfl.ai`), so a strict same-origin check against the configured
|
|
369
|
-
* base URL is not enough. Credentials may also be sent to any https host under
|
|
370
|
-
* the official `bfl.ai` domain.
|
|
371
|
-
*/
|
|
372
|
-
function isTrustedUrl(url: string, baseUrl: string): boolean {
|
|
373
|
-
if (isSameOrigin(url, baseUrl)) {
|
|
374
|
-
return true;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
try {
|
|
378
|
-
const { protocol, hostname } = new URL(url);
|
|
379
|
-
return (
|
|
380
|
-
protocol === 'https:' &&
|
|
381
|
-
(hostname === 'bfl.ai' || hostname.endsWith('.bfl.ai'))
|
|
382
|
-
);
|
|
383
|
-
} catch {
|
|
384
|
-
return false;
|
|
385
|
-
}
|
|
386
|
-
}
|
|
387
|
-
|
|
388
367
|
function convertSizeToAspectRatio(
|
|
389
368
|
size: string,
|
|
390
369
|
): BlackForestLabsAspectRatio | undefined {
|
|
@@ -452,29 +431,3 @@ const bflPollSchema = z
|
|
|
452
431
|
status: (v.status ?? v.state)!,
|
|
453
432
|
result: v.result,
|
|
454
433
|
}));
|
|
455
|
-
|
|
456
|
-
const bflErrorSchema = z.object({
|
|
457
|
-
message: z.string().optional(),
|
|
458
|
-
detail: z.any().optional(),
|
|
459
|
-
});
|
|
460
|
-
|
|
461
|
-
const bflFailedResponseHandler = createJsonErrorResponseHandler({
|
|
462
|
-
errorSchema: bflErrorSchema,
|
|
463
|
-
errorToMessage: error =>
|
|
464
|
-
bflErrorToMessage(error) ?? 'Unknown Black Forest Labs error',
|
|
465
|
-
});
|
|
466
|
-
|
|
467
|
-
function bflErrorToMessage(error: unknown): string | undefined {
|
|
468
|
-
const parsed = bflErrorSchema.safeParse(error);
|
|
469
|
-
if (!parsed.success) return undefined;
|
|
470
|
-
const { message, detail } = parsed.data;
|
|
471
|
-
if (typeof detail === 'string') return detail;
|
|
472
|
-
if (detail != null) {
|
|
473
|
-
try {
|
|
474
|
-
return JSON.stringify(detail);
|
|
475
|
-
} catch {
|
|
476
|
-
// ignore
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
return message;
|
|
480
|
-
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
NoSuchModelError,
|
|
3
|
+
type Experimental_VideoModelV4,
|
|
3
4
|
type ImageModelV4,
|
|
4
5
|
type ProviderV4,
|
|
5
6
|
} from '@ai-sdk/provider';
|
|
@@ -11,6 +12,8 @@ import {
|
|
|
11
12
|
} from '@ai-sdk/provider-utils';
|
|
12
13
|
import { BlackForestLabsImageModel } from './black-forest-labs-image-model';
|
|
13
14
|
import type { BlackForestLabsImageModelId } from './black-forest-labs-image-settings';
|
|
15
|
+
import { BlackForestLabsVideoModel } from './black-forest-labs-video-model';
|
|
16
|
+
import type { BlackForestLabsVideoModelId } from './black-forest-labs-video-settings';
|
|
14
17
|
import { VERSION } from './version';
|
|
15
18
|
|
|
16
19
|
export interface BlackForestLabsProviderSettings {
|
|
@@ -36,12 +39,14 @@ export interface BlackForestLabsProviderSettings {
|
|
|
36
39
|
fetch?: FetchFunction;
|
|
37
40
|
|
|
38
41
|
/**
|
|
39
|
-
* Poll interval in milliseconds between status checks. Defaults to 500ms
|
|
42
|
+
* Poll interval in milliseconds between status checks. Defaults to 500ms for
|
|
43
|
+
* images and 2s for video.
|
|
40
44
|
*/
|
|
41
45
|
pollIntervalMillis?: number;
|
|
42
46
|
|
|
43
47
|
/**
|
|
44
|
-
* Overall timeout in milliseconds for polling before giving up. Defaults to
|
|
48
|
+
* Overall timeout in milliseconds for polling before giving up. Defaults to
|
|
49
|
+
* 60s for images and 10 minutes for video.
|
|
45
50
|
*/
|
|
46
51
|
pollTimeoutMillis?: number;
|
|
47
52
|
}
|
|
@@ -57,6 +62,16 @@ export interface BlackForestLabsProvider extends ProviderV4 {
|
|
|
57
62
|
*/
|
|
58
63
|
imageModel(modelId: BlackForestLabsImageModelId): ImageModelV4;
|
|
59
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Creates a model for video generation.
|
|
67
|
+
*/
|
|
68
|
+
video(modelId: BlackForestLabsVideoModelId): Experimental_VideoModelV4;
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Creates a model for video generation.
|
|
72
|
+
*/
|
|
73
|
+
videoModel(modelId: BlackForestLabsVideoModelId): Experimental_VideoModelV4;
|
|
74
|
+
|
|
60
75
|
/**
|
|
61
76
|
* @deprecated Use `embeddingModel` instead.
|
|
62
77
|
*/
|
|
@@ -92,6 +107,16 @@ export function createBlackForestLabs(
|
|
|
92
107
|
pollTimeoutMillis: options.pollTimeoutMillis,
|
|
93
108
|
});
|
|
94
109
|
|
|
110
|
+
const createVideoModel = (modelId: BlackForestLabsVideoModelId) =>
|
|
111
|
+
new BlackForestLabsVideoModel(modelId, {
|
|
112
|
+
provider: 'black-forest-labs.video',
|
|
113
|
+
baseURL: baseURL ?? defaultBaseURL,
|
|
114
|
+
headers: getHeaders,
|
|
115
|
+
fetch: options.fetch,
|
|
116
|
+
pollIntervalMillis: options.pollIntervalMillis,
|
|
117
|
+
pollTimeoutMillis: options.pollTimeoutMillis,
|
|
118
|
+
});
|
|
119
|
+
|
|
95
120
|
const embeddingModel = (modelId: string) => {
|
|
96
121
|
throw new NoSuchModelError({
|
|
97
122
|
modelId,
|
|
@@ -103,6 +128,8 @@ export function createBlackForestLabs(
|
|
|
103
128
|
specificationVersion: 'v4',
|
|
104
129
|
imageModel: createImageModel,
|
|
105
130
|
image: createImageModel,
|
|
131
|
+
videoModel: createVideoModel,
|
|
132
|
+
video: createVideoModel,
|
|
106
133
|
languageModel: (modelId: string) => {
|
|
107
134
|
throw new NoSuchModelError({
|
|
108
135
|
modelId,
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import {
|
|
2
|
+
lazySchema,
|
|
3
|
+
zodSchema,
|
|
4
|
+
type InferSchema,
|
|
5
|
+
} from '@ai-sdk/provider-utils';
|
|
6
|
+
import { z } from 'zod/v4';
|
|
7
|
+
import {
|
|
8
|
+
blackForestLabsVideoAspectRatios,
|
|
9
|
+
blackForestLabsVideoResolutions,
|
|
10
|
+
} from './black-forest-labs-video-settings';
|
|
11
|
+
|
|
12
|
+
const blackForestLabsTimedVideoKeyframeSchema = z.tuple([
|
|
13
|
+
z.number().min(0).max(20),
|
|
14
|
+
z.string(),
|
|
15
|
+
]);
|
|
16
|
+
|
|
17
|
+
export const blackForestLabsVideoKeyframesSchema = z.union([
|
|
18
|
+
z.array(z.string()).min(1).max(10),
|
|
19
|
+
z
|
|
20
|
+
.array(blackForestLabsTimedVideoKeyframeSchema)
|
|
21
|
+
.min(1)
|
|
22
|
+
.max(10)
|
|
23
|
+
.refine(
|
|
24
|
+
keyframes =>
|
|
25
|
+
keyframes.every(
|
|
26
|
+
(keyframe, index) =>
|
|
27
|
+
index === 0 || keyframe[0] > keyframes[index - 1][0],
|
|
28
|
+
),
|
|
29
|
+
{ message: 'Timed keyframes must be in chronological order.' },
|
|
30
|
+
),
|
|
31
|
+
]);
|
|
32
|
+
|
|
33
|
+
export const blackForestLabsVideoProviderOptions = z.object({
|
|
34
|
+
/**
|
|
35
|
+
* Output resolution tier. Takes precedence over the top-level `resolution`,
|
|
36
|
+
* which is expressed as `{width}x{height}` and has to be mapped onto a tier.
|
|
37
|
+
*/
|
|
38
|
+
resolution: z.enum(blackForestLabsVideoResolutions).optional(),
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Aspect ratio of the generated video. Takes precedence over the top-level
|
|
42
|
+
* `aspectRatio`, and unlike it can be set to `auto`.
|
|
43
|
+
*/
|
|
44
|
+
aspectRatio: z.enum(blackForestLabsVideoAspectRatios).optional(),
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Keyframes for image-to-video generation, for the shapes the top-level
|
|
48
|
+
* `image` and `frameImages` options cannot express: more than two images, or
|
|
49
|
+
* images pinned to a specific second. Takes precedence over both.
|
|
50
|
+
*
|
|
51
|
+
* One image opens the clip, two open and close it, and with more the extras
|
|
52
|
+
* are spaced evenly in between. Three or more plain images require an
|
|
53
|
+
* explicit `duration`.
|
|
54
|
+
*/
|
|
55
|
+
keyframes: blackForestLabsVideoKeyframesSchema.optional(),
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Moderation strictness from 0 (strictest) to 4. Defaults to 2. Sexual
|
|
59
|
+
* content is capped at 3 and hate content at 2 regardless of the request,
|
|
60
|
+
* and any request carrying conditioning media is capped at 2.
|
|
61
|
+
*/
|
|
62
|
+
safetyTolerance: z.number().int().min(0).max(4).optional(),
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Render a fast, lower-quality preview instead of the finished video.
|
|
66
|
+
* Defaults to `false`.
|
|
67
|
+
*/
|
|
68
|
+
draft: z.boolean().optional(),
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Encrypted draft-cache bundle from a prior `draft` generation, which
|
|
72
|
+
* switches the request to draft-enhance mode: the bundle is replayed at full
|
|
73
|
+
* quality.
|
|
74
|
+
*
|
|
75
|
+
* Either the base64-encoded `.bin` downloaded from the draft's `draftCache`
|
|
76
|
+
* URL, or that URL itself while it is still in its expiry window.
|
|
77
|
+
*/
|
|
78
|
+
draftCache: z.string().optional(),
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Model version to pin. Only `latest` is available today.
|
|
82
|
+
*/
|
|
83
|
+
version: z.literal('latest').optional(),
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
export const blackForestLabsVideoModelOptionsSchema = lazySchema(() =>
|
|
87
|
+
zodSchema(blackForestLabsVideoProviderOptions),
|
|
88
|
+
);
|
|
89
|
+
|
|
90
|
+
export type BlackForestLabsVideoModelOptions = InferSchema<
|
|
91
|
+
typeof blackForestLabsVideoModelOptionsSchema
|
|
92
|
+
>;
|