@shop-os/modelkit 0.9.0 → 0.10.0
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 +15 -0
- package/README.md +2 -1
- package/dist/catalog.cjs +454 -386
- 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 +454 -386
- package/dist/catalog.js.map +1 -1
- package/dist/index.cjs +967 -617
- 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 +966 -617
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -66,6 +66,7 @@ __export(index_exports, {
|
|
|
66
66
|
dataOnlyCapable: () => dataOnlyCapable,
|
|
67
67
|
describe: () => describe,
|
|
68
68
|
describeThrown: () => describeThrown,
|
|
69
|
+
elevenLabsAdapter: () => elevenLabsAdapter,
|
|
69
70
|
experimental_generateImage: () => generateImage,
|
|
70
71
|
falAdapter: () => falAdapter,
|
|
71
72
|
falWebhookBodySchema: () => falWebhookBodySchema,
|
|
@@ -1371,303 +1372,6 @@ var VEED_SUBTITLES = {
|
|
|
1371
1372
|
}
|
|
1372
1373
|
};
|
|
1373
1374
|
|
|
1374
|
-
// src/catalog/voices-fish.ts
|
|
1375
|
-
var FISH_VOICES = [
|
|
1376
|
-
{
|
|
1377
|
-
id: "933563129e564b19a115bedd57b7406a",
|
|
1378
|
-
name: "Sarah",
|
|
1379
|
-
gender: "female",
|
|
1380
|
-
languages: ["en"],
|
|
1381
|
-
description: "An engaged speaker.",
|
|
1382
|
-
previewUrl: "https://platform.r2.fish.audio/task/4e204945670c460c86fdab57512cb308.mp3"
|
|
1383
|
-
},
|
|
1384
|
-
{
|
|
1385
|
-
id: "bf322df2096a46f18c579d0baa36f41d",
|
|
1386
|
-
name: "Adrian",
|
|
1387
|
-
gender: "male",
|
|
1388
|
-
languages: ["en"],
|
|
1389
|
-
description: "A steady and reliable narrator.",
|
|
1390
|
-
previewUrl: "https://platform.r2.fish.audio/task/d730b09f4a484316a77ecc86137e85fb.mp3"
|
|
1391
|
-
},
|
|
1392
|
-
{
|
|
1393
|
-
id: "536d3a5e000945adb7038665781a4aca",
|
|
1394
|
-
name: "Ethan",
|
|
1395
|
-
gender: "male",
|
|
1396
|
-
languages: ["en"],
|
|
1397
|
-
description: "A curious explainer.",
|
|
1398
|
-
previewUrl: "https://platform.r2.fish.audio/task/bdd677ed767744fc91f166468786264b.mp3"
|
|
1399
|
-
},
|
|
1400
|
-
{
|
|
1401
|
-
id: "b347db033a6549378b48d00acb0d06cd",
|
|
1402
|
-
name: "Selene",
|
|
1403
|
-
gender: "female",
|
|
1404
|
-
languages: ["en"],
|
|
1405
|
-
description: "A meditative female voice.",
|
|
1406
|
-
previewUrl: "https://platform.r2.fish.audio/task/fcf629b4a0b343558f461338ba1b9da4.mp3"
|
|
1407
|
-
},
|
|
1408
|
-
{
|
|
1409
|
-
id: "9a9cf47702da476aa4629e2506d4a857",
|
|
1410
|
-
name: "Hannah",
|
|
1411
|
-
gender: "female",
|
|
1412
|
-
languages: ["en"],
|
|
1413
|
-
description: "A conversation specialist.",
|
|
1414
|
-
previewUrl: "https://platform.r2.fish.audio/task/08d658835feb427db808e37060b78eb0.mp3"
|
|
1415
|
-
},
|
|
1416
|
-
{
|
|
1417
|
-
id: "79d0bd3e4e5444b18f7b6d89b5927bf1",
|
|
1418
|
-
name: "Jordan",
|
|
1419
|
-
gender: "male",
|
|
1420
|
-
languages: ["en"],
|
|
1421
|
-
description: "A motivational speaker.",
|
|
1422
|
-
previewUrl: "https://platform.r2.fish.audio/task/edecbc0bdd4c46c39eda8520a0f729ef.mp3"
|
|
1423
|
-
},
|
|
1424
|
-
{
|
|
1425
|
-
id: "e3cd384158934cc9a01029cd7d278634",
|
|
1426
|
-
name: "Laura",
|
|
1427
|
-
gender: "female",
|
|
1428
|
-
languages: ["en"],
|
|
1429
|
-
description: "A confident female narrator.",
|
|
1430
|
-
previewUrl: "https://platform.r2.fish.audio/task/e821bef995344d519caa1c93d808db23.mp3"
|
|
1431
|
-
},
|
|
1432
|
-
{
|
|
1433
|
-
id: "f3a2b90078d54a65af4b95f63bc7798e",
|
|
1434
|
-
name: "Sheila",
|
|
1435
|
-
gender: "female",
|
|
1436
|
-
accent: "american",
|
|
1437
|
-
languages: ["en"],
|
|
1438
|
-
description: "A young American English woman's voice.",
|
|
1439
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/9bb9e1a1cf3f47f38700da1c5c0a678a.mp3"
|
|
1440
|
-
},
|
|
1441
|
-
{
|
|
1442
|
-
id: "0db6e93af420470b9d9b9a886dbaa954",
|
|
1443
|
-
name: "Kai",
|
|
1444
|
-
gender: "male",
|
|
1445
|
-
languages: ["en"],
|
|
1446
|
-
description: "A friendly English man's voice for companion apps and everyday conversation.",
|
|
1447
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/13306f1172544c3ba3106d1e363feaa6.mp3"
|
|
1448
|
-
},
|
|
1449
|
-
{
|
|
1450
|
-
id: "8abfa9ebd4c24a3399b68c3cdac8c7b5",
|
|
1451
|
-
name: "Freya",
|
|
1452
|
-
gender: "female",
|
|
1453
|
-
accent: "british",
|
|
1454
|
-
languages: ["en"],
|
|
1455
|
-
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.",
|
|
1456
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/07918705a56b42daaab149f65392cea7.mp3"
|
|
1457
|
-
},
|
|
1458
|
-
{
|
|
1459
|
-
id: "2f64e528a4f2406691925ab1e0ed5b7f",
|
|
1460
|
-
name: "Ananya",
|
|
1461
|
-
gender: "female",
|
|
1462
|
-
languages: ["hi"],
|
|
1463
|
-
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",
|
|
1464
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/a17a700668d8405f8316db120733145c.mp3"
|
|
1465
|
-
},
|
|
1466
|
-
{
|
|
1467
|
-
id: "cefd91a07b99468f9148e2580990082d",
|
|
1468
|
-
name: "Arjun",
|
|
1469
|
-
gender: "male",
|
|
1470
|
-
languages: ["hi"],
|
|
1471
|
-
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",
|
|
1472
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/a0c4a8eadb7841cdae8e5e68031a2dfb.mp3"
|
|
1473
|
-
},
|
|
1474
|
-
{
|
|
1475
|
-
id: "3f065d660212478a9c697fa965b4d098",
|
|
1476
|
-
name: "Carmen",
|
|
1477
|
-
gender: "female",
|
|
1478
|
-
languages: ["es"],
|
|
1479
|
-
description: "Una voz clara y segura para asistentes de voz, atenci\xF3n al cliente y presentaciones.",
|
|
1480
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/3421be48b6cb4c28bf829c25188e7e74.mp3"
|
|
1481
|
-
},
|
|
1482
|
-
{
|
|
1483
|
-
id: "ec0718028a2445fb9be8e8bfb56a0150",
|
|
1484
|
-
name: "Rodrigo",
|
|
1485
|
-
gender: "male",
|
|
1486
|
-
languages: ["es"],
|
|
1487
|
-
description: "Una voz clara y segura para asistentes de voz, atenci\xF3n al cliente y presentaciones.",
|
|
1488
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/5a77c32365604800ad5b4eb13c5585df.mp3"
|
|
1489
|
-
},
|
|
1490
|
-
{
|
|
1491
|
-
id: "10a3a20742114a4ea6dd441e7591850f",
|
|
1492
|
-
name: "Manon",
|
|
1493
|
-
gender: "female",
|
|
1494
|
-
languages: ["fr"],
|
|
1495
|
-
description: "Une voix claire et vive, adapt\xE9e aux assistants vocaux et au support client.",
|
|
1496
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/f7b75ee1fa524e48a8cefb003cf72952.mp3"
|
|
1497
|
-
},
|
|
1498
|
-
{
|
|
1499
|
-
id: "f69bca092b674168a8d02d61ca20943c",
|
|
1500
|
-
name: "Lucas",
|
|
1501
|
-
gender: "male",
|
|
1502
|
-
languages: ["fr"],
|
|
1503
|
-
description: "Une voix claire et assur\xE9e, adapt\xE9e aux assistants vocaux et au service client.",
|
|
1504
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/86fca3e56a014a3d8a11450854bb8311.mp3"
|
|
1505
|
-
},
|
|
1506
|
-
{
|
|
1507
|
-
id: "3937b44b604249f18b94913daef94043",
|
|
1508
|
-
name: "Lena",
|
|
1509
|
-
gender: "female",
|
|
1510
|
-
languages: ["de"],
|
|
1511
|
-
description: "Eine klare, souver\xE4ne Stimme f\xFCr Sprachassistenten, Kundenservice und Pr\xE4sentationen.",
|
|
1512
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/8659fec80b74442dab68a7755716a401.mp3"
|
|
1513
|
-
},
|
|
1514
|
-
{
|
|
1515
|
-
id: "c1e7cc926aa5469aa966c353094d4b0b",
|
|
1516
|
-
name: "Lukas",
|
|
1517
|
-
gender: "male",
|
|
1518
|
-
languages: ["de"],
|
|
1519
|
-
description: "Eine klare, souver\xE4ne Stimme f\xFCr Sprachassistenten, Kundenservice und Pr\xE4sentationen.",
|
|
1520
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/fb1d538126bb4fe38f8366250f6a2136.mp3"
|
|
1521
|
-
},
|
|
1522
|
-
{
|
|
1523
|
-
id: "b3c060cc41544a7da94a2c487647c902",
|
|
1524
|
-
name: "Let\xEDcia",
|
|
1525
|
-
gender: "female",
|
|
1526
|
-
accent: "brazilian",
|
|
1527
|
-
languages: ["pt"],
|
|
1528
|
-
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.",
|
|
1529
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-10-12/13c6c0d96b5c4069951f89868ee15360.mp3"
|
|
1530
|
-
},
|
|
1531
|
-
{
|
|
1532
|
-
id: "add7bcb8d3c8423bbfa152ca232aad6e",
|
|
1533
|
-
name: "Ricardo",
|
|
1534
|
-
gender: "male",
|
|
1535
|
-
accent: "brazilian",
|
|
1536
|
-
languages: ["pt"],
|
|
1537
|
-
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.",
|
|
1538
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-10-12/67475fc717ae45cbb38e647a2dd37fe1.mp3"
|
|
1539
|
-
},
|
|
1540
|
-
{
|
|
1541
|
-
id: "b2d9d8db057042688a5e318b8f405bc2",
|
|
1542
|
-
name: "Kyoko",
|
|
1543
|
-
gender: "female",
|
|
1544
|
-
languages: ["ja"],
|
|
1545
|
-
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",
|
|
1546
|
-
previewUrl: "https://platform.r2.fish.audio/task/993b3ccb52124341aff79580f1ce5a5a.mp3"
|
|
1547
|
-
},
|
|
1548
|
-
{
|
|
1549
|
-
id: "297a6fd278df47c3b9da9bfdf55ac89a",
|
|
1550
|
-
name: "Satoru",
|
|
1551
|
-
gender: "male",
|
|
1552
|
-
languages: ["ja"],
|
|
1553
|
-
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",
|
|
1554
|
-
previewUrl: "https://platform.r2.fish.audio/task/1b4712fb831f4c149eef6b0133157418.mp3"
|
|
1555
|
-
},
|
|
1556
|
-
{
|
|
1557
|
-
id: "0b14f34a13a94ed88fe6113193749bb0",
|
|
1558
|
-
name: "Fatima",
|
|
1559
|
-
gender: "female",
|
|
1560
|
-
languages: ["ar"],
|
|
1561
|
-
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.",
|
|
1562
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/93406e1b905a4c4994306e3421243390.mp3"
|
|
1563
|
-
},
|
|
1564
|
-
{
|
|
1565
|
-
id: "74c6aba5cbf94a15bbdc547ffce5cb38",
|
|
1566
|
-
name: "Yutong",
|
|
1567
|
-
gender: "female",
|
|
1568
|
-
languages: ["zh"],
|
|
1569
|
-
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",
|
|
1570
|
-
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/a48320f37fe44c4699549a1afc3778e8.mp3"
|
|
1571
|
-
}
|
|
1572
|
-
];
|
|
1573
|
-
|
|
1574
|
-
// src/catalog/speech-fish.ts
|
|
1575
|
-
var FISH_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/fishaudio.png";
|
|
1576
|
-
var PER_CALL = { unit: "images" };
|
|
1577
|
-
var PER_REQUEST = { unit: "requests" };
|
|
1578
|
-
var TTS_MAX_CHARS = 1e4;
|
|
1579
|
-
function fishTts(id, label, providerModelId, description) {
|
|
1580
|
-
return {
|
|
1581
|
-
id,
|
|
1582
|
-
aliases: [],
|
|
1583
|
-
label,
|
|
1584
|
-
type: "speech",
|
|
1585
|
-
adapter: "fish",
|
|
1586
|
-
providerModelId,
|
|
1587
|
-
lifecycle: "active",
|
|
1588
|
-
exposure: [],
|
|
1589
|
-
constraints: {
|
|
1590
|
-
voices: FISH_VOICES,
|
|
1591
|
-
outputFormats: ["mp3", "wav"],
|
|
1592
|
-
supports: [],
|
|
1593
|
-
prompt: { referenceSyntax: "numbered", maxChars: TTS_MAX_CHARS }
|
|
1594
|
-
},
|
|
1595
|
-
defaults: { voice: "9a9cf47702da476aa4629e2506d4a857", outputFormat: "mp3" },
|
|
1596
|
-
usage: PER_CALL,
|
|
1597
|
-
pricingKind: "flat",
|
|
1598
|
-
display: { provider: "fishaudio", logo: FISH_LOGO, description },
|
|
1599
|
-
capabilities: { customVoices: true }
|
|
1600
|
-
};
|
|
1601
|
-
}
|
|
1602
|
-
var FISH_MODELS = [
|
|
1603
|
-
fishTts(
|
|
1604
|
-
"fish-s2.1-pro",
|
|
1605
|
-
"Fish Audio S2.1 Pro",
|
|
1606
|
-
"s2.1-pro",
|
|
1607
|
-
"Fish Audio S2.1 Pro text to speech in 83 languages, with [bracket] directions and your own cloned voices."
|
|
1608
|
-
),
|
|
1609
|
-
fishTts(
|
|
1610
|
-
"fish-s2.1-pro-free",
|
|
1611
|
-
"Fish Audio S2.1 Pro Free",
|
|
1612
|
-
"s2.1-pro-free",
|
|
1613
|
-
"Fish Audio S2.1 Pro on the free developer tier: the same voices at no cost, without latency or data-processing guarantees."
|
|
1614
|
-
),
|
|
1615
|
-
fishTts(
|
|
1616
|
-
"fish-drama-3",
|
|
1617
|
-
"Fish Audio Drama 3",
|
|
1618
|
-
"drama-3",
|
|
1619
|
-
"Fish Audio Drama 3 text to speech you direct like an actor: [directions], sounds, pauses and per-word tags."
|
|
1620
|
-
),
|
|
1621
|
-
{
|
|
1622
|
-
id: "fish-voice-clone",
|
|
1623
|
-
aliases: [],
|
|
1624
|
-
label: "Fish Audio Voice Clone",
|
|
1625
|
-
type: "voice-clone",
|
|
1626
|
-
adapter: "fish",
|
|
1627
|
-
providerModelId: "voice-clone",
|
|
1628
|
-
lifecycle: "active",
|
|
1629
|
-
exposure: [],
|
|
1630
|
-
constraints: {
|
|
1631
|
-
// POST /model takes 1-20 voice files; Fish advises 10 s or more of clean speech each.
|
|
1632
|
-
references: { audios: 20, audioFormats: ["wav", "mp3", "m4a", "opus"] },
|
|
1633
|
-
supports: []
|
|
1634
|
-
},
|
|
1635
|
-
defaults: {},
|
|
1636
|
-
usage: PER_REQUEST,
|
|
1637
|
-
pricingKind: "flat",
|
|
1638
|
-
display: {
|
|
1639
|
-
provider: "fishaudio",
|
|
1640
|
-
logo: FISH_LOGO,
|
|
1641
|
-
description: "Clone a private, reusable voice from one or more clean recordings, then speak with it on the Fish Audio speech models."
|
|
1642
|
-
},
|
|
1643
|
-
capabilities: {}
|
|
1644
|
-
},
|
|
1645
|
-
{
|
|
1646
|
-
id: "fish-voice-design-1",
|
|
1647
|
-
aliases: [],
|
|
1648
|
-
label: "Fish Audio Voice Design",
|
|
1649
|
-
type: "voice-design",
|
|
1650
|
-
adapter: "fish",
|
|
1651
|
-
providerModelId: "voice-design-1",
|
|
1652
|
-
lifecycle: "active",
|
|
1653
|
-
exposure: [],
|
|
1654
|
-
constraints: {
|
|
1655
|
-
voiceDesign: { maxCandidates: 4, previewMaxChars: 150 },
|
|
1656
|
-
supports: [],
|
|
1657
|
-
prompt: { referenceSyntax: "numbered", maxChars: 2e3 }
|
|
1658
|
-
},
|
|
1659
|
-
defaults: {},
|
|
1660
|
-
usage: PER_REQUEST,
|
|
1661
|
-
pricingKind: "flat",
|
|
1662
|
-
display: {
|
|
1663
|
-
provider: "fishaudio",
|
|
1664
|
-
logo: FISH_LOGO,
|
|
1665
|
-
description: "Describe a voice and get up to four short candidates; keep one as a cloned voice."
|
|
1666
|
-
},
|
|
1667
|
-
capabilities: {}
|
|
1668
|
-
}
|
|
1669
|
-
];
|
|
1670
|
-
|
|
1671
1375
|
// src/catalog/languages-audio.ts
|
|
1672
1376
|
var ELEVENLABS_V4_LANGUAGES = [
|
|
1673
1377
|
{ code: "af", name: "Afrikaans" },
|
|
@@ -2042,131 +1746,494 @@ var ELEVENLABS_VOICES = [
|
|
|
2042
1746
|
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/IKne3meq5aSn9XLyUdCD/102de6f2-22ed-43e0-a1f1-111fa75c5481.mp3"
|
|
2043
1747
|
},
|
|
2044
1748
|
{
|
|
2045
|
-
id: "George",
|
|
2046
|
-
name: "George",
|
|
2047
|
-
gender: "male",
|
|
1749
|
+
id: "George",
|
|
1750
|
+
name: "George",
|
|
1751
|
+
gender: "male",
|
|
1752
|
+
accent: "british",
|
|
1753
|
+
languages: ["en", "fr", "ar", "ja", "cs", "fil", "es", "hi"],
|
|
1754
|
+
description: "Warm resonance that instantly captivates listeners.",
|
|
1755
|
+
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/JBFqnCBsd6RMkjVDRZzb/e6206d1a-0721-4787-aafb-06a6e705cac5.mp3"
|
|
1756
|
+
},
|
|
1757
|
+
{
|
|
1758
|
+
id: "Callum",
|
|
1759
|
+
name: "Callum",
|
|
1760
|
+
gender: "male",
|
|
1761
|
+
accent: "american",
|
|
1762
|
+
languages: ["en", "fr", "hi"],
|
|
1763
|
+
description: "Deceptively gravelly, yet unsettling edge.",
|
|
1764
|
+
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/N2lVS1w4EtoT3dr4eOWO/ac833bd8-ffda-4938-9ebc-b0f99ca25481.mp3"
|
|
1765
|
+
},
|
|
1766
|
+
{
|
|
1767
|
+
id: "River",
|
|
1768
|
+
name: "River",
|
|
1769
|
+
gender: "neutral",
|
|
1770
|
+
accent: "american",
|
|
1771
|
+
languages: ["en", "it", "fr", "pt", "zh"],
|
|
1772
|
+
description: "A relaxed, neutral voice ready for narrations or conversational projects.",
|
|
1773
|
+
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/SAz9YHcvj6GT2YYXdXww/e6c95f0b-2227-491a-b3d7-2249240decb7.mp3"
|
|
1774
|
+
},
|
|
1775
|
+
{
|
|
1776
|
+
id: "Liam",
|
|
1777
|
+
name: "Liam",
|
|
1778
|
+
gender: "male",
|
|
1779
|
+
accent: "american",
|
|
1780
|
+
languages: ["en", "de", "pt", "cs", "pl", "tr", "hi"],
|
|
1781
|
+
description: "A young adult with energy and warmth - suitable for reels and shorts.",
|
|
1782
|
+
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/TX3LPaxmHKxFdv7VOQHJ/63148076-6363-42db-aea8-31424308b92c.mp3"
|
|
1783
|
+
},
|
|
1784
|
+
{ id: "Charlotte", name: "Charlotte" },
|
|
1785
|
+
{
|
|
1786
|
+
id: "Alice",
|
|
1787
|
+
name: "Alice",
|
|
1788
|
+
gender: "female",
|
|
1789
|
+
accent: "british",
|
|
1790
|
+
languages: ["en", "it", "fr", "ar", "ja", "pl", "hi"],
|
|
1791
|
+
description: "Clear and engaging, friendly woman with a British accent suitable for e-learning.",
|
|
1792
|
+
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/Xb7hH8MSUJpSbSDYk0k2/d10f7534-11f6-41fe-a012-2de1e482d336.mp3"
|
|
1793
|
+
},
|
|
1794
|
+
{
|
|
1795
|
+
id: "Matilda",
|
|
1796
|
+
name: "Matilda",
|
|
1797
|
+
gender: "female",
|
|
1798
|
+
accent: "american",
|
|
1799
|
+
languages: ["en", "it", "fr", "de", "ar", "es"],
|
|
1800
|
+
description: "A professional woman with a pleasing alto pitch. Suitable for many use cases.",
|
|
1801
|
+
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/XrExE9yKIg1WjnnlVkGX/b930e18d-6b4d-466e-bab2-0ae97c6d8535.mp3"
|
|
1802
|
+
},
|
|
1803
|
+
{
|
|
1804
|
+
id: "Will",
|
|
1805
|
+
name: "Will",
|
|
1806
|
+
gender: "male",
|
|
1807
|
+
accent: "american",
|
|
1808
|
+
languages: ["en", "fr", "de", "pt", "zh", "cs", "fil", "sk", "es", "sv"],
|
|
1809
|
+
description: "Conversational and laid back.",
|
|
1810
|
+
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/bIHbv24MWmeRgasZH58o/8caf8f3d-ad29-4980-af41-53f20c72d7a4.mp3"
|
|
1811
|
+
},
|
|
1812
|
+
{
|
|
1813
|
+
id: "Jessica",
|
|
1814
|
+
name: "Jessica",
|
|
1815
|
+
gender: "female",
|
|
1816
|
+
accent: "american",
|
|
1817
|
+
languages: ["en", "fr", "ar", "ja", "zh", "de", "cs", "hi"],
|
|
1818
|
+
description: "Young and popular, this playful American female voice is perfect for trendy content.",
|
|
1819
|
+
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/cgSgspJ2msm6clMCkdW9/56a97bf8-b69b-448f-846c-c3a11683d45a.mp3"
|
|
1820
|
+
},
|
|
1821
|
+
{
|
|
1822
|
+
id: "Eric",
|
|
1823
|
+
name: "Eric",
|
|
1824
|
+
gender: "male",
|
|
1825
|
+
accent: "american",
|
|
1826
|
+
languages: ["en", "fr", "pt", "de", "sk", "es"],
|
|
1827
|
+
description: "A smooth tenor pitch from a man in his 40s - perfect for agentic use cases.",
|
|
1828
|
+
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/cjVigY5qzO86Huf0OWal/d098fda0-6456-4030-b3d8-63aa048c9070.mp3"
|
|
1829
|
+
},
|
|
1830
|
+
{
|
|
1831
|
+
id: "Chris",
|
|
1832
|
+
name: "Chris",
|
|
1833
|
+
gender: "male",
|
|
1834
|
+
accent: "american",
|
|
1835
|
+
languages: ["en", "fr", "ar", "pt", "sv", "hi"],
|
|
1836
|
+
description: "Natural and real, this down-to-earth voice is great across many use-cases.",
|
|
1837
|
+
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/iP95p4xoKVk53GoZ742B/3f4bde72-cc48-40dd-829f-57fbf906f4d7.mp3"
|
|
1838
|
+
},
|
|
1839
|
+
{
|
|
1840
|
+
id: "Brian",
|
|
1841
|
+
name: "Brian",
|
|
1842
|
+
gender: "male",
|
|
1843
|
+
accent: "american",
|
|
1844
|
+
languages: ["en", "ar", "zh", "pt", "de", "nl", "sk", "ro", "hi"],
|
|
1845
|
+
description: "Middle-aged man with a resonant and comforting tone. Great for narrations and advertisements.",
|
|
1846
|
+
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/nPczCjzI2devNBz1zQrb/2dd3e72c-4fd3-42f1-93ea-abc5d4e5aa1d.mp3"
|
|
1847
|
+
},
|
|
1848
|
+
{
|
|
1849
|
+
id: "Daniel",
|
|
1850
|
+
name: "Daniel",
|
|
1851
|
+
gender: "male",
|
|
1852
|
+
accent: "british",
|
|
1853
|
+
languages: ["en", "de", "tr"],
|
|
1854
|
+
description: "A strong voice perfect for delivering a professional broadcast or news story.",
|
|
1855
|
+
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/onwK4e9ZLuTAKqWW03F9/7eee0236-1a72-4b86-b303-5dcadc007ba9.mp3"
|
|
1856
|
+
},
|
|
1857
|
+
{
|
|
1858
|
+
id: "Lily",
|
|
1859
|
+
name: "Lily",
|
|
1860
|
+
gender: "female",
|
|
1861
|
+
accent: "british",
|
|
1862
|
+
languages: ["en", "it", "de", "zh", "cs", "nl", "pl"],
|
|
1863
|
+
description: "Velvety British female voice delivers news and narrations with warmth and clarity.",
|
|
1864
|
+
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/pFZP5JQG7iQjIQuC4Bku/89b68b35-b3dd-4348-a84a-a3c13a3c2b30.mp3"
|
|
1865
|
+
},
|
|
1866
|
+
{
|
|
1867
|
+
id: "Bill",
|
|
1868
|
+
name: "Bill",
|
|
1869
|
+
gender: "male",
|
|
1870
|
+
accent: "american",
|
|
1871
|
+
languages: ["en", "fr", "ar", "zh", "de", "cs"],
|
|
1872
|
+
description: "Friendly and comforting voice ready to narrate your stories.",
|
|
1873
|
+
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/pqHfZKP75CvOlQylNhV4/d782b3ff-84ba-4029-848c-acf01285524d.mp3"
|
|
1874
|
+
}
|
|
1875
|
+
];
|
|
1876
|
+
var PREMADE_ID = /\/premade\/voices\/([A-Za-z0-9]+)\//;
|
|
1877
|
+
var ELEVENLABS_DIRECT_VOICES = ELEVENLABS_VOICES.flatMap((v) => {
|
|
1878
|
+
const id = v.previewUrl ? PREMADE_ID.exec(v.previewUrl)?.[1] : void 0;
|
|
1879
|
+
return id ? [{ ...v, id }] : [];
|
|
1880
|
+
});
|
|
1881
|
+
var ELEVENLABS_DIRECT_DEFAULT_VOICE = "EXAVITQu4vr4xnSDxMaL";
|
|
1882
|
+
|
|
1883
|
+
// src/catalog/speech-elevenlabs-direct.ts
|
|
1884
|
+
var ELEVENLABS_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
|
|
1885
|
+
var PER_CALL = { unit: "images" };
|
|
1886
|
+
var PER_REQUEST = { unit: "requests" };
|
|
1887
|
+
var ELEVENLABS_DIRECT_MODELS = [
|
|
1888
|
+
{
|
|
1889
|
+
id: "elevenlabs-v4-direct",
|
|
1890
|
+
aliases: [],
|
|
1891
|
+
label: "ElevenLabs v4 (direct)",
|
|
1892
|
+
type: "speech",
|
|
1893
|
+
adapter: "elevenlabs",
|
|
1894
|
+
providerModelId: "eleven_v4",
|
|
1895
|
+
lifecycle: "active",
|
|
1896
|
+
exposure: [],
|
|
1897
|
+
constraints: {
|
|
1898
|
+
// Premade voices under their ElevenLabs ids (the direct API takes ids, not names).
|
|
1899
|
+
voices: ELEVENLABS_DIRECT_VOICES,
|
|
1900
|
+
languages: ELEVENLABS_V4_LANGUAGES,
|
|
1901
|
+
outputFormats: ELEVENLABS_MP3_FORMATS,
|
|
1902
|
+
supports: [],
|
|
1903
|
+
// ElevenLabs docs: 10,000 characters per request.
|
|
1904
|
+
prompt: { referenceSyntax: "numbered", maxChars: 1e4 }
|
|
1905
|
+
},
|
|
1906
|
+
defaults: { voice: ELEVENLABS_DIRECT_DEFAULT_VOICE, outputFormat: "mp3_44100_128" },
|
|
1907
|
+
usage: PER_CALL,
|
|
1908
|
+
pricingKind: "flat",
|
|
1909
|
+
display: {
|
|
1910
|
+
provider: "elevenlabs",
|
|
1911
|
+
logo: ELEVENLABS_LOGO,
|
|
1912
|
+
description: "ElevenLabs v4 text to speech with audio tags, in a premade voice or your own cloned voice; up to 10,000 characters."
|
|
1913
|
+
},
|
|
1914
|
+
capabilities: { customVoices: true }
|
|
1915
|
+
},
|
|
1916
|
+
{
|
|
1917
|
+
id: "elevenlabs-ivc",
|
|
1918
|
+
aliases: [],
|
|
1919
|
+
label: "ElevenLabs Instant Voice Clone",
|
|
1920
|
+
type: "voice-clone",
|
|
1921
|
+
adapter: "elevenlabs",
|
|
1922
|
+
providerModelId: "ivc",
|
|
1923
|
+
lifecycle: "active",
|
|
1924
|
+
exposure: [],
|
|
1925
|
+
constraints: {
|
|
1926
|
+
// POST /v1/voices/add; ElevenLabs takes up to 25 samples and advises 1-2 minutes of
|
|
1927
|
+
// clean speech in total. Each clone uses a voice slot on our plan until deleted.
|
|
1928
|
+
references: { audios: 25, audioFormats: ["mp3", "wav", "m4a", "webm", "ogg"] },
|
|
1929
|
+
supports: []
|
|
1930
|
+
},
|
|
1931
|
+
defaults: {},
|
|
1932
|
+
usage: PER_REQUEST,
|
|
1933
|
+
pricingKind: "flat",
|
|
1934
|
+
display: {
|
|
1935
|
+
provider: "elevenlabs",
|
|
1936
|
+
logo: ELEVENLABS_LOGO,
|
|
1937
|
+
description: "Clone a private, reusable voice from one or more clean recordings, then speak with it on ElevenLabs v4 (direct)."
|
|
1938
|
+
},
|
|
1939
|
+
capabilities: {}
|
|
1940
|
+
}
|
|
1941
|
+
];
|
|
1942
|
+
|
|
1943
|
+
// src/catalog/voices-fish.ts
|
|
1944
|
+
var FISH_VOICES = [
|
|
1945
|
+
{
|
|
1946
|
+
id: "933563129e564b19a115bedd57b7406a",
|
|
1947
|
+
name: "Sarah",
|
|
1948
|
+
gender: "female",
|
|
1949
|
+
languages: ["en"],
|
|
1950
|
+
description: "An engaged speaker.",
|
|
1951
|
+
previewUrl: "https://platform.r2.fish.audio/task/4e204945670c460c86fdab57512cb308.mp3"
|
|
1952
|
+
},
|
|
1953
|
+
{
|
|
1954
|
+
id: "bf322df2096a46f18c579d0baa36f41d",
|
|
1955
|
+
name: "Adrian",
|
|
1956
|
+
gender: "male",
|
|
1957
|
+
languages: ["en"],
|
|
1958
|
+
description: "A steady and reliable narrator.",
|
|
1959
|
+
previewUrl: "https://platform.r2.fish.audio/task/d730b09f4a484316a77ecc86137e85fb.mp3"
|
|
1960
|
+
},
|
|
1961
|
+
{
|
|
1962
|
+
id: "536d3a5e000945adb7038665781a4aca",
|
|
1963
|
+
name: "Ethan",
|
|
1964
|
+
gender: "male",
|
|
1965
|
+
languages: ["en"],
|
|
1966
|
+
description: "A curious explainer.",
|
|
1967
|
+
previewUrl: "https://platform.r2.fish.audio/task/bdd677ed767744fc91f166468786264b.mp3"
|
|
1968
|
+
},
|
|
1969
|
+
{
|
|
1970
|
+
id: "b347db033a6549378b48d00acb0d06cd",
|
|
1971
|
+
name: "Selene",
|
|
1972
|
+
gender: "female",
|
|
1973
|
+
languages: ["en"],
|
|
1974
|
+
description: "A meditative female voice.",
|
|
1975
|
+
previewUrl: "https://platform.r2.fish.audio/task/fcf629b4a0b343558f461338ba1b9da4.mp3"
|
|
1976
|
+
},
|
|
1977
|
+
{
|
|
1978
|
+
id: "9a9cf47702da476aa4629e2506d4a857",
|
|
1979
|
+
name: "Hannah",
|
|
1980
|
+
gender: "female",
|
|
1981
|
+
languages: ["en"],
|
|
1982
|
+
description: "A conversation specialist.",
|
|
1983
|
+
previewUrl: "https://platform.r2.fish.audio/task/08d658835feb427db808e37060b78eb0.mp3"
|
|
1984
|
+
},
|
|
1985
|
+
{
|
|
1986
|
+
id: "79d0bd3e4e5444b18f7b6d89b5927bf1",
|
|
1987
|
+
name: "Jordan",
|
|
1988
|
+
gender: "male",
|
|
1989
|
+
languages: ["en"],
|
|
1990
|
+
description: "A motivational speaker.",
|
|
1991
|
+
previewUrl: "https://platform.r2.fish.audio/task/edecbc0bdd4c46c39eda8520a0f729ef.mp3"
|
|
1992
|
+
},
|
|
1993
|
+
{
|
|
1994
|
+
id: "e3cd384158934cc9a01029cd7d278634",
|
|
1995
|
+
name: "Laura",
|
|
1996
|
+
gender: "female",
|
|
1997
|
+
languages: ["en"],
|
|
1998
|
+
description: "A confident female narrator.",
|
|
1999
|
+
previewUrl: "https://platform.r2.fish.audio/task/e821bef995344d519caa1c93d808db23.mp3"
|
|
2000
|
+
},
|
|
2001
|
+
{
|
|
2002
|
+
id: "f3a2b90078d54a65af4b95f63bc7798e",
|
|
2003
|
+
name: "Sheila",
|
|
2004
|
+
gender: "female",
|
|
2005
|
+
accent: "american",
|
|
2006
|
+
languages: ["en"],
|
|
2007
|
+
description: "A young American English woman's voice.",
|
|
2008
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/9bb9e1a1cf3f47f38700da1c5c0a678a.mp3"
|
|
2009
|
+
},
|
|
2010
|
+
{
|
|
2011
|
+
id: "0db6e93af420470b9d9b9a886dbaa954",
|
|
2012
|
+
name: "Kai",
|
|
2013
|
+
gender: "male",
|
|
2014
|
+
languages: ["en"],
|
|
2015
|
+
description: "A friendly English man's voice for companion apps and everyday conversation.",
|
|
2016
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/13306f1172544c3ba3106d1e363feaa6.mp3"
|
|
2017
|
+
},
|
|
2018
|
+
{
|
|
2019
|
+
id: "8abfa9ebd4c24a3399b68c3cdac8c7b5",
|
|
2020
|
+
name: "Freya",
|
|
2021
|
+
gender: "female",
|
|
2048
2022
|
accent: "british",
|
|
2049
|
-
languages: ["en"
|
|
2050
|
-
description: "
|
|
2051
|
-
previewUrl: "https://
|
|
2023
|
+
languages: ["en"],
|
|
2024
|
+
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.",
|
|
2025
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/07918705a56b42daaab149f65392cea7.mp3"
|
|
2052
2026
|
},
|
|
2053
2027
|
{
|
|
2054
|
-
id: "
|
|
2055
|
-
name: "
|
|
2028
|
+
id: "2f64e528a4f2406691925ab1e0ed5b7f",
|
|
2029
|
+
name: "Ananya",
|
|
2030
|
+
gender: "female",
|
|
2031
|
+
languages: ["hi"],
|
|
2032
|
+
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",
|
|
2033
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/a17a700668d8405f8316db120733145c.mp3"
|
|
2034
|
+
},
|
|
2035
|
+
{
|
|
2036
|
+
id: "cefd91a07b99468f9148e2580990082d",
|
|
2037
|
+
name: "Arjun",
|
|
2056
2038
|
gender: "male",
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/N2lVS1w4EtoT3dr4eOWO/ac833bd8-ffda-4938-9ebc-b0f99ca25481.mp3"
|
|
2039
|
+
languages: ["hi"],
|
|
2040
|
+
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",
|
|
2041
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/a0c4a8eadb7841cdae8e5e68031a2dfb.mp3"
|
|
2061
2042
|
},
|
|
2062
2043
|
{
|
|
2063
|
-
id: "
|
|
2064
|
-
name: "
|
|
2065
|
-
gender: "
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/SAz9YHcvj6GT2YYXdXww/e6c95f0b-2227-491a-b3d7-2249240decb7.mp3"
|
|
2044
|
+
id: "3f065d660212478a9c697fa965b4d098",
|
|
2045
|
+
name: "Carmen",
|
|
2046
|
+
gender: "female",
|
|
2047
|
+
languages: ["es"],
|
|
2048
|
+
description: "Una voz clara y segura para asistentes de voz, atenci\xF3n al cliente y presentaciones.",
|
|
2049
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/3421be48b6cb4c28bf829c25188e7e74.mp3"
|
|
2070
2050
|
},
|
|
2071
2051
|
{
|
|
2072
|
-
id: "
|
|
2073
|
-
name: "
|
|
2052
|
+
id: "ec0718028a2445fb9be8e8bfb56a0150",
|
|
2053
|
+
name: "Rodrigo",
|
|
2074
2054
|
gender: "male",
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/TX3LPaxmHKxFdv7VOQHJ/63148076-6363-42db-aea8-31424308b92c.mp3"
|
|
2055
|
+
languages: ["es"],
|
|
2056
|
+
description: "Una voz clara y segura para asistentes de voz, atenci\xF3n al cliente y presentaciones.",
|
|
2057
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/5a77c32365604800ad5b4eb13c5585df.mp3"
|
|
2079
2058
|
},
|
|
2080
|
-
{ id: "Charlotte", name: "Charlotte" },
|
|
2081
2059
|
{
|
|
2082
|
-
id: "
|
|
2083
|
-
name: "
|
|
2060
|
+
id: "10a3a20742114a4ea6dd441e7591850f",
|
|
2061
|
+
name: "Manon",
|
|
2084
2062
|
gender: "female",
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/Xb7hH8MSUJpSbSDYk0k2/d10f7534-11f6-41fe-a012-2de1e482d336.mp3"
|
|
2063
|
+
languages: ["fr"],
|
|
2064
|
+
description: "Une voix claire et vive, adapt\xE9e aux assistants vocaux et au support client.",
|
|
2065
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/f7b75ee1fa524e48a8cefb003cf72952.mp3"
|
|
2089
2066
|
},
|
|
2090
2067
|
{
|
|
2091
|
-
id: "
|
|
2092
|
-
name: "
|
|
2068
|
+
id: "f69bca092b674168a8d02d61ca20943c",
|
|
2069
|
+
name: "Lucas",
|
|
2070
|
+
gender: "male",
|
|
2071
|
+
languages: ["fr"],
|
|
2072
|
+
description: "Une voix claire et assur\xE9e, adapt\xE9e aux assistants vocaux et au service client.",
|
|
2073
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/86fca3e56a014a3d8a11450854bb8311.mp3"
|
|
2074
|
+
},
|
|
2075
|
+
{
|
|
2076
|
+
id: "3937b44b604249f18b94913daef94043",
|
|
2077
|
+
name: "Lena",
|
|
2093
2078
|
gender: "female",
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/XrExE9yKIg1WjnnlVkGX/b930e18d-6b4d-466e-bab2-0ae97c6d8535.mp3"
|
|
2079
|
+
languages: ["de"],
|
|
2080
|
+
description: "Eine klare, souver\xE4ne Stimme f\xFCr Sprachassistenten, Kundenservice und Pr\xE4sentationen.",
|
|
2081
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/8659fec80b74442dab68a7755716a401.mp3"
|
|
2098
2082
|
},
|
|
2099
2083
|
{
|
|
2100
|
-
id: "
|
|
2101
|
-
name: "
|
|
2084
|
+
id: "c1e7cc926aa5469aa966c353094d4b0b",
|
|
2085
|
+
name: "Lukas",
|
|
2102
2086
|
gender: "male",
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/bIHbv24MWmeRgasZH58o/8caf8f3d-ad29-4980-af41-53f20c72d7a4.mp3"
|
|
2087
|
+
languages: ["de"],
|
|
2088
|
+
description: "Eine klare, souver\xE4ne Stimme f\xFCr Sprachassistenten, Kundenservice und Pr\xE4sentationen.",
|
|
2089
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/fb1d538126bb4fe38f8366250f6a2136.mp3"
|
|
2107
2090
|
},
|
|
2108
2091
|
{
|
|
2109
|
-
id: "
|
|
2110
|
-
name: "
|
|
2092
|
+
id: "b3c060cc41544a7da94a2c487647c902",
|
|
2093
|
+
name: "Let\xEDcia",
|
|
2111
2094
|
gender: "female",
|
|
2112
|
-
accent: "
|
|
2113
|
-
languages: ["
|
|
2114
|
-
description: "
|
|
2115
|
-
previewUrl: "https://
|
|
2095
|
+
accent: "brazilian",
|
|
2096
|
+
languages: ["pt"],
|
|
2097
|
+
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.",
|
|
2098
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-10-12/13c6c0d96b5c4069951f89868ee15360.mp3"
|
|
2116
2099
|
},
|
|
2117
2100
|
{
|
|
2118
|
-
id: "
|
|
2119
|
-
name: "
|
|
2101
|
+
id: "add7bcb8d3c8423bbfa152ca232aad6e",
|
|
2102
|
+
name: "Ricardo",
|
|
2120
2103
|
gender: "male",
|
|
2121
|
-
accent: "
|
|
2122
|
-
languages: ["
|
|
2123
|
-
description: "A
|
|
2124
|
-
previewUrl: "https://
|
|
2104
|
+
accent: "brazilian",
|
|
2105
|
+
languages: ["pt"],
|
|
2106
|
+
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.",
|
|
2107
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-10-12/67475fc717ae45cbb38e647a2dd37fe1.mp3"
|
|
2125
2108
|
},
|
|
2126
2109
|
{
|
|
2127
|
-
id: "
|
|
2128
|
-
name: "
|
|
2129
|
-
gender: "
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/iP95p4xoKVk53GoZ742B/3f4bde72-cc48-40dd-829f-57fbf906f4d7.mp3"
|
|
2110
|
+
id: "b2d9d8db057042688a5e318b8f405bc2",
|
|
2111
|
+
name: "Kyoko",
|
|
2112
|
+
gender: "female",
|
|
2113
|
+
languages: ["ja"],
|
|
2114
|
+
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",
|
|
2115
|
+
previewUrl: "https://platform.r2.fish.audio/task/993b3ccb52124341aff79580f1ce5a5a.mp3"
|
|
2134
2116
|
},
|
|
2135
2117
|
{
|
|
2136
|
-
id: "
|
|
2137
|
-
name: "
|
|
2118
|
+
id: "297a6fd278df47c3b9da9bfdf55ac89a",
|
|
2119
|
+
name: "Satoru",
|
|
2138
2120
|
gender: "male",
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/nPczCjzI2devNBz1zQrb/2dd3e72c-4fd3-42f1-93ea-abc5d4e5aa1d.mp3"
|
|
2121
|
+
languages: ["ja"],
|
|
2122
|
+
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",
|
|
2123
|
+
previewUrl: "https://platform.r2.fish.audio/task/1b4712fb831f4c149eef6b0133157418.mp3"
|
|
2143
2124
|
},
|
|
2144
2125
|
{
|
|
2145
|
-
id: "
|
|
2146
|
-
name: "
|
|
2147
|
-
gender: "
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/onwK4e9ZLuTAKqWW03F9/7eee0236-1a72-4b86-b303-5dcadc007ba9.mp3"
|
|
2126
|
+
id: "0b14f34a13a94ed88fe6113193749bb0",
|
|
2127
|
+
name: "Fatima",
|
|
2128
|
+
gender: "female",
|
|
2129
|
+
languages: ["ar"],
|
|
2130
|
+
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.",
|
|
2131
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/93406e1b905a4c4994306e3421243390.mp3"
|
|
2152
2132
|
},
|
|
2153
2133
|
{
|
|
2154
|
-
id: "
|
|
2155
|
-
name: "
|
|
2134
|
+
id: "74c6aba5cbf94a15bbdc547ffce5cb38",
|
|
2135
|
+
name: "Yutong",
|
|
2156
2136
|
gender: "female",
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2137
|
+
languages: ["zh"],
|
|
2138
|
+
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",
|
|
2139
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/a48320f37fe44c4699549a1afc3778e8.mp3"
|
|
2140
|
+
}
|
|
2141
|
+
];
|
|
2142
|
+
|
|
2143
|
+
// src/catalog/speech-fish.ts
|
|
2144
|
+
var FISH_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/fishaudio.png";
|
|
2145
|
+
var PER_CALL2 = { unit: "images" };
|
|
2146
|
+
var PER_REQUEST2 = { unit: "requests" };
|
|
2147
|
+
var TTS_MAX_CHARS = 1e4;
|
|
2148
|
+
function fishTts(id, label, providerModelId, description) {
|
|
2149
|
+
return {
|
|
2150
|
+
id,
|
|
2151
|
+
aliases: [],
|
|
2152
|
+
label,
|
|
2153
|
+
type: "speech",
|
|
2154
|
+
adapter: "fish",
|
|
2155
|
+
providerModelId,
|
|
2156
|
+
lifecycle: "active",
|
|
2157
|
+
exposure: [],
|
|
2158
|
+
constraints: {
|
|
2159
|
+
voices: FISH_VOICES,
|
|
2160
|
+
outputFormats: ["mp3", "wav"],
|
|
2161
|
+
supports: [],
|
|
2162
|
+
prompt: { referenceSyntax: "numbered", maxChars: TTS_MAX_CHARS }
|
|
2163
|
+
},
|
|
2164
|
+
defaults: { voice: "9a9cf47702da476aa4629e2506d4a857", outputFormat: "mp3" },
|
|
2165
|
+
usage: PER_CALL2,
|
|
2166
|
+
pricingKind: "flat",
|
|
2167
|
+
display: { provider: "fishaudio", logo: FISH_LOGO, description },
|
|
2168
|
+
capabilities: { customVoices: true }
|
|
2169
|
+
};
|
|
2170
|
+
}
|
|
2171
|
+
var FISH_MODELS = [
|
|
2172
|
+
fishTts(
|
|
2173
|
+
"fish-s2.1-pro",
|
|
2174
|
+
"Fish Audio S2.1 Pro",
|
|
2175
|
+
"s2.1-pro",
|
|
2176
|
+
"Fish Audio S2.1 Pro text to speech in 83 languages, with [bracket] directions and your own cloned voices."
|
|
2177
|
+
),
|
|
2178
|
+
fishTts(
|
|
2179
|
+
"fish-s2.1-pro-free",
|
|
2180
|
+
"Fish Audio S2.1 Pro Free",
|
|
2181
|
+
"s2.1-pro-free",
|
|
2182
|
+
"Fish Audio S2.1 Pro on the free developer tier: the same voices at no cost, without latency or data-processing guarantees."
|
|
2183
|
+
),
|
|
2184
|
+
fishTts(
|
|
2185
|
+
"fish-drama-3",
|
|
2186
|
+
"Fish Audio Drama 3",
|
|
2187
|
+
"drama-3",
|
|
2188
|
+
"Fish Audio Drama 3 text to speech you direct like an actor: [directions], sounds, pauses and per-word tags."
|
|
2189
|
+
),
|
|
2190
|
+
{
|
|
2191
|
+
id: "fish-voice-clone",
|
|
2192
|
+
aliases: [],
|
|
2193
|
+
label: "Fish Audio Voice Clone",
|
|
2194
|
+
type: "voice-clone",
|
|
2195
|
+
adapter: "fish",
|
|
2196
|
+
providerModelId: "voice-clone",
|
|
2197
|
+
lifecycle: "active",
|
|
2198
|
+
exposure: [],
|
|
2199
|
+
constraints: {
|
|
2200
|
+
// POST /model takes 1-20 voice files; Fish advises 10 s or more of clean speech each.
|
|
2201
|
+
references: { audios: 20, audioFormats: ["wav", "mp3", "m4a", "opus"] },
|
|
2202
|
+
supports: []
|
|
2203
|
+
},
|
|
2204
|
+
defaults: {},
|
|
2205
|
+
usage: PER_REQUEST2,
|
|
2206
|
+
pricingKind: "flat",
|
|
2207
|
+
display: {
|
|
2208
|
+
provider: "fishaudio",
|
|
2209
|
+
logo: FISH_LOGO,
|
|
2210
|
+
description: "Clone a private, reusable voice from one or more clean recordings, then speak with it on the Fish Audio speech models."
|
|
2211
|
+
},
|
|
2212
|
+
capabilities: {}
|
|
2161
2213
|
},
|
|
2162
2214
|
{
|
|
2163
|
-
id: "
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2215
|
+
id: "fish-voice-design-1",
|
|
2216
|
+
aliases: [],
|
|
2217
|
+
label: "Fish Audio Voice Design",
|
|
2218
|
+
type: "voice-design",
|
|
2219
|
+
adapter: "fish",
|
|
2220
|
+
providerModelId: "voice-design-1",
|
|
2221
|
+
lifecycle: "active",
|
|
2222
|
+
exposure: [],
|
|
2223
|
+
constraints: {
|
|
2224
|
+
voiceDesign: { maxCandidates: 4, previewMaxChars: 150 },
|
|
2225
|
+
supports: [],
|
|
2226
|
+
prompt: { referenceSyntax: "numbered", maxChars: 2e3 }
|
|
2227
|
+
},
|
|
2228
|
+
defaults: {},
|
|
2229
|
+
usage: PER_REQUEST2,
|
|
2230
|
+
pricingKind: "flat",
|
|
2231
|
+
display: {
|
|
2232
|
+
provider: "fishaudio",
|
|
2233
|
+
logo: FISH_LOGO,
|
|
2234
|
+
description: "Describe a voice and get up to four short candidates; keep one as a cloned voice."
|
|
2235
|
+
},
|
|
2236
|
+
capabilities: {}
|
|
2170
2237
|
}
|
|
2171
2238
|
];
|
|
2172
2239
|
|
|
@@ -3745,11 +3812,11 @@ var MINIMAX_VOICES = [
|
|
|
3745
3812
|
];
|
|
3746
3813
|
|
|
3747
3814
|
// src/catalog/media-nodes.ts
|
|
3748
|
-
var
|
|
3815
|
+
var ELEVENLABS_LOGO2 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
|
|
3749
3816
|
var GOOGLE_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
|
|
3750
3817
|
var MINIMAX_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png";
|
|
3751
3818
|
var SYNC_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/sync.png";
|
|
3752
|
-
var
|
|
3819
|
+
var PER_CALL3 = { unit: "images" };
|
|
3753
3820
|
var EXPOSURE4 = ["cowork", "space_builder"];
|
|
3754
3821
|
var LIPSYNC_AUDIO = { audioSeconds: { max: 30 } };
|
|
3755
3822
|
function elevenLabsTts(tts) {
|
|
@@ -3770,9 +3837,9 @@ function elevenLabsTts(tts) {
|
|
|
3770
3837
|
prompt: { referenceSyntax: "numbered", maxChars: tts.maxChars }
|
|
3771
3838
|
},
|
|
3772
3839
|
defaults: { voice: "Rachel", ...tts.formats && { outputFormat: "mp3_44100_128" } },
|
|
3773
|
-
usage:
|
|
3840
|
+
usage: PER_CALL3,
|
|
3774
3841
|
pricingKind: "flat",
|
|
3775
|
-
display: { provider: "elevenlabs", logo:
|
|
3842
|
+
display: { provider: "elevenlabs", logo: ELEVENLABS_LOGO2, description: tts.description },
|
|
3776
3843
|
capabilities: {}
|
|
3777
3844
|
};
|
|
3778
3845
|
}
|
|
@@ -3794,7 +3861,7 @@ function geminiTts(id, label, description) {
|
|
|
3794
3861
|
prompt: { referenceSyntax: "numbered", maxChars: 8192 }
|
|
3795
3862
|
},
|
|
3796
3863
|
defaults: { voice: "Kore" },
|
|
3797
|
-
usage:
|
|
3864
|
+
usage: PER_CALL3,
|
|
3798
3865
|
pricingKind: "flat",
|
|
3799
3866
|
display: { provider: "google", logo: GOOGLE_LOGO, description },
|
|
3800
3867
|
capabilities: {}
|
|
@@ -3817,7 +3884,7 @@ function syncLipsync(id, label, providerModelId, syncModel, description) {
|
|
|
3817
3884
|
},
|
|
3818
3885
|
defaults: {},
|
|
3819
3886
|
...syncModel !== void 0 && { providerOptions: { fal: { model: syncModel } } },
|
|
3820
|
-
usage:
|
|
3887
|
+
usage: PER_CALL3,
|
|
3821
3888
|
pricingKind: "flat",
|
|
3822
3889
|
display: { provider: "sync", logo: SYNC_LOGO, description },
|
|
3823
3890
|
capabilities: { acceptsSourceVideo: true }
|
|
@@ -3878,7 +3945,7 @@ var MEDIA_NODE_MODELS = [
|
|
|
3878
3945
|
prompt: { referenceSyntax: "numbered", maxChars: 1e4 }
|
|
3879
3946
|
},
|
|
3880
3947
|
defaults: { voice: "Wise_Woman" },
|
|
3881
|
-
usage:
|
|
3948
|
+
usage: PER_CALL3,
|
|
3882
3949
|
pricingKind: "flat",
|
|
3883
3950
|
display: {
|
|
3884
3951
|
provider: "minimax",
|
|
@@ -3905,11 +3972,11 @@ var MEDIA_NODE_MODELS = [
|
|
|
3905
3972
|
supports: []
|
|
3906
3973
|
},
|
|
3907
3974
|
defaults: { voice: "Rachel", outputFormat: "mp3_44100_128" },
|
|
3908
|
-
usage:
|
|
3975
|
+
usage: PER_CALL3,
|
|
3909
3976
|
pricingKind: "flat",
|
|
3910
3977
|
display: {
|
|
3911
3978
|
provider: "elevenlabs",
|
|
3912
|
-
logo:
|
|
3979
|
+
logo: ELEVENLABS_LOGO2,
|
|
3913
3980
|
description: "ElevenLabs speech to speech; re-voices a recording in another voice and keeps its timing and delivery."
|
|
3914
3981
|
},
|
|
3915
3982
|
capabilities: {}
|
|
@@ -3932,11 +3999,11 @@ var MEDIA_NODE_MODELS = [
|
|
|
3932
3999
|
supports: []
|
|
3933
4000
|
},
|
|
3934
4001
|
defaults: {},
|
|
3935
|
-
usage:
|
|
4002
|
+
usage: PER_CALL3,
|
|
3936
4003
|
pricingKind: "flat",
|
|
3937
4004
|
display: {
|
|
3938
4005
|
provider: "elevenlabs",
|
|
3939
|
-
logo:
|
|
4006
|
+
logo: ELEVENLABS_LOGO2,
|
|
3940
4007
|
description: "ElevenLabs dubbing; translates the speech in a video or audio file into another language in the original voices."
|
|
3941
4008
|
},
|
|
3942
4009
|
capabilities: { acceptsSourceVideo: true }
|
|
@@ -3979,7 +4046,7 @@ var MEDIA_NODE_MODELS = [
|
|
|
3979
4046
|
supports: []
|
|
3980
4047
|
},
|
|
3981
4048
|
defaults: {},
|
|
3982
|
-
usage:
|
|
4049
|
+
usage: PER_CALL3,
|
|
3983
4050
|
pricingKind: "flat",
|
|
3984
4051
|
display: {
|
|
3985
4052
|
provider: "veed",
|
|
@@ -4031,17 +4098,18 @@ var MEDIA_NODE_MODELS = [
|
|
|
4031
4098
|
supports: []
|
|
4032
4099
|
},
|
|
4033
4100
|
defaults: {},
|
|
4034
|
-
usage:
|
|
4101
|
+
usage: PER_CALL3,
|
|
4035
4102
|
pricingKind: "flat",
|
|
4036
4103
|
display: {
|
|
4037
4104
|
provider: "elevenlabs",
|
|
4038
|
-
logo:
|
|
4105
|
+
logo: ELEVENLABS_LOGO2,
|
|
4039
4106
|
description: "ElevenLabs Scribe v2 speech to text with word timings, speaker labels and audio-event tags."
|
|
4040
4107
|
},
|
|
4041
4108
|
capabilities: {}
|
|
4042
4109
|
},
|
|
4043
4110
|
SAM_3_IMAGE,
|
|
4044
|
-
...FISH_MODELS
|
|
4111
|
+
...FISH_MODELS,
|
|
4112
|
+
...ELEVENLABS_DIRECT_MODELS
|
|
4045
4113
|
];
|
|
4046
4114
|
|
|
4047
4115
|
// src/catalog/model3d.ts
|
|
@@ -4237,7 +4305,7 @@ var MODEL3D_MODELS = [
|
|
|
4237
4305
|
|
|
4238
4306
|
// src/catalog/other.ts
|
|
4239
4307
|
var GOOGLE_LOGO2 = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
|
|
4240
|
-
var
|
|
4308
|
+
var ELEVENLABS_LOGO3 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
|
|
4241
4309
|
var MINIMAX_LOGO2 = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png";
|
|
4242
4310
|
var OTHER_MODELS = [
|
|
4243
4311
|
{
|
|
@@ -4402,7 +4470,7 @@ var OTHER_MODELS = [
|
|
|
4402
4470
|
pricingKind: "flat",
|
|
4403
4471
|
display: {
|
|
4404
4472
|
provider: "elevenlabs",
|
|
4405
|
-
logo:
|
|
4473
|
+
logo: ELEVENLABS_LOGO3,
|
|
4406
4474
|
description: "ElevenLabs Music v2.5 text-to-music; full songs or instrumentals from 3 seconds to 1 minute."
|
|
4407
4475
|
},
|
|
4408
4476
|
capabilities: {}
|
|
@@ -4454,7 +4522,7 @@ var OTHER_MODELS = [
|
|
|
4454
4522
|
pricingKind: "flat",
|
|
4455
4523
|
display: {
|
|
4456
4524
|
provider: "elevenlabs",
|
|
4457
|
-
logo:
|
|
4525
|
+
logo: ELEVENLABS_LOGO3,
|
|
4458
4526
|
description: "ElevenLabs Sound Effects v2; a sound effect from a text description, up to 22 seconds."
|
|
4459
4527
|
},
|
|
4460
4528
|
capabilities: {}
|
|
@@ -7677,7 +7745,8 @@ var ADAPTER_IDS = [
|
|
|
7677
7745
|
"higgsfield",
|
|
7678
7746
|
"xai-video",
|
|
7679
7747
|
"luma",
|
|
7680
|
-
"fish"
|
|
7748
|
+
"fish",
|
|
7749
|
+
"elevenlabs"
|
|
7681
7750
|
];
|
|
7682
7751
|
var ModelTypeSchema = import_zod3.z.enum([
|
|
7683
7752
|
"text",
|
|
@@ -8890,16 +8959,16 @@ async function generateSeedreamImage(req, ctx) {
|
|
|
8890
8959
|
} else {
|
|
8891
8960
|
throwArkError(void 0, "Seedream returned no image URL or base64 data", modelId);
|
|
8892
8961
|
}
|
|
8893
|
-
const
|
|
8962
|
+
const usage5 = {
|
|
8894
8963
|
model: modelId,
|
|
8895
8964
|
provider: "ark",
|
|
8896
8965
|
modality: "IMAGE",
|
|
8897
8966
|
unit: "images",
|
|
8898
8967
|
quantity: 1
|
|
8899
8968
|
};
|
|
8900
|
-
if (req.size !== void 0)
|
|
8901
|
-
if (req.quality !== void 0)
|
|
8902
|
-
return { images: [{ bytes, mime: sniffedImageMime(bytes) }], usage:
|
|
8969
|
+
if (req.size !== void 0) usage5.imageSize = req.size;
|
|
8970
|
+
if (req.quality !== void 0) usage5.imageQuality = req.quality;
|
|
8971
|
+
return { images: [{ bytes, mime: sniffedImageMime(bytes) }], usage: usage5, raw: data };
|
|
8903
8972
|
}
|
|
8904
8973
|
var SeedanceUsageSchema = import_zod7.z.object({
|
|
8905
8974
|
total_tokens: import_zod7.z.number().optional(),
|
|
@@ -8940,7 +9009,7 @@ function seedanceErrorMessage(error, status) {
|
|
|
8940
9009
|
if (asObject.success && asObject.data.message !== void 0) return asObject.data.message;
|
|
8941
9010
|
return `Seedance task ${status}`;
|
|
8942
9011
|
}
|
|
8943
|
-
function seedanceJob(ctx, key, jobId,
|
|
9012
|
+
function seedanceJob(ctx, key, jobId, usage5) {
|
|
8944
9013
|
const modelId = ctx.model.id;
|
|
8945
9014
|
const fetchStatus = async () => {
|
|
8946
9015
|
const res = await arkFetch(ctx, `${arkBaseUrl(ctx)}${SUBMIT_PATH}/${jobId}`, {
|
|
@@ -8990,21 +9059,21 @@ function seedanceJob(ctx, key, jobId, usage4) {
|
|
|
8990
9059
|
modelId
|
|
8991
9060
|
);
|
|
8992
9061
|
if (polled.duration !== void 0 && polled.duration > 0) {
|
|
8993
|
-
|
|
8994
|
-
|
|
9062
|
+
usage5.quantity = polled.duration;
|
|
9063
|
+
usage5.durationSeconds = polled.duration;
|
|
8995
9064
|
}
|
|
8996
9065
|
const rendered = VideoResolutionSchema.safeParse(
|
|
8997
9066
|
polled.resolution?.toLowerCase()
|
|
8998
9067
|
);
|
|
8999
|
-
if (rendered.success)
|
|
9068
|
+
if (rendered.success) usage5.resolution = rendered.data;
|
|
9000
9069
|
const tokens = polled.usage;
|
|
9001
9070
|
if (tokens?.total_tokens !== void 0 && tokens.completion_tokens !== void 0) {
|
|
9002
|
-
|
|
9003
|
-
|
|
9071
|
+
usage5.inputTokens = tokens.total_tokens - tokens.completion_tokens;
|
|
9072
|
+
usage5.outputTokens = tokens.completion_tokens;
|
|
9004
9073
|
}
|
|
9005
9074
|
return {
|
|
9006
9075
|
video: { url, expiresAt: new Date(Date.now() + VIDEO_URL_TTL_MS) },
|
|
9007
|
-
usage:
|
|
9076
|
+
usage: usage5,
|
|
9008
9077
|
raw: polled
|
|
9009
9078
|
};
|
|
9010
9079
|
}
|
|
@@ -9110,8 +9179,8 @@ async function generateSeedanceVideo(req, ctx) {
|
|
|
9110
9179
|
);
|
|
9111
9180
|
if (!submit.id) throwArkError(void 0, "Seedance task create returned no id", modelId);
|
|
9112
9181
|
const jobId = submit.id;
|
|
9113
|
-
const
|
|
9114
|
-
return seedanceJob(ctx, key, jobId,
|
|
9182
|
+
const usage5 = seedanceUsage(ctx, req, taskType === "edit" ? requestedDuration : duration);
|
|
9183
|
+
return seedanceJob(ctx, key, jobId, usage5);
|
|
9115
9184
|
}
|
|
9116
9185
|
|
|
9117
9186
|
// src/adapters/fal.ts
|
|
@@ -10599,7 +10668,7 @@ async function collectFalPlanImages(payload, plan4, ctx, req) {
|
|
|
10599
10668
|
return { bytes, mime: mime || "image/png" };
|
|
10600
10669
|
})
|
|
10601
10670
|
);
|
|
10602
|
-
const
|
|
10671
|
+
const usage5 = {
|
|
10603
10672
|
model: ctx.model.id,
|
|
10604
10673
|
provider: "fal",
|
|
10605
10674
|
modality: "IMAGE",
|
|
@@ -10607,9 +10676,9 @@ async function collectFalPlanImages(payload, plan4, ctx, req) {
|
|
|
10607
10676
|
quantity: images.length
|
|
10608
10677
|
};
|
|
10609
10678
|
const billedSize = plan4.imageSize ?? req.size;
|
|
10610
|
-
if (billedSize !== void 0 && ctx.model.type === "image")
|
|
10611
|
-
if (plan4.imageQuality !== void 0)
|
|
10612
|
-
const result = { images, usage:
|
|
10679
|
+
if (billedSize !== void 0 && ctx.model.type === "image") usage5.imageSize = billedSize;
|
|
10680
|
+
if (plan4.imageQuality !== void 0) usage5.imageQuality = plan4.imageQuality;
|
|
10681
|
+
const result = { images, usage: usage5, raw: payload };
|
|
10613
10682
|
const remote = files.find((f) => !f.url.startsWith("data:"));
|
|
10614
10683
|
if (remote !== void 0) result.outputUrl = remote.url;
|
|
10615
10684
|
return result;
|
|
@@ -12772,9 +12841,282 @@ function planUsage(ctx, plan4) {
|
|
|
12772
12841
|
};
|
|
12773
12842
|
}
|
|
12774
12843
|
|
|
12775
|
-
// src/adapters/
|
|
12844
|
+
// src/adapters/elevenlabs.ts
|
|
12776
12845
|
var import_zod21 = require("zod");
|
|
12777
|
-
var DEFAULT_BASE_URL = "https://api.
|
|
12846
|
+
var DEFAULT_BASE_URL = "https://api.elevenlabs.io";
|
|
12847
|
+
var DEFAULT_FORMAT = "mp3_44100_128";
|
|
12848
|
+
var ELEVENLABS_TTS_MODEL_IDS = /* @__PURE__ */ new Set(["eleven_v4"]);
|
|
12849
|
+
var ELEVENLABS_IVC = "ivc";
|
|
12850
|
+
var VOICE_ID = /^[A-Za-z0-9_-]{1,64}$/;
|
|
12851
|
+
function elevenLabsRowRefusal(row2) {
|
|
12852
|
+
const id = row2.providerModelId;
|
|
12853
|
+
if (row2.type === "speech") {
|
|
12854
|
+
return ELEVENLABS_TTS_MODEL_IDS.has(id) ? void 0 : `elevenlabs speech rows need providerModelId ${[...ELEVENLABS_TTS_MODEL_IDS].join(", ")}`;
|
|
12855
|
+
}
|
|
12856
|
+
if (row2.type === "voice-clone") {
|
|
12857
|
+
return id === ELEVENLABS_IVC ? void 0 : `elevenlabs voice-clone rows need providerModelId ${ELEVENLABS_IVC}`;
|
|
12858
|
+
}
|
|
12859
|
+
return `elevenlabs has no ${row2.type} rows`;
|
|
12860
|
+
}
|
|
12861
|
+
function elevenLabsError(ctx, code, message) {
|
|
12862
|
+
return new ModelKitError({
|
|
12863
|
+
code,
|
|
12864
|
+
message,
|
|
12865
|
+
provider: "elevenlabs",
|
|
12866
|
+
model: ctx.model.id,
|
|
12867
|
+
retryable: false
|
|
12868
|
+
});
|
|
12869
|
+
}
|
|
12870
|
+
function checkRow(ctx, type) {
|
|
12871
|
+
const refusal2 = ctx.model.type === type ? elevenLabsRowRefusal(ctx.model) : void 0;
|
|
12872
|
+
if (ctx.model.type !== type || refusal2 !== void 0) {
|
|
12873
|
+
throw elevenLabsError(
|
|
12874
|
+
ctx,
|
|
12875
|
+
"unsupported_option",
|
|
12876
|
+
refusal2 ?? `${ctx.model.id} is not a ${type} row`
|
|
12877
|
+
);
|
|
12878
|
+
}
|
|
12879
|
+
}
|
|
12880
|
+
function checkVoiceId(ctx, field, id) {
|
|
12881
|
+
if (!VOICE_ID.test(id))
|
|
12882
|
+
throw elevenLabsError(ctx, "unsupported_option", `${field} is not a voice id`);
|
|
12883
|
+
return id;
|
|
12884
|
+
}
|
|
12885
|
+
function elevenLabsKey(ctx) {
|
|
12886
|
+
const key = ctx.keys.elevenlabs;
|
|
12887
|
+
if (!key) throw elevenLabsError(ctx, "auth", "Missing API key for elevenlabs");
|
|
12888
|
+
return key;
|
|
12889
|
+
}
|
|
12890
|
+
function elevenLabsUrl(ctx, path) {
|
|
12891
|
+
return `${ctx.endpoints?.elevenlabs ?? DEFAULT_BASE_URL}${path}`;
|
|
12892
|
+
}
|
|
12893
|
+
var errorDetail = import_zod21.z.object({
|
|
12894
|
+
detail: import_zod21.z.object({ status: import_zod21.z.string(), message: import_zod21.z.string().optional() })
|
|
12895
|
+
});
|
|
12896
|
+
function errorStatus(body) {
|
|
12897
|
+
const parsed = errorDetail.safeParse(body);
|
|
12898
|
+
return parsed.success ? parsed.data.detail : void 0;
|
|
12899
|
+
}
|
|
12900
|
+
function classifyResponse(ctx, status, body) {
|
|
12901
|
+
const error = classifyHttpError(status, body, "elevenlabs", ctx.model.id);
|
|
12902
|
+
const detail = errorStatus(body);
|
|
12903
|
+
if (detail?.status === "voice_limit_reached") {
|
|
12904
|
+
return new ModelKitError({
|
|
12905
|
+
code: "provider_rejected",
|
|
12906
|
+
message: detail.message ?? "ElevenLabs voice limit reached",
|
|
12907
|
+
provider: "elevenlabs",
|
|
12908
|
+
model: ctx.model.id,
|
|
12909
|
+
status,
|
|
12910
|
+
body,
|
|
12911
|
+
cause: error,
|
|
12912
|
+
retryable: false
|
|
12913
|
+
});
|
|
12914
|
+
}
|
|
12915
|
+
if (detail?.status === "quota_exceeded") {
|
|
12916
|
+
return new ModelKitError({
|
|
12917
|
+
code: "provider_billing",
|
|
12918
|
+
message: error.message,
|
|
12919
|
+
provider: "elevenlabs",
|
|
12920
|
+
model: ctx.model.id,
|
|
12921
|
+
status,
|
|
12922
|
+
body,
|
|
12923
|
+
cause: error,
|
|
12924
|
+
retryable: false
|
|
12925
|
+
});
|
|
12926
|
+
}
|
|
12927
|
+
return error;
|
|
12928
|
+
}
|
|
12929
|
+
async function elevenLabsFetch(ctx, path, init) {
|
|
12930
|
+
throwIfAborted(ctx.signal);
|
|
12931
|
+
const request = {
|
|
12932
|
+
method: init.method,
|
|
12933
|
+
headers: { "xi-api-key": elevenLabsKey(ctx), ...init.headers }
|
|
12934
|
+
};
|
|
12935
|
+
if (init.body !== void 0) request.body = init.body;
|
|
12936
|
+
if (ctx.signal !== void 0) request.signal = ctx.signal;
|
|
12937
|
+
let res;
|
|
12938
|
+
try {
|
|
12939
|
+
res = await ctx.fetch(elevenLabsUrl(ctx, path), request);
|
|
12940
|
+
} catch (cause) {
|
|
12941
|
+
throw classifyThrown("elevenlabs", cause, ctx.model.id);
|
|
12942
|
+
}
|
|
12943
|
+
if (!res.ok) throw classifyResponse(ctx, res.status, await readBody(res));
|
|
12944
|
+
return res;
|
|
12945
|
+
}
|
|
12946
|
+
function usage2(ctx) {
|
|
12947
|
+
return {
|
|
12948
|
+
model: ctx.model.id,
|
|
12949
|
+
provider: "elevenlabs",
|
|
12950
|
+
modality: "AUDIO",
|
|
12951
|
+
unit: ctx.model.usage.unit,
|
|
12952
|
+
quantity: 1
|
|
12953
|
+
};
|
|
12954
|
+
}
|
|
12955
|
+
function audioMime(res) {
|
|
12956
|
+
const header = res.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase();
|
|
12957
|
+
return header?.startsWith("audio/") ? header : "audio/mpeg";
|
|
12958
|
+
}
|
|
12959
|
+
async function generateSpeech(req, ctx) {
|
|
12960
|
+
checkRow(ctx, "speech");
|
|
12961
|
+
const voice = req.customVoice ?? req.voice;
|
|
12962
|
+
if (voice === void 0) throw elevenLabsError(ctx, "missing_input", "needs a voice");
|
|
12963
|
+
const voiceId = checkVoiceId(ctx, req.customVoice ? "customVoice" : "voice", voice);
|
|
12964
|
+
const format = req.outputFormat ?? DEFAULT_FORMAT;
|
|
12965
|
+
const body = { text: req.text, model_id: ctx.model.providerModelId };
|
|
12966
|
+
if (req.language !== void 0) body.language_code = req.language;
|
|
12967
|
+
const path = `/v1/text-to-speech/${encodeURIComponent(voiceId)}?output_format=${encodeURIComponent(format)}`;
|
|
12968
|
+
const { bytes, mime } = await withRetry(
|
|
12969
|
+
async () => {
|
|
12970
|
+
const res = await elevenLabsFetch(ctx, path, {
|
|
12971
|
+
method: "POST",
|
|
12972
|
+
headers: { "Content-Type": "application/json" },
|
|
12973
|
+
body: JSON.stringify(body)
|
|
12974
|
+
});
|
|
12975
|
+
let audio;
|
|
12976
|
+
try {
|
|
12977
|
+
audio = new Uint8Array(await res.arrayBuffer());
|
|
12978
|
+
} catch (cause) {
|
|
12979
|
+
throw classifyThrown("elevenlabs", cause, ctx.model.id);
|
|
12980
|
+
}
|
|
12981
|
+
return { bytes: audio, mime: audioMime(res) };
|
|
12982
|
+
},
|
|
12983
|
+
mediaRetryOptions(ctx.call, ctx.signal)
|
|
12984
|
+
);
|
|
12985
|
+
if (bytes.byteLength === 0)
|
|
12986
|
+
throw elevenLabsError(ctx, "provider_rejected", "ElevenLabs TTS returned no audio");
|
|
12987
|
+
return { audio: { bytes, mime }, usage: usage2(ctx) };
|
|
12988
|
+
}
|
|
12989
|
+
var createdVoiceSchema = import_zod21.z.object({
|
|
12990
|
+
voice_id: import_zod21.z.string().min(1),
|
|
12991
|
+
requires_verification: import_zod21.z.boolean().optional().catch(void 0)
|
|
12992
|
+
});
|
|
12993
|
+
function sampleMime(mime) {
|
|
12994
|
+
return mime.startsWith("audio/") || mime.startsWith("video/") ? mime : "application/octet-stream";
|
|
12995
|
+
}
|
|
12996
|
+
function fileName(index, mime, ref) {
|
|
12997
|
+
const fromMime = mime === "application/octet-stream" ? void 0 : mime.split("/")[1]?.replace("mpeg", "mp3").replace("x-", "");
|
|
12998
|
+
const fromUrl = "url" in ref ? /\.([A-Za-z0-9]{2,4})$/.exec(new URL(ref.url).pathname)?.[1] : void 0;
|
|
12999
|
+
const ext = fromMime || fromUrl?.toLowerCase();
|
|
13000
|
+
return ext ? `sample-${index + 1}.${ext}` : `sample-${index + 1}`;
|
|
13001
|
+
}
|
|
13002
|
+
async function cloneForm(req, ctx) {
|
|
13003
|
+
if (req.samples.length === 0)
|
|
13004
|
+
throw elevenLabsError(ctx, "missing_input", "needs a voice sample");
|
|
13005
|
+
if (req.samples.some((s) => s.designSignature?.trim())) {
|
|
13006
|
+
throw elevenLabsError(
|
|
13007
|
+
ctx,
|
|
13008
|
+
"unsupported_option",
|
|
13009
|
+
"ElevenLabs cannot keep a voice design signature; clone from recordings only"
|
|
13010
|
+
);
|
|
13011
|
+
}
|
|
13012
|
+
const form = new FormData();
|
|
13013
|
+
form.append("name", req.title.trim());
|
|
13014
|
+
if (req.description?.trim()) form.append("description", req.description.trim());
|
|
13015
|
+
if (req.enhance !== void 0) form.append("remove_background_noise", String(req.enhance));
|
|
13016
|
+
for (const [index, sample] of req.samples.entries()) {
|
|
13017
|
+
const { bytes, mime } = await mediaRefToBytes(sample.audio, ctx.fetch, {
|
|
13018
|
+
signal: ctx.signal,
|
|
13019
|
+
provider: "elevenlabs",
|
|
13020
|
+
model: ctx.model.id
|
|
13021
|
+
});
|
|
13022
|
+
const type = sampleMime(mime);
|
|
13023
|
+
const audio = new Blob([new Uint8Array(bytes)], { type });
|
|
13024
|
+
form.append("files", audio, fileName(index, type, sample.audio));
|
|
13025
|
+
}
|
|
13026
|
+
return form;
|
|
13027
|
+
}
|
|
13028
|
+
async function onlyRateLimitRetries(fn) {
|
|
13029
|
+
try {
|
|
13030
|
+
return await fn();
|
|
13031
|
+
} catch (cause) {
|
|
13032
|
+
if (!isModelKitError(cause) || !cause.retryable || cause.code === "rate_limited")
|
|
13033
|
+
throw cause;
|
|
13034
|
+
throw new ModelKitError({
|
|
13035
|
+
code: cause.code,
|
|
13036
|
+
message: cause.message,
|
|
13037
|
+
...cause.provider !== void 0 && { provider: cause.provider },
|
|
13038
|
+
...cause.model !== void 0 && { model: cause.model },
|
|
13039
|
+
...cause.status !== void 0 && { status: cause.status },
|
|
13040
|
+
...cause.body !== void 0 && { body: cause.body },
|
|
13041
|
+
cause,
|
|
13042
|
+
retryable: false
|
|
13043
|
+
});
|
|
13044
|
+
}
|
|
13045
|
+
}
|
|
13046
|
+
async function createVoice(req, ctx) {
|
|
13047
|
+
checkRow(ctx, "voice-clone");
|
|
13048
|
+
const form = await cloneForm(req, ctx);
|
|
13049
|
+
const res = await withRetry(
|
|
13050
|
+
() => onlyRateLimitRetries(
|
|
13051
|
+
() => elevenLabsFetch(ctx, "/v1/voices/add", { method: "POST", body: form })
|
|
13052
|
+
),
|
|
13053
|
+
mediaRetryOptions(ctx.call, ctx.signal)
|
|
13054
|
+
);
|
|
13055
|
+
const raw = await readBody(res);
|
|
13056
|
+
const parsed = createdVoiceSchema.safeParse(raw);
|
|
13057
|
+
if (!parsed.success) {
|
|
13058
|
+
throw new ModelKitError({
|
|
13059
|
+
code: "provider_rejected",
|
|
13060
|
+
message: "ElevenLabs returned no voice id",
|
|
13061
|
+
provider: "elevenlabs",
|
|
13062
|
+
model: ctx.model.id,
|
|
13063
|
+
status: res.status,
|
|
13064
|
+
body: raw,
|
|
13065
|
+
retryable: false
|
|
13066
|
+
});
|
|
13067
|
+
}
|
|
13068
|
+
return {
|
|
13069
|
+
voiceId: parsed.data.voice_id,
|
|
13070
|
+
state: parsed.data.requires_verification === true ? "created" : "trained",
|
|
13071
|
+
usage: usage2(ctx),
|
|
13072
|
+
raw
|
|
13073
|
+
};
|
|
13074
|
+
}
|
|
13075
|
+
var NOT_FOUND_STATUSES = /* @__PURE__ */ new Set([
|
|
13076
|
+
"voice_not_found",
|
|
13077
|
+
"voice_does_not_exist"
|
|
13078
|
+
]);
|
|
13079
|
+
function notFound(cause) {
|
|
13080
|
+
if (cause.status === 404) return true;
|
|
13081
|
+
const status = errorStatus(cause.body)?.status;
|
|
13082
|
+
return cause.status === 400 && status !== void 0 && NOT_FOUND_STATUSES.has(status);
|
|
13083
|
+
}
|
|
13084
|
+
async function deleteVoice(req, ctx) {
|
|
13085
|
+
checkRow(ctx, "voice-clone");
|
|
13086
|
+
const id = encodeURIComponent(checkVoiceId(ctx, "voiceId", req.voiceId));
|
|
13087
|
+
let attempts = 0;
|
|
13088
|
+
await withRetry(
|
|
13089
|
+
async () => {
|
|
13090
|
+
attempts += 1;
|
|
13091
|
+
try {
|
|
13092
|
+
await elevenLabsFetch(ctx, `/v1/voices/${id}`, { method: "DELETE" });
|
|
13093
|
+
} catch (cause) {
|
|
13094
|
+
if (!isModelKitError(cause) || !notFound(cause)) throw cause;
|
|
13095
|
+
if (attempts > 1) return;
|
|
13096
|
+
throw new ModelKitError({
|
|
13097
|
+
code: "provider_rejected",
|
|
13098
|
+
message: `ElevenLabs has no voice ${req.voiceId} under this key set; delete with the tier that created it`,
|
|
13099
|
+
provider: "elevenlabs",
|
|
13100
|
+
model: ctx.model.id,
|
|
13101
|
+
...cause.status !== void 0 && { status: cause.status },
|
|
13102
|
+
cause,
|
|
13103
|
+
retryable: false
|
|
13104
|
+
});
|
|
13105
|
+
}
|
|
13106
|
+
},
|
|
13107
|
+
mediaRetryOptions(ctx.call, ctx.signal)
|
|
13108
|
+
);
|
|
13109
|
+
}
|
|
13110
|
+
var elevenLabsAdapter = {
|
|
13111
|
+
id: "elevenlabs",
|
|
13112
|
+
generateSpeech,
|
|
13113
|
+
createVoice,
|
|
13114
|
+
deleteVoice
|
|
13115
|
+
};
|
|
13116
|
+
|
|
13117
|
+
// src/adapters/fish.ts
|
|
13118
|
+
var import_zod22 = require("zod");
|
|
13119
|
+
var DEFAULT_BASE_URL2 = "https://api.fish.audio";
|
|
12778
13120
|
var FISH_TTS_MODEL_IDS = /* @__PURE__ */ new Set([
|
|
12779
13121
|
"s2.1-pro",
|
|
12780
13122
|
"s2.1-pro-free",
|
|
@@ -12782,7 +13124,7 @@ var FISH_TTS_MODEL_IDS = /* @__PURE__ */ new Set([
|
|
|
12782
13124
|
]);
|
|
12783
13125
|
var FISH_VOICE_CLONE = "voice-clone";
|
|
12784
13126
|
var FISH_VOICE_DESIGN = "voice-design-1";
|
|
12785
|
-
var
|
|
13127
|
+
var VOICE_ID2 = /^[A-Za-z0-9_-]{1,64}$/;
|
|
12786
13128
|
function fishRowRefusal(row2) {
|
|
12787
13129
|
const id = row2.providerModelId;
|
|
12788
13130
|
if (row2.type === "speech") {
|
|
@@ -12805,7 +13147,7 @@ function fishError(ctx, code, message) {
|
|
|
12805
13147
|
retryable: false
|
|
12806
13148
|
});
|
|
12807
13149
|
}
|
|
12808
|
-
function
|
|
13150
|
+
function checkRow2(ctx, type) {
|
|
12809
13151
|
const refusal2 = ctx.model.type === type ? fishRowRefusal(ctx.model) : void 0;
|
|
12810
13152
|
if (ctx.model.type !== type || refusal2 !== void 0) {
|
|
12811
13153
|
throw fishError(
|
|
@@ -12815,8 +13157,8 @@ function checkRow(ctx, type) {
|
|
|
12815
13157
|
);
|
|
12816
13158
|
}
|
|
12817
13159
|
}
|
|
12818
|
-
function
|
|
12819
|
-
if (!
|
|
13160
|
+
function checkVoiceId2(ctx, field, id) {
|
|
13161
|
+
if (!VOICE_ID2.test(id))
|
|
12820
13162
|
throw fishError(ctx, "unsupported_option", `${field} is not a voice id`);
|
|
12821
13163
|
return id;
|
|
12822
13164
|
}
|
|
@@ -12826,7 +13168,7 @@ function fishKey(ctx) {
|
|
|
12826
13168
|
return key;
|
|
12827
13169
|
}
|
|
12828
13170
|
function fishUrl(ctx, path) {
|
|
12829
|
-
return `${ctx.endpoints?.fish ??
|
|
13171
|
+
return `${ctx.endpoints?.fish ?? DEFAULT_BASE_URL2}${path}`;
|
|
12830
13172
|
}
|
|
12831
13173
|
async function fishFetch(ctx, path, init) {
|
|
12832
13174
|
throwIfAborted(ctx.signal);
|
|
@@ -12845,7 +13187,7 @@ async function fishFetch(ctx, path, init) {
|
|
|
12845
13187
|
if (!res.ok) throw classifyHttpError(res.status, await readBody(res), "fish", ctx.model.id);
|
|
12846
13188
|
return res;
|
|
12847
13189
|
}
|
|
12848
|
-
function
|
|
13190
|
+
function usage3(ctx) {
|
|
12849
13191
|
return {
|
|
12850
13192
|
model: ctx.model.id,
|
|
12851
13193
|
provider: "fish",
|
|
@@ -12854,18 +13196,18 @@ function usage2(ctx) {
|
|
|
12854
13196
|
quantity: 1
|
|
12855
13197
|
};
|
|
12856
13198
|
}
|
|
12857
|
-
function
|
|
13199
|
+
function audioMime2(res, format) {
|
|
12858
13200
|
const header = res.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase();
|
|
12859
13201
|
if (header?.startsWith("audio/")) return header;
|
|
12860
13202
|
return format === "wav" ? "audio/wav" : "audio/mpeg";
|
|
12861
13203
|
}
|
|
12862
|
-
async function
|
|
12863
|
-
|
|
13204
|
+
async function generateSpeech2(req, ctx) {
|
|
13205
|
+
checkRow2(ctx, "speech");
|
|
12864
13206
|
const format = req.outputFormat ?? "mp3";
|
|
12865
13207
|
const body = { text: req.text, format };
|
|
12866
13208
|
const voice = req.customVoice ?? req.voice;
|
|
12867
13209
|
if (voice !== void 0) {
|
|
12868
|
-
body.reference_id =
|
|
13210
|
+
body.reference_id = checkVoiceId2(ctx, req.customVoice ? "customVoice" : "voice", voice);
|
|
12869
13211
|
}
|
|
12870
13212
|
if (req.language !== void 0) body.language = req.language;
|
|
12871
13213
|
const { bytes, mime } = await withRetry(
|
|
@@ -12881,19 +13223,19 @@ async function generateSpeech(req, ctx) {
|
|
|
12881
13223
|
} catch (cause) {
|
|
12882
13224
|
throw classifyThrown("fish", cause, ctx.model.id);
|
|
12883
13225
|
}
|
|
12884
|
-
return { bytes: audio, mime:
|
|
13226
|
+
return { bytes: audio, mime: audioMime2(res, format) };
|
|
12885
13227
|
},
|
|
12886
13228
|
mediaRetryOptions(ctx.call, ctx.signal)
|
|
12887
13229
|
);
|
|
12888
13230
|
if (bytes.byteLength === 0)
|
|
12889
13231
|
throw fishError(ctx, "provider_rejected", "Fish TTS returned no audio");
|
|
12890
|
-
return { audio: { bytes, mime }, usage:
|
|
13232
|
+
return { audio: { bytes, mime }, usage: usage3(ctx) };
|
|
12891
13233
|
}
|
|
12892
|
-
var createdModelSchema =
|
|
12893
|
-
_id:
|
|
12894
|
-
state:
|
|
13234
|
+
var createdModelSchema = import_zod22.z.object({
|
|
13235
|
+
_id: import_zod22.z.string().min(1),
|
|
13236
|
+
state: import_zod22.z.enum(["created", "training", "trained", "failed"]).optional().catch(void 0)
|
|
12895
13237
|
});
|
|
12896
|
-
function
|
|
13238
|
+
function fileName2(index, mime) {
|
|
12897
13239
|
const ext = mime.split("/")[1]?.replace("mpeg", "mp3").replace("x-", "") || "bin";
|
|
12898
13240
|
return `sample-${index + 1}.${ext}`;
|
|
12899
13241
|
}
|
|
@@ -12905,7 +13247,7 @@ function allOrNone(ctx, field, values) {
|
|
|
12905
13247
|
}
|
|
12906
13248
|
return set;
|
|
12907
13249
|
}
|
|
12908
|
-
async function
|
|
13250
|
+
async function cloneForm2(req, ctx) {
|
|
12909
13251
|
if (req.samples.length === 0) throw fishError(ctx, "missing_input", "needs a voice sample");
|
|
12910
13252
|
const transcripts = allOrNone(
|
|
12911
13253
|
ctx,
|
|
@@ -12931,13 +13273,13 @@ async function cloneForm(req, ctx) {
|
|
|
12931
13273
|
model: ctx.model.id
|
|
12932
13274
|
});
|
|
12933
13275
|
const audio = new Blob([new Uint8Array(bytes)], { type: mime });
|
|
12934
|
-
form.append("voices", audio,
|
|
13276
|
+
form.append("voices", audio, fileName2(index, mime));
|
|
12935
13277
|
}
|
|
12936
13278
|
for (const text2 of transcripts) form.append("texts", text2.trim());
|
|
12937
13279
|
for (const signature of signatures) form.append("voice_design_signatures", signature);
|
|
12938
13280
|
return form;
|
|
12939
13281
|
}
|
|
12940
|
-
async function
|
|
13282
|
+
async function onlyRateLimitRetries2(fn) {
|
|
12941
13283
|
try {
|
|
12942
13284
|
return await fn();
|
|
12943
13285
|
} catch (cause) {
|
|
@@ -12955,11 +13297,11 @@ async function onlyRateLimitRetries(fn) {
|
|
|
12955
13297
|
});
|
|
12956
13298
|
}
|
|
12957
13299
|
}
|
|
12958
|
-
async function
|
|
12959
|
-
|
|
12960
|
-
const form = await
|
|
13300
|
+
async function createVoice2(req, ctx) {
|
|
13301
|
+
checkRow2(ctx, "voice-clone");
|
|
13302
|
+
const form = await cloneForm2(req, ctx);
|
|
12961
13303
|
const res = await withRetry(
|
|
12962
|
-
() =>
|
|
13304
|
+
() => onlyRateLimitRetries2(() => fishFetch(ctx, "/model", { method: "POST", body: form })),
|
|
12963
13305
|
mediaRetryOptions(ctx.call, ctx.signal)
|
|
12964
13306
|
);
|
|
12965
13307
|
const raw = await readBody(res);
|
|
@@ -12975,23 +13317,23 @@ async function createVoice(req, ctx) {
|
|
|
12975
13317
|
retryable: false
|
|
12976
13318
|
});
|
|
12977
13319
|
}
|
|
12978
|
-
const result = { voiceId: parsed.data._id, usage:
|
|
13320
|
+
const result = { voiceId: parsed.data._id, usage: usage3(ctx), raw };
|
|
12979
13321
|
if (parsed.data.state !== void 0) result.state = parsed.data.state;
|
|
12980
13322
|
return result;
|
|
12981
13323
|
}
|
|
12982
|
-
var designSchema =
|
|
12983
|
-
candidates:
|
|
12984
|
-
|
|
12985
|
-
id:
|
|
12986
|
-
index:
|
|
12987
|
-
audio_base64:
|
|
12988
|
-
duration_ms:
|
|
12989
|
-
signature:
|
|
13324
|
+
var designSchema = import_zod22.z.object({
|
|
13325
|
+
candidates: import_zod22.z.array(
|
|
13326
|
+
import_zod22.z.looseObject({
|
|
13327
|
+
id: import_zod22.z.string().min(1),
|
|
13328
|
+
index: import_zod22.z.number().int(),
|
|
13329
|
+
audio_base64: import_zod22.z.string().min(1),
|
|
13330
|
+
duration_ms: import_zod22.z.number().nonnegative(),
|
|
13331
|
+
signature: import_zod22.z.string().min(1).optional()
|
|
12990
13332
|
})
|
|
12991
13333
|
).min(1)
|
|
12992
13334
|
});
|
|
12993
13335
|
async function designVoice(req, ctx) {
|
|
12994
|
-
|
|
13336
|
+
checkRow2(ctx, "voice-design");
|
|
12995
13337
|
const body = { instruction: req.prompt.trim() };
|
|
12996
13338
|
if (req.previewText?.trim()) body.reference_text = req.previewText.trim();
|
|
12997
13339
|
if (req.language !== void 0) body.language = req.language;
|
|
@@ -13019,11 +13361,11 @@ async function designVoice(req, ctx) {
|
|
|
13019
13361
|
// rejects a clone whose signature does not verify, so a wrong one fails loudly.
|
|
13020
13362
|
signature: c.signature ?? c.id
|
|
13021
13363
|
}));
|
|
13022
|
-
return { candidates, usage:
|
|
13364
|
+
return { candidates, usage: usage3(ctx) };
|
|
13023
13365
|
}
|
|
13024
|
-
async function
|
|
13025
|
-
|
|
13026
|
-
const id = encodeURIComponent(
|
|
13366
|
+
async function deleteVoice2(req, ctx) {
|
|
13367
|
+
checkRow2(ctx, "voice-clone");
|
|
13368
|
+
const id = encodeURIComponent(checkVoiceId2(ctx, "voiceId", req.voiceId));
|
|
13027
13369
|
let attempts = 0;
|
|
13028
13370
|
await withRetry(
|
|
13029
13371
|
async () => {
|
|
@@ -13049,18 +13391,18 @@ async function deleteVoice(req, ctx) {
|
|
|
13049
13391
|
}
|
|
13050
13392
|
var fishAdapter = {
|
|
13051
13393
|
id: "fish",
|
|
13052
|
-
generateSpeech,
|
|
13053
|
-
createVoice,
|
|
13394
|
+
generateSpeech: generateSpeech2,
|
|
13395
|
+
createVoice: createVoice2,
|
|
13054
13396
|
designVoice,
|
|
13055
|
-
deleteVoice
|
|
13397
|
+
deleteVoice: deleteVoice2
|
|
13056
13398
|
};
|
|
13057
13399
|
|
|
13058
13400
|
// src/adapters/google-genai.ts
|
|
13059
|
-
var
|
|
13401
|
+
var import_zod24 = require("zod");
|
|
13060
13402
|
var import_genai = require("@google/genai");
|
|
13061
13403
|
|
|
13062
13404
|
// src/adapters/google-files.ts
|
|
13063
|
-
var
|
|
13405
|
+
var import_zod23 = require("zod");
|
|
13064
13406
|
var GOOGLE_FILES_BASE = "https://generativelanguage.googleapis.com";
|
|
13065
13407
|
var GOOGLE_FILES_POLL_INTERVAL_MS = 2e3;
|
|
13066
13408
|
var GOOGLE_FILES_POLL_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
@@ -13070,17 +13412,17 @@ var GENERIC_MEDIA_TYPES = /* @__PURE__ */ new Set([
|
|
|
13070
13412
|
"binary/octet-stream",
|
|
13071
13413
|
"application/binary"
|
|
13072
13414
|
]);
|
|
13073
|
-
var uploadedFileSchema =
|
|
13074
|
-
file:
|
|
13075
|
-
uri:
|
|
13076
|
-
name:
|
|
13077
|
-
state:
|
|
13078
|
-
mimeType:
|
|
13415
|
+
var uploadedFileSchema = import_zod23.z.object({
|
|
13416
|
+
file: import_zod23.z.object({
|
|
13417
|
+
uri: import_zod23.z.string().optional(),
|
|
13418
|
+
name: import_zod23.z.string().optional(),
|
|
13419
|
+
state: import_zod23.z.string().optional(),
|
|
13420
|
+
mimeType: import_zod23.z.string().optional()
|
|
13079
13421
|
}).optional()
|
|
13080
13422
|
});
|
|
13081
|
-
var fileStateSchema =
|
|
13082
|
-
state:
|
|
13083
|
-
error:
|
|
13423
|
+
var fileStateSchema = import_zod23.z.object({
|
|
13424
|
+
state: import_zod23.z.string().optional(),
|
|
13425
|
+
error: import_zod23.z.object({ message: import_zod23.z.string().optional() }).optional()
|
|
13084
13426
|
});
|
|
13085
13427
|
function resolveMime(declared, fallback) {
|
|
13086
13428
|
const clean = declared?.split(";")[0]?.trim().toLowerCase();
|
|
@@ -13187,7 +13529,7 @@ async function startAndUpload(bytes, mimeType, opts) {
|
|
|
13187
13529
|
if (uploaded.file?.state !== void 0) ref.state = uploaded.file.state;
|
|
13188
13530
|
return ref;
|
|
13189
13531
|
}
|
|
13190
|
-
async function waitForActive(
|
|
13532
|
+
async function waitForActive(fileName3, opts) {
|
|
13191
13533
|
const pollOptions2 = {
|
|
13192
13534
|
intervalMs: GOOGLE_FILES_POLL_INTERVAL_MS,
|
|
13193
13535
|
timeoutMs: GOOGLE_FILES_POLL_TIMEOUT_MS
|
|
@@ -13200,14 +13542,14 @@ async function waitForActive(fileName2, opts) {
|
|
|
13200
13542
|
retryInit.signal = opts.signal;
|
|
13201
13543
|
}
|
|
13202
13544
|
await pollUntil(async () => {
|
|
13203
|
-
const res = await opts.fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${
|
|
13545
|
+
const res = await opts.fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName3}`, retryInit);
|
|
13204
13546
|
if (res.ok) {
|
|
13205
13547
|
const json = fileStateSchema.parse(await res.json());
|
|
13206
13548
|
if (json.state === "ACTIVE") return true;
|
|
13207
13549
|
if (json.state === "FAILED") {
|
|
13208
13550
|
throw classifyHttpError(
|
|
13209
13551
|
void 0,
|
|
13210
|
-
`Files API processing failed for ${
|
|
13552
|
+
`Files API processing failed for ${fileName3}: ${json.error?.message ?? "unknown error"}`,
|
|
13211
13553
|
"google-genai",
|
|
13212
13554
|
opts.model
|
|
13213
13555
|
);
|
|
@@ -13219,9 +13561,9 @@ async function waitForActive(fileName2, opts) {
|
|
|
13219
13561
|
throw classifyHttpError(res.status, text2, "google-genai", opts.model);
|
|
13220
13562
|
}, pollOptions2);
|
|
13221
13563
|
}
|
|
13222
|
-
async function deleteGoogleFile(
|
|
13564
|
+
async function deleteGoogleFile(fileName3, apiKey, fetchImpl) {
|
|
13223
13565
|
try {
|
|
13224
|
-
await fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${
|
|
13566
|
+
await fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName3}`, {
|
|
13225
13567
|
method: "DELETE",
|
|
13226
13568
|
headers: { "x-goog-api-key": apiKey }
|
|
13227
13569
|
});
|
|
@@ -13301,7 +13643,7 @@ var OMNI_POLL_INTERVAL_MS = 1e4;
|
|
|
13301
13643
|
var RESULT_TIMEOUT_MS3 = 15 * 60 * 1e3;
|
|
13302
13644
|
var OMNI_INLINE_LIMIT_BYTES = 4 * 1024 * 1024;
|
|
13303
13645
|
var MEDIA_PART_INLINE_LIMIT_BYTES = 10 * 1024 * 1024;
|
|
13304
|
-
var errorTextSchema =
|
|
13646
|
+
var errorTextSchema = import_zod24.z.string();
|
|
13305
13647
|
function isGoogleGenaiVideoKnown(providerModelId) {
|
|
13306
13648
|
return providerModelId.startsWith("veo-") || providerModelId.startsWith("gemini-omni");
|
|
13307
13649
|
}
|
|
@@ -13496,7 +13838,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
|
|
|
13496
13838
|
}
|
|
13497
13839
|
};
|
|
13498
13840
|
const jobId = operation.name ?? crypto.randomUUID();
|
|
13499
|
-
const
|
|
13841
|
+
const usage5 = videoUsage2(ctx, duration, req.resolution ?? "720p");
|
|
13500
13842
|
return {
|
|
13501
13843
|
jobId,
|
|
13502
13844
|
async poll() {
|
|
@@ -13534,7 +13876,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
|
|
|
13534
13876
|
modelId
|
|
13535
13877
|
);
|
|
13536
13878
|
}
|
|
13537
|
-
return { video: await downloadVideo(ctx, uri, apiKey, signal), usage:
|
|
13879
|
+
return { video: await downloadVideo(ctx, uri, apiKey, signal), usage: usage5, raw: finished };
|
|
13538
13880
|
}
|
|
13539
13881
|
};
|
|
13540
13882
|
}
|
|
@@ -13645,7 +13987,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
|
|
|
13645
13987
|
return file.fileUri;
|
|
13646
13988
|
};
|
|
13647
13989
|
const cleanupUploads = async () => {
|
|
13648
|
-
for (const
|
|
13990
|
+
for (const fileName3 of uploadedNames) await deleteGoogleFile(fileName3, apiKey, ctx.fetch);
|
|
13649
13991
|
};
|
|
13650
13992
|
const callCreate = (input) => client2.interactions.create(
|
|
13651
13993
|
previousId !== void 0 ? {
|
|
@@ -13739,7 +14081,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
|
|
|
13739
14081
|
if (!(extend && !chained)) await cleanupUploads();
|
|
13740
14082
|
}
|
|
13741
14083
|
const jobId = interaction.id ?? crypto.randomUUID();
|
|
13742
|
-
const
|
|
14084
|
+
const usage5 = videoUsage2(ctx, duration, omniResolution ?? "720p");
|
|
13743
14085
|
const getInteraction = async () => {
|
|
13744
14086
|
try {
|
|
13745
14087
|
const getParams = { stream: false };
|
|
@@ -13787,7 +14129,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
|
|
|
13787
14129
|
bytes: Buffer.from(video.data, "base64"),
|
|
13788
14130
|
mime: video.mime_type ?? "video/mp4"
|
|
13789
14131
|
},
|
|
13790
|
-
usage:
|
|
14132
|
+
usage: usage5,
|
|
13791
14133
|
raw: done,
|
|
13792
14134
|
providerRef
|
|
13793
14135
|
};
|
|
@@ -13795,7 +14137,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
|
|
|
13795
14137
|
if (video.uri)
|
|
13796
14138
|
return {
|
|
13797
14139
|
video: await downloadVideo(ctx, video.uri, apiKey, signal),
|
|
13798
|
-
usage:
|
|
14140
|
+
usage: usage5,
|
|
13799
14141
|
raw: done,
|
|
13800
14142
|
providerRef
|
|
13801
14143
|
};
|
|
@@ -13965,15 +14307,15 @@ async function prepareGoogleMediaPart(ref, mediaType, ctx) {
|
|
|
13965
14307
|
// src/adapters/google-image.ts
|
|
13966
14308
|
var import_google2 = require("@ai-sdk/google");
|
|
13967
14309
|
var import_ai2 = require("ai");
|
|
13968
|
-
var
|
|
14310
|
+
var import_zod25 = require("zod");
|
|
13969
14311
|
var GEMINI_IMAGE_TIMEOUT_MS = 6e5;
|
|
13970
14312
|
var defaultGoogleImageDeps = {
|
|
13971
14313
|
createGoogleClient: (opts) => (0, import_google2.createGoogleGenerativeAI)(opts),
|
|
13972
14314
|
runTextGeneration: (opts) => (0, import_ai2.generateText)(opts)
|
|
13973
14315
|
};
|
|
13974
|
-
var causeChainNodeSchema =
|
|
13975
|
-
message:
|
|
13976
|
-
cause:
|
|
14316
|
+
var causeChainNodeSchema = import_zod25.z.object({
|
|
14317
|
+
message: import_zod25.z.string().optional(),
|
|
14318
|
+
cause: import_zod25.z.unknown().optional()
|
|
13977
14319
|
});
|
|
13978
14320
|
function extractBlockReason(cause) {
|
|
13979
14321
|
let current = cause;
|
|
@@ -14073,7 +14415,7 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
|
|
|
14073
14415
|
retryable: false
|
|
14074
14416
|
});
|
|
14075
14417
|
}
|
|
14076
|
-
const
|
|
14418
|
+
const usage5 = {
|
|
14077
14419
|
model: ctx.model.id,
|
|
14078
14420
|
provider: "google-image",
|
|
14079
14421
|
modality: "IMAGE",
|
|
@@ -14081,19 +14423,19 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
|
|
|
14081
14423
|
quantity: images.length,
|
|
14082
14424
|
imageQuality: "auto"
|
|
14083
14425
|
};
|
|
14084
|
-
if (req.size !== void 0)
|
|
14426
|
+
if (req.size !== void 0) usage5.imageSize = req.size;
|
|
14085
14427
|
if (result.usage?.inputTokens !== void 0)
|
|
14086
|
-
|
|
14428
|
+
usage5.inputTokens = result.usage.inputTokens;
|
|
14087
14429
|
if (result.usage?.outputTokens !== void 0)
|
|
14088
|
-
|
|
14089
|
-
return { images, usage:
|
|
14430
|
+
usage5.outputTokens = result.usage.outputTokens;
|
|
14431
|
+
return { images, usage: usage5, raw: result };
|
|
14090
14432
|
}
|
|
14091
14433
|
};
|
|
14092
14434
|
}
|
|
14093
14435
|
var googleImageAdapter = createGoogleImageAdapter();
|
|
14094
14436
|
|
|
14095
14437
|
// src/adapters/higgsfield.ts
|
|
14096
|
-
var
|
|
14438
|
+
var import_zod26 = require("zod");
|
|
14097
14439
|
|
|
14098
14440
|
// src/adapters/higgsfield-motions.ts
|
|
14099
14441
|
var MOTION_MAP = {
|
|
@@ -14312,14 +14654,14 @@ function klingEndpointFields(providerModelId) {
|
|
|
14312
14654
|
const path = (providerModelId.startsWith("/") ? providerModelId.slice(1) : providerModelId).toLowerCase();
|
|
14313
14655
|
return KLING_ENDPOINT_FIELDS.get(path) ?? UNLISTED_KLING_FIELDS;
|
|
14314
14656
|
}
|
|
14315
|
-
var klingCreateSchema =
|
|
14316
|
-
var klingStatusSchema =
|
|
14317
|
-
status:
|
|
14318
|
-
video:
|
|
14657
|
+
var klingCreateSchema = import_zod26.z.object({ status_url: import_zod26.z.string() });
|
|
14658
|
+
var klingStatusSchema = import_zod26.z.object({
|
|
14659
|
+
status: import_zod26.z.string().optional(),
|
|
14660
|
+
video: import_zod26.z.object({ url: import_zod26.z.string().optional() }).optional(),
|
|
14319
14661
|
error: JsonValueSchema.optional()
|
|
14320
14662
|
});
|
|
14321
|
-
var errorMessageSchema =
|
|
14322
|
-
var textValueSchema =
|
|
14663
|
+
var errorMessageSchema = import_zod26.z.object({ message: import_zod26.z.string().optional() });
|
|
14664
|
+
var textValueSchema = import_zod26.z.string();
|
|
14323
14665
|
function klingErrorDetail(error) {
|
|
14324
14666
|
if (error === void 0) return "unknown_error";
|
|
14325
14667
|
const asText = textValueSchema.safeParse(error);
|
|
@@ -14475,8 +14817,8 @@ async function generateKlingVideo(req, ctx) {
|
|
|
14475
14817
|
}
|
|
14476
14818
|
};
|
|
14477
14819
|
}
|
|
14478
|
-
var dopMotionOptionsSchema =
|
|
14479
|
-
modelkit:
|
|
14820
|
+
var dopMotionOptionsSchema = import_zod26.z.object({
|
|
14821
|
+
modelkit: import_zod26.z.object({ motion: import_zod26.z.string().optional() }).optional()
|
|
14480
14822
|
});
|
|
14481
14823
|
function dopMotionId(ctx) {
|
|
14482
14824
|
const parsed = dopMotionOptionsSchema.safeParse(ctx.model.providerOptions);
|
|
@@ -14492,7 +14834,7 @@ function dopMotionId(ctx) {
|
|
|
14492
14834
|
});
|
|
14493
14835
|
return id;
|
|
14494
14836
|
}
|
|
14495
|
-
var jsonRecordSchema =
|
|
14837
|
+
var jsonRecordSchema = import_zod26.z.record(import_zod26.z.string(), JsonValueSchema);
|
|
14496
14838
|
var DOP_URL_KEYS = ["url", "video_url", "output_url", "result_url", "download_url"];
|
|
14497
14839
|
var DOP_NESTED_KEYS = ["video", "result", "results"];
|
|
14498
14840
|
function dopUrl(body) {
|
|
@@ -14520,8 +14862,8 @@ function dopUrl(body) {
|
|
|
14520
14862
|
}
|
|
14521
14863
|
return void 0;
|
|
14522
14864
|
}
|
|
14523
|
-
var dopCreateSchema =
|
|
14524
|
-
var dopStatusSchema =
|
|
14865
|
+
var dopCreateSchema = import_zod26.z.object({ id: import_zod26.z.string() });
|
|
14866
|
+
var dopStatusSchema = import_zod26.z.object({ status: import_zod26.z.string().optional() });
|
|
14525
14867
|
async function generateDopVideo(req, ctx) {
|
|
14526
14868
|
const firstFrame = req.firstFrame ? refToUrl(req.firstFrame) : void 0;
|
|
14527
14869
|
if (!firstFrame) {
|
|
@@ -14648,7 +14990,7 @@ var higgsfieldAdapter = {
|
|
|
14648
14990
|
};
|
|
14649
14991
|
|
|
14650
14992
|
// src/adapters/luma.ts
|
|
14651
|
-
var
|
|
14993
|
+
var import_zod27 = require("zod");
|
|
14652
14994
|
|
|
14653
14995
|
// src/adapters/mp4-duration.ts
|
|
14654
14996
|
function mp4DurationSeconds(bytes) {
|
|
@@ -14704,7 +15046,7 @@ function findBox(bytes, from, to, type) {
|
|
|
14704
15046
|
}
|
|
14705
15047
|
|
|
14706
15048
|
// src/adapters/luma.ts
|
|
14707
|
-
var
|
|
15049
|
+
var DEFAULT_BASE_URL3 = "https://agents.lumalabs.ai";
|
|
14708
15050
|
var IMAGE_POLL_INTERVAL_MS = 3e3;
|
|
14709
15051
|
var IMAGE_TIMEOUT_MS = 5 * 6e4;
|
|
14710
15052
|
var VIDEO_POLL_INTERVAL_MS = 5e3;
|
|
@@ -14733,7 +15075,7 @@ function lumaModel(ctx) {
|
|
|
14733
15075
|
return ctx.model.providerModelId.toLowerCase();
|
|
14734
15076
|
}
|
|
14735
15077
|
function lumaBase(ctx) {
|
|
14736
|
-
return ctx.endpoints?.luma ??
|
|
15078
|
+
return ctx.endpoints?.luma ?? DEFAULT_BASE_URL3;
|
|
14737
15079
|
}
|
|
14738
15080
|
function lumaKey(ctx) {
|
|
14739
15081
|
const key = ctx.keys.luma;
|
|
@@ -14865,17 +15207,17 @@ function lumaReframeResolution(req, ctx) {
|
|
|
14865
15207
|
});
|
|
14866
15208
|
return "720p";
|
|
14867
15209
|
}
|
|
14868
|
-
var lumaGenerationSchema =
|
|
14869
|
-
id:
|
|
14870
|
-
state:
|
|
14871
|
-
output:
|
|
14872
|
-
|
|
14873
|
-
type:
|
|
14874
|
-
url:
|
|
15210
|
+
var lumaGenerationSchema = import_zod27.z.looseObject({
|
|
15211
|
+
id: import_zod27.z.string(),
|
|
15212
|
+
state: import_zod27.z.string().optional(),
|
|
15213
|
+
output: import_zod27.z.array(
|
|
15214
|
+
import_zod27.z.looseObject({
|
|
15215
|
+
type: import_zod27.z.string().optional(),
|
|
15216
|
+
url: import_zod27.z.string().optional()
|
|
14875
15217
|
})
|
|
14876
15218
|
).optional(),
|
|
14877
|
-
failure_reason:
|
|
14878
|
-
failure_code:
|
|
15219
|
+
failure_reason: import_zod27.z.string().optional().nullable(),
|
|
15220
|
+
failure_code: import_zod27.z.string().optional().nullable()
|
|
14879
15221
|
});
|
|
14880
15222
|
function lumaFailure(ctx, code, reason) {
|
|
14881
15223
|
const detail = reason ?? code ?? "unknown_error";
|
|
@@ -15307,7 +15649,7 @@ var lumaAdapter = {
|
|
|
15307
15649
|
|
|
15308
15650
|
// src/adapters/openai-image.ts
|
|
15309
15651
|
var import_openai2 = __toESM(require("openai"), 1);
|
|
15310
|
-
var
|
|
15652
|
+
var import_zod28 = require("zod");
|
|
15311
15653
|
var MAX_EDIT_REFERENCES = 16;
|
|
15312
15654
|
function aspectRatioToSize(ratio, tier) {
|
|
15313
15655
|
const TIER_LONG_EDGE = {
|
|
@@ -15390,9 +15732,9 @@ function toProviderError2(cause, ctx) {
|
|
|
15390
15732
|
ctx.model.id
|
|
15391
15733
|
);
|
|
15392
15734
|
}
|
|
15393
|
-
var openaiUsageSchema =
|
|
15394
|
-
input_tokens:
|
|
15395
|
-
output_tokens:
|
|
15735
|
+
var openaiUsageSchema = import_zod28.z.object({
|
|
15736
|
+
input_tokens: import_zod28.z.number().optional(),
|
|
15737
|
+
output_tokens: import_zod28.z.number().optional()
|
|
15396
15738
|
});
|
|
15397
15739
|
var openaiImageAdapter = {
|
|
15398
15740
|
id: "openai-image",
|
|
@@ -15517,7 +15859,7 @@ var openaiImageAdapter = {
|
|
|
15517
15859
|
const usageParsed = openaiUsageSchema.safeParse(response.usage);
|
|
15518
15860
|
const inputTokens = usageParsed.success ? usageParsed.data.input_tokens : void 0;
|
|
15519
15861
|
const outputTokens = usageParsed.success ? usageParsed.data.output_tokens : void 0;
|
|
15520
|
-
const
|
|
15862
|
+
const usage5 = {
|
|
15521
15863
|
model: ctx.model.id,
|
|
15522
15864
|
provider: "openai-image",
|
|
15523
15865
|
modality: "IMAGE",
|
|
@@ -15525,10 +15867,10 @@ var openaiImageAdapter = {
|
|
|
15525
15867
|
quantity: images.length,
|
|
15526
15868
|
imageQuality: quality
|
|
15527
15869
|
};
|
|
15528
|
-
if (inputTokens !== void 0)
|
|
15529
|
-
if (outputTokens !== void 0)
|
|
15530
|
-
if (req.size !== void 0)
|
|
15531
|
-
return { images, usage:
|
|
15870
|
+
if (inputTokens !== void 0) usage5.inputTokens = inputTokens;
|
|
15871
|
+
if (outputTokens !== void 0) usage5.outputTokens = outputTokens;
|
|
15872
|
+
if (req.size !== void 0) usage5.imageSize = req.size;
|
|
15873
|
+
return { images, usage: usage5, raw: response };
|
|
15532
15874
|
}
|
|
15533
15875
|
};
|
|
15534
15876
|
|
|
@@ -15784,16 +16126,16 @@ async function generateProdiaImage(req, ctx) {
|
|
|
15784
16126
|
new Uint8Array(await res.arrayBuffer()),
|
|
15785
16127
|
res.headers.get("content-type")
|
|
15786
16128
|
);
|
|
15787
|
-
const
|
|
16129
|
+
const usage5 = {
|
|
15788
16130
|
model: ctx.model.id,
|
|
15789
16131
|
provider: "prodia",
|
|
15790
16132
|
modality: "IMAGE",
|
|
15791
16133
|
unit: "images",
|
|
15792
16134
|
quantity: 1
|
|
15793
16135
|
};
|
|
15794
|
-
if (req.size !== void 0)
|
|
15795
|
-
if (req.quality !== void 0)
|
|
15796
|
-
return { images: [{ bytes, mime }], usage:
|
|
16136
|
+
if (req.size !== void 0) usage5.imageSize = req.size;
|
|
16137
|
+
if (req.quality !== void 0) usage5.imageQuality = req.quality;
|
|
16138
|
+
return { images: [{ bytes, mime }], usage: usage5, raw: void 0 };
|
|
15797
16139
|
}
|
|
15798
16140
|
var prodiaAdapter = {
|
|
15799
16141
|
id: "prodia",
|
|
@@ -15804,13 +16146,13 @@ var prodiaAdapter = {
|
|
|
15804
16146
|
var import_replicate = __toESM(require("replicate"), 1);
|
|
15805
16147
|
|
|
15806
16148
|
// src/adapters/replicate-http.ts
|
|
15807
|
-
var
|
|
15808
|
-
var predictionSchema =
|
|
15809
|
-
id:
|
|
15810
|
-
status:
|
|
16149
|
+
var import_zod29 = require("zod");
|
|
16150
|
+
var predictionSchema = import_zod29.z.object({
|
|
16151
|
+
id: import_zod29.z.string(),
|
|
16152
|
+
status: import_zod29.z.string(),
|
|
15811
16153
|
output: JsonValueSchema.optional(),
|
|
15812
16154
|
error: JsonValueSchema.optional(),
|
|
15813
|
-
metrics:
|
|
16155
|
+
metrics: import_zod29.z.object({ predict_time: import_zod29.z.number().optional() }).optional()
|
|
15814
16156
|
});
|
|
15815
16157
|
function createReplicateHttpClient(opts) {
|
|
15816
16158
|
async function request(path, body, signal) {
|
|
@@ -15861,7 +16203,7 @@ function createReplicateHttpClient(opts) {
|
|
|
15861
16203
|
}
|
|
15862
16204
|
|
|
15863
16205
|
// src/adapters/replicate.ts
|
|
15864
|
-
var
|
|
16206
|
+
var import_zod30 = require("zod");
|
|
15865
16207
|
var POLL_INTERVAL_MS = 1e3;
|
|
15866
16208
|
var POLL_TIMEOUT_MS = 15 * 6e4;
|
|
15867
16209
|
var defaultReplicateDeps = {
|
|
@@ -15901,8 +16243,8 @@ function route(providerModelId) {
|
|
|
15901
16243
|
if (!providerModelId.includes("/")) return { version: providerModelId };
|
|
15902
16244
|
return { model: providerModelId };
|
|
15903
16245
|
}
|
|
15904
|
-
var replicateResponseStatusSchema =
|
|
15905
|
-
response:
|
|
16246
|
+
var replicateResponseStatusSchema = import_zod30.z.object({
|
|
16247
|
+
response: import_zod30.z.object({ status: import_zod30.z.number() }).partial()
|
|
15906
16248
|
});
|
|
15907
16249
|
function replicateError(cause, ctx) {
|
|
15908
16250
|
if (isModelKitError(cause)) return cause;
|
|
@@ -15925,7 +16267,7 @@ function isUrlFn(value) {
|
|
|
15925
16267
|
function extractOutputUrl(output) {
|
|
15926
16268
|
const root = Array.isArray(output) ? output[0] : output;
|
|
15927
16269
|
if (root === void 0) throw noOutput();
|
|
15928
|
-
const asString =
|
|
16270
|
+
const asString = import_zod30.z.string().safeParse(root);
|
|
15929
16271
|
if (asString.success && asString.data) return asString.data;
|
|
15930
16272
|
if (root instanceof URL) return root.href;
|
|
15931
16273
|
if (isObjectOutput(root)) {
|
|
@@ -15934,15 +16276,15 @@ function extractOutputUrl(output) {
|
|
|
15934
16276
|
if (urlValue !== void 0 && isUrlFn(urlValue)) {
|
|
15935
16277
|
const called = urlValue();
|
|
15936
16278
|
if (called instanceof URL) return called.href;
|
|
15937
|
-
const calledString =
|
|
16279
|
+
const calledString = import_zod30.z.string().safeParse(called);
|
|
15938
16280
|
if (calledString.success && calledString.data) return calledString.data;
|
|
15939
16281
|
} else {
|
|
15940
|
-
const direct =
|
|
16282
|
+
const direct = import_zod30.z.string().safeParse(urlValue);
|
|
15941
16283
|
if (direct.success && direct.data) return direct.data;
|
|
15942
16284
|
}
|
|
15943
16285
|
}
|
|
15944
16286
|
if ("default" in root) {
|
|
15945
|
-
const fallback =
|
|
16287
|
+
const fallback = import_zod30.z.string().safeParse(root.default);
|
|
15946
16288
|
if (fallback.success && fallback.data) return fallback.data;
|
|
15947
16289
|
}
|
|
15948
16290
|
}
|
|
@@ -16003,7 +16345,7 @@ async function runPrediction(ctx, input, deps) {
|
|
|
16003
16345
|
}
|
|
16004
16346
|
return void 0;
|
|
16005
16347
|
}, pollOpts);
|
|
16006
|
-
const predictTime =
|
|
16348
|
+
const predictTime = import_zod30.z.number().safeParse(done.metrics?.predict_time);
|
|
16007
16349
|
if (done.output === void 0) throw noOutput();
|
|
16008
16350
|
return {
|
|
16009
16351
|
url: extractOutputUrl(done.output),
|
|
@@ -16249,9 +16591,9 @@ async function generateReplicateImage(req, ctx, deps) {
|
|
|
16249
16591
|
}
|
|
16250
16592
|
const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
|
|
16251
16593
|
const file = await download(ctx, url);
|
|
16252
|
-
const
|
|
16253
|
-
|
|
16254
|
-
return { images: [{ bytes: file.bytes, mime: file.mime }], usage:
|
|
16594
|
+
const usage5 = imageUsage3(ctx, req);
|
|
16595
|
+
usage5.quantity = predictTime;
|
|
16596
|
+
return { images: [{ bytes: file.bytes, mime: file.mime }], usage: usage5, raw, outputUrl: url };
|
|
16255
16597
|
}
|
|
16256
16598
|
function klingInput(req) {
|
|
16257
16599
|
const images = (req.firstFrame ? [req.firstFrame] : []).map(refToUrl);
|
|
@@ -16356,7 +16698,7 @@ async function generateReplicateVideo(req, ctx, deps) {
|
|
|
16356
16698
|
throw replicateError(cause, ctx);
|
|
16357
16699
|
}
|
|
16358
16700
|
if (current.status === "succeeded") {
|
|
16359
|
-
const predictTime =
|
|
16701
|
+
const predictTime = import_zod30.z.number().safeParse(current.metrics?.predict_time);
|
|
16360
16702
|
if (current.output === void 0) throw noOutput();
|
|
16361
16703
|
return {
|
|
16362
16704
|
url: extractOutputUrl(current.output),
|
|
@@ -16375,9 +16717,9 @@ async function generateReplicateVideo(req, ctx, deps) {
|
|
|
16375
16717
|
return void 0;
|
|
16376
16718
|
};
|
|
16377
16719
|
const toResult = (done) => {
|
|
16378
|
-
const
|
|
16379
|
-
|
|
16380
|
-
return { video: { url: done.url }, usage:
|
|
16720
|
+
const usage5 = videoUsage5(ctx, req);
|
|
16721
|
+
usage5.quantity = done.predictTime;
|
|
16722
|
+
return { video: { url: done.url }, usage: usage5, raw: done.raw };
|
|
16381
16723
|
};
|
|
16382
16724
|
return {
|
|
16383
16725
|
jobId,
|
|
@@ -16484,21 +16826,21 @@ async function generateReplicateAudio(req, ctx, deps) {
|
|
|
16484
16826
|
input = specResult.input;
|
|
16485
16827
|
}
|
|
16486
16828
|
const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
|
|
16487
|
-
const
|
|
16829
|
+
const usage5 = audioUsage(ctx, req);
|
|
16488
16830
|
if (ctx.model.usage.unit === "seconds") {
|
|
16489
16831
|
const seconds3 = elevenLabsMusicDuration(req.durationSeconds);
|
|
16490
|
-
|
|
16491
|
-
|
|
16832
|
+
usage5.quantity = seconds3;
|
|
16833
|
+
usage5.durationSeconds = seconds3;
|
|
16492
16834
|
} else {
|
|
16493
|
-
|
|
16835
|
+
usage5.quantity = predictTime;
|
|
16494
16836
|
}
|
|
16495
|
-
return { audio: { url }, usage:
|
|
16837
|
+
return { audio: { url }, usage: usage5, raw: predictionRaw(raw) };
|
|
16496
16838
|
}
|
|
16497
16839
|
|
|
16498
16840
|
// src/adapters/xai-video.ts
|
|
16499
16841
|
var import_ai3 = require("ai");
|
|
16500
16842
|
var import_xai2 = require("@ai-sdk/xai");
|
|
16501
|
-
var
|
|
16843
|
+
var import_zod31 = require("zod");
|
|
16502
16844
|
var POLL_INTERVAL_MS2 = 1e4;
|
|
16503
16845
|
var POLL_TIMEOUT_MS2 = 15 * 6e4;
|
|
16504
16846
|
var defaultXaiDeps = {
|
|
@@ -16511,8 +16853,8 @@ function createXaiVideoAdapter(deps = defaultXaiDeps) {
|
|
|
16511
16853
|
};
|
|
16512
16854
|
}
|
|
16513
16855
|
var xaiVideoAdapter = createXaiVideoAdapter();
|
|
16514
|
-
var xaiResponseStatusSchema =
|
|
16515
|
-
response:
|
|
16856
|
+
var xaiResponseStatusSchema = import_zod31.z.object({
|
|
16857
|
+
response: import_zod31.z.object({ status: import_zod31.z.number() }).partial()
|
|
16516
16858
|
});
|
|
16517
16859
|
function xaiError(cause, ctx) {
|
|
16518
16860
|
const info = describeThrown(cause);
|
|
@@ -16520,12 +16862,12 @@ function xaiError(cause, ctx) {
|
|
|
16520
16862
|
const status = info.status ?? (nested.success ? nested.data.response?.status : void 0);
|
|
16521
16863
|
return classifyThrown("xai-video", cause, ctx.model.id, { status, body: info.body });
|
|
16522
16864
|
}
|
|
16523
|
-
var xaiMetaSchema =
|
|
16865
|
+
var xaiMetaSchema = import_zod31.z.object({
|
|
16524
16866
|
videoUrl: JsonValueSchema.optional(),
|
|
16525
16867
|
costInUsdTicks: JsonValueSchema.optional(),
|
|
16526
16868
|
duration: JsonValueSchema.optional()
|
|
16527
16869
|
});
|
|
16528
|
-
var xaiProviderMetadataSchema =
|
|
16870
|
+
var xaiProviderMetadataSchema = import_zod31.z.object({ xai: xaiMetaSchema });
|
|
16529
16871
|
function metaOf(result) {
|
|
16530
16872
|
const parsed = xaiProviderMetadataSchema.partial().safeParse(result.providerMetadata);
|
|
16531
16873
|
if (!parsed.success) return {};
|
|
@@ -16637,12 +16979,12 @@ async function mapResult(ctx, req, result) {
|
|
|
16637
16979
|
if (first) {
|
|
16638
16980
|
return {
|
|
16639
16981
|
video: { bytes: Uint8Array.from(first.uint8Array), mime: first.mediaType },
|
|
16640
|
-
usage:
|
|
16982
|
+
usage: usage4(ctx, req, metaOf(result)),
|
|
16641
16983
|
raw: result.providerMetadata
|
|
16642
16984
|
};
|
|
16643
16985
|
}
|
|
16644
16986
|
const meta = metaOf(result);
|
|
16645
|
-
const videoUrl =
|
|
16987
|
+
const videoUrl = import_zod31.z.string().safeParse(meta.videoUrl);
|
|
16646
16988
|
if (videoUrl.success && videoUrl.data) {
|
|
16647
16989
|
const res = await ctx.fetch(videoUrl.data);
|
|
16648
16990
|
if (!res.ok) {
|
|
@@ -16652,7 +16994,7 @@ async function mapResult(ctx, req, result) {
|
|
|
16652
16994
|
const mime = res.headers.get("content-type") ?? "video/mp4";
|
|
16653
16995
|
return {
|
|
16654
16996
|
video: { bytes: new Uint8Array(await res.arrayBuffer()), mime },
|
|
16655
|
-
usage:
|
|
16997
|
+
usage: usage4(ctx, req, meta),
|
|
16656
16998
|
raw: result.providerMetadata
|
|
16657
16999
|
};
|
|
16658
17000
|
}
|
|
@@ -16664,8 +17006,8 @@ async function mapResult(ctx, req, result) {
|
|
|
16664
17006
|
retryable: false
|
|
16665
17007
|
});
|
|
16666
17008
|
}
|
|
16667
|
-
function
|
|
16668
|
-
const costTicks =
|
|
17009
|
+
function usage4(ctx, req, meta) {
|
|
17010
|
+
const costTicks = import_zod31.z.number().safeParse(meta.costInUsdTicks);
|
|
16669
17011
|
const cost = costTicks.success ? costTicks.data / 1e10 : void 0;
|
|
16670
17012
|
const event = {
|
|
16671
17013
|
model: ctx.model.id,
|
|
@@ -16705,7 +17047,8 @@ var DEFAULT_ADAPTERS = {
|
|
|
16705
17047
|
higgsfield: higgsfieldAdapter,
|
|
16706
17048
|
"xai-video": xaiVideoAdapter,
|
|
16707
17049
|
luma: lumaAdapter,
|
|
16708
|
-
fish: fishAdapter
|
|
17050
|
+
fish: fishAdapter,
|
|
17051
|
+
elevenlabs: elevenLabsAdapter
|
|
16709
17052
|
};
|
|
16710
17053
|
|
|
16711
17054
|
// src/catalog/data-only.ts
|
|
@@ -16744,15 +17087,15 @@ var FAL_NODE_TYPES = /* @__PURE__ */ new Set([
|
|
|
16744
17087
|
"transcription",
|
|
16745
17088
|
"mask"
|
|
16746
17089
|
]);
|
|
16747
|
-
function
|
|
16748
|
-
return row2.adapter === "fish" && row2.type === "speech";
|
|
17090
|
+
function directSpeech(row2) {
|
|
17091
|
+
return (row2.adapter === "fish" || row2.adapter === "elevenlabs") && row2.type === "speech";
|
|
16749
17092
|
}
|
|
16750
17093
|
function dataOnlyCapable(row2) {
|
|
16751
17094
|
const adapter = DEFAULT_ADAPTERS[row2.adapter];
|
|
16752
17095
|
if (!adapterServesType(adapter, row2.type)) {
|
|
16753
17096
|
return { ok: false, reason: `${row2.adapter} cannot serve ${row2.type} rows` };
|
|
16754
17097
|
}
|
|
16755
|
-
if (FAL_NODE_TYPES.has(row2.type) && row2.adapter !== "fal" && !
|
|
17098
|
+
if (FAL_NODE_TYPES.has(row2.type) && row2.adapter !== "fal" && !directSpeech(row2)) {
|
|
16756
17099
|
return { ok: false, reason: `only fal serves ${row2.type} rows` };
|
|
16757
17100
|
}
|
|
16758
17101
|
switch (row2.adapter) {
|
|
@@ -16834,6 +17177,10 @@ function dataOnlyCapable(row2) {
|
|
|
16834
17177
|
const reason = fishRowRefusal(row2);
|
|
16835
17178
|
return reason === void 0 ? { ok: true } : { ok: false, reason };
|
|
16836
17179
|
}
|
|
17180
|
+
case "elevenlabs": {
|
|
17181
|
+
const reason = elevenLabsRowRefusal(row2);
|
|
17182
|
+
return reason === void 0 ? { ok: true } : { ok: false, reason };
|
|
17183
|
+
}
|
|
16837
17184
|
default: {
|
|
16838
17185
|
return assertNever(row2.adapter);
|
|
16839
17186
|
}
|
|
@@ -16853,22 +17200,22 @@ var liveState = store[KEY] ??= {
|
|
|
16853
17200
|
var liveCatalog = liveState.catalog;
|
|
16854
17201
|
|
|
16855
17202
|
// src/catalog/load.ts
|
|
16856
|
-
var
|
|
17203
|
+
var import_zod32 = require("zod");
|
|
16857
17204
|
function rowCount() {
|
|
16858
17205
|
return liveCatalog.list({ lifecycle: ["active", "deprecated", "retired"] }).length;
|
|
16859
17206
|
}
|
|
16860
17207
|
function authHeaders(auth) {
|
|
16861
17208
|
return "bearer" in auth ? { Authorization: `Bearer ${auth.bearer}` } : { "x-api-key": auth.apiKey };
|
|
16862
17209
|
}
|
|
16863
|
-
var EnvelopeSchema =
|
|
16864
|
-
rows:
|
|
16865
|
-
revision:
|
|
17210
|
+
var EnvelopeSchema = import_zod32.z.object({
|
|
17211
|
+
rows: import_zod32.z.array(JsonValueSchema),
|
|
17212
|
+
revision: import_zod32.z.string().optional()
|
|
16866
17213
|
});
|
|
16867
17214
|
function dropReason(path, message) {
|
|
16868
17215
|
return path.length === 0 ? message : `${path.map((part) => String(part)).join(".")} ${message}`;
|
|
16869
17216
|
}
|
|
16870
17217
|
function rowId(raw) {
|
|
16871
|
-
const parsed =
|
|
17218
|
+
const parsed = import_zod32.z.object({ id: import_zod32.z.string().min(1) }).loose().safeParse(raw);
|
|
16872
17219
|
if (!parsed.success) return "?";
|
|
16873
17220
|
return parsed.data.id;
|
|
16874
17221
|
}
|
|
@@ -18029,7 +18376,8 @@ var ADAPTER_KEYS = {
|
|
|
18029
18376
|
higgsfield: ["higgsfield"],
|
|
18030
18377
|
"xai-video": ["xai"],
|
|
18031
18378
|
luma: ["luma"],
|
|
18032
|
-
fish: ["fish"]
|
|
18379
|
+
fish: ["fish"],
|
|
18380
|
+
elevenlabs: ["elevenlabs"]
|
|
18033
18381
|
};
|
|
18034
18382
|
function hasAll(keys, names) {
|
|
18035
18383
|
if (!keys) return false;
|
|
@@ -18089,6 +18437,7 @@ function keysFromEnv(env, prefix = "") {
|
|
|
18089
18437
|
set("higgsfieldSecret", pick2("HIGGSFIELD_API_SECRET"));
|
|
18090
18438
|
set("luma", pick2("LUMA_API_KEY", "LUMA_AGENTS_API_KEY"));
|
|
18091
18439
|
set("fish", pick2("FISH_AUDIO_API_KEY"));
|
|
18440
|
+
set("elevenlabs", pick2("ELEVENLABS_API_KEY"));
|
|
18092
18441
|
set("cloudflare", pick2("CLOUDFLARE_AI_GATEWAY_TOKEN", "CF_AIG_TOKEN"));
|
|
18093
18442
|
const bearer = pick2("AWS_BEARER_TOKEN_BEDROCK");
|
|
18094
18443
|
const accessKeyId = pick2("AWS_ACCESS_KEY_ID");
|
|
@@ -18111,7 +18460,7 @@ function keysFromEnv(env, prefix = "") {
|
|
|
18111
18460
|
|
|
18112
18461
|
// src/text.ts
|
|
18113
18462
|
var import_ai4 = require("ai");
|
|
18114
|
-
var
|
|
18463
|
+
var import_zod33 = require("zod");
|
|
18115
18464
|
function mergeTextProviderOptions(catalog, caller) {
|
|
18116
18465
|
const merged = {};
|
|
18117
18466
|
const catalogOptions = catalog.providerOptions ?? {};
|
|
@@ -18150,17 +18499,17 @@ function passthroughTextModel(model) {
|
|
|
18150
18499
|
pricingKind: "token"
|
|
18151
18500
|
};
|
|
18152
18501
|
}
|
|
18153
|
-
var perplexityCostSchema =
|
|
18154
|
-
perplexity:
|
|
18502
|
+
var perplexityCostSchema = import_zod33.z.object({
|
|
18503
|
+
perplexity: import_zod33.z.object({ cost: import_zod33.z.object({ totalCost: import_zod33.z.number().finite().nonnegative() }) })
|
|
18155
18504
|
});
|
|
18156
18505
|
function reportedCostUsd(metadata) {
|
|
18157
18506
|
const parsed = perplexityCostSchema.safeParse(metadata);
|
|
18158
18507
|
return parsed.success ? parsed.data.perplexity.cost.totalCost : void 0;
|
|
18159
18508
|
}
|
|
18160
|
-
function textUsageEvent(model, provider,
|
|
18161
|
-
const inputTokens =
|
|
18162
|
-
const outputTokens =
|
|
18163
|
-
const total =
|
|
18509
|
+
function textUsageEvent(model, provider, usage5, providerMetadata) {
|
|
18510
|
+
const inputTokens = usage5.inputTokens ?? 0;
|
|
18511
|
+
const outputTokens = usage5.outputTokens ?? 0;
|
|
18512
|
+
const total = usage5.totalTokens ?? inputTokens + outputTokens;
|
|
18164
18513
|
const event = {
|
|
18165
18514
|
model: model.id,
|
|
18166
18515
|
provider,
|
|
@@ -18195,7 +18544,7 @@ function createTextSteps(initial, resolve, callerProviderOptions) {
|
|
|
18195
18544
|
return { ...prepared, providerOptions };
|
|
18196
18545
|
};
|
|
18197
18546
|
}
|
|
18198
|
-
function
|
|
18547
|
+
function usage5(results) {
|
|
18199
18548
|
const grouped = /* @__PURE__ */ new Map();
|
|
18200
18549
|
for (const [index, step] of results.entries()) {
|
|
18201
18550
|
const target = steps.get(index) ?? initial;
|
|
@@ -18219,12 +18568,12 @@ function createTextSteps(initial, resolve, callerProviderOptions) {
|
|
|
18219
18568
|
}
|
|
18220
18569
|
return [...grouped.values()];
|
|
18221
18570
|
}
|
|
18222
|
-
return { wrap, usage:
|
|
18571
|
+
return { wrap, usage: usage5 };
|
|
18223
18572
|
}
|
|
18224
18573
|
|
|
18225
18574
|
// src/client.ts
|
|
18226
18575
|
var import_ai5 = require("ai");
|
|
18227
|
-
var
|
|
18576
|
+
var import_zod34 = require("zod");
|
|
18228
18577
|
|
|
18229
18578
|
// src/generated-image.ts
|
|
18230
18579
|
function toGeneratedImage(image) {
|
|
@@ -18346,9 +18695,9 @@ function providerJobMethods(kind, deps) {
|
|
|
18346
18695
|
if (!methods.result) throw missing3(adapter, ctx.model);
|
|
18347
18696
|
const result = await methods.result(sub, ctx, webhook);
|
|
18348
18697
|
const base = { ...result.usage, model: ctx.model.id, unit: ctx.model.usage.unit };
|
|
18349
|
-
const
|
|
18350
|
-
await deps.emit(
|
|
18351
|
-
return { ...result, usage:
|
|
18698
|
+
const usage5 = sub.submittedAt === void 0 ? base : deps.timed(base, sub.submittedAt);
|
|
18699
|
+
await deps.emit(usage5);
|
|
18700
|
+
return { ...result, usage: usage5 };
|
|
18352
18701
|
},
|
|
18353
18702
|
async cancel(sub, call = {}) {
|
|
18354
18703
|
const { methods, adapter, ctx } = target(sub.model, call);
|
|
@@ -18588,10 +18937,10 @@ function audioNodeMethods(deps) {
|
|
|
18588
18937
|
const startedAt = Date.now();
|
|
18589
18938
|
const outcome = await adapter.dub(resolved, ctx);
|
|
18590
18939
|
if (outcome.kind === "audio") {
|
|
18591
|
-
const { audio, usage:
|
|
18940
|
+
const { audio, usage: usage5, raw } = outcome.result;
|
|
18592
18941
|
return {
|
|
18593
18942
|
audio,
|
|
18594
|
-
usage: await deps.settle(model,
|
|
18943
|
+
usage: await deps.settle(model, usage5, startedAt),
|
|
18595
18944
|
...raw !== void 0 && { raw }
|
|
18596
18945
|
};
|
|
18597
18946
|
}
|
|
@@ -18629,10 +18978,10 @@ function textAbortOptions(sdk, context) {
|
|
|
18629
18978
|
if (abortSignal) return { abortSignal };
|
|
18630
18979
|
return {};
|
|
18631
18980
|
}
|
|
18632
|
-
var catalogId =
|
|
18633
|
-
var exactSize =
|
|
18634
|
-
var sdkRatio =
|
|
18635
|
-
var sizeTier =
|
|
18981
|
+
var catalogId = import_zod34.z.string();
|
|
18982
|
+
var exactSize = import_zod34.z.templateLiteral([import_zod34.z.number(), "x", import_zod34.z.number()]);
|
|
18983
|
+
var sdkRatio = import_zod34.z.templateLiteral([import_zod34.z.number(), ":", import_zod34.z.number()]);
|
|
18984
|
+
var sizeTier = import_zod34.z.enum(["512", "1K", "2K", "4K"]);
|
|
18636
18985
|
function isCatalogId(model) {
|
|
18637
18986
|
return catalogId.safeParse(model).success;
|
|
18638
18987
|
}
|
|
@@ -18845,7 +19194,7 @@ function createModelKit(config, adapters) {
|
|
|
18845
19194
|
const images = result.images.map(
|
|
18846
19195
|
(file) => toGeneratedImage({ bytes: file.uint8Array, mime: file.mediaType })
|
|
18847
19196
|
);
|
|
18848
|
-
const
|
|
19197
|
+
const usage5 = timed(
|
|
18849
19198
|
{
|
|
18850
19199
|
model: model.modelId,
|
|
18851
19200
|
provider: model.provider,
|
|
@@ -18855,8 +19204,8 @@ function createModelKit(config, adapters) {
|
|
|
18855
19204
|
},
|
|
18856
19205
|
startedAt
|
|
18857
19206
|
);
|
|
18858
|
-
await emit(
|
|
18859
|
-
return { image: images[0], images, usage:
|
|
19207
|
+
await emit(usage5);
|
|
19208
|
+
return { image: images[0], images, usage: usage5, raw: result, warnings };
|
|
18860
19209
|
}
|
|
18861
19210
|
function passthroughVideo(req, call) {
|
|
18862
19211
|
const {
|
|
@@ -18932,7 +19281,7 @@ function createModelKit(config, adapters) {
|
|
|
18932
19281
|
let settled;
|
|
18933
19282
|
let failed = false;
|
|
18934
19283
|
const done = pending.then(async (result) => {
|
|
18935
|
-
const
|
|
19284
|
+
const usage5 = timed(
|
|
18936
19285
|
{
|
|
18937
19286
|
model: model.modelId,
|
|
18938
19287
|
provider: model.provider,
|
|
@@ -18945,10 +19294,10 @@ function createModelKit(config, adapters) {
|
|
|
18945
19294
|
);
|
|
18946
19295
|
settled = {
|
|
18947
19296
|
video: { bytes: result.video.uint8Array, mime: result.video.mediaType },
|
|
18948
|
-
usage:
|
|
19297
|
+
usage: usage5,
|
|
18949
19298
|
raw: result
|
|
18950
19299
|
};
|
|
18951
|
-
await emit(
|
|
19300
|
+
await emit(usage5);
|
|
18952
19301
|
return settled;
|
|
18953
19302
|
});
|
|
18954
19303
|
done.catch(() => {
|
|
@@ -18975,12 +19324,12 @@ function createModelKit(config, adapters) {
|
|
|
18975
19324
|
if (settled) return settled;
|
|
18976
19325
|
const pending = result(opts).then(
|
|
18977
19326
|
async (out) => {
|
|
18978
|
-
const
|
|
19327
|
+
const usage5 = timed(
|
|
18979
19328
|
{ ...out.usage, model: model.id, unit: model.usage.unit },
|
|
18980
19329
|
startedAt
|
|
18981
19330
|
);
|
|
18982
|
-
await emit(
|
|
18983
|
-
return { ...out, usage:
|
|
19331
|
+
await emit(usage5);
|
|
19332
|
+
return { ...out, usage: usage5 };
|
|
18984
19333
|
},
|
|
18985
19334
|
(cause) => {
|
|
18986
19335
|
settled = void 0;
|
|
@@ -19000,9 +19349,9 @@ function createModelKit(config, adapters) {
|
|
|
19000
19349
|
return context(model, signal ? { ...call, signal } : call, warnings);
|
|
19001
19350
|
},
|
|
19002
19351
|
async settle(model, event, startedAt) {
|
|
19003
|
-
const
|
|
19004
|
-
await emit(
|
|
19005
|
-
return
|
|
19352
|
+
const usage5 = timed({ ...event, model: model.id, unit: model.usage.unit }, startedAt);
|
|
19353
|
+
await emit(usage5);
|
|
19354
|
+
return usage5;
|
|
19006
19355
|
},
|
|
19007
19356
|
wrapVideoJob
|
|
19008
19357
|
});
|
|
@@ -19038,11 +19387,11 @@ function createModelKit(config, adapters) {
|
|
|
19038
19387
|
});
|
|
19039
19388
|
const startedAt = Date.now();
|
|
19040
19389
|
const result = await adapter.generateImage(request, ctx);
|
|
19041
|
-
const
|
|
19390
|
+
const usage5 = timed(
|
|
19042
19391
|
{ ...result.usage, model: model.id, unit: model.usage.unit },
|
|
19043
19392
|
startedAt
|
|
19044
19393
|
);
|
|
19045
|
-
await emit(
|
|
19394
|
+
await emit(usage5);
|
|
19046
19395
|
const images = result.images.map(toGeneratedImage);
|
|
19047
19396
|
const first = images[0];
|
|
19048
19397
|
if (!first)
|
|
@@ -19051,7 +19400,7 @@ function createModelKit(config, adapters) {
|
|
|
19051
19400
|
message: `${model.id} returned no image`,
|
|
19052
19401
|
model: model.id
|
|
19053
19402
|
});
|
|
19054
|
-
return { ...result, usage:
|
|
19403
|
+
return { ...result, usage: usage5, image: first, images, warnings };
|
|
19055
19404
|
},
|
|
19056
19405
|
async generateVideo(req, call = {}) {
|
|
19057
19406
|
mediaRetryOptions(call);
|
|
@@ -19150,12 +19499,12 @@ function createModelKit(config, adapters) {
|
|
|
19150
19499
|
}
|
|
19151
19500
|
const startedAt = Date.now();
|
|
19152
19501
|
const result = await adapter.generateAudio(resolved, ctx);
|
|
19153
|
-
const
|
|
19502
|
+
const usage5 = timed(
|
|
19154
19503
|
{ ...result.usage, model: model.id, unit: model.usage.unit },
|
|
19155
19504
|
startedAt
|
|
19156
19505
|
);
|
|
19157
|
-
await emit(
|
|
19158
|
-
return { ...result, usage:
|
|
19506
|
+
await emit(usage5);
|
|
19507
|
+
return { ...result, usage: usage5 };
|
|
19159
19508
|
},
|
|
19160
19509
|
async prepareMediaPart(modelId, ref, mediaType, call = {}) {
|
|
19161
19510
|
mediaRetryOptions(call);
|
|
@@ -19235,8 +19584,8 @@ function createModelKit(config, adapters) {
|
|
|
19235
19584
|
options.prepareStep ?? options.experimental_prepareStep
|
|
19236
19585
|
),
|
|
19237
19586
|
onFinish: async (event) => {
|
|
19238
|
-
for (const
|
|
19239
|
-
await emit(textTimed(withRowUnit(
|
|
19587
|
+
for (const usage5 of steps.usage(event.steps))
|
|
19588
|
+
await emit(textTimed(withRowUnit(usage5), event.steps.length, startedAt));
|
|
19240
19589
|
await callerOnFinish?.(event);
|
|
19241
19590
|
}
|
|
19242
19591
|
});
|
|
@@ -19355,6 +19704,7 @@ var describe = (modelId) => createDefaultModelKit().describe(modelId);
|
|
|
19355
19704
|
dataOnlyCapable,
|
|
19356
19705
|
describe,
|
|
19357
19706
|
describeThrown,
|
|
19707
|
+
elevenLabsAdapter,
|
|
19358
19708
|
experimental_generateImage,
|
|
19359
19709
|
falAdapter,
|
|
19360
19710
|
falWebhookBodySchema,
|