climage 0.5.3 → 0.6.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/dist/cli.js +142 -12
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +141 -12
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/cli.js
CHANGED
|
@@ -1249,9 +1249,138 @@ var openaiProvider = {
|
|
|
1249
1249
|
}
|
|
1250
1250
|
};
|
|
1251
1251
|
|
|
1252
|
+
// src/providers/vercel.ts
|
|
1253
|
+
import {
|
|
1254
|
+
experimental_generateVideo as sdkGenerateVideo,
|
|
1255
|
+
generateImage as sdkGenerateImage,
|
|
1256
|
+
createGateway
|
|
1257
|
+
} from "ai";
|
|
1258
|
+
function getGatewayApiKey(env) {
|
|
1259
|
+
return env.AI_GATEWAY_API_KEY;
|
|
1260
|
+
}
|
|
1261
|
+
var verboseMode4 = false;
|
|
1262
|
+
function log5(...args) {
|
|
1263
|
+
if (verboseMode4) console.error("[vercel]", ...args);
|
|
1264
|
+
}
|
|
1265
|
+
function makeGateway(apiKey) {
|
|
1266
|
+
return createGateway({ apiKey });
|
|
1267
|
+
}
|
|
1268
|
+
function dataUriToUint8Array(dataUri) {
|
|
1269
|
+
const commaIdx = dataUri.indexOf(",");
|
|
1270
|
+
const b64 = dataUri.slice(commaIdx + 1);
|
|
1271
|
+
return Uint8Array.from(Buffer.from(b64, "base64"));
|
|
1272
|
+
}
|
|
1273
|
+
var DEFAULT_VIDEO_MODEL2 = "xai/grok-imagine-video";
|
|
1274
|
+
var DEFAULT_IMAGE_MODEL2 = "xai/grok-imagine-image";
|
|
1275
|
+
async function generateVercelVideo(req, apiKey) {
|
|
1276
|
+
const gw = makeGateway(apiKey);
|
|
1277
|
+
const model = req.model ?? DEFAULT_VIDEO_MODEL2;
|
|
1278
|
+
log5("Starting video generation, model:", model);
|
|
1279
|
+
const imageInput = req.startFrame ?? req.inputImages?.[0];
|
|
1280
|
+
let prompt;
|
|
1281
|
+
if (imageInput) {
|
|
1282
|
+
const imageData = imageInput.startsWith("data:") ? dataUriToUint8Array(imageInput) : imageInput;
|
|
1283
|
+
prompt = { image: imageData, text: req.prompt };
|
|
1284
|
+
log5("Using image-to-video mode");
|
|
1285
|
+
} else {
|
|
1286
|
+
prompt = req.prompt;
|
|
1287
|
+
}
|
|
1288
|
+
log5("Calling experimental_generateVideo...");
|
|
1289
|
+
const startTime = Date.now();
|
|
1290
|
+
const result = await sdkGenerateVideo({
|
|
1291
|
+
model: gw.video(model),
|
|
1292
|
+
prompt,
|
|
1293
|
+
...req.aspectRatio ? { aspectRatio: req.aspectRatio } : {},
|
|
1294
|
+
...req.duration !== void 0 ? { duration: req.duration } : {},
|
|
1295
|
+
n: req.n
|
|
1296
|
+
});
|
|
1297
|
+
log5(`Video generation completed in ${Date.now() - startTime}ms`);
|
|
1298
|
+
const videos = result.videos ?? (result.video ? [result.video] : []);
|
|
1299
|
+
log5(`Got ${videos.length} video(s)`);
|
|
1300
|
+
if (!videos.length) {
|
|
1301
|
+
throw new Error("Vercel AI Gateway returned no videos");
|
|
1302
|
+
}
|
|
1303
|
+
return videos.map((v, i) => ({
|
|
1304
|
+
kind: "video",
|
|
1305
|
+
provider: "vercel",
|
|
1306
|
+
model,
|
|
1307
|
+
index: i,
|
|
1308
|
+
bytes: v.uint8Array,
|
|
1309
|
+
mimeType: "video/mp4"
|
|
1310
|
+
}));
|
|
1311
|
+
}
|
|
1312
|
+
async function generateVercelImage(req, apiKey) {
|
|
1313
|
+
const gw = makeGateway(apiKey);
|
|
1314
|
+
const model = req.model ?? DEFAULT_IMAGE_MODEL2;
|
|
1315
|
+
log5("Starting image generation, model:", model);
|
|
1316
|
+
const hasInputImages = req.inputImages && req.inputImages.length > 0;
|
|
1317
|
+
let prompt;
|
|
1318
|
+
if (hasInputImages) {
|
|
1319
|
+
const images2 = req.inputImages.map(
|
|
1320
|
+
(img) => img.startsWith("data:") ? dataUriToUint8Array(img) : Uint8Array.from(Buffer.from(img))
|
|
1321
|
+
);
|
|
1322
|
+
prompt = { images: images2, text: req.prompt };
|
|
1323
|
+
log5("Using image editing mode with", images2.length, "input image(s)");
|
|
1324
|
+
} else {
|
|
1325
|
+
prompt = req.prompt;
|
|
1326
|
+
}
|
|
1327
|
+
log5("Calling generateImage...");
|
|
1328
|
+
const startTime = Date.now();
|
|
1329
|
+
const result = await sdkGenerateImage({
|
|
1330
|
+
model: gw.image(model),
|
|
1331
|
+
prompt,
|
|
1332
|
+
...req.aspectRatio ? { aspectRatio: req.aspectRatio } : {},
|
|
1333
|
+
n: req.n
|
|
1334
|
+
});
|
|
1335
|
+
log5(`Image generation completed in ${Date.now() - startTime}ms`);
|
|
1336
|
+
const images = result.images ?? (result.image ? [result.image] : []);
|
|
1337
|
+
log5(`Got ${images.length} image(s)`);
|
|
1338
|
+
if (!images.length) {
|
|
1339
|
+
throw new Error("Vercel AI Gateway returned no images");
|
|
1340
|
+
}
|
|
1341
|
+
return images.map((img, i) => ({
|
|
1342
|
+
kind: "image",
|
|
1343
|
+
provider: "vercel",
|
|
1344
|
+
model,
|
|
1345
|
+
index: i,
|
|
1346
|
+
bytes: img.uint8Array,
|
|
1347
|
+
mimeType: "image/png"
|
|
1348
|
+
}));
|
|
1349
|
+
}
|
|
1350
|
+
var vercelCapabilities = {
|
|
1351
|
+
maxInputImages: 1,
|
|
1352
|
+
supportsCustomAspectRatio: true,
|
|
1353
|
+
supportsVideoInterpolation: false,
|
|
1354
|
+
videoDurationRange: [1, 15],
|
|
1355
|
+
supportsImageEditing: true
|
|
1356
|
+
};
|
|
1357
|
+
var vercelProvider = {
|
|
1358
|
+
id: "vercel",
|
|
1359
|
+
displayName: "Vercel AI Gateway",
|
|
1360
|
+
supports: ["video", "image"],
|
|
1361
|
+
capabilities: vercelCapabilities,
|
|
1362
|
+
isAvailable(env) {
|
|
1363
|
+
return Boolean(getGatewayApiKey(env));
|
|
1364
|
+
},
|
|
1365
|
+
async generate(req, env) {
|
|
1366
|
+
const apiKey = getGatewayApiKey(env);
|
|
1367
|
+
if (!apiKey) throw new Error("Missing AI Gateway API key. Set AI_GATEWAY_API_KEY.");
|
|
1368
|
+
verboseMode4 = req.verbose;
|
|
1369
|
+
log5("Provider initialized, kind:", req.kind);
|
|
1370
|
+
if (req.kind === "video") return generateVercelVideo(req, apiKey);
|
|
1371
|
+
return generateVercelImage(req, apiKey);
|
|
1372
|
+
}
|
|
1373
|
+
};
|
|
1374
|
+
|
|
1252
1375
|
// src/core/router.ts
|
|
1253
|
-
var providers = [
|
|
1254
|
-
|
|
1376
|
+
var providers = [
|
|
1377
|
+
googleProvider,
|
|
1378
|
+
xaiProvider,
|
|
1379
|
+
falProvider,
|
|
1380
|
+
openaiProvider,
|
|
1381
|
+
vercelProvider
|
|
1382
|
+
];
|
|
1383
|
+
function log6(verbose, ...args) {
|
|
1255
1384
|
if (verbose) console.error("[router]", ...args);
|
|
1256
1385
|
}
|
|
1257
1386
|
function listProviders() {
|
|
@@ -1284,18 +1413,18 @@ async function normalizeOptions(prompt, opts, verbose) {
|
|
|
1284
1413
|
const nameBase = slugify(opts.name ?? prompt);
|
|
1285
1414
|
let inputImages;
|
|
1286
1415
|
if (opts.inputImages?.length) {
|
|
1287
|
-
|
|
1416
|
+
log6(verbose, `Resolving ${opts.inputImages.length} input image(s)...`);
|
|
1288
1417
|
inputImages = await resolveImageInputs(opts.inputImages);
|
|
1289
|
-
|
|
1418
|
+
log6(verbose, `Resolved input images`);
|
|
1290
1419
|
}
|
|
1291
1420
|
let startFrame;
|
|
1292
1421
|
let endFrame;
|
|
1293
1422
|
if (opts.startFrame) {
|
|
1294
|
-
|
|
1423
|
+
log6(verbose, `Resolving start frame: ${opts.startFrame}`);
|
|
1295
1424
|
startFrame = await resolveImageInput(opts.startFrame);
|
|
1296
1425
|
}
|
|
1297
1426
|
if (opts.endFrame) {
|
|
1298
|
-
|
|
1427
|
+
log6(verbose, `Resolving end frame: ${opts.endFrame}`);
|
|
1299
1428
|
endFrame = await resolveImageInput(opts.endFrame);
|
|
1300
1429
|
}
|
|
1301
1430
|
return {
|
|
@@ -1371,27 +1500,27 @@ async function generateMedia(prompt, opts = {}) {
|
|
|
1371
1500
|
startFrame: req.startFrame?.startsWith("data:") ? `data:...${req.startFrame.length} chars` : req.startFrame,
|
|
1372
1501
|
endFrame: req.endFrame?.startsWith("data:") ? `data:...${req.endFrame.length} chars` : req.endFrame
|
|
1373
1502
|
};
|
|
1374
|
-
|
|
1503
|
+
log6(verbose, "Request:", JSON.stringify(reqSummary));
|
|
1375
1504
|
const provider = pickProvider(req.provider, env);
|
|
1376
|
-
|
|
1505
|
+
log6(verbose, "Selected provider:", provider.id, "| supports:", provider.supports);
|
|
1377
1506
|
if (!provider.supports.includes(req.kind)) {
|
|
1378
1507
|
throw new Error(`Provider ${provider.id} does not support ${req.kind} generation`);
|
|
1379
1508
|
}
|
|
1380
1509
|
validateRequestForProvider(req, provider);
|
|
1381
|
-
|
|
1510
|
+
log6(verbose, "Calling provider.generate()...");
|
|
1382
1511
|
const startTime = Date.now();
|
|
1383
1512
|
const partials = await provider.generate(req, env);
|
|
1384
|
-
|
|
1513
|
+
log6(verbose, `Provider returned ${partials.length} items in ${Date.now() - startTime}ms`);
|
|
1385
1514
|
const items = [];
|
|
1386
1515
|
for (let i = 0; i < partials.length; i++) {
|
|
1387
1516
|
const p = partials[i];
|
|
1388
1517
|
if (!p) continue;
|
|
1389
1518
|
const filePath = makeOutputPath(req, i, p.mimeType);
|
|
1390
|
-
|
|
1519
|
+
log6(verbose, `Writing ${p.bytes.byteLength} bytes to: ${filePath}`);
|
|
1391
1520
|
await writeMediaFile(filePath, p.bytes);
|
|
1392
1521
|
items.push({ ...p, filePath });
|
|
1393
1522
|
}
|
|
1394
|
-
|
|
1523
|
+
log6(verbose, `Done! Generated ${items.length} ${req.kind}(s)`);
|
|
1395
1524
|
return items;
|
|
1396
1525
|
}
|
|
1397
1526
|
|
|
@@ -1430,6 +1559,7 @@ Env:
|
|
|
1430
1559
|
XAI_API_KEY (or XAI_TOKEN, GROK_API_KEY)
|
|
1431
1560
|
FAL_KEY (or FAL_API_KEY)
|
|
1432
1561
|
OPENAI_API_KEY
|
|
1562
|
+
AI_GATEWAY_API_KEY (Vercel AI Gateway)
|
|
1433
1563
|
|
|
1434
1564
|
Examples:
|
|
1435
1565
|
npx climage "make image of kitten"
|