@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.js CHANGED
@@ -4706,6 +4706,8 @@ function range(min, max) {
4706
4706
  }
4707
4707
  var KLING_PROMPT = { referenceSyntax: "numbered", maxChars: 2500 };
4708
4708
  var H3_PROMPT = { referenceSyntax: "numbered", maxChars: 5e4 };
4709
+ var KLING_V4_PROMPT = { referenceSyntax: "numbered", maxChars: 2500 };
4710
+ var KLING_V4_AUDIO = "always";
4709
4711
  var NO_REFERENCES = { images: 0, videos: 0, audios: 0 };
4710
4712
  function klingMotionControl(tier) {
4711
4713
  const label = tier === "pro" ? "Pro" : "Standard";
@@ -4806,6 +4808,79 @@ var VIDEO_FAMILY_MODELS = [
4806
4808
  },
4807
4809
  capabilities: { acceptsSourceVideo: true, videoEdit: true }
4808
4810
  },
4811
+ {
4812
+ // https://fal.ai/models/kling/v4/reference-to-video/api (+ /text-to-video,
4813
+ // /image-to-video): one row; references (images or videos) go to reference-to-video,
4814
+ // else a start frame to image-to-video, else text-to-video. Reference images: 10, the
4815
+ // start frame included (fal: "counts toward the image reference limit"), 300 px min.
4816
+ // Reference videos: 5, 3-30.05 s each and 30 s combined, 700 px min, 23.9-60.05 fps.
4817
+ // The prompt names references as @Image1, @Video1 (no space; @Element1 for elements,
4818
+ // which the kit does not send). No sound switch on any endpoint.
4819
+ id: "kling-4.0",
4820
+ aliases: ["kling-4", "kling-v4"],
4821
+ label: "Kling 4.0",
4822
+ type: "video",
4823
+ adapter: "fal",
4824
+ providerModelId: "kling/v4",
4825
+ lifecycle: "active",
4826
+ exposure: ["cowork", "space_builder"],
4827
+ constraints: {
4828
+ aspectRatios: ["adaptive", "16:9", "9:16", "1:1", "21:9"],
4829
+ resolutions: ["720p", "1080p"],
4830
+ durations: { min: 3, max: 30 },
4831
+ durationPresets: [5, 10, 15, 30],
4832
+ references: {
4833
+ ...NO_REFERENCES,
4834
+ images: 10,
4835
+ videos: 5,
4836
+ videoSeconds: { min: 3, max: 30.05, total: 30 }
4837
+ },
4838
+ supports: ["lastFrame"],
4839
+ prompt: KLING_V4_PROMPT,
4840
+ audio: KLING_V4_AUDIO
4841
+ },
4842
+ defaults: { durationSeconds: 5, resolution: "1080p", aspectRatio: "16:9" },
4843
+ usage: { ...VIDEO_USAGE },
4844
+ pricingKind: "video_per_second",
4845
+ display: {
4846
+ provider: "kuaishou",
4847
+ logo: KLING_LOGO,
4848
+ 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."
4849
+ },
4850
+ capabilities: { lastFrameRequiresFirstFrame: true }
4851
+ },
4852
+ {
4853
+ // https://fal.ai/models/kling/v4/video-to-video/edit/api: source 3-30.05 s (700 px
4854
+ // min, 23.9-60.05 fps), up to 10 reference images. duration 3-30, or left out for the
4855
+ // source's length. The prompt names the source @Video1 and images @Image1, @Image2.
4856
+ id: "kling-4.0-edit",
4857
+ aliases: ["kling-4-edit", "kling-v4-edit"],
4858
+ label: "Kling 4.0 Edit",
4859
+ type: "video",
4860
+ adapter: "fal",
4861
+ providerModelId: "kling/v4/video-to-video/edit",
4862
+ lifecycle: "active",
4863
+ exposure: ["cowork", "space_builder"],
4864
+ constraints: {
4865
+ resolutions: ["720p", "1080p"],
4866
+ durations: { min: 3, max: 30 },
4867
+ references: { ...NO_REFERENCES, images: 10 },
4868
+ requires: ["sourceVideo"],
4869
+ sourceVideoSeconds: { min: 3, max: 30.05 },
4870
+ supports: [],
4871
+ prompt: KLING_V4_PROMPT,
4872
+ audio: KLING_V4_AUDIO
4873
+ },
4874
+ defaults: { resolution: "1080p" },
4875
+ usage: { ...VIDEO_USAGE },
4876
+ pricingKind: "video_per_second",
4877
+ display: {
4878
+ provider: "kuaishou",
4879
+ logo: KLING_LOGO,
4880
+ 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."
4881
+ },
4882
+ capabilities: { acceptsSourceVideo: true, videoEdit: true }
4883
+ },
4809
4884
  {
4810
4885
  // https://fal.ai/models/minimax/h3-max-turbo/text-to-video/api (+ /image-to-video).
4811
4886
  // image-to-video takes a start frame, an end frame, or both, and no aspect_ratio.
@@ -11113,6 +11188,8 @@ var MOTION_PRO = "fal-ai/kling-video/v3/pro/motion-control";
11113
11188
  var MOTION_STANDARD = "fal-ai/kling-video/v3/standard/motion-control";
11114
11189
  var O3_REFERENCE = "fal-ai/kling-video/o3/pro/reference-to-video";
11115
11190
  var O3_EDIT = "fal-ai/kling-video/o3/pro/video-to-video/edit";
11191
+ var V4_FAMILY = "kling/v4";
11192
+ var V4_EDIT = "kling/v4/video-to-video/edit";
11116
11193
  function motionControl(endpoint, req, ctx) {
11117
11194
  const [character] = req.referenceImages ?? [];
11118
11195
  const [motion] = req.referenceVideos ?? [];
@@ -11172,6 +11249,61 @@ var klingV3Family = {
11172
11249
  return motionControl(id, req, ctx);
11173
11250
  }
11174
11251
  };
11252
+ function v4Generate(req, ctx) {
11253
+ const images = urls(req.referenceImages);
11254
+ const videos = urls(req.referenceVideos);
11255
+ const duration = wholeSeconds(req, ctx);
11256
+ const resolution = resolutionOf(req, ctx);
11257
+ const input = { prompt: req.prompt.trim(), duration, resolution };
11258
+ let endpoint;
11259
+ if (images.length + videos.length > 0) {
11260
+ endpoint = `${V4_FAMILY}/reference-to-video`;
11261
+ if (images.length > 0) input["image_urls"] = images;
11262
+ if (videos.length > 0) input["video_urls"] = videos;
11263
+ if (req.firstFrame) input["start_image_url"] = refToUrl(req.firstFrame);
11264
+ if (req.aspectRatio !== void 0) {
11265
+ input["aspect_ratio"] = req.aspectRatio === "adaptive" ? "auto" : req.aspectRatio;
11266
+ }
11267
+ } else if (req.firstFrame) {
11268
+ endpoint = `${V4_FAMILY}/image-to-video`;
11269
+ input["start_image_url"] = refToUrl(req.firstFrame);
11270
+ if (req.lastFrame) input["end_image_url"] = refToUrl(req.lastFrame);
11271
+ } else {
11272
+ endpoint = `${V4_FAMILY}/text-to-video`;
11273
+ const ratio = concreteRatio(req);
11274
+ if (ratio !== void 0) input["aspect_ratio"] = ratio;
11275
+ }
11276
+ return { endpoint, input, resolution, seconds: requestedSeconds(duration) };
11277
+ }
11278
+ function v4Edit(req, ctx) {
11279
+ if (req.sourceVideo === void 0) throw refusal(ctx, "needs a source video", "missing_input");
11280
+ const resolution = resolutionOf(req, ctx);
11281
+ const input = {
11282
+ prompt: req.prompt.trim(),
11283
+ video_url: refToUrl(req.sourceVideo),
11284
+ resolution
11285
+ };
11286
+ const images = urls(req.referenceImages);
11287
+ if (images.length > 0) input["image_urls"] = images;
11288
+ if (req.durationSeconds === void 0) {
11289
+ return {
11290
+ endpoint: V4_EDIT,
11291
+ input,
11292
+ resolution,
11293
+ seconds: inputLengthSeconds(req, req.sourceVideo)
11294
+ };
11295
+ }
11296
+ const duration = wholeSeconds(req, ctx);
11297
+ input["duration"] = duration;
11298
+ return { endpoint: V4_EDIT, input, resolution, seconds: requestedSeconds(duration) };
11299
+ }
11300
+ var KLING_V4_VIDEO_IDS = /* @__PURE__ */ new Set([V4_FAMILY, V4_EDIT]);
11301
+ var klingV4Family = {
11302
+ ids: KLING_V4_VIDEO_IDS,
11303
+ plan(req, ctx) {
11304
+ return ctx.model.providerModelId.toLowerCase() === V4_EDIT ? v4Edit(req, ctx) : v4Generate(req, ctx);
11305
+ }
11306
+ };
11175
11307
 
11176
11308
  // src/replicate-video-kinds.ts
11177
11309
  function replicateBaseModelId(providerModelId) {
@@ -11242,6 +11374,8 @@ var MOTION_PRO2 = "fal-ai/kling-video/v3/pro/motion-control";
11242
11374
  var MOTION_STANDARD2 = "fal-ai/kling-video/v3/standard/motion-control";
11243
11375
  var O3_REFERENCE2 = "fal-ai/kling-video/o3/pro/reference-to-video";
11244
11376
  var O3_EDIT2 = "fal-ai/kling-video/o3/pro/video-to-video/edit";
11377
+ var KLING_V4 = "kling/v4";
11378
+ var KLING_V4_EDIT = "kling/v4/video-to-video/edit";
11245
11379
  var H3_TURBO = "minimax/h3-max-turbo";
11246
11380
  var H3_RECAST = "minimax/h3-max/recast";
11247
11381
  var H3_RELIGHT = "minimax/h3-max/relight";
@@ -11250,6 +11384,7 @@ var HAPPY_HORSE_EDIT = "alibaba/happy-horse/video-edit";
11250
11384
  var VIDU_Q4 = "fal-ai/vidu/q4";
11251
11385
  var OMNIHUMAN_V2 = "bytedance/omnihuman/v2";
11252
11386
  var KLING_O3_IMAGE_CAP = 7;
11387
+ var KLING_V4_IMAGE_CAP = 10;
11253
11388
  var TURBO_AUDIO_MIN_SECONDS = 2;
11254
11389
  var OMNIHUMAN_AUDIO_SECONDS = { min: 4, max: 300 };
11255
11390
  function missing(message) {
@@ -11305,6 +11440,23 @@ function o3Reference2(req) {
11305
11440
  }
11306
11441
  return needsPrompt(req);
11307
11442
  }
11443
+ function hasReferences(req) {
11444
+ return count(req.referenceImages) + count(req.referenceVideos) > 0;
11445
+ }
11446
+ function klingV4(req) {
11447
+ if (hasReferences(req)) {
11448
+ if (req.lastFrame !== void 0) {
11449
+ return unsupported2("takes an end frame only without reference images or videos");
11450
+ }
11451
+ const images = count(req.referenceImages) + (req.firstFrame === void 0 ? 0 : 1);
11452
+ if (images > KLING_V4_IMAGE_CAP) {
11453
+ return unsupported2(
11454
+ `takes up to ${KLING_V4_IMAGE_CAP} images in all, the start frame included; this request has ${images}`
11455
+ );
11456
+ }
11457
+ }
11458
+ return needsPrompt(req);
11459
+ }
11308
11460
  function h3Turbo(req) {
11309
11461
  if (count(req.referenceImages) + count(req.referenceVideos) > 0) {
11310
11462
  return unsupported2("takes no reference images or videos");
@@ -11383,6 +11535,8 @@ var RULES = /* @__PURE__ */ new Map([
11383
11535
  [O3_REFERENCE2, o3Reference2],
11384
11536
  [KLING_O3_OMNI, o3Reference2],
11385
11537
  [O3_EDIT2, (req) => needsSource(req) ?? needsPrompt(req)],
11538
+ [KLING_V4, klingV4],
11539
+ [KLING_V4_EDIT, (req) => needsSource(req) ?? needsPrompt(req)],
11386
11540
  [H3_TURBO, h3Turbo],
11387
11541
  [MINIMAX_H3_INSERT, h3Insert],
11388
11542
  [H3_RECAST, h3Recast],
@@ -11432,6 +11586,19 @@ function applyFalVideoRules(model, req, callerRatio, warnings) {
11432
11586
  warnings.push(viduSilentWarning(model));
11433
11587
  req.generateAudio = false;
11434
11588
  }
11589
+ if (id === KLING_V4 && req.firstFrame !== void 0 && !hasReferences(req)) {
11590
+ if (req.aspectRatio !== void 0) {
11591
+ if (callerRatio !== void 0) {
11592
+ warnings.push({
11593
+ code: "ratio_dropped",
11594
+ field: "aspectRatio",
11595
+ from: req.aspectRatio,
11596
+ message: `${model.id} follows the start frame's aspect ratio`
11597
+ });
11598
+ }
11599
+ delete req.aspectRatio;
11600
+ }
11601
+ }
11435
11602
  const endFrameOnly = req.lastFrame !== void 0 && req.firstFrame === void 0;
11436
11603
  if (id === H3_TURBO && endFrameOnly && req.aspectRatio !== void 0) {
11437
11604
  if (callerRatio !== void 0 && callerRatio !== "adaptive") {
@@ -11608,6 +11775,7 @@ var viduFamily = { ids: VIDU_MODEL_IDS, plan: plan3 };
11608
11775
  var FAMILIES2 = [
11609
11776
  klingV3Family,
11610
11777
  klingOmniFamily,
11778
+ klingV4Family,
11611
11779
  minimaxH3MaxFamily,
11612
11780
  happyHorseFamily,
11613
11781
  viduFamily,
@@ -11894,8 +12062,8 @@ async function collectFalImages(payload, ctx, req, label) {
11894
12062
  };
11895
12063
  }
11896
12064
  async function generateSpecImage(req, ctx, deps, spec) {
11897
- const hasReferences = (req.references ?? []).length > 0;
11898
- const endpoint = hasReferences && spec.spec.editEndpoint !== void 0 ? spec.spec.editEndpoint : ctx.model.providerModelId;
12065
+ const hasReferences2 = (req.references ?? []).length > 0;
12066
+ const endpoint = hasReferences2 && spec.spec.editEndpoint !== void 0 ? spec.spec.editEndpoint : ctx.model.providerModelId;
11899
12067
  const payload = await runJob(ctx, deps, endpoint, spec.input);
11900
12068
  return collectFalImages(payload, ctx, req, `fal ${endpoint}`);
11901
12069
  }
@@ -14242,8 +14410,8 @@ function imageBody(req, ctx, outputFormat) {
14242
14410
  function videoBody(req, ctx, mode) {
14243
14411
  const prompt = checkPrompt(req, ctx);
14244
14412
  const model = lumaModel(ctx);
14245
- const hasReferences = (req.referenceImages ?? []).length + (req.referenceVideos ?? []).length + (req.referenceAudios ?? []).length > 0;
14246
- if (hasReferences) {
14413
+ const hasReferences2 = (req.referenceImages ?? []).length + (req.referenceVideos ?? []).length + (req.referenceAudios ?? []).length > 0;
14414
+ if (hasReferences2) {
14247
14415
  refuseOrDrop(
14248
14416
  ctx,
14249
14417
  "referenceImages",
@@ -17065,7 +17233,7 @@ function keysFromEnv(env, prefix = "") {
17065
17233
  set("deepseek", pick2("DEEPSEEK_API_KEY"));
17066
17234
  set("moonshot", pick2("MOONSHOT_API_KEY"));
17067
17235
  set("minimax", pick2("MINIMAX_API_KEY"));
17068
- set("ark", pick2("ARK_API_KEY", "BYTEPLUS_ARK_API_KEY", "BYTEDANCE_API_KEY"));
17236
+ set("ark", pick2("BYTEDANCE_API_KEY"));
17069
17237
  set("fal", pick2("FAL_KEY", "FAL_API_KEY"));
17070
17238
  set("replicate", pick2("REPLICATE_API_TOKEN", "REPLICATE_API_KEY"));
17071
17239
  set("prodia", pick2("PRODIA_API_KEY", "PRODIA_TOKEN"));