@shop-os/modelkit 0.7.10 → 0.8.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.cjs CHANGED
@@ -4844,6 +4844,8 @@ function range(min, max) {
4844
4844
  }
4845
4845
  var KLING_PROMPT = { referenceSyntax: "numbered", maxChars: 2500 };
4846
4846
  var H3_PROMPT = { referenceSyntax: "numbered", maxChars: 5e4 };
4847
+ var KLING_V4_PROMPT = { referenceSyntax: "numbered", maxChars: 2500 };
4848
+ var KLING_V4_AUDIO = "always";
4847
4849
  var NO_REFERENCES = { images: 0, videos: 0, audios: 0 };
4848
4850
  function klingMotionControl(tier) {
4849
4851
  const label = tier === "pro" ? "Pro" : "Standard";
@@ -4944,6 +4946,79 @@ var VIDEO_FAMILY_MODELS = [
4944
4946
  },
4945
4947
  capabilities: { acceptsSourceVideo: true, videoEdit: true }
4946
4948
  },
4949
+ {
4950
+ // https://fal.ai/models/kling/v4/reference-to-video/api (+ /text-to-video,
4951
+ // /image-to-video): one row; references (images or videos) go to reference-to-video,
4952
+ // else a start frame to image-to-video, else text-to-video. Reference images: 10, the
4953
+ // start frame included (fal: "counts toward the image reference limit"), 300 px min.
4954
+ // Reference videos: 5, 3-30.05 s each and 30 s combined, 700 px min, 23.9-60.05 fps.
4955
+ // The prompt names references as @Image1, @Video1 (no space; @Element1 for elements,
4956
+ // which the kit does not send). No sound switch on any endpoint.
4957
+ id: "kling-4.0",
4958
+ aliases: ["kling-4", "kling-v4"],
4959
+ label: "Kling 4.0",
4960
+ type: "video",
4961
+ adapter: "fal",
4962
+ providerModelId: "kling/v4",
4963
+ lifecycle: "active",
4964
+ exposure: ["cowork", "space_builder"],
4965
+ constraints: {
4966
+ aspectRatios: ["adaptive", "16:9", "9:16", "1:1", "21:9"],
4967
+ resolutions: ["720p", "1080p"],
4968
+ durations: { min: 3, max: 30 },
4969
+ durationPresets: [5, 10, 15, 30],
4970
+ references: {
4971
+ ...NO_REFERENCES,
4972
+ images: 10,
4973
+ videos: 5,
4974
+ videoSeconds: { min: 3, max: 30.05, total: 30 }
4975
+ },
4976
+ supports: ["lastFrame"],
4977
+ prompt: KLING_V4_PROMPT,
4978
+ audio: KLING_V4_AUDIO
4979
+ },
4980
+ defaults: { durationSeconds: 5, resolution: "1080p", aspectRatio: "16:9" },
4981
+ usage: { ...VIDEO_USAGE },
4982
+ pricingKind: "video_per_second",
4983
+ display: {
4984
+ provider: "kuaishou",
4985
+ logo: KLING_LOGO,
4986
+ description: "Kuaishou Kling 4.0: text-to-video, start/end frames, or reference-to-video from up to 10 images and 5 videos (30 seconds combined), 3-30 seconds at 720p or 1080p. Prompts name references @Image1, @Video1."
4987
+ },
4988
+ capabilities: { lastFrameRequiresFirstFrame: true }
4989
+ },
4990
+ {
4991
+ // https://fal.ai/models/kling/v4/video-to-video/edit/api: source 3-30.05 s (700 px
4992
+ // min, 23.9-60.05 fps), up to 10 reference images. duration 3-30, or left out for the
4993
+ // source's length. The prompt names the source @Video1 and images @Image1, @Image2.
4994
+ id: "kling-4.0-edit",
4995
+ aliases: ["kling-4-edit", "kling-v4-edit"],
4996
+ label: "Kling 4.0 Edit",
4997
+ type: "video",
4998
+ adapter: "fal",
4999
+ providerModelId: "kling/v4/video-to-video/edit",
5000
+ lifecycle: "active",
5001
+ exposure: ["cowork", "space_builder"],
5002
+ constraints: {
5003
+ resolutions: ["720p", "1080p"],
5004
+ durations: { min: 3, max: 30 },
5005
+ references: { ...NO_REFERENCES, images: 10 },
5006
+ requires: ["sourceVideo"],
5007
+ sourceVideoSeconds: { min: 3, max: 30.05 },
5008
+ supports: [],
5009
+ prompt: KLING_V4_PROMPT,
5010
+ audio: KLING_V4_AUDIO
5011
+ },
5012
+ defaults: { resolution: "1080p" },
5013
+ usage: { ...VIDEO_USAGE },
5014
+ pricingKind: "video_per_second",
5015
+ display: {
5016
+ provider: "kuaishou",
5017
+ logo: KLING_LOGO,
5018
+ description: "Kuaishou Kling 4.0 video edit: change a 3-30 second clip with a prompt and up to 10 reference images, at 720p or 1080p, as long as the source or a set 3-30 seconds. Prompts name the source @Video1 and images @Image1."
5019
+ },
5020
+ capabilities: { acceptsSourceVideo: true, videoEdit: true }
5021
+ },
4947
5022
  {
4948
5023
  // https://fal.ai/models/minimax/h3-max-turbo/text-to-video/api (+ /image-to-video).
4949
5024
  // image-to-video takes a start frame, an end frame, or both, and no aspect_ratio.
@@ -11251,6 +11326,8 @@ var MOTION_PRO = "fal-ai/kling-video/v3/pro/motion-control";
11251
11326
  var MOTION_STANDARD = "fal-ai/kling-video/v3/standard/motion-control";
11252
11327
  var O3_REFERENCE = "fal-ai/kling-video/o3/pro/reference-to-video";
11253
11328
  var O3_EDIT = "fal-ai/kling-video/o3/pro/video-to-video/edit";
11329
+ var V4_FAMILY = "kling/v4";
11330
+ var V4_EDIT = "kling/v4/video-to-video/edit";
11254
11331
  function motionControl(endpoint, req, ctx) {
11255
11332
  const [character] = req.referenceImages ?? [];
11256
11333
  const [motion] = req.referenceVideos ?? [];
@@ -11310,6 +11387,61 @@ var klingV3Family = {
11310
11387
  return motionControl(id, req, ctx);
11311
11388
  }
11312
11389
  };
11390
+ function v4Generate(req, ctx) {
11391
+ const images = urls(req.referenceImages);
11392
+ const videos = urls(req.referenceVideos);
11393
+ const duration = wholeSeconds(req, ctx);
11394
+ const resolution = resolutionOf(req, ctx);
11395
+ const input = { prompt: req.prompt.trim(), duration, resolution };
11396
+ let endpoint;
11397
+ if (images.length + videos.length > 0) {
11398
+ endpoint = `${V4_FAMILY}/reference-to-video`;
11399
+ if (images.length > 0) input["image_urls"] = images;
11400
+ if (videos.length > 0) input["video_urls"] = videos;
11401
+ if (req.firstFrame) input["start_image_url"] = refToUrl(req.firstFrame);
11402
+ if (req.aspectRatio !== void 0) {
11403
+ input["aspect_ratio"] = req.aspectRatio === "adaptive" ? "auto" : req.aspectRatio;
11404
+ }
11405
+ } else if (req.firstFrame) {
11406
+ endpoint = `${V4_FAMILY}/image-to-video`;
11407
+ input["start_image_url"] = refToUrl(req.firstFrame);
11408
+ if (req.lastFrame) input["end_image_url"] = refToUrl(req.lastFrame);
11409
+ } else {
11410
+ endpoint = `${V4_FAMILY}/text-to-video`;
11411
+ const ratio = concreteRatio(req);
11412
+ if (ratio !== void 0) input["aspect_ratio"] = ratio;
11413
+ }
11414
+ return { endpoint, input, resolution, seconds: requestedSeconds(duration) };
11415
+ }
11416
+ function v4Edit(req, ctx) {
11417
+ if (req.sourceVideo === void 0) throw refusal(ctx, "needs a source video", "missing_input");
11418
+ const resolution = resolutionOf(req, ctx);
11419
+ const input = {
11420
+ prompt: req.prompt.trim(),
11421
+ video_url: refToUrl(req.sourceVideo),
11422
+ resolution
11423
+ };
11424
+ const images = urls(req.referenceImages);
11425
+ if (images.length > 0) input["image_urls"] = images;
11426
+ if (req.durationSeconds === void 0) {
11427
+ return {
11428
+ endpoint: V4_EDIT,
11429
+ input,
11430
+ resolution,
11431
+ seconds: inputLengthSeconds(req, req.sourceVideo)
11432
+ };
11433
+ }
11434
+ const duration = wholeSeconds(req, ctx);
11435
+ input["duration"] = duration;
11436
+ return { endpoint: V4_EDIT, input, resolution, seconds: requestedSeconds(duration) };
11437
+ }
11438
+ var KLING_V4_VIDEO_IDS = /* @__PURE__ */ new Set([V4_FAMILY, V4_EDIT]);
11439
+ var klingV4Family = {
11440
+ ids: KLING_V4_VIDEO_IDS,
11441
+ plan(req, ctx) {
11442
+ return ctx.model.providerModelId.toLowerCase() === V4_EDIT ? v4Edit(req, ctx) : v4Generate(req, ctx);
11443
+ }
11444
+ };
11313
11445
 
11314
11446
  // src/replicate-video-kinds.ts
11315
11447
  function replicateBaseModelId(providerModelId) {
@@ -11380,6 +11512,8 @@ var MOTION_PRO2 = "fal-ai/kling-video/v3/pro/motion-control";
11380
11512
  var MOTION_STANDARD2 = "fal-ai/kling-video/v3/standard/motion-control";
11381
11513
  var O3_REFERENCE2 = "fal-ai/kling-video/o3/pro/reference-to-video";
11382
11514
  var O3_EDIT2 = "fal-ai/kling-video/o3/pro/video-to-video/edit";
11515
+ var KLING_V4 = "kling/v4";
11516
+ var KLING_V4_EDIT = "kling/v4/video-to-video/edit";
11383
11517
  var H3_TURBO = "minimax/h3-max-turbo";
11384
11518
  var H3_RECAST = "minimax/h3-max/recast";
11385
11519
  var H3_RELIGHT = "minimax/h3-max/relight";
@@ -11388,6 +11522,7 @@ var HAPPY_HORSE_EDIT = "alibaba/happy-horse/video-edit";
11388
11522
  var VIDU_Q4 = "fal-ai/vidu/q4";
11389
11523
  var OMNIHUMAN_V2 = "bytedance/omnihuman/v2";
11390
11524
  var KLING_O3_IMAGE_CAP = 7;
11525
+ var KLING_V4_IMAGE_CAP = 10;
11391
11526
  var TURBO_AUDIO_MIN_SECONDS = 2;
11392
11527
  var OMNIHUMAN_AUDIO_SECONDS = { min: 4, max: 300 };
11393
11528
  function missing(message) {
@@ -11443,6 +11578,23 @@ function o3Reference2(req) {
11443
11578
  }
11444
11579
  return needsPrompt(req);
11445
11580
  }
11581
+ function hasReferences(req) {
11582
+ return count(req.referenceImages) + count(req.referenceVideos) > 0;
11583
+ }
11584
+ function klingV4(req) {
11585
+ if (hasReferences(req)) {
11586
+ if (req.lastFrame !== void 0) {
11587
+ return unsupported2("takes an end frame only without reference images or videos");
11588
+ }
11589
+ const images = count(req.referenceImages) + (req.firstFrame === void 0 ? 0 : 1);
11590
+ if (images > KLING_V4_IMAGE_CAP) {
11591
+ return unsupported2(
11592
+ `takes up to ${KLING_V4_IMAGE_CAP} images in all, the start frame included; this request has ${images}`
11593
+ );
11594
+ }
11595
+ }
11596
+ return needsPrompt(req);
11597
+ }
11446
11598
  function h3Turbo(req) {
11447
11599
  if (count(req.referenceImages) + count(req.referenceVideos) > 0) {
11448
11600
  return unsupported2("takes no reference images or videos");
@@ -11521,6 +11673,8 @@ var RULES = /* @__PURE__ */ new Map([
11521
11673
  [O3_REFERENCE2, o3Reference2],
11522
11674
  [KLING_O3_OMNI, o3Reference2],
11523
11675
  [O3_EDIT2, (req) => needsSource(req) ?? needsPrompt(req)],
11676
+ [KLING_V4, klingV4],
11677
+ [KLING_V4_EDIT, (req) => needsSource(req) ?? needsPrompt(req)],
11524
11678
  [H3_TURBO, h3Turbo],
11525
11679
  [MINIMAX_H3_INSERT, h3Insert],
11526
11680
  [H3_RECAST, h3Recast],
@@ -11570,6 +11724,19 @@ function applyFalVideoRules(model, req, callerRatio, warnings) {
11570
11724
  warnings.push(viduSilentWarning(model));
11571
11725
  req.generateAudio = false;
11572
11726
  }
11727
+ if (id === KLING_V4 && req.firstFrame !== void 0 && !hasReferences(req)) {
11728
+ if (req.aspectRatio !== void 0) {
11729
+ if (callerRatio !== void 0) {
11730
+ warnings.push({
11731
+ code: "ratio_dropped",
11732
+ field: "aspectRatio",
11733
+ from: req.aspectRatio,
11734
+ message: `${model.id} follows the start frame's aspect ratio`
11735
+ });
11736
+ }
11737
+ delete req.aspectRatio;
11738
+ }
11739
+ }
11573
11740
  const endFrameOnly = req.lastFrame !== void 0 && req.firstFrame === void 0;
11574
11741
  if (id === H3_TURBO && endFrameOnly && req.aspectRatio !== void 0) {
11575
11742
  if (callerRatio !== void 0 && callerRatio !== "adaptive") {
@@ -11746,6 +11913,7 @@ var viduFamily = { ids: VIDU_MODEL_IDS, plan: plan3 };
11746
11913
  var FAMILIES2 = [
11747
11914
  klingV3Family,
11748
11915
  klingOmniFamily,
11916
+ klingV4Family,
11749
11917
  minimaxH3MaxFamily,
11750
11918
  happyHorseFamily,
11751
11919
  viduFamily,
@@ -12032,8 +12200,8 @@ async function collectFalImages(payload, ctx, req, label) {
12032
12200
  };
12033
12201
  }
12034
12202
  async function generateSpecImage(req, ctx, deps, spec) {
12035
- const hasReferences = (req.references ?? []).length > 0;
12036
- const endpoint = hasReferences && spec.spec.editEndpoint !== void 0 ? spec.spec.editEndpoint : ctx.model.providerModelId;
12203
+ const hasReferences2 = (req.references ?? []).length > 0;
12204
+ const endpoint = hasReferences2 && spec.spec.editEndpoint !== void 0 ? spec.spec.editEndpoint : ctx.model.providerModelId;
12037
12205
  const payload = await runJob(ctx, deps, endpoint, spec.input);
12038
12206
  return collectFalImages(payload, ctx, req, `fal ${endpoint}`);
12039
12207
  }
@@ -14378,8 +14546,8 @@ function imageBody(req, ctx, outputFormat) {
14378
14546
  function videoBody(req, ctx, mode) {
14379
14547
  const prompt = checkPrompt(req, ctx);
14380
14548
  const model = lumaModel(ctx);
14381
- const hasReferences = (req.referenceImages ?? []).length + (req.referenceVideos ?? []).length + (req.referenceAudios ?? []).length > 0;
14382
- if (hasReferences) {
14549
+ const hasReferences2 = (req.referenceImages ?? []).length + (req.referenceVideos ?? []).length + (req.referenceAudios ?? []).length > 0;
14550
+ if (hasReferences2) {
14383
14551
  refuseOrDrop(
14384
14552
  ctx,
14385
14553
  "referenceImages",
@@ -17201,7 +17369,7 @@ function keysFromEnv(env, prefix = "") {
17201
17369
  set("deepseek", pick2("DEEPSEEK_API_KEY"));
17202
17370
  set("moonshot", pick2("MOONSHOT_API_KEY"));
17203
17371
  set("minimax", pick2("MINIMAX_API_KEY"));
17204
- set("ark", pick2("ARK_API_KEY", "BYTEPLUS_ARK_API_KEY", "BYTEDANCE_API_KEY"));
17372
+ set("ark", pick2("BYTEDANCE_API_KEY"));
17205
17373
  set("fal", pick2("FAL_KEY", "FAL_API_KEY"));
17206
17374
  set("replicate", pick2("REPLICATE_API_TOKEN", "REPLICATE_API_KEY"));
17207
17375
  set("prodia", pick2("PRODIA_API_KEY", "PRODIA_TOKEN"));