climage 0.4.1 → 0.5.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/index.js CHANGED
@@ -256,8 +256,7 @@ async function generateXaiVideo(req, apiKey) {
256
256
  prompt: req.prompt,
257
257
  model,
258
258
  ...req.aspectRatio ? { aspect_ratio: req.aspectRatio } : {},
259
- // Add image_url for image-to-video (data URI or URL string)
260
- ...imageUrl ? { image_url: imageUrl } : {},
259
+ ...imageUrl ? { image: { url: imageUrl } } : {},
261
260
  // Add duration (xAI supports 1-15 seconds)
262
261
  ...req.duration !== void 0 ? { duration: req.duration } : {}
263
262
  };
@@ -265,7 +264,7 @@ async function generateXaiVideo(req, apiKey) {
265
264
  "Request body:",
266
265
  JSON.stringify({
267
266
  ...createBody,
268
- image_url: createBody.image_url ? `...(${String(createBody.image_url).length} chars)` : void 0
267
+ image: createBody.image ? { url: `...(${String(createBody.image.url).length} chars)` } : void 0
269
268
  })
270
269
  );
271
270
  log("Calling xAI videos/generations...");
@@ -409,8 +408,15 @@ var DEFAULT_IMAGE_MODEL = "fal-ai/flux/dev";
409
408
  var DEFAULT_IMAGE_TO_IMAGE_MODEL = "fal-ai/flux/dev/image-to-image";
410
409
  var DEFAULT_VIDEO_MODEL = "fal-ai/ltxv-2/text-to-video/fast";
411
410
  var DEFAULT_IMAGE_TO_VIDEO_MODEL = "fal-ai/vidu/q2/image-to-video";
411
+ var KLING_V3_PRO_IMAGE_TO_VIDEO_MODEL = "fal-ai/kling-video/v3/pro/image-to-video";
412
412
  var DEFAULT_START_END_VIDEO_MODEL = "fal-ai/vidu/start-end-to-video";
413
413
  var DEFAULT_REFERENCE_VIDEO_MODEL = "fal-ai/vidu/q2/reference-to-video";
414
+ function isKlingV3Model(model) {
415
+ return model === KLING_V3_PRO_IMAGE_TO_VIDEO_MODEL || model.startsWith("fal-ai/kling-video/v3/");
416
+ }
417
+ function isViduModel(model) {
418
+ return model.includes("/vidu/");
419
+ }
414
420
  function selectVideoModel(req) {
415
421
  if (req.model) return req.model;
416
422
  if (req.startFrame && req.endFrame) {
@@ -429,9 +435,12 @@ function selectImageModel(req) {
429
435
  if (req.inputImages?.length) return DEFAULT_IMAGE_TO_IMAGE_MODEL;
430
436
  return DEFAULT_IMAGE_MODEL;
431
437
  }
432
- function mapAspectRatio(aspectRatio) {
438
+ function mapAspectRatio(aspectRatio, model) {
433
439
  if (!aspectRatio) return void 0;
434
440
  const ar = aspectRatio.trim();
441
+ if (model && isKlingV3Model(model)) {
442
+ return ar;
443
+ }
435
444
  if (ar === "1:1") return "square";
436
445
  if (ar === "4:3") return "landscape_4_3";
437
446
  if (ar === "16:9") return "landscape_16_9";
@@ -439,29 +448,50 @@ function mapAspectRatio(aspectRatio) {
439
448
  if (ar === "9:16") return "portrait_16_9";
440
449
  return ar;
441
450
  }
442
- function buildVideoInput(req) {
451
+ function buildVideoInput(req, model) {
443
452
  const input = {
444
453
  prompt: req.prompt
445
454
  };
446
455
  if (req.startFrame && req.endFrame) {
447
456
  input.start_image_url = req.startFrame;
448
457
  input.end_image_url = req.endFrame;
458
+ const ar = mapAspectRatio(req.aspectRatio, model);
459
+ if (ar) input.aspect_ratio = ar;
460
+ if (req.duration) input.duration = String(req.duration);
449
461
  return input;
450
462
  }
451
463
  if (req.inputImages?.length && !req.startFrame) {
464
+ if (isKlingV3Model(model)) {
465
+ input.start_image_url = req.inputImages[0];
466
+ const ar2 = mapAspectRatio(req.aspectRatio, model);
467
+ if (ar2) input.aspect_ratio = ar2;
468
+ if (req.duration) input.duration = String(req.duration);
469
+ return input;
470
+ }
452
471
  input.reference_image_urls = req.inputImages.slice(0, 7);
453
- const ar = mapAspectRatio(req.aspectRatio);
472
+ const ar = mapAspectRatio(req.aspectRatio, model);
454
473
  if (ar) input.aspect_ratio = ar;
455
474
  if (req.duration) input.duration = String(req.duration);
456
475
  return input;
457
476
  }
458
477
  const imageUrl = req.startFrame ?? req.inputImages?.[0];
459
478
  if (imageUrl) {
460
- input.image_url = imageUrl;
479
+ if (isKlingV3Model(model)) {
480
+ input.start_image_url = imageUrl;
481
+ const ar = mapAspectRatio(req.aspectRatio, model);
482
+ if (ar) input.aspect_ratio = ar;
483
+ } else {
484
+ input.image_url = imageUrl;
485
+ }
461
486
  if (req.duration) input.duration = String(req.duration);
462
487
  return input;
463
488
  }
464
- const imageSize = mapAspectRatio(req.aspectRatio);
489
+ if (isKlingV3Model(model)) {
490
+ throw new Error(
491
+ `Model ${model} requires --start-frame (or --input) because it is image-to-video only`
492
+ );
493
+ }
494
+ const imageSize = mapAspectRatio(req.aspectRatio, model);
465
495
  if (imageSize) input.image_size = imageSize;
466
496
  if (req.n) input.num_videos = req.n;
467
497
  return input;
@@ -486,8 +516,8 @@ var falCapabilities = {
486
516
  supportsCustomAspectRatio: true,
487
517
  supportsVideoInterpolation: true,
488
518
  // Vidu start-end-to-video
489
- videoDurationRange: [2, 8],
490
- // Vidu supports 2-8 seconds
519
+ videoDurationRange: [2, 15],
520
+ // Most models are 2-8; Kling v3 supports up to 15
491
521
  supportsImageEditing: true
492
522
  };
493
523
  var falProvider = {
@@ -515,7 +545,19 @@ var falProvider = {
515
545
  fal.config({ credentials: key });
516
546
  const model = req.kind === "video" ? selectVideoModel(req) : selectImageModel(req);
517
547
  log2(verbose, "Selected model:", model);
518
- const input = req.kind === "video" ? buildVideoInput(req) : buildImageInput(req);
548
+ if (req.kind === "video" && req.duration !== void 0) {
549
+ if (isKlingV3Model(model) && (req.duration < 3 || req.duration > 15)) {
550
+ throw new Error(
551
+ `Model ${model} supports video duration 3-15s, but ${req.duration}s requested`
552
+ );
553
+ }
554
+ if (isViduModel(model) && (req.duration < 2 || req.duration > 8)) {
555
+ throw new Error(
556
+ `Model ${model} supports video duration 2-8s, but ${req.duration}s requested`
557
+ );
558
+ }
559
+ }
560
+ const input = req.kind === "video" ? buildVideoInput(req, model) : buildImageInput(req);
519
561
  const inputSummary = { ...input };
520
562
  for (const key2 of ["image_url", "start_image_url", "end_image_url"]) {
521
563
  if (typeof inputSummary[key2] === "string" && inputSummary[key2].startsWith("data:")) {