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/index.js
CHANGED
|
@@ -1220,9 +1220,138 @@ var openaiProvider = {
|
|
|
1220
1220
|
}
|
|
1221
1221
|
};
|
|
1222
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
|
+
const hasInputImages = req.inputImages && req.inputImages.length > 0;
|
|
1288
|
+
let prompt;
|
|
1289
|
+
if (hasInputImages) {
|
|
1290
|
+
const images2 = req.inputImages.map(
|
|
1291
|
+
(img) => img.startsWith("data:") ? dataUriToUint8Array(img) : Uint8Array.from(Buffer.from(img))
|
|
1292
|
+
);
|
|
1293
|
+
prompt = { images: images2, text: req.prompt };
|
|
1294
|
+
log5("Using image editing mode with", images2.length, "input image(s)");
|
|
1295
|
+
} else {
|
|
1296
|
+
prompt = req.prompt;
|
|
1297
|
+
}
|
|
1298
|
+
log5("Calling generateImage...");
|
|
1299
|
+
const startTime = Date.now();
|
|
1300
|
+
const result = await sdkGenerateImage({
|
|
1301
|
+
model: gw.image(model),
|
|
1302
|
+
prompt,
|
|
1303
|
+
...req.aspectRatio ? { aspectRatio: req.aspectRatio } : {},
|
|
1304
|
+
n: req.n
|
|
1305
|
+
});
|
|
1306
|
+
log5(`Image generation completed in ${Date.now() - startTime}ms`);
|
|
1307
|
+
const images = result.images ?? (result.image ? [result.image] : []);
|
|
1308
|
+
log5(`Got ${images.length} image(s)`);
|
|
1309
|
+
if (!images.length) {
|
|
1310
|
+
throw new Error("Vercel AI Gateway returned no images");
|
|
1311
|
+
}
|
|
1312
|
+
return images.map((img, i) => ({
|
|
1313
|
+
kind: "image",
|
|
1314
|
+
provider: "vercel",
|
|
1315
|
+
model,
|
|
1316
|
+
index: i,
|
|
1317
|
+
bytes: img.uint8Array,
|
|
1318
|
+
mimeType: "image/png"
|
|
1319
|
+
}));
|
|
1320
|
+
}
|
|
1321
|
+
var vercelCapabilities = {
|
|
1322
|
+
maxInputImages: 1,
|
|
1323
|
+
supportsCustomAspectRatio: true,
|
|
1324
|
+
supportsVideoInterpolation: false,
|
|
1325
|
+
videoDurationRange: [1, 15],
|
|
1326
|
+
supportsImageEditing: true
|
|
1327
|
+
};
|
|
1328
|
+
var vercelProvider = {
|
|
1329
|
+
id: "vercel",
|
|
1330
|
+
displayName: "Vercel AI Gateway",
|
|
1331
|
+
supports: ["video", "image"],
|
|
1332
|
+
capabilities: vercelCapabilities,
|
|
1333
|
+
isAvailable(env) {
|
|
1334
|
+
return Boolean(getGatewayApiKey(env));
|
|
1335
|
+
},
|
|
1336
|
+
async generate(req, env) {
|
|
1337
|
+
const apiKey = getGatewayApiKey(env);
|
|
1338
|
+
if (!apiKey) throw new Error("Missing AI Gateway API key. Set AI_GATEWAY_API_KEY.");
|
|
1339
|
+
verboseMode4 = req.verbose;
|
|
1340
|
+
log5("Provider initialized, kind:", req.kind);
|
|
1341
|
+
if (req.kind === "video") return generateVercelVideo(req, apiKey);
|
|
1342
|
+
return generateVercelImage(req, apiKey);
|
|
1343
|
+
}
|
|
1344
|
+
};
|
|
1345
|
+
|
|
1223
1346
|
// src/core/router.ts
|
|
1224
|
-
var providers = [
|
|
1225
|
-
|
|
1347
|
+
var providers = [
|
|
1348
|
+
googleProvider,
|
|
1349
|
+
xaiProvider,
|
|
1350
|
+
falProvider,
|
|
1351
|
+
openaiProvider,
|
|
1352
|
+
vercelProvider
|
|
1353
|
+
];
|
|
1354
|
+
function log6(verbose, ...args) {
|
|
1226
1355
|
if (verbose) console.error("[router]", ...args);
|
|
1227
1356
|
}
|
|
1228
1357
|
function listProviders() {
|
|
@@ -1255,18 +1384,18 @@ async function normalizeOptions(prompt, opts, verbose) {
|
|
|
1255
1384
|
const nameBase = slugify(opts.name ?? prompt);
|
|
1256
1385
|
let inputImages;
|
|
1257
1386
|
if (opts.inputImages?.length) {
|
|
1258
|
-
|
|
1387
|
+
log6(verbose, `Resolving ${opts.inputImages.length} input image(s)...`);
|
|
1259
1388
|
inputImages = await resolveImageInputs(opts.inputImages);
|
|
1260
|
-
|
|
1389
|
+
log6(verbose, `Resolved input images`);
|
|
1261
1390
|
}
|
|
1262
1391
|
let startFrame;
|
|
1263
1392
|
let endFrame;
|
|
1264
1393
|
if (opts.startFrame) {
|
|
1265
|
-
|
|
1394
|
+
log6(verbose, `Resolving start frame: ${opts.startFrame}`);
|
|
1266
1395
|
startFrame = await resolveImageInput(opts.startFrame);
|
|
1267
1396
|
}
|
|
1268
1397
|
if (opts.endFrame) {
|
|
1269
|
-
|
|
1398
|
+
log6(verbose, `Resolving end frame: ${opts.endFrame}`);
|
|
1270
1399
|
endFrame = await resolveImageInput(opts.endFrame);
|
|
1271
1400
|
}
|
|
1272
1401
|
return {
|
|
@@ -1342,27 +1471,27 @@ async function generateMedia(prompt, opts = {}) {
|
|
|
1342
1471
|
startFrame: req.startFrame?.startsWith("data:") ? `data:...${req.startFrame.length} chars` : req.startFrame,
|
|
1343
1472
|
endFrame: req.endFrame?.startsWith("data:") ? `data:...${req.endFrame.length} chars` : req.endFrame
|
|
1344
1473
|
};
|
|
1345
|
-
|
|
1474
|
+
log6(verbose, "Request:", JSON.stringify(reqSummary));
|
|
1346
1475
|
const provider = pickProvider(req.provider, env);
|
|
1347
|
-
|
|
1476
|
+
log6(verbose, "Selected provider:", provider.id, "| supports:", provider.supports);
|
|
1348
1477
|
if (!provider.supports.includes(req.kind)) {
|
|
1349
1478
|
throw new Error(`Provider ${provider.id} does not support ${req.kind} generation`);
|
|
1350
1479
|
}
|
|
1351
1480
|
validateRequestForProvider(req, provider);
|
|
1352
|
-
|
|
1481
|
+
log6(verbose, "Calling provider.generate()...");
|
|
1353
1482
|
const startTime = Date.now();
|
|
1354
1483
|
const partials = await provider.generate(req, env);
|
|
1355
|
-
|
|
1484
|
+
log6(verbose, `Provider returned ${partials.length} items in ${Date.now() - startTime}ms`);
|
|
1356
1485
|
const items = [];
|
|
1357
1486
|
for (let i = 0; i < partials.length; i++) {
|
|
1358
1487
|
const p = partials[i];
|
|
1359
1488
|
if (!p) continue;
|
|
1360
1489
|
const filePath = makeOutputPath(req, i, p.mimeType);
|
|
1361
|
-
|
|
1490
|
+
log6(verbose, `Writing ${p.bytes.byteLength} bytes to: ${filePath}`);
|
|
1362
1491
|
await writeMediaFile(filePath, p.bytes);
|
|
1363
1492
|
items.push({ ...p, filePath });
|
|
1364
1493
|
}
|
|
1365
|
-
|
|
1494
|
+
log6(verbose, `Done! Generated ${items.length} ${req.kind}(s)`);
|
|
1366
1495
|
return items;
|
|
1367
1496
|
}
|
|
1368
1497
|
async function generateImage(prompt, opts = {}) {
|