@ai-sdk/fal 0.1.3 → 0.1.4
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 +6 -0
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +33 -4
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +34 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
package/dist/index.d.mts
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -176,14 +176,43 @@ var falFailedResponseHandler = (0, import_provider_utils.createJsonErrorResponse
|
|
|
176
176
|
|
|
177
177
|
// src/fal-provider.ts
|
|
178
178
|
var defaultBaseURL = "https://fal.run";
|
|
179
|
+
function loadFalApiKey({
|
|
180
|
+
apiKey,
|
|
181
|
+
description = "fal.ai"
|
|
182
|
+
}) {
|
|
183
|
+
if (typeof apiKey === "string") {
|
|
184
|
+
return apiKey;
|
|
185
|
+
}
|
|
186
|
+
if (apiKey != null) {
|
|
187
|
+
throw new Error(`${description} API key must be a string.`);
|
|
188
|
+
}
|
|
189
|
+
if (typeof process === "undefined") {
|
|
190
|
+
throw new Error(
|
|
191
|
+
`${description} API key is missing. Pass it using the 'apiKey' parameter. Environment variables are not supported in this environment.`
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
let envApiKey = process.env.FAL_API_KEY;
|
|
195
|
+
if (envApiKey == null) {
|
|
196
|
+
envApiKey = process.env.FAL_KEY;
|
|
197
|
+
}
|
|
198
|
+
if (envApiKey == null) {
|
|
199
|
+
throw new Error(
|
|
200
|
+
`${description} API key is missing. Pass it using the 'apiKey' parameter or set either the FAL_API_KEY or FAL_KEY environment variable.`
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
if (typeof envApiKey !== "string") {
|
|
204
|
+
throw new Error(
|
|
205
|
+
`${description} API key must be a string. The value of the environment variable is not a string.`
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
return envApiKey;
|
|
209
|
+
}
|
|
179
210
|
function createFal(options = {}) {
|
|
180
211
|
var _a;
|
|
181
212
|
const baseURL = (0, import_provider_utils2.withoutTrailingSlash)((_a = options.baseURL) != null ? _a : defaultBaseURL);
|
|
182
213
|
const getHeaders = () => ({
|
|
183
|
-
Authorization: `Key ${(
|
|
184
|
-
apiKey: options.apiKey
|
|
185
|
-
environmentVariableName: "FAL_API_KEY",
|
|
186
|
-
description: "fal.ai"
|
|
214
|
+
Authorization: `Key ${loadFalApiKey({
|
|
215
|
+
apiKey: options.apiKey
|
|
187
216
|
})}`,
|
|
188
217
|
...options.headers
|
|
189
218
|
});
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/fal-provider.ts","../src/fal-image-model.ts"],"sourcesContent":["export { createFal, fal } from './fal-provider';\nexport type { FalProvider, FalProviderSettings } from './fal-provider';\n","import { ImageModelV1, NoSuchModelError, ProviderV1 } from '@ai-sdk/provider';\nimport type { FetchFunction } from '@ai-sdk/provider-utils';\nimport { loadApiKey, withoutTrailingSlash } from '@ai-sdk/provider-utils';\nimport { FalImageModel } from './fal-image-model';\nimport { FalImageModelId, FalImageSettings } from './fal-image-settings';\n\nexport interface FalProviderSettings {\n /**\nfal.ai API key. Default value is taken from the `FAL_API_KEY` environment\nvariable.\n */\n apiKey?: string;\n\n /**\nBase URL for the API calls.\nThe default prefix is `https://fal.run`.\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 FalProvider extends ProviderV1 {\n /**\nCreates a model for image generation.\n */\n image(modelId: FalImageModelId, settings?: FalImageSettings): ImageModelV1;\n\n /**\nCreates a model for image generation.\n */\n imageModel(\n modelId: FalImageModelId,\n settings?: FalImageSettings,\n ): ImageModelV1;\n}\n\nconst defaultBaseURL = 'https://fal.run';\n\n/**\nCreate a fal.ai provider instance.\n */\nexport function createFal(options: FalProviderSettings = {}): FalProvider {\n const baseURL = withoutTrailingSlash(options.baseURL ?? defaultBaseURL);\n const getHeaders = () => ({\n Authorization: `Key ${loadApiKey({\n apiKey: options.apiKey,\n environmentVariableName: 'FAL_API_KEY',\n description: 'fal.ai',\n })}`,\n ...options.headers,\n });\n\n const createImageModel = (\n modelId: FalImageModelId,\n settings: FalImageSettings = {},\n ) =>\n new FalImageModel(modelId, settings, {\n provider: 'fal.image',\n baseURL: baseURL ?? defaultBaseURL,\n headers: getHeaders,\n fetch: options.fetch,\n });\n\n return {\n image: createImageModel,\n imageModel: 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\n/**\nDefault fal.ai provider instance.\n */\nexport const fal = createFal();\n","import type { ImageModelV1, ImageModelV1CallWarning } from '@ai-sdk/provider';\nimport type { Resolvable } from '@ai-sdk/provider-utils';\nimport {\n FetchFunction,\n combineHeaders,\n createBinaryResponseHandler,\n createJsonResponseHandler,\n createJsonErrorResponseHandler,\n createStatusCodeErrorResponseHandler,\n getFromApi,\n postJsonToApi,\n resolve,\n} from '@ai-sdk/provider-utils';\nimport { z } from 'zod';\nimport {\n FalImageModelId,\n FalImageSettings,\n FalImageSize,\n} from './fal-image-settings';\n\ninterface FalImageModelConfig {\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 FalImageModel implements ImageModelV1 {\n readonly specificationVersion = 'v1';\n\n get provider(): string {\n return this.config.provider;\n }\n\n get maxImagesPerCall(): number {\n return this.settings.maxImagesPerCall ?? 1;\n }\n\n constructor(\n readonly modelId: FalImageModelId,\n private readonly settings: FalImageSettings,\n private readonly config: FalImageModelConfig,\n ) {}\n\n async doGenerate({\n prompt,\n n,\n size,\n aspectRatio,\n seed,\n providerOptions,\n headers,\n abortSignal,\n }: Parameters<ImageModelV1['doGenerate']>[0]): Promise<\n Awaited<ReturnType<ImageModelV1['doGenerate']>>\n > {\n const warnings: Array<ImageModelV1CallWarning> = [];\n\n let imageSize: FalImageSize | undefined;\n if (size) {\n const [width, height] = size.split('x').map(Number);\n imageSize = { width, height };\n } else if (aspectRatio) {\n imageSize = convertAspectRatioToSize(aspectRatio);\n }\n\n const currentDate = this.config._internal?.currentDate?.() ?? new Date();\n const { value, responseHeaders } = await postJsonToApi({\n url: `${this.config.baseURL}/${this.modelId}`,\n headers: combineHeaders(await resolve(this.config.headers), headers),\n body: {\n prompt,\n seed,\n image_size: imageSize,\n num_images: n,\n ...(providerOptions.fal ?? {}),\n },\n failedResponseHandler: falFailedResponseHandler,\n successfulResponseHandler: createJsonResponseHandler(\n falImageResponseSchema,\n ),\n abortSignal,\n fetch: this.config.fetch,\n });\n\n // download the images:\n const targetImages = 'images' in value ? value.images : [value.image];\n const downloadedImages = await Promise.all(\n targetImages.map(image => this.downloadImage(image.url, abortSignal)),\n );\n\n return {\n images: downloadedImages,\n warnings,\n response: {\n modelId: this.modelId,\n timestamp: currentDate,\n headers: responseHeaders,\n },\n };\n }\n\n private async downloadImage(\n url: string,\n abortSignal: AbortSignal | undefined,\n ): Promise<Uint8Array> {\n const { value: response } = await getFromApi({\n url,\n // No specific headers should be needed for this request as it's a\n // generated image provided by fal.ai.\n abortSignal,\n failedResponseHandler: createStatusCodeErrorResponseHandler(),\n successfulResponseHandler: createBinaryResponseHandler(),\n fetch: this.config.fetch,\n });\n return response;\n }\n}\n\n/**\nConverts an aspect ratio to an image size compatible with fal.ai APIs.\n@param aspectRatio - The aspect ratio to convert.\n@returns The image size.\n */\nfunction convertAspectRatioToSize(\n aspectRatio: `${number}:${number}`,\n): FalImageSize | undefined {\n switch (aspectRatio) {\n case '1:1':\n return 'square_hd';\n case '16:9':\n return 'landscape_16_9';\n case '9:16':\n return 'portrait_16_9';\n case '4:3':\n return 'landscape_4_3';\n case '3:4':\n return 'portrait_4_3';\n case '16:10':\n return { width: 1280, height: 800 };\n case '10:16':\n return { width: 800, height: 1280 };\n case '21:9':\n return { width: 2560, height: 1080 };\n case '9:21':\n return { width: 1080, height: 2560 };\n }\n return undefined;\n}\n\n// Validation error has a particular payload to inform the exact property that is invalid\nconst falValidationErrorSchema = z.object({\n detail: z.array(\n z.object({\n loc: z.array(z.string()),\n msg: z.string(),\n type: z.string(),\n }),\n ),\n});\n\ntype ValidationError = z.infer<typeof falValidationErrorSchema>;\n\n// Other errors have a message property\nconst falHttpErrorSchema = z.object({\n message: z.string(),\n});\n\nconst falErrorSchema = z.union([falValidationErrorSchema, falHttpErrorSchema]);\n\nconst falImageSchema = z.object({\n url: z.string(),\n width: z.number(),\n height: z.number(),\n content_type: z.string(),\n});\n\nconst falImageResponseSchema = z.union([\n z.object({\n images: z.array(falImageSchema),\n }),\n z.object({\n image: falImageSchema,\n }),\n]);\n\nfunction isValidationError(error: unknown): error is ValidationError {\n return falValidationErrorSchema.safeParse(error).success;\n}\n\nconst falFailedResponseHandler = createJsonErrorResponseHandler({\n errorSchema: falErrorSchema,\n errorToMessage: error => {\n if (isValidationError(error)) {\n return error.detail\n .map(detail => `${detail.loc.join('.')}: ${detail.msg}`)\n .join('\\n');\n }\n return error.message ?? 'Unknown fal error';\n },\n});\n"],"mappings":"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","names":["import_provider_utils"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/fal-provider.ts","../src/fal-image-model.ts"],"sourcesContent":["export { createFal, fal } from './fal-provider';\nexport type { FalProvider, FalProviderSettings } from './fal-provider';\n","import { ImageModelV1, NoSuchModelError, ProviderV1 } from '@ai-sdk/provider';\nimport type { FetchFunction } from '@ai-sdk/provider-utils';\nimport { withoutTrailingSlash } from '@ai-sdk/provider-utils';\nimport { FalImageModel } from './fal-image-model';\nimport { FalImageModelId, FalImageSettings } from './fal-image-settings';\n\nexport interface FalProviderSettings {\n /**\nfal.ai API key. Default value is taken from the `FAL_API_KEY` environment\nvariable, falling back to `FAL_KEY`.\n */\n apiKey?: string;\n\n /**\nBase URL for the API calls.\nThe default prefix is `https://fal.run`.\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 FalProvider extends ProviderV1 {\n /**\nCreates a model for image generation.\n */\n image(modelId: FalImageModelId, settings?: FalImageSettings): ImageModelV1;\n\n /**\nCreates a model for image generation.\n */\n imageModel(\n modelId: FalImageModelId,\n settings?: FalImageSettings,\n ): ImageModelV1;\n}\n\nconst defaultBaseURL = 'https://fal.run';\n\nfunction loadFalApiKey({\n apiKey,\n description = 'fal.ai',\n}: {\n apiKey: string | undefined;\n description?: string;\n}): string {\n if (typeof apiKey === 'string') {\n return apiKey;\n }\n\n if (apiKey != null) {\n throw new Error(`${description} API key must be a string.`);\n }\n\n if (typeof process === 'undefined') {\n throw new Error(\n `${description} API key is missing. Pass it using the 'apiKey' parameter. Environment variables are not supported in this environment.`,\n );\n }\n\n let envApiKey = process.env.FAL_API_KEY;\n if (envApiKey == null) {\n envApiKey = process.env.FAL_KEY;\n }\n\n if (envApiKey == null) {\n throw new Error(\n `${description} API key is missing. Pass it using the 'apiKey' parameter or set either the FAL_API_KEY or FAL_KEY environment variable.`,\n );\n }\n\n if (typeof envApiKey !== 'string') {\n throw new Error(\n `${description} API key must be a string. The value of the environment variable is not a string.`,\n );\n }\n\n return envApiKey;\n}\n\n/**\nCreate a fal.ai provider instance.\n */\nexport function createFal(options: FalProviderSettings = {}): FalProvider {\n const baseURL = withoutTrailingSlash(options.baseURL ?? defaultBaseURL);\n const getHeaders = () => ({\n Authorization: `Key ${loadFalApiKey({\n apiKey: options.apiKey,\n })}`,\n ...options.headers,\n });\n\n const createImageModel = (\n modelId: FalImageModelId,\n settings: FalImageSettings = {},\n ) =>\n new FalImageModel(modelId, settings, {\n provider: 'fal.image',\n baseURL: baseURL ?? defaultBaseURL,\n headers: getHeaders,\n fetch: options.fetch,\n });\n\n return {\n image: createImageModel,\n imageModel: 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\n/**\nDefault fal.ai provider instance.\n */\nexport const fal = createFal();\n","import type { ImageModelV1, ImageModelV1CallWarning } from '@ai-sdk/provider';\nimport type { Resolvable } from '@ai-sdk/provider-utils';\nimport {\n FetchFunction,\n combineHeaders,\n createBinaryResponseHandler,\n createJsonResponseHandler,\n createJsonErrorResponseHandler,\n createStatusCodeErrorResponseHandler,\n getFromApi,\n postJsonToApi,\n resolve,\n} from '@ai-sdk/provider-utils';\nimport { z } from 'zod';\nimport {\n FalImageModelId,\n FalImageSettings,\n FalImageSize,\n} from './fal-image-settings';\n\ninterface FalImageModelConfig {\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 FalImageModel implements ImageModelV1 {\n readonly specificationVersion = 'v1';\n\n get provider(): string {\n return this.config.provider;\n }\n\n get maxImagesPerCall(): number {\n return this.settings.maxImagesPerCall ?? 1;\n }\n\n constructor(\n readonly modelId: FalImageModelId,\n private readonly settings: FalImageSettings,\n private readonly config: FalImageModelConfig,\n ) {}\n\n async doGenerate({\n prompt,\n n,\n size,\n aspectRatio,\n seed,\n providerOptions,\n headers,\n abortSignal,\n }: Parameters<ImageModelV1['doGenerate']>[0]): Promise<\n Awaited<ReturnType<ImageModelV1['doGenerate']>>\n > {\n const warnings: Array<ImageModelV1CallWarning> = [];\n\n let imageSize: FalImageSize | undefined;\n if (size) {\n const [width, height] = size.split('x').map(Number);\n imageSize = { width, height };\n } else if (aspectRatio) {\n imageSize = convertAspectRatioToSize(aspectRatio);\n }\n\n const currentDate = this.config._internal?.currentDate?.() ?? new Date();\n const { value, responseHeaders } = await postJsonToApi({\n url: `${this.config.baseURL}/${this.modelId}`,\n headers: combineHeaders(await resolve(this.config.headers), headers),\n body: {\n prompt,\n seed,\n image_size: imageSize,\n num_images: n,\n ...(providerOptions.fal ?? {}),\n },\n failedResponseHandler: falFailedResponseHandler,\n successfulResponseHandler: createJsonResponseHandler(\n falImageResponseSchema,\n ),\n abortSignal,\n fetch: this.config.fetch,\n });\n\n // download the images:\n const targetImages = 'images' in value ? value.images : [value.image];\n const downloadedImages = await Promise.all(\n targetImages.map(image => this.downloadImage(image.url, abortSignal)),\n );\n\n return {\n images: downloadedImages,\n warnings,\n response: {\n modelId: this.modelId,\n timestamp: currentDate,\n headers: responseHeaders,\n },\n };\n }\n\n private async downloadImage(\n url: string,\n abortSignal: AbortSignal | undefined,\n ): Promise<Uint8Array> {\n const { value: response } = await getFromApi({\n url,\n // No specific headers should be needed for this request as it's a\n // generated image provided by fal.ai.\n abortSignal,\n failedResponseHandler: createStatusCodeErrorResponseHandler(),\n successfulResponseHandler: createBinaryResponseHandler(),\n fetch: this.config.fetch,\n });\n return response;\n }\n}\n\n/**\nConverts an aspect ratio to an image size compatible with fal.ai APIs.\n@param aspectRatio - The aspect ratio to convert.\n@returns The image size.\n */\nfunction convertAspectRatioToSize(\n aspectRatio: `${number}:${number}`,\n): FalImageSize | undefined {\n switch (aspectRatio) {\n case '1:1':\n return 'square_hd';\n case '16:9':\n return 'landscape_16_9';\n case '9:16':\n return 'portrait_16_9';\n case '4:3':\n return 'landscape_4_3';\n case '3:4':\n return 'portrait_4_3';\n case '16:10':\n return { width: 1280, height: 800 };\n case '10:16':\n return { width: 800, height: 1280 };\n case '21:9':\n return { width: 2560, height: 1080 };\n case '9:21':\n return { width: 1080, height: 2560 };\n }\n return undefined;\n}\n\n// Validation error has a particular payload to inform the exact property that is invalid\nconst falValidationErrorSchema = z.object({\n detail: z.array(\n z.object({\n loc: z.array(z.string()),\n msg: z.string(),\n type: z.string(),\n }),\n ),\n});\n\ntype ValidationError = z.infer<typeof falValidationErrorSchema>;\n\n// Other errors have a message property\nconst falHttpErrorSchema = z.object({\n message: z.string(),\n});\n\nconst falErrorSchema = z.union([falValidationErrorSchema, falHttpErrorSchema]);\n\nconst falImageSchema = z.object({\n url: z.string(),\n width: z.number(),\n height: z.number(),\n content_type: z.string(),\n});\n\nconst falImageResponseSchema = z.union([\n z.object({\n images: z.array(falImageSchema),\n }),\n z.object({\n image: falImageSchema,\n }),\n]);\n\nfunction isValidationError(error: unknown): error is ValidationError {\n return falValidationErrorSchema.safeParse(error).success;\n}\n\nconst falFailedResponseHandler = createJsonErrorResponseHandler({\n errorSchema: falErrorSchema,\n errorToMessage: error => {\n if (isValidationError(error)) {\n return error.detail\n .map(detail => `${detail.loc.join('.')}: ${detail.msg}`)\n .join('\\n');\n }\n return error.message ?? 'Unknown fal error';\n },\n});\n"],"mappings":"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","names":["import_provider_utils"]}
|
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/fal-provider.ts
|
|
2
2
|
import { NoSuchModelError } from "@ai-sdk/provider";
|
|
3
|
-
import {
|
|
3
|
+
import { withoutTrailingSlash } from "@ai-sdk/provider-utils";
|
|
4
4
|
|
|
5
5
|
// src/fal-image-model.ts
|
|
6
6
|
import {
|
|
@@ -158,14 +158,43 @@ var falFailedResponseHandler = createJsonErrorResponseHandler({
|
|
|
158
158
|
|
|
159
159
|
// src/fal-provider.ts
|
|
160
160
|
var defaultBaseURL = "https://fal.run";
|
|
161
|
+
function loadFalApiKey({
|
|
162
|
+
apiKey,
|
|
163
|
+
description = "fal.ai"
|
|
164
|
+
}) {
|
|
165
|
+
if (typeof apiKey === "string") {
|
|
166
|
+
return apiKey;
|
|
167
|
+
}
|
|
168
|
+
if (apiKey != null) {
|
|
169
|
+
throw new Error(`${description} API key must be a string.`);
|
|
170
|
+
}
|
|
171
|
+
if (typeof process === "undefined") {
|
|
172
|
+
throw new Error(
|
|
173
|
+
`${description} API key is missing. Pass it using the 'apiKey' parameter. Environment variables are not supported in this environment.`
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
let envApiKey = process.env.FAL_API_KEY;
|
|
177
|
+
if (envApiKey == null) {
|
|
178
|
+
envApiKey = process.env.FAL_KEY;
|
|
179
|
+
}
|
|
180
|
+
if (envApiKey == null) {
|
|
181
|
+
throw new Error(
|
|
182
|
+
`${description} API key is missing. Pass it using the 'apiKey' parameter or set either the FAL_API_KEY or FAL_KEY environment variable.`
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
if (typeof envApiKey !== "string") {
|
|
186
|
+
throw new Error(
|
|
187
|
+
`${description} API key must be a string. The value of the environment variable is not a string.`
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
return envApiKey;
|
|
191
|
+
}
|
|
161
192
|
function createFal(options = {}) {
|
|
162
193
|
var _a;
|
|
163
194
|
const baseURL = withoutTrailingSlash((_a = options.baseURL) != null ? _a : defaultBaseURL);
|
|
164
195
|
const getHeaders = () => ({
|
|
165
|
-
Authorization: `Key ${
|
|
166
|
-
apiKey: options.apiKey
|
|
167
|
-
environmentVariableName: "FAL_API_KEY",
|
|
168
|
-
description: "fal.ai"
|
|
196
|
+
Authorization: `Key ${loadFalApiKey({
|
|
197
|
+
apiKey: options.apiKey
|
|
169
198
|
})}`,
|
|
170
199
|
...options.headers
|
|
171
200
|
});
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/fal-provider.ts","../src/fal-image-model.ts"],"sourcesContent":["import { ImageModelV1, NoSuchModelError, ProviderV1 } from '@ai-sdk/provider';\nimport type { FetchFunction } from '@ai-sdk/provider-utils';\nimport { loadApiKey, withoutTrailingSlash } from '@ai-sdk/provider-utils';\nimport { FalImageModel } from './fal-image-model';\nimport { FalImageModelId, FalImageSettings } from './fal-image-settings';\n\nexport interface FalProviderSettings {\n /**\nfal.ai API key. Default value is taken from the `FAL_API_KEY` environment\nvariable.\n */\n apiKey?: string;\n\n /**\nBase URL for the API calls.\nThe default prefix is `https://fal.run`.\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 FalProvider extends ProviderV1 {\n /**\nCreates a model for image generation.\n */\n image(modelId: FalImageModelId, settings?: FalImageSettings): ImageModelV1;\n\n /**\nCreates a model for image generation.\n */\n imageModel(\n modelId: FalImageModelId,\n settings?: FalImageSettings,\n ): ImageModelV1;\n}\n\nconst defaultBaseURL = 'https://fal.run';\n\n/**\nCreate a fal.ai provider instance.\n */\nexport function createFal(options: FalProviderSettings = {}): FalProvider {\n const baseURL = withoutTrailingSlash(options.baseURL ?? defaultBaseURL);\n const getHeaders = () => ({\n Authorization: `Key ${loadApiKey({\n apiKey: options.apiKey,\n environmentVariableName: 'FAL_API_KEY',\n description: 'fal.ai',\n })}`,\n ...options.headers,\n });\n\n const createImageModel = (\n modelId: FalImageModelId,\n settings: FalImageSettings = {},\n ) =>\n new FalImageModel(modelId, settings, {\n provider: 'fal.image',\n baseURL: baseURL ?? defaultBaseURL,\n headers: getHeaders,\n fetch: options.fetch,\n });\n\n return {\n image: createImageModel,\n imageModel: 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\n/**\nDefault fal.ai provider instance.\n */\nexport const fal = createFal();\n","import type { ImageModelV1, ImageModelV1CallWarning } from '@ai-sdk/provider';\nimport type { Resolvable } from '@ai-sdk/provider-utils';\nimport {\n FetchFunction,\n combineHeaders,\n createBinaryResponseHandler,\n createJsonResponseHandler,\n createJsonErrorResponseHandler,\n createStatusCodeErrorResponseHandler,\n getFromApi,\n postJsonToApi,\n resolve,\n} from '@ai-sdk/provider-utils';\nimport { z } from 'zod';\nimport {\n FalImageModelId,\n FalImageSettings,\n FalImageSize,\n} from './fal-image-settings';\n\ninterface FalImageModelConfig {\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 FalImageModel implements ImageModelV1 {\n readonly specificationVersion = 'v1';\n\n get provider(): string {\n return this.config.provider;\n }\n\n get maxImagesPerCall(): number {\n return this.settings.maxImagesPerCall ?? 1;\n }\n\n constructor(\n readonly modelId: FalImageModelId,\n private readonly settings: FalImageSettings,\n private readonly config: FalImageModelConfig,\n ) {}\n\n async doGenerate({\n prompt,\n n,\n size,\n aspectRatio,\n seed,\n providerOptions,\n headers,\n abortSignal,\n }: Parameters<ImageModelV1['doGenerate']>[0]): Promise<\n Awaited<ReturnType<ImageModelV1['doGenerate']>>\n > {\n const warnings: Array<ImageModelV1CallWarning> = [];\n\n let imageSize: FalImageSize | undefined;\n if (size) {\n const [width, height] = size.split('x').map(Number);\n imageSize = { width, height };\n } else if (aspectRatio) {\n imageSize = convertAspectRatioToSize(aspectRatio);\n }\n\n const currentDate = this.config._internal?.currentDate?.() ?? new Date();\n const { value, responseHeaders } = await postJsonToApi({\n url: `${this.config.baseURL}/${this.modelId}`,\n headers: combineHeaders(await resolve(this.config.headers), headers),\n body: {\n prompt,\n seed,\n image_size: imageSize,\n num_images: n,\n ...(providerOptions.fal ?? {}),\n },\n failedResponseHandler: falFailedResponseHandler,\n successfulResponseHandler: createJsonResponseHandler(\n falImageResponseSchema,\n ),\n abortSignal,\n fetch: this.config.fetch,\n });\n\n // download the images:\n const targetImages = 'images' in value ? value.images : [value.image];\n const downloadedImages = await Promise.all(\n targetImages.map(image => this.downloadImage(image.url, abortSignal)),\n );\n\n return {\n images: downloadedImages,\n warnings,\n response: {\n modelId: this.modelId,\n timestamp: currentDate,\n headers: responseHeaders,\n },\n };\n }\n\n private async downloadImage(\n url: string,\n abortSignal: AbortSignal | undefined,\n ): Promise<Uint8Array> {\n const { value: response } = await getFromApi({\n url,\n // No specific headers should be needed for this request as it's a\n // generated image provided by fal.ai.\n abortSignal,\n failedResponseHandler: createStatusCodeErrorResponseHandler(),\n successfulResponseHandler: createBinaryResponseHandler(),\n fetch: this.config.fetch,\n });\n return response;\n }\n}\n\n/**\nConverts an aspect ratio to an image size compatible with fal.ai APIs.\n@param aspectRatio - The aspect ratio to convert.\n@returns The image size.\n */\nfunction convertAspectRatioToSize(\n aspectRatio: `${number}:${number}`,\n): FalImageSize | undefined {\n switch (aspectRatio) {\n case '1:1':\n return 'square_hd';\n case '16:9':\n return 'landscape_16_9';\n case '9:16':\n return 'portrait_16_9';\n case '4:3':\n return 'landscape_4_3';\n case '3:4':\n return 'portrait_4_3';\n case '16:10':\n return { width: 1280, height: 800 };\n case '10:16':\n return { width: 800, height: 1280 };\n case '21:9':\n return { width: 2560, height: 1080 };\n case '9:21':\n return { width: 1080, height: 2560 };\n }\n return undefined;\n}\n\n// Validation error has a particular payload to inform the exact property that is invalid\nconst falValidationErrorSchema = z.object({\n detail: z.array(\n z.object({\n loc: z.array(z.string()),\n msg: z.string(),\n type: z.string(),\n }),\n ),\n});\n\ntype ValidationError = z.infer<typeof falValidationErrorSchema>;\n\n// Other errors have a message property\nconst falHttpErrorSchema = z.object({\n message: z.string(),\n});\n\nconst falErrorSchema = z.union([falValidationErrorSchema, falHttpErrorSchema]);\n\nconst falImageSchema = z.object({\n url: z.string(),\n width: z.number(),\n height: z.number(),\n content_type: z.string(),\n});\n\nconst falImageResponseSchema = z.union([\n z.object({\n images: z.array(falImageSchema),\n }),\n z.object({\n image: falImageSchema,\n }),\n]);\n\nfunction isValidationError(error: unknown): error is ValidationError {\n return falValidationErrorSchema.safeParse(error).success;\n}\n\nconst falFailedResponseHandler = createJsonErrorResponseHandler({\n errorSchema: falErrorSchema,\n errorToMessage: error => {\n if (isValidationError(error)) {\n return error.detail\n .map(detail => `${detail.loc.join('.')}: ${detail.msg}`)\n .join('\\n');\n }\n return error.message ?? 'Unknown fal error';\n },\n});\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/fal-provider.ts","../src/fal-image-model.ts"],"sourcesContent":["import { ImageModelV1, NoSuchModelError, ProviderV1 } from '@ai-sdk/provider';\nimport type { FetchFunction } from '@ai-sdk/provider-utils';\nimport { withoutTrailingSlash } from '@ai-sdk/provider-utils';\nimport { FalImageModel } from './fal-image-model';\nimport { FalImageModelId, FalImageSettings } from './fal-image-settings';\n\nexport interface FalProviderSettings {\n /**\nfal.ai API key. Default value is taken from the `FAL_API_KEY` environment\nvariable, falling back to `FAL_KEY`.\n */\n apiKey?: string;\n\n /**\nBase URL for the API calls.\nThe default prefix is `https://fal.run`.\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 FalProvider extends ProviderV1 {\n /**\nCreates a model for image generation.\n */\n image(modelId: FalImageModelId, settings?: FalImageSettings): ImageModelV1;\n\n /**\nCreates a model for image generation.\n */\n imageModel(\n modelId: FalImageModelId,\n settings?: FalImageSettings,\n ): ImageModelV1;\n}\n\nconst defaultBaseURL = 'https://fal.run';\n\nfunction loadFalApiKey({\n apiKey,\n description = 'fal.ai',\n}: {\n apiKey: string | undefined;\n description?: string;\n}): string {\n if (typeof apiKey === 'string') {\n return apiKey;\n }\n\n if (apiKey != null) {\n throw new Error(`${description} API key must be a string.`);\n }\n\n if (typeof process === 'undefined') {\n throw new Error(\n `${description} API key is missing. Pass it using the 'apiKey' parameter. Environment variables are not supported in this environment.`,\n );\n }\n\n let envApiKey = process.env.FAL_API_KEY;\n if (envApiKey == null) {\n envApiKey = process.env.FAL_KEY;\n }\n\n if (envApiKey == null) {\n throw new Error(\n `${description} API key is missing. Pass it using the 'apiKey' parameter or set either the FAL_API_KEY or FAL_KEY environment variable.`,\n );\n }\n\n if (typeof envApiKey !== 'string') {\n throw new Error(\n `${description} API key must be a string. The value of the environment variable is not a string.`,\n );\n }\n\n return envApiKey;\n}\n\n/**\nCreate a fal.ai provider instance.\n */\nexport function createFal(options: FalProviderSettings = {}): FalProvider {\n const baseURL = withoutTrailingSlash(options.baseURL ?? defaultBaseURL);\n const getHeaders = () => ({\n Authorization: `Key ${loadFalApiKey({\n apiKey: options.apiKey,\n })}`,\n ...options.headers,\n });\n\n const createImageModel = (\n modelId: FalImageModelId,\n settings: FalImageSettings = {},\n ) =>\n new FalImageModel(modelId, settings, {\n provider: 'fal.image',\n baseURL: baseURL ?? defaultBaseURL,\n headers: getHeaders,\n fetch: options.fetch,\n });\n\n return {\n image: createImageModel,\n imageModel: 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\n/**\nDefault fal.ai provider instance.\n */\nexport const fal = createFal();\n","import type { ImageModelV1, ImageModelV1CallWarning } from '@ai-sdk/provider';\nimport type { Resolvable } from '@ai-sdk/provider-utils';\nimport {\n FetchFunction,\n combineHeaders,\n createBinaryResponseHandler,\n createJsonResponseHandler,\n createJsonErrorResponseHandler,\n createStatusCodeErrorResponseHandler,\n getFromApi,\n postJsonToApi,\n resolve,\n} from '@ai-sdk/provider-utils';\nimport { z } from 'zod';\nimport {\n FalImageModelId,\n FalImageSettings,\n FalImageSize,\n} from './fal-image-settings';\n\ninterface FalImageModelConfig {\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 FalImageModel implements ImageModelV1 {\n readonly specificationVersion = 'v1';\n\n get provider(): string {\n return this.config.provider;\n }\n\n get maxImagesPerCall(): number {\n return this.settings.maxImagesPerCall ?? 1;\n }\n\n constructor(\n readonly modelId: FalImageModelId,\n private readonly settings: FalImageSettings,\n private readonly config: FalImageModelConfig,\n ) {}\n\n async doGenerate({\n prompt,\n n,\n size,\n aspectRatio,\n seed,\n providerOptions,\n headers,\n abortSignal,\n }: Parameters<ImageModelV1['doGenerate']>[0]): Promise<\n Awaited<ReturnType<ImageModelV1['doGenerate']>>\n > {\n const warnings: Array<ImageModelV1CallWarning> = [];\n\n let imageSize: FalImageSize | undefined;\n if (size) {\n const [width, height] = size.split('x').map(Number);\n imageSize = { width, height };\n } else if (aspectRatio) {\n imageSize = convertAspectRatioToSize(aspectRatio);\n }\n\n const currentDate = this.config._internal?.currentDate?.() ?? new Date();\n const { value, responseHeaders } = await postJsonToApi({\n url: `${this.config.baseURL}/${this.modelId}`,\n headers: combineHeaders(await resolve(this.config.headers), headers),\n body: {\n prompt,\n seed,\n image_size: imageSize,\n num_images: n,\n ...(providerOptions.fal ?? {}),\n },\n failedResponseHandler: falFailedResponseHandler,\n successfulResponseHandler: createJsonResponseHandler(\n falImageResponseSchema,\n ),\n abortSignal,\n fetch: this.config.fetch,\n });\n\n // download the images:\n const targetImages = 'images' in value ? value.images : [value.image];\n const downloadedImages = await Promise.all(\n targetImages.map(image => this.downloadImage(image.url, abortSignal)),\n );\n\n return {\n images: downloadedImages,\n warnings,\n response: {\n modelId: this.modelId,\n timestamp: currentDate,\n headers: responseHeaders,\n },\n };\n }\n\n private async downloadImage(\n url: string,\n abortSignal: AbortSignal | undefined,\n ): Promise<Uint8Array> {\n const { value: response } = await getFromApi({\n url,\n // No specific headers should be needed for this request as it's a\n // generated image provided by fal.ai.\n abortSignal,\n failedResponseHandler: createStatusCodeErrorResponseHandler(),\n successfulResponseHandler: createBinaryResponseHandler(),\n fetch: this.config.fetch,\n });\n return response;\n }\n}\n\n/**\nConverts an aspect ratio to an image size compatible with fal.ai APIs.\n@param aspectRatio - The aspect ratio to convert.\n@returns The image size.\n */\nfunction convertAspectRatioToSize(\n aspectRatio: `${number}:${number}`,\n): FalImageSize | undefined {\n switch (aspectRatio) {\n case '1:1':\n return 'square_hd';\n case '16:9':\n return 'landscape_16_9';\n case '9:16':\n return 'portrait_16_9';\n case '4:3':\n return 'landscape_4_3';\n case '3:4':\n return 'portrait_4_3';\n case '16:10':\n return { width: 1280, height: 800 };\n case '10:16':\n return { width: 800, height: 1280 };\n case '21:9':\n return { width: 2560, height: 1080 };\n case '9:21':\n return { width: 1080, height: 2560 };\n }\n return undefined;\n}\n\n// Validation error has a particular payload to inform the exact property that is invalid\nconst falValidationErrorSchema = z.object({\n detail: z.array(\n z.object({\n loc: z.array(z.string()),\n msg: z.string(),\n type: z.string(),\n }),\n ),\n});\n\ntype ValidationError = z.infer<typeof falValidationErrorSchema>;\n\n// Other errors have a message property\nconst falHttpErrorSchema = z.object({\n message: z.string(),\n});\n\nconst falErrorSchema = z.union([falValidationErrorSchema, falHttpErrorSchema]);\n\nconst falImageSchema = z.object({\n url: z.string(),\n width: z.number(),\n height: z.number(),\n content_type: z.string(),\n});\n\nconst falImageResponseSchema = z.union([\n z.object({\n images: z.array(falImageSchema),\n }),\n z.object({\n image: falImageSchema,\n }),\n]);\n\nfunction isValidationError(error: unknown): error is ValidationError {\n return falValidationErrorSchema.safeParse(error).success;\n}\n\nconst falFailedResponseHandler = createJsonErrorResponseHandler({\n errorSchema: falErrorSchema,\n errorToMessage: error => {\n if (isValidationError(error)) {\n return error.detail\n .map(detail => `${detail.loc.join('.')}: ${detail.msg}`)\n .join('\\n');\n }\n return error.message ?? 'Unknown fal error';\n },\n});\n"],"mappings":"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","names":[]}
|