@broberg/ai-sdk 0.10.1 → 0.10.3
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/dist/index.d.ts +9 -2
- package/dist/index.js +39 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -164,6 +164,9 @@ interface ImageRequest {
|
|
|
164
164
|
height?: number;
|
|
165
165
|
/** LoRAs to merge at inference (F021) — e.g. a trained brand/style LoRA. */
|
|
166
166
|
loras?: LoraWeight[];
|
|
167
|
+
/** F021.4 — re-roll once with a fresh seed if fal's safety-checker false-positives
|
|
168
|
+
* and returns a black image (has_nsfw_concepts). fal only. */
|
|
169
|
+
retryOnBlack?: boolean;
|
|
167
170
|
}
|
|
168
171
|
interface ImageResult {
|
|
169
172
|
url: string;
|
|
@@ -929,6 +932,8 @@ declare const imageInputSchema: z.ZodObject<{
|
|
|
929
932
|
}>, "many">>;
|
|
930
933
|
/** Shorthand for a single LoRA — normalized to loras:[{path, scale:1}]. */
|
|
931
934
|
lora: z.ZodOptional<z.ZodString>;
|
|
935
|
+
/** F021.4 — re-roll once if fal returns a black image (NSFW false-positive). */
|
|
936
|
+
retryOnBlack: z.ZodOptional<z.ZodBoolean>;
|
|
932
937
|
}, "strip", z.ZodTypeAny, {
|
|
933
938
|
prompt: string;
|
|
934
939
|
purpose?: string | undefined;
|
|
@@ -951,6 +956,7 @@ declare const imageInputSchema: z.ZodObject<{
|
|
|
951
956
|
labels?: Record<string, string> | undefined;
|
|
952
957
|
width?: number | undefined;
|
|
953
958
|
height?: number | undefined;
|
|
959
|
+
retryOnBlack?: boolean | undefined;
|
|
954
960
|
}, {
|
|
955
961
|
prompt: string;
|
|
956
962
|
purpose?: string | undefined;
|
|
@@ -973,6 +979,7 @@ declare const imageInputSchema: z.ZodObject<{
|
|
|
973
979
|
labels?: Record<string, string> | undefined;
|
|
974
980
|
width?: number | undefined;
|
|
975
981
|
height?: number | undefined;
|
|
982
|
+
retryOnBlack?: boolean | undefined;
|
|
976
983
|
}>;
|
|
977
984
|
declare const trainStyleInputSchema: z.ZodObject<{
|
|
978
985
|
tier: z.ZodOptional<z.ZodEnum<["fast", "smart", "powerful", "cheap", "vision", "video", "embedding"]>>;
|
|
@@ -1680,8 +1687,8 @@ declare const falStubAdapter: ProviderAdapter;
|
|
|
1680
1687
|
* wires the live adapters. */
|
|
1681
1688
|
declare const stubProviders: Record<string, ProviderAdapter>;
|
|
1682
1689
|
|
|
1683
|
-
declare const VERSION: "0.10.
|
|
1684
|
-
declare const SDK_TAG: "@broberg/ai-sdk@0.10.
|
|
1690
|
+
declare const VERSION: "0.10.3";
|
|
1691
|
+
declare const SDK_TAG: "@broberg/ai-sdk@0.10.3";
|
|
1685
1692
|
|
|
1686
1693
|
/** Built-in defaults. Every entry is overridable via AiConfig.defaults or a
|
|
1687
1694
|
* per-call override. Model IDs are current at scaffold time; callers pin their
|
package/dist/index.js
CHANGED
|
@@ -1317,7 +1317,13 @@ function falAdapter(config = {}) {
|
|
|
1317
1317
|
body.loras = req.loras.map((l) => ({ path: l.path, scale: l.scale ?? 1 }));
|
|
1318
1318
|
}
|
|
1319
1319
|
const mode = config.mode ?? "sync";
|
|
1320
|
-
const
|
|
1320
|
+
const run = (b) => mode === "sync" ? runSync(req.spec.model, headers, b) : runQueue(req.spec.model, headers, b);
|
|
1321
|
+
let calls = 1;
|
|
1322
|
+
let { url, flagged } = await run(body);
|
|
1323
|
+
if (flagged && req.retryOnBlack) {
|
|
1324
|
+
calls++;
|
|
1325
|
+
({ url, flagged } = await run({ ...body, seed: Math.floor(Math.random() * 1e9) }));
|
|
1326
|
+
}
|
|
1321
1327
|
const usage = freshUsage({
|
|
1322
1328
|
provider: "fal",
|
|
1323
1329
|
model: req.spec.model,
|
|
@@ -1326,7 +1332,7 @@ function falAdapter(config = {}) {
|
|
|
1326
1332
|
inputTokens: 0,
|
|
1327
1333
|
outputTokens: 0
|
|
1328
1334
|
});
|
|
1329
|
-
usage.costUsd = config.pricePerImage ?? FAL_IMAGE_PRICE_ESTIMATE[req.spec.model] ?? 0;
|
|
1335
|
+
usage.costUsd = (config.pricePerImage ?? FAL_IMAGE_PRICE_ESTIMATE[req.spec.model] ?? 0) * calls;
|
|
1330
1336
|
return { url, usage };
|
|
1331
1337
|
}
|
|
1332
1338
|
async function trainStyle(req) {
|
|
@@ -1334,7 +1340,7 @@ function falAdapter(config = {}) {
|
|
|
1334
1340
|
if (!apiKey) throw new Error("fal adapter: FAL_KEY not set");
|
|
1335
1341
|
const headers = authHeaders(apiKey);
|
|
1336
1342
|
const body = {
|
|
1337
|
-
images_data_url: await
|
|
1343
|
+
images_data_url: await resolveImagesUrl(req.images, apiKey),
|
|
1338
1344
|
is_style: req.isStyle ?? true
|
|
1339
1345
|
};
|
|
1340
1346
|
if (req.triggerWord !== void 0) body.trigger_word = req.triggerWord;
|
|
@@ -1365,7 +1371,7 @@ function falAdapter(config = {}) {
|
|
|
1365
1371
|
usage.costUsd = config.pricePerTraining ?? FAL_TRAIN_PRICE_ESTIMATE;
|
|
1366
1372
|
return { loraUrl, configUrl: configUrl ?? "", usage };
|
|
1367
1373
|
}
|
|
1368
|
-
async function
|
|
1374
|
+
async function resolveImagesUrl(images, apiKey) {
|
|
1369
1375
|
if (typeof images === "string") return images;
|
|
1370
1376
|
const files = await Promise.all(
|
|
1371
1377
|
images.map(async (url, i) => {
|
|
@@ -1374,8 +1380,27 @@ function falAdapter(config = {}) {
|
|
|
1374
1380
|
return { name: fileNameFromUrl(url, i), data: new Uint8Array(await res.arrayBuffer()) };
|
|
1375
1381
|
})
|
|
1376
1382
|
);
|
|
1377
|
-
|
|
1378
|
-
|
|
1383
|
+
return uploadToFalStorage(buildZip(files), "application/zip", "styleset.zip", apiKey);
|
|
1384
|
+
}
|
|
1385
|
+
async function uploadToFalStorage(bytes, contentType, fileName, apiKey) {
|
|
1386
|
+
const initiate = await doFetch("https://rest.alpha.fal.ai/storage/upload/initiate", {
|
|
1387
|
+
method: "POST",
|
|
1388
|
+
headers: { Authorization: `Key ${apiKey}`, "content-type": "application/json" },
|
|
1389
|
+
body: JSON.stringify({ content_type: contentType, file_name: fileName })
|
|
1390
|
+
});
|
|
1391
|
+
if (!initiate.ok) {
|
|
1392
|
+
throw new Error(
|
|
1393
|
+
`fal storage initiate ${initiate.status}: ${(await initiate.text().catch(() => "")).slice(0, 200)}`
|
|
1394
|
+
);
|
|
1395
|
+
}
|
|
1396
|
+
const { upload_url, file_url } = await initiate.json();
|
|
1397
|
+
const put = await doFetch(upload_url, {
|
|
1398
|
+
method: "PUT",
|
|
1399
|
+
headers: { "content-type": contentType },
|
|
1400
|
+
body: bytes
|
|
1401
|
+
});
|
|
1402
|
+
if (!put.ok) throw new Error(`fal storage upload PUT ${put.status}`);
|
|
1403
|
+
return file_url;
|
|
1379
1404
|
}
|
|
1380
1405
|
async function runSync(model, headers, body) {
|
|
1381
1406
|
const res = await doFetch(`${syncBase}/${model}`, {
|
|
@@ -1389,13 +1414,13 @@ function falAdapter(config = {}) {
|
|
|
1389
1414
|
const data = await res.json();
|
|
1390
1415
|
const out = data.images?.[0]?.url;
|
|
1391
1416
|
if (!out) throw new Error(`fal: no image url in response`);
|
|
1392
|
-
return out;
|
|
1417
|
+
return { url: out, flagged: data.has_nsfw_concepts?.[0] === true };
|
|
1393
1418
|
}
|
|
1394
1419
|
async function runQueue(model, headers, body) {
|
|
1395
1420
|
const result = await queueResult(model, headers, body, timeoutMs);
|
|
1396
1421
|
const out = result.images?.[0]?.url;
|
|
1397
1422
|
if (!out) throw new Error("fal queue: no image url in result");
|
|
1398
|
-
return out;
|
|
1423
|
+
return { url: out, flagged: result.has_nsfw_concepts?.[0] === true };
|
|
1399
1424
|
}
|
|
1400
1425
|
async function queueResult(model, headers, body, deadlineMs) {
|
|
1401
1426
|
const submitRes = await doFetch(`${queueBase}/${model}`, {
|
|
@@ -1835,6 +1860,8 @@ var imageInputSchema = z.object({
|
|
|
1835
1860
|
loras: z.array(loraWeightSchema).optional(),
|
|
1836
1861
|
/** Shorthand for a single LoRA — normalized to loras:[{path, scale:1}]. */
|
|
1837
1862
|
lora: z.string().optional(),
|
|
1863
|
+
/** F021.4 — re-roll once if fal returns a black image (NSFW false-positive). */
|
|
1864
|
+
retryOnBlack: z.boolean().optional(),
|
|
1838
1865
|
...callOptions
|
|
1839
1866
|
});
|
|
1840
1867
|
var trainStyleInputSchema = z.object({
|
|
@@ -2164,7 +2191,8 @@ function createAI(config = {}) {
|
|
|
2164
2191
|
spec,
|
|
2165
2192
|
width: input.width,
|
|
2166
2193
|
height: input.height,
|
|
2167
|
-
loras: loras.length ? loras : void 0
|
|
2194
|
+
loras: loras.length ? loras : void 0,
|
|
2195
|
+
retryOnBlack: input.retryOnBlack
|
|
2168
2196
|
});
|
|
2169
2197
|
}
|
|
2170
2198
|
});
|
|
@@ -2419,8 +2447,8 @@ var stubProviders = {
|
|
|
2419
2447
|
};
|
|
2420
2448
|
|
|
2421
2449
|
// src/version.ts
|
|
2422
|
-
var VERSION = "0.10.
|
|
2423
|
-
var SDK_TAG = "@broberg/ai-sdk@0.10.
|
|
2450
|
+
var VERSION = "0.10.3";
|
|
2451
|
+
var SDK_TAG = "@broberg/ai-sdk@0.10.3";
|
|
2424
2452
|
|
|
2425
2453
|
// src/cost/budget-store.ts
|
|
2426
2454
|
function sqliteBudgetStore(config) {
|