@shop-os/modelkit 0.8.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 +35 -0
- package/README.md +8 -1
- package/dist/catalog.cjs +526 -21
- package/dist/catalog.cjs.map +1 -1
- package/dist/catalog.d.cts +113 -5
- package/dist/catalog.d.ts +113 -5
- package/dist/catalog.js +526 -21
- package/dist/catalog.js.map +1 -1
- package/dist/index.cjs +1312 -190
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +115 -4
- package/dist/index.d.ts +115 -4
- package/dist/index.js +1308 -190
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1731,6 +1731,369 @@ var ELEVENLABS_VOICES = [
|
|
|
1731
1731
|
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/pqHfZKP75CvOlQylNhV4/d782b3ff-84ba-4029-848c-acf01285524d.mp3"
|
|
1732
1732
|
}
|
|
1733
1733
|
];
|
|
1734
|
+
var PREMADE_ID = /\/premade\/voices\/([A-Za-z0-9]+)\//;
|
|
1735
|
+
var ELEVENLABS_DIRECT_VOICES = ELEVENLABS_VOICES.flatMap((v) => {
|
|
1736
|
+
const id = v.previewUrl ? PREMADE_ID.exec(v.previewUrl)?.[1] : void 0;
|
|
1737
|
+
return id ? [{ ...v, id }] : [];
|
|
1738
|
+
});
|
|
1739
|
+
var ELEVENLABS_DIRECT_DEFAULT_VOICE = "EXAVITQu4vr4xnSDxMaL";
|
|
1740
|
+
|
|
1741
|
+
// src/catalog/speech-elevenlabs-direct.ts
|
|
1742
|
+
var ELEVENLABS_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
|
|
1743
|
+
var PER_CALL = { unit: "images" };
|
|
1744
|
+
var PER_REQUEST = { unit: "requests" };
|
|
1745
|
+
var ELEVENLABS_DIRECT_MODELS = [
|
|
1746
|
+
{
|
|
1747
|
+
id: "elevenlabs-v4-direct",
|
|
1748
|
+
aliases: [],
|
|
1749
|
+
label: "ElevenLabs v4 (direct)",
|
|
1750
|
+
type: "speech",
|
|
1751
|
+
adapter: "elevenlabs",
|
|
1752
|
+
providerModelId: "eleven_v4",
|
|
1753
|
+
lifecycle: "active",
|
|
1754
|
+
exposure: [],
|
|
1755
|
+
constraints: {
|
|
1756
|
+
// Premade voices under their ElevenLabs ids (the direct API takes ids, not names).
|
|
1757
|
+
voices: ELEVENLABS_DIRECT_VOICES,
|
|
1758
|
+
languages: ELEVENLABS_V4_LANGUAGES,
|
|
1759
|
+
outputFormats: ELEVENLABS_MP3_FORMATS,
|
|
1760
|
+
supports: [],
|
|
1761
|
+
// ElevenLabs docs: 10,000 characters per request.
|
|
1762
|
+
prompt: { referenceSyntax: "numbered", maxChars: 1e4 }
|
|
1763
|
+
},
|
|
1764
|
+
defaults: { voice: ELEVENLABS_DIRECT_DEFAULT_VOICE, outputFormat: "mp3_44100_128" },
|
|
1765
|
+
usage: PER_CALL,
|
|
1766
|
+
pricingKind: "flat",
|
|
1767
|
+
display: {
|
|
1768
|
+
provider: "elevenlabs",
|
|
1769
|
+
logo: ELEVENLABS_LOGO,
|
|
1770
|
+
description: "ElevenLabs v4 text to speech with audio tags, in a premade voice or your own cloned voice; up to 10,000 characters."
|
|
1771
|
+
},
|
|
1772
|
+
capabilities: { customVoices: true }
|
|
1773
|
+
},
|
|
1774
|
+
{
|
|
1775
|
+
id: "elevenlabs-ivc",
|
|
1776
|
+
aliases: [],
|
|
1777
|
+
label: "ElevenLabs Instant Voice Clone",
|
|
1778
|
+
type: "voice-clone",
|
|
1779
|
+
adapter: "elevenlabs",
|
|
1780
|
+
providerModelId: "ivc",
|
|
1781
|
+
lifecycle: "active",
|
|
1782
|
+
exposure: [],
|
|
1783
|
+
constraints: {
|
|
1784
|
+
// POST /v1/voices/add; ElevenLabs takes up to 25 samples and advises 1-2 minutes of
|
|
1785
|
+
// clean speech in total. Each clone uses a voice slot on our plan until deleted.
|
|
1786
|
+
references: { audios: 25, audioFormats: ["mp3", "wav", "m4a", "webm", "ogg"] },
|
|
1787
|
+
supports: []
|
|
1788
|
+
},
|
|
1789
|
+
defaults: {},
|
|
1790
|
+
usage: PER_REQUEST,
|
|
1791
|
+
pricingKind: "flat",
|
|
1792
|
+
display: {
|
|
1793
|
+
provider: "elevenlabs",
|
|
1794
|
+
logo: ELEVENLABS_LOGO,
|
|
1795
|
+
description: "Clone a private, reusable voice from one or more clean recordings, then speak with it on ElevenLabs v4 (direct)."
|
|
1796
|
+
},
|
|
1797
|
+
capabilities: {}
|
|
1798
|
+
}
|
|
1799
|
+
];
|
|
1800
|
+
|
|
1801
|
+
// src/catalog/voices-fish.ts
|
|
1802
|
+
var FISH_VOICES = [
|
|
1803
|
+
{
|
|
1804
|
+
id: "933563129e564b19a115bedd57b7406a",
|
|
1805
|
+
name: "Sarah",
|
|
1806
|
+
gender: "female",
|
|
1807
|
+
languages: ["en"],
|
|
1808
|
+
description: "An engaged speaker.",
|
|
1809
|
+
previewUrl: "https://platform.r2.fish.audio/task/4e204945670c460c86fdab57512cb308.mp3"
|
|
1810
|
+
},
|
|
1811
|
+
{
|
|
1812
|
+
id: "bf322df2096a46f18c579d0baa36f41d",
|
|
1813
|
+
name: "Adrian",
|
|
1814
|
+
gender: "male",
|
|
1815
|
+
languages: ["en"],
|
|
1816
|
+
description: "A steady and reliable narrator.",
|
|
1817
|
+
previewUrl: "https://platform.r2.fish.audio/task/d730b09f4a484316a77ecc86137e85fb.mp3"
|
|
1818
|
+
},
|
|
1819
|
+
{
|
|
1820
|
+
id: "536d3a5e000945adb7038665781a4aca",
|
|
1821
|
+
name: "Ethan",
|
|
1822
|
+
gender: "male",
|
|
1823
|
+
languages: ["en"],
|
|
1824
|
+
description: "A curious explainer.",
|
|
1825
|
+
previewUrl: "https://platform.r2.fish.audio/task/bdd677ed767744fc91f166468786264b.mp3"
|
|
1826
|
+
},
|
|
1827
|
+
{
|
|
1828
|
+
id: "b347db033a6549378b48d00acb0d06cd",
|
|
1829
|
+
name: "Selene",
|
|
1830
|
+
gender: "female",
|
|
1831
|
+
languages: ["en"],
|
|
1832
|
+
description: "A meditative female voice.",
|
|
1833
|
+
previewUrl: "https://platform.r2.fish.audio/task/fcf629b4a0b343558f461338ba1b9da4.mp3"
|
|
1834
|
+
},
|
|
1835
|
+
{
|
|
1836
|
+
id: "9a9cf47702da476aa4629e2506d4a857",
|
|
1837
|
+
name: "Hannah",
|
|
1838
|
+
gender: "female",
|
|
1839
|
+
languages: ["en"],
|
|
1840
|
+
description: "A conversation specialist.",
|
|
1841
|
+
previewUrl: "https://platform.r2.fish.audio/task/08d658835feb427db808e37060b78eb0.mp3"
|
|
1842
|
+
},
|
|
1843
|
+
{
|
|
1844
|
+
id: "79d0bd3e4e5444b18f7b6d89b5927bf1",
|
|
1845
|
+
name: "Jordan",
|
|
1846
|
+
gender: "male",
|
|
1847
|
+
languages: ["en"],
|
|
1848
|
+
description: "A motivational speaker.",
|
|
1849
|
+
previewUrl: "https://platform.r2.fish.audio/task/edecbc0bdd4c46c39eda8520a0f729ef.mp3"
|
|
1850
|
+
},
|
|
1851
|
+
{
|
|
1852
|
+
id: "e3cd384158934cc9a01029cd7d278634",
|
|
1853
|
+
name: "Laura",
|
|
1854
|
+
gender: "female",
|
|
1855
|
+
languages: ["en"],
|
|
1856
|
+
description: "A confident female narrator.",
|
|
1857
|
+
previewUrl: "https://platform.r2.fish.audio/task/e821bef995344d519caa1c93d808db23.mp3"
|
|
1858
|
+
},
|
|
1859
|
+
{
|
|
1860
|
+
id: "f3a2b90078d54a65af4b95f63bc7798e",
|
|
1861
|
+
name: "Sheila",
|
|
1862
|
+
gender: "female",
|
|
1863
|
+
accent: "american",
|
|
1864
|
+
languages: ["en"],
|
|
1865
|
+
description: "A young American English woman's voice.",
|
|
1866
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/9bb9e1a1cf3f47f38700da1c5c0a678a.mp3"
|
|
1867
|
+
},
|
|
1868
|
+
{
|
|
1869
|
+
id: "0db6e93af420470b9d9b9a886dbaa954",
|
|
1870
|
+
name: "Kai",
|
|
1871
|
+
gender: "male",
|
|
1872
|
+
languages: ["en"],
|
|
1873
|
+
description: "A friendly English man's voice for companion apps and everyday conversation.",
|
|
1874
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/13306f1172544c3ba3106d1e363feaa6.mp3"
|
|
1875
|
+
},
|
|
1876
|
+
{
|
|
1877
|
+
id: "8abfa9ebd4c24a3399b68c3cdac8c7b5",
|
|
1878
|
+
name: "Freya",
|
|
1879
|
+
gender: "female",
|
|
1880
|
+
accent: "british",
|
|
1881
|
+
languages: ["en"],
|
|
1882
|
+
description: "A natural, professional British English voice with a brisk, conversational pace. Clear and easy to follow, suited to voice assistants, customer support and everyday narration.",
|
|
1883
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/07918705a56b42daaab149f65392cea7.mp3"
|
|
1884
|
+
},
|
|
1885
|
+
{
|
|
1886
|
+
id: "2f64e528a4f2406691925ab1e0ed5b7f",
|
|
1887
|
+
name: "Ananya",
|
|
1888
|
+
gender: "female",
|
|
1889
|
+
languages: ["hi"],
|
|
1890
|
+
description: "\u0938\u093E\u092B\u093C \u0914\u0930 \u0906\u0924\u094D\u092E\u0935\u093F\u0936\u094D\u0935\u093E\u0938 \u092D\u0930\u0940 \u0906\u0935\u093E\u091C\u093C, \u091C\u094B \u0935\u0949\u0907\u0938 \u0905\u0938\u093F\u0938\u094D\u091F\u0947\u0902\u091F, \u0917\u094D\u0930\u093E\u0939\u0915 \u0938\u0947\u0935\u093E \u0914\u0930 \u092A\u094D\u0930\u0938\u094D\u0924\u0941\u0924\u093F\u092F\u094B\u0902 \u0915\u0947 \u0932\u093F\u090F \u0909\u092A\u092F\u0941\u0915\u094D\u0924 \u0939\u0948\u0964",
|
|
1891
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/a17a700668d8405f8316db120733145c.mp3"
|
|
1892
|
+
},
|
|
1893
|
+
{
|
|
1894
|
+
id: "cefd91a07b99468f9148e2580990082d",
|
|
1895
|
+
name: "Arjun",
|
|
1896
|
+
gender: "male",
|
|
1897
|
+
languages: ["hi"],
|
|
1898
|
+
description: "\u0938\u093E\u092B\u093C \u0914\u0930 \u0906\u0924\u094D\u092E\u0935\u093F\u0936\u094D\u0935\u093E\u0938 \u092D\u0930\u0940 \u0906\u0935\u093E\u091C\u093C, \u091C\u094B \u0935\u0949\u0907\u0938 \u0905\u0938\u093F\u0938\u094D\u091F\u0947\u0902\u091F, \u0917\u094D\u0930\u093E\u0939\u0915 \u0938\u0947\u0935\u093E \u0914\u0930 \u092A\u094D\u0930\u0938\u094D\u0924\u0941\u0924\u093F\u092F\u094B\u0902 \u0915\u0947 \u0932\u093F\u090F \u0909\u092A\u092F\u0941\u0915\u094D\u0924 \u0939\u0948\u0964",
|
|
1899
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/a0c4a8eadb7841cdae8e5e68031a2dfb.mp3"
|
|
1900
|
+
},
|
|
1901
|
+
{
|
|
1902
|
+
id: "3f065d660212478a9c697fa965b4d098",
|
|
1903
|
+
name: "Carmen",
|
|
1904
|
+
gender: "female",
|
|
1905
|
+
languages: ["es"],
|
|
1906
|
+
description: "Una voz clara y segura para asistentes de voz, atenci\xF3n al cliente y presentaciones.",
|
|
1907
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/3421be48b6cb4c28bf829c25188e7e74.mp3"
|
|
1908
|
+
},
|
|
1909
|
+
{
|
|
1910
|
+
id: "ec0718028a2445fb9be8e8bfb56a0150",
|
|
1911
|
+
name: "Rodrigo",
|
|
1912
|
+
gender: "male",
|
|
1913
|
+
languages: ["es"],
|
|
1914
|
+
description: "Una voz clara y segura para asistentes de voz, atenci\xF3n al cliente y presentaciones.",
|
|
1915
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/5a77c32365604800ad5b4eb13c5585df.mp3"
|
|
1916
|
+
},
|
|
1917
|
+
{
|
|
1918
|
+
id: "10a3a20742114a4ea6dd441e7591850f",
|
|
1919
|
+
name: "Manon",
|
|
1920
|
+
gender: "female",
|
|
1921
|
+
languages: ["fr"],
|
|
1922
|
+
description: "Une voix claire et vive, adapt\xE9e aux assistants vocaux et au support client.",
|
|
1923
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/f7b75ee1fa524e48a8cefb003cf72952.mp3"
|
|
1924
|
+
},
|
|
1925
|
+
{
|
|
1926
|
+
id: "f69bca092b674168a8d02d61ca20943c",
|
|
1927
|
+
name: "Lucas",
|
|
1928
|
+
gender: "male",
|
|
1929
|
+
languages: ["fr"],
|
|
1930
|
+
description: "Une voix claire et assur\xE9e, adapt\xE9e aux assistants vocaux et au service client.",
|
|
1931
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/86fca3e56a014a3d8a11450854bb8311.mp3"
|
|
1932
|
+
},
|
|
1933
|
+
{
|
|
1934
|
+
id: "3937b44b604249f18b94913daef94043",
|
|
1935
|
+
name: "Lena",
|
|
1936
|
+
gender: "female",
|
|
1937
|
+
languages: ["de"],
|
|
1938
|
+
description: "Eine klare, souver\xE4ne Stimme f\xFCr Sprachassistenten, Kundenservice und Pr\xE4sentationen.",
|
|
1939
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/8659fec80b74442dab68a7755716a401.mp3"
|
|
1940
|
+
},
|
|
1941
|
+
{
|
|
1942
|
+
id: "c1e7cc926aa5469aa966c353094d4b0b",
|
|
1943
|
+
name: "Lukas",
|
|
1944
|
+
gender: "male",
|
|
1945
|
+
languages: ["de"],
|
|
1946
|
+
description: "Eine klare, souver\xE4ne Stimme f\xFCr Sprachassistenten, Kundenservice und Pr\xE4sentationen.",
|
|
1947
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/fb1d538126bb4fe38f8366250f6a2136.mp3"
|
|
1948
|
+
},
|
|
1949
|
+
{
|
|
1950
|
+
id: "b3c060cc41544a7da94a2c487647c902",
|
|
1951
|
+
name: "Let\xEDcia",
|
|
1952
|
+
gender: "female",
|
|
1953
|
+
accent: "brazilian",
|
|
1954
|
+
languages: ["pt"],
|
|
1955
|
+
description: "A Brazilian-accented Portuguese woman's voice, in her late twenties. Soft, warm, intimate. A freelance designer from Belo Horizonte who enjoys long walks in the park. Best suited to companion apps and casual everyday conversation.",
|
|
1956
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-10-12/13c6c0d96b5c4069951f89868ee15360.mp3"
|
|
1957
|
+
},
|
|
1958
|
+
{
|
|
1959
|
+
id: "add7bcb8d3c8423bbfa152ca232aad6e",
|
|
1960
|
+
name: "Ricardo",
|
|
1961
|
+
gender: "male",
|
|
1962
|
+
accent: "brazilian",
|
|
1963
|
+
languages: ["pt"],
|
|
1964
|
+
description: "A Brazilian-accented Portuguese man's voice, in his late forties. Clear, professional, monotone. A high school history teacher from Curitiba who loves classical music. Best suited to lessons, tutoring and explainer content.",
|
|
1965
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-10-12/67475fc717ae45cbb38e647a2dd37fe1.mp3"
|
|
1966
|
+
},
|
|
1967
|
+
{
|
|
1968
|
+
id: "b2d9d8db057042688a5e318b8f405bc2",
|
|
1969
|
+
name: "Kyoko",
|
|
1970
|
+
gender: "female",
|
|
1971
|
+
languages: ["ja"],
|
|
1972
|
+
description: "\u4E01\u5BE7\u3067\u843D\u3061\u7740\u3044\u305F\u8A71\u3057\u65B9\u304C\u7279\u5FB4\u306E\u5973\u6027\u306E\u58F0\u3002\u304A\u5BA2\u69D8\u5BFE\u5FDC\u3084\u60C5\u5831\u63D0\u4F9B\u306B\u6700\u9069\u3002",
|
|
1973
|
+
previewUrl: "https://platform.r2.fish.audio/task/993b3ccb52124341aff79580f1ce5a5a.mp3"
|
|
1974
|
+
},
|
|
1975
|
+
{
|
|
1976
|
+
id: "297a6fd278df47c3b9da9bfdf55ac89a",
|
|
1977
|
+
name: "Satoru",
|
|
1978
|
+
gender: "male",
|
|
1979
|
+
languages: ["ja"],
|
|
1980
|
+
description: "\u82E5\u3005\u3057\u304F\u3082\u843D\u3061\u7740\u304D\u306E\u3042\u308B\u7537\u6027\u306E\u58F0\u3002\u65E5\u5E38\u306E\u8A9E\u308A\u3084\u30EA\u30E9\u30C3\u30AF\u30B9\u3057\u305F\u30CA\u30EC\u30FC\u30B7\u30E7\u30F3\u306B\u6700\u9069\u3002",
|
|
1981
|
+
previewUrl: "https://platform.r2.fish.audio/task/1b4712fb831f4c149eef6b0133157418.mp3"
|
|
1982
|
+
},
|
|
1983
|
+
{
|
|
1984
|
+
id: "0b14f34a13a94ed88fe6113193749bb0",
|
|
1985
|
+
name: "Fatima",
|
|
1986
|
+
gender: "female",
|
|
1987
|
+
languages: ["ar"],
|
|
1988
|
+
description: "\u0635\u0648\u062A \u0648\u0627\u0636\u062D \u0648\u0648\u0627\u062B\u0642 \u064A\u0646\u0627\u0633\u0628 \u0627\u0644\u0645\u0633\u0627\u0639\u062F\u0627\u062A \u0627\u0644\u0635\u0648\u062A\u064A\u0629 \u0648\u062E\u062F\u0645\u0629 \u0627\u0644\u0639\u0645\u0644\u0627\u0621 \u0648\u0627\u0644\u0639\u0631\u0648\u0636 \u0627\u0644\u062A\u0642\u062F\u064A\u0645\u064A\u0629.",
|
|
1989
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/93406e1b905a4c4994306e3421243390.mp3"
|
|
1990
|
+
},
|
|
1991
|
+
{
|
|
1992
|
+
id: "74c6aba5cbf94a15bbdc547ffce5cb38",
|
|
1993
|
+
name: "Yutong",
|
|
1994
|
+
gender: "female",
|
|
1995
|
+
languages: ["zh"],
|
|
1996
|
+
description: "\u58F0\u97F3\u6E05\u6670\u81EA\u7136\uFF0C\u8868\u8FBE\u5229\u843D\uFF0C\u9002\u5408\u8BED\u97F3\u52A9\u624B\u3001\u5BA2\u670D\u548C\u65E5\u5E38\u64AD\u62A5\u3002",
|
|
1997
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/a48320f37fe44c4699549a1afc3778e8.mp3"
|
|
1998
|
+
}
|
|
1999
|
+
];
|
|
2000
|
+
|
|
2001
|
+
// src/catalog/speech-fish.ts
|
|
2002
|
+
var FISH_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/fishaudio.png";
|
|
2003
|
+
var PER_CALL2 = { unit: "images" };
|
|
2004
|
+
var PER_REQUEST2 = { unit: "requests" };
|
|
2005
|
+
var TTS_MAX_CHARS = 1e4;
|
|
2006
|
+
function fishTts(id, label, providerModelId, description) {
|
|
2007
|
+
return {
|
|
2008
|
+
id,
|
|
2009
|
+
aliases: [],
|
|
2010
|
+
label,
|
|
2011
|
+
type: "speech",
|
|
2012
|
+
adapter: "fish",
|
|
2013
|
+
providerModelId,
|
|
2014
|
+
lifecycle: "active",
|
|
2015
|
+
exposure: [],
|
|
2016
|
+
constraints: {
|
|
2017
|
+
voices: FISH_VOICES,
|
|
2018
|
+
outputFormats: ["mp3", "wav"],
|
|
2019
|
+
supports: [],
|
|
2020
|
+
prompt: { referenceSyntax: "numbered", maxChars: TTS_MAX_CHARS }
|
|
2021
|
+
},
|
|
2022
|
+
defaults: { voice: "9a9cf47702da476aa4629e2506d4a857", outputFormat: "mp3" },
|
|
2023
|
+
usage: PER_CALL2,
|
|
2024
|
+
pricingKind: "flat",
|
|
2025
|
+
display: { provider: "fishaudio", logo: FISH_LOGO, description },
|
|
2026
|
+
capabilities: { customVoices: true }
|
|
2027
|
+
};
|
|
2028
|
+
}
|
|
2029
|
+
var FISH_MODELS = [
|
|
2030
|
+
fishTts(
|
|
2031
|
+
"fish-s2.1-pro",
|
|
2032
|
+
"Fish Audio S2.1 Pro",
|
|
2033
|
+
"s2.1-pro",
|
|
2034
|
+
"Fish Audio S2.1 Pro text to speech in 83 languages, with [bracket] directions and your own cloned voices."
|
|
2035
|
+
),
|
|
2036
|
+
fishTts(
|
|
2037
|
+
"fish-s2.1-pro-free",
|
|
2038
|
+
"Fish Audio S2.1 Pro Free",
|
|
2039
|
+
"s2.1-pro-free",
|
|
2040
|
+
"Fish Audio S2.1 Pro on the free developer tier: the same voices at no cost, without latency or data-processing guarantees."
|
|
2041
|
+
),
|
|
2042
|
+
fishTts(
|
|
2043
|
+
"fish-drama-3",
|
|
2044
|
+
"Fish Audio Drama 3",
|
|
2045
|
+
"drama-3",
|
|
2046
|
+
"Fish Audio Drama 3 text to speech you direct like an actor: [directions], sounds, pauses and per-word tags."
|
|
2047
|
+
),
|
|
2048
|
+
{
|
|
2049
|
+
id: "fish-voice-clone",
|
|
2050
|
+
aliases: [],
|
|
2051
|
+
label: "Fish Audio Voice Clone",
|
|
2052
|
+
type: "voice-clone",
|
|
2053
|
+
adapter: "fish",
|
|
2054
|
+
providerModelId: "voice-clone",
|
|
2055
|
+
lifecycle: "active",
|
|
2056
|
+
exposure: [],
|
|
2057
|
+
constraints: {
|
|
2058
|
+
// POST /model takes 1-20 voice files; Fish advises 10 s or more of clean speech each.
|
|
2059
|
+
references: { audios: 20, audioFormats: ["wav", "mp3", "m4a", "opus"] },
|
|
2060
|
+
supports: []
|
|
2061
|
+
},
|
|
2062
|
+
defaults: {},
|
|
2063
|
+
usage: PER_REQUEST2,
|
|
2064
|
+
pricingKind: "flat",
|
|
2065
|
+
display: {
|
|
2066
|
+
provider: "fishaudio",
|
|
2067
|
+
logo: FISH_LOGO,
|
|
2068
|
+
description: "Clone a private, reusable voice from one or more clean recordings, then speak with it on the Fish Audio speech models."
|
|
2069
|
+
},
|
|
2070
|
+
capabilities: {}
|
|
2071
|
+
},
|
|
2072
|
+
{
|
|
2073
|
+
id: "fish-voice-design-1",
|
|
2074
|
+
aliases: [],
|
|
2075
|
+
label: "Fish Audio Voice Design",
|
|
2076
|
+
type: "voice-design",
|
|
2077
|
+
adapter: "fish",
|
|
2078
|
+
providerModelId: "voice-design-1",
|
|
2079
|
+
lifecycle: "active",
|
|
2080
|
+
exposure: [],
|
|
2081
|
+
constraints: {
|
|
2082
|
+
voiceDesign: { maxCandidates: 4, previewMaxChars: 150 },
|
|
2083
|
+
supports: [],
|
|
2084
|
+
prompt: { referenceSyntax: "numbered", maxChars: 2e3 }
|
|
2085
|
+
},
|
|
2086
|
+
defaults: {},
|
|
2087
|
+
usage: PER_REQUEST2,
|
|
2088
|
+
pricingKind: "flat",
|
|
2089
|
+
display: {
|
|
2090
|
+
provider: "fishaudio",
|
|
2091
|
+
logo: FISH_LOGO,
|
|
2092
|
+
description: "Describe a voice and get up to four short candidates; keep one as a cloned voice."
|
|
2093
|
+
},
|
|
2094
|
+
capabilities: {}
|
|
2095
|
+
}
|
|
2096
|
+
];
|
|
1734
2097
|
|
|
1735
2098
|
// src/catalog/voices-gemini.ts
|
|
1736
2099
|
var GEMINI_TTS_VOICES = [
|
|
@@ -3307,11 +3670,11 @@ var MINIMAX_VOICES = [
|
|
|
3307
3670
|
];
|
|
3308
3671
|
|
|
3309
3672
|
// src/catalog/media-nodes.ts
|
|
3310
|
-
var
|
|
3673
|
+
var ELEVENLABS_LOGO2 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
|
|
3311
3674
|
var GOOGLE_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
|
|
3312
3675
|
var MINIMAX_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png";
|
|
3313
3676
|
var SYNC_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/sync.png";
|
|
3314
|
-
var
|
|
3677
|
+
var PER_CALL3 = { unit: "images" };
|
|
3315
3678
|
var EXPOSURE4 = ["cowork", "space_builder"];
|
|
3316
3679
|
var LIPSYNC_AUDIO = { audioSeconds: { max: 30 } };
|
|
3317
3680
|
function elevenLabsTts(tts) {
|
|
@@ -3332,9 +3695,9 @@ function elevenLabsTts(tts) {
|
|
|
3332
3695
|
prompt: { referenceSyntax: "numbered", maxChars: tts.maxChars }
|
|
3333
3696
|
},
|
|
3334
3697
|
defaults: { voice: "Rachel", ...tts.formats && { outputFormat: "mp3_44100_128" } },
|
|
3335
|
-
usage:
|
|
3698
|
+
usage: PER_CALL3,
|
|
3336
3699
|
pricingKind: "flat",
|
|
3337
|
-
display: { provider: "elevenlabs", logo:
|
|
3700
|
+
display: { provider: "elevenlabs", logo: ELEVENLABS_LOGO2, description: tts.description },
|
|
3338
3701
|
capabilities: {}
|
|
3339
3702
|
};
|
|
3340
3703
|
}
|
|
@@ -3356,7 +3719,7 @@ function geminiTts(id, label, description) {
|
|
|
3356
3719
|
prompt: { referenceSyntax: "numbered", maxChars: 8192 }
|
|
3357
3720
|
},
|
|
3358
3721
|
defaults: { voice: "Kore" },
|
|
3359
|
-
usage:
|
|
3722
|
+
usage: PER_CALL3,
|
|
3360
3723
|
pricingKind: "flat",
|
|
3361
3724
|
display: { provider: "google", logo: GOOGLE_LOGO, description },
|
|
3362
3725
|
capabilities: {}
|
|
@@ -3379,7 +3742,7 @@ function syncLipsync(id, label, providerModelId, syncModel, description) {
|
|
|
3379
3742
|
},
|
|
3380
3743
|
defaults: {},
|
|
3381
3744
|
...syncModel !== void 0 && { providerOptions: { fal: { model: syncModel } } },
|
|
3382
|
-
usage:
|
|
3745
|
+
usage: PER_CALL3,
|
|
3383
3746
|
pricingKind: "flat",
|
|
3384
3747
|
display: { provider: "sync", logo: SYNC_LOGO, description },
|
|
3385
3748
|
capabilities: { acceptsSourceVideo: true }
|
|
@@ -3440,7 +3803,7 @@ var MEDIA_NODE_MODELS = [
|
|
|
3440
3803
|
prompt: { referenceSyntax: "numbered", maxChars: 1e4 }
|
|
3441
3804
|
},
|
|
3442
3805
|
defaults: { voice: "Wise_Woman" },
|
|
3443
|
-
usage:
|
|
3806
|
+
usage: PER_CALL3,
|
|
3444
3807
|
pricingKind: "flat",
|
|
3445
3808
|
display: {
|
|
3446
3809
|
provider: "minimax",
|
|
@@ -3467,11 +3830,11 @@ var MEDIA_NODE_MODELS = [
|
|
|
3467
3830
|
supports: []
|
|
3468
3831
|
},
|
|
3469
3832
|
defaults: { voice: "Rachel", outputFormat: "mp3_44100_128" },
|
|
3470
|
-
usage:
|
|
3833
|
+
usage: PER_CALL3,
|
|
3471
3834
|
pricingKind: "flat",
|
|
3472
3835
|
display: {
|
|
3473
3836
|
provider: "elevenlabs",
|
|
3474
|
-
logo:
|
|
3837
|
+
logo: ELEVENLABS_LOGO2,
|
|
3475
3838
|
description: "ElevenLabs speech to speech; re-voices a recording in another voice and keeps its timing and delivery."
|
|
3476
3839
|
},
|
|
3477
3840
|
capabilities: {}
|
|
@@ -3494,11 +3857,11 @@ var MEDIA_NODE_MODELS = [
|
|
|
3494
3857
|
supports: []
|
|
3495
3858
|
},
|
|
3496
3859
|
defaults: {},
|
|
3497
|
-
usage:
|
|
3860
|
+
usage: PER_CALL3,
|
|
3498
3861
|
pricingKind: "flat",
|
|
3499
3862
|
display: {
|
|
3500
3863
|
provider: "elevenlabs",
|
|
3501
|
-
logo:
|
|
3864
|
+
logo: ELEVENLABS_LOGO2,
|
|
3502
3865
|
description: "ElevenLabs dubbing; translates the speech in a video or audio file into another language in the original voices."
|
|
3503
3866
|
},
|
|
3504
3867
|
capabilities: { acceptsSourceVideo: true }
|
|
@@ -3541,7 +3904,7 @@ var MEDIA_NODE_MODELS = [
|
|
|
3541
3904
|
supports: []
|
|
3542
3905
|
},
|
|
3543
3906
|
defaults: {},
|
|
3544
|
-
usage:
|
|
3907
|
+
usage: PER_CALL3,
|
|
3545
3908
|
pricingKind: "flat",
|
|
3546
3909
|
display: {
|
|
3547
3910
|
provider: "veed",
|
|
@@ -3593,16 +3956,18 @@ var MEDIA_NODE_MODELS = [
|
|
|
3593
3956
|
supports: []
|
|
3594
3957
|
},
|
|
3595
3958
|
defaults: {},
|
|
3596
|
-
usage:
|
|
3959
|
+
usage: PER_CALL3,
|
|
3597
3960
|
pricingKind: "flat",
|
|
3598
3961
|
display: {
|
|
3599
3962
|
provider: "elevenlabs",
|
|
3600
|
-
logo:
|
|
3963
|
+
logo: ELEVENLABS_LOGO2,
|
|
3601
3964
|
description: "ElevenLabs Scribe v2 speech to text with word timings, speaker labels and audio-event tags."
|
|
3602
3965
|
},
|
|
3603
3966
|
capabilities: {}
|
|
3604
3967
|
},
|
|
3605
|
-
SAM_3_IMAGE
|
|
3968
|
+
SAM_3_IMAGE,
|
|
3969
|
+
...FISH_MODELS,
|
|
3970
|
+
...ELEVENLABS_DIRECT_MODELS
|
|
3606
3971
|
];
|
|
3607
3972
|
|
|
3608
3973
|
// src/catalog/model3d.ts
|
|
@@ -3798,7 +4163,7 @@ var MODEL3D_MODELS = [
|
|
|
3798
4163
|
|
|
3799
4164
|
// src/catalog/other.ts
|
|
3800
4165
|
var GOOGLE_LOGO2 = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
|
|
3801
|
-
var
|
|
4166
|
+
var ELEVENLABS_LOGO3 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
|
|
3802
4167
|
var MINIMAX_LOGO2 = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png";
|
|
3803
4168
|
var OTHER_MODELS = [
|
|
3804
4169
|
{
|
|
@@ -3963,7 +4328,7 @@ var OTHER_MODELS = [
|
|
|
3963
4328
|
pricingKind: "flat",
|
|
3964
4329
|
display: {
|
|
3965
4330
|
provider: "elevenlabs",
|
|
3966
|
-
logo:
|
|
4331
|
+
logo: ELEVENLABS_LOGO3,
|
|
3967
4332
|
description: "ElevenLabs Music v2.5 text-to-music; full songs or instrumentals from 3 seconds to 1 minute."
|
|
3968
4333
|
},
|
|
3969
4334
|
capabilities: {}
|
|
@@ -4015,7 +4380,7 @@ var OTHER_MODELS = [
|
|
|
4015
4380
|
pricingKind: "flat",
|
|
4016
4381
|
display: {
|
|
4017
4382
|
provider: "elevenlabs",
|
|
4018
|
-
logo:
|
|
4383
|
+
logo: ELEVENLABS_LOGO3,
|
|
4019
4384
|
description: "ElevenLabs Sound Effects v2; a sound effect from a text description, up to 22 seconds."
|
|
4020
4385
|
},
|
|
4021
4386
|
capabilities: {}
|
|
@@ -7237,7 +7602,9 @@ var ADAPTER_IDS = [
|
|
|
7237
7602
|
"prodia",
|
|
7238
7603
|
"higgsfield",
|
|
7239
7604
|
"xai-video",
|
|
7240
|
-
"luma"
|
|
7605
|
+
"luma",
|
|
7606
|
+
"fish",
|
|
7607
|
+
"elevenlabs"
|
|
7241
7608
|
];
|
|
7242
7609
|
var ModelTypeSchema = z3.enum([
|
|
7243
7610
|
"text",
|
|
@@ -7254,6 +7621,8 @@ var ModelTypeSchema = z3.enum([
|
|
|
7254
7621
|
"dubbing",
|
|
7255
7622
|
"lipsync",
|
|
7256
7623
|
"transcription",
|
|
7624
|
+
"voice-clone",
|
|
7625
|
+
"voice-design",
|
|
7257
7626
|
"model3d"
|
|
7258
7627
|
]);
|
|
7259
7628
|
var LifecycleSchema = z3.enum(["active", "deprecated", "retired"]);
|
|
@@ -7429,6 +7798,10 @@ var ModelConstraintsSchema = z3.looseObject({
|
|
|
7429
7798
|
supports: z3.array(SupportedOptionSchema).optional(),
|
|
7430
7799
|
ratioIgnoredWith: z3.array(z3.enum(["firstFrame", "sourceVideo"])).optional(),
|
|
7431
7800
|
voices: z3.array(VoiceOptionSchema).optional(),
|
|
7801
|
+
voiceDesign: z3.object({
|
|
7802
|
+
maxCandidates: z3.number().int().positive(),
|
|
7803
|
+
previewMaxChars: z3.number().int().positive()
|
|
7804
|
+
}).optional(),
|
|
7432
7805
|
languages: z3.array(LanguageOptionSchema).optional(),
|
|
7433
7806
|
outputFormats: z3.array(z3.string().min(1)).min(1).optional(),
|
|
7434
7807
|
sourceVideoSeconds: VideoSecondsLimitsSchema.omit({ total: true }).extend({ inReferenceTotal: z3.boolean().optional() }).optional(),
|
|
@@ -7527,6 +7900,7 @@ var CatalogDisplaySchema = z3.looseObject({
|
|
|
7527
7900
|
});
|
|
7528
7901
|
var CatalogCapabilitiesSchema = z3.looseObject({
|
|
7529
7902
|
acceptsSourceVideo: z3.boolean().optional(),
|
|
7903
|
+
customVoices: z3.boolean().optional(),
|
|
7530
7904
|
videoEdit: z3.boolean().optional(),
|
|
7531
7905
|
framesExcludeReferences: z3.boolean().optional(),
|
|
7532
7906
|
sourceVideoExcludesFrames: z3.boolean().optional(),
|
|
@@ -8046,7 +8420,7 @@ var errorCodes = z6.object({
|
|
|
8046
8420
|
type: z6.string().optional(),
|
|
8047
8421
|
error: z6.object({ code: z6.string().optional(), type: z6.string().optional() }).optional()
|
|
8048
8422
|
});
|
|
8049
|
-
var BILLING_TEXT = /insufficient_quota|payment[ _]required|exhausted balance|insufficient (?:credits?|balance|funds)|billing_hard_limit/i;
|
|
8423
|
+
var BILLING_TEXT = /insufficient_quota|payment[ _]required|exhausted balance|insufficient (?:credits?|balance|funds)|billing_hard_limit|top up (?:api )?credit/i;
|
|
8050
8424
|
var BILLING_TEXT_STATUSES = /* @__PURE__ */ new Set([403, 429]);
|
|
8051
8425
|
function billingCode(body) {
|
|
8052
8426
|
const parsed = errorCodes.safeParse(body);
|
|
@@ -8443,16 +8817,16 @@ async function generateSeedreamImage(req, ctx) {
|
|
|
8443
8817
|
} else {
|
|
8444
8818
|
throwArkError(void 0, "Seedream returned no image URL or base64 data", modelId);
|
|
8445
8819
|
}
|
|
8446
|
-
const
|
|
8820
|
+
const usage5 = {
|
|
8447
8821
|
model: modelId,
|
|
8448
8822
|
provider: "ark",
|
|
8449
8823
|
modality: "IMAGE",
|
|
8450
8824
|
unit: "images",
|
|
8451
8825
|
quantity: 1
|
|
8452
8826
|
};
|
|
8453
|
-
if (req.size !== void 0)
|
|
8454
|
-
if (req.quality !== void 0)
|
|
8455
|
-
return { images: [{ bytes, mime: sniffedImageMime(bytes) }], usage:
|
|
8827
|
+
if (req.size !== void 0) usage5.imageSize = req.size;
|
|
8828
|
+
if (req.quality !== void 0) usage5.imageQuality = req.quality;
|
|
8829
|
+
return { images: [{ bytes, mime: sniffedImageMime(bytes) }], usage: usage5, raw: data };
|
|
8456
8830
|
}
|
|
8457
8831
|
var SeedanceUsageSchema = z7.object({
|
|
8458
8832
|
total_tokens: z7.number().optional(),
|
|
@@ -8493,7 +8867,7 @@ function seedanceErrorMessage(error, status) {
|
|
|
8493
8867
|
if (asObject.success && asObject.data.message !== void 0) return asObject.data.message;
|
|
8494
8868
|
return `Seedance task ${status}`;
|
|
8495
8869
|
}
|
|
8496
|
-
function seedanceJob(ctx, key, jobId,
|
|
8870
|
+
function seedanceJob(ctx, key, jobId, usage5) {
|
|
8497
8871
|
const modelId = ctx.model.id;
|
|
8498
8872
|
const fetchStatus = async () => {
|
|
8499
8873
|
const res = await arkFetch(ctx, `${arkBaseUrl(ctx)}${SUBMIT_PATH}/${jobId}`, {
|
|
@@ -8543,21 +8917,21 @@ function seedanceJob(ctx, key, jobId, usage3) {
|
|
|
8543
8917
|
modelId
|
|
8544
8918
|
);
|
|
8545
8919
|
if (polled.duration !== void 0 && polled.duration > 0) {
|
|
8546
|
-
|
|
8547
|
-
|
|
8920
|
+
usage5.quantity = polled.duration;
|
|
8921
|
+
usage5.durationSeconds = polled.duration;
|
|
8548
8922
|
}
|
|
8549
8923
|
const rendered = VideoResolutionSchema.safeParse(
|
|
8550
8924
|
polled.resolution?.toLowerCase()
|
|
8551
8925
|
);
|
|
8552
|
-
if (rendered.success)
|
|
8926
|
+
if (rendered.success) usage5.resolution = rendered.data;
|
|
8553
8927
|
const tokens = polled.usage;
|
|
8554
8928
|
if (tokens?.total_tokens !== void 0 && tokens.completion_tokens !== void 0) {
|
|
8555
|
-
|
|
8556
|
-
|
|
8929
|
+
usage5.inputTokens = tokens.total_tokens - tokens.completion_tokens;
|
|
8930
|
+
usage5.outputTokens = tokens.completion_tokens;
|
|
8557
8931
|
}
|
|
8558
8932
|
return {
|
|
8559
8933
|
video: { url, expiresAt: new Date(Date.now() + VIDEO_URL_TTL_MS) },
|
|
8560
|
-
usage:
|
|
8934
|
+
usage: usage5,
|
|
8561
8935
|
raw: polled
|
|
8562
8936
|
};
|
|
8563
8937
|
}
|
|
@@ -8663,8 +9037,8 @@ async function generateSeedanceVideo(req, ctx) {
|
|
|
8663
9037
|
);
|
|
8664
9038
|
if (!submit.id) throwArkError(void 0, "Seedance task create returned no id", modelId);
|
|
8665
9039
|
const jobId = submit.id;
|
|
8666
|
-
const
|
|
8667
|
-
return seedanceJob(ctx, key, jobId,
|
|
9040
|
+
const usage5 = seedanceUsage(ctx, req, taskType === "edit" ? requestedDuration : duration);
|
|
9041
|
+
return seedanceJob(ctx, key, jobId, usage5);
|
|
8668
9042
|
}
|
|
8669
9043
|
|
|
8670
9044
|
// src/adapters/fal.ts
|
|
@@ -10152,7 +10526,7 @@ async function collectFalPlanImages(payload, plan4, ctx, req) {
|
|
|
10152
10526
|
return { bytes, mime: mime || "image/png" };
|
|
10153
10527
|
})
|
|
10154
10528
|
);
|
|
10155
|
-
const
|
|
10529
|
+
const usage5 = {
|
|
10156
10530
|
model: ctx.model.id,
|
|
10157
10531
|
provider: "fal",
|
|
10158
10532
|
modality: "IMAGE",
|
|
@@ -10160,9 +10534,9 @@ async function collectFalPlanImages(payload, plan4, ctx, req) {
|
|
|
10160
10534
|
quantity: images.length
|
|
10161
10535
|
};
|
|
10162
10536
|
const billedSize = plan4.imageSize ?? req.size;
|
|
10163
|
-
if (billedSize !== void 0 && ctx.model.type === "image")
|
|
10164
|
-
if (plan4.imageQuality !== void 0)
|
|
10165
|
-
const result = { images, usage:
|
|
10537
|
+
if (billedSize !== void 0 && ctx.model.type === "image") usage5.imageSize = billedSize;
|
|
10538
|
+
if (plan4.imageQuality !== void 0) usage5.imageQuality = plan4.imageQuality;
|
|
10539
|
+
const result = { images, usage: usage5, raw: payload };
|
|
10166
10540
|
const remote = files.find((f) => !f.url.startsWith("data:"));
|
|
10167
10541
|
if (remote !== void 0) result.outputUrl = remote.url;
|
|
10168
10542
|
return result;
|
|
@@ -12325,14 +12699,570 @@ function planUsage(ctx, plan4) {
|
|
|
12325
12699
|
};
|
|
12326
12700
|
}
|
|
12327
12701
|
|
|
12328
|
-
// src/adapters/
|
|
12702
|
+
// src/adapters/elevenlabs.ts
|
|
12703
|
+
import { z as z21 } from "zod";
|
|
12704
|
+
var DEFAULT_BASE_URL = "https://api.elevenlabs.io";
|
|
12705
|
+
var DEFAULT_FORMAT = "mp3_44100_128";
|
|
12706
|
+
var ELEVENLABS_TTS_MODEL_IDS = /* @__PURE__ */ new Set(["eleven_v4"]);
|
|
12707
|
+
var ELEVENLABS_IVC = "ivc";
|
|
12708
|
+
var VOICE_ID = /^[A-Za-z0-9_-]{1,64}$/;
|
|
12709
|
+
function elevenLabsRowRefusal(row2) {
|
|
12710
|
+
const id = row2.providerModelId;
|
|
12711
|
+
if (row2.type === "speech") {
|
|
12712
|
+
return ELEVENLABS_TTS_MODEL_IDS.has(id) ? void 0 : `elevenlabs speech rows need providerModelId ${[...ELEVENLABS_TTS_MODEL_IDS].join(", ")}`;
|
|
12713
|
+
}
|
|
12714
|
+
if (row2.type === "voice-clone") {
|
|
12715
|
+
return id === ELEVENLABS_IVC ? void 0 : `elevenlabs voice-clone rows need providerModelId ${ELEVENLABS_IVC}`;
|
|
12716
|
+
}
|
|
12717
|
+
return `elevenlabs has no ${row2.type} rows`;
|
|
12718
|
+
}
|
|
12719
|
+
function elevenLabsError(ctx, code, message) {
|
|
12720
|
+
return new ModelKitError({
|
|
12721
|
+
code,
|
|
12722
|
+
message,
|
|
12723
|
+
provider: "elevenlabs",
|
|
12724
|
+
model: ctx.model.id,
|
|
12725
|
+
retryable: false
|
|
12726
|
+
});
|
|
12727
|
+
}
|
|
12728
|
+
function checkRow(ctx, type) {
|
|
12729
|
+
const refusal2 = ctx.model.type === type ? elevenLabsRowRefusal(ctx.model) : void 0;
|
|
12730
|
+
if (ctx.model.type !== type || refusal2 !== void 0) {
|
|
12731
|
+
throw elevenLabsError(
|
|
12732
|
+
ctx,
|
|
12733
|
+
"unsupported_option",
|
|
12734
|
+
refusal2 ?? `${ctx.model.id} is not a ${type} row`
|
|
12735
|
+
);
|
|
12736
|
+
}
|
|
12737
|
+
}
|
|
12738
|
+
function checkVoiceId(ctx, field, id) {
|
|
12739
|
+
if (!VOICE_ID.test(id))
|
|
12740
|
+
throw elevenLabsError(ctx, "unsupported_option", `${field} is not a voice id`);
|
|
12741
|
+
return id;
|
|
12742
|
+
}
|
|
12743
|
+
function elevenLabsKey(ctx) {
|
|
12744
|
+
const key = ctx.keys.elevenlabs;
|
|
12745
|
+
if (!key) throw elevenLabsError(ctx, "auth", "Missing API key for elevenlabs");
|
|
12746
|
+
return key;
|
|
12747
|
+
}
|
|
12748
|
+
function elevenLabsUrl(ctx, path) {
|
|
12749
|
+
return `${ctx.endpoints?.elevenlabs ?? DEFAULT_BASE_URL}${path}`;
|
|
12750
|
+
}
|
|
12751
|
+
var errorDetail = z21.object({
|
|
12752
|
+
detail: z21.object({ status: z21.string(), message: z21.string().optional() })
|
|
12753
|
+
});
|
|
12754
|
+
function errorStatus(body) {
|
|
12755
|
+
const parsed = errorDetail.safeParse(body);
|
|
12756
|
+
return parsed.success ? parsed.data.detail : void 0;
|
|
12757
|
+
}
|
|
12758
|
+
function classifyResponse(ctx, status, body) {
|
|
12759
|
+
const error = classifyHttpError(status, body, "elevenlabs", ctx.model.id);
|
|
12760
|
+
const detail = errorStatus(body);
|
|
12761
|
+
if (detail?.status === "voice_limit_reached") {
|
|
12762
|
+
return new ModelKitError({
|
|
12763
|
+
code: "provider_rejected",
|
|
12764
|
+
message: detail.message ?? "ElevenLabs voice limit reached",
|
|
12765
|
+
provider: "elevenlabs",
|
|
12766
|
+
model: ctx.model.id,
|
|
12767
|
+
status,
|
|
12768
|
+
body,
|
|
12769
|
+
cause: error,
|
|
12770
|
+
retryable: false
|
|
12771
|
+
});
|
|
12772
|
+
}
|
|
12773
|
+
if (detail?.status === "quota_exceeded") {
|
|
12774
|
+
return new ModelKitError({
|
|
12775
|
+
code: "provider_billing",
|
|
12776
|
+
message: error.message,
|
|
12777
|
+
provider: "elevenlabs",
|
|
12778
|
+
model: ctx.model.id,
|
|
12779
|
+
status,
|
|
12780
|
+
body,
|
|
12781
|
+
cause: error,
|
|
12782
|
+
retryable: false
|
|
12783
|
+
});
|
|
12784
|
+
}
|
|
12785
|
+
return error;
|
|
12786
|
+
}
|
|
12787
|
+
async function elevenLabsFetch(ctx, path, init) {
|
|
12788
|
+
throwIfAborted(ctx.signal);
|
|
12789
|
+
const request = {
|
|
12790
|
+
method: init.method,
|
|
12791
|
+
headers: { "xi-api-key": elevenLabsKey(ctx), ...init.headers }
|
|
12792
|
+
};
|
|
12793
|
+
if (init.body !== void 0) request.body = init.body;
|
|
12794
|
+
if (ctx.signal !== void 0) request.signal = ctx.signal;
|
|
12795
|
+
let res;
|
|
12796
|
+
try {
|
|
12797
|
+
res = await ctx.fetch(elevenLabsUrl(ctx, path), request);
|
|
12798
|
+
} catch (cause) {
|
|
12799
|
+
throw classifyThrown("elevenlabs", cause, ctx.model.id);
|
|
12800
|
+
}
|
|
12801
|
+
if (!res.ok) throw classifyResponse(ctx, res.status, await readBody(res));
|
|
12802
|
+
return res;
|
|
12803
|
+
}
|
|
12804
|
+
function usage2(ctx) {
|
|
12805
|
+
return {
|
|
12806
|
+
model: ctx.model.id,
|
|
12807
|
+
provider: "elevenlabs",
|
|
12808
|
+
modality: "AUDIO",
|
|
12809
|
+
unit: ctx.model.usage.unit,
|
|
12810
|
+
quantity: 1
|
|
12811
|
+
};
|
|
12812
|
+
}
|
|
12813
|
+
function audioMime(res) {
|
|
12814
|
+
const header = res.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase();
|
|
12815
|
+
return header?.startsWith("audio/") ? header : "audio/mpeg";
|
|
12816
|
+
}
|
|
12817
|
+
async function generateSpeech(req, ctx) {
|
|
12818
|
+
checkRow(ctx, "speech");
|
|
12819
|
+
const voice = req.customVoice ?? req.voice;
|
|
12820
|
+
if (voice === void 0) throw elevenLabsError(ctx, "missing_input", "needs a voice");
|
|
12821
|
+
const voiceId = checkVoiceId(ctx, req.customVoice ? "customVoice" : "voice", voice);
|
|
12822
|
+
const format = req.outputFormat ?? DEFAULT_FORMAT;
|
|
12823
|
+
const body = { text: req.text, model_id: ctx.model.providerModelId };
|
|
12824
|
+
if (req.language !== void 0) body.language_code = req.language;
|
|
12825
|
+
const path = `/v1/text-to-speech/${encodeURIComponent(voiceId)}?output_format=${encodeURIComponent(format)}`;
|
|
12826
|
+
const { bytes, mime } = await withRetry(
|
|
12827
|
+
async () => {
|
|
12828
|
+
const res = await elevenLabsFetch(ctx, path, {
|
|
12829
|
+
method: "POST",
|
|
12830
|
+
headers: { "Content-Type": "application/json" },
|
|
12831
|
+
body: JSON.stringify(body)
|
|
12832
|
+
});
|
|
12833
|
+
let audio;
|
|
12834
|
+
try {
|
|
12835
|
+
audio = new Uint8Array(await res.arrayBuffer());
|
|
12836
|
+
} catch (cause) {
|
|
12837
|
+
throw classifyThrown("elevenlabs", cause, ctx.model.id);
|
|
12838
|
+
}
|
|
12839
|
+
return { bytes: audio, mime: audioMime(res) };
|
|
12840
|
+
},
|
|
12841
|
+
mediaRetryOptions(ctx.call, ctx.signal)
|
|
12842
|
+
);
|
|
12843
|
+
if (bytes.byteLength === 0)
|
|
12844
|
+
throw elevenLabsError(ctx, "provider_rejected", "ElevenLabs TTS returned no audio");
|
|
12845
|
+
return { audio: { bytes, mime }, usage: usage2(ctx) };
|
|
12846
|
+
}
|
|
12847
|
+
var createdVoiceSchema = z21.object({
|
|
12848
|
+
voice_id: z21.string().min(1),
|
|
12849
|
+
requires_verification: z21.boolean().optional().catch(void 0)
|
|
12850
|
+
});
|
|
12851
|
+
function sampleMime(mime) {
|
|
12852
|
+
return mime.startsWith("audio/") || mime.startsWith("video/") ? mime : "application/octet-stream";
|
|
12853
|
+
}
|
|
12854
|
+
function fileName(index, mime, ref) {
|
|
12855
|
+
const fromMime = mime === "application/octet-stream" ? void 0 : mime.split("/")[1]?.replace("mpeg", "mp3").replace("x-", "");
|
|
12856
|
+
const fromUrl = "url" in ref ? /\.([A-Za-z0-9]{2,4})$/.exec(new URL(ref.url).pathname)?.[1] : void 0;
|
|
12857
|
+
const ext = fromMime || fromUrl?.toLowerCase();
|
|
12858
|
+
return ext ? `sample-${index + 1}.${ext}` : `sample-${index + 1}`;
|
|
12859
|
+
}
|
|
12860
|
+
async function cloneForm(req, ctx) {
|
|
12861
|
+
if (req.samples.length === 0)
|
|
12862
|
+
throw elevenLabsError(ctx, "missing_input", "needs a voice sample");
|
|
12863
|
+
if (req.samples.some((s) => s.designSignature?.trim())) {
|
|
12864
|
+
throw elevenLabsError(
|
|
12865
|
+
ctx,
|
|
12866
|
+
"unsupported_option",
|
|
12867
|
+
"ElevenLabs cannot keep a voice design signature; clone from recordings only"
|
|
12868
|
+
);
|
|
12869
|
+
}
|
|
12870
|
+
const form = new FormData();
|
|
12871
|
+
form.append("name", req.title.trim());
|
|
12872
|
+
if (req.description?.trim()) form.append("description", req.description.trim());
|
|
12873
|
+
if (req.enhance !== void 0) form.append("remove_background_noise", String(req.enhance));
|
|
12874
|
+
for (const [index, sample] of req.samples.entries()) {
|
|
12875
|
+
const { bytes, mime } = await mediaRefToBytes(sample.audio, ctx.fetch, {
|
|
12876
|
+
signal: ctx.signal,
|
|
12877
|
+
provider: "elevenlabs",
|
|
12878
|
+
model: ctx.model.id
|
|
12879
|
+
});
|
|
12880
|
+
const type = sampleMime(mime);
|
|
12881
|
+
const audio = new Blob([new Uint8Array(bytes)], { type });
|
|
12882
|
+
form.append("files", audio, fileName(index, type, sample.audio));
|
|
12883
|
+
}
|
|
12884
|
+
return form;
|
|
12885
|
+
}
|
|
12886
|
+
async function onlyRateLimitRetries(fn) {
|
|
12887
|
+
try {
|
|
12888
|
+
return await fn();
|
|
12889
|
+
} catch (cause) {
|
|
12890
|
+
if (!isModelKitError(cause) || !cause.retryable || cause.code === "rate_limited")
|
|
12891
|
+
throw cause;
|
|
12892
|
+
throw new ModelKitError({
|
|
12893
|
+
code: cause.code,
|
|
12894
|
+
message: cause.message,
|
|
12895
|
+
...cause.provider !== void 0 && { provider: cause.provider },
|
|
12896
|
+
...cause.model !== void 0 && { model: cause.model },
|
|
12897
|
+
...cause.status !== void 0 && { status: cause.status },
|
|
12898
|
+
...cause.body !== void 0 && { body: cause.body },
|
|
12899
|
+
cause,
|
|
12900
|
+
retryable: false
|
|
12901
|
+
});
|
|
12902
|
+
}
|
|
12903
|
+
}
|
|
12904
|
+
async function createVoice(req, ctx) {
|
|
12905
|
+
checkRow(ctx, "voice-clone");
|
|
12906
|
+
const form = await cloneForm(req, ctx);
|
|
12907
|
+
const res = await withRetry(
|
|
12908
|
+
() => onlyRateLimitRetries(
|
|
12909
|
+
() => elevenLabsFetch(ctx, "/v1/voices/add", { method: "POST", body: form })
|
|
12910
|
+
),
|
|
12911
|
+
mediaRetryOptions(ctx.call, ctx.signal)
|
|
12912
|
+
);
|
|
12913
|
+
const raw = await readBody(res);
|
|
12914
|
+
const parsed = createdVoiceSchema.safeParse(raw);
|
|
12915
|
+
if (!parsed.success) {
|
|
12916
|
+
throw new ModelKitError({
|
|
12917
|
+
code: "provider_rejected",
|
|
12918
|
+
message: "ElevenLabs returned no voice id",
|
|
12919
|
+
provider: "elevenlabs",
|
|
12920
|
+
model: ctx.model.id,
|
|
12921
|
+
status: res.status,
|
|
12922
|
+
body: raw,
|
|
12923
|
+
retryable: false
|
|
12924
|
+
});
|
|
12925
|
+
}
|
|
12926
|
+
return {
|
|
12927
|
+
voiceId: parsed.data.voice_id,
|
|
12928
|
+
state: parsed.data.requires_verification === true ? "created" : "trained",
|
|
12929
|
+
usage: usage2(ctx),
|
|
12930
|
+
raw
|
|
12931
|
+
};
|
|
12932
|
+
}
|
|
12933
|
+
var NOT_FOUND_STATUSES = /* @__PURE__ */ new Set([
|
|
12934
|
+
"voice_not_found",
|
|
12935
|
+
"voice_does_not_exist"
|
|
12936
|
+
]);
|
|
12937
|
+
function notFound(cause) {
|
|
12938
|
+
if (cause.status === 404) return true;
|
|
12939
|
+
const status = errorStatus(cause.body)?.status;
|
|
12940
|
+
return cause.status === 400 && status !== void 0 && NOT_FOUND_STATUSES.has(status);
|
|
12941
|
+
}
|
|
12942
|
+
async function deleteVoice(req, ctx) {
|
|
12943
|
+
checkRow(ctx, "voice-clone");
|
|
12944
|
+
const id = encodeURIComponent(checkVoiceId(ctx, "voiceId", req.voiceId));
|
|
12945
|
+
let attempts = 0;
|
|
12946
|
+
await withRetry(
|
|
12947
|
+
async () => {
|
|
12948
|
+
attempts += 1;
|
|
12949
|
+
try {
|
|
12950
|
+
await elevenLabsFetch(ctx, `/v1/voices/${id}`, { method: "DELETE" });
|
|
12951
|
+
} catch (cause) {
|
|
12952
|
+
if (!isModelKitError(cause) || !notFound(cause)) throw cause;
|
|
12953
|
+
if (attempts > 1) return;
|
|
12954
|
+
throw new ModelKitError({
|
|
12955
|
+
code: "provider_rejected",
|
|
12956
|
+
message: `ElevenLabs has no voice ${req.voiceId} under this key set; delete with the tier that created it`,
|
|
12957
|
+
provider: "elevenlabs",
|
|
12958
|
+
model: ctx.model.id,
|
|
12959
|
+
...cause.status !== void 0 && { status: cause.status },
|
|
12960
|
+
cause,
|
|
12961
|
+
retryable: false
|
|
12962
|
+
});
|
|
12963
|
+
}
|
|
12964
|
+
},
|
|
12965
|
+
mediaRetryOptions(ctx.call, ctx.signal)
|
|
12966
|
+
);
|
|
12967
|
+
}
|
|
12968
|
+
var elevenLabsAdapter = {
|
|
12969
|
+
id: "elevenlabs",
|
|
12970
|
+
generateSpeech,
|
|
12971
|
+
createVoice,
|
|
12972
|
+
deleteVoice
|
|
12973
|
+
};
|
|
12974
|
+
|
|
12975
|
+
// src/adapters/fish.ts
|
|
12329
12976
|
import { z as z22 } from "zod";
|
|
12977
|
+
var DEFAULT_BASE_URL2 = "https://api.fish.audio";
|
|
12978
|
+
var FISH_TTS_MODEL_IDS = /* @__PURE__ */ new Set([
|
|
12979
|
+
"s2.1-pro",
|
|
12980
|
+
"s2.1-pro-free",
|
|
12981
|
+
"drama-3"
|
|
12982
|
+
]);
|
|
12983
|
+
var FISH_VOICE_CLONE = "voice-clone";
|
|
12984
|
+
var FISH_VOICE_DESIGN = "voice-design-1";
|
|
12985
|
+
var VOICE_ID2 = /^[A-Za-z0-9_-]{1,64}$/;
|
|
12986
|
+
function fishRowRefusal(row2) {
|
|
12987
|
+
const id = row2.providerModelId;
|
|
12988
|
+
if (row2.type === "speech") {
|
|
12989
|
+
return FISH_TTS_MODEL_IDS.has(id) ? void 0 : `fish speech rows need providerModelId ${[...FISH_TTS_MODEL_IDS].join(", ")}`;
|
|
12990
|
+
}
|
|
12991
|
+
if (row2.type === "voice-clone") {
|
|
12992
|
+
return id === FISH_VOICE_CLONE ? void 0 : `fish voice-clone rows need providerModelId ${FISH_VOICE_CLONE}`;
|
|
12993
|
+
}
|
|
12994
|
+
if (row2.type === "voice-design") {
|
|
12995
|
+
return id === FISH_VOICE_DESIGN ? void 0 : `fish voice-design rows need providerModelId ${FISH_VOICE_DESIGN}`;
|
|
12996
|
+
}
|
|
12997
|
+
return `fish has no ${row2.type} rows`;
|
|
12998
|
+
}
|
|
12999
|
+
function fishError(ctx, code, message) {
|
|
13000
|
+
return new ModelKitError({
|
|
13001
|
+
code,
|
|
13002
|
+
message,
|
|
13003
|
+
provider: "fish",
|
|
13004
|
+
model: ctx.model.id,
|
|
13005
|
+
retryable: false
|
|
13006
|
+
});
|
|
13007
|
+
}
|
|
13008
|
+
function checkRow2(ctx, type) {
|
|
13009
|
+
const refusal2 = ctx.model.type === type ? fishRowRefusal(ctx.model) : void 0;
|
|
13010
|
+
if (ctx.model.type !== type || refusal2 !== void 0) {
|
|
13011
|
+
throw fishError(
|
|
13012
|
+
ctx,
|
|
13013
|
+
"unsupported_option",
|
|
13014
|
+
refusal2 ?? `${ctx.model.id} is not a ${type} row`
|
|
13015
|
+
);
|
|
13016
|
+
}
|
|
13017
|
+
}
|
|
13018
|
+
function checkVoiceId2(ctx, field, id) {
|
|
13019
|
+
if (!VOICE_ID2.test(id))
|
|
13020
|
+
throw fishError(ctx, "unsupported_option", `${field} is not a voice id`);
|
|
13021
|
+
return id;
|
|
13022
|
+
}
|
|
13023
|
+
function fishKey(ctx) {
|
|
13024
|
+
const key = ctx.keys.fish;
|
|
13025
|
+
if (!key) throw fishError(ctx, "auth", "Missing API key for fish");
|
|
13026
|
+
return key;
|
|
13027
|
+
}
|
|
13028
|
+
function fishUrl(ctx, path) {
|
|
13029
|
+
return `${ctx.endpoints?.fish ?? DEFAULT_BASE_URL2}${path}`;
|
|
13030
|
+
}
|
|
13031
|
+
async function fishFetch(ctx, path, init) {
|
|
13032
|
+
throwIfAborted(ctx.signal);
|
|
13033
|
+
const request = {
|
|
13034
|
+
method: init.method,
|
|
13035
|
+
headers: { Authorization: `Bearer ${fishKey(ctx)}`, ...init.headers }
|
|
13036
|
+
};
|
|
13037
|
+
if (init.body !== void 0) request.body = init.body;
|
|
13038
|
+
if (ctx.signal !== void 0) request.signal = ctx.signal;
|
|
13039
|
+
let res;
|
|
13040
|
+
try {
|
|
13041
|
+
res = await ctx.fetch(fishUrl(ctx, path), request);
|
|
13042
|
+
} catch (cause) {
|
|
13043
|
+
throw classifyThrown("fish", cause, ctx.model.id);
|
|
13044
|
+
}
|
|
13045
|
+
if (!res.ok) throw classifyHttpError(res.status, await readBody(res), "fish", ctx.model.id);
|
|
13046
|
+
return res;
|
|
13047
|
+
}
|
|
13048
|
+
function usage3(ctx) {
|
|
13049
|
+
return {
|
|
13050
|
+
model: ctx.model.id,
|
|
13051
|
+
provider: "fish",
|
|
13052
|
+
modality: "AUDIO",
|
|
13053
|
+
unit: ctx.model.usage.unit,
|
|
13054
|
+
quantity: 1
|
|
13055
|
+
};
|
|
13056
|
+
}
|
|
13057
|
+
function audioMime2(res, format) {
|
|
13058
|
+
const header = res.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase();
|
|
13059
|
+
if (header?.startsWith("audio/")) return header;
|
|
13060
|
+
return format === "wav" ? "audio/wav" : "audio/mpeg";
|
|
13061
|
+
}
|
|
13062
|
+
async function generateSpeech2(req, ctx) {
|
|
13063
|
+
checkRow2(ctx, "speech");
|
|
13064
|
+
const format = req.outputFormat ?? "mp3";
|
|
13065
|
+
const body = { text: req.text, format };
|
|
13066
|
+
const voice = req.customVoice ?? req.voice;
|
|
13067
|
+
if (voice !== void 0) {
|
|
13068
|
+
body.reference_id = checkVoiceId2(ctx, req.customVoice ? "customVoice" : "voice", voice);
|
|
13069
|
+
}
|
|
13070
|
+
if (req.language !== void 0) body.language = req.language;
|
|
13071
|
+
const { bytes, mime } = await withRetry(
|
|
13072
|
+
async () => {
|
|
13073
|
+
const res = await fishFetch(ctx, "/v1/tts", {
|
|
13074
|
+
method: "POST",
|
|
13075
|
+
headers: { "Content-Type": "application/json", model: ctx.model.providerModelId },
|
|
13076
|
+
body: JSON.stringify(body)
|
|
13077
|
+
});
|
|
13078
|
+
let audio;
|
|
13079
|
+
try {
|
|
13080
|
+
audio = new Uint8Array(await res.arrayBuffer());
|
|
13081
|
+
} catch (cause) {
|
|
13082
|
+
throw classifyThrown("fish", cause, ctx.model.id);
|
|
13083
|
+
}
|
|
13084
|
+
return { bytes: audio, mime: audioMime2(res, format) };
|
|
13085
|
+
},
|
|
13086
|
+
mediaRetryOptions(ctx.call, ctx.signal)
|
|
13087
|
+
);
|
|
13088
|
+
if (bytes.byteLength === 0)
|
|
13089
|
+
throw fishError(ctx, "provider_rejected", "Fish TTS returned no audio");
|
|
13090
|
+
return { audio: { bytes, mime }, usage: usage3(ctx) };
|
|
13091
|
+
}
|
|
13092
|
+
var createdModelSchema = z22.object({
|
|
13093
|
+
_id: z22.string().min(1),
|
|
13094
|
+
state: z22.enum(["created", "training", "trained", "failed"]).optional().catch(void 0)
|
|
13095
|
+
});
|
|
13096
|
+
function fileName2(index, mime) {
|
|
13097
|
+
const ext = mime.split("/")[1]?.replace("mpeg", "mp3").replace("x-", "") || "bin";
|
|
13098
|
+
return `sample-${index + 1}.${ext}`;
|
|
13099
|
+
}
|
|
13100
|
+
function allOrNone(ctx, field, values) {
|
|
13101
|
+
const set = values.filter((v) => v !== void 0 && v.trim() !== "");
|
|
13102
|
+
if (set.length === 0) return [];
|
|
13103
|
+
if (set.length !== values.length) {
|
|
13104
|
+
throw fishError(ctx, "missing_input", `set ${field} on every sample or on none`);
|
|
13105
|
+
}
|
|
13106
|
+
return set;
|
|
13107
|
+
}
|
|
13108
|
+
async function cloneForm2(req, ctx) {
|
|
13109
|
+
if (req.samples.length === 0) throw fishError(ctx, "missing_input", "needs a voice sample");
|
|
13110
|
+
const transcripts = allOrNone(
|
|
13111
|
+
ctx,
|
|
13112
|
+
"transcript",
|
|
13113
|
+
req.samples.map((s) => s.transcript)
|
|
13114
|
+
);
|
|
13115
|
+
const signatures = allOrNone(
|
|
13116
|
+
ctx,
|
|
13117
|
+
"designSignature",
|
|
13118
|
+
req.samples.map((s) => s.designSignature)
|
|
13119
|
+
);
|
|
13120
|
+
const form = new FormData();
|
|
13121
|
+
form.append("type", "tts");
|
|
13122
|
+
form.append("train_mode", "fast");
|
|
13123
|
+
form.append("visibility", "private");
|
|
13124
|
+
form.append("title", req.title.trim());
|
|
13125
|
+
if (req.description?.trim()) form.append("description", req.description.trim());
|
|
13126
|
+
if (req.enhance !== void 0) form.append("enhance_audio_quality", String(req.enhance));
|
|
13127
|
+
for (const [index, sample] of req.samples.entries()) {
|
|
13128
|
+
const { bytes, mime } = await mediaRefToBytes(sample.audio, ctx.fetch, {
|
|
13129
|
+
signal: ctx.signal,
|
|
13130
|
+
provider: "fish",
|
|
13131
|
+
model: ctx.model.id
|
|
13132
|
+
});
|
|
13133
|
+
const audio = new Blob([new Uint8Array(bytes)], { type: mime });
|
|
13134
|
+
form.append("voices", audio, fileName2(index, mime));
|
|
13135
|
+
}
|
|
13136
|
+
for (const text2 of transcripts) form.append("texts", text2.trim());
|
|
13137
|
+
for (const signature of signatures) form.append("voice_design_signatures", signature);
|
|
13138
|
+
return form;
|
|
13139
|
+
}
|
|
13140
|
+
async function onlyRateLimitRetries2(fn) {
|
|
13141
|
+
try {
|
|
13142
|
+
return await fn();
|
|
13143
|
+
} catch (cause) {
|
|
13144
|
+
if (!isModelKitError(cause) || !cause.retryable || cause.code === "rate_limited")
|
|
13145
|
+
throw cause;
|
|
13146
|
+
throw new ModelKitError({
|
|
13147
|
+
code: cause.code,
|
|
13148
|
+
message: cause.message,
|
|
13149
|
+
...cause.provider !== void 0 && { provider: cause.provider },
|
|
13150
|
+
...cause.model !== void 0 && { model: cause.model },
|
|
13151
|
+
...cause.status !== void 0 && { status: cause.status },
|
|
13152
|
+
...cause.body !== void 0 && { body: cause.body },
|
|
13153
|
+
cause,
|
|
13154
|
+
retryable: false
|
|
13155
|
+
});
|
|
13156
|
+
}
|
|
13157
|
+
}
|
|
13158
|
+
async function createVoice2(req, ctx) {
|
|
13159
|
+
checkRow2(ctx, "voice-clone");
|
|
13160
|
+
const form = await cloneForm2(req, ctx);
|
|
13161
|
+
const res = await withRetry(
|
|
13162
|
+
() => onlyRateLimitRetries2(() => fishFetch(ctx, "/model", { method: "POST", body: form })),
|
|
13163
|
+
mediaRetryOptions(ctx.call, ctx.signal)
|
|
13164
|
+
);
|
|
13165
|
+
const raw = await readBody(res);
|
|
13166
|
+
const parsed = createdModelSchema.safeParse(raw);
|
|
13167
|
+
if (!parsed.success) {
|
|
13168
|
+
throw new ModelKitError({
|
|
13169
|
+
code: "provider_rejected",
|
|
13170
|
+
message: "Fish returned no voice id",
|
|
13171
|
+
provider: "fish",
|
|
13172
|
+
model: ctx.model.id,
|
|
13173
|
+
status: res.status,
|
|
13174
|
+
body: raw,
|
|
13175
|
+
retryable: false
|
|
13176
|
+
});
|
|
13177
|
+
}
|
|
13178
|
+
const result = { voiceId: parsed.data._id, usage: usage3(ctx), raw };
|
|
13179
|
+
if (parsed.data.state !== void 0) result.state = parsed.data.state;
|
|
13180
|
+
return result;
|
|
13181
|
+
}
|
|
13182
|
+
var designSchema = z22.object({
|
|
13183
|
+
candidates: z22.array(
|
|
13184
|
+
z22.looseObject({
|
|
13185
|
+
id: z22.string().min(1),
|
|
13186
|
+
index: z22.number().int(),
|
|
13187
|
+
audio_base64: z22.string().min(1),
|
|
13188
|
+
duration_ms: z22.number().nonnegative(),
|
|
13189
|
+
signature: z22.string().min(1).optional()
|
|
13190
|
+
})
|
|
13191
|
+
).min(1)
|
|
13192
|
+
});
|
|
13193
|
+
async function designVoice(req, ctx) {
|
|
13194
|
+
checkRow2(ctx, "voice-design");
|
|
13195
|
+
const body = { instruction: req.prompt.trim() };
|
|
13196
|
+
if (req.previewText?.trim()) body.reference_text = req.previewText.trim();
|
|
13197
|
+
if (req.language !== void 0) body.language = req.language;
|
|
13198
|
+
if (req.count !== void 0) body.n = req.count;
|
|
13199
|
+
if (req.seed !== void 0) body.seed = req.seed;
|
|
13200
|
+
const raw = await withRetry(
|
|
13201
|
+
async () => {
|
|
13202
|
+
const res = await fishFetch(ctx, "/v1/voice-design", {
|
|
13203
|
+
method: "POST",
|
|
13204
|
+
headers: { "Content-Type": "application/json", model: ctx.model.providerModelId },
|
|
13205
|
+
body: JSON.stringify(body)
|
|
13206
|
+
});
|
|
13207
|
+
return readBody(res);
|
|
13208
|
+
},
|
|
13209
|
+
mediaRetryOptions(ctx.call, ctx.signal)
|
|
13210
|
+
);
|
|
13211
|
+
const parsed = designSchema.safeParse(raw);
|
|
13212
|
+
if (!parsed.success) {
|
|
13213
|
+
throw fishError(ctx, "provider_rejected", "Fish voice design returned no candidates");
|
|
13214
|
+
}
|
|
13215
|
+
const candidates = [...parsed.data.candidates].sort((a, b) => a.index - b.index).map((c) => ({
|
|
13216
|
+
audio: { bytes: base64ToBytes(c.audio_base64), mime: "audio/wav" },
|
|
13217
|
+
durationSeconds: c.duration_ms / 1e3,
|
|
13218
|
+
// The OpenAPI candidate has no signature field, so its stable id is the handle; Fish
|
|
13219
|
+
// rejects a clone whose signature does not verify, so a wrong one fails loudly.
|
|
13220
|
+
signature: c.signature ?? c.id
|
|
13221
|
+
}));
|
|
13222
|
+
return { candidates, usage: usage3(ctx) };
|
|
13223
|
+
}
|
|
13224
|
+
async function deleteVoice2(req, ctx) {
|
|
13225
|
+
checkRow2(ctx, "voice-clone");
|
|
13226
|
+
const id = encodeURIComponent(checkVoiceId2(ctx, "voiceId", req.voiceId));
|
|
13227
|
+
let attempts = 0;
|
|
13228
|
+
await withRetry(
|
|
13229
|
+
async () => {
|
|
13230
|
+
attempts += 1;
|
|
13231
|
+
try {
|
|
13232
|
+
await fishFetch(ctx, `/model/${id}`, { method: "DELETE" });
|
|
13233
|
+
} catch (cause) {
|
|
13234
|
+
if (!isModelKitError(cause) || cause.status !== 404) throw cause;
|
|
13235
|
+
if (attempts > 1) return;
|
|
13236
|
+
throw new ModelKitError({
|
|
13237
|
+
code: "provider_rejected",
|
|
13238
|
+
message: `Fish has no voice ${req.voiceId} under this key set; delete with the tier that created it`,
|
|
13239
|
+
provider: "fish",
|
|
13240
|
+
model: ctx.model.id,
|
|
13241
|
+
status: 404,
|
|
13242
|
+
cause,
|
|
13243
|
+
retryable: false
|
|
13244
|
+
});
|
|
13245
|
+
}
|
|
13246
|
+
},
|
|
13247
|
+
mediaRetryOptions(ctx.call, ctx.signal)
|
|
13248
|
+
);
|
|
13249
|
+
}
|
|
13250
|
+
var fishAdapter = {
|
|
13251
|
+
id: "fish",
|
|
13252
|
+
generateSpeech: generateSpeech2,
|
|
13253
|
+
createVoice: createVoice2,
|
|
13254
|
+
designVoice,
|
|
13255
|
+
deleteVoice: deleteVoice2
|
|
13256
|
+
};
|
|
13257
|
+
|
|
13258
|
+
// src/adapters/google-genai.ts
|
|
13259
|
+
import { z as z24 } from "zod";
|
|
12330
13260
|
import {
|
|
12331
13261
|
GoogleGenAI
|
|
12332
13262
|
} from "@google/genai";
|
|
12333
13263
|
|
|
12334
13264
|
// src/adapters/google-files.ts
|
|
12335
|
-
import { z as
|
|
13265
|
+
import { z as z23 } from "zod";
|
|
12336
13266
|
var GOOGLE_FILES_BASE = "https://generativelanguage.googleapis.com";
|
|
12337
13267
|
var GOOGLE_FILES_POLL_INTERVAL_MS = 2e3;
|
|
12338
13268
|
var GOOGLE_FILES_POLL_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
@@ -12342,17 +13272,17 @@ var GENERIC_MEDIA_TYPES = /* @__PURE__ */ new Set([
|
|
|
12342
13272
|
"binary/octet-stream",
|
|
12343
13273
|
"application/binary"
|
|
12344
13274
|
]);
|
|
12345
|
-
var uploadedFileSchema =
|
|
12346
|
-
file:
|
|
12347
|
-
uri:
|
|
12348
|
-
name:
|
|
12349
|
-
state:
|
|
12350
|
-
mimeType:
|
|
13275
|
+
var uploadedFileSchema = z23.object({
|
|
13276
|
+
file: z23.object({
|
|
13277
|
+
uri: z23.string().optional(),
|
|
13278
|
+
name: z23.string().optional(),
|
|
13279
|
+
state: z23.string().optional(),
|
|
13280
|
+
mimeType: z23.string().optional()
|
|
12351
13281
|
}).optional()
|
|
12352
13282
|
});
|
|
12353
|
-
var fileStateSchema =
|
|
12354
|
-
state:
|
|
12355
|
-
error:
|
|
13283
|
+
var fileStateSchema = z23.object({
|
|
13284
|
+
state: z23.string().optional(),
|
|
13285
|
+
error: z23.object({ message: z23.string().optional() }).optional()
|
|
12356
13286
|
});
|
|
12357
13287
|
function resolveMime(declared, fallback) {
|
|
12358
13288
|
const clean = declared?.split(";")[0]?.trim().toLowerCase();
|
|
@@ -12459,7 +13389,7 @@ async function startAndUpload(bytes, mimeType, opts) {
|
|
|
12459
13389
|
if (uploaded.file?.state !== void 0) ref.state = uploaded.file.state;
|
|
12460
13390
|
return ref;
|
|
12461
13391
|
}
|
|
12462
|
-
async function waitForActive(
|
|
13392
|
+
async function waitForActive(fileName3, opts) {
|
|
12463
13393
|
const pollOptions2 = {
|
|
12464
13394
|
intervalMs: GOOGLE_FILES_POLL_INTERVAL_MS,
|
|
12465
13395
|
timeoutMs: GOOGLE_FILES_POLL_TIMEOUT_MS
|
|
@@ -12472,14 +13402,14 @@ async function waitForActive(fileName, opts) {
|
|
|
12472
13402
|
retryInit.signal = opts.signal;
|
|
12473
13403
|
}
|
|
12474
13404
|
await pollUntil(async () => {
|
|
12475
|
-
const res = await opts.fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${
|
|
13405
|
+
const res = await opts.fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName3}`, retryInit);
|
|
12476
13406
|
if (res.ok) {
|
|
12477
13407
|
const json = fileStateSchema.parse(await res.json());
|
|
12478
13408
|
if (json.state === "ACTIVE") return true;
|
|
12479
13409
|
if (json.state === "FAILED") {
|
|
12480
13410
|
throw classifyHttpError(
|
|
12481
13411
|
void 0,
|
|
12482
|
-
`Files API processing failed for ${
|
|
13412
|
+
`Files API processing failed for ${fileName3}: ${json.error?.message ?? "unknown error"}`,
|
|
12483
13413
|
"google-genai",
|
|
12484
13414
|
opts.model
|
|
12485
13415
|
);
|
|
@@ -12491,9 +13421,9 @@ async function waitForActive(fileName, opts) {
|
|
|
12491
13421
|
throw classifyHttpError(res.status, text2, "google-genai", opts.model);
|
|
12492
13422
|
}, pollOptions2);
|
|
12493
13423
|
}
|
|
12494
|
-
async function deleteGoogleFile(
|
|
13424
|
+
async function deleteGoogleFile(fileName3, apiKey, fetchImpl) {
|
|
12495
13425
|
try {
|
|
12496
|
-
await fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${
|
|
13426
|
+
await fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName3}`, {
|
|
12497
13427
|
method: "DELETE",
|
|
12498
13428
|
headers: { "x-goog-api-key": apiKey }
|
|
12499
13429
|
});
|
|
@@ -12573,7 +13503,7 @@ var OMNI_POLL_INTERVAL_MS = 1e4;
|
|
|
12573
13503
|
var RESULT_TIMEOUT_MS3 = 15 * 60 * 1e3;
|
|
12574
13504
|
var OMNI_INLINE_LIMIT_BYTES = 4 * 1024 * 1024;
|
|
12575
13505
|
var MEDIA_PART_INLINE_LIMIT_BYTES = 10 * 1024 * 1024;
|
|
12576
|
-
var errorTextSchema =
|
|
13506
|
+
var errorTextSchema = z24.string();
|
|
12577
13507
|
function isGoogleGenaiVideoKnown(providerModelId) {
|
|
12578
13508
|
return providerModelId.startsWith("veo-") || providerModelId.startsWith("gemini-omni");
|
|
12579
13509
|
}
|
|
@@ -12768,7 +13698,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
|
|
|
12768
13698
|
}
|
|
12769
13699
|
};
|
|
12770
13700
|
const jobId = operation.name ?? crypto.randomUUID();
|
|
12771
|
-
const
|
|
13701
|
+
const usage5 = videoUsage2(ctx, duration, req.resolution ?? "720p");
|
|
12772
13702
|
return {
|
|
12773
13703
|
jobId,
|
|
12774
13704
|
async poll() {
|
|
@@ -12806,7 +13736,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
|
|
|
12806
13736
|
modelId
|
|
12807
13737
|
);
|
|
12808
13738
|
}
|
|
12809
|
-
return { video: await downloadVideo(ctx, uri, apiKey, signal), usage:
|
|
13739
|
+
return { video: await downloadVideo(ctx, uri, apiKey, signal), usage: usage5, raw: finished };
|
|
12810
13740
|
}
|
|
12811
13741
|
};
|
|
12812
13742
|
}
|
|
@@ -12917,7 +13847,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
|
|
|
12917
13847
|
return file.fileUri;
|
|
12918
13848
|
};
|
|
12919
13849
|
const cleanupUploads = async () => {
|
|
12920
|
-
for (const
|
|
13850
|
+
for (const fileName3 of uploadedNames) await deleteGoogleFile(fileName3, apiKey, ctx.fetch);
|
|
12921
13851
|
};
|
|
12922
13852
|
const callCreate = (input) => client2.interactions.create(
|
|
12923
13853
|
previousId !== void 0 ? {
|
|
@@ -13011,7 +13941,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
|
|
|
13011
13941
|
if (!(extend && !chained)) await cleanupUploads();
|
|
13012
13942
|
}
|
|
13013
13943
|
const jobId = interaction.id ?? crypto.randomUUID();
|
|
13014
|
-
const
|
|
13944
|
+
const usage5 = videoUsage2(ctx, duration, omniResolution ?? "720p");
|
|
13015
13945
|
const getInteraction = async () => {
|
|
13016
13946
|
try {
|
|
13017
13947
|
const getParams = { stream: false };
|
|
@@ -13059,7 +13989,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
|
|
|
13059
13989
|
bytes: Buffer.from(video.data, "base64"),
|
|
13060
13990
|
mime: video.mime_type ?? "video/mp4"
|
|
13061
13991
|
},
|
|
13062
|
-
usage:
|
|
13992
|
+
usage: usage5,
|
|
13063
13993
|
raw: done,
|
|
13064
13994
|
providerRef
|
|
13065
13995
|
};
|
|
@@ -13067,7 +13997,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
|
|
|
13067
13997
|
if (video.uri)
|
|
13068
13998
|
return {
|
|
13069
13999
|
video: await downloadVideo(ctx, video.uri, apiKey, signal),
|
|
13070
|
-
usage:
|
|
14000
|
+
usage: usage5,
|
|
13071
14001
|
raw: done,
|
|
13072
14002
|
providerRef
|
|
13073
14003
|
};
|
|
@@ -13237,15 +14167,15 @@ async function prepareGoogleMediaPart(ref, mediaType, ctx) {
|
|
|
13237
14167
|
// src/adapters/google-image.ts
|
|
13238
14168
|
import { createGoogleGenerativeAI as createGoogleGenerativeAI2 } from "@ai-sdk/google";
|
|
13239
14169
|
import { generateText } from "ai";
|
|
13240
|
-
import { z as
|
|
14170
|
+
import { z as z25 } from "zod";
|
|
13241
14171
|
var GEMINI_IMAGE_TIMEOUT_MS = 6e5;
|
|
13242
14172
|
var defaultGoogleImageDeps = {
|
|
13243
14173
|
createGoogleClient: (opts) => createGoogleGenerativeAI2(opts),
|
|
13244
14174
|
runTextGeneration: (opts) => generateText(opts)
|
|
13245
14175
|
};
|
|
13246
|
-
var causeChainNodeSchema =
|
|
13247
|
-
message:
|
|
13248
|
-
cause:
|
|
14176
|
+
var causeChainNodeSchema = z25.object({
|
|
14177
|
+
message: z25.string().optional(),
|
|
14178
|
+
cause: z25.unknown().optional()
|
|
13249
14179
|
});
|
|
13250
14180
|
function extractBlockReason(cause) {
|
|
13251
14181
|
let current = cause;
|
|
@@ -13345,7 +14275,7 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
|
|
|
13345
14275
|
retryable: false
|
|
13346
14276
|
});
|
|
13347
14277
|
}
|
|
13348
|
-
const
|
|
14278
|
+
const usage5 = {
|
|
13349
14279
|
model: ctx.model.id,
|
|
13350
14280
|
provider: "google-image",
|
|
13351
14281
|
modality: "IMAGE",
|
|
@@ -13353,19 +14283,19 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
|
|
|
13353
14283
|
quantity: images.length,
|
|
13354
14284
|
imageQuality: "auto"
|
|
13355
14285
|
};
|
|
13356
|
-
if (req.size !== void 0)
|
|
14286
|
+
if (req.size !== void 0) usage5.imageSize = req.size;
|
|
13357
14287
|
if (result.usage?.inputTokens !== void 0)
|
|
13358
|
-
|
|
14288
|
+
usage5.inputTokens = result.usage.inputTokens;
|
|
13359
14289
|
if (result.usage?.outputTokens !== void 0)
|
|
13360
|
-
|
|
13361
|
-
return { images, usage:
|
|
14290
|
+
usage5.outputTokens = result.usage.outputTokens;
|
|
14291
|
+
return { images, usage: usage5, raw: result };
|
|
13362
14292
|
}
|
|
13363
14293
|
};
|
|
13364
14294
|
}
|
|
13365
14295
|
var googleImageAdapter = createGoogleImageAdapter();
|
|
13366
14296
|
|
|
13367
14297
|
// src/adapters/higgsfield.ts
|
|
13368
|
-
import { z as
|
|
14298
|
+
import { z as z26 } from "zod";
|
|
13369
14299
|
|
|
13370
14300
|
// src/adapters/higgsfield-motions.ts
|
|
13371
14301
|
var MOTION_MAP = {
|
|
@@ -13584,14 +14514,14 @@ function klingEndpointFields(providerModelId) {
|
|
|
13584
14514
|
const path = (providerModelId.startsWith("/") ? providerModelId.slice(1) : providerModelId).toLowerCase();
|
|
13585
14515
|
return KLING_ENDPOINT_FIELDS.get(path) ?? UNLISTED_KLING_FIELDS;
|
|
13586
14516
|
}
|
|
13587
|
-
var klingCreateSchema =
|
|
13588
|
-
var klingStatusSchema =
|
|
13589
|
-
status:
|
|
13590
|
-
video:
|
|
14517
|
+
var klingCreateSchema = z26.object({ status_url: z26.string() });
|
|
14518
|
+
var klingStatusSchema = z26.object({
|
|
14519
|
+
status: z26.string().optional(),
|
|
14520
|
+
video: z26.object({ url: z26.string().optional() }).optional(),
|
|
13591
14521
|
error: JsonValueSchema.optional()
|
|
13592
14522
|
});
|
|
13593
|
-
var errorMessageSchema =
|
|
13594
|
-
var textValueSchema =
|
|
14523
|
+
var errorMessageSchema = z26.object({ message: z26.string().optional() });
|
|
14524
|
+
var textValueSchema = z26.string();
|
|
13595
14525
|
function klingErrorDetail(error) {
|
|
13596
14526
|
if (error === void 0) return "unknown_error";
|
|
13597
14527
|
const asText = textValueSchema.safeParse(error);
|
|
@@ -13747,8 +14677,8 @@ async function generateKlingVideo(req, ctx) {
|
|
|
13747
14677
|
}
|
|
13748
14678
|
};
|
|
13749
14679
|
}
|
|
13750
|
-
var dopMotionOptionsSchema =
|
|
13751
|
-
modelkit:
|
|
14680
|
+
var dopMotionOptionsSchema = z26.object({
|
|
14681
|
+
modelkit: z26.object({ motion: z26.string().optional() }).optional()
|
|
13752
14682
|
});
|
|
13753
14683
|
function dopMotionId(ctx) {
|
|
13754
14684
|
const parsed = dopMotionOptionsSchema.safeParse(ctx.model.providerOptions);
|
|
@@ -13764,7 +14694,7 @@ function dopMotionId(ctx) {
|
|
|
13764
14694
|
});
|
|
13765
14695
|
return id;
|
|
13766
14696
|
}
|
|
13767
|
-
var jsonRecordSchema =
|
|
14697
|
+
var jsonRecordSchema = z26.record(z26.string(), JsonValueSchema);
|
|
13768
14698
|
var DOP_URL_KEYS = ["url", "video_url", "output_url", "result_url", "download_url"];
|
|
13769
14699
|
var DOP_NESTED_KEYS = ["video", "result", "results"];
|
|
13770
14700
|
function dopUrl(body) {
|
|
@@ -13792,8 +14722,8 @@ function dopUrl(body) {
|
|
|
13792
14722
|
}
|
|
13793
14723
|
return void 0;
|
|
13794
14724
|
}
|
|
13795
|
-
var dopCreateSchema =
|
|
13796
|
-
var dopStatusSchema =
|
|
14725
|
+
var dopCreateSchema = z26.object({ id: z26.string() });
|
|
14726
|
+
var dopStatusSchema = z26.object({ status: z26.string().optional() });
|
|
13797
14727
|
async function generateDopVideo(req, ctx) {
|
|
13798
14728
|
const firstFrame = req.firstFrame ? refToUrl(req.firstFrame) : void 0;
|
|
13799
14729
|
if (!firstFrame) {
|
|
@@ -13920,7 +14850,7 @@ var higgsfieldAdapter = {
|
|
|
13920
14850
|
};
|
|
13921
14851
|
|
|
13922
14852
|
// src/adapters/luma.ts
|
|
13923
|
-
import { z as
|
|
14853
|
+
import { z as z27 } from "zod";
|
|
13924
14854
|
|
|
13925
14855
|
// src/adapters/mp4-duration.ts
|
|
13926
14856
|
function mp4DurationSeconds(bytes) {
|
|
@@ -13976,7 +14906,7 @@ function findBox(bytes, from, to, type) {
|
|
|
13976
14906
|
}
|
|
13977
14907
|
|
|
13978
14908
|
// src/adapters/luma.ts
|
|
13979
|
-
var
|
|
14909
|
+
var DEFAULT_BASE_URL3 = "https://agents.lumalabs.ai";
|
|
13980
14910
|
var IMAGE_POLL_INTERVAL_MS = 3e3;
|
|
13981
14911
|
var IMAGE_TIMEOUT_MS = 5 * 6e4;
|
|
13982
14912
|
var VIDEO_POLL_INTERVAL_MS = 5e3;
|
|
@@ -14005,7 +14935,7 @@ function lumaModel(ctx) {
|
|
|
14005
14935
|
return ctx.model.providerModelId.toLowerCase();
|
|
14006
14936
|
}
|
|
14007
14937
|
function lumaBase(ctx) {
|
|
14008
|
-
return ctx.endpoints?.luma ??
|
|
14938
|
+
return ctx.endpoints?.luma ?? DEFAULT_BASE_URL3;
|
|
14009
14939
|
}
|
|
14010
14940
|
function lumaKey(ctx) {
|
|
14011
14941
|
const key = ctx.keys.luma;
|
|
@@ -14137,17 +15067,17 @@ function lumaReframeResolution(req, ctx) {
|
|
|
14137
15067
|
});
|
|
14138
15068
|
return "720p";
|
|
14139
15069
|
}
|
|
14140
|
-
var lumaGenerationSchema =
|
|
14141
|
-
id:
|
|
14142
|
-
state:
|
|
14143
|
-
output:
|
|
14144
|
-
|
|
14145
|
-
type:
|
|
14146
|
-
url:
|
|
15070
|
+
var lumaGenerationSchema = z27.looseObject({
|
|
15071
|
+
id: z27.string(),
|
|
15072
|
+
state: z27.string().optional(),
|
|
15073
|
+
output: z27.array(
|
|
15074
|
+
z27.looseObject({
|
|
15075
|
+
type: z27.string().optional(),
|
|
15076
|
+
url: z27.string().optional()
|
|
14147
15077
|
})
|
|
14148
15078
|
).optional(),
|
|
14149
|
-
failure_reason:
|
|
14150
|
-
failure_code:
|
|
15079
|
+
failure_reason: z27.string().optional().nullable(),
|
|
15080
|
+
failure_code: z27.string().optional().nullable()
|
|
14151
15081
|
});
|
|
14152
15082
|
function lumaFailure(ctx, code, reason) {
|
|
14153
15083
|
const detail = reason ?? code ?? "unknown_error";
|
|
@@ -14579,7 +15509,7 @@ var lumaAdapter = {
|
|
|
14579
15509
|
|
|
14580
15510
|
// src/adapters/openai-image.ts
|
|
14581
15511
|
import OpenAI from "openai";
|
|
14582
|
-
import { z as
|
|
15512
|
+
import { z as z28 } from "zod";
|
|
14583
15513
|
var MAX_EDIT_REFERENCES = 16;
|
|
14584
15514
|
function aspectRatioToSize(ratio, tier) {
|
|
14585
15515
|
const TIER_LONG_EDGE = {
|
|
@@ -14662,9 +15592,9 @@ function toProviderError2(cause, ctx) {
|
|
|
14662
15592
|
ctx.model.id
|
|
14663
15593
|
);
|
|
14664
15594
|
}
|
|
14665
|
-
var openaiUsageSchema =
|
|
14666
|
-
input_tokens:
|
|
14667
|
-
output_tokens:
|
|
15595
|
+
var openaiUsageSchema = z28.object({
|
|
15596
|
+
input_tokens: z28.number().optional(),
|
|
15597
|
+
output_tokens: z28.number().optional()
|
|
14668
15598
|
});
|
|
14669
15599
|
var openaiImageAdapter = {
|
|
14670
15600
|
id: "openai-image",
|
|
@@ -14789,7 +15719,7 @@ var openaiImageAdapter = {
|
|
|
14789
15719
|
const usageParsed = openaiUsageSchema.safeParse(response.usage);
|
|
14790
15720
|
const inputTokens = usageParsed.success ? usageParsed.data.input_tokens : void 0;
|
|
14791
15721
|
const outputTokens = usageParsed.success ? usageParsed.data.output_tokens : void 0;
|
|
14792
|
-
const
|
|
15722
|
+
const usage5 = {
|
|
14793
15723
|
model: ctx.model.id,
|
|
14794
15724
|
provider: "openai-image",
|
|
14795
15725
|
modality: "IMAGE",
|
|
@@ -14797,10 +15727,10 @@ var openaiImageAdapter = {
|
|
|
14797
15727
|
quantity: images.length,
|
|
14798
15728
|
imageQuality: quality
|
|
14799
15729
|
};
|
|
14800
|
-
if (inputTokens !== void 0)
|
|
14801
|
-
if (outputTokens !== void 0)
|
|
14802
|
-
if (req.size !== void 0)
|
|
14803
|
-
return { images, usage:
|
|
15730
|
+
if (inputTokens !== void 0) usage5.inputTokens = inputTokens;
|
|
15731
|
+
if (outputTokens !== void 0) usage5.outputTokens = outputTokens;
|
|
15732
|
+
if (req.size !== void 0) usage5.imageSize = req.size;
|
|
15733
|
+
return { images, usage: usage5, raw: response };
|
|
14804
15734
|
}
|
|
14805
15735
|
};
|
|
14806
15736
|
|
|
@@ -15056,16 +15986,16 @@ async function generateProdiaImage(req, ctx) {
|
|
|
15056
15986
|
new Uint8Array(await res.arrayBuffer()),
|
|
15057
15987
|
res.headers.get("content-type")
|
|
15058
15988
|
);
|
|
15059
|
-
const
|
|
15989
|
+
const usage5 = {
|
|
15060
15990
|
model: ctx.model.id,
|
|
15061
15991
|
provider: "prodia",
|
|
15062
15992
|
modality: "IMAGE",
|
|
15063
15993
|
unit: "images",
|
|
15064
15994
|
quantity: 1
|
|
15065
15995
|
};
|
|
15066
|
-
if (req.size !== void 0)
|
|
15067
|
-
if (req.quality !== void 0)
|
|
15068
|
-
return { images: [{ bytes, mime }], usage:
|
|
15996
|
+
if (req.size !== void 0) usage5.imageSize = req.size;
|
|
15997
|
+
if (req.quality !== void 0) usage5.imageQuality = req.quality;
|
|
15998
|
+
return { images: [{ bytes, mime }], usage: usage5, raw: void 0 };
|
|
15069
15999
|
}
|
|
15070
16000
|
var prodiaAdapter = {
|
|
15071
16001
|
id: "prodia",
|
|
@@ -15076,13 +16006,13 @@ var prodiaAdapter = {
|
|
|
15076
16006
|
import Replicate from "replicate";
|
|
15077
16007
|
|
|
15078
16008
|
// src/adapters/replicate-http.ts
|
|
15079
|
-
import { z as
|
|
15080
|
-
var predictionSchema =
|
|
15081
|
-
id:
|
|
15082
|
-
status:
|
|
16009
|
+
import { z as z29 } from "zod";
|
|
16010
|
+
var predictionSchema = z29.object({
|
|
16011
|
+
id: z29.string(),
|
|
16012
|
+
status: z29.string(),
|
|
15083
16013
|
output: JsonValueSchema.optional(),
|
|
15084
16014
|
error: JsonValueSchema.optional(),
|
|
15085
|
-
metrics:
|
|
16015
|
+
metrics: z29.object({ predict_time: z29.number().optional() }).optional()
|
|
15086
16016
|
});
|
|
15087
16017
|
function createReplicateHttpClient(opts) {
|
|
15088
16018
|
async function request(path, body, signal) {
|
|
@@ -15133,7 +16063,7 @@ function createReplicateHttpClient(opts) {
|
|
|
15133
16063
|
}
|
|
15134
16064
|
|
|
15135
16065
|
// src/adapters/replicate.ts
|
|
15136
|
-
import { z as
|
|
16066
|
+
import { z as z30 } from "zod";
|
|
15137
16067
|
var POLL_INTERVAL_MS = 1e3;
|
|
15138
16068
|
var POLL_TIMEOUT_MS = 15 * 6e4;
|
|
15139
16069
|
var defaultReplicateDeps = {
|
|
@@ -15173,8 +16103,8 @@ function route(providerModelId) {
|
|
|
15173
16103
|
if (!providerModelId.includes("/")) return { version: providerModelId };
|
|
15174
16104
|
return { model: providerModelId };
|
|
15175
16105
|
}
|
|
15176
|
-
var replicateResponseStatusSchema =
|
|
15177
|
-
response:
|
|
16106
|
+
var replicateResponseStatusSchema = z30.object({
|
|
16107
|
+
response: z30.object({ status: z30.number() }).partial()
|
|
15178
16108
|
});
|
|
15179
16109
|
function replicateError(cause, ctx) {
|
|
15180
16110
|
if (isModelKitError(cause)) return cause;
|
|
@@ -15197,7 +16127,7 @@ function isUrlFn(value) {
|
|
|
15197
16127
|
function extractOutputUrl(output) {
|
|
15198
16128
|
const root = Array.isArray(output) ? output[0] : output;
|
|
15199
16129
|
if (root === void 0) throw noOutput();
|
|
15200
|
-
const asString =
|
|
16130
|
+
const asString = z30.string().safeParse(root);
|
|
15201
16131
|
if (asString.success && asString.data) return asString.data;
|
|
15202
16132
|
if (root instanceof URL) return root.href;
|
|
15203
16133
|
if (isObjectOutput(root)) {
|
|
@@ -15206,15 +16136,15 @@ function extractOutputUrl(output) {
|
|
|
15206
16136
|
if (urlValue !== void 0 && isUrlFn(urlValue)) {
|
|
15207
16137
|
const called = urlValue();
|
|
15208
16138
|
if (called instanceof URL) return called.href;
|
|
15209
|
-
const calledString =
|
|
16139
|
+
const calledString = z30.string().safeParse(called);
|
|
15210
16140
|
if (calledString.success && calledString.data) return calledString.data;
|
|
15211
16141
|
} else {
|
|
15212
|
-
const direct =
|
|
16142
|
+
const direct = z30.string().safeParse(urlValue);
|
|
15213
16143
|
if (direct.success && direct.data) return direct.data;
|
|
15214
16144
|
}
|
|
15215
16145
|
}
|
|
15216
16146
|
if ("default" in root) {
|
|
15217
|
-
const fallback =
|
|
16147
|
+
const fallback = z30.string().safeParse(root.default);
|
|
15218
16148
|
if (fallback.success && fallback.data) return fallback.data;
|
|
15219
16149
|
}
|
|
15220
16150
|
}
|
|
@@ -15275,7 +16205,7 @@ async function runPrediction(ctx, input, deps) {
|
|
|
15275
16205
|
}
|
|
15276
16206
|
return void 0;
|
|
15277
16207
|
}, pollOpts);
|
|
15278
|
-
const predictTime =
|
|
16208
|
+
const predictTime = z30.number().safeParse(done.metrics?.predict_time);
|
|
15279
16209
|
if (done.output === void 0) throw noOutput();
|
|
15280
16210
|
return {
|
|
15281
16211
|
url: extractOutputUrl(done.output),
|
|
@@ -15521,9 +16451,9 @@ async function generateReplicateImage(req, ctx, deps) {
|
|
|
15521
16451
|
}
|
|
15522
16452
|
const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
|
|
15523
16453
|
const file = await download(ctx, url);
|
|
15524
|
-
const
|
|
15525
|
-
|
|
15526
|
-
return { images: [{ bytes: file.bytes, mime: file.mime }], usage:
|
|
16454
|
+
const usage5 = imageUsage3(ctx, req);
|
|
16455
|
+
usage5.quantity = predictTime;
|
|
16456
|
+
return { images: [{ bytes: file.bytes, mime: file.mime }], usage: usage5, raw, outputUrl: url };
|
|
15527
16457
|
}
|
|
15528
16458
|
function klingInput(req) {
|
|
15529
16459
|
const images = (req.firstFrame ? [req.firstFrame] : []).map(refToUrl);
|
|
@@ -15628,7 +16558,7 @@ async function generateReplicateVideo(req, ctx, deps) {
|
|
|
15628
16558
|
throw replicateError(cause, ctx);
|
|
15629
16559
|
}
|
|
15630
16560
|
if (current.status === "succeeded") {
|
|
15631
|
-
const predictTime =
|
|
16561
|
+
const predictTime = z30.number().safeParse(current.metrics?.predict_time);
|
|
15632
16562
|
if (current.output === void 0) throw noOutput();
|
|
15633
16563
|
return {
|
|
15634
16564
|
url: extractOutputUrl(current.output),
|
|
@@ -15647,9 +16577,9 @@ async function generateReplicateVideo(req, ctx, deps) {
|
|
|
15647
16577
|
return void 0;
|
|
15648
16578
|
};
|
|
15649
16579
|
const toResult = (done) => {
|
|
15650
|
-
const
|
|
15651
|
-
|
|
15652
|
-
return { video: { url: done.url }, usage:
|
|
16580
|
+
const usage5 = videoUsage5(ctx, req);
|
|
16581
|
+
usage5.quantity = done.predictTime;
|
|
16582
|
+
return { video: { url: done.url }, usage: usage5, raw: done.raw };
|
|
15653
16583
|
};
|
|
15654
16584
|
return {
|
|
15655
16585
|
jobId,
|
|
@@ -15756,21 +16686,21 @@ async function generateReplicateAudio(req, ctx, deps) {
|
|
|
15756
16686
|
input = specResult.input;
|
|
15757
16687
|
}
|
|
15758
16688
|
const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
|
|
15759
|
-
const
|
|
16689
|
+
const usage5 = audioUsage(ctx, req);
|
|
15760
16690
|
if (ctx.model.usage.unit === "seconds") {
|
|
15761
16691
|
const seconds3 = elevenLabsMusicDuration(req.durationSeconds);
|
|
15762
|
-
|
|
15763
|
-
|
|
16692
|
+
usage5.quantity = seconds3;
|
|
16693
|
+
usage5.durationSeconds = seconds3;
|
|
15764
16694
|
} else {
|
|
15765
|
-
|
|
16695
|
+
usage5.quantity = predictTime;
|
|
15766
16696
|
}
|
|
15767
|
-
return { audio: { url }, usage:
|
|
16697
|
+
return { audio: { url }, usage: usage5, raw: predictionRaw(raw) };
|
|
15768
16698
|
}
|
|
15769
16699
|
|
|
15770
16700
|
// src/adapters/xai-video.ts
|
|
15771
16701
|
import { experimental_generateVideo } from "ai";
|
|
15772
16702
|
import { createXai as createXai2 } from "@ai-sdk/xai";
|
|
15773
|
-
import { z as
|
|
16703
|
+
import { z as z31 } from "zod";
|
|
15774
16704
|
var POLL_INTERVAL_MS2 = 1e4;
|
|
15775
16705
|
var POLL_TIMEOUT_MS2 = 15 * 6e4;
|
|
15776
16706
|
var defaultXaiDeps = {
|
|
@@ -15783,8 +16713,8 @@ function createXaiVideoAdapter(deps = defaultXaiDeps) {
|
|
|
15783
16713
|
};
|
|
15784
16714
|
}
|
|
15785
16715
|
var xaiVideoAdapter = createXaiVideoAdapter();
|
|
15786
|
-
var xaiResponseStatusSchema =
|
|
15787
|
-
response:
|
|
16716
|
+
var xaiResponseStatusSchema = z31.object({
|
|
16717
|
+
response: z31.object({ status: z31.number() }).partial()
|
|
15788
16718
|
});
|
|
15789
16719
|
function xaiError(cause, ctx) {
|
|
15790
16720
|
const info = describeThrown(cause);
|
|
@@ -15792,12 +16722,12 @@ function xaiError(cause, ctx) {
|
|
|
15792
16722
|
const status = info.status ?? (nested.success ? nested.data.response?.status : void 0);
|
|
15793
16723
|
return classifyThrown("xai-video", cause, ctx.model.id, { status, body: info.body });
|
|
15794
16724
|
}
|
|
15795
|
-
var xaiMetaSchema =
|
|
16725
|
+
var xaiMetaSchema = z31.object({
|
|
15796
16726
|
videoUrl: JsonValueSchema.optional(),
|
|
15797
16727
|
costInUsdTicks: JsonValueSchema.optional(),
|
|
15798
16728
|
duration: JsonValueSchema.optional()
|
|
15799
16729
|
});
|
|
15800
|
-
var xaiProviderMetadataSchema =
|
|
16730
|
+
var xaiProviderMetadataSchema = z31.object({ xai: xaiMetaSchema });
|
|
15801
16731
|
function metaOf(result) {
|
|
15802
16732
|
const parsed = xaiProviderMetadataSchema.partial().safeParse(result.providerMetadata);
|
|
15803
16733
|
if (!parsed.success) return {};
|
|
@@ -15909,12 +16839,12 @@ async function mapResult(ctx, req, result) {
|
|
|
15909
16839
|
if (first) {
|
|
15910
16840
|
return {
|
|
15911
16841
|
video: { bytes: Uint8Array.from(first.uint8Array), mime: first.mediaType },
|
|
15912
|
-
usage:
|
|
16842
|
+
usage: usage4(ctx, req, metaOf(result)),
|
|
15913
16843
|
raw: result.providerMetadata
|
|
15914
16844
|
};
|
|
15915
16845
|
}
|
|
15916
16846
|
const meta = metaOf(result);
|
|
15917
|
-
const videoUrl =
|
|
16847
|
+
const videoUrl = z31.string().safeParse(meta.videoUrl);
|
|
15918
16848
|
if (videoUrl.success && videoUrl.data) {
|
|
15919
16849
|
const res = await ctx.fetch(videoUrl.data);
|
|
15920
16850
|
if (!res.ok) {
|
|
@@ -15924,7 +16854,7 @@ async function mapResult(ctx, req, result) {
|
|
|
15924
16854
|
const mime = res.headers.get("content-type") ?? "video/mp4";
|
|
15925
16855
|
return {
|
|
15926
16856
|
video: { bytes: new Uint8Array(await res.arrayBuffer()), mime },
|
|
15927
|
-
usage:
|
|
16857
|
+
usage: usage4(ctx, req, meta),
|
|
15928
16858
|
raw: result.providerMetadata
|
|
15929
16859
|
};
|
|
15930
16860
|
}
|
|
@@ -15936,8 +16866,8 @@ async function mapResult(ctx, req, result) {
|
|
|
15936
16866
|
retryable: false
|
|
15937
16867
|
});
|
|
15938
16868
|
}
|
|
15939
|
-
function
|
|
15940
|
-
const costTicks =
|
|
16869
|
+
function usage4(ctx, req, meta) {
|
|
16870
|
+
const costTicks = z31.number().safeParse(meta.costInUsdTicks);
|
|
15941
16871
|
const cost = costTicks.success ? costTicks.data / 1e10 : void 0;
|
|
15942
16872
|
const event = {
|
|
15943
16873
|
model: ctx.model.id,
|
|
@@ -15976,7 +16906,9 @@ var DEFAULT_ADAPTERS = {
|
|
|
15976
16906
|
prodia: prodiaAdapter,
|
|
15977
16907
|
higgsfield: higgsfieldAdapter,
|
|
15978
16908
|
"xai-video": xaiVideoAdapter,
|
|
15979
|
-
luma: lumaAdapter
|
|
16909
|
+
luma: lumaAdapter,
|
|
16910
|
+
fish: fishAdapter,
|
|
16911
|
+
elevenlabs: elevenLabsAdapter
|
|
15980
16912
|
};
|
|
15981
16913
|
|
|
15982
16914
|
// src/catalog/data-only.ts
|
|
@@ -16000,6 +16932,8 @@ function adapterServesType(adapter, type) {
|
|
|
16000
16932
|
if (type === "dubbing") return adapter.dub !== void 0;
|
|
16001
16933
|
if (type === "lipsync") return adapter.lipsync !== void 0;
|
|
16002
16934
|
if (type === "transcription") return adapter.transcribe !== void 0;
|
|
16935
|
+
if (type === "voice-clone") return adapter.createVoice !== void 0;
|
|
16936
|
+
if (type === "voice-design") return adapter.designVoice !== void 0;
|
|
16003
16937
|
if (type === "video-tool") return adapter.submitVideoTool !== void 0;
|
|
16004
16938
|
if (type === "model3d") return adapter.submitModel3d !== void 0;
|
|
16005
16939
|
return adapter.languageModel !== void 0;
|
|
@@ -16013,12 +16947,15 @@ var FAL_NODE_TYPES = /* @__PURE__ */ new Set([
|
|
|
16013
16947
|
"transcription",
|
|
16014
16948
|
"mask"
|
|
16015
16949
|
]);
|
|
16950
|
+
function directSpeech(row2) {
|
|
16951
|
+
return (row2.adapter === "fish" || row2.adapter === "elevenlabs") && row2.type === "speech";
|
|
16952
|
+
}
|
|
16016
16953
|
function dataOnlyCapable(row2) {
|
|
16017
16954
|
const adapter = DEFAULT_ADAPTERS[row2.adapter];
|
|
16018
16955
|
if (!adapterServesType(adapter, row2.type)) {
|
|
16019
16956
|
return { ok: false, reason: `${row2.adapter} cannot serve ${row2.type} rows` };
|
|
16020
16957
|
}
|
|
16021
|
-
if (FAL_NODE_TYPES.has(row2.type) && row2.adapter !== "fal") {
|
|
16958
|
+
if (FAL_NODE_TYPES.has(row2.type) && row2.adapter !== "fal" && !directSpeech(row2)) {
|
|
16022
16959
|
return { ok: false, reason: `only fal serves ${row2.type} rows` };
|
|
16023
16960
|
}
|
|
16024
16961
|
switch (row2.adapter) {
|
|
@@ -16096,6 +17033,14 @@ function dataOnlyCapable(row2) {
|
|
|
16096
17033
|
const reason = lumaRowRefusal(row2);
|
|
16097
17034
|
return reason === void 0 ? { ok: true } : { ok: false, reason };
|
|
16098
17035
|
}
|
|
17036
|
+
case "fish": {
|
|
17037
|
+
const reason = fishRowRefusal(row2);
|
|
17038
|
+
return reason === void 0 ? { ok: true } : { ok: false, reason };
|
|
17039
|
+
}
|
|
17040
|
+
case "elevenlabs": {
|
|
17041
|
+
const reason = elevenLabsRowRefusal(row2);
|
|
17042
|
+
return reason === void 0 ? { ok: true } : { ok: false, reason };
|
|
17043
|
+
}
|
|
16099
17044
|
default: {
|
|
16100
17045
|
return assertNever(row2.adapter);
|
|
16101
17046
|
}
|
|
@@ -16115,22 +17060,22 @@ var liveState = store[KEY] ??= {
|
|
|
16115
17060
|
var liveCatalog = liveState.catalog;
|
|
16116
17061
|
|
|
16117
17062
|
// src/catalog/load.ts
|
|
16118
|
-
import { z as
|
|
17063
|
+
import { z as z32 } from "zod";
|
|
16119
17064
|
function rowCount() {
|
|
16120
17065
|
return liveCatalog.list({ lifecycle: ["active", "deprecated", "retired"] }).length;
|
|
16121
17066
|
}
|
|
16122
17067
|
function authHeaders(auth) {
|
|
16123
17068
|
return "bearer" in auth ? { Authorization: `Bearer ${auth.bearer}` } : { "x-api-key": auth.apiKey };
|
|
16124
17069
|
}
|
|
16125
|
-
var EnvelopeSchema =
|
|
16126
|
-
rows:
|
|
16127
|
-
revision:
|
|
17070
|
+
var EnvelopeSchema = z32.object({
|
|
17071
|
+
rows: z32.array(JsonValueSchema),
|
|
17072
|
+
revision: z32.string().optional()
|
|
16128
17073
|
});
|
|
16129
17074
|
function dropReason(path, message) {
|
|
16130
17075
|
return path.length === 0 ? message : `${path.map((part) => String(part)).join(".")} ${message}`;
|
|
16131
17076
|
}
|
|
16132
17077
|
function rowId(raw) {
|
|
16133
|
-
const parsed =
|
|
17078
|
+
const parsed = z32.object({ id: z32.string().min(1) }).loose().safeParse(raw);
|
|
16134
17079
|
if (!parsed.success) return "?";
|
|
16135
17080
|
return parsed.data.id;
|
|
16136
17081
|
}
|
|
@@ -17046,8 +17991,17 @@ function resolveSpeechOptions(model, request, onUnsupported = "error") {
|
|
|
17046
17991
|
const warnings = [];
|
|
17047
17992
|
checkScript(model, request.text);
|
|
17048
17993
|
const resolved = { model: model.id, text: request.text };
|
|
17049
|
-
const
|
|
17050
|
-
if (
|
|
17994
|
+
const customVoice = request.customVoice?.trim();
|
|
17995
|
+
if (customVoice) {
|
|
17996
|
+
if (model.capabilities?.customVoices !== true) {
|
|
17997
|
+
throw unsupported3(model, "does not take a custom voice");
|
|
17998
|
+
}
|
|
17999
|
+
if (request.voice?.trim()) throw unsupported3(model, "takes voice or customVoice, not both");
|
|
18000
|
+
resolved.customVoice = customVoice;
|
|
18001
|
+
} else {
|
|
18002
|
+
const voice = resolveVoice(model, request.voice, onUnsupported, warnings);
|
|
18003
|
+
if (voice !== void 0) resolved.voice = voice;
|
|
18004
|
+
}
|
|
17051
18005
|
const language = resolveListed(
|
|
17052
18006
|
model,
|
|
17053
18007
|
{
|
|
@@ -17169,6 +18123,106 @@ function resolveTranscriptionOptions(model, request, onUnsupported = "error") {
|
|
|
17169
18123
|
return { request: resolved, warnings };
|
|
17170
18124
|
}
|
|
17171
18125
|
|
|
18126
|
+
// src/resolve-voice.ts
|
|
18127
|
+
function refuse(model, code, message) {
|
|
18128
|
+
return new ModelKitError({ code, message: `${model.label} ${message}`, model: model.id });
|
|
18129
|
+
}
|
|
18130
|
+
function checkSample(model, sample, index) {
|
|
18131
|
+
const limits = model.constraints.references?.audioSeconds;
|
|
18132
|
+
const length = sample.audio.durationSeconds;
|
|
18133
|
+
if (limits === void 0 || length === void 0) return;
|
|
18134
|
+
if (limits.min !== void 0 && length < limits.min || limits.max !== void 0 && length > limits.max) {
|
|
18135
|
+
const range2 = `${limits.min ?? 0}-${limits.max ?? "any"} s`;
|
|
18136
|
+
throw refuse(
|
|
18137
|
+
model,
|
|
18138
|
+
"unsupported_option",
|
|
18139
|
+
`takes samples of ${range2}; sample ${index + 1} is ${length} s`
|
|
18140
|
+
);
|
|
18141
|
+
}
|
|
18142
|
+
}
|
|
18143
|
+
function resolveVoiceCloneOptions(model, request) {
|
|
18144
|
+
const title = request.title.trim();
|
|
18145
|
+
if (!title) throw refuse(model, "missing_input", "needs a title");
|
|
18146
|
+
if (request.samples.length === 0) throw refuse(model, "missing_input", "needs a voice sample");
|
|
18147
|
+
const max = model.constraints.references?.audios;
|
|
18148
|
+
if (max !== void 0 && request.samples.length > max) {
|
|
18149
|
+
throw refuse(
|
|
18150
|
+
model,
|
|
18151
|
+
"unsupported_option",
|
|
18152
|
+
`takes up to ${max} samples; got ${request.samples.length}`
|
|
18153
|
+
);
|
|
18154
|
+
}
|
|
18155
|
+
request.samples.forEach((sample, index) => checkSample(model, sample, index));
|
|
18156
|
+
const total = model.constraints.references?.audioSeconds?.total;
|
|
18157
|
+
const seconds3 = request.samples.reduce((sum, s) => sum + (s.audio.durationSeconds ?? 0), 0);
|
|
18158
|
+
if (total !== void 0 && seconds3 > total) {
|
|
18159
|
+
throw refuse(
|
|
18160
|
+
model,
|
|
18161
|
+
"unsupported_option",
|
|
18162
|
+
`takes up to ${total} s of samples; got ${seconds3} s`
|
|
18163
|
+
);
|
|
18164
|
+
}
|
|
18165
|
+
for (const field of ["transcript", "designSignature"]) {
|
|
18166
|
+
const set = request.samples.filter((s) => s[field]?.trim()).length;
|
|
18167
|
+
if (set !== 0 && set !== request.samples.length) {
|
|
18168
|
+
throw refuse(model, "missing_input", `needs ${field} on every sample or on none`);
|
|
18169
|
+
}
|
|
18170
|
+
}
|
|
18171
|
+
return { request: { ...request, model: model.id, title }, warnings: [] };
|
|
18172
|
+
}
|
|
18173
|
+
function resolveVoiceDesignOptions(model, request, onUnsupported = "error") {
|
|
18174
|
+
const warnings = [];
|
|
18175
|
+
const prompt = request.prompt.trim();
|
|
18176
|
+
if (!prompt) throw refuse(model, "missing_input", "needs a voice description");
|
|
18177
|
+
const maxChars = promptConventions(model).maxChars;
|
|
18178
|
+
if (maxChars !== void 0 && prompt.length > maxChars) {
|
|
18179
|
+
throw refuse(
|
|
18180
|
+
model,
|
|
18181
|
+
"unsupported_option",
|
|
18182
|
+
`takes up to ${maxChars} characters; got ${prompt.length}`
|
|
18183
|
+
);
|
|
18184
|
+
}
|
|
18185
|
+
const limits = model.constraints.voiceDesign;
|
|
18186
|
+
const resolved = { model: model.id, prompt };
|
|
18187
|
+
const preview2 = request.previewText?.trim();
|
|
18188
|
+
if (preview2) {
|
|
18189
|
+
if (limits !== void 0 && preview2.length > limits.previewMaxChars) {
|
|
18190
|
+
throw refuse(
|
|
18191
|
+
model,
|
|
18192
|
+
"unsupported_option",
|
|
18193
|
+
`takes a preview line of up to ${limits.previewMaxChars} characters; got ${preview2.length}`
|
|
18194
|
+
);
|
|
18195
|
+
}
|
|
18196
|
+
resolved.previewText = preview2;
|
|
18197
|
+
}
|
|
18198
|
+
const language = request.language?.trim();
|
|
18199
|
+
if (language) resolved.language = language;
|
|
18200
|
+
if (request.seed !== void 0) resolved.seed = request.seed;
|
|
18201
|
+
const count2 = request.count ?? model.defaults.count;
|
|
18202
|
+
if (count2 !== void 0) {
|
|
18203
|
+
const cap = limits?.maxCandidates ?? count2;
|
|
18204
|
+
if (!Number.isInteger(count2) || count2 < 1 || count2 > cap) {
|
|
18205
|
+
if (onUnsupported === "error" || !Number.isInteger(count2)) {
|
|
18206
|
+
throw refuse(
|
|
18207
|
+
model,
|
|
18208
|
+
"unsupported_option",
|
|
18209
|
+
`returns 1-${cap} candidates; got ${count2}`
|
|
18210
|
+
);
|
|
18211
|
+
}
|
|
18212
|
+
const to = Math.min(Math.max(count2, 1), cap);
|
|
18213
|
+
warnings.push({
|
|
18214
|
+
code: "option_ignored",
|
|
18215
|
+
field: "count",
|
|
18216
|
+
from: String(count2),
|
|
18217
|
+
to: String(to),
|
|
18218
|
+
message: `count ${count2} replaced by ${to} for ${model.id}`
|
|
18219
|
+
});
|
|
18220
|
+
resolved.count = to;
|
|
18221
|
+
} else resolved.count = count2;
|
|
18222
|
+
}
|
|
18223
|
+
return { request: resolved, warnings };
|
|
18224
|
+
}
|
|
18225
|
+
|
|
17172
18226
|
// src/keys.ts
|
|
17173
18227
|
var ADAPTER_KEYS = {
|
|
17174
18228
|
"ai-sdk-text": [],
|
|
@@ -17181,7 +18235,9 @@ var ADAPTER_KEYS = {
|
|
|
17181
18235
|
prodia: ["prodia"],
|
|
17182
18236
|
higgsfield: ["higgsfield"],
|
|
17183
18237
|
"xai-video": ["xai"],
|
|
17184
|
-
luma: ["luma"]
|
|
18238
|
+
luma: ["luma"],
|
|
18239
|
+
fish: ["fish"],
|
|
18240
|
+
elevenlabs: ["elevenlabs"]
|
|
17185
18241
|
};
|
|
17186
18242
|
function hasAll(keys, names) {
|
|
17187
18243
|
if (!keys) return false;
|
|
@@ -17240,6 +18296,8 @@ function keysFromEnv(env, prefix = "") {
|
|
|
17240
18296
|
set("higgsfield", pick2("HIGGSFIELD_API_KEY"));
|
|
17241
18297
|
set("higgsfieldSecret", pick2("HIGGSFIELD_API_SECRET"));
|
|
17242
18298
|
set("luma", pick2("LUMA_API_KEY", "LUMA_AGENTS_API_KEY"));
|
|
18299
|
+
set("fish", pick2("FISH_AUDIO_API_KEY"));
|
|
18300
|
+
set("elevenlabs", pick2("ELEVENLABS_API_KEY"));
|
|
17243
18301
|
set("cloudflare", pick2("CLOUDFLARE_AI_GATEWAY_TOKEN", "CF_AIG_TOKEN"));
|
|
17244
18302
|
const bearer = pick2("AWS_BEARER_TOKEN_BEDROCK");
|
|
17245
18303
|
const accessKeyId = pick2("AWS_ACCESS_KEY_ID");
|
|
@@ -17262,7 +18320,7 @@ function keysFromEnv(env, prefix = "") {
|
|
|
17262
18320
|
|
|
17263
18321
|
// src/text.ts
|
|
17264
18322
|
import "ai";
|
|
17265
|
-
import { z as
|
|
18323
|
+
import { z as z33 } from "zod";
|
|
17266
18324
|
function mergeTextProviderOptions(catalog, caller) {
|
|
17267
18325
|
const merged = {};
|
|
17268
18326
|
const catalogOptions = catalog.providerOptions ?? {};
|
|
@@ -17301,17 +18359,17 @@ function passthroughTextModel(model) {
|
|
|
17301
18359
|
pricingKind: "token"
|
|
17302
18360
|
};
|
|
17303
18361
|
}
|
|
17304
|
-
var perplexityCostSchema =
|
|
17305
|
-
perplexity:
|
|
18362
|
+
var perplexityCostSchema = z33.object({
|
|
18363
|
+
perplexity: z33.object({ cost: z33.object({ totalCost: z33.number().finite().nonnegative() }) })
|
|
17306
18364
|
});
|
|
17307
18365
|
function reportedCostUsd(metadata) {
|
|
17308
18366
|
const parsed = perplexityCostSchema.safeParse(metadata);
|
|
17309
18367
|
return parsed.success ? parsed.data.perplexity.cost.totalCost : void 0;
|
|
17310
18368
|
}
|
|
17311
|
-
function textUsageEvent(model, provider,
|
|
17312
|
-
const inputTokens =
|
|
17313
|
-
const outputTokens =
|
|
17314
|
-
const total =
|
|
18369
|
+
function textUsageEvent(model, provider, usage5, providerMetadata) {
|
|
18370
|
+
const inputTokens = usage5.inputTokens ?? 0;
|
|
18371
|
+
const outputTokens = usage5.outputTokens ?? 0;
|
|
18372
|
+
const total = usage5.totalTokens ?? inputTokens + outputTokens;
|
|
17315
18373
|
const event = {
|
|
17316
18374
|
model: model.id,
|
|
17317
18375
|
provider,
|
|
@@ -17346,7 +18404,7 @@ function createTextSteps(initial, resolve, callerProviderOptions) {
|
|
|
17346
18404
|
return { ...prepared, providerOptions };
|
|
17347
18405
|
};
|
|
17348
18406
|
}
|
|
17349
|
-
function
|
|
18407
|
+
function usage5(results) {
|
|
17350
18408
|
const grouped = /* @__PURE__ */ new Map();
|
|
17351
18409
|
for (const [index, step] of results.entries()) {
|
|
17352
18410
|
const target = steps.get(index) ?? initial;
|
|
@@ -17370,7 +18428,7 @@ function createTextSteps(initial, resolve, callerProviderOptions) {
|
|
|
17370
18428
|
}
|
|
17371
18429
|
return [...grouped.values()];
|
|
17372
18430
|
}
|
|
17373
|
-
return { wrap, usage:
|
|
18431
|
+
return { wrap, usage: usage5 };
|
|
17374
18432
|
}
|
|
17375
18433
|
|
|
17376
18434
|
// src/client.ts
|
|
@@ -17382,7 +18440,7 @@ import {
|
|
|
17382
18440
|
streamObject as aiStreamObject2,
|
|
17383
18441
|
streamText as aiStreamText2
|
|
17384
18442
|
} from "ai";
|
|
17385
|
-
import { z as
|
|
18443
|
+
import { z as z34 } from "zod";
|
|
17386
18444
|
|
|
17387
18445
|
// src/generated-image.ts
|
|
17388
18446
|
function toGeneratedImage(image) {
|
|
@@ -17504,9 +18562,9 @@ function providerJobMethods(kind, deps) {
|
|
|
17504
18562
|
if (!methods.result) throw missing3(adapter, ctx.model);
|
|
17505
18563
|
const result = await methods.result(sub, ctx, webhook);
|
|
17506
18564
|
const base = { ...result.usage, model: ctx.model.id, unit: ctx.model.usage.unit };
|
|
17507
|
-
const
|
|
17508
|
-
await deps.emit(
|
|
17509
|
-
return { ...result, usage:
|
|
18565
|
+
const usage5 = sub.submittedAt === void 0 ? base : deps.timed(base, sub.submittedAt);
|
|
18566
|
+
await deps.emit(usage5);
|
|
18567
|
+
return { ...result, usage: usage5 };
|
|
17510
18568
|
},
|
|
17511
18569
|
async cancel(sub, call = {}) {
|
|
17512
18570
|
const { methods, adapter, ctx } = target(sub.model, call);
|
|
@@ -17531,6 +18589,9 @@ var MEDIA_METHODS = {
|
|
|
17531
18589
|
lipsync: ["lipsync"],
|
|
17532
18590
|
dubbing: ["dub"],
|
|
17533
18591
|
transcription: ["transcribe"],
|
|
18592
|
+
// deleteVoice runs on the voice-clone row too; it checks with assertMethod("createVoice").
|
|
18593
|
+
"voice-clone": ["createVoice"],
|
|
18594
|
+
"voice-design": ["designVoice"],
|
|
17534
18595
|
"video-tool": ["submitVideoTool"],
|
|
17535
18596
|
// 3D jobs run through submitModel3d, which checks the row type itself; their preflight
|
|
17536
18597
|
// is model3dInputRefusal, not resolveOptions.
|
|
@@ -17545,6 +18606,8 @@ var METHOD_NOUN = {
|
|
|
17545
18606
|
lipsync: "a lipsync model",
|
|
17546
18607
|
dub: "a dubbing model",
|
|
17547
18608
|
transcribe: "a transcription model",
|
|
18609
|
+
createVoice: "a voice cloning model",
|
|
18610
|
+
designVoice: "a voice design model",
|
|
17548
18611
|
submitVideoTool: "a video tool"
|
|
17549
18612
|
};
|
|
17550
18613
|
function assertMethod(model, method) {
|
|
@@ -17587,6 +18650,14 @@ function resolveTranscriptionCall(model, request, onUnsupported = "error") {
|
|
|
17587
18650
|
assertMethod(model, "transcribe");
|
|
17588
18651
|
return resolveTranscriptionOptions(model, request, onUnsupported);
|
|
17589
18652
|
}
|
|
18653
|
+
function resolveVoiceCloneCall(model, request) {
|
|
18654
|
+
assertMethod(model, "createVoice");
|
|
18655
|
+
return resolveVoiceCloneOptions(model, request);
|
|
18656
|
+
}
|
|
18657
|
+
function resolveVoiceDesignCall(model, request, onUnsupported = "error") {
|
|
18658
|
+
assertMethod(model, "designVoice");
|
|
18659
|
+
return resolveVoiceDesignOptions(model, request, onUnsupported);
|
|
18660
|
+
}
|
|
17590
18661
|
|
|
17591
18662
|
// src/client-audio.ts
|
|
17592
18663
|
function noMethod(adapter, model, what) {
|
|
@@ -17676,6 +18747,49 @@ function audioNodeMethods(deps) {
|
|
|
17676
18747
|
const result = await adapter.transcribe(resolved, ctx);
|
|
17677
18748
|
return { ...result, usage: await deps.settle(model, result.usage, startedAt) };
|
|
17678
18749
|
},
|
|
18750
|
+
async createVoice(req, call = {}) {
|
|
18751
|
+
mediaRetryOptions(call);
|
|
18752
|
+
const { abortSignal, ...request } = req;
|
|
18753
|
+
const model = catalog.require(req.model);
|
|
18754
|
+
const { request: resolved, warnings } = resolveVoiceCloneCall(model, request);
|
|
18755
|
+
const { adapter, ctx } = prepare(model, call, abortSignal, warnings);
|
|
18756
|
+
if (!adapter.createVoice) throw noMethod(adapter, model, "clone a voice");
|
|
18757
|
+
const startedAt = Date.now();
|
|
18758
|
+
const result = await adapter.createVoice(resolved, ctx);
|
|
18759
|
+
return { ...result, usage: await deps.settle(model, result.usage, startedAt) };
|
|
18760
|
+
},
|
|
18761
|
+
async designVoice(req, call = {}) {
|
|
18762
|
+
mediaRetryOptions(call);
|
|
18763
|
+
const { abortSignal, ...request } = req;
|
|
18764
|
+
const model = catalog.require(req.model);
|
|
18765
|
+
const { request: resolved, warnings } = resolveVoiceDesignCall(
|
|
18766
|
+
model,
|
|
18767
|
+
request,
|
|
18768
|
+
call.onUnsupported ?? "error"
|
|
18769
|
+
);
|
|
18770
|
+
const { adapter, ctx } = prepare(model, call, abortSignal, warnings);
|
|
18771
|
+
if (!adapter.designVoice) throw noMethod(adapter, model, "design a voice");
|
|
18772
|
+
const startedAt = Date.now();
|
|
18773
|
+
const result = await adapter.designVoice(resolved, ctx);
|
|
18774
|
+
return { ...result, usage: await deps.settle(model, result.usage, startedAt) };
|
|
18775
|
+
},
|
|
18776
|
+
async deleteVoice(req, call = {}) {
|
|
18777
|
+
mediaRetryOptions(call);
|
|
18778
|
+
const { abortSignal, ...request } = req;
|
|
18779
|
+
const model = catalog.require(req.model);
|
|
18780
|
+
assertMethod(model, "createVoice");
|
|
18781
|
+
const voiceId = request.voiceId.trim();
|
|
18782
|
+
if (!voiceId) {
|
|
18783
|
+
throw new ModelKitError({
|
|
18784
|
+
code: "missing_input",
|
|
18785
|
+
message: `${model.id} requires voiceId`,
|
|
18786
|
+
model: model.id
|
|
18787
|
+
});
|
|
18788
|
+
}
|
|
18789
|
+
const { adapter, ctx } = prepare(model, call, abortSignal, []);
|
|
18790
|
+
if (!adapter.deleteVoice) throw noMethod(adapter, model, "delete a voice");
|
|
18791
|
+
await adapter.deleteVoice({ model: model.id, voiceId }, ctx);
|
|
18792
|
+
},
|
|
17679
18793
|
async dub(req, call = {}) {
|
|
17680
18794
|
mediaRetryOptions(call);
|
|
17681
18795
|
const { abortSignal, ...request } = req;
|
|
@@ -17690,10 +18804,10 @@ function audioNodeMethods(deps) {
|
|
|
17690
18804
|
const startedAt = Date.now();
|
|
17691
18805
|
const outcome = await adapter.dub(resolved, ctx);
|
|
17692
18806
|
if (outcome.kind === "audio") {
|
|
17693
|
-
const { audio, usage:
|
|
18807
|
+
const { audio, usage: usage5, raw } = outcome.result;
|
|
17694
18808
|
return {
|
|
17695
18809
|
audio,
|
|
17696
|
-
usage: await deps.settle(model,
|
|
18810
|
+
usage: await deps.settle(model, usage5, startedAt),
|
|
17697
18811
|
...raw !== void 0 && { raw }
|
|
17698
18812
|
};
|
|
17699
18813
|
}
|
|
@@ -17731,10 +18845,10 @@ function textAbortOptions(sdk, context) {
|
|
|
17731
18845
|
if (abortSignal) return { abortSignal };
|
|
17732
18846
|
return {};
|
|
17733
18847
|
}
|
|
17734
|
-
var catalogId =
|
|
17735
|
-
var exactSize =
|
|
17736
|
-
var sdkRatio =
|
|
17737
|
-
var sizeTier =
|
|
18848
|
+
var catalogId = z34.string();
|
|
18849
|
+
var exactSize = z34.templateLiteral([z34.number(), "x", z34.number()]);
|
|
18850
|
+
var sdkRatio = z34.templateLiteral([z34.number(), ":", z34.number()]);
|
|
18851
|
+
var sizeTier = z34.enum(["512", "1K", "2K", "4K"]);
|
|
17738
18852
|
function isCatalogId(model) {
|
|
17739
18853
|
return catalogId.safeParse(model).success;
|
|
17740
18854
|
}
|
|
@@ -17947,7 +19061,7 @@ function createModelKit(config, adapters) {
|
|
|
17947
19061
|
const images = result.images.map(
|
|
17948
19062
|
(file) => toGeneratedImage({ bytes: file.uint8Array, mime: file.mediaType })
|
|
17949
19063
|
);
|
|
17950
|
-
const
|
|
19064
|
+
const usage5 = timed(
|
|
17951
19065
|
{
|
|
17952
19066
|
model: model.modelId,
|
|
17953
19067
|
provider: model.provider,
|
|
@@ -17957,8 +19071,8 @@ function createModelKit(config, adapters) {
|
|
|
17957
19071
|
},
|
|
17958
19072
|
startedAt
|
|
17959
19073
|
);
|
|
17960
|
-
await emit(
|
|
17961
|
-
return { image: images[0], images, usage:
|
|
19074
|
+
await emit(usage5);
|
|
19075
|
+
return { image: images[0], images, usage: usage5, raw: result, warnings };
|
|
17962
19076
|
}
|
|
17963
19077
|
function passthroughVideo(req, call) {
|
|
17964
19078
|
const {
|
|
@@ -18034,7 +19148,7 @@ function createModelKit(config, adapters) {
|
|
|
18034
19148
|
let settled;
|
|
18035
19149
|
let failed = false;
|
|
18036
19150
|
const done = pending.then(async (result) => {
|
|
18037
|
-
const
|
|
19151
|
+
const usage5 = timed(
|
|
18038
19152
|
{
|
|
18039
19153
|
model: model.modelId,
|
|
18040
19154
|
provider: model.provider,
|
|
@@ -18047,10 +19161,10 @@ function createModelKit(config, adapters) {
|
|
|
18047
19161
|
);
|
|
18048
19162
|
settled = {
|
|
18049
19163
|
video: { bytes: result.video.uint8Array, mime: result.video.mediaType },
|
|
18050
|
-
usage:
|
|
19164
|
+
usage: usage5,
|
|
18051
19165
|
raw: result
|
|
18052
19166
|
};
|
|
18053
|
-
await emit(
|
|
19167
|
+
await emit(usage5);
|
|
18054
19168
|
return settled;
|
|
18055
19169
|
});
|
|
18056
19170
|
done.catch(() => {
|
|
@@ -18077,12 +19191,12 @@ function createModelKit(config, adapters) {
|
|
|
18077
19191
|
if (settled) return settled;
|
|
18078
19192
|
const pending = result(opts).then(
|
|
18079
19193
|
async (out) => {
|
|
18080
|
-
const
|
|
19194
|
+
const usage5 = timed(
|
|
18081
19195
|
{ ...out.usage, model: model.id, unit: model.usage.unit },
|
|
18082
19196
|
startedAt
|
|
18083
19197
|
);
|
|
18084
|
-
await emit(
|
|
18085
|
-
return { ...out, usage:
|
|
19198
|
+
await emit(usage5);
|
|
19199
|
+
return { ...out, usage: usage5 };
|
|
18086
19200
|
},
|
|
18087
19201
|
(cause) => {
|
|
18088
19202
|
settled = void 0;
|
|
@@ -18102,9 +19216,9 @@ function createModelKit(config, adapters) {
|
|
|
18102
19216
|
return context(model, signal ? { ...call, signal } : call, warnings);
|
|
18103
19217
|
},
|
|
18104
19218
|
async settle(model, event, startedAt) {
|
|
18105
|
-
const
|
|
18106
|
-
await emit(
|
|
18107
|
-
return
|
|
19219
|
+
const usage5 = timed({ ...event, model: model.id, unit: model.usage.unit }, startedAt);
|
|
19220
|
+
await emit(usage5);
|
|
19221
|
+
return usage5;
|
|
18108
19222
|
},
|
|
18109
19223
|
wrapVideoJob
|
|
18110
19224
|
});
|
|
@@ -18140,11 +19254,11 @@ function createModelKit(config, adapters) {
|
|
|
18140
19254
|
});
|
|
18141
19255
|
const startedAt = Date.now();
|
|
18142
19256
|
const result = await adapter.generateImage(request, ctx);
|
|
18143
|
-
const
|
|
19257
|
+
const usage5 = timed(
|
|
18144
19258
|
{ ...result.usage, model: model.id, unit: model.usage.unit },
|
|
18145
19259
|
startedAt
|
|
18146
19260
|
);
|
|
18147
|
-
await emit(
|
|
19261
|
+
await emit(usage5);
|
|
18148
19262
|
const images = result.images.map(toGeneratedImage);
|
|
18149
19263
|
const first = images[0];
|
|
18150
19264
|
if (!first)
|
|
@@ -18153,7 +19267,7 @@ function createModelKit(config, adapters) {
|
|
|
18153
19267
|
message: `${model.id} returned no image`,
|
|
18154
19268
|
model: model.id
|
|
18155
19269
|
});
|
|
18156
|
-
return { ...result, usage:
|
|
19270
|
+
return { ...result, usage: usage5, image: first, images, warnings };
|
|
18157
19271
|
},
|
|
18158
19272
|
async generateVideo(req, call = {}) {
|
|
18159
19273
|
mediaRetryOptions(call);
|
|
@@ -18252,12 +19366,12 @@ function createModelKit(config, adapters) {
|
|
|
18252
19366
|
}
|
|
18253
19367
|
const startedAt = Date.now();
|
|
18254
19368
|
const result = await adapter.generateAudio(resolved, ctx);
|
|
18255
|
-
const
|
|
19369
|
+
const usage5 = timed(
|
|
18256
19370
|
{ ...result.usage, model: model.id, unit: model.usage.unit },
|
|
18257
19371
|
startedAt
|
|
18258
19372
|
);
|
|
18259
|
-
await emit(
|
|
18260
|
-
return { ...result, usage:
|
|
19373
|
+
await emit(usage5);
|
|
19374
|
+
return { ...result, usage: usage5 };
|
|
18261
19375
|
},
|
|
18262
19376
|
async prepareMediaPart(modelId, ref, mediaType, call = {}) {
|
|
18263
19377
|
mediaRetryOptions(call);
|
|
@@ -18337,8 +19451,8 @@ function createModelKit(config, adapters) {
|
|
|
18337
19451
|
options.prepareStep ?? options.experimental_prepareStep
|
|
18338
19452
|
),
|
|
18339
19453
|
onFinish: async (event) => {
|
|
18340
|
-
for (const
|
|
18341
|
-
await emit(textTimed(withRowUnit(
|
|
19454
|
+
for (const usage5 of steps.usage(event.steps))
|
|
19455
|
+
await emit(textTimed(withRowUnit(usage5), event.steps.length, startedAt));
|
|
18342
19456
|
await callerOnFinish?.(event);
|
|
18343
19457
|
}
|
|
18344
19458
|
});
|
|
@@ -18456,10 +19570,12 @@ export {
|
|
|
18456
19570
|
dataOnlyCapable,
|
|
18457
19571
|
describe,
|
|
18458
19572
|
describeThrown,
|
|
19573
|
+
elevenLabsAdapter,
|
|
18459
19574
|
generateImage as experimental_generateImage,
|
|
18460
19575
|
falAdapter,
|
|
18461
19576
|
falWebhookBodySchema,
|
|
18462
19577
|
fileCatalogCache,
|
|
19578
|
+
fishAdapter,
|
|
18463
19579
|
generateAudio,
|
|
18464
19580
|
generateImage,
|
|
18465
19581
|
generateObject,
|
|
@@ -18512,6 +19628,8 @@ export {
|
|
|
18512
19628
|
resolveTranscriptionOptions,
|
|
18513
19629
|
resolveVideoOptions,
|
|
18514
19630
|
resolveVoiceChangeOptions,
|
|
19631
|
+
resolveVoiceCloneOptions,
|
|
19632
|
+
resolveVoiceDesignOptions,
|
|
18515
19633
|
shouldRetry,
|
|
18516
19634
|
sleep,
|
|
18517
19635
|
sortCatalogRows,
|