@shop-os/modelkit 0.2.27 → 0.3.1
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 +31 -0
- package/README.md +23 -4
- package/dist/catalog.cjs +314 -19
- package/dist/catalog.cjs.map +1 -1
- package/dist/catalog.d.cts +158 -2
- package/dist/catalog.d.ts +158 -2
- package/dist/catalog.js +314 -19
- package/dist/catalog.js.map +1 -1
- package/dist/index.cjs +811 -260
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +195 -2
- package/dist/index.d.ts +195 -2
- package/dist/index.js +806 -260
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/catalog.js
CHANGED
|
@@ -1293,6 +1293,11 @@ var NEGATIVE_PROMPT = "blur, distort, and low quality";
|
|
|
1293
1293
|
var FRAMES_EXCLUDE_REFERENCES = { framesExcludeReferences: true };
|
|
1294
1294
|
var KLING_PROMPT = { referenceSyntax: "numbered", maxChars: 2500 };
|
|
1295
1295
|
var SEEDANCE_PROMPT = { referenceSyntax: "numbered", maxChars: 3e4 };
|
|
1296
|
+
var SEEDANCE_2_AUDIO = {
|
|
1297
|
+
audioSeconds: { min: 2, max: 15, total: 15 },
|
|
1298
|
+
audioFormats: ["wav", "mp3"],
|
|
1299
|
+
audioMaxBytes: 15 * 1024 * 1024
|
|
1300
|
+
};
|
|
1296
1301
|
var H3_PROMPT = { referenceSyntax: "numbered", maxChars: 5e4 };
|
|
1297
1302
|
var OMNI_PROMPT = { referenceSyntax: "caption", maxChars: 5e4 };
|
|
1298
1303
|
var BYTEDANCE_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/3bba5d81-4e57-4e71-911b-cdfa05acca2c_compressed.png";
|
|
@@ -1429,7 +1434,7 @@ var VIDEO_MODELS = [
|
|
|
1429
1434
|
description: "Google's conversational video model with native audio, human support, and natural language editing. Aspect ratio only \u2014 resolution and duration are model-determined.",
|
|
1430
1435
|
logo: GOOGLE_LOGO2
|
|
1431
1436
|
},
|
|
1432
|
-
capabilities: { acceptsSourceVideo: true }
|
|
1437
|
+
capabilities: { acceptsSourceVideo: true, videoEdit: true }
|
|
1433
1438
|
},
|
|
1434
1439
|
{
|
|
1435
1440
|
id: "gemini-omni-1.1-flash",
|
|
@@ -1454,7 +1459,7 @@ var VIDEO_MODELS = [
|
|
|
1454
1459
|
// with a video task, so those calls carry the prompt alone).
|
|
1455
1460
|
// First-to-last-frame interpolation: `<LAST_FRAME>` goes with `<FIRST_FRAME>`.
|
|
1456
1461
|
supports: ["videoExtension", "lastFrame"],
|
|
1457
|
-
extension: { segmentSeconds: 10, maxTotalSeconds: 40 },
|
|
1462
|
+
extension: { segmentSeconds: 10, maxTotalSeconds: 40, returns: "joined" },
|
|
1458
1463
|
prompt: OMNI_PROMPT,
|
|
1459
1464
|
audio: "always"
|
|
1460
1465
|
},
|
|
@@ -1466,7 +1471,11 @@ var VIDEO_MODELS = [
|
|
|
1466
1471
|
logo: GOOGLE_LOGO2,
|
|
1467
1472
|
description: "Google Gemini Omni Flash 1.1 conversational video generation, editing and extension; text, image, and up to 10-second video input, 3-10 second output at up to 4K and 24 FPS, extendable to 40 seconds."
|
|
1468
1473
|
},
|
|
1469
|
-
capabilities: {
|
|
1474
|
+
capabilities: {
|
|
1475
|
+
acceptsSourceVideo: true,
|
|
1476
|
+
videoEdit: true,
|
|
1477
|
+
lastFrameRequiresFirstFrame: true
|
|
1478
|
+
}
|
|
1470
1479
|
},
|
|
1471
1480
|
{
|
|
1472
1481
|
// vibe-triggers and Space Builder drop the ratio when a frame is wired; Cowork always sends it.
|
|
@@ -1488,7 +1497,8 @@ var VIDEO_MODELS = [
|
|
|
1488
1497
|
videos: 3,
|
|
1489
1498
|
audios: 3,
|
|
1490
1499
|
audioOnly: false,
|
|
1491
|
-
videoSeconds: { min: 2, max: 15, total: 15 }
|
|
1500
|
+
videoSeconds: { min: 2, max: 15, total: 15 },
|
|
1501
|
+
...SEEDANCE_2_AUDIO
|
|
1492
1502
|
},
|
|
1493
1503
|
sourceVideoSeconds: { min: 2, max: 15, inReferenceTotal: true },
|
|
1494
1504
|
ratioIgnoredWith: ["firstFrame", "sourceVideo"],
|
|
@@ -1510,7 +1520,7 @@ var VIDEO_MODELS = [
|
|
|
1510
1520
|
description: "High-quality AI video generation with reference image conditioning. Supports 4-15 second clips with human preprocessing.",
|
|
1511
1521
|
logo: BYTEDANCE_LOGO
|
|
1512
1522
|
},
|
|
1513
|
-
capabilities: { acceptsSourceVideo: true, ...FRAMES_EXCLUDE_REFERENCES }
|
|
1523
|
+
capabilities: { acceptsSourceVideo: true, videoEdit: false, ...FRAMES_EXCLUDE_REFERENCES }
|
|
1514
1524
|
},
|
|
1515
1525
|
{
|
|
1516
1526
|
id: "seedance-2.0-fast",
|
|
@@ -1530,7 +1540,8 @@ var VIDEO_MODELS = [
|
|
|
1530
1540
|
videos: 3,
|
|
1531
1541
|
audios: 3,
|
|
1532
1542
|
audioOnly: false,
|
|
1533
|
-
videoSeconds: { min: 2, max: 15, total: 15 }
|
|
1543
|
+
videoSeconds: { min: 2, max: 15, total: 15 },
|
|
1544
|
+
...SEEDANCE_2_AUDIO
|
|
1534
1545
|
},
|
|
1535
1546
|
sourceVideoSeconds: { min: 2, max: 15, inReferenceTotal: true },
|
|
1536
1547
|
ratioIgnoredWith: ["firstFrame", "sourceVideo"],
|
|
@@ -1552,7 +1563,7 @@ var VIDEO_MODELS = [
|
|
|
1552
1563
|
logo: BYTEDANCE_LOGO,
|
|
1553
1564
|
description: "Speed- and cost-optimized ByteDance Seedance 2.0 Fast; text plus image, video, and audio references to generate or edit 4-15 second clips."
|
|
1554
1565
|
},
|
|
1555
|
-
capabilities: { acceptsSourceVideo: true, ...FRAMES_EXCLUDE_REFERENCES }
|
|
1566
|
+
capabilities: { acceptsSourceVideo: true, videoEdit: false, ...FRAMES_EXCLUDE_REFERENCES }
|
|
1556
1567
|
},
|
|
1557
1568
|
{
|
|
1558
1569
|
// omni_reference_task_type edit/extend: adaptive ratio, edit sends duration -1.
|
|
@@ -1572,12 +1583,20 @@ var VIDEO_MODELS = [
|
|
|
1572
1583
|
images: 30,
|
|
1573
1584
|
videos: 10,
|
|
1574
1585
|
audios: 10,
|
|
1575
|
-
videoSeconds: { min: 2, max: 30, total: 30, editMin: 4 }
|
|
1586
|
+
videoSeconds: { min: 2, max: 30, total: 30, editMin: 4 },
|
|
1587
|
+
// BytePlus: 2-30 s per clip, 30 s in all, wav/mp3, 15 MB each.
|
|
1588
|
+
audioSeconds: { min: 2, max: 30, total: 30 },
|
|
1589
|
+
audioFormats: ["wav", "mp3"],
|
|
1590
|
+
audioMaxBytes: 15 * 1024 * 1024
|
|
1576
1591
|
},
|
|
1577
1592
|
sourceVideoSeconds: { min: 2, max: 30, editMin: 4, inReferenceTotal: true },
|
|
1578
1593
|
ratioIgnoredWith: ["firstFrame", "sourceVideo"],
|
|
1579
1594
|
// No seed: 2.x echoes it but does not honour it (two seeded runs differed, 2026-10-01).
|
|
1580
|
-
supports: ["generateAudio", "lastFrame", "watermark", "taskType"],
|
|
1595
|
+
supports: ["generateAudio", "lastFrame", "watermark", "taskType", "videoExtension"],
|
|
1596
|
+
// Extend (probe 2026-10-02, 480p): returns ONLY the added footage, continuing from
|
|
1597
|
+
// the source's last frame at the source's framing and fps but at the requested
|
|
1598
|
+
// resolution, so the caller joins the clips. Forward only in practice.
|
|
1599
|
+
extension: { segmentSeconds: 30, maxTotalSeconds: 60, returns: "new" },
|
|
1581
1600
|
prompt: SEEDANCE_PROMPT,
|
|
1582
1601
|
audio: "optional"
|
|
1583
1602
|
},
|
|
@@ -1594,7 +1613,7 @@ var VIDEO_MODELS = [
|
|
|
1594
1613
|
logo: BYTEDANCE_LOGO,
|
|
1595
1614
|
description: "ByteDance Seedance 2.5 for long-form storytelling and omni-reference generation/editing; up to 50 reference assets and 4-30 second clips at up to 1080p."
|
|
1596
1615
|
},
|
|
1597
|
-
capabilities: { acceptsSourceVideo: true, ...FRAMES_EXCLUDE_REFERENCES }
|
|
1616
|
+
capabilities: { acceptsSourceVideo: true, videoEdit: true, ...FRAMES_EXCLUDE_REFERENCES }
|
|
1598
1617
|
},
|
|
1599
1618
|
{
|
|
1600
1619
|
id: "grok-imagine",
|
|
@@ -1958,11 +1977,116 @@ var VIDEO_MODELS = [
|
|
|
1958
1977
|
}
|
|
1959
1978
|
];
|
|
1960
1979
|
|
|
1980
|
+
// src/catalog/video-tools.ts
|
|
1981
|
+
var TOPAZ_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/topazlabs.png";
|
|
1982
|
+
var TOPAZ_SOURCE_SECONDS = { max: 300 };
|
|
1983
|
+
var TOPAZ_USAGE = { unit: "seconds" };
|
|
1984
|
+
var VIDEO_TOOL_MODELS = [
|
|
1985
|
+
{
|
|
1986
|
+
id: "topaz-precision",
|
|
1987
|
+
aliases: [],
|
|
1988
|
+
label: "Topaz Precision",
|
|
1989
|
+
type: "video-tool",
|
|
1990
|
+
adapter: "fal",
|
|
1991
|
+
providerModelId: "topaz/upscale/video/precision",
|
|
1992
|
+
lifecycle: "active",
|
|
1993
|
+
exposure: ["cowork"],
|
|
1994
|
+
constraints: {
|
|
1995
|
+
supports: [],
|
|
1996
|
+
sourceVideoSeconds: TOPAZ_SOURCE_SECONDS,
|
|
1997
|
+
tool: { kind: "upscale", upscaleFactor: { min: 1, max: 4 }, maxOutputLongEdge: 3840 }
|
|
1998
|
+
},
|
|
1999
|
+
defaults: {},
|
|
2000
|
+
providerOptions: { fal: { model: "Proteus" } },
|
|
2001
|
+
usage: TOPAZ_USAGE,
|
|
2002
|
+
pricingKind: "video_per_second",
|
|
2003
|
+
display: {
|
|
2004
|
+
provider: "topaz",
|
|
2005
|
+
logo: TOPAZ_LOGO,
|
|
2006
|
+
description: "Topaz Proteus upscaling: sharper, cleaner footage up to 4K while staying faithful to the source.",
|
|
2007
|
+
sortOrder: 20
|
|
2008
|
+
}
|
|
2009
|
+
},
|
|
2010
|
+
{
|
|
2011
|
+
id: "topaz-starlight",
|
|
2012
|
+
aliases: [],
|
|
2013
|
+
label: "Topaz Starlight",
|
|
2014
|
+
type: "video-tool",
|
|
2015
|
+
adapter: "fal",
|
|
2016
|
+
providerModelId: "topaz/upscale/video/generative",
|
|
2017
|
+
lifecycle: "active",
|
|
2018
|
+
exposure: ["cowork"],
|
|
2019
|
+
constraints: {
|
|
2020
|
+
supports: [],
|
|
2021
|
+
sourceVideoSeconds: TOPAZ_SOURCE_SECONDS,
|
|
2022
|
+
tool: { kind: "upscale", upscaleFactor: { min: 1, max: 4 }, maxOutputLongEdge: 3840 }
|
|
2023
|
+
},
|
|
2024
|
+
defaults: {},
|
|
2025
|
+
providerOptions: { fal: { model: "Starlight Precise 2.6" } },
|
|
2026
|
+
usage: TOPAZ_USAGE,
|
|
2027
|
+
pricingKind: "video_per_second",
|
|
2028
|
+
display: {
|
|
2029
|
+
provider: "topaz",
|
|
2030
|
+
logo: TOPAZ_LOGO,
|
|
2031
|
+
description: "Topaz Starlight Precise 2.6: generative upscaling that rebuilds fine detail, up to 4K. Slower and costlier than Precision.",
|
|
2032
|
+
sortOrder: 10
|
|
2033
|
+
}
|
|
2034
|
+
},
|
|
2035
|
+
{
|
|
2036
|
+
id: "topaz-apollo",
|
|
2037
|
+
aliases: [],
|
|
2038
|
+
label: "Topaz Apollo",
|
|
2039
|
+
type: "video-tool",
|
|
2040
|
+
adapter: "fal",
|
|
2041
|
+
providerModelId: "topaz/interpolate/video",
|
|
2042
|
+
lifecycle: "active",
|
|
2043
|
+
exposure: ["cowork"],
|
|
2044
|
+
constraints: {
|
|
2045
|
+
supports: [],
|
|
2046
|
+
sourceVideoSeconds: TOPAZ_SOURCE_SECONDS,
|
|
2047
|
+
tool: { kind: "interpolate", fps: { min: 16, max: 120 } }
|
|
2048
|
+
},
|
|
2049
|
+
defaults: {},
|
|
2050
|
+
providerOptions: { fal: { model: "Apollo" } },
|
|
2051
|
+
usage: TOPAZ_USAGE,
|
|
2052
|
+
pricingKind: "video_per_second",
|
|
2053
|
+
display: {
|
|
2054
|
+
provider: "topaz",
|
|
2055
|
+
logo: TOPAZ_LOGO,
|
|
2056
|
+
description: "Topaz Apollo frame interpolation: smoother motion at up to 120 fps, same length as the source."
|
|
2057
|
+
}
|
|
2058
|
+
},
|
|
2059
|
+
{
|
|
2060
|
+
id: "topaz-hyperion-2.5",
|
|
2061
|
+
aliases: [],
|
|
2062
|
+
label: "Topaz Hyperion 2.5",
|
|
2063
|
+
type: "video-tool",
|
|
2064
|
+
adapter: "fal",
|
|
2065
|
+
providerModelId: "topaz/sdr-to-hdr/video",
|
|
2066
|
+
lifecycle: "active",
|
|
2067
|
+
exposure: ["cowork"],
|
|
2068
|
+
constraints: {
|
|
2069
|
+
supports: [],
|
|
2070
|
+
sourceVideoSeconds: TOPAZ_SOURCE_SECONDS,
|
|
2071
|
+
tool: { kind: "hdr", outputFormats: ["h265", "prores"] }
|
|
2072
|
+
},
|
|
2073
|
+
defaults: {},
|
|
2074
|
+
usage: TOPAZ_USAGE,
|
|
2075
|
+
pricingKind: "video_per_second",
|
|
2076
|
+
display: {
|
|
2077
|
+
provider: "topaz",
|
|
2078
|
+
logo: TOPAZ_LOGO,
|
|
2079
|
+
description: "Topaz Hyperion 2.5 SDR to HDR: a 10-bit HDR master in H.265 (HDR10) or ProRes 422 HQ, at the source's size and frame rate."
|
|
2080
|
+
}
|
|
2081
|
+
}
|
|
2082
|
+
];
|
|
2083
|
+
|
|
1961
2084
|
// src/catalog/models.ts
|
|
1962
2085
|
var MODELS = [
|
|
1963
2086
|
...TEXT_MODELS,
|
|
1964
2087
|
...IMAGE_MODELS,
|
|
1965
2088
|
...VIDEO_MODELS,
|
|
2089
|
+
...VIDEO_TOOL_MODELS,
|
|
1966
2090
|
...OTHER_MODELS
|
|
1967
2091
|
];
|
|
1968
2092
|
|
|
@@ -2129,6 +2253,10 @@ var ALL_KEY_SET = /* @__PURE__ */ new Set([
|
|
|
2129
2253
|
...IMAGE_INPUT_SPEC_KEYS,
|
|
2130
2254
|
...AUDIO_INPUT_SPEC_KEYS
|
|
2131
2255
|
]);
|
|
2256
|
+
var TYPES_BY_ADAPTER = /* @__PURE__ */ new Map([
|
|
2257
|
+
["replicate", ["video", "image", "audio"]],
|
|
2258
|
+
["fal", ["image"]]
|
|
2259
|
+
]);
|
|
2132
2260
|
var ALLOWED_KEYS_BY_TYPE = /* @__PURE__ */ new Map([
|
|
2133
2261
|
["video", VIDEO_KEY_SET],
|
|
2134
2262
|
["image", IMAGE_KEY_SET],
|
|
@@ -2167,7 +2295,8 @@ var StaticSchema = z2.record(z2.string(), ProviderScalarSchema);
|
|
|
2167
2295
|
var InputSpecSchema = z2.strictObject({
|
|
2168
2296
|
fields: FieldsSchema,
|
|
2169
2297
|
values: ValuesSchema.optional(),
|
|
2170
|
-
static: StaticSchema.optional()
|
|
2298
|
+
static: StaticSchema.optional(),
|
|
2299
|
+
editEndpoint: z2.string().min(1).optional()
|
|
2171
2300
|
}).superRefine((spec, ctx) => {
|
|
2172
2301
|
const mappedNames = new Set(Object.values(spec.fields));
|
|
2173
2302
|
for (const key of Object.keys(spec.static ?? {})) {
|
|
@@ -2192,18 +2321,21 @@ function validateInputSpec(raw, row) {
|
|
|
2192
2321
|
};
|
|
2193
2322
|
}
|
|
2194
2323
|
const spec = parsed.data;
|
|
2195
|
-
|
|
2324
|
+
const supportedTypes = TYPES_BY_ADAPTER.get(row.adapter);
|
|
2325
|
+
if (supportedTypes === void 0) {
|
|
2196
2326
|
return {
|
|
2197
2327
|
ok: false,
|
|
2198
|
-
issues: [
|
|
2328
|
+
issues: [
|
|
2329
|
+
{ path: [], message: "inputSpec is only supported on replicate and fal rows" }
|
|
2330
|
+
]
|
|
2199
2331
|
};
|
|
2200
2332
|
}
|
|
2201
2333
|
const issues = [];
|
|
2202
2334
|
const allowed = ALLOWED_KEYS_BY_TYPE.get(row.type);
|
|
2203
|
-
if (allowed === void 0) {
|
|
2335
|
+
if (allowed === void 0 || !supportedTypes.includes(row.type)) {
|
|
2204
2336
|
issues.push({
|
|
2205
2337
|
path: [],
|
|
2206
|
-
message: `inputSpec is not supported for "${row.type}" rows`
|
|
2338
|
+
message: row.adapter === "fal" ? `inputSpec on fal rows is only supported for image rows, not "${row.type}"` : `inputSpec is not supported for "${row.type}" rows`
|
|
2207
2339
|
});
|
|
2208
2340
|
} else {
|
|
2209
2341
|
for (const key of Object.keys(spec.fields)) {
|
|
@@ -2223,6 +2355,19 @@ function validateInputSpec(raw, row) {
|
|
|
2223
2355
|
}
|
|
2224
2356
|
}
|
|
2225
2357
|
}
|
|
2358
|
+
if (spec.editEndpoint !== void 0) {
|
|
2359
|
+
if (row.adapter !== "fal") {
|
|
2360
|
+
issues.push({
|
|
2361
|
+
path: ["editEndpoint"],
|
|
2362
|
+
message: "inputSpec.editEndpoint is only supported on fal rows"
|
|
2363
|
+
});
|
|
2364
|
+
} else if (!("references" in spec.fields)) {
|
|
2365
|
+
issues.push({
|
|
2366
|
+
path: ["editEndpoint"],
|
|
2367
|
+
message: 'inputSpec.editEndpoint needs a "references" entry in inputSpec.fields'
|
|
2368
|
+
});
|
|
2369
|
+
}
|
|
2370
|
+
}
|
|
2226
2371
|
const seenNames = /* @__PURE__ */ new Map();
|
|
2227
2372
|
for (const [key, name] of Object.entries(spec.fields)) {
|
|
2228
2373
|
const first = seenNames.get(name);
|
|
@@ -2268,7 +2413,15 @@ var ADAPTER_IDS = [
|
|
|
2268
2413
|
"higgsfield",
|
|
2269
2414
|
"xai-video"
|
|
2270
2415
|
];
|
|
2271
|
-
var ModelTypeSchema = z3.enum([
|
|
2416
|
+
var ModelTypeSchema = z3.enum([
|
|
2417
|
+
"text",
|
|
2418
|
+
"image",
|
|
2419
|
+
"video",
|
|
2420
|
+
"audio",
|
|
2421
|
+
"upscale",
|
|
2422
|
+
"bg-remove",
|
|
2423
|
+
"video-tool"
|
|
2424
|
+
]);
|
|
2272
2425
|
var LifecycleSchema = z3.enum(["active", "deprecated", "retired"]);
|
|
2273
2426
|
var SurfaceSchema = z3.enum(["cowork", "space_builder"]);
|
|
2274
2427
|
var SURFACES2 = SurfaceSchema.options;
|
|
@@ -2348,7 +2501,22 @@ var ReferenceLimitsSchema = z3.looseObject({
|
|
|
2348
2501
|
audios: z3.number().optional(),
|
|
2349
2502
|
total: z3.number().optional(),
|
|
2350
2503
|
audioOnly: z3.boolean().optional(),
|
|
2351
|
-
videoSeconds: VideoSecondsLimitsSchema.optional()
|
|
2504
|
+
videoSeconds: VideoSecondsLimitsSchema.optional(),
|
|
2505
|
+
audioSeconds: z3.looseObject({
|
|
2506
|
+
min: z3.number().optional(),
|
|
2507
|
+
max: z3.number().optional(),
|
|
2508
|
+
total: z3.number().optional()
|
|
2509
|
+
}).optional(),
|
|
2510
|
+
audioFormats: z3.array(z3.string()).optional(),
|
|
2511
|
+
audioMaxBytes: z3.number().positive().optional()
|
|
2512
|
+
});
|
|
2513
|
+
var RangeSchema = z3.looseObject({ min: z3.number(), max: z3.number() });
|
|
2514
|
+
var VideoToolConstraintsSchema = z3.looseObject({
|
|
2515
|
+
kind: z3.enum(["upscale", "interpolate", "hdr"]),
|
|
2516
|
+
upscaleFactor: RangeSchema.optional(),
|
|
2517
|
+
maxOutputLongEdge: z3.number().positive().optional(),
|
|
2518
|
+
fps: RangeSchema.optional(),
|
|
2519
|
+
outputFormats: z3.array(z3.enum(["h265", "prores"])).min(1).optional()
|
|
2352
2520
|
});
|
|
2353
2521
|
var ModelConstraintsSchema = z3.looseObject({
|
|
2354
2522
|
aspectRatios: z3.array(AspectRatioSchema).optional(),
|
|
@@ -2363,7 +2531,14 @@ var ModelConstraintsSchema = z3.looseObject({
|
|
|
2363
2531
|
supports: z3.array(SupportedOptionSchema).optional(),
|
|
2364
2532
|
ratioIgnoredWith: z3.array(z3.enum(["firstFrame", "sourceVideo"])).optional(),
|
|
2365
2533
|
sourceVideoSeconds: VideoSecondsLimitsSchema.omit({ total: true }).extend({ inReferenceTotal: z3.boolean().optional() }).optional(),
|
|
2366
|
-
|
|
2534
|
+
// segmentSeconds/maxTotalSeconds stay required: a kit before 0.3.0 drops a row whose
|
|
2535
|
+
// extension lacks them, so every extension block keeps them.
|
|
2536
|
+
extension: z3.looseObject({
|
|
2537
|
+
segmentSeconds: z3.number(),
|
|
2538
|
+
maxTotalSeconds: z3.number(),
|
|
2539
|
+
returns: z3.enum(["new", "joined"]).optional()
|
|
2540
|
+
}).optional(),
|
|
2541
|
+
tool: VideoToolConstraintsSchema.optional(),
|
|
2367
2542
|
// Loose on purpose: the read path keeps a row whose value is invalid (the accessors in
|
|
2368
2543
|
// conventions.ts read it as "not set"); CatalogModelSchema below rejects it on write.
|
|
2369
2544
|
audio: z3.unknown().optional(),
|
|
@@ -2435,6 +2610,7 @@ var CatalogDisplaySchema = z3.looseObject({
|
|
|
2435
2610
|
});
|
|
2436
2611
|
var CatalogCapabilitiesSchema = z3.looseObject({
|
|
2437
2612
|
acceptsSourceVideo: z3.boolean().optional(),
|
|
2613
|
+
videoEdit: z3.boolean().optional(),
|
|
2438
2614
|
framesExcludeReferences: z3.boolean().optional(),
|
|
2439
2615
|
lastFrameRequiresFirstFrame: z3.boolean().optional(),
|
|
2440
2616
|
reasoning: z3.boolean().optional(),
|
|
@@ -2477,6 +2653,13 @@ var CatalogModelSchemaBase = z3.looseObject({
|
|
|
2477
2653
|
message: "active text rows need contextWindow"
|
|
2478
2654
|
});
|
|
2479
2655
|
}
|
|
2656
|
+
if (row.type === "video-tool" && row.constraints.tool === void 0) {
|
|
2657
|
+
ctx.addIssue({
|
|
2658
|
+
code: "custom",
|
|
2659
|
+
path: ["constraints", "tool"],
|
|
2660
|
+
message: "video-tool rows need constraints.tool"
|
|
2661
|
+
});
|
|
2662
|
+
}
|
|
2480
2663
|
if (row.replacedBy !== void 0 && row.replacedBy === row.id) {
|
|
2481
2664
|
ctx.addIssue({
|
|
2482
2665
|
code: "custom",
|
|
@@ -2782,6 +2965,114 @@ function resetLiveCatalog() {
|
|
|
2782
2965
|
liveCatalog.replace([...MODELS]);
|
|
2783
2966
|
}
|
|
2784
2967
|
|
|
2968
|
+
// src/catalog/video-tools-spec.ts
|
|
2969
|
+
import { z as z6 } from "zod";
|
|
2970
|
+
var RangeSchema2 = z6.object({ min: z6.number(), max: z6.number() });
|
|
2971
|
+
var ToolSchema = z6.object({
|
|
2972
|
+
kind: z6.enum(["upscale", "interpolate", "hdr"]),
|
|
2973
|
+
upscaleFactor: RangeSchema2.optional(),
|
|
2974
|
+
maxOutputLongEdge: z6.number().positive().optional(),
|
|
2975
|
+
fps: RangeSchema2.optional(),
|
|
2976
|
+
outputFormats: z6.array(z6.enum(["h265", "prores"])).min(1).optional()
|
|
2977
|
+
});
|
|
2978
|
+
function videoToolConstraints(row) {
|
|
2979
|
+
if (row.type !== "video-tool") return void 0;
|
|
2980
|
+
const parsed = ToolSchema.safeParse(row.constraints.tool);
|
|
2981
|
+
if (!parsed.success) return void 0;
|
|
2982
|
+
const { kind, upscaleFactor, maxOutputLongEdge, fps, outputFormats } = parsed.data;
|
|
2983
|
+
return {
|
|
2984
|
+
kind,
|
|
2985
|
+
...upscaleFactor !== void 0 && { upscaleFactor },
|
|
2986
|
+
...maxOutputLongEdge !== void 0 && { maxOutputLongEdge },
|
|
2987
|
+
...fps !== void 0 && { fps },
|
|
2988
|
+
...outputFormats !== void 0 && { outputFormats }
|
|
2989
|
+
};
|
|
2990
|
+
}
|
|
2991
|
+
function resolutionTier(width, height) {
|
|
2992
|
+
const shortEdge = Math.min(width, height);
|
|
2993
|
+
if (shortEdge <= 360) return "360p";
|
|
2994
|
+
if (shortEdge <= 480) return "480p";
|
|
2995
|
+
if (shortEdge <= 720) return "720p";
|
|
2996
|
+
if (shortEdge <= 1080) return "1080p";
|
|
2997
|
+
if (shortEdge <= 1440) return "2k";
|
|
2998
|
+
return "4k";
|
|
2999
|
+
}
|
|
3000
|
+
function fail(error) {
|
|
3001
|
+
return { ok: false, error };
|
|
3002
|
+
}
|
|
3003
|
+
function planVideoTool(row, req) {
|
|
3004
|
+
const tool = videoToolConstraints(row);
|
|
3005
|
+
if (!tool) return fail(`${row.id} is not a video tool`);
|
|
3006
|
+
const { width, height, durationSeconds, fps } = req.source;
|
|
3007
|
+
if (!(width > 0 && height > 0 && durationSeconds > 0)) {
|
|
3008
|
+
return fail("The source video's width, height and duration are required");
|
|
3009
|
+
}
|
|
3010
|
+
const maxSeconds = row.constraints.sourceVideoSeconds?.max;
|
|
3011
|
+
if (maxSeconds !== void 0 && durationSeconds > maxSeconds) {
|
|
3012
|
+
return fail(`${row.label} takes source videos up to ${maxSeconds} seconds.`);
|
|
3013
|
+
}
|
|
3014
|
+
const base = {
|
|
3015
|
+
durationSeconds,
|
|
3016
|
+
...fps !== void 0 && { fps }
|
|
3017
|
+
};
|
|
3018
|
+
if (tool.kind === "upscale") {
|
|
3019
|
+
const factor = req.upscaleFactor;
|
|
3020
|
+
if (factor === void 0) return fail("An upscale factor is required");
|
|
3021
|
+
const range = tool.upscaleFactor;
|
|
3022
|
+
if (range && (factor < range.min || factor > range.max)) {
|
|
3023
|
+
return fail(`${row.label} upscales by ${range.min}x to ${range.max}x.`);
|
|
3024
|
+
}
|
|
3025
|
+
const outWidth = Math.round(width * factor);
|
|
3026
|
+
const outHeight = Math.round(height * factor);
|
|
3027
|
+
const limit = tool.maxOutputLongEdge;
|
|
3028
|
+
if (limit !== void 0 && Math.max(outWidth, outHeight) > limit) {
|
|
3029
|
+
return fail(
|
|
3030
|
+
`A ${factor}x upscale of a ${width}x${height} video passes the ${limit}px limit.`
|
|
3031
|
+
);
|
|
3032
|
+
}
|
|
3033
|
+
return {
|
|
3034
|
+
ok: true,
|
|
3035
|
+
output: {
|
|
3036
|
+
...base,
|
|
3037
|
+
width: outWidth,
|
|
3038
|
+
height: outHeight,
|
|
3039
|
+
resolution: resolutionTier(outWidth, outHeight),
|
|
3040
|
+
format: "h264"
|
|
3041
|
+
}
|
|
3042
|
+
};
|
|
3043
|
+
}
|
|
3044
|
+
if (tool.kind === "interpolate") {
|
|
3045
|
+
const target = req.targetFps;
|
|
3046
|
+
if (target === void 0 || !Number.isInteger(target)) {
|
|
3047
|
+
return fail("A whole-number target frame rate is required");
|
|
3048
|
+
}
|
|
3049
|
+
const range = tool.fps;
|
|
3050
|
+
if (range && (target < range.min || target > range.max)) {
|
|
3051
|
+
return fail(`${row.label} outputs ${range.min} to ${range.max} fps.`);
|
|
3052
|
+
}
|
|
3053
|
+
return {
|
|
3054
|
+
ok: true,
|
|
3055
|
+
output: {
|
|
3056
|
+
durationSeconds,
|
|
3057
|
+
fps: target,
|
|
3058
|
+
width,
|
|
3059
|
+
height,
|
|
3060
|
+
resolution: resolutionTier(width, height),
|
|
3061
|
+
format: "h264"
|
|
3062
|
+
}
|
|
3063
|
+
};
|
|
3064
|
+
}
|
|
3065
|
+
const formats = tool.outputFormats ?? ["h265"];
|
|
3066
|
+
const format = req.outputFormat ?? formats[0] ?? "h265";
|
|
3067
|
+
if (!formats.includes(format)) {
|
|
3068
|
+
return fail(`${row.label} writes ${formats.join(" or ")}.`);
|
|
3069
|
+
}
|
|
3070
|
+
return {
|
|
3071
|
+
ok: true,
|
|
3072
|
+
output: { ...base, width, height, resolution: resolutionTier(width, height), format }
|
|
3073
|
+
};
|
|
3074
|
+
}
|
|
3075
|
+
|
|
2785
3076
|
// src/resolve-options.ts
|
|
2786
3077
|
var SIZE_ORDER = ["512", "1K", "2K", "4K"];
|
|
2787
3078
|
var RESOLUTION_ORDER = ["360p", "480p", "720p", "768p", "1080p", "2k", "4k"];
|
|
@@ -3270,6 +3561,7 @@ export {
|
|
|
3270
3561
|
SurfaceSchema,
|
|
3271
3562
|
TEXT_MODELS,
|
|
3272
3563
|
VIDEO_MODELS,
|
|
3564
|
+
VIDEO_TOOL_MODELS,
|
|
3273
3565
|
billedAudio,
|
|
3274
3566
|
compareCatalogOrder,
|
|
3275
3567
|
isListed,
|
|
@@ -3280,14 +3572,17 @@ export {
|
|
|
3280
3572
|
nearestAspectRatio,
|
|
3281
3573
|
normalizeExposure,
|
|
3282
3574
|
outputAudio,
|
|
3575
|
+
planVideoTool,
|
|
3283
3576
|
primeCatalog,
|
|
3284
3577
|
promptConventions,
|
|
3285
3578
|
resetLiveCatalog,
|
|
3579
|
+
resolutionTier,
|
|
3286
3580
|
resolveAudioOptions,
|
|
3287
3581
|
resolveImageOptions,
|
|
3288
3582
|
resolveOptions,
|
|
3289
3583
|
resolveVideoOptions,
|
|
3290
3584
|
sortCatalogRows,
|
|
3291
|
-
videoLengthViolation
|
|
3585
|
+
videoLengthViolation,
|
|
3586
|
+
videoToolConstraints
|
|
3292
3587
|
};
|
|
3293
3588
|
//# sourceMappingURL=catalog.js.map
|