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/index.js
CHANGED
|
@@ -690,17 +690,12 @@ function imageToVeoFormat(imageInput) {
|
|
|
690
690
|
`Veo image inputs must be data: URIs or gs:// URIs (got ${imageInput.slice(0, 24)}...)`
|
|
691
691
|
);
|
|
692
692
|
}
|
|
693
|
-
var GEMINI_IMAGE_MODELS = [
|
|
694
|
-
"gemini-2.5-flash-image",
|
|
695
|
-
"gemini-3-pro-image-preview",
|
|
696
|
-
"gemini-3.1-flash-image-preview"
|
|
697
|
-
];
|
|
698
693
|
function resolveModel(model) {
|
|
699
694
|
if (!model) return "gemini-2.5-flash-image";
|
|
700
695
|
return MODEL_ALIASES[model] ?? model;
|
|
701
696
|
}
|
|
702
697
|
function isGeminiImageModel(model) {
|
|
703
|
-
return
|
|
698
|
+
return model.startsWith("gemini-");
|
|
704
699
|
}
|
|
705
700
|
async function downloadBytes3(url) {
|
|
706
701
|
log3("Downloading from:", url.slice(0, 100) + "...");
|
|
@@ -1225,9 +1220,127 @@ var openaiProvider = {
|
|
|
1225
1220
|
}
|
|
1226
1221
|
};
|
|
1227
1222
|
|
|
1223
|
+
// src/providers/vercel.ts
|
|
1224
|
+
import {
|
|
1225
|
+
experimental_generateVideo as sdkGenerateVideo,
|
|
1226
|
+
generateImage as sdkGenerateImage,
|
|
1227
|
+
createGateway
|
|
1228
|
+
} from "ai";
|
|
1229
|
+
function getGatewayApiKey(env) {
|
|
1230
|
+
return env.AI_GATEWAY_API_KEY;
|
|
1231
|
+
}
|
|
1232
|
+
var verboseMode4 = false;
|
|
1233
|
+
function log5(...args) {
|
|
1234
|
+
if (verboseMode4) console.error("[vercel]", ...args);
|
|
1235
|
+
}
|
|
1236
|
+
function makeGateway(apiKey) {
|
|
1237
|
+
return createGateway({ apiKey });
|
|
1238
|
+
}
|
|
1239
|
+
function dataUriToUint8Array(dataUri) {
|
|
1240
|
+
const commaIdx = dataUri.indexOf(",");
|
|
1241
|
+
const b64 = dataUri.slice(commaIdx + 1);
|
|
1242
|
+
return Uint8Array.from(Buffer.from(b64, "base64"));
|
|
1243
|
+
}
|
|
1244
|
+
var DEFAULT_VIDEO_MODEL2 = "xai/grok-imagine-video";
|
|
1245
|
+
var DEFAULT_IMAGE_MODEL2 = "xai/grok-imagine-image";
|
|
1246
|
+
async function generateVercelVideo(req, apiKey) {
|
|
1247
|
+
const gw = makeGateway(apiKey);
|
|
1248
|
+
const model = req.model ?? DEFAULT_VIDEO_MODEL2;
|
|
1249
|
+
log5("Starting video generation, model:", model);
|
|
1250
|
+
const imageInput = req.startFrame ?? req.inputImages?.[0];
|
|
1251
|
+
let prompt;
|
|
1252
|
+
if (imageInput) {
|
|
1253
|
+
const imageData = imageInput.startsWith("data:") ? dataUriToUint8Array(imageInput) : imageInput;
|
|
1254
|
+
prompt = { image: imageData, text: req.prompt };
|
|
1255
|
+
log5("Using image-to-video mode");
|
|
1256
|
+
} else {
|
|
1257
|
+
prompt = req.prompt;
|
|
1258
|
+
}
|
|
1259
|
+
log5("Calling experimental_generateVideo...");
|
|
1260
|
+
const startTime = Date.now();
|
|
1261
|
+
const result = await sdkGenerateVideo({
|
|
1262
|
+
model: gw.video(model),
|
|
1263
|
+
prompt,
|
|
1264
|
+
...req.aspectRatio ? { aspectRatio: req.aspectRatio } : {},
|
|
1265
|
+
...req.duration !== void 0 ? { duration: req.duration } : {},
|
|
1266
|
+
n: req.n
|
|
1267
|
+
});
|
|
1268
|
+
log5(`Video generation completed in ${Date.now() - startTime}ms`);
|
|
1269
|
+
const videos = result.videos ?? (result.video ? [result.video] : []);
|
|
1270
|
+
log5(`Got ${videos.length} video(s)`);
|
|
1271
|
+
if (!videos.length) {
|
|
1272
|
+
throw new Error("Vercel AI Gateway returned no videos");
|
|
1273
|
+
}
|
|
1274
|
+
return videos.map((v, i) => ({
|
|
1275
|
+
kind: "video",
|
|
1276
|
+
provider: "vercel",
|
|
1277
|
+
model,
|
|
1278
|
+
index: i,
|
|
1279
|
+
bytes: v.uint8Array,
|
|
1280
|
+
mimeType: "video/mp4"
|
|
1281
|
+
}));
|
|
1282
|
+
}
|
|
1283
|
+
async function generateVercelImage(req, apiKey) {
|
|
1284
|
+
const gw = makeGateway(apiKey);
|
|
1285
|
+
const model = req.model ?? DEFAULT_IMAGE_MODEL2;
|
|
1286
|
+
log5("Starting image generation, model:", model);
|
|
1287
|
+
log5("Calling generateImage...");
|
|
1288
|
+
const startTime = Date.now();
|
|
1289
|
+
const result = await sdkGenerateImage({
|
|
1290
|
+
model: gw.image(model),
|
|
1291
|
+
prompt: req.prompt,
|
|
1292
|
+
...req.aspectRatio ? { aspectRatio: req.aspectRatio } : {},
|
|
1293
|
+
n: req.n
|
|
1294
|
+
});
|
|
1295
|
+
log5(`Image generation completed in ${Date.now() - startTime}ms`);
|
|
1296
|
+
const images = result.images ?? (result.image ? [result.image] : []);
|
|
1297
|
+
log5(`Got ${images.length} image(s)`);
|
|
1298
|
+
if (!images.length) {
|
|
1299
|
+
throw new Error("Vercel AI Gateway returned no images");
|
|
1300
|
+
}
|
|
1301
|
+
return images.map((img, i) => ({
|
|
1302
|
+
kind: "image",
|
|
1303
|
+
provider: "vercel",
|
|
1304
|
+
model,
|
|
1305
|
+
index: i,
|
|
1306
|
+
bytes: img.uint8Array,
|
|
1307
|
+
mimeType: "image/png"
|
|
1308
|
+
}));
|
|
1309
|
+
}
|
|
1310
|
+
var vercelCapabilities = {
|
|
1311
|
+
maxInputImages: 1,
|
|
1312
|
+
supportsCustomAspectRatio: true,
|
|
1313
|
+
supportsVideoInterpolation: false,
|
|
1314
|
+
videoDurationRange: [1, 15],
|
|
1315
|
+
supportsImageEditing: false
|
|
1316
|
+
};
|
|
1317
|
+
var vercelProvider = {
|
|
1318
|
+
id: "vercel",
|
|
1319
|
+
displayName: "Vercel AI Gateway",
|
|
1320
|
+
supports: ["video", "image"],
|
|
1321
|
+
capabilities: vercelCapabilities,
|
|
1322
|
+
isAvailable(env) {
|
|
1323
|
+
return Boolean(getGatewayApiKey(env));
|
|
1324
|
+
},
|
|
1325
|
+
async generate(req, env) {
|
|
1326
|
+
const apiKey = getGatewayApiKey(env);
|
|
1327
|
+
if (!apiKey) throw new Error("Missing AI Gateway API key. Set AI_GATEWAY_API_KEY.");
|
|
1328
|
+
verboseMode4 = req.verbose;
|
|
1329
|
+
log5("Provider initialized, kind:", req.kind);
|
|
1330
|
+
if (req.kind === "video") return generateVercelVideo(req, apiKey);
|
|
1331
|
+
return generateVercelImage(req, apiKey);
|
|
1332
|
+
}
|
|
1333
|
+
};
|
|
1334
|
+
|
|
1228
1335
|
// src/core/router.ts
|
|
1229
|
-
var providers = [
|
|
1230
|
-
|
|
1336
|
+
var providers = [
|
|
1337
|
+
googleProvider,
|
|
1338
|
+
xaiProvider,
|
|
1339
|
+
falProvider,
|
|
1340
|
+
openaiProvider,
|
|
1341
|
+
vercelProvider
|
|
1342
|
+
];
|
|
1343
|
+
function log6(verbose, ...args) {
|
|
1231
1344
|
if (verbose) console.error("[router]", ...args);
|
|
1232
1345
|
}
|
|
1233
1346
|
function listProviders() {
|
|
@@ -1260,18 +1373,18 @@ async function normalizeOptions(prompt, opts, verbose) {
|
|
|
1260
1373
|
const nameBase = slugify(opts.name ?? prompt);
|
|
1261
1374
|
let inputImages;
|
|
1262
1375
|
if (opts.inputImages?.length) {
|
|
1263
|
-
|
|
1376
|
+
log6(verbose, `Resolving ${opts.inputImages.length} input image(s)...`);
|
|
1264
1377
|
inputImages = await resolveImageInputs(opts.inputImages);
|
|
1265
|
-
|
|
1378
|
+
log6(verbose, `Resolved input images`);
|
|
1266
1379
|
}
|
|
1267
1380
|
let startFrame;
|
|
1268
1381
|
let endFrame;
|
|
1269
1382
|
if (opts.startFrame) {
|
|
1270
|
-
|
|
1383
|
+
log6(verbose, `Resolving start frame: ${opts.startFrame}`);
|
|
1271
1384
|
startFrame = await resolveImageInput(opts.startFrame);
|
|
1272
1385
|
}
|
|
1273
1386
|
if (opts.endFrame) {
|
|
1274
|
-
|
|
1387
|
+
log6(verbose, `Resolving end frame: ${opts.endFrame}`);
|
|
1275
1388
|
endFrame = await resolveImageInput(opts.endFrame);
|
|
1276
1389
|
}
|
|
1277
1390
|
return {
|
|
@@ -1347,27 +1460,27 @@ async function generateMedia(prompt, opts = {}) {
|
|
|
1347
1460
|
startFrame: req.startFrame?.startsWith("data:") ? `data:...${req.startFrame.length} chars` : req.startFrame,
|
|
1348
1461
|
endFrame: req.endFrame?.startsWith("data:") ? `data:...${req.endFrame.length} chars` : req.endFrame
|
|
1349
1462
|
};
|
|
1350
|
-
|
|
1463
|
+
log6(verbose, "Request:", JSON.stringify(reqSummary));
|
|
1351
1464
|
const provider = pickProvider(req.provider, env);
|
|
1352
|
-
|
|
1465
|
+
log6(verbose, "Selected provider:", provider.id, "| supports:", provider.supports);
|
|
1353
1466
|
if (!provider.supports.includes(req.kind)) {
|
|
1354
1467
|
throw new Error(`Provider ${provider.id} does not support ${req.kind} generation`);
|
|
1355
1468
|
}
|
|
1356
1469
|
validateRequestForProvider(req, provider);
|
|
1357
|
-
|
|
1470
|
+
log6(verbose, "Calling provider.generate()...");
|
|
1358
1471
|
const startTime = Date.now();
|
|
1359
1472
|
const partials = await provider.generate(req, env);
|
|
1360
|
-
|
|
1473
|
+
log6(verbose, `Provider returned ${partials.length} items in ${Date.now() - startTime}ms`);
|
|
1361
1474
|
const items = [];
|
|
1362
1475
|
for (let i = 0; i < partials.length; i++) {
|
|
1363
1476
|
const p = partials[i];
|
|
1364
1477
|
if (!p) continue;
|
|
1365
1478
|
const filePath = makeOutputPath(req, i, p.mimeType);
|
|
1366
|
-
|
|
1479
|
+
log6(verbose, `Writing ${p.bytes.byteLength} bytes to: ${filePath}`);
|
|
1367
1480
|
await writeMediaFile(filePath, p.bytes);
|
|
1368
1481
|
items.push({ ...p, filePath });
|
|
1369
1482
|
}
|
|
1370
|
-
|
|
1483
|
+
log6(verbose, `Done! Generated ${items.length} ${req.kind}(s)`);
|
|
1371
1484
|
return items;
|
|
1372
1485
|
}
|
|
1373
1486
|
async function generateImage(prompt, opts = {}) {
|