@shop-os/modelkit 0.1.5 → 0.1.6
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/README.md +11 -11
- package/dist/index.cjs +538 -302
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +41 -9
- package/dist/index.d.ts +41 -9
- package/dist/index.js +537 -302
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -105,7 +105,11 @@ function geminiImage(id, label, aliases, sizes) {
|
|
|
105
105
|
adapter: "google-image",
|
|
106
106
|
providerModelId: id,
|
|
107
107
|
lifecycle: "active",
|
|
108
|
-
constraints: {
|
|
108
|
+
constraints: {
|
|
109
|
+
aspectRatios: [...GEMINI_RATIOS],
|
|
110
|
+
sizes,
|
|
111
|
+
supports: ["safetySettings", "temperature"]
|
|
112
|
+
},
|
|
109
113
|
defaults: { size: "1K", aspectRatio: "1:1" },
|
|
110
114
|
usage: { ...IMAGE_USAGE },
|
|
111
115
|
pricingKind: "image_size"
|
|
@@ -244,8 +248,20 @@ var IMAGE_MODELS = [
|
|
|
244
248
|
constraints: {
|
|
245
249
|
// 97:30 has no Ark size spelling; the A+ flow pads inputs to 97:30 and
|
|
246
250
|
// omits the ratio instead. Advertise only sizes the adapter can send.
|
|
247
|
-
aspectRatios: [
|
|
248
|
-
|
|
251
|
+
aspectRatios: [
|
|
252
|
+
"1:1",
|
|
253
|
+
"2:3",
|
|
254
|
+
"3:2",
|
|
255
|
+
"4:3",
|
|
256
|
+
"3:4",
|
|
257
|
+
"4:5",
|
|
258
|
+
"5:4",
|
|
259
|
+
"9:16",
|
|
260
|
+
"16:9",
|
|
261
|
+
"21:9",
|
|
262
|
+
"9:21"
|
|
263
|
+
],
|
|
264
|
+
sizes: ["1K", "2K", "4K"],
|
|
249
265
|
references: { images: 10 },
|
|
250
266
|
supports: ["seed"]
|
|
251
267
|
},
|
|
@@ -475,7 +491,7 @@ var OTHER_MODELS = [
|
|
|
475
491
|
constraints: {
|
|
476
492
|
references: { images: 1 },
|
|
477
493
|
requires: ["references"],
|
|
478
|
-
supports: ["scaleFactor", "outputFormat"]
|
|
494
|
+
supports: ["scaleFactor", "outputFormat", "upscale"]
|
|
479
495
|
},
|
|
480
496
|
defaults: { scaleFactor: 2, outputFormat: "png" },
|
|
481
497
|
usage: { unit: "compute_seconds", modality: "IMAGE" },
|
|
@@ -722,7 +738,7 @@ var VIDEO_MODELS = [
|
|
|
722
738
|
durations: [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
|
|
723
739
|
references: { images: 9, videos: 3, audios: 3, audioOnly: false },
|
|
724
740
|
ratioIgnoredWith: ["firstFrame"],
|
|
725
|
-
supports: ["generateAudio", "seed", "lastFrame"]
|
|
741
|
+
supports: ["generateAudio", "seed", "lastFrame", "watermark"]
|
|
726
742
|
},
|
|
727
743
|
defaults: {
|
|
728
744
|
durationSeconds: 5,
|
|
@@ -747,7 +763,7 @@ var VIDEO_MODELS = [
|
|
|
747
763
|
durations: [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
|
|
748
764
|
references: { images: 9, videos: 3, audios: 3, audioOnly: false },
|
|
749
765
|
ratioIgnoredWith: ["firstFrame"],
|
|
750
|
-
supports: ["generateAudio", "seed", "lastFrame"]
|
|
766
|
+
supports: ["generateAudio", "seed", "lastFrame", "watermark"]
|
|
751
767
|
},
|
|
752
768
|
defaults: {
|
|
753
769
|
durationSeconds: 5,
|
|
@@ -773,7 +789,7 @@ var VIDEO_MODELS = [
|
|
|
773
789
|
durations: { min: 4, max: 30 },
|
|
774
790
|
references: { images: 30, videos: 10, audios: 10 },
|
|
775
791
|
ratioIgnoredWith: ["firstFrame"],
|
|
776
|
-
supports: ["generateAudio", "seed", "lastFrame"]
|
|
792
|
+
supports: ["generateAudio", "seed", "lastFrame", "watermark"]
|
|
777
793
|
},
|
|
778
794
|
defaults: {
|
|
779
795
|
durationSeconds: 5,
|
|
@@ -800,7 +816,8 @@ var VIDEO_MODELS = [
|
|
|
800
816
|
references: { images: 7 },
|
|
801
817
|
supports: []
|
|
802
818
|
},
|
|
803
|
-
|
|
819
|
+
// No resolution default: xAI picks its own unless the caller asks.
|
|
820
|
+
defaults: { durationSeconds: 8, aspectRatio: "16:9" },
|
|
804
821
|
usage: { unit: "reported_cost_usd", modality: "VIDEO" },
|
|
805
822
|
pricingKind: "video_per_second"
|
|
806
823
|
},
|
|
@@ -894,7 +911,7 @@ var VIDEO_MODELS = [
|
|
|
894
911
|
aspectRatios: [...H3_RATIOS],
|
|
895
912
|
resolutions: ["480p", "768p", "2k", "4k"],
|
|
896
913
|
durations: { min: 5, max: 15 },
|
|
897
|
-
supports: ["seed", "promptExpansion"]
|
|
914
|
+
supports: ["seed", "promptExpansion", "lastFrame", "safetyChecker"]
|
|
898
915
|
},
|
|
899
916
|
defaults: {
|
|
900
917
|
durationSeconds: 5,
|
|
@@ -917,7 +934,7 @@ var VIDEO_MODELS = [
|
|
|
917
934
|
aspectRatios: [...H3_RATIOS],
|
|
918
935
|
resolutions: ["480p", "768p"],
|
|
919
936
|
durations: { min: 5, max: 15 },
|
|
920
|
-
supports: ["seed", "promptExpansion"]
|
|
937
|
+
supports: ["seed", "promptExpansion", "lastFrame", "safetyChecker"]
|
|
921
938
|
},
|
|
922
939
|
defaults: {
|
|
923
940
|
durationSeconds: 5,
|
|
@@ -941,7 +958,7 @@ var VIDEO_MODELS = [
|
|
|
941
958
|
resolutions: ["480p", "768p", "2k", "4k"],
|
|
942
959
|
durations: { min: 5, max: 15 },
|
|
943
960
|
references: { images: 9, videos: 3, audios: 3, total: 12, audioOnly: false },
|
|
944
|
-
supports: ["seed", "promptExpansion"]
|
|
961
|
+
supports: ["seed", "promptExpansion", "safetyChecker"]
|
|
945
962
|
},
|
|
946
963
|
defaults: {
|
|
947
964
|
durationSeconds: 5,
|
|
@@ -965,7 +982,7 @@ var VIDEO_MODELS = [
|
|
|
965
982
|
resolutions: ["480p", "768p"],
|
|
966
983
|
durations: { min: 5, max: 15 },
|
|
967
984
|
references: { images: 9, videos: 3, audios: 3, total: 12, audioOnly: false },
|
|
968
|
-
supports: ["seed", "promptExpansion"]
|
|
985
|
+
supports: ["seed", "promptExpansion", "safetyChecker"]
|
|
969
986
|
},
|
|
970
987
|
defaults: {
|
|
971
988
|
durationSeconds: 5,
|
|
@@ -1093,19 +1110,22 @@ function resolveTier(field, code, requested, supported, order, model, onUnsuppor
|
|
|
1093
1110
|
});
|
|
1094
1111
|
return to;
|
|
1095
1112
|
}
|
|
1096
|
-
function resolveDuration(requested, durations, model, warnings) {
|
|
1113
|
+
function resolveDuration(requested, durations, model, onUnsupported, warnings) {
|
|
1097
1114
|
if (requested === void 0 || !durations) return requested;
|
|
1098
|
-
|
|
1099
|
-
if (
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
if (to === requested) return requested;
|
|
1115
|
+
const inSet = Array.isArray(durations) ? durations.includes(requested) : requested >= durations.min && requested <= durations.max;
|
|
1116
|
+
if (inSet) return requested;
|
|
1117
|
+
if (onUnsupported === "error") {
|
|
1118
|
+
const supported = Array.isArray(durations) ? `Supported: ${durations.join(", ")}.` : `Supported range: ${durations.min}-${durations.max}.`;
|
|
1119
|
+
throw new ModelKitError({
|
|
1120
|
+
code: "unsupported_option",
|
|
1121
|
+
message: `${model.id} does not support durationSeconds ${requested}. ${supported}`,
|
|
1122
|
+
model: model.id
|
|
1123
|
+
});
|
|
1108
1124
|
}
|
|
1125
|
+
const to = Array.isArray(durations) ? durations.reduce(
|
|
1126
|
+
(best, d) => Math.abs(d - requested) < Math.abs(best - requested) ? d : best,
|
|
1127
|
+
durations[0] ?? requested
|
|
1128
|
+
) : Math.min(Math.max(requested, durations.min), durations.max);
|
|
1109
1129
|
warnings.push({
|
|
1110
1130
|
code: "duration_coerced",
|
|
1111
1131
|
field: "durationSeconds",
|
|
@@ -1115,6 +1135,26 @@ function resolveDuration(requested, durations, model, warnings) {
|
|
|
1115
1135
|
});
|
|
1116
1136
|
return to;
|
|
1117
1137
|
}
|
|
1138
|
+
function resolveAspectRatio(requested, supported, model, onUnsupported, warnings) {
|
|
1139
|
+
if (requested === void 0 || requested === "adaptive" || !supported) return requested;
|
|
1140
|
+
if (supported.includes(requested)) return requested;
|
|
1141
|
+
if (onUnsupported === "error") {
|
|
1142
|
+
throw new ModelKitError({
|
|
1143
|
+
code: "unsupported_option",
|
|
1144
|
+
message: `${model.id} does not support aspectRatio "${requested}". Supported: ${supported.join(", ")}.`,
|
|
1145
|
+
model: model.id
|
|
1146
|
+
});
|
|
1147
|
+
}
|
|
1148
|
+
const to = nearestAspectRatio(requested, supported);
|
|
1149
|
+
warnings.push({
|
|
1150
|
+
code: "ratio_coerced",
|
|
1151
|
+
field: "aspectRatio",
|
|
1152
|
+
from: requested,
|
|
1153
|
+
to,
|
|
1154
|
+
message: `aspect ratio ${requested} coerced to ${to} for ${model.id}`
|
|
1155
|
+
});
|
|
1156
|
+
return to;
|
|
1157
|
+
}
|
|
1118
1158
|
function compact(refs) {
|
|
1119
1159
|
return (refs ?? []).filter((r) => Boolean(r));
|
|
1120
1160
|
}
|
|
@@ -1133,17 +1173,14 @@ function resolveImageOptions(model, request, onUnsupported = "error") {
|
|
|
1133
1173
|
const warnings = [];
|
|
1134
1174
|
const c = model.constraints;
|
|
1135
1175
|
const merged = { ...model.defaults, ...stripUndefined(request), model: model.id };
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
});
|
|
1145
|
-
merged.aspectRatio = to;
|
|
1146
|
-
}
|
|
1176
|
+
const aspectRatio = resolveAspectRatio(
|
|
1177
|
+
merged.aspectRatio,
|
|
1178
|
+
c.aspectRatios,
|
|
1179
|
+
model,
|
|
1180
|
+
onUnsupported,
|
|
1181
|
+
warnings
|
|
1182
|
+
);
|
|
1183
|
+
if (aspectRatio !== void 0) merged.aspectRatio = aspectRatio;
|
|
1147
1184
|
const size = resolveTier(
|
|
1148
1185
|
"size",
|
|
1149
1186
|
"size_coerced",
|
|
@@ -1177,7 +1214,9 @@ function resolveImageOptions(model, request, onUnsupported = "error") {
|
|
|
1177
1214
|
"count",
|
|
1178
1215
|
"outputFormat",
|
|
1179
1216
|
"scaleFactor",
|
|
1180
|
-
"safetySettings"
|
|
1217
|
+
"safetySettings",
|
|
1218
|
+
"temperature",
|
|
1219
|
+
"upscale"
|
|
1181
1220
|
]);
|
|
1182
1221
|
return { request: merged, warnings };
|
|
1183
1222
|
}
|
|
@@ -1207,17 +1246,14 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
|
|
|
1207
1246
|
delete merged.aspectRatio;
|
|
1208
1247
|
}
|
|
1209
1248
|
}
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
});
|
|
1219
|
-
merged.aspectRatio = to;
|
|
1220
|
-
}
|
|
1249
|
+
const aspectRatio = resolveAspectRatio(
|
|
1250
|
+
merged.aspectRatio,
|
|
1251
|
+
c.aspectRatios,
|
|
1252
|
+
model,
|
|
1253
|
+
onUnsupported,
|
|
1254
|
+
warnings
|
|
1255
|
+
);
|
|
1256
|
+
if (aspectRatio !== void 0) merged.aspectRatio = aspectRatio;
|
|
1221
1257
|
const resolution = resolveTier(
|
|
1222
1258
|
"resolution",
|
|
1223
1259
|
"resolution_coerced",
|
|
@@ -1229,7 +1265,13 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
|
|
|
1229
1265
|
warnings
|
|
1230
1266
|
);
|
|
1231
1267
|
if (resolution !== void 0) merged.resolution = resolution;
|
|
1232
|
-
const duration = resolveDuration(
|
|
1268
|
+
const duration = resolveDuration(
|
|
1269
|
+
merged.durationSeconds,
|
|
1270
|
+
c.durations,
|
|
1271
|
+
model,
|
|
1272
|
+
onUnsupported,
|
|
1273
|
+
warnings
|
|
1274
|
+
);
|
|
1233
1275
|
if (duration !== void 0) merged.durationSeconds = duration;
|
|
1234
1276
|
const limits = c.references ?? {};
|
|
1235
1277
|
let images = trim(
|
|
@@ -1284,10 +1326,45 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
|
|
|
1284
1326
|
"cfgScale",
|
|
1285
1327
|
"generateAudio",
|
|
1286
1328
|
"promptExpansion",
|
|
1287
|
-
"lastFrame"
|
|
1329
|
+
"lastFrame",
|
|
1330
|
+
"watermark",
|
|
1331
|
+
"safetyChecker"
|
|
1288
1332
|
]);
|
|
1289
1333
|
return { request: merged, warnings };
|
|
1290
1334
|
}
|
|
1335
|
+
function resolveAudioOptions(model, request, onUnsupported = "error") {
|
|
1336
|
+
const warnings = [];
|
|
1337
|
+
const c = model.constraints;
|
|
1338
|
+
const merged = { ...model.defaults, ...stripUndefined(request), model: model.id };
|
|
1339
|
+
for (const input of c.requires ?? []) {
|
|
1340
|
+
const present = input === "references" ? compact(merged.references).length > 0 : input === "sourceVideo" && merged.sourceVideo !== void 0;
|
|
1341
|
+
if (!present)
|
|
1342
|
+
throw new ModelKitError({
|
|
1343
|
+
code: "missing_input",
|
|
1344
|
+
message: `${model.id} requires ${input}`,
|
|
1345
|
+
model: model.id
|
|
1346
|
+
});
|
|
1347
|
+
}
|
|
1348
|
+
const duration = resolveDuration(
|
|
1349
|
+
merged.durationSeconds,
|
|
1350
|
+
c.durations,
|
|
1351
|
+
model,
|
|
1352
|
+
onUnsupported,
|
|
1353
|
+
warnings
|
|
1354
|
+
);
|
|
1355
|
+
if (duration !== void 0) merged.durationSeconds = duration;
|
|
1356
|
+
const references = trim(
|
|
1357
|
+
"references",
|
|
1358
|
+
compact(merged.references),
|
|
1359
|
+
c.references?.images ?? c.references?.total,
|
|
1360
|
+
model,
|
|
1361
|
+
warnings
|
|
1362
|
+
);
|
|
1363
|
+
if (references.length > 0) merged.references = references;
|
|
1364
|
+
else delete merged.references;
|
|
1365
|
+
dropUnsupported(merged, model, warnings, ["seed", "negativePrompt", "instrumental"]);
|
|
1366
|
+
return { request: merged, warnings };
|
|
1367
|
+
}
|
|
1291
1368
|
function dropUnsupported(req, model, warnings, fields) {
|
|
1292
1369
|
const supports = model.constraints.supports ?? [];
|
|
1293
1370
|
for (const field of fields) {
|
|
@@ -1329,6 +1406,9 @@ function hasAll(keys, names) {
|
|
|
1329
1406
|
(n) => Boolean(keys[n]) && (n !== "higgsfield" || Boolean(keys.higgsfieldSecret))
|
|
1330
1407
|
);
|
|
1331
1408
|
}
|
|
1409
|
+
function missingEnterpriseKeys(config, names) {
|
|
1410
|
+
return names.filter((name) => !hasAll(config.keys.enterprise, [name]));
|
|
1411
|
+
}
|
|
1332
1412
|
function resolveKeys(config, names, tier = "pro") {
|
|
1333
1413
|
if (tier === "enterprise" && hasAll(config.keys.enterprise, names))
|
|
1334
1414
|
return config.keys.enterprise;
|
|
@@ -1361,7 +1441,6 @@ function keysFromEnv(env, prefix = "") {
|
|
|
1361
1441
|
set("prodia", pick("PRODIA_API_KEY", "PRODIA_TOKEN"));
|
|
1362
1442
|
set("higgsfield", pick("HIGGSFIELD_API_KEY"));
|
|
1363
1443
|
set("higgsfieldSecret", pick("HIGGSFIELD_API_SECRET"));
|
|
1364
|
-
set("openrouter", pick("OPENROUTER_API_KEY"));
|
|
1365
1444
|
set("cloudflare", pick("CLOUDFLARE_AI_GATEWAY_TOKEN", "CF_AIG_TOKEN"));
|
|
1366
1445
|
return keys;
|
|
1367
1446
|
}
|
|
@@ -1409,7 +1488,9 @@ var textBody = z2.string();
|
|
|
1409
1488
|
function classifyHttpError(status, body, provider, model) {
|
|
1410
1489
|
const asText = textBody.safeParse(body);
|
|
1411
1490
|
const text2 = asText.success ? asText.data : JSON.stringify(body);
|
|
1412
|
-
const blocked = /
|
|
1491
|
+
const blocked = /content_policy_violation|blockReason|PROHIBITED_CONTENT|moderation_blocked|safety(?![_A-Za-z])/i.test(
|
|
1492
|
+
text2
|
|
1493
|
+
);
|
|
1413
1494
|
let code = "provider_rejected";
|
|
1414
1495
|
if (blocked) code = "content_blocked";
|
|
1415
1496
|
else if (status === 401 || status === 403) code = "auth";
|
|
@@ -1430,8 +1511,8 @@ function classifyHttpError(status, body, provider, model) {
|
|
|
1430
1511
|
}
|
|
1431
1512
|
function shouldRetry(err) {
|
|
1432
1513
|
if (err instanceof ModelKitError) return err.retryable;
|
|
1433
|
-
if (err.name === "AbortError"
|
|
1434
|
-
|
|
1514
|
+
if (err.name === "AbortError") return false;
|
|
1515
|
+
if (/ECONNRESET|ETIMEDOUT|fetch failed|socket hang up/i.test(err.message)) return true;
|
|
1435
1516
|
return false;
|
|
1436
1517
|
}
|
|
1437
1518
|
async function withRetry(fn, opts = {}) {
|
|
@@ -1623,6 +1704,12 @@ import { z as z4 } from "zod";
|
|
|
1623
1704
|
function isUrlRef(ref) {
|
|
1624
1705
|
return "url" in ref;
|
|
1625
1706
|
}
|
|
1707
|
+
function abortedError() {
|
|
1708
|
+
return new ModelKitError({ code: "timeout", message: "aborted", retryable: false });
|
|
1709
|
+
}
|
|
1710
|
+
function throwIfAborted(signal) {
|
|
1711
|
+
if (signal?.aborted) throw abortedError();
|
|
1712
|
+
}
|
|
1626
1713
|
function mediaRefToBase64(bytes) {
|
|
1627
1714
|
let binary = "";
|
|
1628
1715
|
const CHUNK = 32768;
|
|
@@ -1637,10 +1724,34 @@ function base64ToBytes(b64) {
|
|
|
1637
1724
|
for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i);
|
|
1638
1725
|
return out;
|
|
1639
1726
|
}
|
|
1640
|
-
|
|
1727
|
+
function mediaRefToDataUrl(ref) {
|
|
1728
|
+
if (isUrlRef(ref)) return ref.url;
|
|
1729
|
+
return `data:${ref.mime};base64,${mediaRefToBase64(ref.bytes)}`;
|
|
1730
|
+
}
|
|
1731
|
+
var refToUrl = mediaRefToDataUrl;
|
|
1732
|
+
async function readBody(res) {
|
|
1733
|
+
const text2 = await res.text().catch(() => "");
|
|
1734
|
+
try {
|
|
1735
|
+
const decoded = JsonValueSchema.safeParse(JSON.parse(text2));
|
|
1736
|
+
return decoded.success ? decoded.data : text2;
|
|
1737
|
+
} catch {
|
|
1738
|
+
return text2;
|
|
1739
|
+
}
|
|
1740
|
+
}
|
|
1741
|
+
async function mediaRefToBytes(ref, fetch, options = {}) {
|
|
1641
1742
|
if (!isUrlRef(ref)) return { bytes: ref.bytes, mime: ref.mime };
|
|
1642
|
-
const
|
|
1643
|
-
if (
|
|
1743
|
+
const init = {};
|
|
1744
|
+
if (options.signal !== void 0) init.signal = options.signal;
|
|
1745
|
+
const res = await fetch(ref.url, init);
|
|
1746
|
+
if (!res.ok) {
|
|
1747
|
+
const text2 = await res.text().catch(() => "");
|
|
1748
|
+
throw classifyHttpError(
|
|
1749
|
+
res.status,
|
|
1750
|
+
text2,
|
|
1751
|
+
options.provider ?? "media-reference",
|
|
1752
|
+
options.model
|
|
1753
|
+
);
|
|
1754
|
+
}
|
|
1644
1755
|
const mime = res.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase() || "image/png";
|
|
1645
1756
|
return { bytes: new Uint8Array(await res.arrayBuffer()), mime };
|
|
1646
1757
|
}
|
|
@@ -1698,16 +1809,6 @@ var GATEWAY_SLUGS = {
|
|
|
1698
1809
|
perplexity: "perplexity-ai",
|
|
1699
1810
|
deepseek: "deepseek"
|
|
1700
1811
|
};
|
|
1701
|
-
var OPENROUTER_VENDORS = {
|
|
1702
|
-
openai: "openai",
|
|
1703
|
-
anthropic: "anthropic",
|
|
1704
|
-
google: "google",
|
|
1705
|
-
xai: "x-ai",
|
|
1706
|
-
perplexity: "perplexity",
|
|
1707
|
-
deepseek: "deepseek",
|
|
1708
|
-
moonshot: "moonshotai",
|
|
1709
|
-
minimax: "minimax"
|
|
1710
|
-
};
|
|
1711
1812
|
function detectTextProvider(modelId) {
|
|
1712
1813
|
const id = modelId.toLowerCase();
|
|
1713
1814
|
if (id.startsWith("claude") || id.includes("anthropic.")) return "anthropic";
|
|
@@ -1724,14 +1825,17 @@ function detectTextProvider(modelId) {
|
|
|
1724
1825
|
message: `ai-sdk-text cannot detect a provider for "${modelId}". Set providerOptions.provider to one of ${TEXT_PROVIDERS.join(", ")}.`
|
|
1725
1826
|
});
|
|
1726
1827
|
}
|
|
1727
|
-
function textKeyName(model,
|
|
1728
|
-
if (routing.text === "openrouter") return "openrouter";
|
|
1828
|
+
function textKeyName(model, _routing) {
|
|
1729
1829
|
return textProviderOf(model);
|
|
1730
1830
|
}
|
|
1731
1831
|
function textProviderOf(model) {
|
|
1732
1832
|
const explicit = model.providerOptions?.["modelkit"]?.["provider"];
|
|
1733
1833
|
return isTextProvider(explicit) ? explicit : detectTextProvider(model.providerModelId);
|
|
1734
1834
|
}
|
|
1835
|
+
function textUsesCloudflareGateway(model, routing) {
|
|
1836
|
+
if (routing.text !== "cloudflare") return false;
|
|
1837
|
+
return GATEWAY_SLUGS[textProviderOf(model)] !== void 0;
|
|
1838
|
+
}
|
|
1735
1839
|
function nativeClientFor(provider) {
|
|
1736
1840
|
switch (provider) {
|
|
1737
1841
|
case "openai":
|
|
@@ -1764,16 +1868,6 @@ function resolveTextRoute(ctx) {
|
|
|
1764
1868
|
retryable: false
|
|
1765
1869
|
});
|
|
1766
1870
|
}
|
|
1767
|
-
if (mode === "openrouter") {
|
|
1768
|
-
const modelId = ctx.model.providerModelId.includes("/") ? ctx.model.providerModelId : `${OPENROUTER_VENDORS[provider]}/${ctx.model.providerModelId}`;
|
|
1769
|
-
return {
|
|
1770
|
-
provider,
|
|
1771
|
-
client: "openai-compatible",
|
|
1772
|
-
modelId,
|
|
1773
|
-
keyName: "openrouter",
|
|
1774
|
-
baseURL: "https://openrouter.ai/api/v1"
|
|
1775
|
-
};
|
|
1776
|
-
}
|
|
1777
1871
|
const compatBase = OPENAI_COMPATIBLE_BASE_URLS[provider];
|
|
1778
1872
|
const route2 = {
|
|
1779
1873
|
provider,
|
|
@@ -1841,7 +1935,7 @@ var aiSdkTextAdapter = {
|
|
|
1841
1935
|
case "openai-compatible":
|
|
1842
1936
|
return createOpenAI({
|
|
1843
1937
|
...settings,
|
|
1844
|
-
name: route2.provider
|
|
1938
|
+
name: route2.provider
|
|
1845
1939
|
}).chat(route2.modelId);
|
|
1846
1940
|
case "openai":
|
|
1847
1941
|
return createOpenAI(settings)(route2.modelId);
|
|
@@ -1854,8 +1948,9 @@ function requiredKeys(model, config) {
|
|
|
1854
1948
|
if (model.adapter === "fal" && config.routing?.fal === "cloudflare-passthrough")
|
|
1855
1949
|
return ["cloudflare"];
|
|
1856
1950
|
if (model.adapter === "ai-sdk-text") {
|
|
1857
|
-
const
|
|
1858
|
-
|
|
1951
|
+
const routing = config.routing ?? {};
|
|
1952
|
+
const names = [textKeyName(model, routing)];
|
|
1953
|
+
if (textUsesCloudflareGateway(model, routing)) names.push("cloudflare");
|
|
1859
1954
|
return names;
|
|
1860
1955
|
}
|
|
1861
1956
|
return ADAPTER_KEYS[model.adapter];
|
|
@@ -1929,6 +2024,11 @@ function pushIgnored(warnings, field, from, modelId) {
|
|
|
1929
2024
|
message: `${modelId} provider instance does not support ${field}; ignored`
|
|
1930
2025
|
});
|
|
1931
2026
|
}
|
|
2027
|
+
function withoutModelkit(options) {
|
|
2028
|
+
if (!options) return {};
|
|
2029
|
+
const { modelkit: _modelkit, ...rest } = options;
|
|
2030
|
+
return rest;
|
|
2031
|
+
}
|
|
1932
2032
|
function logCoercions(logger, modelId, warnings) {
|
|
1933
2033
|
if (warnings.length === 0) return;
|
|
1934
2034
|
logger.warn(`[modelkit] ${modelId} request coerced`, { model: modelId, warnings });
|
|
@@ -1945,7 +2045,16 @@ function createModelKit(config, adapters) {
|
|
|
1945
2045
|
message: `No adapter registered for ${model.adapter}`,
|
|
1946
2046
|
model: model.id
|
|
1947
2047
|
});
|
|
1948
|
-
const
|
|
2048
|
+
const names = requiredKeys(model, config);
|
|
2049
|
+
if (call.tier === "enterprise") {
|
|
2050
|
+
const missing = missingEnterpriseKeys(config, names);
|
|
2051
|
+
if (missing.length > 0)
|
|
2052
|
+
logger.warn(
|
|
2053
|
+
`[modelkit] enterprise keys incomplete for ${model.adapter}; using pro`,
|
|
2054
|
+
{ missing }
|
|
2055
|
+
);
|
|
2056
|
+
}
|
|
2057
|
+
const keys = resolveKeys(config, names, call.tier);
|
|
1949
2058
|
const ctx = {
|
|
1950
2059
|
model,
|
|
1951
2060
|
keys,
|
|
@@ -2266,8 +2375,15 @@ function createModelKit(config, adapters) {
|
|
|
2266
2375
|
model: model.id
|
|
2267
2376
|
});
|
|
2268
2377
|
}
|
|
2269
|
-
const
|
|
2270
|
-
const {
|
|
2378
|
+
const { abortSignal: _signal, ...request } = req;
|
|
2379
|
+
const { request: resolved, warnings } = resolveAudioOptions(
|
|
2380
|
+
model,
|
|
2381
|
+
request,
|
|
2382
|
+
call.onUnsupported ?? "error"
|
|
2383
|
+
);
|
|
2384
|
+
logCoercions(logger, model.id, warnings);
|
|
2385
|
+
const signal = combineSignals(req.abortSignal, call.signal);
|
|
2386
|
+
const { adapter, ctx } = context(model, signal ? { ...call, signal } : call, warnings);
|
|
2271
2387
|
if (!adapter.generateAudio) {
|
|
2272
2388
|
throw new ModelKitError({
|
|
2273
2389
|
code: "unsupported_option",
|
|
@@ -2275,11 +2391,7 @@ function createModelKit(config, adapters) {
|
|
|
2275
2391
|
model: model.id
|
|
2276
2392
|
});
|
|
2277
2393
|
}
|
|
2278
|
-
const result = await adapter.generateAudio(
|
|
2279
|
-
{ ...model.defaults, ...req, model: model.id },
|
|
2280
|
-
ctx
|
|
2281
|
-
);
|
|
2282
|
-
logCoercions(logger, model.id, warnings);
|
|
2394
|
+
const result = await adapter.generateAudio(resolved, ctx);
|
|
2283
2395
|
await emit({ ...result.usage, model: model.id, unit: model.usage.unit });
|
|
2284
2396
|
return result;
|
|
2285
2397
|
},
|
|
@@ -2300,7 +2412,7 @@ function createModelKit(config, adapters) {
|
|
|
2300
2412
|
});
|
|
2301
2413
|
return {
|
|
2302
2414
|
model,
|
|
2303
|
-
providerOptions: entry.providerOptions
|
|
2415
|
+
providerOptions: withoutModelkit(entry.providerOptions),
|
|
2304
2416
|
catalog: entry
|
|
2305
2417
|
};
|
|
2306
2418
|
},
|
|
@@ -2336,7 +2448,9 @@ function createModelKit(config, adapters) {
|
|
|
2336
2448
|
...textAbortOptions(options.abortSignal, call.signal),
|
|
2337
2449
|
model: target.languageModel,
|
|
2338
2450
|
providerOptions: {},
|
|
2339
|
-
prepareStep: steps.wrap(
|
|
2451
|
+
prepareStep: steps.wrap(
|
|
2452
|
+
options.prepareStep ?? options.experimental_prepareStep
|
|
2453
|
+
),
|
|
2340
2454
|
onFinish: async (event) => {
|
|
2341
2455
|
for (const usage2 of steps.usage(event.steps)) await emit(withRowUnit(usage2));
|
|
2342
2456
|
await callerOnFinish?.(event);
|
|
@@ -2393,6 +2507,7 @@ var SEEDREAM_SIZES = {
|
|
|
2393
2507
|
"3:2": "1248x832",
|
|
2394
2508
|
"2:3": "832x1248",
|
|
2395
2509
|
"21:9": "1568x672",
|
|
2510
|
+
"9:21": "672x1568",
|
|
2396
2511
|
"4:5": "864x1080",
|
|
2397
2512
|
"5:4": "1080x864"
|
|
2398
2513
|
},
|
|
@@ -2405,16 +2520,34 @@ var SEEDREAM_SIZES = {
|
|
|
2405
2520
|
"3:2": "2496x1664",
|
|
2406
2521
|
"2:3": "1664x2496",
|
|
2407
2522
|
"21:9": "3136x1344",
|
|
2523
|
+
"9:21": "1344x3136",
|
|
2408
2524
|
"4:5": "1728x2160",
|
|
2409
2525
|
"5:4": "2160x1728"
|
|
2526
|
+
},
|
|
2527
|
+
// 4K keeps the long edge at Ark's 4096 cap (a doubled 2K entry would exceed
|
|
2528
|
+
// it); sides are multiples of 16.
|
|
2529
|
+
"4K": {
|
|
2530
|
+
"1:1": "4096x4096",
|
|
2531
|
+
"4:3": "4096x3072",
|
|
2532
|
+
"3:4": "3072x4096",
|
|
2533
|
+
"16:9": "4096x2304",
|
|
2534
|
+
"9:16": "2304x4096",
|
|
2535
|
+
"3:2": "4096x2736",
|
|
2536
|
+
"2:3": "2736x4096",
|
|
2537
|
+
"21:9": "4096x1760",
|
|
2538
|
+
"9:21": "1760x4096",
|
|
2539
|
+
"4:5": "3280x4096",
|
|
2540
|
+
"5:4": "4096x3280"
|
|
2410
2541
|
}
|
|
2411
2542
|
};
|
|
2412
2543
|
var arkAdapter = {
|
|
2413
2544
|
id: "ark",
|
|
2414
2545
|
async generateImage(req, ctx) {
|
|
2546
|
+
throwIfAborted(ctx.signal);
|
|
2415
2547
|
return generateSeedreamImage(req, ctx);
|
|
2416
2548
|
},
|
|
2417
2549
|
async generateVideo(req, ctx) {
|
|
2550
|
+
throwIfAborted(ctx.signal);
|
|
2418
2551
|
return generateSeedanceVideo(req, ctx);
|
|
2419
2552
|
}
|
|
2420
2553
|
};
|
|
@@ -2434,7 +2567,7 @@ function arkKey(ctx) {
|
|
|
2434
2567
|
function throwArkError(status, body, model) {
|
|
2435
2568
|
const parsed = z5.string().safeParse(body);
|
|
2436
2569
|
const text2 = parsed.success ? parsed.data : JSON.stringify(body ?? "");
|
|
2437
|
-
if (/sensitive.?content|
|
|
2570
|
+
if (/sensitive.?content|human.?face/i.test(text2)) {
|
|
2438
2571
|
const init = {
|
|
2439
2572
|
code: "content_blocked",
|
|
2440
2573
|
message: `ark rejected the request: ${text2.slice(0, 500)}`,
|
|
@@ -2459,7 +2592,7 @@ function throwArkError(status, body, model) {
|
|
|
2459
2592
|
throw classifyHttpError(status, body, "ark", model);
|
|
2460
2593
|
}
|
|
2461
2594
|
function seedreamSize(aspect, size) {
|
|
2462
|
-
const tier = size === "
|
|
2595
|
+
const tier = size === "4K" || size === "1K" ? size : "2K";
|
|
2463
2596
|
const table = SEEDREAM_SIZES[tier];
|
|
2464
2597
|
return table[aspect ?? ""] ?? table["1:1"] ?? "2048x2048";
|
|
2465
2598
|
}
|
|
@@ -2470,10 +2603,6 @@ function sniffedImageMime(bytes) {
|
|
|
2470
2603
|
return "image/webp";
|
|
2471
2604
|
return "image/jpeg";
|
|
2472
2605
|
}
|
|
2473
|
-
function arkUrl(ref) {
|
|
2474
|
-
if ("url" in ref) return ref.url;
|
|
2475
|
-
return `data:${ref.mime};base64,${Buffer.from(ref.bytes).toString("base64")}`;
|
|
2476
|
-
}
|
|
2477
2606
|
var SeedreamImageSchema = z5.object({
|
|
2478
2607
|
url: z5.string().optional(),
|
|
2479
2608
|
b64_json: z5.string().optional()
|
|
@@ -2500,7 +2629,7 @@ async function generateSeedreamImage(req, ctx) {
|
|
|
2500
2629
|
const key = arkKey(ctx);
|
|
2501
2630
|
const modelId = ctx.model.id;
|
|
2502
2631
|
const size = seedreamSize(req.aspectRatio, req.size);
|
|
2503
|
-
const refs = (req.references ?? []).map(
|
|
2632
|
+
const refs = (req.references ?? []).map(refToUrl);
|
|
2504
2633
|
const body = {
|
|
2505
2634
|
model: ctx.model.providerModelId,
|
|
2506
2635
|
prompt: req.prompt,
|
|
@@ -2552,10 +2681,18 @@ async function generateSeedreamImage(req, ctx) {
|
|
|
2552
2681
|
if (req.quality !== void 0) usage2.imageQuality = req.quality;
|
|
2553
2682
|
return { images: [{ bytes, mime: sniffedImageMime(bytes) }], usage: usage2, raw: data };
|
|
2554
2683
|
}
|
|
2684
|
+
var SeedanceUsageSchema = z5.object({
|
|
2685
|
+
total_tokens: z5.number().optional(),
|
|
2686
|
+
completion_tokens: z5.number().optional()
|
|
2687
|
+
});
|
|
2555
2688
|
var SeedanceResponseSchema = z5.object({
|
|
2556
2689
|
id: z5.string().optional(),
|
|
2557
2690
|
status: z5.string().optional(),
|
|
2558
2691
|
content: z5.object({ video_url: z5.string().optional() }).optional(),
|
|
2692
|
+
usage: SeedanceUsageSchema.optional(),
|
|
2693
|
+
duration: z5.number().optional(),
|
|
2694
|
+
framespersecond: z5.number().optional(),
|
|
2695
|
+
resolution: z5.string().optional(),
|
|
2559
2696
|
error: z5.union([z5.string(), z5.object({ message: z5.string().optional() })]).optional()
|
|
2560
2697
|
});
|
|
2561
2698
|
var SeedanceErrorMessageSchema = z5.object({ message: z5.string().optional() });
|
|
@@ -2587,42 +2724,42 @@ async function generateSeedanceVideo(req, ctx) {
|
|
|
2587
2724
|
if (req.firstFrame) {
|
|
2588
2725
|
content.push({
|
|
2589
2726
|
type: "image_url",
|
|
2590
|
-
image_url: { url:
|
|
2727
|
+
image_url: { url: refToUrl(req.firstFrame) },
|
|
2591
2728
|
role: "first_frame"
|
|
2592
2729
|
});
|
|
2593
2730
|
}
|
|
2594
2731
|
if (req.lastFrame) {
|
|
2595
2732
|
content.push({
|
|
2596
2733
|
type: "image_url",
|
|
2597
|
-
image_url: { url:
|
|
2734
|
+
image_url: { url: refToUrl(req.lastFrame) },
|
|
2598
2735
|
role: "last_frame"
|
|
2599
2736
|
});
|
|
2600
2737
|
}
|
|
2601
2738
|
for (const ref of req.referenceImages ?? []) {
|
|
2602
2739
|
content.push({
|
|
2603
2740
|
type: "image_url",
|
|
2604
|
-
image_url: { url:
|
|
2741
|
+
image_url: { url: refToUrl(ref) },
|
|
2605
2742
|
role: "reference_image"
|
|
2606
2743
|
});
|
|
2607
2744
|
}
|
|
2608
2745
|
if (req.sourceVideo) {
|
|
2609
2746
|
content.push({
|
|
2610
2747
|
type: "video_url",
|
|
2611
|
-
video_url: { url:
|
|
2748
|
+
video_url: { url: refToUrl(req.sourceVideo) },
|
|
2612
2749
|
role: "reference_video"
|
|
2613
2750
|
});
|
|
2614
2751
|
}
|
|
2615
2752
|
for (const ref of req.referenceVideos ?? []) {
|
|
2616
2753
|
content.push({
|
|
2617
2754
|
type: "video_url",
|
|
2618
|
-
video_url: { url:
|
|
2755
|
+
video_url: { url: refToUrl(ref) },
|
|
2619
2756
|
role: "reference_video"
|
|
2620
2757
|
});
|
|
2621
2758
|
}
|
|
2622
2759
|
for (const ref of req.referenceAudios ?? []) {
|
|
2623
2760
|
content.push({
|
|
2624
2761
|
type: "audio_url",
|
|
2625
|
-
audio_url: { url:
|
|
2762
|
+
audio_url: { url: refToUrl(ref) },
|
|
2626
2763
|
role: "reference_audio"
|
|
2627
2764
|
});
|
|
2628
2765
|
}
|
|
@@ -2636,6 +2773,7 @@ async function generateSeedanceVideo(req, ctx) {
|
|
|
2636
2773
|
if (!hasFrameAnchor && req.aspectRatio !== void 0) body.ratio = req.aspectRatio;
|
|
2637
2774
|
if (req.generateAudio !== void 0) body.generate_audio = req.generateAudio;
|
|
2638
2775
|
if (req.seed !== void 0) body.seed = req.seed;
|
|
2776
|
+
if (req.watermark !== void 0) body.watermark = req.watermark;
|
|
2639
2777
|
const submit = await withRetry(async () => {
|
|
2640
2778
|
const res = await arkFetch(ctx, `${arkBaseUrl(ctx)}${SUBMIT_PATH}`, {
|
|
2641
2779
|
method: "POST",
|
|
@@ -2699,6 +2837,11 @@ async function generateSeedanceVideo(req, ctx) {
|
|
|
2699
2837
|
"Seedance task succeeded but returned no video_url",
|
|
2700
2838
|
modelId
|
|
2701
2839
|
);
|
|
2840
|
+
const tokens = polled.usage;
|
|
2841
|
+
if (tokens?.total_tokens !== void 0 && tokens.completion_tokens !== void 0) {
|
|
2842
|
+
usage2.inputTokens = tokens.total_tokens - tokens.completion_tokens;
|
|
2843
|
+
usage2.outputTokens = tokens.completion_tokens;
|
|
2844
|
+
}
|
|
2702
2845
|
return {
|
|
2703
2846
|
video: { url, expiresAt: new Date(Date.now() + VIDEO_URL_TTL_MS) },
|
|
2704
2847
|
usage: usage2,
|
|
@@ -2762,24 +2905,17 @@ var defaultDeps = { createFalClient: defaultCreateFalClient };
|
|
|
2762
2905
|
function createFalAdapter(deps = defaultDeps) {
|
|
2763
2906
|
return {
|
|
2764
2907
|
id: "fal",
|
|
2765
|
-
generateImage: (req, ctx) =>
|
|
2766
|
-
|
|
2908
|
+
generateImage: (req, ctx) => {
|
|
2909
|
+
throwIfAborted(ctx.signal);
|
|
2910
|
+
return generateMuseImage(req, ctx, deps);
|
|
2911
|
+
},
|
|
2912
|
+
generateVideo: (req, ctx) => {
|
|
2913
|
+
throwIfAborted(ctx.signal);
|
|
2914
|
+
return generateFalVideo(req, ctx, deps);
|
|
2915
|
+
}
|
|
2767
2916
|
};
|
|
2768
2917
|
}
|
|
2769
2918
|
var falAdapter = createFalAdapter();
|
|
2770
|
-
function refToUrl(ref) {
|
|
2771
|
-
if ("url" in ref) return ref.url;
|
|
2772
|
-
return `data:${ref.mime};base64,${Buffer.from(ref.bytes).toString("base64")}`;
|
|
2773
|
-
}
|
|
2774
|
-
async function readBody(res) {
|
|
2775
|
-
const text2 = await res.text().catch(() => "");
|
|
2776
|
-
try {
|
|
2777
|
-
const decoded = JsonValueSchema.safeParse(JSON.parse(text2));
|
|
2778
|
-
return decoded.success ? decoded.data : text2;
|
|
2779
|
-
} catch {
|
|
2780
|
-
return text2;
|
|
2781
|
-
}
|
|
2782
|
-
}
|
|
2783
2919
|
var falDetailSchema = z6.object({ detail: JsonValueSchema });
|
|
2784
2920
|
function liftDetail(body) {
|
|
2785
2921
|
const parsed = falDetailSchema.safeParse(body);
|
|
@@ -3016,8 +3152,12 @@ async function generateMuseImage(req, ctx, deps) {
|
|
|
3016
3152
|
raw: payload
|
|
3017
3153
|
};
|
|
3018
3154
|
}
|
|
3155
|
+
var H3_MAX_MODEL_IDS = /* @__PURE__ */ new Set([
|
|
3156
|
+
"minimax/h3-max",
|
|
3157
|
+
"minimax/h3-max/reference-to-video"
|
|
3158
|
+
]);
|
|
3019
3159
|
function minimaxFamily(providerModelId) {
|
|
3020
|
-
return providerModelId.toLowerCase()
|
|
3160
|
+
return H3_MAX_MODEL_IDS.has(providerModelId.toLowerCase()) ? "h3-max" : "h3";
|
|
3021
3161
|
}
|
|
3022
3162
|
function minimaxBase(req, family) {
|
|
3023
3163
|
const resolution = (family === "h3-max" ? req.resolution ?? "768p" : req.resolution ?? "2k").toUpperCase();
|
|
@@ -3025,14 +3165,17 @@ function minimaxBase(req, family) {
|
|
|
3025
3165
|
prompt: req.prompt.trim(),
|
|
3026
3166
|
duration: req.durationSeconds ?? 5,
|
|
3027
3167
|
resolution,
|
|
3028
|
-
prompt_expansion_mode: req.promptExpansion ?? "balanced"
|
|
3029
|
-
enable_safety_checker: true
|
|
3168
|
+
prompt_expansion_mode: req.promptExpansion ?? "balanced"
|
|
3030
3169
|
};
|
|
3170
|
+
if (req.safetyChecker !== void 0) input.enable_safety_checker = req.safetyChecker;
|
|
3031
3171
|
if (req.seed !== void 0) input.seed = req.seed;
|
|
3032
3172
|
return input;
|
|
3033
3173
|
}
|
|
3174
|
+
var KLING_MODEL_IDS = /* @__PURE__ */ new Set([
|
|
3175
|
+
"fal-ai/kling-video/o1/video-to-video/reference"
|
|
3176
|
+
]);
|
|
3034
3177
|
function isKling(providerModelId) {
|
|
3035
|
-
return providerModelId.toLowerCase()
|
|
3178
|
+
return KLING_MODEL_IDS.has(providerModelId.toLowerCase());
|
|
3036
3179
|
}
|
|
3037
3180
|
function klingO1Input(req) {
|
|
3038
3181
|
const source = req.sourceVideo ? refToUrl(req.sourceVideo) : void 0;
|
|
@@ -3105,7 +3248,9 @@ async function generateFalVideo(req, ctx, deps) {
|
|
|
3105
3248
|
if (lastFrame) base.end_image_url = lastFrame;
|
|
3106
3249
|
} else {
|
|
3107
3250
|
endpoint = `minimax/${family}/text-to-video`;
|
|
3108
|
-
|
|
3251
|
+
if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive") {
|
|
3252
|
+
base.aspect_ratio = req.aspectRatio;
|
|
3253
|
+
}
|
|
3109
3254
|
}
|
|
3110
3255
|
if (ctx.routing.fal === "cloudflare-passthrough") {
|
|
3111
3256
|
return await passthroughVideoJob(ctx, req, endpoint, base);
|
|
@@ -3593,6 +3738,14 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
|
|
|
3593
3738
|
model: modelId
|
|
3594
3739
|
});
|
|
3595
3740
|
}
|
|
3741
|
+
if (req.lastFrame !== void 0 && req.firstFrame === void 0) {
|
|
3742
|
+
throw new ModelKitError({
|
|
3743
|
+
code: "missing_input",
|
|
3744
|
+
message: `${modelId} requires firstFrame when lastFrame is set`,
|
|
3745
|
+
provider: "google-genai",
|
|
3746
|
+
model: modelId
|
|
3747
|
+
});
|
|
3748
|
+
}
|
|
3596
3749
|
const duration = req.durationSeconds ?? 8;
|
|
3597
3750
|
const personGeneration = req.firstFrame ?? refs.length > 0 ? "allow_adult" : "allow_all";
|
|
3598
3751
|
let image;
|
|
@@ -3659,7 +3812,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
|
|
|
3659
3812
|
throwSdkError(cause, modelId);
|
|
3660
3813
|
}
|
|
3661
3814
|
};
|
|
3662
|
-
const jobId = operation.name ??
|
|
3815
|
+
const jobId = operation.name ?? crypto.randomUUID();
|
|
3663
3816
|
const usage2 = videoUsage2(ctx, req, duration);
|
|
3664
3817
|
return {
|
|
3665
3818
|
jobId,
|
|
@@ -3798,6 +3951,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
|
|
|
3798
3951
|
});
|
|
3799
3952
|
}
|
|
3800
3953
|
for (const ref of videos) {
|
|
3954
|
+
if (ref.label !== void 0) parts.push({ type: "text", text: ref.label });
|
|
3801
3955
|
const media = await resolveMedia(ref, ctx.fetch, ctx.signal, "video/mp4", modelId);
|
|
3802
3956
|
parts.push({
|
|
3803
3957
|
type: "video",
|
|
@@ -3806,6 +3960,8 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
|
|
|
3806
3960
|
});
|
|
3807
3961
|
}
|
|
3808
3962
|
if (req.firstFrame) {
|
|
3963
|
+
if (req.firstFrame.label !== void 0)
|
|
3964
|
+
parts.push({ type: "text", text: req.firstFrame.label });
|
|
3809
3965
|
const media = await resolveMedia(
|
|
3810
3966
|
req.firstFrame,
|
|
3811
3967
|
ctx.fetch,
|
|
@@ -3824,6 +3980,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
|
|
|
3824
3980
|
}
|
|
3825
3981
|
}
|
|
3826
3982
|
for (const ref of images) {
|
|
3983
|
+
if (ref.label !== void 0) parts.push({ type: "text", text: ref.label });
|
|
3827
3984
|
const media = await resolveMedia(ref, ctx.fetch, ctx.signal, "image/png", modelId);
|
|
3828
3985
|
if (media.bytes.length > OMNI_INLINE_LIMIT_BYTES) {
|
|
3829
3986
|
parts.push({
|
|
@@ -3867,7 +4024,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
|
|
|
3867
4024
|
} finally {
|
|
3868
4025
|
await cleanupUploads();
|
|
3869
4026
|
}
|
|
3870
|
-
const jobId = interaction.id ??
|
|
4027
|
+
const jobId = interaction.id ?? crypto.randomUUID();
|
|
3871
4028
|
const usage2 = videoUsage2(ctx, req, duration);
|
|
3872
4029
|
const getInteraction = async () => {
|
|
3873
4030
|
try {
|
|
@@ -4093,11 +4250,11 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
|
|
|
4093
4250
|
const model = google(ctx.model.providerModelId);
|
|
4094
4251
|
const content = [];
|
|
4095
4252
|
for (const ref of req.references ?? []) {
|
|
4253
|
+
if (ref.label !== void 0) content.push({ type: "text", text: ref.label });
|
|
4096
4254
|
if ("url" in ref) content.push({ type: "image", image: ref.url });
|
|
4097
4255
|
else content.push({ type: "image", image: ref.bytes, mediaType: ref.mime });
|
|
4098
4256
|
}
|
|
4099
4257
|
content.push({ type: "text", text: req.prompt });
|
|
4100
|
-
void ctx.call.postCropToAspect;
|
|
4101
4258
|
const imageConfig = {};
|
|
4102
4259
|
if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive")
|
|
4103
4260
|
imageConfig.aspectRatio = req.aspectRatio;
|
|
@@ -4113,7 +4270,7 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
|
|
|
4113
4270
|
const timeout = AbortSignal.timeout(GEMINI_IMAGE_TIMEOUT_MS);
|
|
4114
4271
|
const signal = ctx.signal !== void 0 ? AbortSignal.any([ctx.signal, timeout]) : timeout;
|
|
4115
4272
|
try {
|
|
4116
|
-
|
|
4273
|
+
const genOptions = {
|
|
4117
4274
|
model,
|
|
4118
4275
|
messages: [{ role: "user", content }],
|
|
4119
4276
|
maxRetries: 0,
|
|
@@ -4121,7 +4278,9 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
|
|
|
4121
4278
|
google: googleOptions
|
|
4122
4279
|
},
|
|
4123
4280
|
abortSignal: signal
|
|
4124
|
-
}
|
|
4281
|
+
};
|
|
4282
|
+
if (req.temperature !== void 0) genOptions.temperature = req.temperature;
|
|
4283
|
+
return await deps.runTextGeneration(genOptions);
|
|
4125
4284
|
} catch (cause) {
|
|
4126
4285
|
throw toProviderError(cause, ctx);
|
|
4127
4286
|
}
|
|
@@ -4325,26 +4484,14 @@ function headers(ctx) {
|
|
|
4325
4484
|
const { key, secret } = credentials(ctx);
|
|
4326
4485
|
return { "Content-Type": "application/json", "hf-api-key": key, "hf-secret": secret };
|
|
4327
4486
|
}
|
|
4328
|
-
function refToUrl2(ref) {
|
|
4329
|
-
if ("url" in ref) return ref.url;
|
|
4330
|
-
return `data:${ref.mime};base64,${Buffer.from(ref.bytes).toString("base64")}`;
|
|
4331
|
-
}
|
|
4332
|
-
async function readBody2(res) {
|
|
4333
|
-
const text2 = await res.text().catch(() => "");
|
|
4334
|
-
try {
|
|
4335
|
-
const decoded = JsonValueSchema.safeParse(JSON.parse(text2));
|
|
4336
|
-
return decoded.success ? decoded.data : text2;
|
|
4337
|
-
} catch {
|
|
4338
|
-
return text2;
|
|
4339
|
-
}
|
|
4340
|
-
}
|
|
4341
4487
|
function klingEndpoint(providerModelId) {
|
|
4342
4488
|
if (providerModelId.startsWith("http")) return providerModelId;
|
|
4343
4489
|
const path = providerModelId.startsWith("/") ? providerModelId.slice(1) : providerModelId;
|
|
4344
4490
|
return `${PLATFORM}/${path}`;
|
|
4345
4491
|
}
|
|
4346
|
-
|
|
4347
|
-
|
|
4492
|
+
var DOP_MODEL_IDS = /* @__PURE__ */ new Set(["dop", "dop-preview"]);
|
|
4493
|
+
function higgsfieldVideoKind(providerModelId) {
|
|
4494
|
+
return DOP_MODEL_IDS.has(providerModelId.toLowerCase()) ? "dop" : "kling";
|
|
4348
4495
|
}
|
|
4349
4496
|
function videoUsage3(ctx, req, duration) {
|
|
4350
4497
|
const event = {
|
|
@@ -4388,12 +4535,12 @@ async function createRequest(ctx, url, init) {
|
|
|
4388
4535
|
throw classifyThrown("higgsfield", cause, ctx.model.id);
|
|
4389
4536
|
}
|
|
4390
4537
|
if (!res.ok) {
|
|
4391
|
-
throw classifyHttpError(res.status, await
|
|
4538
|
+
throw classifyHttpError(res.status, await readBody(res), "higgsfield", ctx.model.id);
|
|
4392
4539
|
}
|
|
4393
4540
|
return res;
|
|
4394
4541
|
}
|
|
4395
4542
|
async function generateKlingVideo(req, ctx) {
|
|
4396
|
-
const firstFrame = req.firstFrame ?
|
|
4543
|
+
const firstFrame = req.firstFrame ? refToUrl(req.firstFrame) : void 0;
|
|
4397
4544
|
if (!firstFrame) {
|
|
4398
4545
|
throw new ModelKitError({
|
|
4399
4546
|
code: "missing_input",
|
|
@@ -4412,7 +4559,7 @@ async function generateKlingVideo(req, ctx) {
|
|
|
4412
4559
|
if (req.durationSeconds !== void 0) body.duration = req.durationSeconds;
|
|
4413
4560
|
if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive")
|
|
4414
4561
|
body.aspect_ratio = req.aspectRatio;
|
|
4415
|
-
if (req.lastFrame) body.last_image_url =
|
|
4562
|
+
if (req.lastFrame) body.last_image_url = refToUrl(req.lastFrame);
|
|
4416
4563
|
const endpoint = klingEndpoint(ctx.model.providerModelId);
|
|
4417
4564
|
const retryOptions = {};
|
|
4418
4565
|
if (ctx.signal !== void 0) retryOptions.signal = ctx.signal;
|
|
@@ -4438,9 +4585,9 @@ async function generateKlingVideo(req, ctx) {
|
|
|
4438
4585
|
} catch {
|
|
4439
4586
|
return void 0;
|
|
4440
4587
|
}
|
|
4441
|
-
if (res.status >= 500) return void 0;
|
|
4588
|
+
if (res.status === 429 || res.status >= 500) return void 0;
|
|
4442
4589
|
if (!res.ok) {
|
|
4443
|
-
throw classifyHttpError(res.status, await
|
|
4590
|
+
throw classifyHttpError(res.status, await readBody(res), "higgsfield", ctx.model.id);
|
|
4444
4591
|
}
|
|
4445
4592
|
const payload = JsonValueSchema.parse(await res.json());
|
|
4446
4593
|
const parsed = klingStatusSchema.safeParse(payload);
|
|
@@ -4547,7 +4694,7 @@ function dopUrl(body) {
|
|
|
4547
4694
|
var dopCreateSchema = z10.object({ id: z10.string() });
|
|
4548
4695
|
var dopStatusSchema = z10.object({ status: z10.string().optional() });
|
|
4549
4696
|
async function generateDopVideo(req, ctx) {
|
|
4550
|
-
const firstFrame = req.firstFrame ?
|
|
4697
|
+
const firstFrame = req.firstFrame ? refToUrl(req.firstFrame) : void 0;
|
|
4551
4698
|
if (!firstFrame) {
|
|
4552
4699
|
throw new ModelKitError({
|
|
4553
4700
|
code: "missing_input",
|
|
@@ -4567,7 +4714,7 @@ async function generateDopVideo(req, ctx) {
|
|
|
4567
4714
|
webhook: null
|
|
4568
4715
|
};
|
|
4569
4716
|
if (req.lastFrame) {
|
|
4570
|
-
params.input_images_end = [{ type: "image_url", image_url:
|
|
4717
|
+
params.input_images_end = [{ type: "image_url", image_url: refToUrl(req.lastFrame) }];
|
|
4571
4718
|
}
|
|
4572
4719
|
if (req.seed !== void 0) params.seed = req.seed;
|
|
4573
4720
|
const retryOptions = {};
|
|
@@ -4657,7 +4804,10 @@ async function generateDopVideo(req, ctx) {
|
|
|
4657
4804
|
}
|
|
4658
4805
|
var higgsfieldAdapter = {
|
|
4659
4806
|
id: "higgsfield",
|
|
4660
|
-
generateVideo: (req, ctx) =>
|
|
4807
|
+
generateVideo: (req, ctx) => {
|
|
4808
|
+
throwIfAborted(ctx.signal);
|
|
4809
|
+
return higgsfieldVideoKind(ctx.model.providerModelId) === "dop" ? generateDopVideo(req, ctx) : generateKlingVideo(req, ctx);
|
|
4810
|
+
}
|
|
4661
4811
|
};
|
|
4662
4812
|
|
|
4663
4813
|
// src/adapters/openai-image.ts
|
|
@@ -4752,6 +4902,7 @@ var openaiUsageSchema = z11.object({
|
|
|
4752
4902
|
var openaiImageAdapter = {
|
|
4753
4903
|
id: "openai-image",
|
|
4754
4904
|
async generateImage(req, ctx) {
|
|
4905
|
+
throwIfAborted(ctx.signal);
|
|
4755
4906
|
const apiKey = ctx.keys.openai;
|
|
4756
4907
|
if (!apiKey)
|
|
4757
4908
|
throw new ModelKitError({
|
|
@@ -4761,6 +4912,13 @@ var openaiImageAdapter = {
|
|
|
4761
4912
|
model: ctx.model.id,
|
|
4762
4913
|
retryable: false
|
|
4763
4914
|
});
|
|
4915
|
+
if ((req.references ?? []).some((ref) => ref.label !== void 0)) {
|
|
4916
|
+
ctx.warnings.push({
|
|
4917
|
+
code: "option_ignored",
|
|
4918
|
+
field: "references.label",
|
|
4919
|
+
message: "openai-image cannot express reference labels; ignoring them"
|
|
4920
|
+
});
|
|
4921
|
+
}
|
|
4764
4922
|
const client2 = new OpenAI({ apiKey, fetch: ctx.fetch, maxRetries: 0 });
|
|
4765
4923
|
const size = req.exactSize !== void 0 ? req.exactSize : req.aspectRatio === void 0 || req.aspectRatio === "adaptive" ? void 0 : aspectRatioToSize(req.aspectRatio, req.size ?? "1K");
|
|
4766
4924
|
const refs = req.references ?? [];
|
|
@@ -4774,24 +4932,34 @@ var openaiImageAdapter = {
|
|
|
4774
4932
|
try {
|
|
4775
4933
|
if (!isEdit) {
|
|
4776
4934
|
if (size !== void 0) {
|
|
4777
|
-
return await client2.images.generate(
|
|
4935
|
+
return await client2.images.generate(
|
|
4936
|
+
{
|
|
4937
|
+
model: ctx.model.providerModelId,
|
|
4938
|
+
prompt: req.prompt,
|
|
4939
|
+
size,
|
|
4940
|
+
quality: sdkQuality,
|
|
4941
|
+
...count
|
|
4942
|
+
},
|
|
4943
|
+
{ signal: ctx.signal }
|
|
4944
|
+
);
|
|
4945
|
+
}
|
|
4946
|
+
return await client2.images.generate(
|
|
4947
|
+
{
|
|
4778
4948
|
model: ctx.model.providerModelId,
|
|
4779
4949
|
prompt: req.prompt,
|
|
4780
|
-
size,
|
|
4781
4950
|
quality: sdkQuality,
|
|
4782
4951
|
...count
|
|
4783
|
-
}
|
|
4784
|
-
|
|
4785
|
-
|
|
4786
|
-
model: ctx.model.providerModelId,
|
|
4787
|
-
prompt: req.prompt,
|
|
4788
|
-
quality: sdkQuality,
|
|
4789
|
-
...count
|
|
4790
|
-
});
|
|
4952
|
+
},
|
|
4953
|
+
{ signal: ctx.signal }
|
|
4954
|
+
);
|
|
4791
4955
|
}
|
|
4792
4956
|
const files = await Promise.all(
|
|
4793
4957
|
refs.slice(0, MAX_EDIT_REFERENCES).map(async (ref, i) => {
|
|
4794
|
-
const { bytes, mime } = await mediaRefToBytes(ref, ctx.fetch
|
|
4958
|
+
const { bytes, mime } = await mediaRefToBytes(ref, ctx.fetch, {
|
|
4959
|
+
signal: ctx.signal,
|
|
4960
|
+
provider: "openai-image",
|
|
4961
|
+
model: ctx.model.id
|
|
4962
|
+
});
|
|
4795
4963
|
const ext = mime.includes("jpeg") ? "jpg" : mime.includes("webp") ? "webp" : "png";
|
|
4796
4964
|
return new File([bytes], `ref-${i}.${ext}`, { type: mime });
|
|
4797
4965
|
})
|
|
@@ -4799,22 +4967,28 @@ var openaiImageAdapter = {
|
|
|
4799
4967
|
const single = files.length === 1 ? files[0] : void 0;
|
|
4800
4968
|
const imageInput = single ?? files;
|
|
4801
4969
|
if (size !== void 0) {
|
|
4802
|
-
return await client2.images.edit(
|
|
4970
|
+
return await client2.images.edit(
|
|
4971
|
+
{
|
|
4972
|
+
model: ctx.model.providerModelId,
|
|
4973
|
+
image: imageInput,
|
|
4974
|
+
prompt: req.prompt,
|
|
4975
|
+
size,
|
|
4976
|
+
quality: sdkQuality,
|
|
4977
|
+
...count
|
|
4978
|
+
},
|
|
4979
|
+
{ signal: ctx.signal }
|
|
4980
|
+
);
|
|
4981
|
+
}
|
|
4982
|
+
return await client2.images.edit(
|
|
4983
|
+
{
|
|
4803
4984
|
model: ctx.model.providerModelId,
|
|
4804
4985
|
image: imageInput,
|
|
4805
4986
|
prompt: req.prompt,
|
|
4806
|
-
size,
|
|
4807
4987
|
quality: sdkQuality,
|
|
4808
4988
|
...count
|
|
4809
|
-
}
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
model: ctx.model.providerModelId,
|
|
4813
|
-
image: imageInput,
|
|
4814
|
-
prompt: req.prompt,
|
|
4815
|
-
quality: sdkQuality,
|
|
4816
|
-
...count
|
|
4817
|
-
});
|
|
4989
|
+
},
|
|
4990
|
+
{ signal: ctx.signal }
|
|
4991
|
+
);
|
|
4818
4992
|
} catch (cause) {
|
|
4819
4993
|
throw toProviderError2(cause, ctx);
|
|
4820
4994
|
}
|
|
@@ -4896,7 +5070,7 @@ async function refToBytes(ctx, ref) {
|
|
|
4896
5070
|
if ("bytes" in ref) return { bytes: ref.bytes, mime: ref.mime };
|
|
4897
5071
|
let res;
|
|
4898
5072
|
try {
|
|
4899
|
-
res = await ctx.fetch(ref.url);
|
|
5073
|
+
res = await ctx.fetch(ref.url, ctx.signal ? { signal: ctx.signal } : {});
|
|
4900
5074
|
} catch (cause) {
|
|
4901
5075
|
throw classifyThrown("prodia", cause, ctx.model.id);
|
|
4902
5076
|
}
|
|
@@ -4942,6 +5116,12 @@ function emptyImage() {
|
|
|
4942
5116
|
retryable: false
|
|
4943
5117
|
});
|
|
4944
5118
|
}
|
|
5119
|
+
function inputExtension(mime) {
|
|
5120
|
+
if (mime.includes("jpeg") || mime.includes("jpg")) return "jpg";
|
|
5121
|
+
if (mime.includes("webp")) return "webp";
|
|
5122
|
+
if (mime.includes("gif")) return "gif";
|
|
5123
|
+
return "png";
|
|
5124
|
+
}
|
|
4945
5125
|
function isBgRemove(providerModelId) {
|
|
4946
5126
|
const id = providerModelId.toLowerCase();
|
|
4947
5127
|
return id.includes("remove-background") || id.includes("bg-remove");
|
|
@@ -4950,6 +5130,7 @@ function isKlein(providerModelId) {
|
|
|
4950
5130
|
return providerModelId.toLowerCase().includes("klein");
|
|
4951
5131
|
}
|
|
4952
5132
|
async function generateProdiaImage(req, ctx) {
|
|
5133
|
+
throwIfAborted(ctx.signal);
|
|
4953
5134
|
const key = ctx.keys.prodia;
|
|
4954
5135
|
if (!key) {
|
|
4955
5136
|
throw new ModelKitError({
|
|
@@ -5048,7 +5229,9 @@ async function generateProdiaImage(req, ctx) {
|
|
|
5048
5229
|
"input",
|
|
5049
5230
|
// Uint8Array<ArrayBufferLike> is not a valid BlobPart under the
|
|
5050
5231
|
// strict lib types; copy into a fresh ArrayBuffer-backed view.
|
|
5051
|
-
new File([new Uint8Array(input.bytes)], `input-${i}.
|
|
5232
|
+
new File([new Uint8Array(input.bytes)], `input-${i}.${inputExtension(input.mime)}`, {
|
|
5233
|
+
type: input.mime
|
|
5234
|
+
})
|
|
5052
5235
|
);
|
|
5053
5236
|
});
|
|
5054
5237
|
const retryOpts = {
|
|
@@ -5063,11 +5246,13 @@ async function generateProdiaImage(req, ctx) {
|
|
|
5063
5246
|
res = await withRetry(async () => {
|
|
5064
5247
|
let attemptRes;
|
|
5065
5248
|
try {
|
|
5066
|
-
|
|
5249
|
+
const init = {
|
|
5067
5250
|
method: "POST",
|
|
5068
5251
|
headers: { Authorization: `Bearer ${key}`, Accept: accept },
|
|
5069
5252
|
body: form
|
|
5070
|
-
}
|
|
5253
|
+
};
|
|
5254
|
+
if (ctx.signal !== void 0) init.signal = ctx.signal;
|
|
5255
|
+
attemptRes = await ctx.fetch(PRODIA_JOB_URL, init);
|
|
5071
5256
|
} catch (err) {
|
|
5072
5257
|
throw classifyThrown("prodia", err, ctx.model.id);
|
|
5073
5258
|
}
|
|
@@ -5128,11 +5313,7 @@ function client(ctx, deps) {
|
|
|
5128
5313
|
retryable: false
|
|
5129
5314
|
});
|
|
5130
5315
|
}
|
|
5131
|
-
return deps.createReplicateClient({ auth: token });
|
|
5132
|
-
}
|
|
5133
|
-
function refToUrl3(ref) {
|
|
5134
|
-
if ("url" in ref) return ref.url;
|
|
5135
|
-
return `data:${ref.mime};base64,${Buffer.from(ref.bytes).toString("base64")}`;
|
|
5316
|
+
return deps.createReplicateClient({ auth: token, fetch: ctx.fetch });
|
|
5136
5317
|
}
|
|
5137
5318
|
function route(providerModelId) {
|
|
5138
5319
|
if (providerModelId.includes(":")) {
|
|
@@ -5152,8 +5333,9 @@ function replicateError(cause, ctx) {
|
|
|
5152
5333
|
const status = info.status ?? (nested.success ? nested.data.response?.status : void 0);
|
|
5153
5334
|
return classifyThrown("replicate", cause, ctx.model.id, { status, body: info.body });
|
|
5154
5335
|
}
|
|
5155
|
-
function
|
|
5156
|
-
|
|
5336
|
+
function baseModelId(providerModelId) {
|
|
5337
|
+
const colon = providerModelId.indexOf(":");
|
|
5338
|
+
return colon === -1 ? providerModelId : providerModelId.slice(0, colon);
|
|
5157
5339
|
}
|
|
5158
5340
|
function predictionErrorBody(cause) {
|
|
5159
5341
|
const parsed = JsonValueSchema.safeParse(cause);
|
|
@@ -5201,6 +5383,7 @@ function noOutput() {
|
|
|
5201
5383
|
});
|
|
5202
5384
|
}
|
|
5203
5385
|
async function runPrediction(ctx, input, deps) {
|
|
5386
|
+
throwIfAborted(ctx.signal);
|
|
5204
5387
|
const api = client(ctx, deps);
|
|
5205
5388
|
const createOptions = { ...route(ctx.model.providerModelId), input };
|
|
5206
5389
|
let prediction;
|
|
@@ -5208,12 +5391,14 @@ async function runPrediction(ctx, input, deps) {
|
|
|
5208
5391
|
prediction = await withRetry(
|
|
5209
5392
|
async () => {
|
|
5210
5393
|
try {
|
|
5211
|
-
return await api.predictions.create(
|
|
5394
|
+
return await api.predictions.create(
|
|
5395
|
+
ctx.signal ? { ...createOptions, signal: ctx.signal } : createOptions
|
|
5396
|
+
);
|
|
5212
5397
|
} catch (cause) {
|
|
5213
5398
|
throw replicateError(cause, ctx);
|
|
5214
5399
|
}
|
|
5215
5400
|
},
|
|
5216
|
-
|
|
5401
|
+
{ attempts: 1 }
|
|
5217
5402
|
);
|
|
5218
5403
|
} catch (cause) {
|
|
5219
5404
|
throw replicateError(cause, ctx);
|
|
@@ -5226,7 +5411,10 @@ async function runPrediction(ctx, input, deps) {
|
|
|
5226
5411
|
const done = await pollUntil(async () => {
|
|
5227
5412
|
let current;
|
|
5228
5413
|
try {
|
|
5229
|
-
current = await api.predictions.get(
|
|
5414
|
+
current = await api.predictions.get(
|
|
5415
|
+
prediction.id,
|
|
5416
|
+
ctx.signal ? { signal: ctx.signal } : void 0
|
|
5417
|
+
);
|
|
5230
5418
|
} catch (cause) {
|
|
5231
5419
|
throw replicateError(cause, ctx);
|
|
5232
5420
|
}
|
|
@@ -5293,21 +5481,32 @@ async function download(ctx, url) {
|
|
|
5293
5481
|
const mime = res.headers.get("content-type") ?? "image/png";
|
|
5294
5482
|
return { bytes: new Uint8Array(await res.arrayBuffer()), mime };
|
|
5295
5483
|
}
|
|
5296
|
-
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
}
|
|
5303
|
-
function
|
|
5304
|
-
return
|
|
5305
|
-
}
|
|
5306
|
-
|
|
5307
|
-
|
|
5484
|
+
var REPLICATE_IMAGE_KINDS = {
|
|
5485
|
+
"topazlabs/image-upscale": "topaz",
|
|
5486
|
+
"philz1337x/crystal-upscaler": "upscaler",
|
|
5487
|
+
"wan-video/wan-2.7-image-pro": "wan",
|
|
5488
|
+
"qwen/qwen-image-2-pro": "qwen-image",
|
|
5489
|
+
"qwen-edit-apps/qwen-image-edit-plus-lora-skin": "qwen-edit"
|
|
5490
|
+
};
|
|
5491
|
+
function imageKind(providerModelId) {
|
|
5492
|
+
return REPLICATE_IMAGE_KINDS[baseModelId(providerModelId)] ?? "generic";
|
|
5493
|
+
}
|
|
5494
|
+
var REPLICATE_VIDEO_KINDS = {
|
|
5495
|
+
"kling-video/v2.5-turbo/pro/image-to-video": "kling",
|
|
5496
|
+
"kling-video/v3.0/pro/image-to-video": "kling",
|
|
5497
|
+
"kwaivgi/kling-v3-video": "kling",
|
|
5498
|
+
"kwaivgi/kling-v3-omni-video": "kling-omni",
|
|
5499
|
+
"minimax/hailuo-02": "hailuo"
|
|
5500
|
+
};
|
|
5501
|
+
function videoKind(providerModelId) {
|
|
5502
|
+
return REPLICATE_VIDEO_KINDS[baseModelId(providerModelId)] ?? "wan";
|
|
5308
5503
|
}
|
|
5309
|
-
|
|
5310
|
-
|
|
5504
|
+
var REPLICATE_AUDIO_KINDS = {
|
|
5505
|
+
"zsxkib/mmaudio": "mmaudio",
|
|
5506
|
+
"elevenlabs/music": "elevenlabs"
|
|
5507
|
+
};
|
|
5508
|
+
function audioKind(providerModelId) {
|
|
5509
|
+
return REPLICATE_AUDIO_KINDS[baseModelId(providerModelId)] ?? "lyria";
|
|
5311
5510
|
}
|
|
5312
5511
|
var QWEN_IMAGE_RATIOS = /* @__PURE__ */ new Set([
|
|
5313
5512
|
"1:1",
|
|
@@ -5350,87 +5549,113 @@ function wanImageSize(aspectRatio, size) {
|
|
|
5350
5549
|
async function generateReplicateImage(req, ctx, deps) {
|
|
5351
5550
|
const id = ctx.model.providerModelId;
|
|
5352
5551
|
let input;
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5552
|
+
switch (imageKind(id)) {
|
|
5553
|
+
case "topaz": {
|
|
5554
|
+
const first = (req.references ?? [])[0];
|
|
5555
|
+
if (!first) {
|
|
5556
|
+
throw new ModelKitError({
|
|
5557
|
+
code: "missing_input",
|
|
5558
|
+
message: `${ctx.model.id} requires a reference image to upscale`,
|
|
5559
|
+
provider: "replicate",
|
|
5560
|
+
model: ctx.model.id,
|
|
5561
|
+
retryable: false
|
|
5562
|
+
});
|
|
5563
|
+
}
|
|
5564
|
+
let format = req.outputFormat === "jpeg" ? "jpg" : req.outputFormat ?? "png";
|
|
5565
|
+
if (format !== "png" && format !== "jpg") {
|
|
5566
|
+
ctx.warnings.push({
|
|
5567
|
+
code: "option_ignored",
|
|
5568
|
+
field: "outputFormat",
|
|
5569
|
+
from: format,
|
|
5570
|
+
message: "topazlabs/image-upscale supports only png and jpg; using png"
|
|
5571
|
+
});
|
|
5572
|
+
format = "png";
|
|
5573
|
+
}
|
|
5574
|
+
const upscale = req.upscale;
|
|
5575
|
+
const topaz = {
|
|
5576
|
+
image: refToUrl(first),
|
|
5577
|
+
enhance_model: upscale?.enhanceModel ?? "Standard V2",
|
|
5578
|
+
output_format: format,
|
|
5579
|
+
upscale_factor: `${req.scaleFactor ?? 2}x`,
|
|
5580
|
+
face_enhancement: upscale?.faceEnhancement ?? false
|
|
5581
|
+
};
|
|
5582
|
+
if (upscale?.subjectDetection !== void 0)
|
|
5583
|
+
topaz.subject_detection = upscale.subjectDetection;
|
|
5584
|
+
if (upscale?.faceEnhancementCreativity !== void 0)
|
|
5585
|
+
topaz.face_enhancement_creativity = upscale.faceEnhancementCreativity;
|
|
5586
|
+
if (upscale?.faceEnhancementStrength !== void 0)
|
|
5587
|
+
topaz.face_enhancement_strength = upscale.faceEnhancementStrength;
|
|
5588
|
+
input = topaz;
|
|
5589
|
+
break;
|
|
5363
5590
|
}
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
|
|
5591
|
+
case "upscaler": {
|
|
5592
|
+
const first = (req.references ?? [])[0];
|
|
5593
|
+
if (!first) {
|
|
5594
|
+
throw new ModelKitError({
|
|
5595
|
+
code: "missing_input",
|
|
5596
|
+
message: `${ctx.model.id} requires a reference image to upscale`,
|
|
5597
|
+
provider: "replicate",
|
|
5598
|
+
model: ctx.model.id,
|
|
5599
|
+
retryable: false
|
|
5600
|
+
});
|
|
5601
|
+
}
|
|
5602
|
+
const imageInput = { prompt: req.prompt };
|
|
5603
|
+
imageInput.image = refToUrl(first);
|
|
5604
|
+
imageInput.creativity = 0;
|
|
5605
|
+
imageInput.scale_factor = 2;
|
|
5606
|
+
imageInput.output_format = "png";
|
|
5607
|
+
input = imageInput;
|
|
5608
|
+
break;
|
|
5373
5609
|
}
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
} else if (isUpscaler(id)) {
|
|
5382
|
-
const refs = req.references ?? [];
|
|
5383
|
-
const first = refs[0];
|
|
5384
|
-
if (!first) {
|
|
5385
|
-
throw new ModelKitError({
|
|
5386
|
-
code: "missing_input",
|
|
5387
|
-
message: `${ctx.model.id} requires a reference image to upscale`,
|
|
5388
|
-
provider: "replicate",
|
|
5389
|
-
model: ctx.model.id,
|
|
5390
|
-
retryable: false
|
|
5391
|
-
});
|
|
5610
|
+
case "wan": {
|
|
5611
|
+
const refs = (req.references ?? []).map(refToUrl);
|
|
5612
|
+
const imageInput = { prompt: req.prompt };
|
|
5613
|
+
if (refs.length > 0) imageInput.images = refs;
|
|
5614
|
+
imageInput.size = wanImageSize(req.aspectRatio, req.size);
|
|
5615
|
+
input = imageInput;
|
|
5616
|
+
break;
|
|
5392
5617
|
}
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
} else if (isQwen(id)) {
|
|
5406
|
-
const refs = (req.references ?? []).map(refToUrl3);
|
|
5407
|
-
const firstUrl = refs[0];
|
|
5408
|
-
const imageInput = { prompt: req.prompt };
|
|
5409
|
-
if (firstUrl !== void 0) {
|
|
5410
|
-
imageInput.image = firstUrl;
|
|
5411
|
-
if (!isQwenEditPlus(id)) imageInput.match_input_image = true;
|
|
5618
|
+
case "qwen-image": {
|
|
5619
|
+
const refs = (req.references ?? []).map(refToUrl);
|
|
5620
|
+
const firstUrl = refs[0];
|
|
5621
|
+
const imageInput = { prompt: req.prompt };
|
|
5622
|
+
if (firstUrl !== void 0) {
|
|
5623
|
+
imageInput.image = firstUrl;
|
|
5624
|
+
imageInput.match_input_image = true;
|
|
5625
|
+
} else if (req.aspectRatio !== void 0 && QWEN_IMAGE_RATIOS.has(req.aspectRatio)) {
|
|
5626
|
+
imageInput.aspect_ratio = req.aspectRatio;
|
|
5627
|
+
}
|
|
5628
|
+
input = imageInput;
|
|
5629
|
+
break;
|
|
5412
5630
|
}
|
|
5413
|
-
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5631
|
+
case "qwen-edit": {
|
|
5632
|
+
const refs = (req.references ?? []).map(refToUrl);
|
|
5633
|
+
const firstUrl = refs[0];
|
|
5634
|
+
const imageInput = { prompt: req.prompt };
|
|
5635
|
+
if (firstUrl !== void 0) imageInput.image = firstUrl;
|
|
5636
|
+
if (req.aspectRatio !== void 0) {
|
|
5637
|
+
if (QWEN_EDIT_RATIOS.has(req.aspectRatio))
|
|
5638
|
+
imageInput.aspect_ratio = req.aspectRatio;
|
|
5639
|
+
else
|
|
5640
|
+
ctx.warnings.push({
|
|
5641
|
+
code: "option_ignored",
|
|
5642
|
+
field: "aspectRatio",
|
|
5643
|
+
from: req.aspectRatio,
|
|
5644
|
+
message: `${id} has no ${req.aspectRatio} aspect_ratio; using the provider default`
|
|
5645
|
+
});
|
|
5646
|
+
}
|
|
5647
|
+
if (req.outputFormat !== void 0) {
|
|
5648
|
+
imageInput.output_format = req.outputFormat === "jpeg" ? "jpg" : req.outputFormat;
|
|
5649
|
+
}
|
|
5650
|
+
input = imageInput;
|
|
5651
|
+
break;
|
|
5423
5652
|
}
|
|
5424
|
-
|
|
5425
|
-
|
|
5653
|
+
default: {
|
|
5654
|
+
const first = (req.references ?? [])[0];
|
|
5655
|
+
const imageInput = { prompt: req.prompt };
|
|
5656
|
+
if (first) imageInput.image = refToUrl(first);
|
|
5657
|
+
input = imageInput;
|
|
5426
5658
|
}
|
|
5427
|
-
input = imageInput;
|
|
5428
|
-
} else {
|
|
5429
|
-
const refs = req.references ?? [];
|
|
5430
|
-
const first = refs[0];
|
|
5431
|
-
const imageInput = { prompt: req.prompt };
|
|
5432
|
-
if (first) imageInput.image = refToUrl3(first);
|
|
5433
|
-
input = imageInput;
|
|
5434
5659
|
}
|
|
5435
5660
|
const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
|
|
5436
5661
|
const file = await download(ctx, url);
|
|
@@ -5447,8 +5672,8 @@ function wanSize(aspectRatio) {
|
|
|
5447
5672
|
return w > h ? "2048*1152" : "1536*2048";
|
|
5448
5673
|
}
|
|
5449
5674
|
function klingInput(req) {
|
|
5450
|
-
const images = (req.firstFrame ? [req.firstFrame] : []).map(
|
|
5451
|
-
if (req.lastFrame) images.push(
|
|
5675
|
+
const images = (req.firstFrame ? [req.firstFrame] : []).map(refToUrl);
|
|
5676
|
+
if (req.lastFrame) images.push(refToUrl(req.lastFrame));
|
|
5452
5677
|
const input = {
|
|
5453
5678
|
prompt: req.prompt,
|
|
5454
5679
|
duration: req.durationSeconds ?? 10,
|
|
@@ -5466,13 +5691,18 @@ function klingInput(req) {
|
|
|
5466
5691
|
if (req.negativePrompt !== void 0) input.negative_prompt = req.negativePrompt;
|
|
5467
5692
|
return input;
|
|
5468
5693
|
}
|
|
5694
|
+
function klingOmniMode(req) {
|
|
5695
|
+
if (req.resolution === "1080p") return "pro";
|
|
5696
|
+
if (req.resolution === "720p") return "standard";
|
|
5697
|
+
return req.mode ?? "standard";
|
|
5698
|
+
}
|
|
5469
5699
|
function klingOmniInput(req) {
|
|
5470
|
-
const images = (req.firstFrame ? [req.firstFrame] : []).map(
|
|
5471
|
-
if (req.lastFrame) images.push(
|
|
5700
|
+
const images = (req.firstFrame ? [req.firstFrame] : []).map(refToUrl);
|
|
5701
|
+
if (req.lastFrame) images.push(refToUrl(req.lastFrame));
|
|
5472
5702
|
const input = {
|
|
5473
5703
|
prompt: req.prompt,
|
|
5474
5704
|
duration: req.durationSeconds ?? 10,
|
|
5475
|
-
mode: req
|
|
5705
|
+
mode: klingOmniMode(req),
|
|
5476
5706
|
generate_audio: req.generateAudio ?? false
|
|
5477
5707
|
};
|
|
5478
5708
|
const startImage = images[0];
|
|
@@ -5483,7 +5713,7 @@ function klingOmniInput(req) {
|
|
|
5483
5713
|
} else if (req.aspectRatio !== "adaptive") {
|
|
5484
5714
|
input.aspect_ratio = req.aspectRatio ?? "16:9";
|
|
5485
5715
|
}
|
|
5486
|
-
const refs = (req.referenceImages ?? []).map(
|
|
5716
|
+
const refs = (req.referenceImages ?? []).map(refToUrl);
|
|
5487
5717
|
if (refs.length > 0) input.reference_images = refs;
|
|
5488
5718
|
return input;
|
|
5489
5719
|
}
|
|
@@ -5494,8 +5724,8 @@ function hailuoInput(req) {
|
|
|
5494
5724
|
resolution: req.resolution ?? "768p",
|
|
5495
5725
|
prompt_optimizer: true
|
|
5496
5726
|
};
|
|
5497
|
-
if (req.firstFrame) input.first_frame_image =
|
|
5498
|
-
if (req.lastFrame) input.last_frame_image =
|
|
5727
|
+
if (req.firstFrame) input.first_frame_image = refToUrl(req.firstFrame);
|
|
5728
|
+
if (req.lastFrame) input.last_frame_image = refToUrl(req.lastFrame);
|
|
5499
5729
|
return input;
|
|
5500
5730
|
}
|
|
5501
5731
|
function wanInput(req) {
|
|
@@ -5504,12 +5734,13 @@ function wanInput(req) {
|
|
|
5504
5734
|
duration: req.durationSeconds ?? 5,
|
|
5505
5735
|
size: wanSize(req.aspectRatio)
|
|
5506
5736
|
};
|
|
5507
|
-
if (req.firstFrame) input.image =
|
|
5737
|
+
if (req.firstFrame) input.image = refToUrl(req.firstFrame);
|
|
5508
5738
|
return input;
|
|
5509
5739
|
}
|
|
5510
5740
|
async function generateReplicateVideo(req, ctx, deps) {
|
|
5511
|
-
|
|
5512
|
-
const
|
|
5741
|
+
throwIfAborted(ctx.signal);
|
|
5742
|
+
const kind = videoKind(ctx.model.providerModelId);
|
|
5743
|
+
const input = kind === "kling" ? klingInput(req) : kind === "kling-omni" ? klingOmniInput(req) : kind === "hailuo" ? hailuoInput(req) : wanInput(req);
|
|
5513
5744
|
const api = client(ctx, deps);
|
|
5514
5745
|
const createOptions = { ...route(ctx.model.providerModelId), input };
|
|
5515
5746
|
let prediction;
|
|
@@ -5517,12 +5748,14 @@ async function generateReplicateVideo(req, ctx, deps) {
|
|
|
5517
5748
|
prediction = await withRetry(
|
|
5518
5749
|
async () => {
|
|
5519
5750
|
try {
|
|
5520
|
-
return await api.predictions.create(
|
|
5751
|
+
return await api.predictions.create(
|
|
5752
|
+
ctx.signal ? { ...createOptions, signal: ctx.signal } : createOptions
|
|
5753
|
+
);
|
|
5521
5754
|
} catch (cause) {
|
|
5522
5755
|
throw replicateError(cause, ctx);
|
|
5523
5756
|
}
|
|
5524
5757
|
},
|
|
5525
|
-
|
|
5758
|
+
{ attempts: 1 }
|
|
5526
5759
|
);
|
|
5527
5760
|
} catch (cause) {
|
|
5528
5761
|
throw replicateError(cause, ctx);
|
|
@@ -5531,7 +5764,10 @@ async function generateReplicateVideo(req, ctx, deps) {
|
|
|
5531
5764
|
const check = async () => {
|
|
5532
5765
|
let current;
|
|
5533
5766
|
try {
|
|
5534
|
-
current = await api.predictions.get(
|
|
5767
|
+
current = await api.predictions.get(
|
|
5768
|
+
jobId,
|
|
5769
|
+
ctx.signal ? { signal: ctx.signal } : void 0
|
|
5770
|
+
);
|
|
5535
5771
|
} catch (cause) {
|
|
5536
5772
|
throw replicateError(cause, ctx);
|
|
5537
5773
|
}
|
|
@@ -5632,7 +5868,7 @@ function mmaudioInput(req, ctx) {
|
|
|
5632
5868
|
});
|
|
5633
5869
|
}
|
|
5634
5870
|
const input = {
|
|
5635
|
-
video:
|
|
5871
|
+
video: refToUrl(video),
|
|
5636
5872
|
duration: req.durationSeconds ?? 8,
|
|
5637
5873
|
seed: req.seed ?? -1
|
|
5638
5874
|
};
|
|
@@ -5651,8 +5887,8 @@ function predictionRaw(prediction) {
|
|
|
5651
5887
|
return raw;
|
|
5652
5888
|
}
|
|
5653
5889
|
async function generateReplicateAudio(req, ctx, deps) {
|
|
5654
|
-
const
|
|
5655
|
-
const input =
|
|
5890
|
+
const kind = audioKind(ctx.model.providerModelId);
|
|
5891
|
+
const input = kind === "mmaudio" ? mmaudioInput(req, ctx) : kind === "elevenlabs" ? elevenLabsMusicInput(req, ctx) : lyriaAudioInput(req, ctx);
|
|
5656
5892
|
const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
|
|
5657
5893
|
const usage2 = audioUsage(ctx, req);
|
|
5658
5894
|
if (ctx.model.usage.unit === "seconds") {
|
|
@@ -5681,10 +5917,6 @@ function createXaiVideoAdapter(deps = defaultXaiDeps) {
|
|
|
5681
5917
|
};
|
|
5682
5918
|
}
|
|
5683
5919
|
var xaiVideoAdapter = createXaiVideoAdapter();
|
|
5684
|
-
function refToUrl4(ref) {
|
|
5685
|
-
if ("url" in ref) return ref.url;
|
|
5686
|
-
return `data:${ref.mime};base64,${Buffer.from(ref.bytes).toString("base64")}`;
|
|
5687
|
-
}
|
|
5688
5920
|
var xaiResponseStatusSchema = z13.object({
|
|
5689
5921
|
response: z13.object({ status: z13.number() }).partial()
|
|
5690
5922
|
});
|
|
@@ -5716,13 +5948,14 @@ async function generateXaiVideo(req, ctx, deps) {
|
|
|
5716
5948
|
retryable: false
|
|
5717
5949
|
});
|
|
5718
5950
|
}
|
|
5719
|
-
const refUrls = (req.referenceImages ?? []).map(
|
|
5720
|
-
const resolution = req.resolution === "480p" ? "480p" : "720p";
|
|
5951
|
+
const refUrls = (req.referenceImages ?? []).map(refToUrl).slice(0, 7);
|
|
5721
5952
|
const xaiOptions = {
|
|
5722
|
-
resolution,
|
|
5723
5953
|
pollIntervalMs: POLL_INTERVAL_MS2,
|
|
5724
5954
|
pollTimeoutMs: POLL_TIMEOUT_MS2
|
|
5725
5955
|
};
|
|
5956
|
+
if (req.resolution === "480p" || req.resolution === "720p" || req.resolution === "1080p") {
|
|
5957
|
+
xaiOptions.resolution = req.resolution;
|
|
5958
|
+
}
|
|
5726
5959
|
if (refUrls.length > 0) {
|
|
5727
5960
|
xaiOptions.mode = "reference-to-video";
|
|
5728
5961
|
xaiOptions.referenceImageUrls = refUrls;
|
|
@@ -5742,7 +5975,7 @@ async function generateXaiVideo(req, ctx, deps) {
|
|
|
5742
5975
|
providerOptions: { xai: xaiOptions }
|
|
5743
5976
|
};
|
|
5744
5977
|
if (req.firstFrame) {
|
|
5745
|
-
callBody.frameImages = [{ image:
|
|
5978
|
+
callBody.frameImages = [{ image: refToUrl(req.firstFrame), frameType: "first_frame" }];
|
|
5746
5979
|
}
|
|
5747
5980
|
if (req.aspectRatio !== void 0 && req.aspectRatio !== "adaptive") {
|
|
5748
5981
|
callBody.aspectRatio = req.aspectRatio;
|
|
@@ -5778,7 +6011,8 @@ async function generateXaiVideo(req, ctx, deps) {
|
|
|
5778
6011
|
return settled;
|
|
5779
6012
|
};
|
|
5780
6013
|
return {
|
|
5781
|
-
|
|
6014
|
+
// xAI exposes no request id on the synchronous handle, so each job gets a fresh one.
|
|
6015
|
+
jobId: crypto.randomUUID(),
|
|
5782
6016
|
async poll() {
|
|
5783
6017
|
if (failed !== void 0) return { status: "failed" };
|
|
5784
6018
|
return settled ? { status: "succeeded" } : { status: "pending" };
|
|
@@ -5912,6 +6146,7 @@ export {
|
|
|
5912
6146
|
prodiaAdapter,
|
|
5913
6147
|
readErrorBody,
|
|
5914
6148
|
replicateAdapter,
|
|
6149
|
+
resolveAudioOptions,
|
|
5915
6150
|
resolveImageOptions,
|
|
5916
6151
|
resolveKeys,
|
|
5917
6152
|
resolveVideoOptions,
|