@shop-os/modelkit 0.9.0 → 0.10.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 +25 -0
- package/README.md +2 -1
- package/dist/catalog.cjs +464 -395
- package/dist/catalog.cjs.map +1 -1
- package/dist/catalog.d.cts +6 -3
- package/dist/catalog.d.ts +6 -3
- package/dist/catalog.js +464 -395
- package/dist/catalog.js.map +1 -1
- package/dist/index.cjs +974 -623
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +9 -4
- package/dist/index.d.ts +9 -4
- package/dist/index.js +973 -623
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1230,303 +1230,6 @@ var VEED_SUBTITLES = {
|
|
|
1230
1230
|
}
|
|
1231
1231
|
};
|
|
1232
1232
|
|
|
1233
|
-
// src/catalog/voices-fish.ts
|
|
1234
|
-
var FISH_VOICES = [
|
|
1235
|
-
{
|
|
1236
|
-
id: "933563129e564b19a115bedd57b7406a",
|
|
1237
|
-
name: "Sarah",
|
|
1238
|
-
gender: "female",
|
|
1239
|
-
languages: ["en"],
|
|
1240
|
-
description: "An engaged speaker.",
|
|
1241
|
-
previewUrl: "https://platform.r2.fish.audio/task/4e204945670c460c86fdab57512cb308.mp3"
|
|
1242
|
-
},
|
|
1243
|
-
{
|
|
1244
|
-
id: "bf322df2096a46f18c579d0baa36f41d",
|
|
1245
|
-
name: "Adrian",
|
|
1246
|
-
gender: "male",
|
|
1247
|
-
languages: ["en"],
|
|
1248
|
-
description: "A steady and reliable narrator.",
|
|
1249
|
-
previewUrl: "https://platform.r2.fish.audio/task/d730b09f4a484316a77ecc86137e85fb.mp3"
|
|
1250
|
-
},
|
|
1251
|
-
{
|
|
1252
|
-
id: "536d3a5e000945adb7038665781a4aca",
|
|
1253
|
-
name: "Ethan",
|
|
1254
|
-
gender: "male",
|
|
1255
|
-
languages: ["en"],
|
|
1256
|
-
description: "A curious explainer.",
|
|
1257
|
-
previewUrl: "https://platform.r2.fish.audio/task/bdd677ed767744fc91f166468786264b.mp3"
|
|
1258
|
-
},
|
|
1259
|
-
{
|
|
1260
|
-
id: "b347db033a6549378b48d00acb0d06cd",
|
|
1261
|
-
name: "Selene",
|
|
1262
|
-
gender: "female",
|
|
1263
|
-
languages: ["en"],
|
|
1264
|
-
description: "A meditative female voice.",
|
|
1265
|
-
previewUrl: "https://platform.r2.fish.audio/task/fcf629b4a0b343558f461338ba1b9da4.mp3"
|
|
1266
|
-
},
|
|
1267
|
-
{
|
|
1268
|
-
id: "9a9cf47702da476aa4629e2506d4a857",
|
|
1269
|
-
name: "Hannah",
|
|
1270
|
-
gender: "female",
|
|
1271
|
-
languages: ["en"],
|
|
1272
|
-
description: "A conversation specialist.",
|
|
1273
|
-
previewUrl: "https://platform.r2.fish.audio/task/08d658835feb427db808e37060b78eb0.mp3"
|
|
1274
|
-
},
|
|
1275
|
-
{
|
|
1276
|
-
id: "79d0bd3e4e5444b18f7b6d89b5927bf1",
|
|
1277
|
-
name: "Jordan",
|
|
1278
|
-
gender: "male",
|
|
1279
|
-
languages: ["en"],
|
|
1280
|
-
description: "A motivational speaker.",
|
|
1281
|
-
previewUrl: "https://platform.r2.fish.audio/task/edecbc0bdd4c46c39eda8520a0f729ef.mp3"
|
|
1282
|
-
},
|
|
1283
|
-
{
|
|
1284
|
-
id: "e3cd384158934cc9a01029cd7d278634",
|
|
1285
|
-
name: "Laura",
|
|
1286
|
-
gender: "female",
|
|
1287
|
-
languages: ["en"],
|
|
1288
|
-
description: "A confident female narrator.",
|
|
1289
|
-
previewUrl: "https://platform.r2.fish.audio/task/e821bef995344d519caa1c93d808db23.mp3"
|
|
1290
|
-
},
|
|
1291
|
-
{
|
|
1292
|
-
id: "f3a2b90078d54a65af4b95f63bc7798e",
|
|
1293
|
-
name: "Sheila",
|
|
1294
|
-
gender: "female",
|
|
1295
|
-
accent: "american",
|
|
1296
|
-
languages: ["en"],
|
|
1297
|
-
description: "A young American English woman's voice.",
|
|
1298
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/9bb9e1a1cf3f47f38700da1c5c0a678a.mp3"
|
|
1299
|
-
},
|
|
1300
|
-
{
|
|
1301
|
-
id: "0db6e93af420470b9d9b9a886dbaa954",
|
|
1302
|
-
name: "Kai",
|
|
1303
|
-
gender: "male",
|
|
1304
|
-
languages: ["en"],
|
|
1305
|
-
description: "A friendly English man's voice for companion apps and everyday conversation.",
|
|
1306
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/13306f1172544c3ba3106d1e363feaa6.mp3"
|
|
1307
|
-
},
|
|
1308
|
-
{
|
|
1309
|
-
id: "8abfa9ebd4c24a3399b68c3cdac8c7b5",
|
|
1310
|
-
name: "Freya",
|
|
1311
|
-
gender: "female",
|
|
1312
|
-
accent: "british",
|
|
1313
|
-
languages: ["en"],
|
|
1314
|
-
description: "A natural, professional British English voice with a brisk, conversational pace. Clear and easy to follow, suited to voice assistants, customer support and everyday narration.",
|
|
1315
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/07918705a56b42daaab149f65392cea7.mp3"
|
|
1316
|
-
},
|
|
1317
|
-
{
|
|
1318
|
-
id: "2f64e528a4f2406691925ab1e0ed5b7f",
|
|
1319
|
-
name: "Ananya",
|
|
1320
|
-
gender: "female",
|
|
1321
|
-
languages: ["hi"],
|
|
1322
|
-
description: "\u0938\u093E\u092B\u093C \u0914\u0930 \u0906\u0924\u094D\u092E\u0935\u093F\u0936\u094D\u0935\u093E\u0938 \u092D\u0930\u0940 \u0906\u0935\u093E\u091C\u093C, \u091C\u094B \u0935\u0949\u0907\u0938 \u0905\u0938\u093F\u0938\u094D\u091F\u0947\u0902\u091F, \u0917\u094D\u0930\u093E\u0939\u0915 \u0938\u0947\u0935\u093E \u0914\u0930 \u092A\u094D\u0930\u0938\u094D\u0924\u0941\u0924\u093F\u092F\u094B\u0902 \u0915\u0947 \u0932\u093F\u090F \u0909\u092A\u092F\u0941\u0915\u094D\u0924 \u0939\u0948\u0964",
|
|
1323
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/a17a700668d8405f8316db120733145c.mp3"
|
|
1324
|
-
},
|
|
1325
|
-
{
|
|
1326
|
-
id: "cefd91a07b99468f9148e2580990082d",
|
|
1327
|
-
name: "Arjun",
|
|
1328
|
-
gender: "male",
|
|
1329
|
-
languages: ["hi"],
|
|
1330
|
-
description: "\u0938\u093E\u092B\u093C \u0914\u0930 \u0906\u0924\u094D\u092E\u0935\u093F\u0936\u094D\u0935\u093E\u0938 \u092D\u0930\u0940 \u0906\u0935\u093E\u091C\u093C, \u091C\u094B \u0935\u0949\u0907\u0938 \u0905\u0938\u093F\u0938\u094D\u091F\u0947\u0902\u091F, \u0917\u094D\u0930\u093E\u0939\u0915 \u0938\u0947\u0935\u093E \u0914\u0930 \u092A\u094D\u0930\u0938\u094D\u0924\u0941\u0924\u093F\u092F\u094B\u0902 \u0915\u0947 \u0932\u093F\u090F \u0909\u092A\u092F\u0941\u0915\u094D\u0924 \u0939\u0948\u0964",
|
|
1331
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/a0c4a8eadb7841cdae8e5e68031a2dfb.mp3"
|
|
1332
|
-
},
|
|
1333
|
-
{
|
|
1334
|
-
id: "3f065d660212478a9c697fa965b4d098",
|
|
1335
|
-
name: "Carmen",
|
|
1336
|
-
gender: "female",
|
|
1337
|
-
languages: ["es"],
|
|
1338
|
-
description: "Una voz clara y segura para asistentes de voz, atenci\xF3n al cliente y presentaciones.",
|
|
1339
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/3421be48b6cb4c28bf829c25188e7e74.mp3"
|
|
1340
|
-
},
|
|
1341
|
-
{
|
|
1342
|
-
id: "ec0718028a2445fb9be8e8bfb56a0150",
|
|
1343
|
-
name: "Rodrigo",
|
|
1344
|
-
gender: "male",
|
|
1345
|
-
languages: ["es"],
|
|
1346
|
-
description: "Una voz clara y segura para asistentes de voz, atenci\xF3n al cliente y presentaciones.",
|
|
1347
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/5a77c32365604800ad5b4eb13c5585df.mp3"
|
|
1348
|
-
},
|
|
1349
|
-
{
|
|
1350
|
-
id: "10a3a20742114a4ea6dd441e7591850f",
|
|
1351
|
-
name: "Manon",
|
|
1352
|
-
gender: "female",
|
|
1353
|
-
languages: ["fr"],
|
|
1354
|
-
description: "Une voix claire et vive, adapt\xE9e aux assistants vocaux et au support client.",
|
|
1355
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/f7b75ee1fa524e48a8cefb003cf72952.mp3"
|
|
1356
|
-
},
|
|
1357
|
-
{
|
|
1358
|
-
id: "f69bca092b674168a8d02d61ca20943c",
|
|
1359
|
-
name: "Lucas",
|
|
1360
|
-
gender: "male",
|
|
1361
|
-
languages: ["fr"],
|
|
1362
|
-
description: "Une voix claire et assur\xE9e, adapt\xE9e aux assistants vocaux et au service client.",
|
|
1363
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/86fca3e56a014a3d8a11450854bb8311.mp3"
|
|
1364
|
-
},
|
|
1365
|
-
{
|
|
1366
|
-
id: "3937b44b604249f18b94913daef94043",
|
|
1367
|
-
name: "Lena",
|
|
1368
|
-
gender: "female",
|
|
1369
|
-
languages: ["de"],
|
|
1370
|
-
description: "Eine klare, souver\xE4ne Stimme f\xFCr Sprachassistenten, Kundenservice und Pr\xE4sentationen.",
|
|
1371
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/8659fec80b74442dab68a7755716a401.mp3"
|
|
1372
|
-
},
|
|
1373
|
-
{
|
|
1374
|
-
id: "c1e7cc926aa5469aa966c353094d4b0b",
|
|
1375
|
-
name: "Lukas",
|
|
1376
|
-
gender: "male",
|
|
1377
|
-
languages: ["de"],
|
|
1378
|
-
description: "Eine klare, souver\xE4ne Stimme f\xFCr Sprachassistenten, Kundenservice und Pr\xE4sentationen.",
|
|
1379
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/fb1d538126bb4fe38f8366250f6a2136.mp3"
|
|
1380
|
-
},
|
|
1381
|
-
{
|
|
1382
|
-
id: "b3c060cc41544a7da94a2c487647c902",
|
|
1383
|
-
name: "Let\xEDcia",
|
|
1384
|
-
gender: "female",
|
|
1385
|
-
accent: "brazilian",
|
|
1386
|
-
languages: ["pt"],
|
|
1387
|
-
description: "A Brazilian-accented Portuguese woman's voice, in her late twenties. Soft, warm, intimate. A freelance designer from Belo Horizonte who enjoys long walks in the park. Best suited to companion apps and casual everyday conversation.",
|
|
1388
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-10-12/13c6c0d96b5c4069951f89868ee15360.mp3"
|
|
1389
|
-
},
|
|
1390
|
-
{
|
|
1391
|
-
id: "add7bcb8d3c8423bbfa152ca232aad6e",
|
|
1392
|
-
name: "Ricardo",
|
|
1393
|
-
gender: "male",
|
|
1394
|
-
accent: "brazilian",
|
|
1395
|
-
languages: ["pt"],
|
|
1396
|
-
description: "A Brazilian-accented Portuguese man's voice, in his late forties. Clear, professional, monotone. A high school history teacher from Curitiba who loves classical music. Best suited to lessons, tutoring and explainer content.",
|
|
1397
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-10-12/67475fc717ae45cbb38e647a2dd37fe1.mp3"
|
|
1398
|
-
},
|
|
1399
|
-
{
|
|
1400
|
-
id: "b2d9d8db057042688a5e318b8f405bc2",
|
|
1401
|
-
name: "Kyoko",
|
|
1402
|
-
gender: "female",
|
|
1403
|
-
languages: ["ja"],
|
|
1404
|
-
description: "\u4E01\u5BE7\u3067\u843D\u3061\u7740\u3044\u305F\u8A71\u3057\u65B9\u304C\u7279\u5FB4\u306E\u5973\u6027\u306E\u58F0\u3002\u304A\u5BA2\u69D8\u5BFE\u5FDC\u3084\u60C5\u5831\u63D0\u4F9B\u306B\u6700\u9069\u3002",
|
|
1405
|
-
previewUrl: "https://platform.r2.fish.audio/task/993b3ccb52124341aff79580f1ce5a5a.mp3"
|
|
1406
|
-
},
|
|
1407
|
-
{
|
|
1408
|
-
id: "297a6fd278df47c3b9da9bfdf55ac89a",
|
|
1409
|
-
name: "Satoru",
|
|
1410
|
-
gender: "male",
|
|
1411
|
-
languages: ["ja"],
|
|
1412
|
-
description: "\u82E5\u3005\u3057\u304F\u3082\u843D\u3061\u7740\u304D\u306E\u3042\u308B\u7537\u6027\u306E\u58F0\u3002\u65E5\u5E38\u306E\u8A9E\u308A\u3084\u30EA\u30E9\u30C3\u30AF\u30B9\u3057\u305F\u30CA\u30EC\u30FC\u30B7\u30E7\u30F3\u306B\u6700\u9069\u3002",
|
|
1413
|
-
previewUrl: "https://platform.r2.fish.audio/task/1b4712fb831f4c149eef6b0133157418.mp3"
|
|
1414
|
-
},
|
|
1415
|
-
{
|
|
1416
|
-
id: "0b14f34a13a94ed88fe6113193749bb0",
|
|
1417
|
-
name: "Fatima",
|
|
1418
|
-
gender: "female",
|
|
1419
|
-
languages: ["ar"],
|
|
1420
|
-
description: "\u0635\u0648\u062A \u0648\u0627\u0636\u062D \u0648\u0648\u0627\u062B\u0642 \u064A\u0646\u0627\u0633\u0628 \u0627\u0644\u0645\u0633\u0627\u0639\u062F\u0627\u062A \u0627\u0644\u0635\u0648\u062A\u064A\u0629 \u0648\u062E\u062F\u0645\u0629 \u0627\u0644\u0639\u0645\u0644\u0627\u0621 \u0648\u0627\u0644\u0639\u0631\u0648\u0636 \u0627\u0644\u062A\u0642\u062F\u064A\u0645\u064A\u0629.",
|
|
1421
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/93406e1b905a4c4994306e3421243390.mp3"
|
|
1422
|
-
},
|
|
1423
|
-
{
|
|
1424
|
-
id: "74c6aba5cbf94a15bbdc547ffce5cb38",
|
|
1425
|
-
name: "Yutong",
|
|
1426
|
-
gender: "female",
|
|
1427
|
-
languages: ["zh"],
|
|
1428
|
-
description: "\u58F0\u97F3\u6E05\u6670\u81EA\u7136\uFF0C\u8868\u8FBE\u5229\u843D\uFF0C\u9002\u5408\u8BED\u97F3\u52A9\u624B\u3001\u5BA2\u670D\u548C\u65E5\u5E38\u64AD\u62A5\u3002",
|
|
1429
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/a48320f37fe44c4699549a1afc3778e8.mp3"
|
|
1430
|
-
}
|
|
1431
|
-
];
|
|
1432
|
-
|
|
1433
|
-
// src/catalog/speech-fish.ts
|
|
1434
|
-
var FISH_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/fishaudio.png";
|
|
1435
|
-
var PER_CALL = { unit: "images" };
|
|
1436
|
-
var PER_REQUEST = { unit: "requests" };
|
|
1437
|
-
var TTS_MAX_CHARS = 1e4;
|
|
1438
|
-
function fishTts(id, label, providerModelId, description) {
|
|
1439
|
-
return {
|
|
1440
|
-
id,
|
|
1441
|
-
aliases: [],
|
|
1442
|
-
label,
|
|
1443
|
-
type: "speech",
|
|
1444
|
-
adapter: "fish",
|
|
1445
|
-
providerModelId,
|
|
1446
|
-
lifecycle: "active",
|
|
1447
|
-
exposure: [],
|
|
1448
|
-
constraints: {
|
|
1449
|
-
voices: FISH_VOICES,
|
|
1450
|
-
outputFormats: ["mp3", "wav"],
|
|
1451
|
-
supports: [],
|
|
1452
|
-
prompt: { referenceSyntax: "numbered", maxChars: TTS_MAX_CHARS }
|
|
1453
|
-
},
|
|
1454
|
-
defaults: { voice: "9a9cf47702da476aa4629e2506d4a857", outputFormat: "mp3" },
|
|
1455
|
-
usage: PER_CALL,
|
|
1456
|
-
pricingKind: "flat",
|
|
1457
|
-
display: { provider: "fishaudio", logo: FISH_LOGO, description },
|
|
1458
|
-
capabilities: { customVoices: true }
|
|
1459
|
-
};
|
|
1460
|
-
}
|
|
1461
|
-
var FISH_MODELS = [
|
|
1462
|
-
fishTts(
|
|
1463
|
-
"fish-s2.1-pro",
|
|
1464
|
-
"Fish Audio S2.1 Pro",
|
|
1465
|
-
"s2.1-pro",
|
|
1466
|
-
"Fish Audio S2.1 Pro text to speech in 83 languages, with [bracket] directions and your own cloned voices."
|
|
1467
|
-
),
|
|
1468
|
-
fishTts(
|
|
1469
|
-
"fish-s2.1-pro-free",
|
|
1470
|
-
"Fish Audio S2.1 Pro Free",
|
|
1471
|
-
"s2.1-pro-free",
|
|
1472
|
-
"Fish Audio S2.1 Pro on the free developer tier: the same voices at no cost, without latency or data-processing guarantees."
|
|
1473
|
-
),
|
|
1474
|
-
fishTts(
|
|
1475
|
-
"fish-drama-3",
|
|
1476
|
-
"Fish Audio Drama 3",
|
|
1477
|
-
"drama-3",
|
|
1478
|
-
"Fish Audio Drama 3 text to speech you direct like an actor: [directions], sounds, pauses and per-word tags."
|
|
1479
|
-
),
|
|
1480
|
-
{
|
|
1481
|
-
id: "fish-voice-clone",
|
|
1482
|
-
aliases: [],
|
|
1483
|
-
label: "Fish Audio Voice Clone",
|
|
1484
|
-
type: "voice-clone",
|
|
1485
|
-
adapter: "fish",
|
|
1486
|
-
providerModelId: "voice-clone",
|
|
1487
|
-
lifecycle: "active",
|
|
1488
|
-
exposure: [],
|
|
1489
|
-
constraints: {
|
|
1490
|
-
// POST /model takes 1-20 voice files; Fish advises 10 s or more of clean speech each.
|
|
1491
|
-
references: { audios: 20, audioFormats: ["wav", "mp3", "m4a", "opus"] },
|
|
1492
|
-
supports: []
|
|
1493
|
-
},
|
|
1494
|
-
defaults: {},
|
|
1495
|
-
usage: PER_REQUEST,
|
|
1496
|
-
pricingKind: "flat",
|
|
1497
|
-
display: {
|
|
1498
|
-
provider: "fishaudio",
|
|
1499
|
-
logo: FISH_LOGO,
|
|
1500
|
-
description: "Clone a private, reusable voice from one or more clean recordings, then speak with it on the Fish Audio speech models."
|
|
1501
|
-
},
|
|
1502
|
-
capabilities: {}
|
|
1503
|
-
},
|
|
1504
|
-
{
|
|
1505
|
-
id: "fish-voice-design-1",
|
|
1506
|
-
aliases: [],
|
|
1507
|
-
label: "Fish Audio Voice Design",
|
|
1508
|
-
type: "voice-design",
|
|
1509
|
-
adapter: "fish",
|
|
1510
|
-
providerModelId: "voice-design-1",
|
|
1511
|
-
lifecycle: "active",
|
|
1512
|
-
exposure: [],
|
|
1513
|
-
constraints: {
|
|
1514
|
-
voiceDesign: { maxCandidates: 4, previewMaxChars: 150 },
|
|
1515
|
-
supports: [],
|
|
1516
|
-
prompt: { referenceSyntax: "numbered", maxChars: 2e3 }
|
|
1517
|
-
},
|
|
1518
|
-
defaults: {},
|
|
1519
|
-
usage: PER_REQUEST,
|
|
1520
|
-
pricingKind: "flat",
|
|
1521
|
-
display: {
|
|
1522
|
-
provider: "fishaudio",
|
|
1523
|
-
logo: FISH_LOGO,
|
|
1524
|
-
description: "Describe a voice and get up to four short candidates; keep one as a cloned voice."
|
|
1525
|
-
},
|
|
1526
|
-
capabilities: {}
|
|
1527
|
-
}
|
|
1528
|
-
];
|
|
1529
|
-
|
|
1530
1233
|
// src/catalog/languages-audio.ts
|
|
1531
1234
|
var ELEVENLABS_V4_LANGUAGES = [
|
|
1532
1235
|
{ code: "af", name: "Afrikaans" },
|
|
@@ -1913,119 +1616,483 @@ var ELEVENLABS_VOICES = [
|
|
|
1913
1616
|
id: "Callum",
|
|
1914
1617
|
name: "Callum",
|
|
1915
1618
|
gender: "male",
|
|
1916
|
-
accent: "american",
|
|
1917
|
-
languages: ["en", "fr", "hi"],
|
|
1918
|
-
description: "Deceptively gravelly, yet unsettling edge.",
|
|
1919
|
-
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/N2lVS1w4EtoT3dr4eOWO/ac833bd8-ffda-4938-9ebc-b0f99ca25481.mp3"
|
|
1619
|
+
accent: "american",
|
|
1620
|
+
languages: ["en", "fr", "hi"],
|
|
1621
|
+
description: "Deceptively gravelly, yet unsettling edge.",
|
|
1622
|
+
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/N2lVS1w4EtoT3dr4eOWO/ac833bd8-ffda-4938-9ebc-b0f99ca25481.mp3"
|
|
1623
|
+
},
|
|
1624
|
+
{
|
|
1625
|
+
id: "River",
|
|
1626
|
+
name: "River",
|
|
1627
|
+
gender: "neutral",
|
|
1628
|
+
accent: "american",
|
|
1629
|
+
languages: ["en", "it", "fr", "pt", "zh"],
|
|
1630
|
+
description: "A relaxed, neutral voice ready for narrations or conversational projects.",
|
|
1631
|
+
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/SAz9YHcvj6GT2YYXdXww/e6c95f0b-2227-491a-b3d7-2249240decb7.mp3"
|
|
1632
|
+
},
|
|
1633
|
+
{
|
|
1634
|
+
id: "Liam",
|
|
1635
|
+
name: "Liam",
|
|
1636
|
+
gender: "male",
|
|
1637
|
+
accent: "american",
|
|
1638
|
+
languages: ["en", "de", "pt", "cs", "pl", "tr", "hi"],
|
|
1639
|
+
description: "A young adult with energy and warmth - suitable for reels and shorts.",
|
|
1640
|
+
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/TX3LPaxmHKxFdv7VOQHJ/63148076-6363-42db-aea8-31424308b92c.mp3"
|
|
1641
|
+
},
|
|
1642
|
+
{ id: "Charlotte", name: "Charlotte" },
|
|
1643
|
+
{
|
|
1644
|
+
id: "Alice",
|
|
1645
|
+
name: "Alice",
|
|
1646
|
+
gender: "female",
|
|
1647
|
+
accent: "british",
|
|
1648
|
+
languages: ["en", "it", "fr", "ar", "ja", "pl", "hi"],
|
|
1649
|
+
description: "Clear and engaging, friendly woman with a British accent suitable for e-learning.",
|
|
1650
|
+
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/Xb7hH8MSUJpSbSDYk0k2/d10f7534-11f6-41fe-a012-2de1e482d336.mp3"
|
|
1651
|
+
},
|
|
1652
|
+
{
|
|
1653
|
+
id: "Matilda",
|
|
1654
|
+
name: "Matilda",
|
|
1655
|
+
gender: "female",
|
|
1656
|
+
accent: "american",
|
|
1657
|
+
languages: ["en", "it", "fr", "de", "ar", "es"],
|
|
1658
|
+
description: "A professional woman with a pleasing alto pitch. Suitable for many use cases.",
|
|
1659
|
+
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/XrExE9yKIg1WjnnlVkGX/b930e18d-6b4d-466e-bab2-0ae97c6d8535.mp3"
|
|
1660
|
+
},
|
|
1661
|
+
{
|
|
1662
|
+
id: "Will",
|
|
1663
|
+
name: "Will",
|
|
1664
|
+
gender: "male",
|
|
1665
|
+
accent: "american",
|
|
1666
|
+
languages: ["en", "fr", "de", "pt", "zh", "cs", "fil", "sk", "es", "sv"],
|
|
1667
|
+
description: "Conversational and laid back.",
|
|
1668
|
+
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/bIHbv24MWmeRgasZH58o/8caf8f3d-ad29-4980-af41-53f20c72d7a4.mp3"
|
|
1669
|
+
},
|
|
1670
|
+
{
|
|
1671
|
+
id: "Jessica",
|
|
1672
|
+
name: "Jessica",
|
|
1673
|
+
gender: "female",
|
|
1674
|
+
accent: "american",
|
|
1675
|
+
languages: ["en", "fr", "ar", "ja", "zh", "de", "cs", "hi"],
|
|
1676
|
+
description: "Young and popular, this playful American female voice is perfect for trendy content.",
|
|
1677
|
+
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/cgSgspJ2msm6clMCkdW9/56a97bf8-b69b-448f-846c-c3a11683d45a.mp3"
|
|
1678
|
+
},
|
|
1679
|
+
{
|
|
1680
|
+
id: "Eric",
|
|
1681
|
+
name: "Eric",
|
|
1682
|
+
gender: "male",
|
|
1683
|
+
accent: "american",
|
|
1684
|
+
languages: ["en", "fr", "pt", "de", "sk", "es"],
|
|
1685
|
+
description: "A smooth tenor pitch from a man in his 40s - perfect for agentic use cases.",
|
|
1686
|
+
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/cjVigY5qzO86Huf0OWal/d098fda0-6456-4030-b3d8-63aa048c9070.mp3"
|
|
1687
|
+
},
|
|
1688
|
+
{
|
|
1689
|
+
id: "Chris",
|
|
1690
|
+
name: "Chris",
|
|
1691
|
+
gender: "male",
|
|
1692
|
+
accent: "american",
|
|
1693
|
+
languages: ["en", "fr", "ar", "pt", "sv", "hi"],
|
|
1694
|
+
description: "Natural and real, this down-to-earth voice is great across many use-cases.",
|
|
1695
|
+
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/iP95p4xoKVk53GoZ742B/3f4bde72-cc48-40dd-829f-57fbf906f4d7.mp3"
|
|
1696
|
+
},
|
|
1697
|
+
{
|
|
1698
|
+
id: "Brian",
|
|
1699
|
+
name: "Brian",
|
|
1700
|
+
gender: "male",
|
|
1701
|
+
accent: "american",
|
|
1702
|
+
languages: ["en", "ar", "zh", "pt", "de", "nl", "sk", "ro", "hi"],
|
|
1703
|
+
description: "Middle-aged man with a resonant and comforting tone. Great for narrations and advertisements.",
|
|
1704
|
+
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/nPczCjzI2devNBz1zQrb/2dd3e72c-4fd3-42f1-93ea-abc5d4e5aa1d.mp3"
|
|
1705
|
+
},
|
|
1706
|
+
{
|
|
1707
|
+
id: "Daniel",
|
|
1708
|
+
name: "Daniel",
|
|
1709
|
+
gender: "male",
|
|
1710
|
+
accent: "british",
|
|
1711
|
+
languages: ["en", "de", "tr"],
|
|
1712
|
+
description: "A strong voice perfect for delivering a professional broadcast or news story.",
|
|
1713
|
+
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/onwK4e9ZLuTAKqWW03F9/7eee0236-1a72-4b86-b303-5dcadc007ba9.mp3"
|
|
1714
|
+
},
|
|
1715
|
+
{
|
|
1716
|
+
id: "Lily",
|
|
1717
|
+
name: "Lily",
|
|
1718
|
+
gender: "female",
|
|
1719
|
+
accent: "british",
|
|
1720
|
+
languages: ["en", "it", "de", "zh", "cs", "nl", "pl"],
|
|
1721
|
+
description: "Velvety British female voice delivers news and narrations with warmth and clarity.",
|
|
1722
|
+
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/pFZP5JQG7iQjIQuC4Bku/89b68b35-b3dd-4348-a84a-a3c13a3c2b30.mp3"
|
|
1723
|
+
},
|
|
1724
|
+
{
|
|
1725
|
+
id: "Bill",
|
|
1726
|
+
name: "Bill",
|
|
1727
|
+
gender: "male",
|
|
1728
|
+
accent: "american",
|
|
1729
|
+
languages: ["en", "fr", "ar", "zh", "de", "cs"],
|
|
1730
|
+
description: "Friendly and comforting voice ready to narrate your stories.",
|
|
1731
|
+
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/pqHfZKP75CvOlQylNhV4/d782b3ff-84ba-4029-848c-acf01285524d.mp3"
|
|
1732
|
+
}
|
|
1733
|
+
];
|
|
1734
|
+
var PREMADE_ID = /\/premade\/voices\/([A-Za-z0-9]+)\//;
|
|
1735
|
+
var ELEVENLABS_DIRECT_VOICES = ELEVENLABS_VOICES.flatMap((v) => {
|
|
1736
|
+
const id = v.previewUrl ? PREMADE_ID.exec(v.previewUrl)?.[1] : void 0;
|
|
1737
|
+
return id ? [{ ...v, id }] : [];
|
|
1738
|
+
});
|
|
1739
|
+
var ELEVENLABS_DIRECT_DEFAULT_VOICE = "EXAVITQu4vr4xnSDxMaL";
|
|
1740
|
+
|
|
1741
|
+
// src/catalog/speech-elevenlabs-direct.ts
|
|
1742
|
+
var ELEVENLABS_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
|
|
1743
|
+
var PER_CALL = { unit: "images" };
|
|
1744
|
+
var PER_REQUEST = { unit: "requests" };
|
|
1745
|
+
var ELEVENLABS_DIRECT_MODELS = [
|
|
1746
|
+
{
|
|
1747
|
+
id: "elevenlabs-v4-direct",
|
|
1748
|
+
aliases: [],
|
|
1749
|
+
label: "ElevenLabs v4 (direct)",
|
|
1750
|
+
type: "speech",
|
|
1751
|
+
adapter: "elevenlabs",
|
|
1752
|
+
providerModelId: "eleven_v4",
|
|
1753
|
+
lifecycle: "active",
|
|
1754
|
+
exposure: [],
|
|
1755
|
+
constraints: {
|
|
1756
|
+
// Premade voices under their ElevenLabs ids (the direct API takes ids, not names).
|
|
1757
|
+
voices: ELEVENLABS_DIRECT_VOICES,
|
|
1758
|
+
languages: ELEVENLABS_V4_LANGUAGES,
|
|
1759
|
+
outputFormats: ELEVENLABS_MP3_FORMATS,
|
|
1760
|
+
supports: [],
|
|
1761
|
+
// ElevenLabs docs: 10,000 characters per request.
|
|
1762
|
+
prompt: { referenceSyntax: "numbered", maxChars: 1e4 }
|
|
1763
|
+
},
|
|
1764
|
+
defaults: { voice: ELEVENLABS_DIRECT_DEFAULT_VOICE, outputFormat: "mp3_44100_128" },
|
|
1765
|
+
usage: PER_CALL,
|
|
1766
|
+
pricingKind: "flat",
|
|
1767
|
+
display: {
|
|
1768
|
+
provider: "elevenlabs",
|
|
1769
|
+
logo: ELEVENLABS_LOGO,
|
|
1770
|
+
description: "ElevenLabs v4 text to speech with audio tags, in a premade voice or your own cloned voice; up to 10,000 characters."
|
|
1771
|
+
},
|
|
1772
|
+
capabilities: { customVoices: true }
|
|
1773
|
+
},
|
|
1774
|
+
{
|
|
1775
|
+
id: "elevenlabs-ivc",
|
|
1776
|
+
aliases: [],
|
|
1777
|
+
label: "ElevenLabs Instant Voice Clone",
|
|
1778
|
+
type: "voice-clone",
|
|
1779
|
+
adapter: "elevenlabs",
|
|
1780
|
+
providerModelId: "ivc",
|
|
1781
|
+
lifecycle: "active",
|
|
1782
|
+
exposure: [],
|
|
1783
|
+
constraints: {
|
|
1784
|
+
// POST /v1/voices/add; ElevenLabs takes up to 25 samples and advises 1-2 minutes of
|
|
1785
|
+
// clean speech in total. Each clone uses a voice slot on our plan until deleted.
|
|
1786
|
+
references: { audios: 25, audioFormats: ["mp3", "wav", "m4a", "webm", "ogg"] },
|
|
1787
|
+
supports: []
|
|
1788
|
+
},
|
|
1789
|
+
defaults: {},
|
|
1790
|
+
usage: PER_REQUEST,
|
|
1791
|
+
pricingKind: "flat",
|
|
1792
|
+
display: {
|
|
1793
|
+
provider: "elevenlabs",
|
|
1794
|
+
logo: ELEVENLABS_LOGO,
|
|
1795
|
+
description: "Clone a private, reusable voice from one or more clean recordings, then speak with it on ElevenLabs v4 (direct)."
|
|
1796
|
+
},
|
|
1797
|
+
capabilities: {}
|
|
1798
|
+
}
|
|
1799
|
+
];
|
|
1800
|
+
|
|
1801
|
+
// src/catalog/voices-fish.ts
|
|
1802
|
+
var FISH_VOICES = [
|
|
1803
|
+
{
|
|
1804
|
+
id: "933563129e564b19a115bedd57b7406a",
|
|
1805
|
+
name: "Sarah",
|
|
1806
|
+
gender: "female",
|
|
1807
|
+
languages: ["en"],
|
|
1808
|
+
description: "An engaged speaker.",
|
|
1809
|
+
previewUrl: "https://platform.r2.fish.audio/task/4e204945670c460c86fdab57512cb308.mp3"
|
|
1810
|
+
},
|
|
1811
|
+
{
|
|
1812
|
+
id: "bf322df2096a46f18c579d0baa36f41d",
|
|
1813
|
+
name: "Adrian",
|
|
1814
|
+
gender: "male",
|
|
1815
|
+
languages: ["en"],
|
|
1816
|
+
description: "A steady and reliable narrator.",
|
|
1817
|
+
previewUrl: "https://platform.r2.fish.audio/task/d730b09f4a484316a77ecc86137e85fb.mp3"
|
|
1818
|
+
},
|
|
1819
|
+
{
|
|
1820
|
+
id: "536d3a5e000945adb7038665781a4aca",
|
|
1821
|
+
name: "Ethan",
|
|
1822
|
+
gender: "male",
|
|
1823
|
+
languages: ["en"],
|
|
1824
|
+
description: "A curious explainer.",
|
|
1825
|
+
previewUrl: "https://platform.r2.fish.audio/task/bdd677ed767744fc91f166468786264b.mp3"
|
|
1826
|
+
},
|
|
1827
|
+
{
|
|
1828
|
+
id: "b347db033a6549378b48d00acb0d06cd",
|
|
1829
|
+
name: "Selene",
|
|
1830
|
+
gender: "female",
|
|
1831
|
+
languages: ["en"],
|
|
1832
|
+
description: "A meditative female voice.",
|
|
1833
|
+
previewUrl: "https://platform.r2.fish.audio/task/fcf629b4a0b343558f461338ba1b9da4.mp3"
|
|
1834
|
+
},
|
|
1835
|
+
{
|
|
1836
|
+
id: "9a9cf47702da476aa4629e2506d4a857",
|
|
1837
|
+
name: "Hannah",
|
|
1838
|
+
gender: "female",
|
|
1839
|
+
languages: ["en"],
|
|
1840
|
+
description: "A conversation specialist.",
|
|
1841
|
+
previewUrl: "https://platform.r2.fish.audio/task/08d658835feb427db808e37060b78eb0.mp3"
|
|
1842
|
+
},
|
|
1843
|
+
{
|
|
1844
|
+
id: "79d0bd3e4e5444b18f7b6d89b5927bf1",
|
|
1845
|
+
name: "Jordan",
|
|
1846
|
+
gender: "male",
|
|
1847
|
+
languages: ["en"],
|
|
1848
|
+
description: "A motivational speaker.",
|
|
1849
|
+
previewUrl: "https://platform.r2.fish.audio/task/edecbc0bdd4c46c39eda8520a0f729ef.mp3"
|
|
1850
|
+
},
|
|
1851
|
+
{
|
|
1852
|
+
id: "e3cd384158934cc9a01029cd7d278634",
|
|
1853
|
+
name: "Laura",
|
|
1854
|
+
gender: "female",
|
|
1855
|
+
languages: ["en"],
|
|
1856
|
+
description: "A confident female narrator.",
|
|
1857
|
+
previewUrl: "https://platform.r2.fish.audio/task/e821bef995344d519caa1c93d808db23.mp3"
|
|
1858
|
+
},
|
|
1859
|
+
{
|
|
1860
|
+
id: "f3a2b90078d54a65af4b95f63bc7798e",
|
|
1861
|
+
name: "Sheila",
|
|
1862
|
+
gender: "female",
|
|
1863
|
+
accent: "american",
|
|
1864
|
+
languages: ["en"],
|
|
1865
|
+
description: "A young American English woman's voice.",
|
|
1866
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/9bb9e1a1cf3f47f38700da1c5c0a678a.mp3"
|
|
1867
|
+
},
|
|
1868
|
+
{
|
|
1869
|
+
id: "0db6e93af420470b9d9b9a886dbaa954",
|
|
1870
|
+
name: "Kai",
|
|
1871
|
+
gender: "male",
|
|
1872
|
+
languages: ["en"],
|
|
1873
|
+
description: "A friendly English man's voice for companion apps and everyday conversation.",
|
|
1874
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/13306f1172544c3ba3106d1e363feaa6.mp3"
|
|
1875
|
+
},
|
|
1876
|
+
{
|
|
1877
|
+
id: "8abfa9ebd4c24a3399b68c3cdac8c7b5",
|
|
1878
|
+
name: "Freya",
|
|
1879
|
+
gender: "female",
|
|
1880
|
+
accent: "british",
|
|
1881
|
+
languages: ["en"],
|
|
1882
|
+
description: "A natural, professional British English voice with a brisk, conversational pace. Clear and easy to follow, suited to voice assistants, customer support and everyday narration.",
|
|
1883
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/07918705a56b42daaab149f65392cea7.mp3"
|
|
1884
|
+
},
|
|
1885
|
+
{
|
|
1886
|
+
id: "2f64e528a4f2406691925ab1e0ed5b7f",
|
|
1887
|
+
name: "Ananya",
|
|
1888
|
+
gender: "female",
|
|
1889
|
+
languages: ["hi"],
|
|
1890
|
+
description: "\u0938\u093E\u092B\u093C \u0914\u0930 \u0906\u0924\u094D\u092E\u0935\u093F\u0936\u094D\u0935\u093E\u0938 \u092D\u0930\u0940 \u0906\u0935\u093E\u091C\u093C, \u091C\u094B \u0935\u0949\u0907\u0938 \u0905\u0938\u093F\u0938\u094D\u091F\u0947\u0902\u091F, \u0917\u094D\u0930\u093E\u0939\u0915 \u0938\u0947\u0935\u093E \u0914\u0930 \u092A\u094D\u0930\u0938\u094D\u0924\u0941\u0924\u093F\u092F\u094B\u0902 \u0915\u0947 \u0932\u093F\u090F \u0909\u092A\u092F\u0941\u0915\u094D\u0924 \u0939\u0948\u0964",
|
|
1891
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/a17a700668d8405f8316db120733145c.mp3"
|
|
1892
|
+
},
|
|
1893
|
+
{
|
|
1894
|
+
id: "cefd91a07b99468f9148e2580990082d",
|
|
1895
|
+
name: "Arjun",
|
|
1896
|
+
gender: "male",
|
|
1897
|
+
languages: ["hi"],
|
|
1898
|
+
description: "\u0938\u093E\u092B\u093C \u0914\u0930 \u0906\u0924\u094D\u092E\u0935\u093F\u0936\u094D\u0935\u093E\u0938 \u092D\u0930\u0940 \u0906\u0935\u093E\u091C\u093C, \u091C\u094B \u0935\u0949\u0907\u0938 \u0905\u0938\u093F\u0938\u094D\u091F\u0947\u0902\u091F, \u0917\u094D\u0930\u093E\u0939\u0915 \u0938\u0947\u0935\u093E \u0914\u0930 \u092A\u094D\u0930\u0938\u094D\u0924\u0941\u0924\u093F\u092F\u094B\u0902 \u0915\u0947 \u0932\u093F\u090F \u0909\u092A\u092F\u0941\u0915\u094D\u0924 \u0939\u0948\u0964",
|
|
1899
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/a0c4a8eadb7841cdae8e5e68031a2dfb.mp3"
|
|
1920
1900
|
},
|
|
1921
1901
|
{
|
|
1922
|
-
id: "
|
|
1923
|
-
name: "
|
|
1924
|
-
gender: "
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/SAz9YHcvj6GT2YYXdXww/e6c95f0b-2227-491a-b3d7-2249240decb7.mp3"
|
|
1902
|
+
id: "3f065d660212478a9c697fa965b4d098",
|
|
1903
|
+
name: "Carmen",
|
|
1904
|
+
gender: "female",
|
|
1905
|
+
languages: ["es"],
|
|
1906
|
+
description: "Una voz clara y segura para asistentes de voz, atenci\xF3n al cliente y presentaciones.",
|
|
1907
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/3421be48b6cb4c28bf829c25188e7e74.mp3"
|
|
1929
1908
|
},
|
|
1930
1909
|
{
|
|
1931
|
-
id: "
|
|
1932
|
-
name: "
|
|
1910
|
+
id: "ec0718028a2445fb9be8e8bfb56a0150",
|
|
1911
|
+
name: "Rodrigo",
|
|
1933
1912
|
gender: "male",
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/TX3LPaxmHKxFdv7VOQHJ/63148076-6363-42db-aea8-31424308b92c.mp3"
|
|
1913
|
+
languages: ["es"],
|
|
1914
|
+
description: "Una voz clara y segura para asistentes de voz, atenci\xF3n al cliente y presentaciones.",
|
|
1915
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/5a77c32365604800ad5b4eb13c5585df.mp3"
|
|
1938
1916
|
},
|
|
1939
|
-
{ id: "Charlotte", name: "Charlotte" },
|
|
1940
1917
|
{
|
|
1941
|
-
id: "
|
|
1942
|
-
name: "
|
|
1918
|
+
id: "10a3a20742114a4ea6dd441e7591850f",
|
|
1919
|
+
name: "Manon",
|
|
1943
1920
|
gender: "female",
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/Xb7hH8MSUJpSbSDYk0k2/d10f7534-11f6-41fe-a012-2de1e482d336.mp3"
|
|
1921
|
+
languages: ["fr"],
|
|
1922
|
+
description: "Une voix claire et vive, adapt\xE9e aux assistants vocaux et au support client.",
|
|
1923
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/f7b75ee1fa524e48a8cefb003cf72952.mp3"
|
|
1948
1924
|
},
|
|
1949
1925
|
{
|
|
1950
|
-
id: "
|
|
1951
|
-
name: "
|
|
1926
|
+
id: "f69bca092b674168a8d02d61ca20943c",
|
|
1927
|
+
name: "Lucas",
|
|
1928
|
+
gender: "male",
|
|
1929
|
+
languages: ["fr"],
|
|
1930
|
+
description: "Une voix claire et assur\xE9e, adapt\xE9e aux assistants vocaux et au service client.",
|
|
1931
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/86fca3e56a014a3d8a11450854bb8311.mp3"
|
|
1932
|
+
},
|
|
1933
|
+
{
|
|
1934
|
+
id: "3937b44b604249f18b94913daef94043",
|
|
1935
|
+
name: "Lena",
|
|
1952
1936
|
gender: "female",
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/XrExE9yKIg1WjnnlVkGX/b930e18d-6b4d-466e-bab2-0ae97c6d8535.mp3"
|
|
1937
|
+
languages: ["de"],
|
|
1938
|
+
description: "Eine klare, souver\xE4ne Stimme f\xFCr Sprachassistenten, Kundenservice und Pr\xE4sentationen.",
|
|
1939
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/8659fec80b74442dab68a7755716a401.mp3"
|
|
1957
1940
|
},
|
|
1958
1941
|
{
|
|
1959
|
-
id: "
|
|
1960
|
-
name: "
|
|
1942
|
+
id: "c1e7cc926aa5469aa966c353094d4b0b",
|
|
1943
|
+
name: "Lukas",
|
|
1961
1944
|
gender: "male",
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/bIHbv24MWmeRgasZH58o/8caf8f3d-ad29-4980-af41-53f20c72d7a4.mp3"
|
|
1945
|
+
languages: ["de"],
|
|
1946
|
+
description: "Eine klare, souver\xE4ne Stimme f\xFCr Sprachassistenten, Kundenservice und Pr\xE4sentationen.",
|
|
1947
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/fb1d538126bb4fe38f8366250f6a2136.mp3"
|
|
1966
1948
|
},
|
|
1967
1949
|
{
|
|
1968
|
-
id: "
|
|
1969
|
-
name: "
|
|
1950
|
+
id: "b3c060cc41544a7da94a2c487647c902",
|
|
1951
|
+
name: "Let\xEDcia",
|
|
1970
1952
|
gender: "female",
|
|
1971
|
-
accent: "
|
|
1972
|
-
languages: ["
|
|
1973
|
-
description: "
|
|
1974
|
-
previewUrl: "https://
|
|
1953
|
+
accent: "brazilian",
|
|
1954
|
+
languages: ["pt"],
|
|
1955
|
+
description: "A Brazilian-accented Portuguese woman's voice, in her late twenties. Soft, warm, intimate. A freelance designer from Belo Horizonte who enjoys long walks in the park. Best suited to companion apps and casual everyday conversation.",
|
|
1956
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-10-12/13c6c0d96b5c4069951f89868ee15360.mp3"
|
|
1975
1957
|
},
|
|
1976
1958
|
{
|
|
1977
|
-
id: "
|
|
1978
|
-
name: "
|
|
1959
|
+
id: "add7bcb8d3c8423bbfa152ca232aad6e",
|
|
1960
|
+
name: "Ricardo",
|
|
1979
1961
|
gender: "male",
|
|
1980
|
-
accent: "
|
|
1981
|
-
languages: ["
|
|
1982
|
-
description: "A
|
|
1983
|
-
previewUrl: "https://
|
|
1962
|
+
accent: "brazilian",
|
|
1963
|
+
languages: ["pt"],
|
|
1964
|
+
description: "A Brazilian-accented Portuguese man's voice, in his late forties. Clear, professional, monotone. A high school history teacher from Curitiba who loves classical music. Best suited to lessons, tutoring and explainer content.",
|
|
1965
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-10-12/67475fc717ae45cbb38e647a2dd37fe1.mp3"
|
|
1984
1966
|
},
|
|
1985
1967
|
{
|
|
1986
|
-
id: "
|
|
1987
|
-
name: "
|
|
1988
|
-
gender: "
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/iP95p4xoKVk53GoZ742B/3f4bde72-cc48-40dd-829f-57fbf906f4d7.mp3"
|
|
1968
|
+
id: "b2d9d8db057042688a5e318b8f405bc2",
|
|
1969
|
+
name: "Kyoko",
|
|
1970
|
+
gender: "female",
|
|
1971
|
+
languages: ["ja"],
|
|
1972
|
+
description: "\u4E01\u5BE7\u3067\u843D\u3061\u7740\u3044\u305F\u8A71\u3057\u65B9\u304C\u7279\u5FB4\u306E\u5973\u6027\u306E\u58F0\u3002\u304A\u5BA2\u69D8\u5BFE\u5FDC\u3084\u60C5\u5831\u63D0\u4F9B\u306B\u6700\u9069\u3002",
|
|
1973
|
+
previewUrl: "https://platform.r2.fish.audio/task/993b3ccb52124341aff79580f1ce5a5a.mp3"
|
|
1993
1974
|
},
|
|
1994
1975
|
{
|
|
1995
|
-
id: "
|
|
1996
|
-
name: "
|
|
1976
|
+
id: "297a6fd278df47c3b9da9bfdf55ac89a",
|
|
1977
|
+
name: "Satoru",
|
|
1997
1978
|
gender: "male",
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/nPczCjzI2devNBz1zQrb/2dd3e72c-4fd3-42f1-93ea-abc5d4e5aa1d.mp3"
|
|
1979
|
+
languages: ["ja"],
|
|
1980
|
+
description: "\u82E5\u3005\u3057\u304F\u3082\u843D\u3061\u7740\u304D\u306E\u3042\u308B\u7537\u6027\u306E\u58F0\u3002\u65E5\u5E38\u306E\u8A9E\u308A\u3084\u30EA\u30E9\u30C3\u30AF\u30B9\u3057\u305F\u30CA\u30EC\u30FC\u30B7\u30E7\u30F3\u306B\u6700\u9069\u3002",
|
|
1981
|
+
previewUrl: "https://platform.r2.fish.audio/task/1b4712fb831f4c149eef6b0133157418.mp3"
|
|
2002
1982
|
},
|
|
2003
1983
|
{
|
|
2004
|
-
id: "
|
|
2005
|
-
name: "
|
|
2006
|
-
gender: "
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/onwK4e9ZLuTAKqWW03F9/7eee0236-1a72-4b86-b303-5dcadc007ba9.mp3"
|
|
1984
|
+
id: "0b14f34a13a94ed88fe6113193749bb0",
|
|
1985
|
+
name: "Fatima",
|
|
1986
|
+
gender: "female",
|
|
1987
|
+
languages: ["ar"],
|
|
1988
|
+
description: "\u0635\u0648\u062A \u0648\u0627\u0636\u062D \u0648\u0648\u0627\u062B\u0642 \u064A\u0646\u0627\u0633\u0628 \u0627\u0644\u0645\u0633\u0627\u0639\u062F\u0627\u062A \u0627\u0644\u0635\u0648\u062A\u064A\u0629 \u0648\u062E\u062F\u0645\u0629 \u0627\u0644\u0639\u0645\u0644\u0627\u0621 \u0648\u0627\u0644\u0639\u0631\u0648\u0636 \u0627\u0644\u062A\u0642\u062F\u064A\u0645\u064A\u0629.",
|
|
1989
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/93406e1b905a4c4994306e3421243390.mp3"
|
|
2011
1990
|
},
|
|
2012
1991
|
{
|
|
2013
|
-
id: "
|
|
2014
|
-
name: "
|
|
1992
|
+
id: "74c6aba5cbf94a15bbdc547ffce5cb38",
|
|
1993
|
+
name: "Yutong",
|
|
2015
1994
|
gender: "female",
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
1995
|
+
languages: ["zh"],
|
|
1996
|
+
description: "\u58F0\u97F3\u6E05\u6670\u81EA\u7136\uFF0C\u8868\u8FBE\u5229\u843D\uFF0C\u9002\u5408\u8BED\u97F3\u52A9\u624B\u3001\u5BA2\u670D\u548C\u65E5\u5E38\u64AD\u62A5\u3002",
|
|
1997
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/a48320f37fe44c4699549a1afc3778e8.mp3"
|
|
1998
|
+
}
|
|
1999
|
+
];
|
|
2000
|
+
|
|
2001
|
+
// src/catalog/speech-fish.ts
|
|
2002
|
+
var FISH_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/fishaudio.png";
|
|
2003
|
+
var PER_CALL2 = { unit: "images" };
|
|
2004
|
+
var PER_REQUEST2 = { unit: "requests" };
|
|
2005
|
+
var EXPOSURE4 = ["cowork", "space_builder"];
|
|
2006
|
+
var TTS_MAX_CHARS = 1e4;
|
|
2007
|
+
function fishTts(id, label, providerModelId, description) {
|
|
2008
|
+
return {
|
|
2009
|
+
id,
|
|
2010
|
+
aliases: [],
|
|
2011
|
+
label,
|
|
2012
|
+
type: "speech",
|
|
2013
|
+
adapter: "fish",
|
|
2014
|
+
providerModelId,
|
|
2015
|
+
lifecycle: "active",
|
|
2016
|
+
exposure: EXPOSURE4,
|
|
2017
|
+
constraints: {
|
|
2018
|
+
voices: FISH_VOICES,
|
|
2019
|
+
outputFormats: ["mp3", "wav"],
|
|
2020
|
+
supports: [],
|
|
2021
|
+
prompt: { referenceSyntax: "numbered", maxChars: TTS_MAX_CHARS }
|
|
2022
|
+
},
|
|
2023
|
+
defaults: { voice: "9a9cf47702da476aa4629e2506d4a857", outputFormat: "mp3" },
|
|
2024
|
+
usage: PER_CALL2,
|
|
2025
|
+
pricingKind: "flat",
|
|
2026
|
+
display: { provider: "fishaudio", logo: FISH_LOGO, description },
|
|
2027
|
+
capabilities: { customVoices: true }
|
|
2028
|
+
};
|
|
2029
|
+
}
|
|
2030
|
+
var FISH_MODELS = [
|
|
2031
|
+
fishTts(
|
|
2032
|
+
"fish-s2.1-pro",
|
|
2033
|
+
"Fish Audio S2.1 Pro",
|
|
2034
|
+
"s2.1-pro",
|
|
2035
|
+
"Fish Audio S2.1 Pro text to speech in 83 languages, with [bracket] directions and your own cloned voices."
|
|
2036
|
+
),
|
|
2037
|
+
fishTts(
|
|
2038
|
+
"fish-s2.1-pro-free",
|
|
2039
|
+
"Fish Audio S2.1 Pro Free",
|
|
2040
|
+
"s2.1-pro-free",
|
|
2041
|
+
"Fish Audio S2.1 Pro on the free developer tier: the same voices at no cost, without latency or data-processing guarantees."
|
|
2042
|
+
),
|
|
2043
|
+
fishTts(
|
|
2044
|
+
"fish-drama-3",
|
|
2045
|
+
"Fish Audio Drama 3",
|
|
2046
|
+
"drama-3",
|
|
2047
|
+
"Fish Audio Drama 3 text to speech you direct like an actor: [directions], sounds, pauses and per-word tags."
|
|
2048
|
+
),
|
|
2049
|
+
{
|
|
2050
|
+
id: "fish-voice-clone",
|
|
2051
|
+
aliases: [],
|
|
2052
|
+
label: "Fish Audio Voice Clone",
|
|
2053
|
+
type: "voice-clone",
|
|
2054
|
+
adapter: "fish",
|
|
2055
|
+
providerModelId: "voice-clone",
|
|
2056
|
+
lifecycle: "active",
|
|
2057
|
+
exposure: EXPOSURE4,
|
|
2058
|
+
constraints: {
|
|
2059
|
+
// POST /model takes 1-20 voice files; Fish advises 10 s or more of clean speech each.
|
|
2060
|
+
references: { audios: 20, audioFormats: ["wav", "mp3", "m4a", "opus"] },
|
|
2061
|
+
supports: []
|
|
2062
|
+
},
|
|
2063
|
+
defaults: {},
|
|
2064
|
+
usage: PER_REQUEST2,
|
|
2065
|
+
pricingKind: "flat",
|
|
2066
|
+
display: {
|
|
2067
|
+
provider: "fishaudio",
|
|
2068
|
+
logo: FISH_LOGO,
|
|
2069
|
+
description: "Clone a private, reusable voice from one or more clean recordings, then speak with it on the Fish Audio speech models."
|
|
2070
|
+
},
|
|
2071
|
+
capabilities: {}
|
|
2020
2072
|
},
|
|
2021
2073
|
{
|
|
2022
|
-
id: "
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2074
|
+
id: "fish-voice-design-1",
|
|
2075
|
+
aliases: [],
|
|
2076
|
+
label: "Fish Audio Voice Design",
|
|
2077
|
+
type: "voice-design",
|
|
2078
|
+
adapter: "fish",
|
|
2079
|
+
providerModelId: "voice-design-1",
|
|
2080
|
+
lifecycle: "active",
|
|
2081
|
+
exposure: EXPOSURE4,
|
|
2082
|
+
constraints: {
|
|
2083
|
+
voiceDesign: { maxCandidates: 4, previewMaxChars: 150 },
|
|
2084
|
+
supports: [],
|
|
2085
|
+
prompt: { referenceSyntax: "numbered", maxChars: 2e3 }
|
|
2086
|
+
},
|
|
2087
|
+
defaults: {},
|
|
2088
|
+
usage: PER_REQUEST2,
|
|
2089
|
+
pricingKind: "flat",
|
|
2090
|
+
display: {
|
|
2091
|
+
provider: "fishaudio",
|
|
2092
|
+
logo: FISH_LOGO,
|
|
2093
|
+
description: "Describe a voice and get up to four short candidates; keep one as a cloned voice."
|
|
2094
|
+
},
|
|
2095
|
+
capabilities: {}
|
|
2029
2096
|
}
|
|
2030
2097
|
];
|
|
2031
2098
|
|
|
@@ -3604,12 +3671,12 @@ var MINIMAX_VOICES = [
|
|
|
3604
3671
|
];
|
|
3605
3672
|
|
|
3606
3673
|
// src/catalog/media-nodes.ts
|
|
3607
|
-
var
|
|
3674
|
+
var ELEVENLABS_LOGO2 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
|
|
3608
3675
|
var GOOGLE_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
|
|
3609
3676
|
var MINIMAX_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png";
|
|
3610
3677
|
var SYNC_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/sync.png";
|
|
3611
|
-
var
|
|
3612
|
-
var
|
|
3678
|
+
var PER_CALL3 = { unit: "images" };
|
|
3679
|
+
var EXPOSURE5 = ["cowork", "space_builder"];
|
|
3613
3680
|
var LIPSYNC_AUDIO = { audioSeconds: { max: 30 } };
|
|
3614
3681
|
function elevenLabsTts(tts) {
|
|
3615
3682
|
return {
|
|
@@ -3620,7 +3687,7 @@ function elevenLabsTts(tts) {
|
|
|
3620
3687
|
adapter: "fal",
|
|
3621
3688
|
providerModelId: tts.providerModelId,
|
|
3622
3689
|
lifecycle: "active",
|
|
3623
|
-
exposure:
|
|
3690
|
+
exposure: EXPOSURE5,
|
|
3624
3691
|
constraints: {
|
|
3625
3692
|
voices: ELEVENLABS_VOICES,
|
|
3626
3693
|
languages: tts.languages,
|
|
@@ -3629,9 +3696,9 @@ function elevenLabsTts(tts) {
|
|
|
3629
3696
|
prompt: { referenceSyntax: "numbered", maxChars: tts.maxChars }
|
|
3630
3697
|
},
|
|
3631
3698
|
defaults: { voice: "Rachel", ...tts.formats && { outputFormat: "mp3_44100_128" } },
|
|
3632
|
-
usage:
|
|
3699
|
+
usage: PER_CALL3,
|
|
3633
3700
|
pricingKind: "flat",
|
|
3634
|
-
display: { provider: "elevenlabs", logo:
|
|
3701
|
+
display: { provider: "elevenlabs", logo: ELEVENLABS_LOGO2, description: tts.description },
|
|
3635
3702
|
capabilities: {}
|
|
3636
3703
|
};
|
|
3637
3704
|
}
|
|
@@ -3645,7 +3712,7 @@ function geminiTts(id, label, description) {
|
|
|
3645
3712
|
adapter: "fal",
|
|
3646
3713
|
providerModelId,
|
|
3647
3714
|
lifecycle: "active",
|
|
3648
|
-
exposure:
|
|
3715
|
+
exposure: EXPOSURE5,
|
|
3649
3716
|
constraints: {
|
|
3650
3717
|
voices: GEMINI_TTS_VOICES,
|
|
3651
3718
|
supports: ["style"],
|
|
@@ -3653,7 +3720,7 @@ function geminiTts(id, label, description) {
|
|
|
3653
3720
|
prompt: { referenceSyntax: "numbered", maxChars: 8192 }
|
|
3654
3721
|
},
|
|
3655
3722
|
defaults: { voice: "Kore" },
|
|
3656
|
-
usage:
|
|
3723
|
+
usage: PER_CALL3,
|
|
3657
3724
|
pricingKind: "flat",
|
|
3658
3725
|
display: { provider: "google", logo: GOOGLE_LOGO, description },
|
|
3659
3726
|
capabilities: {}
|
|
@@ -3668,7 +3735,7 @@ function syncLipsync(id, label, providerModelId, syncModel, description) {
|
|
|
3668
3735
|
adapter: "fal",
|
|
3669
3736
|
providerModelId,
|
|
3670
3737
|
lifecycle: "active",
|
|
3671
|
-
exposure:
|
|
3738
|
+
exposure: EXPOSURE5,
|
|
3672
3739
|
constraints: {
|
|
3673
3740
|
requires: ["sourceVideo", "sourceAudio"],
|
|
3674
3741
|
references: LIPSYNC_AUDIO,
|
|
@@ -3676,7 +3743,7 @@ function syncLipsync(id, label, providerModelId, syncModel, description) {
|
|
|
3676
3743
|
},
|
|
3677
3744
|
defaults: {},
|
|
3678
3745
|
...syncModel !== void 0 && { providerOptions: { fal: { model: syncModel } } },
|
|
3679
|
-
usage:
|
|
3746
|
+
usage: PER_CALL3,
|
|
3680
3747
|
pricingKind: "flat",
|
|
3681
3748
|
display: { provider: "sync", logo: SYNC_LOGO, description },
|
|
3682
3749
|
capabilities: { acceptsSourceVideo: true }
|
|
@@ -3729,7 +3796,7 @@ var MEDIA_NODE_MODELS = [
|
|
|
3729
3796
|
adapter: "fal",
|
|
3730
3797
|
providerModelId: "fal-ai/minimax/speech-2.8-hd",
|
|
3731
3798
|
lifecycle: "active",
|
|
3732
|
-
exposure:
|
|
3799
|
+
exposure: EXPOSURE5,
|
|
3733
3800
|
constraints: {
|
|
3734
3801
|
voices: MINIMAX_VOICES,
|
|
3735
3802
|
languages: MINIMAX_SPEECH_LANGUAGES,
|
|
@@ -3737,7 +3804,7 @@ var MEDIA_NODE_MODELS = [
|
|
|
3737
3804
|
prompt: { referenceSyntax: "numbered", maxChars: 1e4 }
|
|
3738
3805
|
},
|
|
3739
3806
|
defaults: { voice: "Wise_Woman" },
|
|
3740
|
-
usage:
|
|
3807
|
+
usage: PER_CALL3,
|
|
3741
3808
|
pricingKind: "flat",
|
|
3742
3809
|
display: {
|
|
3743
3810
|
provider: "minimax",
|
|
@@ -3754,7 +3821,7 @@ var MEDIA_NODE_MODELS = [
|
|
|
3754
3821
|
adapter: "fal",
|
|
3755
3822
|
providerModelId: "fal-ai/elevenlabs/voice-changer",
|
|
3756
3823
|
lifecycle: "active",
|
|
3757
|
-
exposure:
|
|
3824
|
+
exposure: EXPOSURE5,
|
|
3758
3825
|
constraints: {
|
|
3759
3826
|
requires: ["sourceAudio"],
|
|
3760
3827
|
// The flat price assumes at most a minute of speech.
|
|
@@ -3764,11 +3831,11 @@ var MEDIA_NODE_MODELS = [
|
|
|
3764
3831
|
supports: []
|
|
3765
3832
|
},
|
|
3766
3833
|
defaults: { voice: "Rachel", outputFormat: "mp3_44100_128" },
|
|
3767
|
-
usage:
|
|
3834
|
+
usage: PER_CALL3,
|
|
3768
3835
|
pricingKind: "flat",
|
|
3769
3836
|
display: {
|
|
3770
3837
|
provider: "elevenlabs",
|
|
3771
|
-
logo:
|
|
3838
|
+
logo: ELEVENLABS_LOGO2,
|
|
3772
3839
|
description: "ElevenLabs speech to speech; re-voices a recording in another voice and keeps its timing and delivery."
|
|
3773
3840
|
},
|
|
3774
3841
|
capabilities: {}
|
|
@@ -3781,7 +3848,7 @@ var MEDIA_NODE_MODELS = [
|
|
|
3781
3848
|
adapter: "fal",
|
|
3782
3849
|
providerModelId: "fal-ai/elevenlabs/dubbing",
|
|
3783
3850
|
lifecycle: "active",
|
|
3784
|
-
exposure:
|
|
3851
|
+
exposure: EXPOSURE5,
|
|
3785
3852
|
constraints: {
|
|
3786
3853
|
requiresOneOf: ["sourceVideo", "sourceAudio"],
|
|
3787
3854
|
// The flat price covers 60 s of source.
|
|
@@ -3791,11 +3858,11 @@ var MEDIA_NODE_MODELS = [
|
|
|
3791
3858
|
supports: []
|
|
3792
3859
|
},
|
|
3793
3860
|
defaults: {},
|
|
3794
|
-
usage:
|
|
3861
|
+
usage: PER_CALL3,
|
|
3795
3862
|
pricingKind: "flat",
|
|
3796
3863
|
display: {
|
|
3797
3864
|
provider: "elevenlabs",
|
|
3798
|
-
logo:
|
|
3865
|
+
logo: ELEVENLABS_LOGO2,
|
|
3799
3866
|
description: "ElevenLabs dubbing; translates the speech in a video or audio file into another language in the original voices."
|
|
3800
3867
|
},
|
|
3801
3868
|
capabilities: { acceptsSourceVideo: true }
|
|
@@ -3829,7 +3896,7 @@ var MEDIA_NODE_MODELS = [
|
|
|
3829
3896
|
adapter: "fal",
|
|
3830
3897
|
providerModelId: "veed/lipsync/v2",
|
|
3831
3898
|
lifecycle: "active",
|
|
3832
|
-
exposure:
|
|
3899
|
+
exposure: EXPOSURE5,
|
|
3833
3900
|
constraints: {
|
|
3834
3901
|
requires: ["sourceVideo", "sourceAudio"],
|
|
3835
3902
|
references: LIPSYNC_AUDIO,
|
|
@@ -3838,7 +3905,7 @@ var MEDIA_NODE_MODELS = [
|
|
|
3838
3905
|
supports: []
|
|
3839
3906
|
},
|
|
3840
3907
|
defaults: {},
|
|
3841
|
-
usage:
|
|
3908
|
+
usage: PER_CALL3,
|
|
3842
3909
|
pricingKind: "flat",
|
|
3843
3910
|
display: {
|
|
3844
3911
|
provider: "veed",
|
|
@@ -3855,7 +3922,7 @@ var MEDIA_NODE_MODELS = [
|
|
|
3855
3922
|
adapter: "fal",
|
|
3856
3923
|
providerModelId: "minimax/h3-max/lip-sync/image-to-video",
|
|
3857
3924
|
lifecycle: "active",
|
|
3858
|
-
exposure:
|
|
3925
|
+
exposure: EXPOSURE5,
|
|
3859
3926
|
constraints: {
|
|
3860
3927
|
requires: ["firstFrame", "sourceAudio"],
|
|
3861
3928
|
resolutions: ["480p", "768p", "1080p", "2k"],
|
|
@@ -3881,7 +3948,7 @@ var MEDIA_NODE_MODELS = [
|
|
|
3881
3948
|
adapter: "fal",
|
|
3882
3949
|
providerModelId: "fal-ai/elevenlabs/speech-to-text/scribe-v2",
|
|
3883
3950
|
lifecycle: "active",
|
|
3884
|
-
exposure:
|
|
3951
|
+
exposure: EXPOSURE5,
|
|
3885
3952
|
constraints: {
|
|
3886
3953
|
requires: ["sourceAudio"],
|
|
3887
3954
|
// The flat price covers 10 minutes of audio.
|
|
@@ -3890,17 +3957,18 @@ var MEDIA_NODE_MODELS = [
|
|
|
3890
3957
|
supports: []
|
|
3891
3958
|
},
|
|
3892
3959
|
defaults: {},
|
|
3893
|
-
usage:
|
|
3960
|
+
usage: PER_CALL3,
|
|
3894
3961
|
pricingKind: "flat",
|
|
3895
3962
|
display: {
|
|
3896
3963
|
provider: "elevenlabs",
|
|
3897
|
-
logo:
|
|
3964
|
+
logo: ELEVENLABS_LOGO2,
|
|
3898
3965
|
description: "ElevenLabs Scribe v2 speech to text with word timings, speaker labels and audio-event tags."
|
|
3899
3966
|
},
|
|
3900
3967
|
capabilities: {}
|
|
3901
3968
|
},
|
|
3902
3969
|
SAM_3_IMAGE,
|
|
3903
|
-
...FISH_MODELS
|
|
3970
|
+
...FISH_MODELS,
|
|
3971
|
+
...ELEVENLABS_DIRECT_MODELS
|
|
3904
3972
|
];
|
|
3905
3973
|
|
|
3906
3974
|
// src/catalog/model3d.ts
|
|
@@ -4096,7 +4164,7 @@ var MODEL3D_MODELS = [
|
|
|
4096
4164
|
|
|
4097
4165
|
// src/catalog/other.ts
|
|
4098
4166
|
var GOOGLE_LOGO2 = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
|
|
4099
|
-
var
|
|
4167
|
+
var ELEVENLABS_LOGO3 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
|
|
4100
4168
|
var MINIMAX_LOGO2 = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png";
|
|
4101
4169
|
var OTHER_MODELS = [
|
|
4102
4170
|
{
|
|
@@ -4261,7 +4329,7 @@ var OTHER_MODELS = [
|
|
|
4261
4329
|
pricingKind: "flat",
|
|
4262
4330
|
display: {
|
|
4263
4331
|
provider: "elevenlabs",
|
|
4264
|
-
logo:
|
|
4332
|
+
logo: ELEVENLABS_LOGO3,
|
|
4265
4333
|
description: "ElevenLabs Music v2.5 text-to-music; full songs or instrumentals from 3 seconds to 1 minute."
|
|
4266
4334
|
},
|
|
4267
4335
|
capabilities: {}
|
|
@@ -4313,7 +4381,7 @@ var OTHER_MODELS = [
|
|
|
4313
4381
|
pricingKind: "flat",
|
|
4314
4382
|
display: {
|
|
4315
4383
|
provider: "elevenlabs",
|
|
4316
|
-
logo:
|
|
4384
|
+
logo: ELEVENLABS_LOGO3,
|
|
4317
4385
|
description: "ElevenLabs Sound Effects v2; a sound effect from a text description, up to 22 seconds."
|
|
4318
4386
|
},
|
|
4319
4387
|
capabilities: {}
|
|
@@ -5495,7 +5563,7 @@ var VIDEO_FAMILY_MODELS = [
|
|
|
5495
5563
|
|
|
5496
5564
|
// src/catalog/video-luma.ts
|
|
5497
5565
|
var VIDEO_USAGE2 = { unit: "seconds" };
|
|
5498
|
-
var
|
|
5566
|
+
var EXPOSURE6 = ["cowork", "space_builder"];
|
|
5499
5567
|
var LUMA_LOGO2 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/luma-color.png";
|
|
5500
5568
|
var RAY_RATIOS = ["9:16", "3:4", "1:1", "4:3", "16:9", "21:9"];
|
|
5501
5569
|
var RAY_RESOLUTIONS = ["360p", "720p", "1080p"];
|
|
@@ -5513,7 +5581,7 @@ var LUMA_VIDEO_MODELS = [
|
|
|
5513
5581
|
adapter: "luma",
|
|
5514
5582
|
providerModelId: "ray-3.2",
|
|
5515
5583
|
lifecycle: "active",
|
|
5516
|
-
exposure:
|
|
5584
|
+
exposure: EXPOSURE6,
|
|
5517
5585
|
constraints: {
|
|
5518
5586
|
aspectRatios: ["adaptive", ...RAY_RATIOS],
|
|
5519
5587
|
resolutions: [...RAY_RESOLUTIONS],
|
|
@@ -5545,7 +5613,7 @@ var LUMA_VIDEO_MODELS = [
|
|
|
5545
5613
|
adapter: "luma",
|
|
5546
5614
|
providerModelId: "ray-3.2",
|
|
5547
5615
|
lifecycle: "active",
|
|
5548
|
-
exposure:
|
|
5616
|
+
exposure: EXPOSURE6,
|
|
5549
5617
|
constraints: {
|
|
5550
5618
|
resolutions: [...RAY_RESOLUTIONS],
|
|
5551
5619
|
requires: ["sourceVideo"],
|
|
@@ -5578,7 +5646,7 @@ var LUMA_VIDEO_MODELS = [
|
|
|
5578
5646
|
adapter: "luma",
|
|
5579
5647
|
providerModelId: "ray-3.2",
|
|
5580
5648
|
lifecycle: "active",
|
|
5581
|
-
exposure:
|
|
5649
|
+
exposure: EXPOSURE6,
|
|
5582
5650
|
constraints: {
|
|
5583
5651
|
aspectRatios: [...RAY_RATIOS],
|
|
5584
5652
|
resolutions: [...RAY_RESOLUTIONS],
|
|
@@ -7536,7 +7604,8 @@ var ADAPTER_IDS = [
|
|
|
7536
7604
|
"higgsfield",
|
|
7537
7605
|
"xai-video",
|
|
7538
7606
|
"luma",
|
|
7539
|
-
"fish"
|
|
7607
|
+
"fish",
|
|
7608
|
+
"elevenlabs"
|
|
7540
7609
|
];
|
|
7541
7610
|
var ModelTypeSchema = z3.enum([
|
|
7542
7611
|
"text",
|
|
@@ -8749,16 +8818,16 @@ async function generateSeedreamImage(req, ctx) {
|
|
|
8749
8818
|
} else {
|
|
8750
8819
|
throwArkError(void 0, "Seedream returned no image URL or base64 data", modelId);
|
|
8751
8820
|
}
|
|
8752
|
-
const
|
|
8821
|
+
const usage5 = {
|
|
8753
8822
|
model: modelId,
|
|
8754
8823
|
provider: "ark",
|
|
8755
8824
|
modality: "IMAGE",
|
|
8756
8825
|
unit: "images",
|
|
8757
8826
|
quantity: 1
|
|
8758
8827
|
};
|
|
8759
|
-
if (req.size !== void 0)
|
|
8760
|
-
if (req.quality !== void 0)
|
|
8761
|
-
return { images: [{ bytes, mime: sniffedImageMime(bytes) }], usage:
|
|
8828
|
+
if (req.size !== void 0) usage5.imageSize = req.size;
|
|
8829
|
+
if (req.quality !== void 0) usage5.imageQuality = req.quality;
|
|
8830
|
+
return { images: [{ bytes, mime: sniffedImageMime(bytes) }], usage: usage5, raw: data };
|
|
8762
8831
|
}
|
|
8763
8832
|
var SeedanceUsageSchema = z7.object({
|
|
8764
8833
|
total_tokens: z7.number().optional(),
|
|
@@ -8799,7 +8868,7 @@ function seedanceErrorMessage(error, status) {
|
|
|
8799
8868
|
if (asObject.success && asObject.data.message !== void 0) return asObject.data.message;
|
|
8800
8869
|
return `Seedance task ${status}`;
|
|
8801
8870
|
}
|
|
8802
|
-
function seedanceJob(ctx, key, jobId,
|
|
8871
|
+
function seedanceJob(ctx, key, jobId, usage5) {
|
|
8803
8872
|
const modelId = ctx.model.id;
|
|
8804
8873
|
const fetchStatus = async () => {
|
|
8805
8874
|
const res = await arkFetch(ctx, `${arkBaseUrl(ctx)}${SUBMIT_PATH}/${jobId}`, {
|
|
@@ -8849,21 +8918,21 @@ function seedanceJob(ctx, key, jobId, usage4) {
|
|
|
8849
8918
|
modelId
|
|
8850
8919
|
);
|
|
8851
8920
|
if (polled.duration !== void 0 && polled.duration > 0) {
|
|
8852
|
-
|
|
8853
|
-
|
|
8921
|
+
usage5.quantity = polled.duration;
|
|
8922
|
+
usage5.durationSeconds = polled.duration;
|
|
8854
8923
|
}
|
|
8855
8924
|
const rendered = VideoResolutionSchema.safeParse(
|
|
8856
8925
|
polled.resolution?.toLowerCase()
|
|
8857
8926
|
);
|
|
8858
|
-
if (rendered.success)
|
|
8927
|
+
if (rendered.success) usage5.resolution = rendered.data;
|
|
8859
8928
|
const tokens = polled.usage;
|
|
8860
8929
|
if (tokens?.total_tokens !== void 0 && tokens.completion_tokens !== void 0) {
|
|
8861
|
-
|
|
8862
|
-
|
|
8930
|
+
usage5.inputTokens = tokens.total_tokens - tokens.completion_tokens;
|
|
8931
|
+
usage5.outputTokens = tokens.completion_tokens;
|
|
8863
8932
|
}
|
|
8864
8933
|
return {
|
|
8865
8934
|
video: { url, expiresAt: new Date(Date.now() + VIDEO_URL_TTL_MS) },
|
|
8866
|
-
usage:
|
|
8935
|
+
usage: usage5,
|
|
8867
8936
|
raw: polled
|
|
8868
8937
|
};
|
|
8869
8938
|
}
|
|
@@ -8969,8 +9038,8 @@ async function generateSeedanceVideo(req, ctx) {
|
|
|
8969
9038
|
);
|
|
8970
9039
|
if (!submit.id) throwArkError(void 0, "Seedance task create returned no id", modelId);
|
|
8971
9040
|
const jobId = submit.id;
|
|
8972
|
-
const
|
|
8973
|
-
return seedanceJob(ctx, key, jobId,
|
|
9041
|
+
const usage5 = seedanceUsage(ctx, req, taskType === "edit" ? requestedDuration : duration);
|
|
9042
|
+
return seedanceJob(ctx, key, jobId, usage5);
|
|
8974
9043
|
}
|
|
8975
9044
|
|
|
8976
9045
|
// src/adapters/fal.ts
|
|
@@ -10458,7 +10527,7 @@ async function collectFalPlanImages(payload, plan4, ctx, req) {
|
|
|
10458
10527
|
return { bytes, mime: mime || "image/png" };
|
|
10459
10528
|
})
|
|
10460
10529
|
);
|
|
10461
|
-
const
|
|
10530
|
+
const usage5 = {
|
|
10462
10531
|
model: ctx.model.id,
|
|
10463
10532
|
provider: "fal",
|
|
10464
10533
|
modality: "IMAGE",
|
|
@@ -10466,9 +10535,9 @@ async function collectFalPlanImages(payload, plan4, ctx, req) {
|
|
|
10466
10535
|
quantity: images.length
|
|
10467
10536
|
};
|
|
10468
10537
|
const billedSize = plan4.imageSize ?? req.size;
|
|
10469
|
-
if (billedSize !== void 0 && ctx.model.type === "image")
|
|
10470
|
-
if (plan4.imageQuality !== void 0)
|
|
10471
|
-
const result = { images, usage:
|
|
10538
|
+
if (billedSize !== void 0 && ctx.model.type === "image") usage5.imageSize = billedSize;
|
|
10539
|
+
if (plan4.imageQuality !== void 0) usage5.imageQuality = plan4.imageQuality;
|
|
10540
|
+
const result = { images, usage: usage5, raw: payload };
|
|
10472
10541
|
const remote = files.find((f) => !f.url.startsWith("data:"));
|
|
10473
10542
|
if (remote !== void 0) result.outputUrl = remote.url;
|
|
10474
10543
|
return result;
|
|
@@ -12631,9 +12700,282 @@ function planUsage(ctx, plan4) {
|
|
|
12631
12700
|
};
|
|
12632
12701
|
}
|
|
12633
12702
|
|
|
12634
|
-
// src/adapters/
|
|
12703
|
+
// src/adapters/elevenlabs.ts
|
|
12635
12704
|
import { z as z21 } from "zod";
|
|
12636
|
-
var DEFAULT_BASE_URL = "https://api.
|
|
12705
|
+
var DEFAULT_BASE_URL = "https://api.elevenlabs.io";
|
|
12706
|
+
var DEFAULT_FORMAT = "mp3_44100_128";
|
|
12707
|
+
var ELEVENLABS_TTS_MODEL_IDS = /* @__PURE__ */ new Set(["eleven_v4"]);
|
|
12708
|
+
var ELEVENLABS_IVC = "ivc";
|
|
12709
|
+
var VOICE_ID = /^[A-Za-z0-9_-]{1,64}$/;
|
|
12710
|
+
function elevenLabsRowRefusal(row2) {
|
|
12711
|
+
const id = row2.providerModelId;
|
|
12712
|
+
if (row2.type === "speech") {
|
|
12713
|
+
return ELEVENLABS_TTS_MODEL_IDS.has(id) ? void 0 : `elevenlabs speech rows need providerModelId ${[...ELEVENLABS_TTS_MODEL_IDS].join(", ")}`;
|
|
12714
|
+
}
|
|
12715
|
+
if (row2.type === "voice-clone") {
|
|
12716
|
+
return id === ELEVENLABS_IVC ? void 0 : `elevenlabs voice-clone rows need providerModelId ${ELEVENLABS_IVC}`;
|
|
12717
|
+
}
|
|
12718
|
+
return `elevenlabs has no ${row2.type} rows`;
|
|
12719
|
+
}
|
|
12720
|
+
function elevenLabsError(ctx, code, message) {
|
|
12721
|
+
return new ModelKitError({
|
|
12722
|
+
code,
|
|
12723
|
+
message,
|
|
12724
|
+
provider: "elevenlabs",
|
|
12725
|
+
model: ctx.model.id,
|
|
12726
|
+
retryable: false
|
|
12727
|
+
});
|
|
12728
|
+
}
|
|
12729
|
+
function checkRow(ctx, type) {
|
|
12730
|
+
const refusal2 = ctx.model.type === type ? elevenLabsRowRefusal(ctx.model) : void 0;
|
|
12731
|
+
if (ctx.model.type !== type || refusal2 !== void 0) {
|
|
12732
|
+
throw elevenLabsError(
|
|
12733
|
+
ctx,
|
|
12734
|
+
"unsupported_option",
|
|
12735
|
+
refusal2 ?? `${ctx.model.id} is not a ${type} row`
|
|
12736
|
+
);
|
|
12737
|
+
}
|
|
12738
|
+
}
|
|
12739
|
+
function checkVoiceId(ctx, field, id) {
|
|
12740
|
+
if (!VOICE_ID.test(id))
|
|
12741
|
+
throw elevenLabsError(ctx, "unsupported_option", `${field} is not a voice id`);
|
|
12742
|
+
return id;
|
|
12743
|
+
}
|
|
12744
|
+
function elevenLabsKey(ctx) {
|
|
12745
|
+
const key = ctx.keys.elevenlabs;
|
|
12746
|
+
if (!key) throw elevenLabsError(ctx, "auth", "Missing API key for elevenlabs");
|
|
12747
|
+
return key;
|
|
12748
|
+
}
|
|
12749
|
+
function elevenLabsUrl(ctx, path) {
|
|
12750
|
+
return `${ctx.endpoints?.elevenlabs ?? DEFAULT_BASE_URL}${path}`;
|
|
12751
|
+
}
|
|
12752
|
+
var errorDetail = z21.object({
|
|
12753
|
+
detail: z21.object({ status: z21.string(), message: z21.string().optional() })
|
|
12754
|
+
});
|
|
12755
|
+
function errorStatus(body) {
|
|
12756
|
+
const parsed = errorDetail.safeParse(body);
|
|
12757
|
+
return parsed.success ? parsed.data.detail : void 0;
|
|
12758
|
+
}
|
|
12759
|
+
function classifyResponse(ctx, status, body) {
|
|
12760
|
+
const error = classifyHttpError(status, body, "elevenlabs", ctx.model.id);
|
|
12761
|
+
const detail = errorStatus(body);
|
|
12762
|
+
if (detail?.status === "voice_limit_reached") {
|
|
12763
|
+
return new ModelKitError({
|
|
12764
|
+
code: "provider_rejected",
|
|
12765
|
+
message: detail.message ?? "ElevenLabs voice limit reached",
|
|
12766
|
+
provider: "elevenlabs",
|
|
12767
|
+
model: ctx.model.id,
|
|
12768
|
+
status,
|
|
12769
|
+
body,
|
|
12770
|
+
cause: error,
|
|
12771
|
+
retryable: false
|
|
12772
|
+
});
|
|
12773
|
+
}
|
|
12774
|
+
if (detail?.status === "quota_exceeded") {
|
|
12775
|
+
return new ModelKitError({
|
|
12776
|
+
code: "provider_billing",
|
|
12777
|
+
message: error.message,
|
|
12778
|
+
provider: "elevenlabs",
|
|
12779
|
+
model: ctx.model.id,
|
|
12780
|
+
status,
|
|
12781
|
+
body,
|
|
12782
|
+
cause: error,
|
|
12783
|
+
retryable: false
|
|
12784
|
+
});
|
|
12785
|
+
}
|
|
12786
|
+
return error;
|
|
12787
|
+
}
|
|
12788
|
+
async function elevenLabsFetch(ctx, path, init) {
|
|
12789
|
+
throwIfAborted(ctx.signal);
|
|
12790
|
+
const request = {
|
|
12791
|
+
method: init.method,
|
|
12792
|
+
headers: { "xi-api-key": elevenLabsKey(ctx), ...init.headers }
|
|
12793
|
+
};
|
|
12794
|
+
if (init.body !== void 0) request.body = init.body;
|
|
12795
|
+
if (ctx.signal !== void 0) request.signal = ctx.signal;
|
|
12796
|
+
let res;
|
|
12797
|
+
try {
|
|
12798
|
+
res = await ctx.fetch(elevenLabsUrl(ctx, path), request);
|
|
12799
|
+
} catch (cause) {
|
|
12800
|
+
throw classifyThrown("elevenlabs", cause, ctx.model.id);
|
|
12801
|
+
}
|
|
12802
|
+
if (!res.ok) throw classifyResponse(ctx, res.status, await readBody(res));
|
|
12803
|
+
return res;
|
|
12804
|
+
}
|
|
12805
|
+
function usage2(ctx) {
|
|
12806
|
+
return {
|
|
12807
|
+
model: ctx.model.id,
|
|
12808
|
+
provider: "elevenlabs",
|
|
12809
|
+
modality: "AUDIO",
|
|
12810
|
+
unit: ctx.model.usage.unit,
|
|
12811
|
+
quantity: 1
|
|
12812
|
+
};
|
|
12813
|
+
}
|
|
12814
|
+
function audioMime(res) {
|
|
12815
|
+
const header = res.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase();
|
|
12816
|
+
return header?.startsWith("audio/") ? header : "audio/mpeg";
|
|
12817
|
+
}
|
|
12818
|
+
async function generateSpeech(req, ctx) {
|
|
12819
|
+
checkRow(ctx, "speech");
|
|
12820
|
+
const voice = req.customVoice ?? req.voice;
|
|
12821
|
+
if (voice === void 0) throw elevenLabsError(ctx, "missing_input", "needs a voice");
|
|
12822
|
+
const voiceId = checkVoiceId(ctx, req.customVoice ? "customVoice" : "voice", voice);
|
|
12823
|
+
const format = req.outputFormat ?? DEFAULT_FORMAT;
|
|
12824
|
+
const body = { text: req.text, model_id: ctx.model.providerModelId };
|
|
12825
|
+
if (req.language !== void 0) body.language_code = req.language;
|
|
12826
|
+
const path = `/v1/text-to-speech/${encodeURIComponent(voiceId)}?output_format=${encodeURIComponent(format)}`;
|
|
12827
|
+
const { bytes, mime } = await withRetry(
|
|
12828
|
+
async () => {
|
|
12829
|
+
const res = await elevenLabsFetch(ctx, path, {
|
|
12830
|
+
method: "POST",
|
|
12831
|
+
headers: { "Content-Type": "application/json" },
|
|
12832
|
+
body: JSON.stringify(body)
|
|
12833
|
+
});
|
|
12834
|
+
let audio;
|
|
12835
|
+
try {
|
|
12836
|
+
audio = new Uint8Array(await res.arrayBuffer());
|
|
12837
|
+
} catch (cause) {
|
|
12838
|
+
throw classifyThrown("elevenlabs", cause, ctx.model.id);
|
|
12839
|
+
}
|
|
12840
|
+
return { bytes: audio, mime: audioMime(res) };
|
|
12841
|
+
},
|
|
12842
|
+
mediaRetryOptions(ctx.call, ctx.signal)
|
|
12843
|
+
);
|
|
12844
|
+
if (bytes.byteLength === 0)
|
|
12845
|
+
throw elevenLabsError(ctx, "provider_rejected", "ElevenLabs TTS returned no audio");
|
|
12846
|
+
return { audio: { bytes, mime }, usage: usage2(ctx) };
|
|
12847
|
+
}
|
|
12848
|
+
var createdVoiceSchema = z21.object({
|
|
12849
|
+
voice_id: z21.string().min(1),
|
|
12850
|
+
requires_verification: z21.boolean().optional().catch(void 0)
|
|
12851
|
+
});
|
|
12852
|
+
function sampleMime(mime) {
|
|
12853
|
+
return mime.startsWith("audio/") || mime.startsWith("video/") ? mime : "application/octet-stream";
|
|
12854
|
+
}
|
|
12855
|
+
function fileName(index, mime, ref) {
|
|
12856
|
+
const fromMime = mime === "application/octet-stream" ? void 0 : mime.split("/")[1]?.replace("mpeg", "mp3").replace("x-", "");
|
|
12857
|
+
const fromUrl = "url" in ref ? /\.([A-Za-z0-9]{2,4})$/.exec(new URL(ref.url).pathname)?.[1] : void 0;
|
|
12858
|
+
const ext = fromMime || fromUrl?.toLowerCase();
|
|
12859
|
+
return ext ? `sample-${index + 1}.${ext}` : `sample-${index + 1}`;
|
|
12860
|
+
}
|
|
12861
|
+
async function cloneForm(req, ctx) {
|
|
12862
|
+
if (req.samples.length === 0)
|
|
12863
|
+
throw elevenLabsError(ctx, "missing_input", "needs a voice sample");
|
|
12864
|
+
if (req.samples.some((s) => s.designSignature?.trim())) {
|
|
12865
|
+
throw elevenLabsError(
|
|
12866
|
+
ctx,
|
|
12867
|
+
"unsupported_option",
|
|
12868
|
+
"ElevenLabs cannot keep a voice design signature; clone from recordings only"
|
|
12869
|
+
);
|
|
12870
|
+
}
|
|
12871
|
+
const form = new FormData();
|
|
12872
|
+
form.append("name", req.title.trim());
|
|
12873
|
+
if (req.description?.trim()) form.append("description", req.description.trim());
|
|
12874
|
+
if (req.enhance !== void 0) form.append("remove_background_noise", String(req.enhance));
|
|
12875
|
+
for (const [index, sample] of req.samples.entries()) {
|
|
12876
|
+
const { bytes, mime } = await mediaRefToBytes(sample.audio, ctx.fetch, {
|
|
12877
|
+
signal: ctx.signal,
|
|
12878
|
+
provider: "elevenlabs",
|
|
12879
|
+
model: ctx.model.id
|
|
12880
|
+
});
|
|
12881
|
+
const type = sampleMime(mime);
|
|
12882
|
+
const audio = new Blob([new Uint8Array(bytes)], { type });
|
|
12883
|
+
form.append("files", audio, fileName(index, type, sample.audio));
|
|
12884
|
+
}
|
|
12885
|
+
return form;
|
|
12886
|
+
}
|
|
12887
|
+
async function onlyRateLimitRetries(fn) {
|
|
12888
|
+
try {
|
|
12889
|
+
return await fn();
|
|
12890
|
+
} catch (cause) {
|
|
12891
|
+
if (!isModelKitError(cause) || !cause.retryable || cause.code === "rate_limited")
|
|
12892
|
+
throw cause;
|
|
12893
|
+
throw new ModelKitError({
|
|
12894
|
+
code: cause.code,
|
|
12895
|
+
message: cause.message,
|
|
12896
|
+
...cause.provider !== void 0 && { provider: cause.provider },
|
|
12897
|
+
...cause.model !== void 0 && { model: cause.model },
|
|
12898
|
+
...cause.status !== void 0 && { status: cause.status },
|
|
12899
|
+
...cause.body !== void 0 && { body: cause.body },
|
|
12900
|
+
cause,
|
|
12901
|
+
retryable: false
|
|
12902
|
+
});
|
|
12903
|
+
}
|
|
12904
|
+
}
|
|
12905
|
+
async function createVoice(req, ctx) {
|
|
12906
|
+
checkRow(ctx, "voice-clone");
|
|
12907
|
+
const form = await cloneForm(req, ctx);
|
|
12908
|
+
const res = await withRetry(
|
|
12909
|
+
() => onlyRateLimitRetries(
|
|
12910
|
+
() => elevenLabsFetch(ctx, "/v1/voices/add", { method: "POST", body: form })
|
|
12911
|
+
),
|
|
12912
|
+
mediaRetryOptions(ctx.call, ctx.signal)
|
|
12913
|
+
);
|
|
12914
|
+
const raw = await readBody(res);
|
|
12915
|
+
const parsed = createdVoiceSchema.safeParse(raw);
|
|
12916
|
+
if (!parsed.success) {
|
|
12917
|
+
throw new ModelKitError({
|
|
12918
|
+
code: "provider_rejected",
|
|
12919
|
+
message: "ElevenLabs returned no voice id",
|
|
12920
|
+
provider: "elevenlabs",
|
|
12921
|
+
model: ctx.model.id,
|
|
12922
|
+
status: res.status,
|
|
12923
|
+
body: raw,
|
|
12924
|
+
retryable: false
|
|
12925
|
+
});
|
|
12926
|
+
}
|
|
12927
|
+
return {
|
|
12928
|
+
voiceId: parsed.data.voice_id,
|
|
12929
|
+
state: parsed.data.requires_verification === true ? "created" : "trained",
|
|
12930
|
+
usage: usage2(ctx),
|
|
12931
|
+
raw
|
|
12932
|
+
};
|
|
12933
|
+
}
|
|
12934
|
+
var NOT_FOUND_STATUSES = /* @__PURE__ */ new Set([
|
|
12935
|
+
"voice_not_found",
|
|
12936
|
+
"voice_does_not_exist"
|
|
12937
|
+
]);
|
|
12938
|
+
function notFound(cause) {
|
|
12939
|
+
if (cause.status === 404) return true;
|
|
12940
|
+
const status = errorStatus(cause.body)?.status;
|
|
12941
|
+
return cause.status === 400 && status !== void 0 && NOT_FOUND_STATUSES.has(status);
|
|
12942
|
+
}
|
|
12943
|
+
async function deleteVoice(req, ctx) {
|
|
12944
|
+
checkRow(ctx, "voice-clone");
|
|
12945
|
+
const id = encodeURIComponent(checkVoiceId(ctx, "voiceId", req.voiceId));
|
|
12946
|
+
let attempts = 0;
|
|
12947
|
+
await withRetry(
|
|
12948
|
+
async () => {
|
|
12949
|
+
attempts += 1;
|
|
12950
|
+
try {
|
|
12951
|
+
await elevenLabsFetch(ctx, `/v1/voices/${id}`, { method: "DELETE" });
|
|
12952
|
+
} catch (cause) {
|
|
12953
|
+
if (!isModelKitError(cause) || !notFound(cause)) throw cause;
|
|
12954
|
+
if (attempts > 1) return;
|
|
12955
|
+
throw new ModelKitError({
|
|
12956
|
+
code: "provider_rejected",
|
|
12957
|
+
message: `ElevenLabs has no voice ${req.voiceId} under this key set; delete with the tier that created it`,
|
|
12958
|
+
provider: "elevenlabs",
|
|
12959
|
+
model: ctx.model.id,
|
|
12960
|
+
...cause.status !== void 0 && { status: cause.status },
|
|
12961
|
+
cause,
|
|
12962
|
+
retryable: false
|
|
12963
|
+
});
|
|
12964
|
+
}
|
|
12965
|
+
},
|
|
12966
|
+
mediaRetryOptions(ctx.call, ctx.signal)
|
|
12967
|
+
);
|
|
12968
|
+
}
|
|
12969
|
+
var elevenLabsAdapter = {
|
|
12970
|
+
id: "elevenlabs",
|
|
12971
|
+
generateSpeech,
|
|
12972
|
+
createVoice,
|
|
12973
|
+
deleteVoice
|
|
12974
|
+
};
|
|
12975
|
+
|
|
12976
|
+
// src/adapters/fish.ts
|
|
12977
|
+
import { z as z22 } from "zod";
|
|
12978
|
+
var DEFAULT_BASE_URL2 = "https://api.fish.audio";
|
|
12637
12979
|
var FISH_TTS_MODEL_IDS = /* @__PURE__ */ new Set([
|
|
12638
12980
|
"s2.1-pro",
|
|
12639
12981
|
"s2.1-pro-free",
|
|
@@ -12641,7 +12983,7 @@ var FISH_TTS_MODEL_IDS = /* @__PURE__ */ new Set([
|
|
|
12641
12983
|
]);
|
|
12642
12984
|
var FISH_VOICE_CLONE = "voice-clone";
|
|
12643
12985
|
var FISH_VOICE_DESIGN = "voice-design-1";
|
|
12644
|
-
var
|
|
12986
|
+
var VOICE_ID2 = /^[A-Za-z0-9_-]{1,64}$/;
|
|
12645
12987
|
function fishRowRefusal(row2) {
|
|
12646
12988
|
const id = row2.providerModelId;
|
|
12647
12989
|
if (row2.type === "speech") {
|
|
@@ -12664,7 +13006,7 @@ function fishError(ctx, code, message) {
|
|
|
12664
13006
|
retryable: false
|
|
12665
13007
|
});
|
|
12666
13008
|
}
|
|
12667
|
-
function
|
|
13009
|
+
function checkRow2(ctx, type) {
|
|
12668
13010
|
const refusal2 = ctx.model.type === type ? fishRowRefusal(ctx.model) : void 0;
|
|
12669
13011
|
if (ctx.model.type !== type || refusal2 !== void 0) {
|
|
12670
13012
|
throw fishError(
|
|
@@ -12674,8 +13016,8 @@ function checkRow(ctx, type) {
|
|
|
12674
13016
|
);
|
|
12675
13017
|
}
|
|
12676
13018
|
}
|
|
12677
|
-
function
|
|
12678
|
-
if (!
|
|
13019
|
+
function checkVoiceId2(ctx, field, id) {
|
|
13020
|
+
if (!VOICE_ID2.test(id))
|
|
12679
13021
|
throw fishError(ctx, "unsupported_option", `${field} is not a voice id`);
|
|
12680
13022
|
return id;
|
|
12681
13023
|
}
|
|
@@ -12685,7 +13027,7 @@ function fishKey(ctx) {
|
|
|
12685
13027
|
return key;
|
|
12686
13028
|
}
|
|
12687
13029
|
function fishUrl(ctx, path) {
|
|
12688
|
-
return `${ctx.endpoints?.fish ??
|
|
13030
|
+
return `${ctx.endpoints?.fish ?? DEFAULT_BASE_URL2}${path}`;
|
|
12689
13031
|
}
|
|
12690
13032
|
async function fishFetch(ctx, path, init) {
|
|
12691
13033
|
throwIfAborted(ctx.signal);
|
|
@@ -12704,7 +13046,7 @@ async function fishFetch(ctx, path, init) {
|
|
|
12704
13046
|
if (!res.ok) throw classifyHttpError(res.status, await readBody(res), "fish", ctx.model.id);
|
|
12705
13047
|
return res;
|
|
12706
13048
|
}
|
|
12707
|
-
function
|
|
13049
|
+
function usage3(ctx) {
|
|
12708
13050
|
return {
|
|
12709
13051
|
model: ctx.model.id,
|
|
12710
13052
|
provider: "fish",
|
|
@@ -12713,18 +13055,18 @@ function usage2(ctx) {
|
|
|
12713
13055
|
quantity: 1
|
|
12714
13056
|
};
|
|
12715
13057
|
}
|
|
12716
|
-
function
|
|
13058
|
+
function audioMime2(res, format) {
|
|
12717
13059
|
const header = res.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase();
|
|
12718
13060
|
if (header?.startsWith("audio/")) return header;
|
|
12719
13061
|
return format === "wav" ? "audio/wav" : "audio/mpeg";
|
|
12720
13062
|
}
|
|
12721
|
-
async function
|
|
12722
|
-
|
|
13063
|
+
async function generateSpeech2(req, ctx) {
|
|
13064
|
+
checkRow2(ctx, "speech");
|
|
12723
13065
|
const format = req.outputFormat ?? "mp3";
|
|
12724
13066
|
const body = { text: req.text, format };
|
|
12725
13067
|
const voice = req.customVoice ?? req.voice;
|
|
12726
13068
|
if (voice !== void 0) {
|
|
12727
|
-
body.reference_id =
|
|
13069
|
+
body.reference_id = checkVoiceId2(ctx, req.customVoice ? "customVoice" : "voice", voice);
|
|
12728
13070
|
}
|
|
12729
13071
|
if (req.language !== void 0) body.language = req.language;
|
|
12730
13072
|
const { bytes, mime } = await withRetry(
|
|
@@ -12740,19 +13082,19 @@ async function generateSpeech(req, ctx) {
|
|
|
12740
13082
|
} catch (cause) {
|
|
12741
13083
|
throw classifyThrown("fish", cause, ctx.model.id);
|
|
12742
13084
|
}
|
|
12743
|
-
return { bytes: audio, mime:
|
|
13085
|
+
return { bytes: audio, mime: audioMime2(res, format) };
|
|
12744
13086
|
},
|
|
12745
13087
|
mediaRetryOptions(ctx.call, ctx.signal)
|
|
12746
13088
|
);
|
|
12747
13089
|
if (bytes.byteLength === 0)
|
|
12748
13090
|
throw fishError(ctx, "provider_rejected", "Fish TTS returned no audio");
|
|
12749
|
-
return { audio: { bytes, mime }, usage:
|
|
13091
|
+
return { audio: { bytes, mime }, usage: usage3(ctx) };
|
|
12750
13092
|
}
|
|
12751
|
-
var createdModelSchema =
|
|
12752
|
-
_id:
|
|
12753
|
-
state:
|
|
13093
|
+
var createdModelSchema = z22.object({
|
|
13094
|
+
_id: z22.string().min(1),
|
|
13095
|
+
state: z22.enum(["created", "training", "trained", "failed"]).optional().catch(void 0)
|
|
12754
13096
|
});
|
|
12755
|
-
function
|
|
13097
|
+
function fileName2(index, mime) {
|
|
12756
13098
|
const ext = mime.split("/")[1]?.replace("mpeg", "mp3").replace("x-", "") || "bin";
|
|
12757
13099
|
return `sample-${index + 1}.${ext}`;
|
|
12758
13100
|
}
|
|
@@ -12764,7 +13106,7 @@ function allOrNone(ctx, field, values) {
|
|
|
12764
13106
|
}
|
|
12765
13107
|
return set;
|
|
12766
13108
|
}
|
|
12767
|
-
async function
|
|
13109
|
+
async function cloneForm2(req, ctx) {
|
|
12768
13110
|
if (req.samples.length === 0) throw fishError(ctx, "missing_input", "needs a voice sample");
|
|
12769
13111
|
const transcripts = allOrNone(
|
|
12770
13112
|
ctx,
|
|
@@ -12790,13 +13132,13 @@ async function cloneForm(req, ctx) {
|
|
|
12790
13132
|
model: ctx.model.id
|
|
12791
13133
|
});
|
|
12792
13134
|
const audio = new Blob([new Uint8Array(bytes)], { type: mime });
|
|
12793
|
-
form.append("voices", audio,
|
|
13135
|
+
form.append("voices", audio, fileName2(index, mime));
|
|
12794
13136
|
}
|
|
12795
13137
|
for (const text2 of transcripts) form.append("texts", text2.trim());
|
|
12796
13138
|
for (const signature of signatures) form.append("voice_design_signatures", signature);
|
|
12797
13139
|
return form;
|
|
12798
13140
|
}
|
|
12799
|
-
async function
|
|
13141
|
+
async function onlyRateLimitRetries2(fn) {
|
|
12800
13142
|
try {
|
|
12801
13143
|
return await fn();
|
|
12802
13144
|
} catch (cause) {
|
|
@@ -12814,11 +13156,11 @@ async function onlyRateLimitRetries(fn) {
|
|
|
12814
13156
|
});
|
|
12815
13157
|
}
|
|
12816
13158
|
}
|
|
12817
|
-
async function
|
|
12818
|
-
|
|
12819
|
-
const form = await
|
|
13159
|
+
async function createVoice2(req, ctx) {
|
|
13160
|
+
checkRow2(ctx, "voice-clone");
|
|
13161
|
+
const form = await cloneForm2(req, ctx);
|
|
12820
13162
|
const res = await withRetry(
|
|
12821
|
-
() =>
|
|
13163
|
+
() => onlyRateLimitRetries2(() => fishFetch(ctx, "/model", { method: "POST", body: form })),
|
|
12822
13164
|
mediaRetryOptions(ctx.call, ctx.signal)
|
|
12823
13165
|
);
|
|
12824
13166
|
const raw = await readBody(res);
|
|
@@ -12834,23 +13176,23 @@ async function createVoice(req, ctx) {
|
|
|
12834
13176
|
retryable: false
|
|
12835
13177
|
});
|
|
12836
13178
|
}
|
|
12837
|
-
const result = { voiceId: parsed.data._id, usage:
|
|
13179
|
+
const result = { voiceId: parsed.data._id, usage: usage3(ctx), raw };
|
|
12838
13180
|
if (parsed.data.state !== void 0) result.state = parsed.data.state;
|
|
12839
13181
|
return result;
|
|
12840
13182
|
}
|
|
12841
|
-
var designSchema =
|
|
12842
|
-
candidates:
|
|
12843
|
-
|
|
12844
|
-
id:
|
|
12845
|
-
index:
|
|
12846
|
-
audio_base64:
|
|
12847
|
-
duration_ms:
|
|
12848
|
-
signature:
|
|
13183
|
+
var designSchema = z22.object({
|
|
13184
|
+
candidates: z22.array(
|
|
13185
|
+
z22.looseObject({
|
|
13186
|
+
id: z22.string().min(1),
|
|
13187
|
+
index: z22.number().int(),
|
|
13188
|
+
audio_base64: z22.string().min(1),
|
|
13189
|
+
duration_ms: z22.number().nonnegative(),
|
|
13190
|
+
signature: z22.string().min(1).optional()
|
|
12849
13191
|
})
|
|
12850
13192
|
).min(1)
|
|
12851
13193
|
});
|
|
12852
13194
|
async function designVoice(req, ctx) {
|
|
12853
|
-
|
|
13195
|
+
checkRow2(ctx, "voice-design");
|
|
12854
13196
|
const body = { instruction: req.prompt.trim() };
|
|
12855
13197
|
if (req.previewText?.trim()) body.reference_text = req.previewText.trim();
|
|
12856
13198
|
if (req.language !== void 0) body.language = req.language;
|
|
@@ -12878,11 +13220,11 @@ async function designVoice(req, ctx) {
|
|
|
12878
13220
|
// rejects a clone whose signature does not verify, so a wrong one fails loudly.
|
|
12879
13221
|
signature: c.signature ?? c.id
|
|
12880
13222
|
}));
|
|
12881
|
-
return { candidates, usage:
|
|
13223
|
+
return { candidates, usage: usage3(ctx) };
|
|
12882
13224
|
}
|
|
12883
|
-
async function
|
|
12884
|
-
|
|
12885
|
-
const id = encodeURIComponent(
|
|
13225
|
+
async function deleteVoice2(req, ctx) {
|
|
13226
|
+
checkRow2(ctx, "voice-clone");
|
|
13227
|
+
const id = encodeURIComponent(checkVoiceId2(ctx, "voiceId", req.voiceId));
|
|
12886
13228
|
let attempts = 0;
|
|
12887
13229
|
await withRetry(
|
|
12888
13230
|
async () => {
|
|
@@ -12908,20 +13250,20 @@ async function deleteVoice(req, ctx) {
|
|
|
12908
13250
|
}
|
|
12909
13251
|
var fishAdapter = {
|
|
12910
13252
|
id: "fish",
|
|
12911
|
-
generateSpeech,
|
|
12912
|
-
createVoice,
|
|
13253
|
+
generateSpeech: generateSpeech2,
|
|
13254
|
+
createVoice: createVoice2,
|
|
12913
13255
|
designVoice,
|
|
12914
|
-
deleteVoice
|
|
13256
|
+
deleteVoice: deleteVoice2
|
|
12915
13257
|
};
|
|
12916
13258
|
|
|
12917
13259
|
// src/adapters/google-genai.ts
|
|
12918
|
-
import { z as
|
|
13260
|
+
import { z as z24 } from "zod";
|
|
12919
13261
|
import {
|
|
12920
13262
|
GoogleGenAI
|
|
12921
13263
|
} from "@google/genai";
|
|
12922
13264
|
|
|
12923
13265
|
// src/adapters/google-files.ts
|
|
12924
|
-
import { z as
|
|
13266
|
+
import { z as z23 } from "zod";
|
|
12925
13267
|
var GOOGLE_FILES_BASE = "https://generativelanguage.googleapis.com";
|
|
12926
13268
|
var GOOGLE_FILES_POLL_INTERVAL_MS = 2e3;
|
|
12927
13269
|
var GOOGLE_FILES_POLL_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
@@ -12931,17 +13273,17 @@ var GENERIC_MEDIA_TYPES = /* @__PURE__ */ new Set([
|
|
|
12931
13273
|
"binary/octet-stream",
|
|
12932
13274
|
"application/binary"
|
|
12933
13275
|
]);
|
|
12934
|
-
var uploadedFileSchema =
|
|
12935
|
-
file:
|
|
12936
|
-
uri:
|
|
12937
|
-
name:
|
|
12938
|
-
state:
|
|
12939
|
-
mimeType:
|
|
13276
|
+
var uploadedFileSchema = z23.object({
|
|
13277
|
+
file: z23.object({
|
|
13278
|
+
uri: z23.string().optional(),
|
|
13279
|
+
name: z23.string().optional(),
|
|
13280
|
+
state: z23.string().optional(),
|
|
13281
|
+
mimeType: z23.string().optional()
|
|
12940
13282
|
}).optional()
|
|
12941
13283
|
});
|
|
12942
|
-
var fileStateSchema =
|
|
12943
|
-
state:
|
|
12944
|
-
error:
|
|
13284
|
+
var fileStateSchema = z23.object({
|
|
13285
|
+
state: z23.string().optional(),
|
|
13286
|
+
error: z23.object({ message: z23.string().optional() }).optional()
|
|
12945
13287
|
});
|
|
12946
13288
|
function resolveMime(declared, fallback) {
|
|
12947
13289
|
const clean = declared?.split(";")[0]?.trim().toLowerCase();
|
|
@@ -13048,7 +13390,7 @@ async function startAndUpload(bytes, mimeType, opts) {
|
|
|
13048
13390
|
if (uploaded.file?.state !== void 0) ref.state = uploaded.file.state;
|
|
13049
13391
|
return ref;
|
|
13050
13392
|
}
|
|
13051
|
-
async function waitForActive(
|
|
13393
|
+
async function waitForActive(fileName3, opts) {
|
|
13052
13394
|
const pollOptions2 = {
|
|
13053
13395
|
intervalMs: GOOGLE_FILES_POLL_INTERVAL_MS,
|
|
13054
13396
|
timeoutMs: GOOGLE_FILES_POLL_TIMEOUT_MS
|
|
@@ -13061,14 +13403,14 @@ async function waitForActive(fileName2, opts) {
|
|
|
13061
13403
|
retryInit.signal = opts.signal;
|
|
13062
13404
|
}
|
|
13063
13405
|
await pollUntil(async () => {
|
|
13064
|
-
const res = await opts.fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${
|
|
13406
|
+
const res = await opts.fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName3}`, retryInit);
|
|
13065
13407
|
if (res.ok) {
|
|
13066
13408
|
const json = fileStateSchema.parse(await res.json());
|
|
13067
13409
|
if (json.state === "ACTIVE") return true;
|
|
13068
13410
|
if (json.state === "FAILED") {
|
|
13069
13411
|
throw classifyHttpError(
|
|
13070
13412
|
void 0,
|
|
13071
|
-
`Files API processing failed for ${
|
|
13413
|
+
`Files API processing failed for ${fileName3}: ${json.error?.message ?? "unknown error"}`,
|
|
13072
13414
|
"google-genai",
|
|
13073
13415
|
opts.model
|
|
13074
13416
|
);
|
|
@@ -13080,9 +13422,9 @@ async function waitForActive(fileName2, opts) {
|
|
|
13080
13422
|
throw classifyHttpError(res.status, text2, "google-genai", opts.model);
|
|
13081
13423
|
}, pollOptions2);
|
|
13082
13424
|
}
|
|
13083
|
-
async function deleteGoogleFile(
|
|
13425
|
+
async function deleteGoogleFile(fileName3, apiKey, fetchImpl) {
|
|
13084
13426
|
try {
|
|
13085
|
-
await fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${
|
|
13427
|
+
await fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName3}`, {
|
|
13086
13428
|
method: "DELETE",
|
|
13087
13429
|
headers: { "x-goog-api-key": apiKey }
|
|
13088
13430
|
});
|
|
@@ -13162,7 +13504,7 @@ var OMNI_POLL_INTERVAL_MS = 1e4;
|
|
|
13162
13504
|
var RESULT_TIMEOUT_MS3 = 15 * 60 * 1e3;
|
|
13163
13505
|
var OMNI_INLINE_LIMIT_BYTES = 4 * 1024 * 1024;
|
|
13164
13506
|
var MEDIA_PART_INLINE_LIMIT_BYTES = 10 * 1024 * 1024;
|
|
13165
|
-
var errorTextSchema =
|
|
13507
|
+
var errorTextSchema = z24.string();
|
|
13166
13508
|
function isGoogleGenaiVideoKnown(providerModelId) {
|
|
13167
13509
|
return providerModelId.startsWith("veo-") || providerModelId.startsWith("gemini-omni");
|
|
13168
13510
|
}
|
|
@@ -13357,7 +13699,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
|
|
|
13357
13699
|
}
|
|
13358
13700
|
};
|
|
13359
13701
|
const jobId = operation.name ?? crypto.randomUUID();
|
|
13360
|
-
const
|
|
13702
|
+
const usage5 = videoUsage2(ctx, duration, req.resolution ?? "720p");
|
|
13361
13703
|
return {
|
|
13362
13704
|
jobId,
|
|
13363
13705
|
async poll() {
|
|
@@ -13395,7 +13737,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
|
|
|
13395
13737
|
modelId
|
|
13396
13738
|
);
|
|
13397
13739
|
}
|
|
13398
|
-
return { video: await downloadVideo(ctx, uri, apiKey, signal), usage:
|
|
13740
|
+
return { video: await downloadVideo(ctx, uri, apiKey, signal), usage: usage5, raw: finished };
|
|
13399
13741
|
}
|
|
13400
13742
|
};
|
|
13401
13743
|
}
|
|
@@ -13506,7 +13848,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
|
|
|
13506
13848
|
return file.fileUri;
|
|
13507
13849
|
};
|
|
13508
13850
|
const cleanupUploads = async () => {
|
|
13509
|
-
for (const
|
|
13851
|
+
for (const fileName3 of uploadedNames) await deleteGoogleFile(fileName3, apiKey, ctx.fetch);
|
|
13510
13852
|
};
|
|
13511
13853
|
const callCreate = (input) => client2.interactions.create(
|
|
13512
13854
|
previousId !== void 0 ? {
|
|
@@ -13600,7 +13942,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
|
|
|
13600
13942
|
if (!(extend && !chained)) await cleanupUploads();
|
|
13601
13943
|
}
|
|
13602
13944
|
const jobId = interaction.id ?? crypto.randomUUID();
|
|
13603
|
-
const
|
|
13945
|
+
const usage5 = videoUsage2(ctx, duration, omniResolution ?? "720p");
|
|
13604
13946
|
const getInteraction = async () => {
|
|
13605
13947
|
try {
|
|
13606
13948
|
const getParams = { stream: false };
|
|
@@ -13648,7 +13990,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
|
|
|
13648
13990
|
bytes: Buffer.from(video.data, "base64"),
|
|
13649
13991
|
mime: video.mime_type ?? "video/mp4"
|
|
13650
13992
|
},
|
|
13651
|
-
usage:
|
|
13993
|
+
usage: usage5,
|
|
13652
13994
|
raw: done,
|
|
13653
13995
|
providerRef
|
|
13654
13996
|
};
|
|
@@ -13656,7 +13998,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
|
|
|
13656
13998
|
if (video.uri)
|
|
13657
13999
|
return {
|
|
13658
14000
|
video: await downloadVideo(ctx, video.uri, apiKey, signal),
|
|
13659
|
-
usage:
|
|
14001
|
+
usage: usage5,
|
|
13660
14002
|
raw: done,
|
|
13661
14003
|
providerRef
|
|
13662
14004
|
};
|
|
@@ -13826,15 +14168,15 @@ async function prepareGoogleMediaPart(ref, mediaType, ctx) {
|
|
|
13826
14168
|
// src/adapters/google-image.ts
|
|
13827
14169
|
import { createGoogleGenerativeAI as createGoogleGenerativeAI2 } from "@ai-sdk/google";
|
|
13828
14170
|
import { generateText } from "ai";
|
|
13829
|
-
import { z as
|
|
14171
|
+
import { z as z25 } from "zod";
|
|
13830
14172
|
var GEMINI_IMAGE_TIMEOUT_MS = 6e5;
|
|
13831
14173
|
var defaultGoogleImageDeps = {
|
|
13832
14174
|
createGoogleClient: (opts) => createGoogleGenerativeAI2(opts),
|
|
13833
14175
|
runTextGeneration: (opts) => generateText(opts)
|
|
13834
14176
|
};
|
|
13835
|
-
var causeChainNodeSchema =
|
|
13836
|
-
message:
|
|
13837
|
-
cause:
|
|
14177
|
+
var causeChainNodeSchema = z25.object({
|
|
14178
|
+
message: z25.string().optional(),
|
|
14179
|
+
cause: z25.unknown().optional()
|
|
13838
14180
|
});
|
|
13839
14181
|
function extractBlockReason(cause) {
|
|
13840
14182
|
let current = cause;
|
|
@@ -13934,7 +14276,7 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
|
|
|
13934
14276
|
retryable: false
|
|
13935
14277
|
});
|
|
13936
14278
|
}
|
|
13937
|
-
const
|
|
14279
|
+
const usage5 = {
|
|
13938
14280
|
model: ctx.model.id,
|
|
13939
14281
|
provider: "google-image",
|
|
13940
14282
|
modality: "IMAGE",
|
|
@@ -13942,19 +14284,19 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
|
|
|
13942
14284
|
quantity: images.length,
|
|
13943
14285
|
imageQuality: "auto"
|
|
13944
14286
|
};
|
|
13945
|
-
if (req.size !== void 0)
|
|
14287
|
+
if (req.size !== void 0) usage5.imageSize = req.size;
|
|
13946
14288
|
if (result.usage?.inputTokens !== void 0)
|
|
13947
|
-
|
|
14289
|
+
usage5.inputTokens = result.usage.inputTokens;
|
|
13948
14290
|
if (result.usage?.outputTokens !== void 0)
|
|
13949
|
-
|
|
13950
|
-
return { images, usage:
|
|
14291
|
+
usage5.outputTokens = result.usage.outputTokens;
|
|
14292
|
+
return { images, usage: usage5, raw: result };
|
|
13951
14293
|
}
|
|
13952
14294
|
};
|
|
13953
14295
|
}
|
|
13954
14296
|
var googleImageAdapter = createGoogleImageAdapter();
|
|
13955
14297
|
|
|
13956
14298
|
// src/adapters/higgsfield.ts
|
|
13957
|
-
import { z as
|
|
14299
|
+
import { z as z26 } from "zod";
|
|
13958
14300
|
|
|
13959
14301
|
// src/adapters/higgsfield-motions.ts
|
|
13960
14302
|
var MOTION_MAP = {
|
|
@@ -14173,14 +14515,14 @@ function klingEndpointFields(providerModelId) {
|
|
|
14173
14515
|
const path = (providerModelId.startsWith("/") ? providerModelId.slice(1) : providerModelId).toLowerCase();
|
|
14174
14516
|
return KLING_ENDPOINT_FIELDS.get(path) ?? UNLISTED_KLING_FIELDS;
|
|
14175
14517
|
}
|
|
14176
|
-
var klingCreateSchema =
|
|
14177
|
-
var klingStatusSchema =
|
|
14178
|
-
status:
|
|
14179
|
-
video:
|
|
14518
|
+
var klingCreateSchema = z26.object({ status_url: z26.string() });
|
|
14519
|
+
var klingStatusSchema = z26.object({
|
|
14520
|
+
status: z26.string().optional(),
|
|
14521
|
+
video: z26.object({ url: z26.string().optional() }).optional(),
|
|
14180
14522
|
error: JsonValueSchema.optional()
|
|
14181
14523
|
});
|
|
14182
|
-
var errorMessageSchema =
|
|
14183
|
-
var textValueSchema =
|
|
14524
|
+
var errorMessageSchema = z26.object({ message: z26.string().optional() });
|
|
14525
|
+
var textValueSchema = z26.string();
|
|
14184
14526
|
function klingErrorDetail(error) {
|
|
14185
14527
|
if (error === void 0) return "unknown_error";
|
|
14186
14528
|
const asText = textValueSchema.safeParse(error);
|
|
@@ -14336,8 +14678,8 @@ async function generateKlingVideo(req, ctx) {
|
|
|
14336
14678
|
}
|
|
14337
14679
|
};
|
|
14338
14680
|
}
|
|
14339
|
-
var dopMotionOptionsSchema =
|
|
14340
|
-
modelkit:
|
|
14681
|
+
var dopMotionOptionsSchema = z26.object({
|
|
14682
|
+
modelkit: z26.object({ motion: z26.string().optional() }).optional()
|
|
14341
14683
|
});
|
|
14342
14684
|
function dopMotionId(ctx) {
|
|
14343
14685
|
const parsed = dopMotionOptionsSchema.safeParse(ctx.model.providerOptions);
|
|
@@ -14353,7 +14695,7 @@ function dopMotionId(ctx) {
|
|
|
14353
14695
|
});
|
|
14354
14696
|
return id;
|
|
14355
14697
|
}
|
|
14356
|
-
var jsonRecordSchema =
|
|
14698
|
+
var jsonRecordSchema = z26.record(z26.string(), JsonValueSchema);
|
|
14357
14699
|
var DOP_URL_KEYS = ["url", "video_url", "output_url", "result_url", "download_url"];
|
|
14358
14700
|
var DOP_NESTED_KEYS = ["video", "result", "results"];
|
|
14359
14701
|
function dopUrl(body) {
|
|
@@ -14381,8 +14723,8 @@ function dopUrl(body) {
|
|
|
14381
14723
|
}
|
|
14382
14724
|
return void 0;
|
|
14383
14725
|
}
|
|
14384
|
-
var dopCreateSchema =
|
|
14385
|
-
var dopStatusSchema =
|
|
14726
|
+
var dopCreateSchema = z26.object({ id: z26.string() });
|
|
14727
|
+
var dopStatusSchema = z26.object({ status: z26.string().optional() });
|
|
14386
14728
|
async function generateDopVideo(req, ctx) {
|
|
14387
14729
|
const firstFrame = req.firstFrame ? refToUrl(req.firstFrame) : void 0;
|
|
14388
14730
|
if (!firstFrame) {
|
|
@@ -14509,7 +14851,7 @@ var higgsfieldAdapter = {
|
|
|
14509
14851
|
};
|
|
14510
14852
|
|
|
14511
14853
|
// src/adapters/luma.ts
|
|
14512
|
-
import { z as
|
|
14854
|
+
import { z as z27 } from "zod";
|
|
14513
14855
|
|
|
14514
14856
|
// src/adapters/mp4-duration.ts
|
|
14515
14857
|
function mp4DurationSeconds(bytes) {
|
|
@@ -14565,7 +14907,7 @@ function findBox(bytes, from, to, type) {
|
|
|
14565
14907
|
}
|
|
14566
14908
|
|
|
14567
14909
|
// src/adapters/luma.ts
|
|
14568
|
-
var
|
|
14910
|
+
var DEFAULT_BASE_URL3 = "https://agents.lumalabs.ai";
|
|
14569
14911
|
var IMAGE_POLL_INTERVAL_MS = 3e3;
|
|
14570
14912
|
var IMAGE_TIMEOUT_MS = 5 * 6e4;
|
|
14571
14913
|
var VIDEO_POLL_INTERVAL_MS = 5e3;
|
|
@@ -14594,7 +14936,7 @@ function lumaModel(ctx) {
|
|
|
14594
14936
|
return ctx.model.providerModelId.toLowerCase();
|
|
14595
14937
|
}
|
|
14596
14938
|
function lumaBase(ctx) {
|
|
14597
|
-
return ctx.endpoints?.luma ??
|
|
14939
|
+
return ctx.endpoints?.luma ?? DEFAULT_BASE_URL3;
|
|
14598
14940
|
}
|
|
14599
14941
|
function lumaKey(ctx) {
|
|
14600
14942
|
const key = ctx.keys.luma;
|
|
@@ -14726,17 +15068,17 @@ function lumaReframeResolution(req, ctx) {
|
|
|
14726
15068
|
});
|
|
14727
15069
|
return "720p";
|
|
14728
15070
|
}
|
|
14729
|
-
var lumaGenerationSchema =
|
|
14730
|
-
id:
|
|
14731
|
-
state:
|
|
14732
|
-
output:
|
|
14733
|
-
|
|
14734
|
-
type:
|
|
14735
|
-
url:
|
|
15071
|
+
var lumaGenerationSchema = z27.looseObject({
|
|
15072
|
+
id: z27.string(),
|
|
15073
|
+
state: z27.string().optional(),
|
|
15074
|
+
output: z27.array(
|
|
15075
|
+
z27.looseObject({
|
|
15076
|
+
type: z27.string().optional(),
|
|
15077
|
+
url: z27.string().optional()
|
|
14736
15078
|
})
|
|
14737
15079
|
).optional(),
|
|
14738
|
-
failure_reason:
|
|
14739
|
-
failure_code:
|
|
15080
|
+
failure_reason: z27.string().optional().nullable(),
|
|
15081
|
+
failure_code: z27.string().optional().nullable()
|
|
14740
15082
|
});
|
|
14741
15083
|
function lumaFailure(ctx, code, reason) {
|
|
14742
15084
|
const detail = reason ?? code ?? "unknown_error";
|
|
@@ -15168,7 +15510,7 @@ var lumaAdapter = {
|
|
|
15168
15510
|
|
|
15169
15511
|
// src/adapters/openai-image.ts
|
|
15170
15512
|
import OpenAI from "openai";
|
|
15171
|
-
import { z as
|
|
15513
|
+
import { z as z28 } from "zod";
|
|
15172
15514
|
var MAX_EDIT_REFERENCES = 16;
|
|
15173
15515
|
function aspectRatioToSize(ratio, tier) {
|
|
15174
15516
|
const TIER_LONG_EDGE = {
|
|
@@ -15251,9 +15593,9 @@ function toProviderError2(cause, ctx) {
|
|
|
15251
15593
|
ctx.model.id
|
|
15252
15594
|
);
|
|
15253
15595
|
}
|
|
15254
|
-
var openaiUsageSchema =
|
|
15255
|
-
input_tokens:
|
|
15256
|
-
output_tokens:
|
|
15596
|
+
var openaiUsageSchema = z28.object({
|
|
15597
|
+
input_tokens: z28.number().optional(),
|
|
15598
|
+
output_tokens: z28.number().optional()
|
|
15257
15599
|
});
|
|
15258
15600
|
var openaiImageAdapter = {
|
|
15259
15601
|
id: "openai-image",
|
|
@@ -15378,7 +15720,7 @@ var openaiImageAdapter = {
|
|
|
15378
15720
|
const usageParsed = openaiUsageSchema.safeParse(response.usage);
|
|
15379
15721
|
const inputTokens = usageParsed.success ? usageParsed.data.input_tokens : void 0;
|
|
15380
15722
|
const outputTokens = usageParsed.success ? usageParsed.data.output_tokens : void 0;
|
|
15381
|
-
const
|
|
15723
|
+
const usage5 = {
|
|
15382
15724
|
model: ctx.model.id,
|
|
15383
15725
|
provider: "openai-image",
|
|
15384
15726
|
modality: "IMAGE",
|
|
@@ -15386,10 +15728,10 @@ var openaiImageAdapter = {
|
|
|
15386
15728
|
quantity: images.length,
|
|
15387
15729
|
imageQuality: quality
|
|
15388
15730
|
};
|
|
15389
|
-
if (inputTokens !== void 0)
|
|
15390
|
-
if (outputTokens !== void 0)
|
|
15391
|
-
if (req.size !== void 0)
|
|
15392
|
-
return { images, usage:
|
|
15731
|
+
if (inputTokens !== void 0) usage5.inputTokens = inputTokens;
|
|
15732
|
+
if (outputTokens !== void 0) usage5.outputTokens = outputTokens;
|
|
15733
|
+
if (req.size !== void 0) usage5.imageSize = req.size;
|
|
15734
|
+
return { images, usage: usage5, raw: response };
|
|
15393
15735
|
}
|
|
15394
15736
|
};
|
|
15395
15737
|
|
|
@@ -15645,16 +15987,16 @@ async function generateProdiaImage(req, ctx) {
|
|
|
15645
15987
|
new Uint8Array(await res.arrayBuffer()),
|
|
15646
15988
|
res.headers.get("content-type")
|
|
15647
15989
|
);
|
|
15648
|
-
const
|
|
15990
|
+
const usage5 = {
|
|
15649
15991
|
model: ctx.model.id,
|
|
15650
15992
|
provider: "prodia",
|
|
15651
15993
|
modality: "IMAGE",
|
|
15652
15994
|
unit: "images",
|
|
15653
15995
|
quantity: 1
|
|
15654
15996
|
};
|
|
15655
|
-
if (req.size !== void 0)
|
|
15656
|
-
if (req.quality !== void 0)
|
|
15657
|
-
return { images: [{ bytes, mime }], usage:
|
|
15997
|
+
if (req.size !== void 0) usage5.imageSize = req.size;
|
|
15998
|
+
if (req.quality !== void 0) usage5.imageQuality = req.quality;
|
|
15999
|
+
return { images: [{ bytes, mime }], usage: usage5, raw: void 0 };
|
|
15658
16000
|
}
|
|
15659
16001
|
var prodiaAdapter = {
|
|
15660
16002
|
id: "prodia",
|
|
@@ -15665,13 +16007,13 @@ var prodiaAdapter = {
|
|
|
15665
16007
|
import Replicate from "replicate";
|
|
15666
16008
|
|
|
15667
16009
|
// src/adapters/replicate-http.ts
|
|
15668
|
-
import { z as
|
|
15669
|
-
var predictionSchema =
|
|
15670
|
-
id:
|
|
15671
|
-
status:
|
|
16010
|
+
import { z as z29 } from "zod";
|
|
16011
|
+
var predictionSchema = z29.object({
|
|
16012
|
+
id: z29.string(),
|
|
16013
|
+
status: z29.string(),
|
|
15672
16014
|
output: JsonValueSchema.optional(),
|
|
15673
16015
|
error: JsonValueSchema.optional(),
|
|
15674
|
-
metrics:
|
|
16016
|
+
metrics: z29.object({ predict_time: z29.number().optional() }).optional()
|
|
15675
16017
|
});
|
|
15676
16018
|
function createReplicateHttpClient(opts) {
|
|
15677
16019
|
async function request(path, body, signal) {
|
|
@@ -15722,7 +16064,7 @@ function createReplicateHttpClient(opts) {
|
|
|
15722
16064
|
}
|
|
15723
16065
|
|
|
15724
16066
|
// src/adapters/replicate.ts
|
|
15725
|
-
import { z as
|
|
16067
|
+
import { z as z30 } from "zod";
|
|
15726
16068
|
var POLL_INTERVAL_MS = 1e3;
|
|
15727
16069
|
var POLL_TIMEOUT_MS = 15 * 6e4;
|
|
15728
16070
|
var defaultReplicateDeps = {
|
|
@@ -15762,8 +16104,8 @@ function route(providerModelId) {
|
|
|
15762
16104
|
if (!providerModelId.includes("/")) return { version: providerModelId };
|
|
15763
16105
|
return { model: providerModelId };
|
|
15764
16106
|
}
|
|
15765
|
-
var replicateResponseStatusSchema =
|
|
15766
|
-
response:
|
|
16107
|
+
var replicateResponseStatusSchema = z30.object({
|
|
16108
|
+
response: z30.object({ status: z30.number() }).partial()
|
|
15767
16109
|
});
|
|
15768
16110
|
function replicateError(cause, ctx) {
|
|
15769
16111
|
if (isModelKitError(cause)) return cause;
|
|
@@ -15786,7 +16128,7 @@ function isUrlFn(value) {
|
|
|
15786
16128
|
function extractOutputUrl(output) {
|
|
15787
16129
|
const root = Array.isArray(output) ? output[0] : output;
|
|
15788
16130
|
if (root === void 0) throw noOutput();
|
|
15789
|
-
const asString =
|
|
16131
|
+
const asString = z30.string().safeParse(root);
|
|
15790
16132
|
if (asString.success && asString.data) return asString.data;
|
|
15791
16133
|
if (root instanceof URL) return root.href;
|
|
15792
16134
|
if (isObjectOutput(root)) {
|
|
@@ -15795,15 +16137,15 @@ function extractOutputUrl(output) {
|
|
|
15795
16137
|
if (urlValue !== void 0 && isUrlFn(urlValue)) {
|
|
15796
16138
|
const called = urlValue();
|
|
15797
16139
|
if (called instanceof URL) return called.href;
|
|
15798
|
-
const calledString =
|
|
16140
|
+
const calledString = z30.string().safeParse(called);
|
|
15799
16141
|
if (calledString.success && calledString.data) return calledString.data;
|
|
15800
16142
|
} else {
|
|
15801
|
-
const direct =
|
|
16143
|
+
const direct = z30.string().safeParse(urlValue);
|
|
15802
16144
|
if (direct.success && direct.data) return direct.data;
|
|
15803
16145
|
}
|
|
15804
16146
|
}
|
|
15805
16147
|
if ("default" in root) {
|
|
15806
|
-
const fallback =
|
|
16148
|
+
const fallback = z30.string().safeParse(root.default);
|
|
15807
16149
|
if (fallback.success && fallback.data) return fallback.data;
|
|
15808
16150
|
}
|
|
15809
16151
|
}
|
|
@@ -15864,7 +16206,7 @@ async function runPrediction(ctx, input, deps) {
|
|
|
15864
16206
|
}
|
|
15865
16207
|
return void 0;
|
|
15866
16208
|
}, pollOpts);
|
|
15867
|
-
const predictTime =
|
|
16209
|
+
const predictTime = z30.number().safeParse(done.metrics?.predict_time);
|
|
15868
16210
|
if (done.output === void 0) throw noOutput();
|
|
15869
16211
|
return {
|
|
15870
16212
|
url: extractOutputUrl(done.output),
|
|
@@ -16110,9 +16452,9 @@ async function generateReplicateImage(req, ctx, deps) {
|
|
|
16110
16452
|
}
|
|
16111
16453
|
const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
|
|
16112
16454
|
const file = await download(ctx, url);
|
|
16113
|
-
const
|
|
16114
|
-
|
|
16115
|
-
return { images: [{ bytes: file.bytes, mime: file.mime }], usage:
|
|
16455
|
+
const usage5 = imageUsage3(ctx, req);
|
|
16456
|
+
usage5.quantity = predictTime;
|
|
16457
|
+
return { images: [{ bytes: file.bytes, mime: file.mime }], usage: usage5, raw, outputUrl: url };
|
|
16116
16458
|
}
|
|
16117
16459
|
function klingInput(req) {
|
|
16118
16460
|
const images = (req.firstFrame ? [req.firstFrame] : []).map(refToUrl);
|
|
@@ -16217,7 +16559,7 @@ async function generateReplicateVideo(req, ctx, deps) {
|
|
|
16217
16559
|
throw replicateError(cause, ctx);
|
|
16218
16560
|
}
|
|
16219
16561
|
if (current.status === "succeeded") {
|
|
16220
|
-
const predictTime =
|
|
16562
|
+
const predictTime = z30.number().safeParse(current.metrics?.predict_time);
|
|
16221
16563
|
if (current.output === void 0) throw noOutput();
|
|
16222
16564
|
return {
|
|
16223
16565
|
url: extractOutputUrl(current.output),
|
|
@@ -16236,9 +16578,9 @@ async function generateReplicateVideo(req, ctx, deps) {
|
|
|
16236
16578
|
return void 0;
|
|
16237
16579
|
};
|
|
16238
16580
|
const toResult = (done) => {
|
|
16239
|
-
const
|
|
16240
|
-
|
|
16241
|
-
return { video: { url: done.url }, usage:
|
|
16581
|
+
const usage5 = videoUsage5(ctx, req);
|
|
16582
|
+
usage5.quantity = done.predictTime;
|
|
16583
|
+
return { video: { url: done.url }, usage: usage5, raw: done.raw };
|
|
16242
16584
|
};
|
|
16243
16585
|
return {
|
|
16244
16586
|
jobId,
|
|
@@ -16345,21 +16687,21 @@ async function generateReplicateAudio(req, ctx, deps) {
|
|
|
16345
16687
|
input = specResult.input;
|
|
16346
16688
|
}
|
|
16347
16689
|
const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
|
|
16348
|
-
const
|
|
16690
|
+
const usage5 = audioUsage(ctx, req);
|
|
16349
16691
|
if (ctx.model.usage.unit === "seconds") {
|
|
16350
16692
|
const seconds3 = elevenLabsMusicDuration(req.durationSeconds);
|
|
16351
|
-
|
|
16352
|
-
|
|
16693
|
+
usage5.quantity = seconds3;
|
|
16694
|
+
usage5.durationSeconds = seconds3;
|
|
16353
16695
|
} else {
|
|
16354
|
-
|
|
16696
|
+
usage5.quantity = predictTime;
|
|
16355
16697
|
}
|
|
16356
|
-
return { audio: { url }, usage:
|
|
16698
|
+
return { audio: { url }, usage: usage5, raw: predictionRaw(raw) };
|
|
16357
16699
|
}
|
|
16358
16700
|
|
|
16359
16701
|
// src/adapters/xai-video.ts
|
|
16360
16702
|
import { experimental_generateVideo } from "ai";
|
|
16361
16703
|
import { createXai as createXai2 } from "@ai-sdk/xai";
|
|
16362
|
-
import { z as
|
|
16704
|
+
import { z as z31 } from "zod";
|
|
16363
16705
|
var POLL_INTERVAL_MS2 = 1e4;
|
|
16364
16706
|
var POLL_TIMEOUT_MS2 = 15 * 6e4;
|
|
16365
16707
|
var defaultXaiDeps = {
|
|
@@ -16372,8 +16714,8 @@ function createXaiVideoAdapter(deps = defaultXaiDeps) {
|
|
|
16372
16714
|
};
|
|
16373
16715
|
}
|
|
16374
16716
|
var xaiVideoAdapter = createXaiVideoAdapter();
|
|
16375
|
-
var xaiResponseStatusSchema =
|
|
16376
|
-
response:
|
|
16717
|
+
var xaiResponseStatusSchema = z31.object({
|
|
16718
|
+
response: z31.object({ status: z31.number() }).partial()
|
|
16377
16719
|
});
|
|
16378
16720
|
function xaiError(cause, ctx) {
|
|
16379
16721
|
const info = describeThrown(cause);
|
|
@@ -16381,12 +16723,12 @@ function xaiError(cause, ctx) {
|
|
|
16381
16723
|
const status = info.status ?? (nested.success ? nested.data.response?.status : void 0);
|
|
16382
16724
|
return classifyThrown("xai-video", cause, ctx.model.id, { status, body: info.body });
|
|
16383
16725
|
}
|
|
16384
|
-
var xaiMetaSchema =
|
|
16726
|
+
var xaiMetaSchema = z31.object({
|
|
16385
16727
|
videoUrl: JsonValueSchema.optional(),
|
|
16386
16728
|
costInUsdTicks: JsonValueSchema.optional(),
|
|
16387
16729
|
duration: JsonValueSchema.optional()
|
|
16388
16730
|
});
|
|
16389
|
-
var xaiProviderMetadataSchema =
|
|
16731
|
+
var xaiProviderMetadataSchema = z31.object({ xai: xaiMetaSchema });
|
|
16390
16732
|
function metaOf(result) {
|
|
16391
16733
|
const parsed = xaiProviderMetadataSchema.partial().safeParse(result.providerMetadata);
|
|
16392
16734
|
if (!parsed.success) return {};
|
|
@@ -16498,12 +16840,12 @@ async function mapResult(ctx, req, result) {
|
|
|
16498
16840
|
if (first) {
|
|
16499
16841
|
return {
|
|
16500
16842
|
video: { bytes: Uint8Array.from(first.uint8Array), mime: first.mediaType },
|
|
16501
|
-
usage:
|
|
16843
|
+
usage: usage4(ctx, req, metaOf(result)),
|
|
16502
16844
|
raw: result.providerMetadata
|
|
16503
16845
|
};
|
|
16504
16846
|
}
|
|
16505
16847
|
const meta = metaOf(result);
|
|
16506
|
-
const videoUrl =
|
|
16848
|
+
const videoUrl = z31.string().safeParse(meta.videoUrl);
|
|
16507
16849
|
if (videoUrl.success && videoUrl.data) {
|
|
16508
16850
|
const res = await ctx.fetch(videoUrl.data);
|
|
16509
16851
|
if (!res.ok) {
|
|
@@ -16513,7 +16855,7 @@ async function mapResult(ctx, req, result) {
|
|
|
16513
16855
|
const mime = res.headers.get("content-type") ?? "video/mp4";
|
|
16514
16856
|
return {
|
|
16515
16857
|
video: { bytes: new Uint8Array(await res.arrayBuffer()), mime },
|
|
16516
|
-
usage:
|
|
16858
|
+
usage: usage4(ctx, req, meta),
|
|
16517
16859
|
raw: result.providerMetadata
|
|
16518
16860
|
};
|
|
16519
16861
|
}
|
|
@@ -16525,8 +16867,8 @@ async function mapResult(ctx, req, result) {
|
|
|
16525
16867
|
retryable: false
|
|
16526
16868
|
});
|
|
16527
16869
|
}
|
|
16528
|
-
function
|
|
16529
|
-
const costTicks =
|
|
16870
|
+
function usage4(ctx, req, meta) {
|
|
16871
|
+
const costTicks = z31.number().safeParse(meta.costInUsdTicks);
|
|
16530
16872
|
const cost = costTicks.success ? costTicks.data / 1e10 : void 0;
|
|
16531
16873
|
const event = {
|
|
16532
16874
|
model: ctx.model.id,
|
|
@@ -16566,7 +16908,8 @@ var DEFAULT_ADAPTERS = {
|
|
|
16566
16908
|
higgsfield: higgsfieldAdapter,
|
|
16567
16909
|
"xai-video": xaiVideoAdapter,
|
|
16568
16910
|
luma: lumaAdapter,
|
|
16569
|
-
fish: fishAdapter
|
|
16911
|
+
fish: fishAdapter,
|
|
16912
|
+
elevenlabs: elevenLabsAdapter
|
|
16570
16913
|
};
|
|
16571
16914
|
|
|
16572
16915
|
// src/catalog/data-only.ts
|
|
@@ -16605,15 +16948,15 @@ var FAL_NODE_TYPES = /* @__PURE__ */ new Set([
|
|
|
16605
16948
|
"transcription",
|
|
16606
16949
|
"mask"
|
|
16607
16950
|
]);
|
|
16608
|
-
function
|
|
16609
|
-
return row2.adapter === "fish" && row2.type === "speech";
|
|
16951
|
+
function directSpeech(row2) {
|
|
16952
|
+
return (row2.adapter === "fish" || row2.adapter === "elevenlabs") && row2.type === "speech";
|
|
16610
16953
|
}
|
|
16611
16954
|
function dataOnlyCapable(row2) {
|
|
16612
16955
|
const adapter = DEFAULT_ADAPTERS[row2.adapter];
|
|
16613
16956
|
if (!adapterServesType(adapter, row2.type)) {
|
|
16614
16957
|
return { ok: false, reason: `${row2.adapter} cannot serve ${row2.type} rows` };
|
|
16615
16958
|
}
|
|
16616
|
-
if (FAL_NODE_TYPES.has(row2.type) && row2.adapter !== "fal" && !
|
|
16959
|
+
if (FAL_NODE_TYPES.has(row2.type) && row2.adapter !== "fal" && !directSpeech(row2)) {
|
|
16617
16960
|
return { ok: false, reason: `only fal serves ${row2.type} rows` };
|
|
16618
16961
|
}
|
|
16619
16962
|
switch (row2.adapter) {
|
|
@@ -16695,6 +17038,10 @@ function dataOnlyCapable(row2) {
|
|
|
16695
17038
|
const reason = fishRowRefusal(row2);
|
|
16696
17039
|
return reason === void 0 ? { ok: true } : { ok: false, reason };
|
|
16697
17040
|
}
|
|
17041
|
+
case "elevenlabs": {
|
|
17042
|
+
const reason = elevenLabsRowRefusal(row2);
|
|
17043
|
+
return reason === void 0 ? { ok: true } : { ok: false, reason };
|
|
17044
|
+
}
|
|
16698
17045
|
default: {
|
|
16699
17046
|
return assertNever(row2.adapter);
|
|
16700
17047
|
}
|
|
@@ -16714,22 +17061,22 @@ var liveState = store[KEY] ??= {
|
|
|
16714
17061
|
var liveCatalog = liveState.catalog;
|
|
16715
17062
|
|
|
16716
17063
|
// src/catalog/load.ts
|
|
16717
|
-
import { z as
|
|
17064
|
+
import { z as z32 } from "zod";
|
|
16718
17065
|
function rowCount() {
|
|
16719
17066
|
return liveCatalog.list({ lifecycle: ["active", "deprecated", "retired"] }).length;
|
|
16720
17067
|
}
|
|
16721
17068
|
function authHeaders(auth) {
|
|
16722
17069
|
return "bearer" in auth ? { Authorization: `Bearer ${auth.bearer}` } : { "x-api-key": auth.apiKey };
|
|
16723
17070
|
}
|
|
16724
|
-
var EnvelopeSchema =
|
|
16725
|
-
rows:
|
|
16726
|
-
revision:
|
|
17071
|
+
var EnvelopeSchema = z32.object({
|
|
17072
|
+
rows: z32.array(JsonValueSchema),
|
|
17073
|
+
revision: z32.string().optional()
|
|
16727
17074
|
});
|
|
16728
17075
|
function dropReason(path, message) {
|
|
16729
17076
|
return path.length === 0 ? message : `${path.map((part) => String(part)).join(".")} ${message}`;
|
|
16730
17077
|
}
|
|
16731
17078
|
function rowId(raw) {
|
|
16732
|
-
const parsed =
|
|
17079
|
+
const parsed = z32.object({ id: z32.string().min(1) }).loose().safeParse(raw);
|
|
16733
17080
|
if (!parsed.success) return "?";
|
|
16734
17081
|
return parsed.data.id;
|
|
16735
17082
|
}
|
|
@@ -17890,7 +18237,8 @@ var ADAPTER_KEYS = {
|
|
|
17890
18237
|
higgsfield: ["higgsfield"],
|
|
17891
18238
|
"xai-video": ["xai"],
|
|
17892
18239
|
luma: ["luma"],
|
|
17893
|
-
fish: ["fish"]
|
|
18240
|
+
fish: ["fish"],
|
|
18241
|
+
elevenlabs: ["elevenlabs"]
|
|
17894
18242
|
};
|
|
17895
18243
|
function hasAll(keys, names) {
|
|
17896
18244
|
if (!keys) return false;
|
|
@@ -17950,6 +18298,7 @@ function keysFromEnv(env, prefix = "") {
|
|
|
17950
18298
|
set("higgsfieldSecret", pick2("HIGGSFIELD_API_SECRET"));
|
|
17951
18299
|
set("luma", pick2("LUMA_API_KEY", "LUMA_AGENTS_API_KEY"));
|
|
17952
18300
|
set("fish", pick2("FISH_AUDIO_API_KEY"));
|
|
18301
|
+
set("elevenlabs", pick2("ELEVENLABS_API_KEY"));
|
|
17953
18302
|
set("cloudflare", pick2("CLOUDFLARE_AI_GATEWAY_TOKEN", "CF_AIG_TOKEN"));
|
|
17954
18303
|
const bearer = pick2("AWS_BEARER_TOKEN_BEDROCK");
|
|
17955
18304
|
const accessKeyId = pick2("AWS_ACCESS_KEY_ID");
|
|
@@ -17972,7 +18321,7 @@ function keysFromEnv(env, prefix = "") {
|
|
|
17972
18321
|
|
|
17973
18322
|
// src/text.ts
|
|
17974
18323
|
import "ai";
|
|
17975
|
-
import { z as
|
|
18324
|
+
import { z as z33 } from "zod";
|
|
17976
18325
|
function mergeTextProviderOptions(catalog, caller) {
|
|
17977
18326
|
const merged = {};
|
|
17978
18327
|
const catalogOptions = catalog.providerOptions ?? {};
|
|
@@ -18011,17 +18360,17 @@ function passthroughTextModel(model) {
|
|
|
18011
18360
|
pricingKind: "token"
|
|
18012
18361
|
};
|
|
18013
18362
|
}
|
|
18014
|
-
var perplexityCostSchema =
|
|
18015
|
-
perplexity:
|
|
18363
|
+
var perplexityCostSchema = z33.object({
|
|
18364
|
+
perplexity: z33.object({ cost: z33.object({ totalCost: z33.number().finite().nonnegative() }) })
|
|
18016
18365
|
});
|
|
18017
18366
|
function reportedCostUsd(metadata) {
|
|
18018
18367
|
const parsed = perplexityCostSchema.safeParse(metadata);
|
|
18019
18368
|
return parsed.success ? parsed.data.perplexity.cost.totalCost : void 0;
|
|
18020
18369
|
}
|
|
18021
|
-
function textUsageEvent(model, provider,
|
|
18022
|
-
const inputTokens =
|
|
18023
|
-
const outputTokens =
|
|
18024
|
-
const total =
|
|
18370
|
+
function textUsageEvent(model, provider, usage5, providerMetadata) {
|
|
18371
|
+
const inputTokens = usage5.inputTokens ?? 0;
|
|
18372
|
+
const outputTokens = usage5.outputTokens ?? 0;
|
|
18373
|
+
const total = usage5.totalTokens ?? inputTokens + outputTokens;
|
|
18025
18374
|
const event = {
|
|
18026
18375
|
model: model.id,
|
|
18027
18376
|
provider,
|
|
@@ -18056,7 +18405,7 @@ function createTextSteps(initial, resolve, callerProviderOptions) {
|
|
|
18056
18405
|
return { ...prepared, providerOptions };
|
|
18057
18406
|
};
|
|
18058
18407
|
}
|
|
18059
|
-
function
|
|
18408
|
+
function usage5(results) {
|
|
18060
18409
|
const grouped = /* @__PURE__ */ new Map();
|
|
18061
18410
|
for (const [index, step] of results.entries()) {
|
|
18062
18411
|
const target = steps.get(index) ?? initial;
|
|
@@ -18080,7 +18429,7 @@ function createTextSteps(initial, resolve, callerProviderOptions) {
|
|
|
18080
18429
|
}
|
|
18081
18430
|
return [...grouped.values()];
|
|
18082
18431
|
}
|
|
18083
|
-
return { wrap, usage:
|
|
18432
|
+
return { wrap, usage: usage5 };
|
|
18084
18433
|
}
|
|
18085
18434
|
|
|
18086
18435
|
// src/client.ts
|
|
@@ -18092,7 +18441,7 @@ import {
|
|
|
18092
18441
|
streamObject as aiStreamObject2,
|
|
18093
18442
|
streamText as aiStreamText2
|
|
18094
18443
|
} from "ai";
|
|
18095
|
-
import { z as
|
|
18444
|
+
import { z as z34 } from "zod";
|
|
18096
18445
|
|
|
18097
18446
|
// src/generated-image.ts
|
|
18098
18447
|
function toGeneratedImage(image) {
|
|
@@ -18214,9 +18563,9 @@ function providerJobMethods(kind, deps) {
|
|
|
18214
18563
|
if (!methods.result) throw missing3(adapter, ctx.model);
|
|
18215
18564
|
const result = await methods.result(sub, ctx, webhook);
|
|
18216
18565
|
const base = { ...result.usage, model: ctx.model.id, unit: ctx.model.usage.unit };
|
|
18217
|
-
const
|
|
18218
|
-
await deps.emit(
|
|
18219
|
-
return { ...result, usage:
|
|
18566
|
+
const usage5 = sub.submittedAt === void 0 ? base : deps.timed(base, sub.submittedAt);
|
|
18567
|
+
await deps.emit(usage5);
|
|
18568
|
+
return { ...result, usage: usage5 };
|
|
18220
18569
|
},
|
|
18221
18570
|
async cancel(sub, call = {}) {
|
|
18222
18571
|
const { methods, adapter, ctx } = target(sub.model, call);
|
|
@@ -18456,10 +18805,10 @@ function audioNodeMethods(deps) {
|
|
|
18456
18805
|
const startedAt = Date.now();
|
|
18457
18806
|
const outcome = await adapter.dub(resolved, ctx);
|
|
18458
18807
|
if (outcome.kind === "audio") {
|
|
18459
|
-
const { audio, usage:
|
|
18808
|
+
const { audio, usage: usage5, raw } = outcome.result;
|
|
18460
18809
|
return {
|
|
18461
18810
|
audio,
|
|
18462
|
-
usage: await deps.settle(model,
|
|
18811
|
+
usage: await deps.settle(model, usage5, startedAt),
|
|
18463
18812
|
...raw !== void 0 && { raw }
|
|
18464
18813
|
};
|
|
18465
18814
|
}
|
|
@@ -18497,10 +18846,10 @@ function textAbortOptions(sdk, context) {
|
|
|
18497
18846
|
if (abortSignal) return { abortSignal };
|
|
18498
18847
|
return {};
|
|
18499
18848
|
}
|
|
18500
|
-
var catalogId =
|
|
18501
|
-
var exactSize =
|
|
18502
|
-
var sdkRatio =
|
|
18503
|
-
var sizeTier =
|
|
18849
|
+
var catalogId = z34.string();
|
|
18850
|
+
var exactSize = z34.templateLiteral([z34.number(), "x", z34.number()]);
|
|
18851
|
+
var sdkRatio = z34.templateLiteral([z34.number(), ":", z34.number()]);
|
|
18852
|
+
var sizeTier = z34.enum(["512", "1K", "2K", "4K"]);
|
|
18504
18853
|
function isCatalogId(model) {
|
|
18505
18854
|
return catalogId.safeParse(model).success;
|
|
18506
18855
|
}
|
|
@@ -18713,7 +19062,7 @@ function createModelKit(config, adapters) {
|
|
|
18713
19062
|
const images = result.images.map(
|
|
18714
19063
|
(file) => toGeneratedImage({ bytes: file.uint8Array, mime: file.mediaType })
|
|
18715
19064
|
);
|
|
18716
|
-
const
|
|
19065
|
+
const usage5 = timed(
|
|
18717
19066
|
{
|
|
18718
19067
|
model: model.modelId,
|
|
18719
19068
|
provider: model.provider,
|
|
@@ -18723,8 +19072,8 @@ function createModelKit(config, adapters) {
|
|
|
18723
19072
|
},
|
|
18724
19073
|
startedAt
|
|
18725
19074
|
);
|
|
18726
|
-
await emit(
|
|
18727
|
-
return { image: images[0], images, usage:
|
|
19075
|
+
await emit(usage5);
|
|
19076
|
+
return { image: images[0], images, usage: usage5, raw: result, warnings };
|
|
18728
19077
|
}
|
|
18729
19078
|
function passthroughVideo(req, call) {
|
|
18730
19079
|
const {
|
|
@@ -18800,7 +19149,7 @@ function createModelKit(config, adapters) {
|
|
|
18800
19149
|
let settled;
|
|
18801
19150
|
let failed = false;
|
|
18802
19151
|
const done = pending.then(async (result) => {
|
|
18803
|
-
const
|
|
19152
|
+
const usage5 = timed(
|
|
18804
19153
|
{
|
|
18805
19154
|
model: model.modelId,
|
|
18806
19155
|
provider: model.provider,
|
|
@@ -18813,10 +19162,10 @@ function createModelKit(config, adapters) {
|
|
|
18813
19162
|
);
|
|
18814
19163
|
settled = {
|
|
18815
19164
|
video: { bytes: result.video.uint8Array, mime: result.video.mediaType },
|
|
18816
|
-
usage:
|
|
19165
|
+
usage: usage5,
|
|
18817
19166
|
raw: result
|
|
18818
19167
|
};
|
|
18819
|
-
await emit(
|
|
19168
|
+
await emit(usage5);
|
|
18820
19169
|
return settled;
|
|
18821
19170
|
});
|
|
18822
19171
|
done.catch(() => {
|
|
@@ -18843,12 +19192,12 @@ function createModelKit(config, adapters) {
|
|
|
18843
19192
|
if (settled) return settled;
|
|
18844
19193
|
const pending = result(opts).then(
|
|
18845
19194
|
async (out) => {
|
|
18846
|
-
const
|
|
19195
|
+
const usage5 = timed(
|
|
18847
19196
|
{ ...out.usage, model: model.id, unit: model.usage.unit },
|
|
18848
19197
|
startedAt
|
|
18849
19198
|
);
|
|
18850
|
-
await emit(
|
|
18851
|
-
return { ...out, usage:
|
|
19199
|
+
await emit(usage5);
|
|
19200
|
+
return { ...out, usage: usage5 };
|
|
18852
19201
|
},
|
|
18853
19202
|
(cause) => {
|
|
18854
19203
|
settled = void 0;
|
|
@@ -18868,9 +19217,9 @@ function createModelKit(config, adapters) {
|
|
|
18868
19217
|
return context(model, signal ? { ...call, signal } : call, warnings);
|
|
18869
19218
|
},
|
|
18870
19219
|
async settle(model, event, startedAt) {
|
|
18871
|
-
const
|
|
18872
|
-
await emit(
|
|
18873
|
-
return
|
|
19220
|
+
const usage5 = timed({ ...event, model: model.id, unit: model.usage.unit }, startedAt);
|
|
19221
|
+
await emit(usage5);
|
|
19222
|
+
return usage5;
|
|
18874
19223
|
},
|
|
18875
19224
|
wrapVideoJob
|
|
18876
19225
|
});
|
|
@@ -18906,11 +19255,11 @@ function createModelKit(config, adapters) {
|
|
|
18906
19255
|
});
|
|
18907
19256
|
const startedAt = Date.now();
|
|
18908
19257
|
const result = await adapter.generateImage(request, ctx);
|
|
18909
|
-
const
|
|
19258
|
+
const usage5 = timed(
|
|
18910
19259
|
{ ...result.usage, model: model.id, unit: model.usage.unit },
|
|
18911
19260
|
startedAt
|
|
18912
19261
|
);
|
|
18913
|
-
await emit(
|
|
19262
|
+
await emit(usage5);
|
|
18914
19263
|
const images = result.images.map(toGeneratedImage);
|
|
18915
19264
|
const first = images[0];
|
|
18916
19265
|
if (!first)
|
|
@@ -18919,7 +19268,7 @@ function createModelKit(config, adapters) {
|
|
|
18919
19268
|
message: `${model.id} returned no image`,
|
|
18920
19269
|
model: model.id
|
|
18921
19270
|
});
|
|
18922
|
-
return { ...result, usage:
|
|
19271
|
+
return { ...result, usage: usage5, image: first, images, warnings };
|
|
18923
19272
|
},
|
|
18924
19273
|
async generateVideo(req, call = {}) {
|
|
18925
19274
|
mediaRetryOptions(call);
|
|
@@ -19018,12 +19367,12 @@ function createModelKit(config, adapters) {
|
|
|
19018
19367
|
}
|
|
19019
19368
|
const startedAt = Date.now();
|
|
19020
19369
|
const result = await adapter.generateAudio(resolved, ctx);
|
|
19021
|
-
const
|
|
19370
|
+
const usage5 = timed(
|
|
19022
19371
|
{ ...result.usage, model: model.id, unit: model.usage.unit },
|
|
19023
19372
|
startedAt
|
|
19024
19373
|
);
|
|
19025
|
-
await emit(
|
|
19026
|
-
return { ...result, usage:
|
|
19374
|
+
await emit(usage5);
|
|
19375
|
+
return { ...result, usage: usage5 };
|
|
19027
19376
|
},
|
|
19028
19377
|
async prepareMediaPart(modelId, ref, mediaType, call = {}) {
|
|
19029
19378
|
mediaRetryOptions(call);
|
|
@@ -19103,8 +19452,8 @@ function createModelKit(config, adapters) {
|
|
|
19103
19452
|
options.prepareStep ?? options.experimental_prepareStep
|
|
19104
19453
|
),
|
|
19105
19454
|
onFinish: async (event) => {
|
|
19106
|
-
for (const
|
|
19107
|
-
await emit(textTimed(withRowUnit(
|
|
19455
|
+
for (const usage5 of steps.usage(event.steps))
|
|
19456
|
+
await emit(textTimed(withRowUnit(usage5), event.steps.length, startedAt));
|
|
19108
19457
|
await callerOnFinish?.(event);
|
|
19109
19458
|
}
|
|
19110
19459
|
});
|
|
@@ -19222,6 +19571,7 @@ export {
|
|
|
19222
19571
|
dataOnlyCapable,
|
|
19223
19572
|
describe,
|
|
19224
19573
|
describeThrown,
|
|
19574
|
+
elevenLabsAdapter,
|
|
19225
19575
|
generateImage as experimental_generateImage,
|
|
19226
19576
|
falAdapter,
|
|
19227
19577
|
falWebhookBodySchema,
|