@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.js
CHANGED
|
@@ -6549,6 +6549,161 @@ var MODEL3D_IMAGE_SLOTS = {
|
|
|
6549
6549
|
ordered: ["image", "left", "back", "right"],
|
|
6550
6550
|
unordered: ["image", "back", "left", "right", "top"]
|
|
6551
6551
|
};
|
|
6552
|
+
var MODEL3D_FAMILY_RULES = {
|
|
6553
|
+
trellis: {
|
|
6554
|
+
textPath: false,
|
|
6555
|
+
views: ["none"],
|
|
6556
|
+
multiImage: false,
|
|
6557
|
+
texture: null,
|
|
6558
|
+
pbr: false,
|
|
6559
|
+
seed: true,
|
|
6560
|
+
textureRef: false,
|
|
6561
|
+
resolutions: "integer"
|
|
6562
|
+
},
|
|
6563
|
+
hunyuan: {
|
|
6564
|
+
textPath: true,
|
|
6565
|
+
views: ["none", "named"],
|
|
6566
|
+
multiImage: false,
|
|
6567
|
+
// generate_type
|
|
6568
|
+
texture: { none: "Geometry", standard: "Normal" },
|
|
6569
|
+
pbr: true,
|
|
6570
|
+
seed: false,
|
|
6571
|
+
textureRef: false,
|
|
6572
|
+
resolutions: null
|
|
6573
|
+
},
|
|
6574
|
+
tripo: {
|
|
6575
|
+
textPath: true,
|
|
6576
|
+
views: ["none", "ordered"],
|
|
6577
|
+
multiImage: true,
|
|
6578
|
+
// texture_quality; null sends an untextured model.
|
|
6579
|
+
texture: { none: null, standard: "standard", detailed: "detailed" },
|
|
6580
|
+
pbr: true,
|
|
6581
|
+
seed: true,
|
|
6582
|
+
textureRef: false,
|
|
6583
|
+
resolutions: null
|
|
6584
|
+
},
|
|
6585
|
+
rodin: {
|
|
6586
|
+
textPath: true,
|
|
6587
|
+
views: ["none", "unordered"],
|
|
6588
|
+
multiImage: false,
|
|
6589
|
+
texture: null,
|
|
6590
|
+
pbr: false,
|
|
6591
|
+
seed: true,
|
|
6592
|
+
textureRef: false,
|
|
6593
|
+
resolutions: null
|
|
6594
|
+
},
|
|
6595
|
+
meshy: {
|
|
6596
|
+
textPath: true,
|
|
6597
|
+
views: ["none", "unordered"],
|
|
6598
|
+
multiImage: true,
|
|
6599
|
+
// The text endpoint's mode; the image endpoints take should_texture.
|
|
6600
|
+
texture: { none: "preview", standard: "full" },
|
|
6601
|
+
pbr: true,
|
|
6602
|
+
seed: true,
|
|
6603
|
+
textureRef: true,
|
|
6604
|
+
resolutions: null
|
|
6605
|
+
},
|
|
6606
|
+
hi3d: {
|
|
6607
|
+
textPath: false,
|
|
6608
|
+
views: ["none", "named"],
|
|
6609
|
+
multiImage: true,
|
|
6610
|
+
// enable_texture
|
|
6611
|
+
texture: { none: false, standard: true },
|
|
6612
|
+
pbr: true,
|
|
6613
|
+
seed: false,
|
|
6614
|
+
textureRef: false,
|
|
6615
|
+
resolutions: { quality: "2048quality", master: "2048master" }
|
|
6616
|
+
},
|
|
6617
|
+
sam: {
|
|
6618
|
+
textPath: false,
|
|
6619
|
+
views: ["none"],
|
|
6620
|
+
multiImage: false,
|
|
6621
|
+
texture: null,
|
|
6622
|
+
pbr: false,
|
|
6623
|
+
seed: true,
|
|
6624
|
+
textureRef: false,
|
|
6625
|
+
resolutions: null
|
|
6626
|
+
}
|
|
6627
|
+
};
|
|
6628
|
+
function model3dSpecIssues(spec) {
|
|
6629
|
+
const issues = [];
|
|
6630
|
+
const add = (path, message) => issues.push({ path, message });
|
|
6631
|
+
const rules = MODEL3D_FAMILY_RULES[spec.family];
|
|
6632
|
+
const promptOnly = spec.text && !spec.imageRequired;
|
|
6633
|
+
if (spec.endpoints.image === void 0)
|
|
6634
|
+
add(["endpoints", "image"], "every row needs an image endpoint");
|
|
6635
|
+
if (promptOnly && !rules.textPath) {
|
|
6636
|
+
add(
|
|
6637
|
+
["imageRequired"],
|
|
6638
|
+
`${spec.family} has no text-to-3D endpoint; a text row needs an image`
|
|
6639
|
+
);
|
|
6640
|
+
}
|
|
6641
|
+
if (promptOnly && spec.endpoints.text === void 0) {
|
|
6642
|
+
add(["endpoints", "text"], "a text row needs a text endpoint");
|
|
6643
|
+
}
|
|
6644
|
+
if (!rules.views.includes(spec.views)) {
|
|
6645
|
+
add(["views"], `${spec.family} takes views ${rules.views.join(" or ")}`);
|
|
6646
|
+
}
|
|
6647
|
+
if (spec.views === "none" && spec.maxImages !== 1) {
|
|
6648
|
+
add(["maxImages"], "a row without views takes 1 image");
|
|
6649
|
+
}
|
|
6650
|
+
if (spec.views === "unordered" && spec.maxImages < 2) {
|
|
6651
|
+
add(["maxImages"], "a row with views takes at least 2 images");
|
|
6652
|
+
}
|
|
6653
|
+
const slots = MODEL3D_IMAGE_SLOTS[spec.views].length;
|
|
6654
|
+
if (spec.views !== "none" && spec.maxImages > slots) {
|
|
6655
|
+
add(["maxImages"], `a row with ${spec.views} views sends at most ${slots} images`);
|
|
6656
|
+
}
|
|
6657
|
+
if ((spec.views === "named" || spec.views === "ordered") && spec.maxImages < slots) {
|
|
6658
|
+
add(
|
|
6659
|
+
["maxImages"],
|
|
6660
|
+
`a row with ${spec.views} views takes ${slots} images (front and three sides)`
|
|
6661
|
+
);
|
|
6662
|
+
}
|
|
6663
|
+
if (spec.views !== "none" && rules.multiImage && spec.endpoints.multiImage === void 0) {
|
|
6664
|
+
add(["endpoints", "multiImage"], `${spec.family} sends views to a multi-image endpoint`);
|
|
6665
|
+
}
|
|
6666
|
+
if (rules.texture === null) {
|
|
6667
|
+
if (spec.texture.length > 0) add(["texture"], `${spec.family} has no texture switch`);
|
|
6668
|
+
} else {
|
|
6669
|
+
const allowed = rules.texture;
|
|
6670
|
+
if (spec.texture.length === 0) add(["texture"], `${spec.family} needs its texture options`);
|
|
6671
|
+
if (new Set(spec.texture).size !== spec.texture.length)
|
|
6672
|
+
add(["texture"], "texture options repeat");
|
|
6673
|
+
for (const t of spec.texture) {
|
|
6674
|
+
if (!Object.hasOwn(allowed, t))
|
|
6675
|
+
add(["texture"], `${spec.family} has no "${t}" texture`);
|
|
6676
|
+
}
|
|
6677
|
+
}
|
|
6678
|
+
if (spec.pbr && !rules.pbr) add(["pbr"], `${spec.family} has no PBR switch`);
|
|
6679
|
+
if (spec.pbr && !spec.texture.some((t) => t !== "none")) {
|
|
6680
|
+
add(["pbr"], "PBR needs a textured option");
|
|
6681
|
+
}
|
|
6682
|
+
if (spec.seed && !rules.seed) add(["seed"], `${spec.family} takes no seed`);
|
|
6683
|
+
if (spec.seedMax !== void 0 && !spec.seed) add(["seedMax"], "seedMax needs seed");
|
|
6684
|
+
if (spec.textureRef && !rules.textureRef)
|
|
6685
|
+
add(["textureRef"], `${spec.family} takes no texture reference`);
|
|
6686
|
+
const res = spec.resolutions;
|
|
6687
|
+
if (rules.resolutions === null) {
|
|
6688
|
+
if (res !== void 0) add(["resolutions"], `${spec.family} has no resolution option`);
|
|
6689
|
+
} else if (res === void 0) {
|
|
6690
|
+
add(["resolutions"], `${spec.family} needs its resolution options`);
|
|
6691
|
+
} else {
|
|
6692
|
+
if (!res.options.includes(res.default)) {
|
|
6693
|
+
add(["resolutions", "default"], "default must be an option");
|
|
6694
|
+
}
|
|
6695
|
+
if (new Set(res.options).size !== res.options.length) {
|
|
6696
|
+
add(["resolutions", "options"], "resolution options repeat");
|
|
6697
|
+
}
|
|
6698
|
+
const allowed = rules.resolutions;
|
|
6699
|
+
for (const option of res.options) {
|
|
6700
|
+
const ok = allowed === "integer" ? /^[1-9][0-9]*$/.test(option) : Object.hasOwn(allowed, option);
|
|
6701
|
+
if (!ok)
|
|
6702
|
+
add(["resolutions", "options"], `${spec.family} has no "${option}" resolution`);
|
|
6703
|
+
}
|
|
6704
|
+
}
|
|
6705
|
+
return issues;
|
|
6706
|
+
}
|
|
6552
6707
|
function model3dInputRefusal(spec, wired) {
|
|
6553
6708
|
const top = spec.views === "unordered" && wired.top === true;
|
|
6554
6709
|
const anyView = spec.views !== "none" && (wired.back || wired.left || wired.right || top);
|
|
@@ -7136,156 +7291,6 @@ var LanguageOptionSchema = z3.looseObject({
|
|
|
7136
7291
|
code: z3.string().min(1),
|
|
7137
7292
|
name: z3.string().min(1)
|
|
7138
7293
|
});
|
|
7139
|
-
var MODEL3D_FAMILY_RULES = {
|
|
7140
|
-
trellis: {
|
|
7141
|
-
textPath: false,
|
|
7142
|
-
views: ["none"],
|
|
7143
|
-
multiImage: false,
|
|
7144
|
-
texture: null,
|
|
7145
|
-
pbr: false,
|
|
7146
|
-
seed: true,
|
|
7147
|
-
textureRef: false,
|
|
7148
|
-
resolutions: "integer"
|
|
7149
|
-
},
|
|
7150
|
-
hunyuan: {
|
|
7151
|
-
textPath: true,
|
|
7152
|
-
views: ["none", "named"],
|
|
7153
|
-
multiImage: false,
|
|
7154
|
-
texture: ["none", "standard"],
|
|
7155
|
-
pbr: true,
|
|
7156
|
-
seed: false,
|
|
7157
|
-
textureRef: false,
|
|
7158
|
-
resolutions: null
|
|
7159
|
-
},
|
|
7160
|
-
tripo: {
|
|
7161
|
-
textPath: true,
|
|
7162
|
-
views: ["none", "ordered"],
|
|
7163
|
-
multiImage: true,
|
|
7164
|
-
texture: ["none", "standard", "detailed"],
|
|
7165
|
-
pbr: true,
|
|
7166
|
-
seed: true,
|
|
7167
|
-
textureRef: false,
|
|
7168
|
-
resolutions: null
|
|
7169
|
-
},
|
|
7170
|
-
rodin: {
|
|
7171
|
-
textPath: true,
|
|
7172
|
-
views: ["none", "unordered"],
|
|
7173
|
-
multiImage: false,
|
|
7174
|
-
texture: null,
|
|
7175
|
-
pbr: false,
|
|
7176
|
-
seed: true,
|
|
7177
|
-
textureRef: false,
|
|
7178
|
-
resolutions: null
|
|
7179
|
-
},
|
|
7180
|
-
meshy: {
|
|
7181
|
-
textPath: true,
|
|
7182
|
-
views: ["none", "unordered"],
|
|
7183
|
-
multiImage: true,
|
|
7184
|
-
texture: ["none", "standard"],
|
|
7185
|
-
pbr: true,
|
|
7186
|
-
seed: true,
|
|
7187
|
-
textureRef: true,
|
|
7188
|
-
resolutions: null
|
|
7189
|
-
},
|
|
7190
|
-
hi3d: {
|
|
7191
|
-
textPath: false,
|
|
7192
|
-
views: ["none", "named"],
|
|
7193
|
-
multiImage: true,
|
|
7194
|
-
texture: ["none", "standard"],
|
|
7195
|
-
pbr: true,
|
|
7196
|
-
seed: false,
|
|
7197
|
-
textureRef: false,
|
|
7198
|
-
resolutions: ["quality", "master"]
|
|
7199
|
-
},
|
|
7200
|
-
sam: {
|
|
7201
|
-
textPath: false,
|
|
7202
|
-
views: ["none"],
|
|
7203
|
-
multiImage: false,
|
|
7204
|
-
texture: null,
|
|
7205
|
-
pbr: false,
|
|
7206
|
-
seed: true,
|
|
7207
|
-
textureRef: false,
|
|
7208
|
-
resolutions: null
|
|
7209
|
-
}
|
|
7210
|
-
};
|
|
7211
|
-
function model3dSpecIssues(spec) {
|
|
7212
|
-
const issues = [];
|
|
7213
|
-
const add = (path, message) => issues.push({ path, message });
|
|
7214
|
-
const rules = MODEL3D_FAMILY_RULES[spec.family];
|
|
7215
|
-
const promptOnly = spec.text && !spec.imageRequired;
|
|
7216
|
-
if (spec.endpoints.image === void 0)
|
|
7217
|
-
add(["endpoints", "image"], "every row needs an image endpoint");
|
|
7218
|
-
if (promptOnly && !rules.textPath) {
|
|
7219
|
-
add(
|
|
7220
|
-
["imageRequired"],
|
|
7221
|
-
`${spec.family} has no text-to-3D endpoint; a text row needs an image`
|
|
7222
|
-
);
|
|
7223
|
-
}
|
|
7224
|
-
if (promptOnly && spec.endpoints.text === void 0) {
|
|
7225
|
-
add(["endpoints", "text"], "a text row needs a text endpoint");
|
|
7226
|
-
}
|
|
7227
|
-
if (!rules.views.includes(spec.views)) {
|
|
7228
|
-
add(["views"], `${spec.family} takes views ${rules.views.join(" or ")}`);
|
|
7229
|
-
}
|
|
7230
|
-
if (spec.views === "none" && spec.maxImages !== 1) {
|
|
7231
|
-
add(["maxImages"], "a row without views takes 1 image");
|
|
7232
|
-
}
|
|
7233
|
-
if (spec.views === "unordered" && spec.maxImages < 2) {
|
|
7234
|
-
add(["maxImages"], "a row with views takes at least 2 images");
|
|
7235
|
-
}
|
|
7236
|
-
const slots = MODEL3D_IMAGE_SLOTS[spec.views].length;
|
|
7237
|
-
if (spec.views !== "none" && spec.maxImages > slots) {
|
|
7238
|
-
add(["maxImages"], `a row with ${spec.views} views sends at most ${slots} images`);
|
|
7239
|
-
}
|
|
7240
|
-
if ((spec.views === "named" || spec.views === "ordered") && spec.maxImages < slots) {
|
|
7241
|
-
add(
|
|
7242
|
-
["maxImages"],
|
|
7243
|
-
`a row with ${spec.views} views takes ${slots} images (front and three sides)`
|
|
7244
|
-
);
|
|
7245
|
-
}
|
|
7246
|
-
if (spec.views !== "none" && rules.multiImage && spec.endpoints.multiImage === void 0) {
|
|
7247
|
-
add(["endpoints", "multiImage"], `${spec.family} sends views to a multi-image endpoint`);
|
|
7248
|
-
}
|
|
7249
|
-
if (rules.texture === null) {
|
|
7250
|
-
if (spec.texture.length > 0) add(["texture"], `${spec.family} has no texture switch`);
|
|
7251
|
-
} else {
|
|
7252
|
-
const allowed = rules.texture;
|
|
7253
|
-
if (spec.texture.length === 0) add(["texture"], `${spec.family} needs its texture options`);
|
|
7254
|
-
if (new Set(spec.texture).size !== spec.texture.length)
|
|
7255
|
-
add(["texture"], "texture options repeat");
|
|
7256
|
-
for (const t of spec.texture) {
|
|
7257
|
-
if (!allowed.includes(t)) add(["texture"], `${spec.family} has no "${t}" texture`);
|
|
7258
|
-
}
|
|
7259
|
-
}
|
|
7260
|
-
if (spec.pbr && !rules.pbr) add(["pbr"], `${spec.family} has no PBR switch`);
|
|
7261
|
-
if (spec.pbr && !spec.texture.some((t) => t !== "none")) {
|
|
7262
|
-
add(["pbr"], "PBR needs a textured option");
|
|
7263
|
-
}
|
|
7264
|
-
if (spec.seed && !rules.seed) add(["seed"], `${spec.family} takes no seed`);
|
|
7265
|
-
if (spec.seedMax !== void 0 && !spec.seed) add(["seedMax"], "seedMax needs seed");
|
|
7266
|
-
if (spec.textureRef && !rules.textureRef)
|
|
7267
|
-
add(["textureRef"], `${spec.family} takes no texture reference`);
|
|
7268
|
-
const res = spec.resolutions;
|
|
7269
|
-
if (rules.resolutions === null) {
|
|
7270
|
-
if (res !== void 0) add(["resolutions"], `${spec.family} has no resolution option`);
|
|
7271
|
-
} else if (res === void 0) {
|
|
7272
|
-
add(["resolutions"], `${spec.family} needs its resolution options`);
|
|
7273
|
-
} else {
|
|
7274
|
-
if (!res.options.includes(res.default)) {
|
|
7275
|
-
add(["resolutions", "default"], "default must be an option");
|
|
7276
|
-
}
|
|
7277
|
-
if (new Set(res.options).size !== res.options.length) {
|
|
7278
|
-
add(["resolutions", "options"], "resolution options repeat");
|
|
7279
|
-
}
|
|
7280
|
-
const allowed = rules.resolutions;
|
|
7281
|
-
for (const option of res.options) {
|
|
7282
|
-
const ok = allowed === "integer" ? /^[1-9][0-9]*$/.test(option) : allowed.includes(option);
|
|
7283
|
-
if (!ok)
|
|
7284
|
-
add(["resolutions", "options"], `${spec.family} has no "${option}" resolution`);
|
|
7285
|
-
}
|
|
7286
|
-
}
|
|
7287
|
-
return issues;
|
|
7288
|
-
}
|
|
7289
7294
|
var VideoToolConstraintsSchema = z3.looseObject({
|
|
7290
7295
|
kind: z3.enum(["upscale", "interpolate", "hdr", "bg-remove", "subtitles"]),
|
|
7291
7296
|
upscaleFactor: RangeSchema.optional(),
|
|
@@ -10687,6 +10692,19 @@ function specOf(ctx) {
|
|
|
10687
10692
|
return spec;
|
|
10688
10693
|
}
|
|
10689
10694
|
var present = (v) => v !== void 0 && v.length > 0;
|
|
10695
|
+
function wireValue(row2, values, option, what) {
|
|
10696
|
+
const value = option !== void 0 && Object.hasOwn(values, option) ? values[option] : void 0;
|
|
10697
|
+
if (value === void 0) {
|
|
10698
|
+
throw new ModelKitError({
|
|
10699
|
+
code: "unsupported_option",
|
|
10700
|
+
message: `${row2.id} has no ${what} "${option ?? ""}" to send`,
|
|
10701
|
+
provider: "fal",
|
|
10702
|
+
model: row2.id,
|
|
10703
|
+
retryable: false
|
|
10704
|
+
});
|
|
10705
|
+
}
|
|
10706
|
+
return value;
|
|
10707
|
+
}
|
|
10690
10708
|
function model3dCall(row2, spec, req) {
|
|
10691
10709
|
const prompt = req.prompt?.trim() || void 0;
|
|
10692
10710
|
const texture = model3dTexture(spec, req.texture);
|
|
@@ -10730,7 +10748,15 @@ function model3dCall(row2, spec, req) {
|
|
|
10730
10748
|
}
|
|
10731
10749
|
};
|
|
10732
10750
|
case "hunyuan": {
|
|
10733
|
-
const opts = {
|
|
10751
|
+
const opts = {
|
|
10752
|
+
generate_type: wireValue(
|
|
10753
|
+
row2,
|
|
10754
|
+
MODEL3D_FAMILY_RULES.hunyuan.texture,
|
|
10755
|
+
texture,
|
|
10756
|
+
"texture"
|
|
10757
|
+
),
|
|
10758
|
+
enable_pbr: pbr
|
|
10759
|
+
};
|
|
10734
10760
|
if (!present(req.image)) {
|
|
10735
10761
|
return {
|
|
10736
10762
|
endpoint: endpoint(spec.endpoints.text),
|
|
@@ -10749,12 +10775,11 @@ function model3dCall(row2, spec, req) {
|
|
|
10749
10775
|
};
|
|
10750
10776
|
}
|
|
10751
10777
|
case "tripo": {
|
|
10778
|
+
const quality = wireValue(row2, MODEL3D_FAMILY_RULES.tripo.texture, texture, "texture");
|
|
10752
10779
|
const opts = {
|
|
10753
10780
|
texture: textured,
|
|
10754
10781
|
pbr,
|
|
10755
|
-
...
|
|
10756
|
-
texture_quality: texture === "detailed" ? "detailed" : "standard"
|
|
10757
|
-
},
|
|
10782
|
+
...quality !== null && { texture_quality: quality },
|
|
10758
10783
|
...seed !== void 0 && { model_seed: seed }
|
|
10759
10784
|
};
|
|
10760
10785
|
if (!present(req.image)) {
|
|
@@ -10790,6 +10815,7 @@ function model3dCall(row2, spec, req) {
|
|
|
10790
10815
|
};
|
|
10791
10816
|
}
|
|
10792
10817
|
case "meshy": {
|
|
10818
|
+
const mode = wireValue(row2, MODEL3D_FAMILY_RULES.meshy.texture, texture, "texture");
|
|
10793
10819
|
const texturePrompt = req.texturePrompt?.trim() || void 0;
|
|
10794
10820
|
const opts = {
|
|
10795
10821
|
enable_pbr: pbr,
|
|
@@ -10801,7 +10827,7 @@ function model3dCall(row2, spec, req) {
|
|
|
10801
10827
|
endpoint: endpoint(spec.endpoints.text),
|
|
10802
10828
|
input: {
|
|
10803
10829
|
prompt: prompt ?? "",
|
|
10804
|
-
mode
|
|
10830
|
+
mode,
|
|
10805
10831
|
...opts,
|
|
10806
10832
|
...seed !== void 0 && { seed }
|
|
10807
10833
|
}
|
|
@@ -10817,8 +10843,18 @@ function model3dCall(row2, spec, req) {
|
|
|
10817
10843
|
}
|
|
10818
10844
|
case "hi3d": {
|
|
10819
10845
|
const opts = {
|
|
10820
|
-
resolution:
|
|
10821
|
-
|
|
10846
|
+
resolution: wireValue(
|
|
10847
|
+
row2,
|
|
10848
|
+
MODEL3D_FAMILY_RULES.hi3d.resolutions,
|
|
10849
|
+
resolution,
|
|
10850
|
+
"resolution"
|
|
10851
|
+
),
|
|
10852
|
+
enable_texture: wireValue(
|
|
10853
|
+
row2,
|
|
10854
|
+
MODEL3D_FAMILY_RULES.hi3d.texture,
|
|
10855
|
+
texture,
|
|
10856
|
+
"texture"
|
|
10857
|
+
),
|
|
10822
10858
|
enable_pbr: pbr,
|
|
10823
10859
|
export_format: "glb"
|
|
10824
10860
|
};
|
|
@@ -13672,24 +13708,24 @@ import { z as z25 } from "zod";
|
|
|
13672
13708
|
function mp4DurationSeconds(bytes) {
|
|
13673
13709
|
const moov = findBox(bytes, 0, bytes.length, "moov");
|
|
13674
13710
|
if (!moov) return void 0;
|
|
13675
|
-
const mvhd = findBox(bytes, moov.
|
|
13711
|
+
const mvhd = findBox(bytes, moov.body, moov.end, "mvhd");
|
|
13676
13712
|
if (!mvhd) return void 0;
|
|
13677
13713
|
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
13678
|
-
const size = mvhd.end - mvhd.
|
|
13679
|
-
if (size <
|
|
13680
|
-
const version = view.getUint8(mvhd.
|
|
13714
|
+
const size = mvhd.end - mvhd.body;
|
|
13715
|
+
if (size < 4) return void 0;
|
|
13716
|
+
const version = view.getUint8(mvhd.body);
|
|
13681
13717
|
if (version === 0) {
|
|
13682
|
-
if (size <
|
|
13683
|
-
const timescale = view.getUint32(mvhd.
|
|
13684
|
-
const duration = view.getUint32(mvhd.
|
|
13718
|
+
if (size < 4 + 4 + 4 + 4 + 4) return void 0;
|
|
13719
|
+
const timescale = view.getUint32(mvhd.body + 4 + 4 + 4);
|
|
13720
|
+
const duration = view.getUint32(mvhd.body + 4 + 4 + 4 + 4);
|
|
13685
13721
|
if (timescale === 0) return void 0;
|
|
13686
13722
|
return duration / timescale;
|
|
13687
13723
|
}
|
|
13688
13724
|
if (version === 1) {
|
|
13689
|
-
if (size <
|
|
13690
|
-
const timescale = view.getUint32(mvhd.
|
|
13691
|
-
const high = view.getUint32(mvhd.
|
|
13692
|
-
const low = view.getUint32(mvhd.
|
|
13725
|
+
if (size < 4 + 8 + 8 + 4 + 8) return void 0;
|
|
13726
|
+
const timescale = view.getUint32(mvhd.body + 4 + 8 + 8);
|
|
13727
|
+
const high = view.getUint32(mvhd.body + 4 + 8 + 8 + 4);
|
|
13728
|
+
const low = view.getUint32(mvhd.body + 4 + 8 + 8 + 4 + 4);
|
|
13693
13729
|
if (timescale === 0) return void 0;
|
|
13694
13730
|
return (high * 2 ** 32 + low) / timescale;
|
|
13695
13731
|
}
|
|
@@ -13699,15 +13735,23 @@ function findBox(bytes, from, to, type) {
|
|
|
13699
13735
|
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
13700
13736
|
let offset = from;
|
|
13701
13737
|
while (offset + 8 <= to) {
|
|
13702
|
-
|
|
13738
|
+
let size = view.getUint32(offset);
|
|
13739
|
+
let header = 8;
|
|
13703
13740
|
const name = String.fromCharCode(
|
|
13704
13741
|
view.getUint8(offset + 4),
|
|
13705
13742
|
view.getUint8(offset + 5),
|
|
13706
13743
|
view.getUint8(offset + 6),
|
|
13707
13744
|
view.getUint8(offset + 7)
|
|
13708
13745
|
);
|
|
13709
|
-
if (size
|
|
13710
|
-
|
|
13746
|
+
if (size === 1) {
|
|
13747
|
+
if (offset + 16 > to) return void 0;
|
|
13748
|
+
size = view.getUint32(offset + 8) * 2 ** 32 + view.getUint32(offset + 12);
|
|
13749
|
+
header = 16;
|
|
13750
|
+
} else if (size === 0) {
|
|
13751
|
+
size = to - offset;
|
|
13752
|
+
}
|
|
13753
|
+
if (size < header || offset + size > to) return void 0;
|
|
13754
|
+
if (name === type) return { body: offset + header, end: offset + size };
|
|
13711
13755
|
offset += size;
|
|
13712
13756
|
}
|
|
13713
13757
|
return void 0;
|
|
@@ -13720,6 +13764,7 @@ var IMAGE_TIMEOUT_MS = 5 * 6e4;
|
|
|
13720
13764
|
var VIDEO_POLL_INTERVAL_MS = 5e3;
|
|
13721
13765
|
var VIDEO_TIMEOUT_MS = 20 * 6e4;
|
|
13722
13766
|
var PROMPT_MAX_CHARS = 6e3;
|
|
13767
|
+
var OUTPUT_URL_TTL_MS = 55 * 6e4;
|
|
13723
13768
|
var LUMA_IMAGE_MODEL_IDS = /* @__PURE__ */ new Set(["uni-1", "uni-1-max"]);
|
|
13724
13769
|
var LUMA_VIDEO_MODEL_ID = "ray-3.2";
|
|
13725
13770
|
var LUMA_VIDEO_MODES = /* @__PURE__ */ new Map([
|
|
@@ -13738,6 +13783,9 @@ function lumaRowRefusal(row2) {
|
|
|
13738
13783
|
}
|
|
13739
13784
|
return `luma has no ${row2.type} rows`;
|
|
13740
13785
|
}
|
|
13786
|
+
function lumaModel(ctx) {
|
|
13787
|
+
return ctx.model.providerModelId.toLowerCase();
|
|
13788
|
+
}
|
|
13741
13789
|
function lumaBase(ctx) {
|
|
13742
13790
|
return ctx.endpoints?.luma ?? DEFAULT_BASE_URL;
|
|
13743
13791
|
}
|
|
@@ -13780,8 +13828,23 @@ function imageRef(ref) {
|
|
|
13780
13828
|
if ("url" in ref) return { url: ref.url };
|
|
13781
13829
|
return { data: mediaRefToBase64(ref.bytes), media_type: ref.mime };
|
|
13782
13830
|
}
|
|
13831
|
+
var VIDEO_TYPES_BY_EXTENSION = /* @__PURE__ */ new Map([
|
|
13832
|
+
["mp4", "video/mp4"],
|
|
13833
|
+
["m4v", "video/mp4"],
|
|
13834
|
+
["mov", "video/quicktime"],
|
|
13835
|
+
["webm", "video/webm"]
|
|
13836
|
+
]);
|
|
13837
|
+
function videoUrlType(url) {
|
|
13838
|
+
let path = url;
|
|
13839
|
+
try {
|
|
13840
|
+
path = new URL(url).pathname;
|
|
13841
|
+
} catch {
|
|
13842
|
+
}
|
|
13843
|
+
const extension = path.slice(path.lastIndexOf(".") + 1).toLowerCase();
|
|
13844
|
+
return VIDEO_TYPES_BY_EXTENSION.get(extension) ?? "video/mp4";
|
|
13845
|
+
}
|
|
13783
13846
|
function videoRef(ref) {
|
|
13784
|
-
if ("url" in ref) return { url: ref.url, media_type:
|
|
13847
|
+
if ("url" in ref) return { url: ref.url, media_type: videoUrlType(ref.url) };
|
|
13785
13848
|
const mediaType = ref.mime.startsWith("video/") ? ref.mime : "video/mp4";
|
|
13786
13849
|
return { data: mediaRefToBase64(ref.bytes), media_type: mediaType };
|
|
13787
13850
|
}
|
|
@@ -13945,14 +14008,22 @@ async function lumaRequest(ctx, url, body) {
|
|
|
13945
14008
|
}
|
|
13946
14009
|
return res;
|
|
13947
14010
|
}
|
|
14011
|
+
async function parseGeneration(res) {
|
|
14012
|
+
try {
|
|
14013
|
+
const parsed = lumaGenerationSchema.safeParse(await res.json());
|
|
14014
|
+
return parsed.success ? parsed.data : void 0;
|
|
14015
|
+
} catch {
|
|
14016
|
+
return "not_json";
|
|
14017
|
+
}
|
|
14018
|
+
}
|
|
13948
14019
|
async function submitGeneration(ctx, body) {
|
|
13949
14020
|
const retryOptions = mediaRetryOptions(ctx.call, ctx.signal);
|
|
13950
14021
|
const res = await withRetry(
|
|
13951
14022
|
() => lumaRequest(ctx, `${lumaBase(ctx)}/v1/generations`, JSON.stringify(body)),
|
|
13952
14023
|
retryOptions
|
|
13953
14024
|
);
|
|
13954
|
-
const
|
|
13955
|
-
if (
|
|
14025
|
+
const generation = await parseGeneration(res);
|
|
14026
|
+
if (generation === void 0 || generation === "not_json") {
|
|
13956
14027
|
throw new ModelKitError({
|
|
13957
14028
|
code: "provider_rejected",
|
|
13958
14029
|
message: "Luma submit returned no generation id",
|
|
@@ -13961,13 +14032,20 @@ async function submitGeneration(ctx, body) {
|
|
|
13961
14032
|
retryable: false
|
|
13962
14033
|
});
|
|
13963
14034
|
}
|
|
13964
|
-
return
|
|
14035
|
+
return generation;
|
|
13965
14036
|
}
|
|
13966
14037
|
async function readGeneration(ctx, id) {
|
|
13967
14038
|
const res = await lumaRequest(ctx, `${lumaBase(ctx)}/v1/generations/${id}`);
|
|
13968
|
-
const
|
|
13969
|
-
|
|
13970
|
-
|
|
14039
|
+
const generation = await parseGeneration(res);
|
|
14040
|
+
if (generation === "not_json") {
|
|
14041
|
+
throw new ModelKitError({
|
|
14042
|
+
code: "network",
|
|
14043
|
+
message: "Luma returned a poll response that is not JSON",
|
|
14044
|
+
provider: "luma",
|
|
14045
|
+
model: ctx.model.id
|
|
14046
|
+
});
|
|
14047
|
+
}
|
|
14048
|
+
if (generation === void 0) {
|
|
13971
14049
|
throw new ModelKitError({
|
|
13972
14050
|
code: "provider_rejected",
|
|
13973
14051
|
message: "Luma returned an unreadable generation",
|
|
@@ -13976,14 +14054,12 @@ async function readGeneration(ctx, id) {
|
|
|
13976
14054
|
retryable: false
|
|
13977
14055
|
});
|
|
13978
14056
|
}
|
|
13979
|
-
return
|
|
14057
|
+
return generation;
|
|
13980
14058
|
}
|
|
13981
14059
|
function outputUrl(generation, type) {
|
|
13982
14060
|
const outputs = generation.output ?? [];
|
|
13983
|
-
const match = outputs.find((item) => item.type === type && item.url);
|
|
13984
|
-
|
|
13985
|
-
const fallback = outputs.find((item) => item.url);
|
|
13986
|
-
return fallback?.url;
|
|
14061
|
+
const match = outputs.find((item) => item.type === type && item.url) ?? outputs.find((item) => item.type === void 0 && item.url);
|
|
14062
|
+
return match?.url;
|
|
13987
14063
|
}
|
|
13988
14064
|
async function readGenerationOnce(ctx, id) {
|
|
13989
14065
|
try {
|
|
@@ -14022,21 +14098,22 @@ async function checkGeneration(ctx, id, type) {
|
|
|
14022
14098
|
return void 0;
|
|
14023
14099
|
}
|
|
14024
14100
|
async function downloadBytes(ctx, url, fallback) {
|
|
14025
|
-
|
|
14026
|
-
|
|
14027
|
-
|
|
14028
|
-
|
|
14029
|
-
|
|
14030
|
-
|
|
14031
|
-
|
|
14032
|
-
|
|
14033
|
-
|
|
14034
|
-
|
|
14035
|
-
|
|
14036
|
-
|
|
14037
|
-
|
|
14101
|
+
const { bytes, mime: header } = await withRetry(
|
|
14102
|
+
async () => {
|
|
14103
|
+
try {
|
|
14104
|
+
return await mediaRefToBytes({ url }, ctx.fetch, {
|
|
14105
|
+
...ctx.signal !== void 0 && { signal: ctx.signal },
|
|
14106
|
+
provider: "luma",
|
|
14107
|
+
model: ctx.model.id
|
|
14108
|
+
});
|
|
14109
|
+
} catch (cause) {
|
|
14110
|
+
throw classifyThrown("luma", cause, ctx.model.id);
|
|
14111
|
+
}
|
|
14112
|
+
},
|
|
14113
|
+
mediaRetryOptions(ctx.call, ctx.signal)
|
|
14114
|
+
);
|
|
14038
14115
|
const kind = fallback.split("/")[0];
|
|
14039
|
-
const usable = header
|
|
14116
|
+
const usable = header.startsWith(`${kind}/`);
|
|
14040
14117
|
return { bytes, mime: usable ? header : fallback };
|
|
14041
14118
|
}
|
|
14042
14119
|
function imageUsage2(ctx) {
|
|
@@ -14051,15 +14128,12 @@ function imageUsage2(ctx) {
|
|
|
14051
14128
|
}
|
|
14052
14129
|
var GENERATE_SECONDS = 5;
|
|
14053
14130
|
var MAX_PLAUSIBLE_SECONDS = 60;
|
|
14054
|
-
function
|
|
14055
|
-
if (mode === "generate") return GENERATE_SECONDS;
|
|
14131
|
+
function editedSeconds(req, bytes) {
|
|
14056
14132
|
const measured = mp4DurationSeconds(bytes);
|
|
14057
|
-
const
|
|
14058
|
-
const length = measured !== void 0 && measured > 0 && measured <= MAX_PLAUSIBLE_SECONDS ? measured : source2 !== void 0 && "url" in source2 ? source2.durationSeconds : void 0;
|
|
14133
|
+
const length = measured !== void 0 && measured > 0 && measured <= MAX_PLAUSIBLE_SECONDS ? measured : req.sourceVideo?.durationSeconds;
|
|
14059
14134
|
return Math.max(length ?? 0, GENERATE_SECONDS);
|
|
14060
14135
|
}
|
|
14061
|
-
function videoUsage4(ctx, req, mode,
|
|
14062
|
-
const seconds3 = billedSeconds(req, mode, bytes);
|
|
14136
|
+
function videoUsage4(ctx, req, mode, seconds3) {
|
|
14063
14137
|
const event = {
|
|
14064
14138
|
model: ctx.model.id,
|
|
14065
14139
|
provider: "luma",
|
|
@@ -14074,7 +14148,7 @@ function videoUsage4(ctx, req, mode, bytes) {
|
|
|
14074
14148
|
}
|
|
14075
14149
|
function imageBody(req, ctx, outputFormat) {
|
|
14076
14150
|
const prompt = checkPrompt(req, ctx);
|
|
14077
|
-
const model = ctx
|
|
14151
|
+
const model = lumaModel(ctx);
|
|
14078
14152
|
const ratio = req.aspectRatio !== "adaptive" ? req.aspectRatio : void 0;
|
|
14079
14153
|
const [source2, ...rest] = req.references ?? [];
|
|
14080
14154
|
if (source2 === void 0) {
|
|
@@ -14102,7 +14176,7 @@ function imageBody(req, ctx, outputFormat) {
|
|
|
14102
14176
|
}
|
|
14103
14177
|
function videoBody(req, ctx, mode) {
|
|
14104
14178
|
const prompt = checkPrompt(req, ctx);
|
|
14105
|
-
const model = ctx
|
|
14179
|
+
const model = lumaModel(ctx);
|
|
14106
14180
|
const hasReferences = (req.referenceImages ?? []).length + (req.referenceVideos ?? []).length + (req.referenceAudios ?? []).length > 0;
|
|
14107
14181
|
if (hasReferences) {
|
|
14108
14182
|
refuseOrDrop(
|
|
@@ -14184,7 +14258,7 @@ function videoBody(req, ctx, mode) {
|
|
|
14184
14258
|
async function generateLumaImage(req, ctx) {
|
|
14185
14259
|
throwIfAborted(ctx.signal);
|
|
14186
14260
|
lumaKey(ctx);
|
|
14187
|
-
if (!LUMA_IMAGE_MODEL_IDS.has(ctx
|
|
14261
|
+
if (!LUMA_IMAGE_MODEL_IDS.has(lumaModel(ctx))) {
|
|
14188
14262
|
throw new ModelKitError({
|
|
14189
14263
|
code: "unsupported_option",
|
|
14190
14264
|
message: `luma has no image mapping for "${ctx.model.providerModelId}"`,
|
|
@@ -14217,16 +14291,25 @@ function lumaVideoJob(ctx, req, mode, id) {
|
|
|
14217
14291
|
return { status: "pending" };
|
|
14218
14292
|
},
|
|
14219
14293
|
async result(opts) {
|
|
14220
|
-
const signal = opts?.signal
|
|
14221
|
-
const
|
|
14294
|
+
const signal = combineSignals(ctx.signal, opts?.signal);
|
|
14295
|
+
const jobCtx = { ...ctx, ...signal !== void 0 && { signal } };
|
|
14296
|
+
const url = await pollUntil(checkGeneration.bind(null, jobCtx, id, "video"), {
|
|
14222
14297
|
intervalMs: opts?.pollIntervalMs ?? VIDEO_POLL_INTERVAL_MS,
|
|
14223
14298
|
timeoutMs: opts?.timeoutMs ?? VIDEO_TIMEOUT_MS,
|
|
14224
14299
|
...signal !== void 0 && { signal }
|
|
14225
14300
|
});
|
|
14226
|
-
|
|
14301
|
+
if (mode === "generate") {
|
|
14302
|
+
const result2 = {
|
|
14303
|
+
video: { url, expiresAt: new Date(Date.now() + OUTPUT_URL_TTL_MS) },
|
|
14304
|
+
usage: videoUsage4(jobCtx, req, mode, GENERATE_SECONDS),
|
|
14305
|
+
raw: { id }
|
|
14306
|
+
};
|
|
14307
|
+
return result2;
|
|
14308
|
+
}
|
|
14309
|
+
const video = await downloadBytes(jobCtx, url, "video/mp4");
|
|
14227
14310
|
const result = {
|
|
14228
14311
|
video,
|
|
14229
|
-
usage: videoUsage4(
|
|
14312
|
+
usage: videoUsage4(jobCtx, req, mode, editedSeconds(req, video.bytes)),
|
|
14230
14313
|
raw: { id }
|
|
14231
14314
|
};
|
|
14232
14315
|
return result;
|
|
@@ -14236,7 +14319,7 @@ function lumaVideoJob(ctx, req, mode, id) {
|
|
|
14236
14319
|
async function generateLumaVideo(req, ctx) {
|
|
14237
14320
|
throwIfAborted(ctx.signal);
|
|
14238
14321
|
lumaKey(ctx);
|
|
14239
|
-
if (ctx
|
|
14322
|
+
if (lumaModel(ctx) !== LUMA_VIDEO_MODEL_ID) {
|
|
14240
14323
|
throw new ModelKitError({
|
|
14241
14324
|
code: "unsupported_option",
|
|
14242
14325
|
message: `luma has no video mapping for "${ctx.model.providerModelId}"`,
|