@shop-os/modelkit 0.7.2 → 0.7.4
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/CHANGELOG.md +23 -0
- package/dist/catalog.cjs +155 -150
- package/dist/catalog.cjs.map +1 -1
- package/dist/catalog.js +155 -150
- package/dist/catalog.js.map +1 -1
- package/dist/index.cjs +294 -211
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +294 -211
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -6687,6 +6687,161 @@ var MODEL3D_IMAGE_SLOTS = {
|
|
|
6687
6687
|
ordered: ["image", "left", "back", "right"],
|
|
6688
6688
|
unordered: ["image", "back", "left", "right", "top"]
|
|
6689
6689
|
};
|
|
6690
|
+
var MODEL3D_FAMILY_RULES = {
|
|
6691
|
+
trellis: {
|
|
6692
|
+
textPath: false,
|
|
6693
|
+
views: ["none"],
|
|
6694
|
+
multiImage: false,
|
|
6695
|
+
texture: null,
|
|
6696
|
+
pbr: false,
|
|
6697
|
+
seed: true,
|
|
6698
|
+
textureRef: false,
|
|
6699
|
+
resolutions: "integer"
|
|
6700
|
+
},
|
|
6701
|
+
hunyuan: {
|
|
6702
|
+
textPath: true,
|
|
6703
|
+
views: ["none", "named"],
|
|
6704
|
+
multiImage: false,
|
|
6705
|
+
// generate_type
|
|
6706
|
+
texture: { none: "Geometry", standard: "Normal" },
|
|
6707
|
+
pbr: true,
|
|
6708
|
+
seed: false,
|
|
6709
|
+
textureRef: false,
|
|
6710
|
+
resolutions: null
|
|
6711
|
+
},
|
|
6712
|
+
tripo: {
|
|
6713
|
+
textPath: true,
|
|
6714
|
+
views: ["none", "ordered"],
|
|
6715
|
+
multiImage: true,
|
|
6716
|
+
// texture_quality; null sends an untextured model.
|
|
6717
|
+
texture: { none: null, standard: "standard", detailed: "detailed" },
|
|
6718
|
+
pbr: true,
|
|
6719
|
+
seed: true,
|
|
6720
|
+
textureRef: false,
|
|
6721
|
+
resolutions: null
|
|
6722
|
+
},
|
|
6723
|
+
rodin: {
|
|
6724
|
+
textPath: true,
|
|
6725
|
+
views: ["none", "unordered"],
|
|
6726
|
+
multiImage: false,
|
|
6727
|
+
texture: null,
|
|
6728
|
+
pbr: false,
|
|
6729
|
+
seed: true,
|
|
6730
|
+
textureRef: false,
|
|
6731
|
+
resolutions: null
|
|
6732
|
+
},
|
|
6733
|
+
meshy: {
|
|
6734
|
+
textPath: true,
|
|
6735
|
+
views: ["none", "unordered"],
|
|
6736
|
+
multiImage: true,
|
|
6737
|
+
// The text endpoint's mode; the image endpoints take should_texture.
|
|
6738
|
+
texture: { none: "preview", standard: "full" },
|
|
6739
|
+
pbr: true,
|
|
6740
|
+
seed: true,
|
|
6741
|
+
textureRef: true,
|
|
6742
|
+
resolutions: null
|
|
6743
|
+
},
|
|
6744
|
+
hi3d: {
|
|
6745
|
+
textPath: false,
|
|
6746
|
+
views: ["none", "named"],
|
|
6747
|
+
multiImage: true,
|
|
6748
|
+
// enable_texture
|
|
6749
|
+
texture: { none: false, standard: true },
|
|
6750
|
+
pbr: true,
|
|
6751
|
+
seed: false,
|
|
6752
|
+
textureRef: false,
|
|
6753
|
+
resolutions: { quality: "2048quality", master: "2048master" }
|
|
6754
|
+
},
|
|
6755
|
+
sam: {
|
|
6756
|
+
textPath: false,
|
|
6757
|
+
views: ["none"],
|
|
6758
|
+
multiImage: false,
|
|
6759
|
+
texture: null,
|
|
6760
|
+
pbr: false,
|
|
6761
|
+
seed: true,
|
|
6762
|
+
textureRef: false,
|
|
6763
|
+
resolutions: null
|
|
6764
|
+
}
|
|
6765
|
+
};
|
|
6766
|
+
function model3dSpecIssues(spec) {
|
|
6767
|
+
const issues = [];
|
|
6768
|
+
const add = (path, message) => issues.push({ path, message });
|
|
6769
|
+
const rules = MODEL3D_FAMILY_RULES[spec.family];
|
|
6770
|
+
const promptOnly = spec.text && !spec.imageRequired;
|
|
6771
|
+
if (spec.endpoints.image === void 0)
|
|
6772
|
+
add(["endpoints", "image"], "every row needs an image endpoint");
|
|
6773
|
+
if (promptOnly && !rules.textPath) {
|
|
6774
|
+
add(
|
|
6775
|
+
["imageRequired"],
|
|
6776
|
+
`${spec.family} has no text-to-3D endpoint; a text row needs an image`
|
|
6777
|
+
);
|
|
6778
|
+
}
|
|
6779
|
+
if (promptOnly && spec.endpoints.text === void 0) {
|
|
6780
|
+
add(["endpoints", "text"], "a text row needs a text endpoint");
|
|
6781
|
+
}
|
|
6782
|
+
if (!rules.views.includes(spec.views)) {
|
|
6783
|
+
add(["views"], `${spec.family} takes views ${rules.views.join(" or ")}`);
|
|
6784
|
+
}
|
|
6785
|
+
if (spec.views === "none" && spec.maxImages !== 1) {
|
|
6786
|
+
add(["maxImages"], "a row without views takes 1 image");
|
|
6787
|
+
}
|
|
6788
|
+
if (spec.views === "unordered" && spec.maxImages < 2) {
|
|
6789
|
+
add(["maxImages"], "a row with views takes at least 2 images");
|
|
6790
|
+
}
|
|
6791
|
+
const slots = MODEL3D_IMAGE_SLOTS[spec.views].length;
|
|
6792
|
+
if (spec.views !== "none" && spec.maxImages > slots) {
|
|
6793
|
+
add(["maxImages"], `a row with ${spec.views} views sends at most ${slots} images`);
|
|
6794
|
+
}
|
|
6795
|
+
if ((spec.views === "named" || spec.views === "ordered") && spec.maxImages < slots) {
|
|
6796
|
+
add(
|
|
6797
|
+
["maxImages"],
|
|
6798
|
+
`a row with ${spec.views} views takes ${slots} images (front and three sides)`
|
|
6799
|
+
);
|
|
6800
|
+
}
|
|
6801
|
+
if (spec.views !== "none" && rules.multiImage && spec.endpoints.multiImage === void 0) {
|
|
6802
|
+
add(["endpoints", "multiImage"], `${spec.family} sends views to a multi-image endpoint`);
|
|
6803
|
+
}
|
|
6804
|
+
if (rules.texture === null) {
|
|
6805
|
+
if (spec.texture.length > 0) add(["texture"], `${spec.family} has no texture switch`);
|
|
6806
|
+
} else {
|
|
6807
|
+
const allowed = rules.texture;
|
|
6808
|
+
if (spec.texture.length === 0) add(["texture"], `${spec.family} needs its texture options`);
|
|
6809
|
+
if (new Set(spec.texture).size !== spec.texture.length)
|
|
6810
|
+
add(["texture"], "texture options repeat");
|
|
6811
|
+
for (const t of spec.texture) {
|
|
6812
|
+
if (!Object.hasOwn(allowed, t))
|
|
6813
|
+
add(["texture"], `${spec.family} has no "${t}" texture`);
|
|
6814
|
+
}
|
|
6815
|
+
}
|
|
6816
|
+
if (spec.pbr && !rules.pbr) add(["pbr"], `${spec.family} has no PBR switch`);
|
|
6817
|
+
if (spec.pbr && !spec.texture.some((t) => t !== "none")) {
|
|
6818
|
+
add(["pbr"], "PBR needs a textured option");
|
|
6819
|
+
}
|
|
6820
|
+
if (spec.seed && !rules.seed) add(["seed"], `${spec.family} takes no seed`);
|
|
6821
|
+
if (spec.seedMax !== void 0 && !spec.seed) add(["seedMax"], "seedMax needs seed");
|
|
6822
|
+
if (spec.textureRef && !rules.textureRef)
|
|
6823
|
+
add(["textureRef"], `${spec.family} takes no texture reference`);
|
|
6824
|
+
const res = spec.resolutions;
|
|
6825
|
+
if (rules.resolutions === null) {
|
|
6826
|
+
if (res !== void 0) add(["resolutions"], `${spec.family} has no resolution option`);
|
|
6827
|
+
} else if (res === void 0) {
|
|
6828
|
+
add(["resolutions"], `${spec.family} needs its resolution options`);
|
|
6829
|
+
} else {
|
|
6830
|
+
if (!res.options.includes(res.default)) {
|
|
6831
|
+
add(["resolutions", "default"], "default must be an option");
|
|
6832
|
+
}
|
|
6833
|
+
if (new Set(res.options).size !== res.options.length) {
|
|
6834
|
+
add(["resolutions", "options"], "resolution options repeat");
|
|
6835
|
+
}
|
|
6836
|
+
const allowed = rules.resolutions;
|
|
6837
|
+
for (const option of res.options) {
|
|
6838
|
+
const ok = allowed === "integer" ? /^[1-9][0-9]*$/.test(option) : Object.hasOwn(allowed, option);
|
|
6839
|
+
if (!ok)
|
|
6840
|
+
add(["resolutions", "options"], `${spec.family} has no "${option}" resolution`);
|
|
6841
|
+
}
|
|
6842
|
+
}
|
|
6843
|
+
return issues;
|
|
6844
|
+
}
|
|
6690
6845
|
function model3dInputRefusal(spec, wired) {
|
|
6691
6846
|
const top = spec.views === "unordered" && wired.top === true;
|
|
6692
6847
|
const anyView = spec.views !== "none" && (wired.back || wired.left || wired.right || top);
|
|
@@ -7274,156 +7429,6 @@ var LanguageOptionSchema = import_zod3.z.looseObject({
|
|
|
7274
7429
|
code: import_zod3.z.string().min(1),
|
|
7275
7430
|
name: import_zod3.z.string().min(1)
|
|
7276
7431
|
});
|
|
7277
|
-
var MODEL3D_FAMILY_RULES = {
|
|
7278
|
-
trellis: {
|
|
7279
|
-
textPath: false,
|
|
7280
|
-
views: ["none"],
|
|
7281
|
-
multiImage: false,
|
|
7282
|
-
texture: null,
|
|
7283
|
-
pbr: false,
|
|
7284
|
-
seed: true,
|
|
7285
|
-
textureRef: false,
|
|
7286
|
-
resolutions: "integer"
|
|
7287
|
-
},
|
|
7288
|
-
hunyuan: {
|
|
7289
|
-
textPath: true,
|
|
7290
|
-
views: ["none", "named"],
|
|
7291
|
-
multiImage: false,
|
|
7292
|
-
texture: ["none", "standard"],
|
|
7293
|
-
pbr: true,
|
|
7294
|
-
seed: false,
|
|
7295
|
-
textureRef: false,
|
|
7296
|
-
resolutions: null
|
|
7297
|
-
},
|
|
7298
|
-
tripo: {
|
|
7299
|
-
textPath: true,
|
|
7300
|
-
views: ["none", "ordered"],
|
|
7301
|
-
multiImage: true,
|
|
7302
|
-
texture: ["none", "standard", "detailed"],
|
|
7303
|
-
pbr: true,
|
|
7304
|
-
seed: true,
|
|
7305
|
-
textureRef: false,
|
|
7306
|
-
resolutions: null
|
|
7307
|
-
},
|
|
7308
|
-
rodin: {
|
|
7309
|
-
textPath: true,
|
|
7310
|
-
views: ["none", "unordered"],
|
|
7311
|
-
multiImage: false,
|
|
7312
|
-
texture: null,
|
|
7313
|
-
pbr: false,
|
|
7314
|
-
seed: true,
|
|
7315
|
-
textureRef: false,
|
|
7316
|
-
resolutions: null
|
|
7317
|
-
},
|
|
7318
|
-
meshy: {
|
|
7319
|
-
textPath: true,
|
|
7320
|
-
views: ["none", "unordered"],
|
|
7321
|
-
multiImage: true,
|
|
7322
|
-
texture: ["none", "standard"],
|
|
7323
|
-
pbr: true,
|
|
7324
|
-
seed: true,
|
|
7325
|
-
textureRef: true,
|
|
7326
|
-
resolutions: null
|
|
7327
|
-
},
|
|
7328
|
-
hi3d: {
|
|
7329
|
-
textPath: false,
|
|
7330
|
-
views: ["none", "named"],
|
|
7331
|
-
multiImage: true,
|
|
7332
|
-
texture: ["none", "standard"],
|
|
7333
|
-
pbr: true,
|
|
7334
|
-
seed: false,
|
|
7335
|
-
textureRef: false,
|
|
7336
|
-
resolutions: ["quality", "master"]
|
|
7337
|
-
},
|
|
7338
|
-
sam: {
|
|
7339
|
-
textPath: false,
|
|
7340
|
-
views: ["none"],
|
|
7341
|
-
multiImage: false,
|
|
7342
|
-
texture: null,
|
|
7343
|
-
pbr: false,
|
|
7344
|
-
seed: true,
|
|
7345
|
-
textureRef: false,
|
|
7346
|
-
resolutions: null
|
|
7347
|
-
}
|
|
7348
|
-
};
|
|
7349
|
-
function model3dSpecIssues(spec) {
|
|
7350
|
-
const issues = [];
|
|
7351
|
-
const add = (path, message) => issues.push({ path, message });
|
|
7352
|
-
const rules = MODEL3D_FAMILY_RULES[spec.family];
|
|
7353
|
-
const promptOnly = spec.text && !spec.imageRequired;
|
|
7354
|
-
if (spec.endpoints.image === void 0)
|
|
7355
|
-
add(["endpoints", "image"], "every row needs an image endpoint");
|
|
7356
|
-
if (promptOnly && !rules.textPath) {
|
|
7357
|
-
add(
|
|
7358
|
-
["imageRequired"],
|
|
7359
|
-
`${spec.family} has no text-to-3D endpoint; a text row needs an image`
|
|
7360
|
-
);
|
|
7361
|
-
}
|
|
7362
|
-
if (promptOnly && spec.endpoints.text === void 0) {
|
|
7363
|
-
add(["endpoints", "text"], "a text row needs a text endpoint");
|
|
7364
|
-
}
|
|
7365
|
-
if (!rules.views.includes(spec.views)) {
|
|
7366
|
-
add(["views"], `${spec.family} takes views ${rules.views.join(" or ")}`);
|
|
7367
|
-
}
|
|
7368
|
-
if (spec.views === "none" && spec.maxImages !== 1) {
|
|
7369
|
-
add(["maxImages"], "a row without views takes 1 image");
|
|
7370
|
-
}
|
|
7371
|
-
if (spec.views === "unordered" && spec.maxImages < 2) {
|
|
7372
|
-
add(["maxImages"], "a row with views takes at least 2 images");
|
|
7373
|
-
}
|
|
7374
|
-
const slots = MODEL3D_IMAGE_SLOTS[spec.views].length;
|
|
7375
|
-
if (spec.views !== "none" && spec.maxImages > slots) {
|
|
7376
|
-
add(["maxImages"], `a row with ${spec.views} views sends at most ${slots} images`);
|
|
7377
|
-
}
|
|
7378
|
-
if ((spec.views === "named" || spec.views === "ordered") && spec.maxImages < slots) {
|
|
7379
|
-
add(
|
|
7380
|
-
["maxImages"],
|
|
7381
|
-
`a row with ${spec.views} views takes ${slots} images (front and three sides)`
|
|
7382
|
-
);
|
|
7383
|
-
}
|
|
7384
|
-
if (spec.views !== "none" && rules.multiImage && spec.endpoints.multiImage === void 0) {
|
|
7385
|
-
add(["endpoints", "multiImage"], `${spec.family} sends views to a multi-image endpoint`);
|
|
7386
|
-
}
|
|
7387
|
-
if (rules.texture === null) {
|
|
7388
|
-
if (spec.texture.length > 0) add(["texture"], `${spec.family} has no texture switch`);
|
|
7389
|
-
} else {
|
|
7390
|
-
const allowed = rules.texture;
|
|
7391
|
-
if (spec.texture.length === 0) add(["texture"], `${spec.family} needs its texture options`);
|
|
7392
|
-
if (new Set(spec.texture).size !== spec.texture.length)
|
|
7393
|
-
add(["texture"], "texture options repeat");
|
|
7394
|
-
for (const t of spec.texture) {
|
|
7395
|
-
if (!allowed.includes(t)) add(["texture"], `${spec.family} has no "${t}" texture`);
|
|
7396
|
-
}
|
|
7397
|
-
}
|
|
7398
|
-
if (spec.pbr && !rules.pbr) add(["pbr"], `${spec.family} has no PBR switch`);
|
|
7399
|
-
if (spec.pbr && !spec.texture.some((t) => t !== "none")) {
|
|
7400
|
-
add(["pbr"], "PBR needs a textured option");
|
|
7401
|
-
}
|
|
7402
|
-
if (spec.seed && !rules.seed) add(["seed"], `${spec.family} takes no seed`);
|
|
7403
|
-
if (spec.seedMax !== void 0 && !spec.seed) add(["seedMax"], "seedMax needs seed");
|
|
7404
|
-
if (spec.textureRef && !rules.textureRef)
|
|
7405
|
-
add(["textureRef"], `${spec.family} takes no texture reference`);
|
|
7406
|
-
const res = spec.resolutions;
|
|
7407
|
-
if (rules.resolutions === null) {
|
|
7408
|
-
if (res !== void 0) add(["resolutions"], `${spec.family} has no resolution option`);
|
|
7409
|
-
} else if (res === void 0) {
|
|
7410
|
-
add(["resolutions"], `${spec.family} needs its resolution options`);
|
|
7411
|
-
} else {
|
|
7412
|
-
if (!res.options.includes(res.default)) {
|
|
7413
|
-
add(["resolutions", "default"], "default must be an option");
|
|
7414
|
-
}
|
|
7415
|
-
if (new Set(res.options).size !== res.options.length) {
|
|
7416
|
-
add(["resolutions", "options"], "resolution options repeat");
|
|
7417
|
-
}
|
|
7418
|
-
const allowed = rules.resolutions;
|
|
7419
|
-
for (const option of res.options) {
|
|
7420
|
-
const ok = allowed === "integer" ? /^[1-9][0-9]*$/.test(option) : allowed.includes(option);
|
|
7421
|
-
if (!ok)
|
|
7422
|
-
add(["resolutions", "options"], `${spec.family} has no "${option}" resolution`);
|
|
7423
|
-
}
|
|
7424
|
-
}
|
|
7425
|
-
return issues;
|
|
7426
|
-
}
|
|
7427
7432
|
var VideoToolConstraintsSchema = import_zod3.z.looseObject({
|
|
7428
7433
|
kind: import_zod3.z.enum(["upscale", "interpolate", "hdr", "bg-remove", "subtitles"]),
|
|
7429
7434
|
upscaleFactor: RangeSchema.optional(),
|
|
@@ -10825,6 +10830,19 @@ function specOf(ctx) {
|
|
|
10825
10830
|
return spec;
|
|
10826
10831
|
}
|
|
10827
10832
|
var present = (v) => v !== void 0 && v.length > 0;
|
|
10833
|
+
function wireValue(row2, values, option, what) {
|
|
10834
|
+
const value = option !== void 0 && Object.hasOwn(values, option) ? values[option] : void 0;
|
|
10835
|
+
if (value === void 0) {
|
|
10836
|
+
throw new ModelKitError({
|
|
10837
|
+
code: "unsupported_option",
|
|
10838
|
+
message: `${row2.id} has no ${what} "${option ?? ""}" to send`,
|
|
10839
|
+
provider: "fal",
|
|
10840
|
+
model: row2.id,
|
|
10841
|
+
retryable: false
|
|
10842
|
+
});
|
|
10843
|
+
}
|
|
10844
|
+
return value;
|
|
10845
|
+
}
|
|
10828
10846
|
function model3dCall(row2, spec, req) {
|
|
10829
10847
|
const prompt = req.prompt?.trim() || void 0;
|
|
10830
10848
|
const texture = model3dTexture(spec, req.texture);
|
|
@@ -10868,7 +10886,15 @@ function model3dCall(row2, spec, req) {
|
|
|
10868
10886
|
}
|
|
10869
10887
|
};
|
|
10870
10888
|
case "hunyuan": {
|
|
10871
|
-
const opts = {
|
|
10889
|
+
const opts = {
|
|
10890
|
+
generate_type: wireValue(
|
|
10891
|
+
row2,
|
|
10892
|
+
MODEL3D_FAMILY_RULES.hunyuan.texture,
|
|
10893
|
+
texture,
|
|
10894
|
+
"texture"
|
|
10895
|
+
),
|
|
10896
|
+
enable_pbr: pbr
|
|
10897
|
+
};
|
|
10872
10898
|
if (!present(req.image)) {
|
|
10873
10899
|
return {
|
|
10874
10900
|
endpoint: endpoint(spec.endpoints.text),
|
|
@@ -10887,12 +10913,11 @@ function model3dCall(row2, spec, req) {
|
|
|
10887
10913
|
};
|
|
10888
10914
|
}
|
|
10889
10915
|
case "tripo": {
|
|
10916
|
+
const quality = wireValue(row2, MODEL3D_FAMILY_RULES.tripo.texture, texture, "texture");
|
|
10890
10917
|
const opts = {
|
|
10891
10918
|
texture: textured,
|
|
10892
10919
|
pbr,
|
|
10893
|
-
...
|
|
10894
|
-
texture_quality: texture === "detailed" ? "detailed" : "standard"
|
|
10895
|
-
},
|
|
10920
|
+
...quality !== null && { texture_quality: quality },
|
|
10896
10921
|
...seed !== void 0 && { model_seed: seed }
|
|
10897
10922
|
};
|
|
10898
10923
|
if (!present(req.image)) {
|
|
@@ -10928,6 +10953,7 @@ function model3dCall(row2, spec, req) {
|
|
|
10928
10953
|
};
|
|
10929
10954
|
}
|
|
10930
10955
|
case "meshy": {
|
|
10956
|
+
const mode = wireValue(row2, MODEL3D_FAMILY_RULES.meshy.texture, texture, "texture");
|
|
10931
10957
|
const texturePrompt = req.texturePrompt?.trim() || void 0;
|
|
10932
10958
|
const opts = {
|
|
10933
10959
|
enable_pbr: pbr,
|
|
@@ -10939,7 +10965,7 @@ function model3dCall(row2, spec, req) {
|
|
|
10939
10965
|
endpoint: endpoint(spec.endpoints.text),
|
|
10940
10966
|
input: {
|
|
10941
10967
|
prompt: prompt ?? "",
|
|
10942
|
-
mode
|
|
10968
|
+
mode,
|
|
10943
10969
|
...opts,
|
|
10944
10970
|
...seed !== void 0 && { seed }
|
|
10945
10971
|
}
|
|
@@ -10955,8 +10981,18 @@ function model3dCall(row2, spec, req) {
|
|
|
10955
10981
|
}
|
|
10956
10982
|
case "hi3d": {
|
|
10957
10983
|
const opts = {
|
|
10958
|
-
resolution:
|
|
10959
|
-
|
|
10984
|
+
resolution: wireValue(
|
|
10985
|
+
row2,
|
|
10986
|
+
MODEL3D_FAMILY_RULES.hi3d.resolutions,
|
|
10987
|
+
resolution,
|
|
10988
|
+
"resolution"
|
|
10989
|
+
),
|
|
10990
|
+
enable_texture: wireValue(
|
|
10991
|
+
row2,
|
|
10992
|
+
MODEL3D_FAMILY_RULES.hi3d.texture,
|
|
10993
|
+
texture,
|
|
10994
|
+
"texture"
|
|
10995
|
+
),
|
|
10960
10996
|
enable_pbr: pbr,
|
|
10961
10997
|
export_format: "glb"
|
|
10962
10998
|
};
|
|
@@ -13808,24 +13844,24 @@ var import_zod25 = require("zod");
|
|
|
13808
13844
|
function mp4DurationSeconds(bytes) {
|
|
13809
13845
|
const moov = findBox(bytes, 0, bytes.length, "moov");
|
|
13810
13846
|
if (!moov) return void 0;
|
|
13811
|
-
const mvhd = findBox(bytes, moov.
|
|
13847
|
+
const mvhd = findBox(bytes, moov.body, moov.end, "mvhd");
|
|
13812
13848
|
if (!mvhd) return void 0;
|
|
13813
13849
|
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
13814
|
-
const size = mvhd.end - mvhd.
|
|
13815
|
-
if (size <
|
|
13816
|
-
const version = view.getUint8(mvhd.
|
|
13850
|
+
const size = mvhd.end - mvhd.body;
|
|
13851
|
+
if (size < 4) return void 0;
|
|
13852
|
+
const version = view.getUint8(mvhd.body);
|
|
13817
13853
|
if (version === 0) {
|
|
13818
|
-
if (size <
|
|
13819
|
-
const timescale = view.getUint32(mvhd.
|
|
13820
|
-
const duration = view.getUint32(mvhd.
|
|
13854
|
+
if (size < 4 + 4 + 4 + 4 + 4) return void 0;
|
|
13855
|
+
const timescale = view.getUint32(mvhd.body + 4 + 4 + 4);
|
|
13856
|
+
const duration = view.getUint32(mvhd.body + 4 + 4 + 4 + 4);
|
|
13821
13857
|
if (timescale === 0) return void 0;
|
|
13822
13858
|
return duration / timescale;
|
|
13823
13859
|
}
|
|
13824
13860
|
if (version === 1) {
|
|
13825
|
-
if (size <
|
|
13826
|
-
const timescale = view.getUint32(mvhd.
|
|
13827
|
-
const high = view.getUint32(mvhd.
|
|
13828
|
-
const low = view.getUint32(mvhd.
|
|
13861
|
+
if (size < 4 + 8 + 8 + 4 + 8) return void 0;
|
|
13862
|
+
const timescale = view.getUint32(mvhd.body + 4 + 8 + 8);
|
|
13863
|
+
const high = view.getUint32(mvhd.body + 4 + 8 + 8 + 4);
|
|
13864
|
+
const low = view.getUint32(mvhd.body + 4 + 8 + 8 + 4 + 4);
|
|
13829
13865
|
if (timescale === 0) return void 0;
|
|
13830
13866
|
return (high * 2 ** 32 + low) / timescale;
|
|
13831
13867
|
}
|
|
@@ -13835,15 +13871,23 @@ function findBox(bytes, from, to, type) {
|
|
|
13835
13871
|
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
13836
13872
|
let offset = from;
|
|
13837
13873
|
while (offset + 8 <= to) {
|
|
13838
|
-
|
|
13874
|
+
let size = view.getUint32(offset);
|
|
13875
|
+
let header = 8;
|
|
13839
13876
|
const name = String.fromCharCode(
|
|
13840
13877
|
view.getUint8(offset + 4),
|
|
13841
13878
|
view.getUint8(offset + 5),
|
|
13842
13879
|
view.getUint8(offset + 6),
|
|
13843
13880
|
view.getUint8(offset + 7)
|
|
13844
13881
|
);
|
|
13845
|
-
if (size
|
|
13846
|
-
|
|
13882
|
+
if (size === 1) {
|
|
13883
|
+
if (offset + 16 > to) return void 0;
|
|
13884
|
+
size = view.getUint32(offset + 8) * 2 ** 32 + view.getUint32(offset + 12);
|
|
13885
|
+
header = 16;
|
|
13886
|
+
} else if (size === 0) {
|
|
13887
|
+
size = to - offset;
|
|
13888
|
+
}
|
|
13889
|
+
if (size < header || offset + size > to) return void 0;
|
|
13890
|
+
if (name === type) return { body: offset + header, end: offset + size };
|
|
13847
13891
|
offset += size;
|
|
13848
13892
|
}
|
|
13849
13893
|
return void 0;
|
|
@@ -13856,6 +13900,7 @@ var IMAGE_TIMEOUT_MS = 5 * 6e4;
|
|
|
13856
13900
|
var VIDEO_POLL_INTERVAL_MS = 5e3;
|
|
13857
13901
|
var VIDEO_TIMEOUT_MS = 20 * 6e4;
|
|
13858
13902
|
var PROMPT_MAX_CHARS = 6e3;
|
|
13903
|
+
var OUTPUT_URL_TTL_MS = 55 * 6e4;
|
|
13859
13904
|
var LUMA_IMAGE_MODEL_IDS = /* @__PURE__ */ new Set(["uni-1", "uni-1-max"]);
|
|
13860
13905
|
var LUMA_VIDEO_MODEL_ID = "ray-3.2";
|
|
13861
13906
|
var LUMA_VIDEO_MODES = /* @__PURE__ */ new Map([
|
|
@@ -13874,6 +13919,9 @@ function lumaRowRefusal(row2) {
|
|
|
13874
13919
|
}
|
|
13875
13920
|
return `luma has no ${row2.type} rows`;
|
|
13876
13921
|
}
|
|
13922
|
+
function lumaModel(ctx) {
|
|
13923
|
+
return ctx.model.providerModelId.toLowerCase();
|
|
13924
|
+
}
|
|
13877
13925
|
function lumaBase(ctx) {
|
|
13878
13926
|
return ctx.endpoints?.luma ?? DEFAULT_BASE_URL;
|
|
13879
13927
|
}
|
|
@@ -13916,8 +13964,23 @@ function imageRef(ref) {
|
|
|
13916
13964
|
if ("url" in ref) return { url: ref.url };
|
|
13917
13965
|
return { data: mediaRefToBase64(ref.bytes), media_type: ref.mime };
|
|
13918
13966
|
}
|
|
13967
|
+
var VIDEO_TYPES_BY_EXTENSION = /* @__PURE__ */ new Map([
|
|
13968
|
+
["mp4", "video/mp4"],
|
|
13969
|
+
["m4v", "video/mp4"],
|
|
13970
|
+
["mov", "video/quicktime"],
|
|
13971
|
+
["webm", "video/webm"]
|
|
13972
|
+
]);
|
|
13973
|
+
function videoUrlType(url) {
|
|
13974
|
+
let path = url;
|
|
13975
|
+
try {
|
|
13976
|
+
path = new URL(url).pathname;
|
|
13977
|
+
} catch {
|
|
13978
|
+
}
|
|
13979
|
+
const extension = path.slice(path.lastIndexOf(".") + 1).toLowerCase();
|
|
13980
|
+
return VIDEO_TYPES_BY_EXTENSION.get(extension) ?? "video/mp4";
|
|
13981
|
+
}
|
|
13919
13982
|
function videoRef(ref) {
|
|
13920
|
-
if ("url" in ref) return { url: ref.url, media_type:
|
|
13983
|
+
if ("url" in ref) return { url: ref.url, media_type: videoUrlType(ref.url) };
|
|
13921
13984
|
const mediaType = ref.mime.startsWith("video/") ? ref.mime : "video/mp4";
|
|
13922
13985
|
return { data: mediaRefToBase64(ref.bytes), media_type: mediaType };
|
|
13923
13986
|
}
|
|
@@ -14081,14 +14144,22 @@ async function lumaRequest(ctx, url, body) {
|
|
|
14081
14144
|
}
|
|
14082
14145
|
return res;
|
|
14083
14146
|
}
|
|
14147
|
+
async function parseGeneration(res) {
|
|
14148
|
+
try {
|
|
14149
|
+
const parsed = lumaGenerationSchema.safeParse(await res.json());
|
|
14150
|
+
return parsed.success ? parsed.data : void 0;
|
|
14151
|
+
} catch {
|
|
14152
|
+
return "not_json";
|
|
14153
|
+
}
|
|
14154
|
+
}
|
|
14084
14155
|
async function submitGeneration(ctx, body) {
|
|
14085
14156
|
const retryOptions = mediaRetryOptions(ctx.call, ctx.signal);
|
|
14086
14157
|
const res = await withRetry(
|
|
14087
14158
|
() => lumaRequest(ctx, `${lumaBase(ctx)}/v1/generations`, JSON.stringify(body)),
|
|
14088
14159
|
retryOptions
|
|
14089
14160
|
);
|
|
14090
|
-
const
|
|
14091
|
-
if (
|
|
14161
|
+
const generation = await parseGeneration(res);
|
|
14162
|
+
if (generation === void 0 || generation === "not_json") {
|
|
14092
14163
|
throw new ModelKitError({
|
|
14093
14164
|
code: "provider_rejected",
|
|
14094
14165
|
message: "Luma submit returned no generation id",
|
|
@@ -14097,13 +14168,20 @@ async function submitGeneration(ctx, body) {
|
|
|
14097
14168
|
retryable: false
|
|
14098
14169
|
});
|
|
14099
14170
|
}
|
|
14100
|
-
return
|
|
14171
|
+
return generation;
|
|
14101
14172
|
}
|
|
14102
14173
|
async function readGeneration(ctx, id) {
|
|
14103
14174
|
const res = await lumaRequest(ctx, `${lumaBase(ctx)}/v1/generations/${id}`);
|
|
14104
|
-
const
|
|
14105
|
-
|
|
14106
|
-
|
|
14175
|
+
const generation = await parseGeneration(res);
|
|
14176
|
+
if (generation === "not_json") {
|
|
14177
|
+
throw new ModelKitError({
|
|
14178
|
+
code: "network",
|
|
14179
|
+
message: "Luma returned a poll response that is not JSON",
|
|
14180
|
+
provider: "luma",
|
|
14181
|
+
model: ctx.model.id
|
|
14182
|
+
});
|
|
14183
|
+
}
|
|
14184
|
+
if (generation === void 0) {
|
|
14107
14185
|
throw new ModelKitError({
|
|
14108
14186
|
code: "provider_rejected",
|
|
14109
14187
|
message: "Luma returned an unreadable generation",
|
|
@@ -14112,14 +14190,12 @@ async function readGeneration(ctx, id) {
|
|
|
14112
14190
|
retryable: false
|
|
14113
14191
|
});
|
|
14114
14192
|
}
|
|
14115
|
-
return
|
|
14193
|
+
return generation;
|
|
14116
14194
|
}
|
|
14117
14195
|
function outputUrl(generation, type) {
|
|
14118
14196
|
const outputs = generation.output ?? [];
|
|
14119
|
-
const match = outputs.find((item) => item.type === type && item.url);
|
|
14120
|
-
|
|
14121
|
-
const fallback = outputs.find((item) => item.url);
|
|
14122
|
-
return fallback?.url;
|
|
14197
|
+
const match = outputs.find((item) => item.type === type && item.url) ?? outputs.find((item) => item.type === void 0 && item.url);
|
|
14198
|
+
return match?.url;
|
|
14123
14199
|
}
|
|
14124
14200
|
async function readGenerationOnce(ctx, id) {
|
|
14125
14201
|
try {
|
|
@@ -14158,21 +14234,22 @@ async function checkGeneration(ctx, id, type) {
|
|
|
14158
14234
|
return void 0;
|
|
14159
14235
|
}
|
|
14160
14236
|
async function downloadBytes(ctx, url, fallback) {
|
|
14161
|
-
|
|
14162
|
-
|
|
14163
|
-
|
|
14164
|
-
|
|
14165
|
-
|
|
14166
|
-
|
|
14167
|
-
|
|
14168
|
-
|
|
14169
|
-
|
|
14170
|
-
|
|
14171
|
-
|
|
14172
|
-
|
|
14173
|
-
|
|
14237
|
+
const { bytes, mime: header } = await withRetry(
|
|
14238
|
+
async () => {
|
|
14239
|
+
try {
|
|
14240
|
+
return await mediaRefToBytes({ url }, ctx.fetch, {
|
|
14241
|
+
...ctx.signal !== void 0 && { signal: ctx.signal },
|
|
14242
|
+
provider: "luma",
|
|
14243
|
+
model: ctx.model.id
|
|
14244
|
+
});
|
|
14245
|
+
} catch (cause) {
|
|
14246
|
+
throw classifyThrown("luma", cause, ctx.model.id);
|
|
14247
|
+
}
|
|
14248
|
+
},
|
|
14249
|
+
mediaRetryOptions(ctx.call, ctx.signal)
|
|
14250
|
+
);
|
|
14174
14251
|
const kind = fallback.split("/")[0];
|
|
14175
|
-
const usable = header
|
|
14252
|
+
const usable = header.startsWith(`${kind}/`);
|
|
14176
14253
|
return { bytes, mime: usable ? header : fallback };
|
|
14177
14254
|
}
|
|
14178
14255
|
function imageUsage2(ctx) {
|
|
@@ -14187,15 +14264,12 @@ function imageUsage2(ctx) {
|
|
|
14187
14264
|
}
|
|
14188
14265
|
var GENERATE_SECONDS = 5;
|
|
14189
14266
|
var MAX_PLAUSIBLE_SECONDS = 60;
|
|
14190
|
-
function
|
|
14191
|
-
if (mode === "generate") return GENERATE_SECONDS;
|
|
14267
|
+
function editedSeconds(req, bytes) {
|
|
14192
14268
|
const measured = mp4DurationSeconds(bytes);
|
|
14193
|
-
const
|
|
14194
|
-
const length = measured !== void 0 && measured > 0 && measured <= MAX_PLAUSIBLE_SECONDS ? measured : source2 !== void 0 && "url" in source2 ? source2.durationSeconds : void 0;
|
|
14269
|
+
const length = measured !== void 0 && measured > 0 && measured <= MAX_PLAUSIBLE_SECONDS ? measured : req.sourceVideo?.durationSeconds;
|
|
14195
14270
|
return Math.max(length ?? 0, GENERATE_SECONDS);
|
|
14196
14271
|
}
|
|
14197
|
-
function videoUsage4(ctx, req, mode,
|
|
14198
|
-
const seconds3 = billedSeconds(req, mode, bytes);
|
|
14272
|
+
function videoUsage4(ctx, req, mode, seconds3) {
|
|
14199
14273
|
const event = {
|
|
14200
14274
|
model: ctx.model.id,
|
|
14201
14275
|
provider: "luma",
|
|
@@ -14210,7 +14284,7 @@ function videoUsage4(ctx, req, mode, bytes) {
|
|
|
14210
14284
|
}
|
|
14211
14285
|
function imageBody(req, ctx, outputFormat) {
|
|
14212
14286
|
const prompt = checkPrompt(req, ctx);
|
|
14213
|
-
const model = ctx
|
|
14287
|
+
const model = lumaModel(ctx);
|
|
14214
14288
|
const ratio = req.aspectRatio !== "adaptive" ? req.aspectRatio : void 0;
|
|
14215
14289
|
const [source2, ...rest] = req.references ?? [];
|
|
14216
14290
|
if (source2 === void 0) {
|
|
@@ -14238,7 +14312,7 @@ function imageBody(req, ctx, outputFormat) {
|
|
|
14238
14312
|
}
|
|
14239
14313
|
function videoBody(req, ctx, mode) {
|
|
14240
14314
|
const prompt = checkPrompt(req, ctx);
|
|
14241
|
-
const model = ctx
|
|
14315
|
+
const model = lumaModel(ctx);
|
|
14242
14316
|
const hasReferences = (req.referenceImages ?? []).length + (req.referenceVideos ?? []).length + (req.referenceAudios ?? []).length > 0;
|
|
14243
14317
|
if (hasReferences) {
|
|
14244
14318
|
refuseOrDrop(
|
|
@@ -14320,7 +14394,7 @@ function videoBody(req, ctx, mode) {
|
|
|
14320
14394
|
async function generateLumaImage(req, ctx) {
|
|
14321
14395
|
throwIfAborted(ctx.signal);
|
|
14322
14396
|
lumaKey(ctx);
|
|
14323
|
-
if (!LUMA_IMAGE_MODEL_IDS.has(ctx
|
|
14397
|
+
if (!LUMA_IMAGE_MODEL_IDS.has(lumaModel(ctx))) {
|
|
14324
14398
|
throw new ModelKitError({
|
|
14325
14399
|
code: "unsupported_option",
|
|
14326
14400
|
message: `luma has no image mapping for "${ctx.model.providerModelId}"`,
|
|
@@ -14353,16 +14427,25 @@ function lumaVideoJob(ctx, req, mode, id) {
|
|
|
14353
14427
|
return { status: "pending" };
|
|
14354
14428
|
},
|
|
14355
14429
|
async result(opts) {
|
|
14356
|
-
const signal = opts?.signal
|
|
14357
|
-
const
|
|
14430
|
+
const signal = combineSignals(ctx.signal, opts?.signal);
|
|
14431
|
+
const jobCtx = { ...ctx, ...signal !== void 0 && { signal } };
|
|
14432
|
+
const url = await pollUntil(checkGeneration.bind(null, jobCtx, id, "video"), {
|
|
14358
14433
|
intervalMs: opts?.pollIntervalMs ?? VIDEO_POLL_INTERVAL_MS,
|
|
14359
14434
|
timeoutMs: opts?.timeoutMs ?? VIDEO_TIMEOUT_MS,
|
|
14360
14435
|
...signal !== void 0 && { signal }
|
|
14361
14436
|
});
|
|
14362
|
-
|
|
14437
|
+
if (mode === "generate") {
|
|
14438
|
+
const result2 = {
|
|
14439
|
+
video: { url, expiresAt: new Date(Date.now() + OUTPUT_URL_TTL_MS) },
|
|
14440
|
+
usage: videoUsage4(jobCtx, req, mode, GENERATE_SECONDS),
|
|
14441
|
+
raw: { id }
|
|
14442
|
+
};
|
|
14443
|
+
return result2;
|
|
14444
|
+
}
|
|
14445
|
+
const video = await downloadBytes(jobCtx, url, "video/mp4");
|
|
14363
14446
|
const result = {
|
|
14364
14447
|
video,
|
|
14365
|
-
usage: videoUsage4(
|
|
14448
|
+
usage: videoUsage4(jobCtx, req, mode, editedSeconds(req, video.bytes)),
|
|
14366
14449
|
raw: { id }
|
|
14367
14450
|
};
|
|
14368
14451
|
return result;
|
|
@@ -14372,7 +14455,7 @@ function lumaVideoJob(ctx, req, mode, id) {
|
|
|
14372
14455
|
async function generateLumaVideo(req, ctx) {
|
|
14373
14456
|
throwIfAborted(ctx.signal);
|
|
14374
14457
|
lumaKey(ctx);
|
|
14375
|
-
if (ctx
|
|
14458
|
+
if (lumaModel(ctx) !== LUMA_VIDEO_MODEL_ID) {
|
|
14376
14459
|
throw new ModelKitError({
|
|
14377
14460
|
code: "unsupported_option",
|
|
14378
14461
|
message: `luma has no video mapping for "${ctx.model.providerModelId}"`,
|