climage 0.5.2 → 0.6.0
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 +132 -18
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +131 -18
- package/dist/index.js.map +1 -1
- package/package.json +2 -1
package/dist/cli.js
CHANGED
|
@@ -719,17 +719,12 @@ function imageToVeoFormat(imageInput) {
|
|
|
719
719
|
`Veo image inputs must be data: URIs or gs:// URIs (got ${imageInput.slice(0, 24)}...)`
|
|
720
720
|
);
|
|
721
721
|
}
|
|
722
|
-
var GEMINI_IMAGE_MODELS = [
|
|
723
|
-
"gemini-2.5-flash-image",
|
|
724
|
-
"gemini-3-pro-image-preview",
|
|
725
|
-
"gemini-3.1-flash-image-preview"
|
|
726
|
-
];
|
|
727
722
|
function resolveModel(model) {
|
|
728
723
|
if (!model) return "gemini-2.5-flash-image";
|
|
729
724
|
return MODEL_ALIASES[model] ?? model;
|
|
730
725
|
}
|
|
731
726
|
function isGeminiImageModel(model) {
|
|
732
|
-
return
|
|
727
|
+
return model.startsWith("gemini-");
|
|
733
728
|
}
|
|
734
729
|
async function downloadBytes3(url) {
|
|
735
730
|
log3("Downloading from:", url.slice(0, 100) + "...");
|
|
@@ -1254,9 +1249,127 @@ var openaiProvider = {
|
|
|
1254
1249
|
}
|
|
1255
1250
|
};
|
|
1256
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
|
+
log5("Calling generateImage...");
|
|
1317
|
+
const startTime = Date.now();
|
|
1318
|
+
const result = await sdkGenerateImage({
|
|
1319
|
+
model: gw.image(model),
|
|
1320
|
+
prompt: req.prompt,
|
|
1321
|
+
...req.aspectRatio ? { aspectRatio: req.aspectRatio } : {},
|
|
1322
|
+
n: req.n
|
|
1323
|
+
});
|
|
1324
|
+
log5(`Image generation completed in ${Date.now() - startTime}ms`);
|
|
1325
|
+
const images = result.images ?? (result.image ? [result.image] : []);
|
|
1326
|
+
log5(`Got ${images.length} image(s)`);
|
|
1327
|
+
if (!images.length) {
|
|
1328
|
+
throw new Error("Vercel AI Gateway returned no images");
|
|
1329
|
+
}
|
|
1330
|
+
return images.map((img, i) => ({
|
|
1331
|
+
kind: "image",
|
|
1332
|
+
provider: "vercel",
|
|
1333
|
+
model,
|
|
1334
|
+
index: i,
|
|
1335
|
+
bytes: img.uint8Array,
|
|
1336
|
+
mimeType: "image/png"
|
|
1337
|
+
}));
|
|
1338
|
+
}
|
|
1339
|
+
var vercelCapabilities = {
|
|
1340
|
+
maxInputImages: 1,
|
|
1341
|
+
supportsCustomAspectRatio: true,
|
|
1342
|
+
supportsVideoInterpolation: false,
|
|
1343
|
+
videoDurationRange: [1, 15],
|
|
1344
|
+
supportsImageEditing: false
|
|
1345
|
+
};
|
|
1346
|
+
var vercelProvider = {
|
|
1347
|
+
id: "vercel",
|
|
1348
|
+
displayName: "Vercel AI Gateway",
|
|
1349
|
+
supports: ["video", "image"],
|
|
1350
|
+
capabilities: vercelCapabilities,
|
|
1351
|
+
isAvailable(env) {
|
|
1352
|
+
return Boolean(getGatewayApiKey(env));
|
|
1353
|
+
},
|
|
1354
|
+
async generate(req, env) {
|
|
1355
|
+
const apiKey = getGatewayApiKey(env);
|
|
1356
|
+
if (!apiKey) throw new Error("Missing AI Gateway API key. Set AI_GATEWAY_API_KEY.");
|
|
1357
|
+
verboseMode4 = req.verbose;
|
|
1358
|
+
log5("Provider initialized, kind:", req.kind);
|
|
1359
|
+
if (req.kind === "video") return generateVercelVideo(req, apiKey);
|
|
1360
|
+
return generateVercelImage(req, apiKey);
|
|
1361
|
+
}
|
|
1362
|
+
};
|
|
1363
|
+
|
|
1257
1364
|
// src/core/router.ts
|
|
1258
|
-
var providers = [
|
|
1259
|
-
|
|
1365
|
+
var providers = [
|
|
1366
|
+
googleProvider,
|
|
1367
|
+
xaiProvider,
|
|
1368
|
+
falProvider,
|
|
1369
|
+
openaiProvider,
|
|
1370
|
+
vercelProvider
|
|
1371
|
+
];
|
|
1372
|
+
function log6(verbose, ...args) {
|
|
1260
1373
|
if (verbose) console.error("[router]", ...args);
|
|
1261
1374
|
}
|
|
1262
1375
|
function listProviders() {
|
|
@@ -1289,18 +1402,18 @@ async function normalizeOptions(prompt, opts, verbose) {
|
|
|
1289
1402
|
const nameBase = slugify(opts.name ?? prompt);
|
|
1290
1403
|
let inputImages;
|
|
1291
1404
|
if (opts.inputImages?.length) {
|
|
1292
|
-
|
|
1405
|
+
log6(verbose, `Resolving ${opts.inputImages.length} input image(s)...`);
|
|
1293
1406
|
inputImages = await resolveImageInputs(opts.inputImages);
|
|
1294
|
-
|
|
1407
|
+
log6(verbose, `Resolved input images`);
|
|
1295
1408
|
}
|
|
1296
1409
|
let startFrame;
|
|
1297
1410
|
let endFrame;
|
|
1298
1411
|
if (opts.startFrame) {
|
|
1299
|
-
|
|
1412
|
+
log6(verbose, `Resolving start frame: ${opts.startFrame}`);
|
|
1300
1413
|
startFrame = await resolveImageInput(opts.startFrame);
|
|
1301
1414
|
}
|
|
1302
1415
|
if (opts.endFrame) {
|
|
1303
|
-
|
|
1416
|
+
log6(verbose, `Resolving end frame: ${opts.endFrame}`);
|
|
1304
1417
|
endFrame = await resolveImageInput(opts.endFrame);
|
|
1305
1418
|
}
|
|
1306
1419
|
return {
|
|
@@ -1376,27 +1489,27 @@ async function generateMedia(prompt, opts = {}) {
|
|
|
1376
1489
|
startFrame: req.startFrame?.startsWith("data:") ? `data:...${req.startFrame.length} chars` : req.startFrame,
|
|
1377
1490
|
endFrame: req.endFrame?.startsWith("data:") ? `data:...${req.endFrame.length} chars` : req.endFrame
|
|
1378
1491
|
};
|
|
1379
|
-
|
|
1492
|
+
log6(verbose, "Request:", JSON.stringify(reqSummary));
|
|
1380
1493
|
const provider = pickProvider(req.provider, env);
|
|
1381
|
-
|
|
1494
|
+
log6(verbose, "Selected provider:", provider.id, "| supports:", provider.supports);
|
|
1382
1495
|
if (!provider.supports.includes(req.kind)) {
|
|
1383
1496
|
throw new Error(`Provider ${provider.id} does not support ${req.kind} generation`);
|
|
1384
1497
|
}
|
|
1385
1498
|
validateRequestForProvider(req, provider);
|
|
1386
|
-
|
|
1499
|
+
log6(verbose, "Calling provider.generate()...");
|
|
1387
1500
|
const startTime = Date.now();
|
|
1388
1501
|
const partials = await provider.generate(req, env);
|
|
1389
|
-
|
|
1502
|
+
log6(verbose, `Provider returned ${partials.length} items in ${Date.now() - startTime}ms`);
|
|
1390
1503
|
const items = [];
|
|
1391
1504
|
for (let i = 0; i < partials.length; i++) {
|
|
1392
1505
|
const p = partials[i];
|
|
1393
1506
|
if (!p) continue;
|
|
1394
1507
|
const filePath = makeOutputPath(req, i, p.mimeType);
|
|
1395
|
-
|
|
1508
|
+
log6(verbose, `Writing ${p.bytes.byteLength} bytes to: ${filePath}`);
|
|
1396
1509
|
await writeMediaFile(filePath, p.bytes);
|
|
1397
1510
|
items.push({ ...p, filePath });
|
|
1398
1511
|
}
|
|
1399
|
-
|
|
1512
|
+
log6(verbose, `Done! Generated ${items.length} ${req.kind}(s)`);
|
|
1400
1513
|
return items;
|
|
1401
1514
|
}
|
|
1402
1515
|
|
|
@@ -1435,6 +1548,7 @@ Env:
|
|
|
1435
1548
|
XAI_API_KEY (or XAI_TOKEN, GROK_API_KEY)
|
|
1436
1549
|
FAL_KEY (or FAL_API_KEY)
|
|
1437
1550
|
OPENAI_API_KEY
|
|
1551
|
+
AI_GATEWAY_API_KEY (Vercel AI Gateway)
|
|
1438
1552
|
|
|
1439
1553
|
Examples:
|
|
1440
1554
|
npx climage "make image of kitten"
|