@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.cjs
CHANGED
|
@@ -66,10 +66,12 @@ __export(index_exports, {
|
|
|
66
66
|
dataOnlyCapable: () => dataOnlyCapable,
|
|
67
67
|
describe: () => describe,
|
|
68
68
|
describeThrown: () => describeThrown,
|
|
69
|
+
elevenLabsAdapter: () => elevenLabsAdapter,
|
|
69
70
|
experimental_generateImage: () => generateImage,
|
|
70
71
|
falAdapter: () => falAdapter,
|
|
71
72
|
falWebhookBodySchema: () => falWebhookBodySchema,
|
|
72
73
|
fileCatalogCache: () => fileCatalogCache,
|
|
74
|
+
fishAdapter: () => fishAdapter,
|
|
73
75
|
generateAudio: () => generateAudio,
|
|
74
76
|
generateImage: () => generateImage,
|
|
75
77
|
generateObject: () => generateObject,
|
|
@@ -122,6 +124,8 @@ __export(index_exports, {
|
|
|
122
124
|
resolveTranscriptionOptions: () => resolveTranscriptionOptions,
|
|
123
125
|
resolveVideoOptions: () => resolveVideoOptions,
|
|
124
126
|
resolveVoiceChangeOptions: () => resolveVoiceChangeOptions,
|
|
127
|
+
resolveVoiceCloneOptions: () => resolveVoiceCloneOptions,
|
|
128
|
+
resolveVoiceDesignOptions: () => resolveVoiceDesignOptions,
|
|
125
129
|
shouldRetry: () => shouldRetry,
|
|
126
130
|
sleep: () => sleep,
|
|
127
131
|
sortCatalogRows: () => sortCatalogRows,
|
|
@@ -1869,6 +1873,369 @@ var ELEVENLABS_VOICES = [
|
|
|
1869
1873
|
previewUrl: "https://storage.googleapis.com/eleven-public-prod/premade/voices/pqHfZKP75CvOlQylNhV4/d782b3ff-84ba-4029-848c-acf01285524d.mp3"
|
|
1870
1874
|
}
|
|
1871
1875
|
];
|
|
1876
|
+
var PREMADE_ID = /\/premade\/voices\/([A-Za-z0-9]+)\//;
|
|
1877
|
+
var ELEVENLABS_DIRECT_VOICES = ELEVENLABS_VOICES.flatMap((v) => {
|
|
1878
|
+
const id = v.previewUrl ? PREMADE_ID.exec(v.previewUrl)?.[1] : void 0;
|
|
1879
|
+
return id ? [{ ...v, id }] : [];
|
|
1880
|
+
});
|
|
1881
|
+
var ELEVENLABS_DIRECT_DEFAULT_VOICE = "EXAVITQu4vr4xnSDxMaL";
|
|
1882
|
+
|
|
1883
|
+
// src/catalog/speech-elevenlabs-direct.ts
|
|
1884
|
+
var ELEVENLABS_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
|
|
1885
|
+
var PER_CALL = { unit: "images" };
|
|
1886
|
+
var PER_REQUEST = { unit: "requests" };
|
|
1887
|
+
var ELEVENLABS_DIRECT_MODELS = [
|
|
1888
|
+
{
|
|
1889
|
+
id: "elevenlabs-v4-direct",
|
|
1890
|
+
aliases: [],
|
|
1891
|
+
label: "ElevenLabs v4 (direct)",
|
|
1892
|
+
type: "speech",
|
|
1893
|
+
adapter: "elevenlabs",
|
|
1894
|
+
providerModelId: "eleven_v4",
|
|
1895
|
+
lifecycle: "active",
|
|
1896
|
+
exposure: [],
|
|
1897
|
+
constraints: {
|
|
1898
|
+
// Premade voices under their ElevenLabs ids (the direct API takes ids, not names).
|
|
1899
|
+
voices: ELEVENLABS_DIRECT_VOICES,
|
|
1900
|
+
languages: ELEVENLABS_V4_LANGUAGES,
|
|
1901
|
+
outputFormats: ELEVENLABS_MP3_FORMATS,
|
|
1902
|
+
supports: [],
|
|
1903
|
+
// ElevenLabs docs: 10,000 characters per request.
|
|
1904
|
+
prompt: { referenceSyntax: "numbered", maxChars: 1e4 }
|
|
1905
|
+
},
|
|
1906
|
+
defaults: { voice: ELEVENLABS_DIRECT_DEFAULT_VOICE, outputFormat: "mp3_44100_128" },
|
|
1907
|
+
usage: PER_CALL,
|
|
1908
|
+
pricingKind: "flat",
|
|
1909
|
+
display: {
|
|
1910
|
+
provider: "elevenlabs",
|
|
1911
|
+
logo: ELEVENLABS_LOGO,
|
|
1912
|
+
description: "ElevenLabs v4 text to speech with audio tags, in a premade voice or your own cloned voice; up to 10,000 characters."
|
|
1913
|
+
},
|
|
1914
|
+
capabilities: { customVoices: true }
|
|
1915
|
+
},
|
|
1916
|
+
{
|
|
1917
|
+
id: "elevenlabs-ivc",
|
|
1918
|
+
aliases: [],
|
|
1919
|
+
label: "ElevenLabs Instant Voice Clone",
|
|
1920
|
+
type: "voice-clone",
|
|
1921
|
+
adapter: "elevenlabs",
|
|
1922
|
+
providerModelId: "ivc",
|
|
1923
|
+
lifecycle: "active",
|
|
1924
|
+
exposure: [],
|
|
1925
|
+
constraints: {
|
|
1926
|
+
// POST /v1/voices/add; ElevenLabs takes up to 25 samples and advises 1-2 minutes of
|
|
1927
|
+
// clean speech in total. Each clone uses a voice slot on our plan until deleted.
|
|
1928
|
+
references: { audios: 25, audioFormats: ["mp3", "wav", "m4a", "webm", "ogg"] },
|
|
1929
|
+
supports: []
|
|
1930
|
+
},
|
|
1931
|
+
defaults: {},
|
|
1932
|
+
usage: PER_REQUEST,
|
|
1933
|
+
pricingKind: "flat",
|
|
1934
|
+
display: {
|
|
1935
|
+
provider: "elevenlabs",
|
|
1936
|
+
logo: ELEVENLABS_LOGO,
|
|
1937
|
+
description: "Clone a private, reusable voice from one or more clean recordings, then speak with it on ElevenLabs v4 (direct)."
|
|
1938
|
+
},
|
|
1939
|
+
capabilities: {}
|
|
1940
|
+
}
|
|
1941
|
+
];
|
|
1942
|
+
|
|
1943
|
+
// src/catalog/voices-fish.ts
|
|
1944
|
+
var FISH_VOICES = [
|
|
1945
|
+
{
|
|
1946
|
+
id: "933563129e564b19a115bedd57b7406a",
|
|
1947
|
+
name: "Sarah",
|
|
1948
|
+
gender: "female",
|
|
1949
|
+
languages: ["en"],
|
|
1950
|
+
description: "An engaged speaker.",
|
|
1951
|
+
previewUrl: "https://platform.r2.fish.audio/task/4e204945670c460c86fdab57512cb308.mp3"
|
|
1952
|
+
},
|
|
1953
|
+
{
|
|
1954
|
+
id: "bf322df2096a46f18c579d0baa36f41d",
|
|
1955
|
+
name: "Adrian",
|
|
1956
|
+
gender: "male",
|
|
1957
|
+
languages: ["en"],
|
|
1958
|
+
description: "A steady and reliable narrator.",
|
|
1959
|
+
previewUrl: "https://platform.r2.fish.audio/task/d730b09f4a484316a77ecc86137e85fb.mp3"
|
|
1960
|
+
},
|
|
1961
|
+
{
|
|
1962
|
+
id: "536d3a5e000945adb7038665781a4aca",
|
|
1963
|
+
name: "Ethan",
|
|
1964
|
+
gender: "male",
|
|
1965
|
+
languages: ["en"],
|
|
1966
|
+
description: "A curious explainer.",
|
|
1967
|
+
previewUrl: "https://platform.r2.fish.audio/task/bdd677ed767744fc91f166468786264b.mp3"
|
|
1968
|
+
},
|
|
1969
|
+
{
|
|
1970
|
+
id: "b347db033a6549378b48d00acb0d06cd",
|
|
1971
|
+
name: "Selene",
|
|
1972
|
+
gender: "female",
|
|
1973
|
+
languages: ["en"],
|
|
1974
|
+
description: "A meditative female voice.",
|
|
1975
|
+
previewUrl: "https://platform.r2.fish.audio/task/fcf629b4a0b343558f461338ba1b9da4.mp3"
|
|
1976
|
+
},
|
|
1977
|
+
{
|
|
1978
|
+
id: "9a9cf47702da476aa4629e2506d4a857",
|
|
1979
|
+
name: "Hannah",
|
|
1980
|
+
gender: "female",
|
|
1981
|
+
languages: ["en"],
|
|
1982
|
+
description: "A conversation specialist.",
|
|
1983
|
+
previewUrl: "https://platform.r2.fish.audio/task/08d658835feb427db808e37060b78eb0.mp3"
|
|
1984
|
+
},
|
|
1985
|
+
{
|
|
1986
|
+
id: "79d0bd3e4e5444b18f7b6d89b5927bf1",
|
|
1987
|
+
name: "Jordan",
|
|
1988
|
+
gender: "male",
|
|
1989
|
+
languages: ["en"],
|
|
1990
|
+
description: "A motivational speaker.",
|
|
1991
|
+
previewUrl: "https://platform.r2.fish.audio/task/edecbc0bdd4c46c39eda8520a0f729ef.mp3"
|
|
1992
|
+
},
|
|
1993
|
+
{
|
|
1994
|
+
id: "e3cd384158934cc9a01029cd7d278634",
|
|
1995
|
+
name: "Laura",
|
|
1996
|
+
gender: "female",
|
|
1997
|
+
languages: ["en"],
|
|
1998
|
+
description: "A confident female narrator.",
|
|
1999
|
+
previewUrl: "https://platform.r2.fish.audio/task/e821bef995344d519caa1c93d808db23.mp3"
|
|
2000
|
+
},
|
|
2001
|
+
{
|
|
2002
|
+
id: "f3a2b90078d54a65af4b95f63bc7798e",
|
|
2003
|
+
name: "Sheila",
|
|
2004
|
+
gender: "female",
|
|
2005
|
+
accent: "american",
|
|
2006
|
+
languages: ["en"],
|
|
2007
|
+
description: "A young American English woman's voice.",
|
|
2008
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/9bb9e1a1cf3f47f38700da1c5c0a678a.mp3"
|
|
2009
|
+
},
|
|
2010
|
+
{
|
|
2011
|
+
id: "0db6e93af420470b9d9b9a886dbaa954",
|
|
2012
|
+
name: "Kai",
|
|
2013
|
+
gender: "male",
|
|
2014
|
+
languages: ["en"],
|
|
2015
|
+
description: "A friendly English man's voice for companion apps and everyday conversation.",
|
|
2016
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/13306f1172544c3ba3106d1e363feaa6.mp3"
|
|
2017
|
+
},
|
|
2018
|
+
{
|
|
2019
|
+
id: "8abfa9ebd4c24a3399b68c3cdac8c7b5",
|
|
2020
|
+
name: "Freya",
|
|
2021
|
+
gender: "female",
|
|
2022
|
+
accent: "british",
|
|
2023
|
+
languages: ["en"],
|
|
2024
|
+
description: "A natural, professional British English voice with a brisk, conversational pace. Clear and easy to follow, suited to voice assistants, customer support and everyday narration.",
|
|
2025
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/07918705a56b42daaab149f65392cea7.mp3"
|
|
2026
|
+
},
|
|
2027
|
+
{
|
|
2028
|
+
id: "2f64e528a4f2406691925ab1e0ed5b7f",
|
|
2029
|
+
name: "Ananya",
|
|
2030
|
+
gender: "female",
|
|
2031
|
+
languages: ["hi"],
|
|
2032
|
+
description: "\u0938\u093E\u092B\u093C \u0914\u0930 \u0906\u0924\u094D\u092E\u0935\u093F\u0936\u094D\u0935\u093E\u0938 \u092D\u0930\u0940 \u0906\u0935\u093E\u091C\u093C, \u091C\u094B \u0935\u0949\u0907\u0938 \u0905\u0938\u093F\u0938\u094D\u091F\u0947\u0902\u091F, \u0917\u094D\u0930\u093E\u0939\u0915 \u0938\u0947\u0935\u093E \u0914\u0930 \u092A\u094D\u0930\u0938\u094D\u0924\u0941\u0924\u093F\u092F\u094B\u0902 \u0915\u0947 \u0932\u093F\u090F \u0909\u092A\u092F\u0941\u0915\u094D\u0924 \u0939\u0948\u0964",
|
|
2033
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/a17a700668d8405f8316db120733145c.mp3"
|
|
2034
|
+
},
|
|
2035
|
+
{
|
|
2036
|
+
id: "cefd91a07b99468f9148e2580990082d",
|
|
2037
|
+
name: "Arjun",
|
|
2038
|
+
gender: "male",
|
|
2039
|
+
languages: ["hi"],
|
|
2040
|
+
description: "\u0938\u093E\u092B\u093C \u0914\u0930 \u0906\u0924\u094D\u092E\u0935\u093F\u0936\u094D\u0935\u093E\u0938 \u092D\u0930\u0940 \u0906\u0935\u093E\u091C\u093C, \u091C\u094B \u0935\u0949\u0907\u0938 \u0905\u0938\u093F\u0938\u094D\u091F\u0947\u0902\u091F, \u0917\u094D\u0930\u093E\u0939\u0915 \u0938\u0947\u0935\u093E \u0914\u0930 \u092A\u094D\u0930\u0938\u094D\u0924\u0941\u0924\u093F\u092F\u094B\u0902 \u0915\u0947 \u0932\u093F\u090F \u0909\u092A\u092F\u0941\u0915\u094D\u0924 \u0939\u0948\u0964",
|
|
2041
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/a0c4a8eadb7841cdae8e5e68031a2dfb.mp3"
|
|
2042
|
+
},
|
|
2043
|
+
{
|
|
2044
|
+
id: "3f065d660212478a9c697fa965b4d098",
|
|
2045
|
+
name: "Carmen",
|
|
2046
|
+
gender: "female",
|
|
2047
|
+
languages: ["es"],
|
|
2048
|
+
description: "Una voz clara y segura para asistentes de voz, atenci\xF3n al cliente y presentaciones.",
|
|
2049
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/3421be48b6cb4c28bf829c25188e7e74.mp3"
|
|
2050
|
+
},
|
|
2051
|
+
{
|
|
2052
|
+
id: "ec0718028a2445fb9be8e8bfb56a0150",
|
|
2053
|
+
name: "Rodrigo",
|
|
2054
|
+
gender: "male",
|
|
2055
|
+
languages: ["es"],
|
|
2056
|
+
description: "Una voz clara y segura para asistentes de voz, atenci\xF3n al cliente y presentaciones.",
|
|
2057
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/5a77c32365604800ad5b4eb13c5585df.mp3"
|
|
2058
|
+
},
|
|
2059
|
+
{
|
|
2060
|
+
id: "10a3a20742114a4ea6dd441e7591850f",
|
|
2061
|
+
name: "Manon",
|
|
2062
|
+
gender: "female",
|
|
2063
|
+
languages: ["fr"],
|
|
2064
|
+
description: "Une voix claire et vive, adapt\xE9e aux assistants vocaux et au support client.",
|
|
2065
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/f7b75ee1fa524e48a8cefb003cf72952.mp3"
|
|
2066
|
+
},
|
|
2067
|
+
{
|
|
2068
|
+
id: "f69bca092b674168a8d02d61ca20943c",
|
|
2069
|
+
name: "Lucas",
|
|
2070
|
+
gender: "male",
|
|
2071
|
+
languages: ["fr"],
|
|
2072
|
+
description: "Une voix claire et assur\xE9e, adapt\xE9e aux assistants vocaux et au service client.",
|
|
2073
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/86fca3e56a014a3d8a11450854bb8311.mp3"
|
|
2074
|
+
},
|
|
2075
|
+
{
|
|
2076
|
+
id: "3937b44b604249f18b94913daef94043",
|
|
2077
|
+
name: "Lena",
|
|
2078
|
+
gender: "female",
|
|
2079
|
+
languages: ["de"],
|
|
2080
|
+
description: "Eine klare, souver\xE4ne Stimme f\xFCr Sprachassistenten, Kundenservice und Pr\xE4sentationen.",
|
|
2081
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/8659fec80b74442dab68a7755716a401.mp3"
|
|
2082
|
+
},
|
|
2083
|
+
{
|
|
2084
|
+
id: "c1e7cc926aa5469aa966c353094d4b0b",
|
|
2085
|
+
name: "Lukas",
|
|
2086
|
+
gender: "male",
|
|
2087
|
+
languages: ["de"],
|
|
2088
|
+
description: "Eine klare, souver\xE4ne Stimme f\xFCr Sprachassistenten, Kundenservice und Pr\xE4sentationen.",
|
|
2089
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/fb1d538126bb4fe38f8366250f6a2136.mp3"
|
|
2090
|
+
},
|
|
2091
|
+
{
|
|
2092
|
+
id: "b3c060cc41544a7da94a2c487647c902",
|
|
2093
|
+
name: "Let\xEDcia",
|
|
2094
|
+
gender: "female",
|
|
2095
|
+
accent: "brazilian",
|
|
2096
|
+
languages: ["pt"],
|
|
2097
|
+
description: "A Brazilian-accented Portuguese woman's voice, in her late twenties. Soft, warm, intimate. A freelance designer from Belo Horizonte who enjoys long walks in the park. Best suited to companion apps and casual everyday conversation.",
|
|
2098
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-10-12/13c6c0d96b5c4069951f89868ee15360.mp3"
|
|
2099
|
+
},
|
|
2100
|
+
{
|
|
2101
|
+
id: "add7bcb8d3c8423bbfa152ca232aad6e",
|
|
2102
|
+
name: "Ricardo",
|
|
2103
|
+
gender: "male",
|
|
2104
|
+
accent: "brazilian",
|
|
2105
|
+
languages: ["pt"],
|
|
2106
|
+
description: "A Brazilian-accented Portuguese man's voice, in his late forties. Clear, professional, monotone. A high school history teacher from Curitiba who loves classical music. Best suited to lessons, tutoring and explainer content.",
|
|
2107
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-10-12/67475fc717ae45cbb38e647a2dd37fe1.mp3"
|
|
2108
|
+
},
|
|
2109
|
+
{
|
|
2110
|
+
id: "b2d9d8db057042688a5e318b8f405bc2",
|
|
2111
|
+
name: "Kyoko",
|
|
2112
|
+
gender: "female",
|
|
2113
|
+
languages: ["ja"],
|
|
2114
|
+
description: "\u4E01\u5BE7\u3067\u843D\u3061\u7740\u3044\u305F\u8A71\u3057\u65B9\u304C\u7279\u5FB4\u306E\u5973\u6027\u306E\u58F0\u3002\u304A\u5BA2\u69D8\u5BFE\u5FDC\u3084\u60C5\u5831\u63D0\u4F9B\u306B\u6700\u9069\u3002",
|
|
2115
|
+
previewUrl: "https://platform.r2.fish.audio/task/993b3ccb52124341aff79580f1ce5a5a.mp3"
|
|
2116
|
+
},
|
|
2117
|
+
{
|
|
2118
|
+
id: "297a6fd278df47c3b9da9bfdf55ac89a",
|
|
2119
|
+
name: "Satoru",
|
|
2120
|
+
gender: "male",
|
|
2121
|
+
languages: ["ja"],
|
|
2122
|
+
description: "\u82E5\u3005\u3057\u304F\u3082\u843D\u3061\u7740\u304D\u306E\u3042\u308B\u7537\u6027\u306E\u58F0\u3002\u65E5\u5E38\u306E\u8A9E\u308A\u3084\u30EA\u30E9\u30C3\u30AF\u30B9\u3057\u305F\u30CA\u30EC\u30FC\u30B7\u30E7\u30F3\u306B\u6700\u9069\u3002",
|
|
2123
|
+
previewUrl: "https://platform.r2.fish.audio/task/1b4712fb831f4c149eef6b0133157418.mp3"
|
|
2124
|
+
},
|
|
2125
|
+
{
|
|
2126
|
+
id: "0b14f34a13a94ed88fe6113193749bb0",
|
|
2127
|
+
name: "Fatima",
|
|
2128
|
+
gender: "female",
|
|
2129
|
+
languages: ["ar"],
|
|
2130
|
+
description: "\u0635\u0648\u062A \u0648\u0627\u0636\u062D \u0648\u0648\u0627\u062B\u0642 \u064A\u0646\u0627\u0633\u0628 \u0627\u0644\u0645\u0633\u0627\u0639\u062F\u0627\u062A \u0627\u0644\u0635\u0648\u062A\u064A\u0629 \u0648\u062E\u062F\u0645\u0629 \u0627\u0644\u0639\u0645\u0644\u0627\u0621 \u0648\u0627\u0644\u0639\u0631\u0648\u0636 \u0627\u0644\u062A\u0642\u062F\u064A\u0645\u064A\u0629.",
|
|
2131
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-24/93406e1b905a4c4994306e3421243390.mp3"
|
|
2132
|
+
},
|
|
2133
|
+
{
|
|
2134
|
+
id: "74c6aba5cbf94a15bbdc547ffce5cb38",
|
|
2135
|
+
name: "Yutong",
|
|
2136
|
+
gender: "female",
|
|
2137
|
+
languages: ["zh"],
|
|
2138
|
+
description: "\u58F0\u97F3\u6E05\u6670\u81EA\u7136\uFF0C\u8868\u8FBE\u5229\u843D\uFF0C\u9002\u5408\u8BED\u97F3\u52A9\u624B\u3001\u5BA2\u670D\u548C\u65E5\u5E38\u64AD\u62A5\u3002",
|
|
2139
|
+
previewUrl: "https://platform.r2.fish.audio/tasks/2026-08-25/a48320f37fe44c4699549a1afc3778e8.mp3"
|
|
2140
|
+
}
|
|
2141
|
+
];
|
|
2142
|
+
|
|
2143
|
+
// src/catalog/speech-fish.ts
|
|
2144
|
+
var FISH_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/fishaudio.png";
|
|
2145
|
+
var PER_CALL2 = { unit: "images" };
|
|
2146
|
+
var PER_REQUEST2 = { unit: "requests" };
|
|
2147
|
+
var TTS_MAX_CHARS = 1e4;
|
|
2148
|
+
function fishTts(id, label, providerModelId, description) {
|
|
2149
|
+
return {
|
|
2150
|
+
id,
|
|
2151
|
+
aliases: [],
|
|
2152
|
+
label,
|
|
2153
|
+
type: "speech",
|
|
2154
|
+
adapter: "fish",
|
|
2155
|
+
providerModelId,
|
|
2156
|
+
lifecycle: "active",
|
|
2157
|
+
exposure: [],
|
|
2158
|
+
constraints: {
|
|
2159
|
+
voices: FISH_VOICES,
|
|
2160
|
+
outputFormats: ["mp3", "wav"],
|
|
2161
|
+
supports: [],
|
|
2162
|
+
prompt: { referenceSyntax: "numbered", maxChars: TTS_MAX_CHARS }
|
|
2163
|
+
},
|
|
2164
|
+
defaults: { voice: "9a9cf47702da476aa4629e2506d4a857", outputFormat: "mp3" },
|
|
2165
|
+
usage: PER_CALL2,
|
|
2166
|
+
pricingKind: "flat",
|
|
2167
|
+
display: { provider: "fishaudio", logo: FISH_LOGO, description },
|
|
2168
|
+
capabilities: { customVoices: true }
|
|
2169
|
+
};
|
|
2170
|
+
}
|
|
2171
|
+
var FISH_MODELS = [
|
|
2172
|
+
fishTts(
|
|
2173
|
+
"fish-s2.1-pro",
|
|
2174
|
+
"Fish Audio S2.1 Pro",
|
|
2175
|
+
"s2.1-pro",
|
|
2176
|
+
"Fish Audio S2.1 Pro text to speech in 83 languages, with [bracket] directions and your own cloned voices."
|
|
2177
|
+
),
|
|
2178
|
+
fishTts(
|
|
2179
|
+
"fish-s2.1-pro-free",
|
|
2180
|
+
"Fish Audio S2.1 Pro Free",
|
|
2181
|
+
"s2.1-pro-free",
|
|
2182
|
+
"Fish Audio S2.1 Pro on the free developer tier: the same voices at no cost, without latency or data-processing guarantees."
|
|
2183
|
+
),
|
|
2184
|
+
fishTts(
|
|
2185
|
+
"fish-drama-3",
|
|
2186
|
+
"Fish Audio Drama 3",
|
|
2187
|
+
"drama-3",
|
|
2188
|
+
"Fish Audio Drama 3 text to speech you direct like an actor: [directions], sounds, pauses and per-word tags."
|
|
2189
|
+
),
|
|
2190
|
+
{
|
|
2191
|
+
id: "fish-voice-clone",
|
|
2192
|
+
aliases: [],
|
|
2193
|
+
label: "Fish Audio Voice Clone",
|
|
2194
|
+
type: "voice-clone",
|
|
2195
|
+
adapter: "fish",
|
|
2196
|
+
providerModelId: "voice-clone",
|
|
2197
|
+
lifecycle: "active",
|
|
2198
|
+
exposure: [],
|
|
2199
|
+
constraints: {
|
|
2200
|
+
// POST /model takes 1-20 voice files; Fish advises 10 s or more of clean speech each.
|
|
2201
|
+
references: { audios: 20, audioFormats: ["wav", "mp3", "m4a", "opus"] },
|
|
2202
|
+
supports: []
|
|
2203
|
+
},
|
|
2204
|
+
defaults: {},
|
|
2205
|
+
usage: PER_REQUEST2,
|
|
2206
|
+
pricingKind: "flat",
|
|
2207
|
+
display: {
|
|
2208
|
+
provider: "fishaudio",
|
|
2209
|
+
logo: FISH_LOGO,
|
|
2210
|
+
description: "Clone a private, reusable voice from one or more clean recordings, then speak with it on the Fish Audio speech models."
|
|
2211
|
+
},
|
|
2212
|
+
capabilities: {}
|
|
2213
|
+
},
|
|
2214
|
+
{
|
|
2215
|
+
id: "fish-voice-design-1",
|
|
2216
|
+
aliases: [],
|
|
2217
|
+
label: "Fish Audio Voice Design",
|
|
2218
|
+
type: "voice-design",
|
|
2219
|
+
adapter: "fish",
|
|
2220
|
+
providerModelId: "voice-design-1",
|
|
2221
|
+
lifecycle: "active",
|
|
2222
|
+
exposure: [],
|
|
2223
|
+
constraints: {
|
|
2224
|
+
voiceDesign: { maxCandidates: 4, previewMaxChars: 150 },
|
|
2225
|
+
supports: [],
|
|
2226
|
+
prompt: { referenceSyntax: "numbered", maxChars: 2e3 }
|
|
2227
|
+
},
|
|
2228
|
+
defaults: {},
|
|
2229
|
+
usage: PER_REQUEST2,
|
|
2230
|
+
pricingKind: "flat",
|
|
2231
|
+
display: {
|
|
2232
|
+
provider: "fishaudio",
|
|
2233
|
+
logo: FISH_LOGO,
|
|
2234
|
+
description: "Describe a voice and get up to four short candidates; keep one as a cloned voice."
|
|
2235
|
+
},
|
|
2236
|
+
capabilities: {}
|
|
2237
|
+
}
|
|
2238
|
+
];
|
|
1872
2239
|
|
|
1873
2240
|
// src/catalog/voices-gemini.ts
|
|
1874
2241
|
var GEMINI_TTS_VOICES = [
|
|
@@ -3445,11 +3812,11 @@ var MINIMAX_VOICES = [
|
|
|
3445
3812
|
];
|
|
3446
3813
|
|
|
3447
3814
|
// src/catalog/media-nodes.ts
|
|
3448
|
-
var
|
|
3815
|
+
var ELEVENLABS_LOGO2 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
|
|
3449
3816
|
var GOOGLE_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
|
|
3450
3817
|
var MINIMAX_LOGO = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png";
|
|
3451
3818
|
var SYNC_LOGO = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/sync.png";
|
|
3452
|
-
var
|
|
3819
|
+
var PER_CALL3 = { unit: "images" };
|
|
3453
3820
|
var EXPOSURE4 = ["cowork", "space_builder"];
|
|
3454
3821
|
var LIPSYNC_AUDIO = { audioSeconds: { max: 30 } };
|
|
3455
3822
|
function elevenLabsTts(tts) {
|
|
@@ -3470,9 +3837,9 @@ function elevenLabsTts(tts) {
|
|
|
3470
3837
|
prompt: { referenceSyntax: "numbered", maxChars: tts.maxChars }
|
|
3471
3838
|
},
|
|
3472
3839
|
defaults: { voice: "Rachel", ...tts.formats && { outputFormat: "mp3_44100_128" } },
|
|
3473
|
-
usage:
|
|
3840
|
+
usage: PER_CALL3,
|
|
3474
3841
|
pricingKind: "flat",
|
|
3475
|
-
display: { provider: "elevenlabs", logo:
|
|
3842
|
+
display: { provider: "elevenlabs", logo: ELEVENLABS_LOGO2, description: tts.description },
|
|
3476
3843
|
capabilities: {}
|
|
3477
3844
|
};
|
|
3478
3845
|
}
|
|
@@ -3494,7 +3861,7 @@ function geminiTts(id, label, description) {
|
|
|
3494
3861
|
prompt: { referenceSyntax: "numbered", maxChars: 8192 }
|
|
3495
3862
|
},
|
|
3496
3863
|
defaults: { voice: "Kore" },
|
|
3497
|
-
usage:
|
|
3864
|
+
usage: PER_CALL3,
|
|
3498
3865
|
pricingKind: "flat",
|
|
3499
3866
|
display: { provider: "google", logo: GOOGLE_LOGO, description },
|
|
3500
3867
|
capabilities: {}
|
|
@@ -3517,7 +3884,7 @@ function syncLipsync(id, label, providerModelId, syncModel, description) {
|
|
|
3517
3884
|
},
|
|
3518
3885
|
defaults: {},
|
|
3519
3886
|
...syncModel !== void 0 && { providerOptions: { fal: { model: syncModel } } },
|
|
3520
|
-
usage:
|
|
3887
|
+
usage: PER_CALL3,
|
|
3521
3888
|
pricingKind: "flat",
|
|
3522
3889
|
display: { provider: "sync", logo: SYNC_LOGO, description },
|
|
3523
3890
|
capabilities: { acceptsSourceVideo: true }
|
|
@@ -3578,7 +3945,7 @@ var MEDIA_NODE_MODELS = [
|
|
|
3578
3945
|
prompt: { referenceSyntax: "numbered", maxChars: 1e4 }
|
|
3579
3946
|
},
|
|
3580
3947
|
defaults: { voice: "Wise_Woman" },
|
|
3581
|
-
usage:
|
|
3948
|
+
usage: PER_CALL3,
|
|
3582
3949
|
pricingKind: "flat",
|
|
3583
3950
|
display: {
|
|
3584
3951
|
provider: "minimax",
|
|
@@ -3605,11 +3972,11 @@ var MEDIA_NODE_MODELS = [
|
|
|
3605
3972
|
supports: []
|
|
3606
3973
|
},
|
|
3607
3974
|
defaults: { voice: "Rachel", outputFormat: "mp3_44100_128" },
|
|
3608
|
-
usage:
|
|
3975
|
+
usage: PER_CALL3,
|
|
3609
3976
|
pricingKind: "flat",
|
|
3610
3977
|
display: {
|
|
3611
3978
|
provider: "elevenlabs",
|
|
3612
|
-
logo:
|
|
3979
|
+
logo: ELEVENLABS_LOGO2,
|
|
3613
3980
|
description: "ElevenLabs speech to speech; re-voices a recording in another voice and keeps its timing and delivery."
|
|
3614
3981
|
},
|
|
3615
3982
|
capabilities: {}
|
|
@@ -3632,11 +3999,11 @@ var MEDIA_NODE_MODELS = [
|
|
|
3632
3999
|
supports: []
|
|
3633
4000
|
},
|
|
3634
4001
|
defaults: {},
|
|
3635
|
-
usage:
|
|
4002
|
+
usage: PER_CALL3,
|
|
3636
4003
|
pricingKind: "flat",
|
|
3637
4004
|
display: {
|
|
3638
4005
|
provider: "elevenlabs",
|
|
3639
|
-
logo:
|
|
4006
|
+
logo: ELEVENLABS_LOGO2,
|
|
3640
4007
|
description: "ElevenLabs dubbing; translates the speech in a video or audio file into another language in the original voices."
|
|
3641
4008
|
},
|
|
3642
4009
|
capabilities: { acceptsSourceVideo: true }
|
|
@@ -3679,7 +4046,7 @@ var MEDIA_NODE_MODELS = [
|
|
|
3679
4046
|
supports: []
|
|
3680
4047
|
},
|
|
3681
4048
|
defaults: {},
|
|
3682
|
-
usage:
|
|
4049
|
+
usage: PER_CALL3,
|
|
3683
4050
|
pricingKind: "flat",
|
|
3684
4051
|
display: {
|
|
3685
4052
|
provider: "veed",
|
|
@@ -3731,16 +4098,18 @@ var MEDIA_NODE_MODELS = [
|
|
|
3731
4098
|
supports: []
|
|
3732
4099
|
},
|
|
3733
4100
|
defaults: {},
|
|
3734
|
-
usage:
|
|
4101
|
+
usage: PER_CALL3,
|
|
3735
4102
|
pricingKind: "flat",
|
|
3736
4103
|
display: {
|
|
3737
4104
|
provider: "elevenlabs",
|
|
3738
|
-
logo:
|
|
4105
|
+
logo: ELEVENLABS_LOGO2,
|
|
3739
4106
|
description: "ElevenLabs Scribe v2 speech to text with word timings, speaker labels and audio-event tags."
|
|
3740
4107
|
},
|
|
3741
4108
|
capabilities: {}
|
|
3742
4109
|
},
|
|
3743
|
-
SAM_3_IMAGE
|
|
4110
|
+
SAM_3_IMAGE,
|
|
4111
|
+
...FISH_MODELS,
|
|
4112
|
+
...ELEVENLABS_DIRECT_MODELS
|
|
3744
4113
|
];
|
|
3745
4114
|
|
|
3746
4115
|
// src/catalog/model3d.ts
|
|
@@ -3936,7 +4305,7 @@ var MODEL3D_MODELS = [
|
|
|
3936
4305
|
|
|
3937
4306
|
// src/catalog/other.ts
|
|
3938
4307
|
var GOOGLE_LOGO2 = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
|
|
3939
|
-
var
|
|
4308
|
+
var ELEVENLABS_LOGO3 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
|
|
3940
4309
|
var MINIMAX_LOGO2 = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png";
|
|
3941
4310
|
var OTHER_MODELS = [
|
|
3942
4311
|
{
|
|
@@ -4101,7 +4470,7 @@ var OTHER_MODELS = [
|
|
|
4101
4470
|
pricingKind: "flat",
|
|
4102
4471
|
display: {
|
|
4103
4472
|
provider: "elevenlabs",
|
|
4104
|
-
logo:
|
|
4473
|
+
logo: ELEVENLABS_LOGO3,
|
|
4105
4474
|
description: "ElevenLabs Music v2.5 text-to-music; full songs or instrumentals from 3 seconds to 1 minute."
|
|
4106
4475
|
},
|
|
4107
4476
|
capabilities: {}
|
|
@@ -4153,7 +4522,7 @@ var OTHER_MODELS = [
|
|
|
4153
4522
|
pricingKind: "flat",
|
|
4154
4523
|
display: {
|
|
4155
4524
|
provider: "elevenlabs",
|
|
4156
|
-
logo:
|
|
4525
|
+
logo: ELEVENLABS_LOGO3,
|
|
4157
4526
|
description: "ElevenLabs Sound Effects v2; a sound effect from a text description, up to 22 seconds."
|
|
4158
4527
|
},
|
|
4159
4528
|
capabilities: {}
|
|
@@ -7375,7 +7744,9 @@ var ADAPTER_IDS = [
|
|
|
7375
7744
|
"prodia",
|
|
7376
7745
|
"higgsfield",
|
|
7377
7746
|
"xai-video",
|
|
7378
|
-
"luma"
|
|
7747
|
+
"luma",
|
|
7748
|
+
"fish",
|
|
7749
|
+
"elevenlabs"
|
|
7379
7750
|
];
|
|
7380
7751
|
var ModelTypeSchema = import_zod3.z.enum([
|
|
7381
7752
|
"text",
|
|
@@ -7392,6 +7763,8 @@ var ModelTypeSchema = import_zod3.z.enum([
|
|
|
7392
7763
|
"dubbing",
|
|
7393
7764
|
"lipsync",
|
|
7394
7765
|
"transcription",
|
|
7766
|
+
"voice-clone",
|
|
7767
|
+
"voice-design",
|
|
7395
7768
|
"model3d"
|
|
7396
7769
|
]);
|
|
7397
7770
|
var LifecycleSchema = import_zod3.z.enum(["active", "deprecated", "retired"]);
|
|
@@ -7567,6 +7940,10 @@ var ModelConstraintsSchema = import_zod3.z.looseObject({
|
|
|
7567
7940
|
supports: import_zod3.z.array(SupportedOptionSchema).optional(),
|
|
7568
7941
|
ratioIgnoredWith: import_zod3.z.array(import_zod3.z.enum(["firstFrame", "sourceVideo"])).optional(),
|
|
7569
7942
|
voices: import_zod3.z.array(VoiceOptionSchema).optional(),
|
|
7943
|
+
voiceDesign: import_zod3.z.object({
|
|
7944
|
+
maxCandidates: import_zod3.z.number().int().positive(),
|
|
7945
|
+
previewMaxChars: import_zod3.z.number().int().positive()
|
|
7946
|
+
}).optional(),
|
|
7570
7947
|
languages: import_zod3.z.array(LanguageOptionSchema).optional(),
|
|
7571
7948
|
outputFormats: import_zod3.z.array(import_zod3.z.string().min(1)).min(1).optional(),
|
|
7572
7949
|
sourceVideoSeconds: VideoSecondsLimitsSchema.omit({ total: true }).extend({ inReferenceTotal: import_zod3.z.boolean().optional() }).optional(),
|
|
@@ -7665,6 +8042,7 @@ var CatalogDisplaySchema = import_zod3.z.looseObject({
|
|
|
7665
8042
|
});
|
|
7666
8043
|
var CatalogCapabilitiesSchema = import_zod3.z.looseObject({
|
|
7667
8044
|
acceptsSourceVideo: import_zod3.z.boolean().optional(),
|
|
8045
|
+
customVoices: import_zod3.z.boolean().optional(),
|
|
7668
8046
|
videoEdit: import_zod3.z.boolean().optional(),
|
|
7669
8047
|
framesExcludeReferences: import_zod3.z.boolean().optional(),
|
|
7670
8048
|
sourceVideoExcludesFrames: import_zod3.z.boolean().optional(),
|
|
@@ -8184,7 +8562,7 @@ var errorCodes = import_zod6.z.object({
|
|
|
8184
8562
|
type: import_zod6.z.string().optional(),
|
|
8185
8563
|
error: import_zod6.z.object({ code: import_zod6.z.string().optional(), type: import_zod6.z.string().optional() }).optional()
|
|
8186
8564
|
});
|
|
8187
|
-
var BILLING_TEXT = /insufficient_quota|payment[ _]required|exhausted balance|insufficient (?:credits?|balance|funds)|billing_hard_limit/i;
|
|
8565
|
+
var BILLING_TEXT = /insufficient_quota|payment[ _]required|exhausted balance|insufficient (?:credits?|balance|funds)|billing_hard_limit|top up (?:api )?credit/i;
|
|
8188
8566
|
var BILLING_TEXT_STATUSES = /* @__PURE__ */ new Set([403, 429]);
|
|
8189
8567
|
function billingCode(body) {
|
|
8190
8568
|
const parsed = errorCodes.safeParse(body);
|
|
@@ -8581,16 +8959,16 @@ async function generateSeedreamImage(req, ctx) {
|
|
|
8581
8959
|
} else {
|
|
8582
8960
|
throwArkError(void 0, "Seedream returned no image URL or base64 data", modelId);
|
|
8583
8961
|
}
|
|
8584
|
-
const
|
|
8962
|
+
const usage5 = {
|
|
8585
8963
|
model: modelId,
|
|
8586
8964
|
provider: "ark",
|
|
8587
8965
|
modality: "IMAGE",
|
|
8588
8966
|
unit: "images",
|
|
8589
8967
|
quantity: 1
|
|
8590
8968
|
};
|
|
8591
|
-
if (req.size !== void 0)
|
|
8592
|
-
if (req.quality !== void 0)
|
|
8593
|
-
return { images: [{ bytes, mime: sniffedImageMime(bytes) }], usage:
|
|
8969
|
+
if (req.size !== void 0) usage5.imageSize = req.size;
|
|
8970
|
+
if (req.quality !== void 0) usage5.imageQuality = req.quality;
|
|
8971
|
+
return { images: [{ bytes, mime: sniffedImageMime(bytes) }], usage: usage5, raw: data };
|
|
8594
8972
|
}
|
|
8595
8973
|
var SeedanceUsageSchema = import_zod7.z.object({
|
|
8596
8974
|
total_tokens: import_zod7.z.number().optional(),
|
|
@@ -8631,7 +9009,7 @@ function seedanceErrorMessage(error, status) {
|
|
|
8631
9009
|
if (asObject.success && asObject.data.message !== void 0) return asObject.data.message;
|
|
8632
9010
|
return `Seedance task ${status}`;
|
|
8633
9011
|
}
|
|
8634
|
-
function seedanceJob(ctx, key, jobId,
|
|
9012
|
+
function seedanceJob(ctx, key, jobId, usage5) {
|
|
8635
9013
|
const modelId = ctx.model.id;
|
|
8636
9014
|
const fetchStatus = async () => {
|
|
8637
9015
|
const res = await arkFetch(ctx, `${arkBaseUrl(ctx)}${SUBMIT_PATH}/${jobId}`, {
|
|
@@ -8681,21 +9059,21 @@ function seedanceJob(ctx, key, jobId, usage3) {
|
|
|
8681
9059
|
modelId
|
|
8682
9060
|
);
|
|
8683
9061
|
if (polled.duration !== void 0 && polled.duration > 0) {
|
|
8684
|
-
|
|
8685
|
-
|
|
9062
|
+
usage5.quantity = polled.duration;
|
|
9063
|
+
usage5.durationSeconds = polled.duration;
|
|
8686
9064
|
}
|
|
8687
9065
|
const rendered = VideoResolutionSchema.safeParse(
|
|
8688
9066
|
polled.resolution?.toLowerCase()
|
|
8689
9067
|
);
|
|
8690
|
-
if (rendered.success)
|
|
9068
|
+
if (rendered.success) usage5.resolution = rendered.data;
|
|
8691
9069
|
const tokens = polled.usage;
|
|
8692
9070
|
if (tokens?.total_tokens !== void 0 && tokens.completion_tokens !== void 0) {
|
|
8693
|
-
|
|
8694
|
-
|
|
9071
|
+
usage5.inputTokens = tokens.total_tokens - tokens.completion_tokens;
|
|
9072
|
+
usage5.outputTokens = tokens.completion_tokens;
|
|
8695
9073
|
}
|
|
8696
9074
|
return {
|
|
8697
9075
|
video: { url, expiresAt: new Date(Date.now() + VIDEO_URL_TTL_MS) },
|
|
8698
|
-
usage:
|
|
9076
|
+
usage: usage5,
|
|
8699
9077
|
raw: polled
|
|
8700
9078
|
};
|
|
8701
9079
|
}
|
|
@@ -8801,8 +9179,8 @@ async function generateSeedanceVideo(req, ctx) {
|
|
|
8801
9179
|
);
|
|
8802
9180
|
if (!submit.id) throwArkError(void 0, "Seedance task create returned no id", modelId);
|
|
8803
9181
|
const jobId = submit.id;
|
|
8804
|
-
const
|
|
8805
|
-
return seedanceJob(ctx, key, jobId,
|
|
9182
|
+
const usage5 = seedanceUsage(ctx, req, taskType === "edit" ? requestedDuration : duration);
|
|
9183
|
+
return seedanceJob(ctx, key, jobId, usage5);
|
|
8806
9184
|
}
|
|
8807
9185
|
|
|
8808
9186
|
// src/adapters/fal.ts
|
|
@@ -10290,7 +10668,7 @@ async function collectFalPlanImages(payload, plan4, ctx, req) {
|
|
|
10290
10668
|
return { bytes, mime: mime || "image/png" };
|
|
10291
10669
|
})
|
|
10292
10670
|
);
|
|
10293
|
-
const
|
|
10671
|
+
const usage5 = {
|
|
10294
10672
|
model: ctx.model.id,
|
|
10295
10673
|
provider: "fal",
|
|
10296
10674
|
modality: "IMAGE",
|
|
@@ -10298,9 +10676,9 @@ async function collectFalPlanImages(payload, plan4, ctx, req) {
|
|
|
10298
10676
|
quantity: images.length
|
|
10299
10677
|
};
|
|
10300
10678
|
const billedSize = plan4.imageSize ?? req.size;
|
|
10301
|
-
if (billedSize !== void 0 && ctx.model.type === "image")
|
|
10302
|
-
if (plan4.imageQuality !== void 0)
|
|
10303
|
-
const result = { images, usage:
|
|
10679
|
+
if (billedSize !== void 0 && ctx.model.type === "image") usage5.imageSize = billedSize;
|
|
10680
|
+
if (plan4.imageQuality !== void 0) usage5.imageQuality = plan4.imageQuality;
|
|
10681
|
+
const result = { images, usage: usage5, raw: payload };
|
|
10304
10682
|
const remote = files.find((f) => !f.url.startsWith("data:"));
|
|
10305
10683
|
if (remote !== void 0) result.outputUrl = remote.url;
|
|
10306
10684
|
return result;
|
|
@@ -12463,12 +12841,568 @@ function planUsage(ctx, plan4) {
|
|
|
12463
12841
|
};
|
|
12464
12842
|
}
|
|
12465
12843
|
|
|
12466
|
-
// src/adapters/
|
|
12844
|
+
// src/adapters/elevenlabs.ts
|
|
12845
|
+
var import_zod21 = require("zod");
|
|
12846
|
+
var DEFAULT_BASE_URL = "https://api.elevenlabs.io";
|
|
12847
|
+
var DEFAULT_FORMAT = "mp3_44100_128";
|
|
12848
|
+
var ELEVENLABS_TTS_MODEL_IDS = /* @__PURE__ */ new Set(["eleven_v4"]);
|
|
12849
|
+
var ELEVENLABS_IVC = "ivc";
|
|
12850
|
+
var VOICE_ID = /^[A-Za-z0-9_-]{1,64}$/;
|
|
12851
|
+
function elevenLabsRowRefusal(row2) {
|
|
12852
|
+
const id = row2.providerModelId;
|
|
12853
|
+
if (row2.type === "speech") {
|
|
12854
|
+
return ELEVENLABS_TTS_MODEL_IDS.has(id) ? void 0 : `elevenlabs speech rows need providerModelId ${[...ELEVENLABS_TTS_MODEL_IDS].join(", ")}`;
|
|
12855
|
+
}
|
|
12856
|
+
if (row2.type === "voice-clone") {
|
|
12857
|
+
return id === ELEVENLABS_IVC ? void 0 : `elevenlabs voice-clone rows need providerModelId ${ELEVENLABS_IVC}`;
|
|
12858
|
+
}
|
|
12859
|
+
return `elevenlabs has no ${row2.type} rows`;
|
|
12860
|
+
}
|
|
12861
|
+
function elevenLabsError(ctx, code, message) {
|
|
12862
|
+
return new ModelKitError({
|
|
12863
|
+
code,
|
|
12864
|
+
message,
|
|
12865
|
+
provider: "elevenlabs",
|
|
12866
|
+
model: ctx.model.id,
|
|
12867
|
+
retryable: false
|
|
12868
|
+
});
|
|
12869
|
+
}
|
|
12870
|
+
function checkRow(ctx, type) {
|
|
12871
|
+
const refusal2 = ctx.model.type === type ? elevenLabsRowRefusal(ctx.model) : void 0;
|
|
12872
|
+
if (ctx.model.type !== type || refusal2 !== void 0) {
|
|
12873
|
+
throw elevenLabsError(
|
|
12874
|
+
ctx,
|
|
12875
|
+
"unsupported_option",
|
|
12876
|
+
refusal2 ?? `${ctx.model.id} is not a ${type} row`
|
|
12877
|
+
);
|
|
12878
|
+
}
|
|
12879
|
+
}
|
|
12880
|
+
function checkVoiceId(ctx, field, id) {
|
|
12881
|
+
if (!VOICE_ID.test(id))
|
|
12882
|
+
throw elevenLabsError(ctx, "unsupported_option", `${field} is not a voice id`);
|
|
12883
|
+
return id;
|
|
12884
|
+
}
|
|
12885
|
+
function elevenLabsKey(ctx) {
|
|
12886
|
+
const key = ctx.keys.elevenlabs;
|
|
12887
|
+
if (!key) throw elevenLabsError(ctx, "auth", "Missing API key for elevenlabs");
|
|
12888
|
+
return key;
|
|
12889
|
+
}
|
|
12890
|
+
function elevenLabsUrl(ctx, path) {
|
|
12891
|
+
return `${ctx.endpoints?.elevenlabs ?? DEFAULT_BASE_URL}${path}`;
|
|
12892
|
+
}
|
|
12893
|
+
var errorDetail = import_zod21.z.object({
|
|
12894
|
+
detail: import_zod21.z.object({ status: import_zod21.z.string(), message: import_zod21.z.string().optional() })
|
|
12895
|
+
});
|
|
12896
|
+
function errorStatus(body) {
|
|
12897
|
+
const parsed = errorDetail.safeParse(body);
|
|
12898
|
+
return parsed.success ? parsed.data.detail : void 0;
|
|
12899
|
+
}
|
|
12900
|
+
function classifyResponse(ctx, status, body) {
|
|
12901
|
+
const error = classifyHttpError(status, body, "elevenlabs", ctx.model.id);
|
|
12902
|
+
const detail = errorStatus(body);
|
|
12903
|
+
if (detail?.status === "voice_limit_reached") {
|
|
12904
|
+
return new ModelKitError({
|
|
12905
|
+
code: "provider_rejected",
|
|
12906
|
+
message: detail.message ?? "ElevenLabs voice limit reached",
|
|
12907
|
+
provider: "elevenlabs",
|
|
12908
|
+
model: ctx.model.id,
|
|
12909
|
+
status,
|
|
12910
|
+
body,
|
|
12911
|
+
cause: error,
|
|
12912
|
+
retryable: false
|
|
12913
|
+
});
|
|
12914
|
+
}
|
|
12915
|
+
if (detail?.status === "quota_exceeded") {
|
|
12916
|
+
return new ModelKitError({
|
|
12917
|
+
code: "provider_billing",
|
|
12918
|
+
message: error.message,
|
|
12919
|
+
provider: "elevenlabs",
|
|
12920
|
+
model: ctx.model.id,
|
|
12921
|
+
status,
|
|
12922
|
+
body,
|
|
12923
|
+
cause: error,
|
|
12924
|
+
retryable: false
|
|
12925
|
+
});
|
|
12926
|
+
}
|
|
12927
|
+
return error;
|
|
12928
|
+
}
|
|
12929
|
+
async function elevenLabsFetch(ctx, path, init) {
|
|
12930
|
+
throwIfAborted(ctx.signal);
|
|
12931
|
+
const request = {
|
|
12932
|
+
method: init.method,
|
|
12933
|
+
headers: { "xi-api-key": elevenLabsKey(ctx), ...init.headers }
|
|
12934
|
+
};
|
|
12935
|
+
if (init.body !== void 0) request.body = init.body;
|
|
12936
|
+
if (ctx.signal !== void 0) request.signal = ctx.signal;
|
|
12937
|
+
let res;
|
|
12938
|
+
try {
|
|
12939
|
+
res = await ctx.fetch(elevenLabsUrl(ctx, path), request);
|
|
12940
|
+
} catch (cause) {
|
|
12941
|
+
throw classifyThrown("elevenlabs", cause, ctx.model.id);
|
|
12942
|
+
}
|
|
12943
|
+
if (!res.ok) throw classifyResponse(ctx, res.status, await readBody(res));
|
|
12944
|
+
return res;
|
|
12945
|
+
}
|
|
12946
|
+
function usage2(ctx) {
|
|
12947
|
+
return {
|
|
12948
|
+
model: ctx.model.id,
|
|
12949
|
+
provider: "elevenlabs",
|
|
12950
|
+
modality: "AUDIO",
|
|
12951
|
+
unit: ctx.model.usage.unit,
|
|
12952
|
+
quantity: 1
|
|
12953
|
+
};
|
|
12954
|
+
}
|
|
12955
|
+
function audioMime(res) {
|
|
12956
|
+
const header = res.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase();
|
|
12957
|
+
return header?.startsWith("audio/") ? header : "audio/mpeg";
|
|
12958
|
+
}
|
|
12959
|
+
async function generateSpeech(req, ctx) {
|
|
12960
|
+
checkRow(ctx, "speech");
|
|
12961
|
+
const voice = req.customVoice ?? req.voice;
|
|
12962
|
+
if (voice === void 0) throw elevenLabsError(ctx, "missing_input", "needs a voice");
|
|
12963
|
+
const voiceId = checkVoiceId(ctx, req.customVoice ? "customVoice" : "voice", voice);
|
|
12964
|
+
const format = req.outputFormat ?? DEFAULT_FORMAT;
|
|
12965
|
+
const body = { text: req.text, model_id: ctx.model.providerModelId };
|
|
12966
|
+
if (req.language !== void 0) body.language_code = req.language;
|
|
12967
|
+
const path = `/v1/text-to-speech/${encodeURIComponent(voiceId)}?output_format=${encodeURIComponent(format)}`;
|
|
12968
|
+
const { bytes, mime } = await withRetry(
|
|
12969
|
+
async () => {
|
|
12970
|
+
const res = await elevenLabsFetch(ctx, path, {
|
|
12971
|
+
method: "POST",
|
|
12972
|
+
headers: { "Content-Type": "application/json" },
|
|
12973
|
+
body: JSON.stringify(body)
|
|
12974
|
+
});
|
|
12975
|
+
let audio;
|
|
12976
|
+
try {
|
|
12977
|
+
audio = new Uint8Array(await res.arrayBuffer());
|
|
12978
|
+
} catch (cause) {
|
|
12979
|
+
throw classifyThrown("elevenlabs", cause, ctx.model.id);
|
|
12980
|
+
}
|
|
12981
|
+
return { bytes: audio, mime: audioMime(res) };
|
|
12982
|
+
},
|
|
12983
|
+
mediaRetryOptions(ctx.call, ctx.signal)
|
|
12984
|
+
);
|
|
12985
|
+
if (bytes.byteLength === 0)
|
|
12986
|
+
throw elevenLabsError(ctx, "provider_rejected", "ElevenLabs TTS returned no audio");
|
|
12987
|
+
return { audio: { bytes, mime }, usage: usage2(ctx) };
|
|
12988
|
+
}
|
|
12989
|
+
var createdVoiceSchema = import_zod21.z.object({
|
|
12990
|
+
voice_id: import_zod21.z.string().min(1),
|
|
12991
|
+
requires_verification: import_zod21.z.boolean().optional().catch(void 0)
|
|
12992
|
+
});
|
|
12993
|
+
function sampleMime(mime) {
|
|
12994
|
+
return mime.startsWith("audio/") || mime.startsWith("video/") ? mime : "application/octet-stream";
|
|
12995
|
+
}
|
|
12996
|
+
function fileName(index, mime, ref) {
|
|
12997
|
+
const fromMime = mime === "application/octet-stream" ? void 0 : mime.split("/")[1]?.replace("mpeg", "mp3").replace("x-", "");
|
|
12998
|
+
const fromUrl = "url" in ref ? /\.([A-Za-z0-9]{2,4})$/.exec(new URL(ref.url).pathname)?.[1] : void 0;
|
|
12999
|
+
const ext = fromMime || fromUrl?.toLowerCase();
|
|
13000
|
+
return ext ? `sample-${index + 1}.${ext}` : `sample-${index + 1}`;
|
|
13001
|
+
}
|
|
13002
|
+
async function cloneForm(req, ctx) {
|
|
13003
|
+
if (req.samples.length === 0)
|
|
13004
|
+
throw elevenLabsError(ctx, "missing_input", "needs a voice sample");
|
|
13005
|
+
if (req.samples.some((s) => s.designSignature?.trim())) {
|
|
13006
|
+
throw elevenLabsError(
|
|
13007
|
+
ctx,
|
|
13008
|
+
"unsupported_option",
|
|
13009
|
+
"ElevenLabs cannot keep a voice design signature; clone from recordings only"
|
|
13010
|
+
);
|
|
13011
|
+
}
|
|
13012
|
+
const form = new FormData();
|
|
13013
|
+
form.append("name", req.title.trim());
|
|
13014
|
+
if (req.description?.trim()) form.append("description", req.description.trim());
|
|
13015
|
+
if (req.enhance !== void 0) form.append("remove_background_noise", String(req.enhance));
|
|
13016
|
+
for (const [index, sample] of req.samples.entries()) {
|
|
13017
|
+
const { bytes, mime } = await mediaRefToBytes(sample.audio, ctx.fetch, {
|
|
13018
|
+
signal: ctx.signal,
|
|
13019
|
+
provider: "elevenlabs",
|
|
13020
|
+
model: ctx.model.id
|
|
13021
|
+
});
|
|
13022
|
+
const type = sampleMime(mime);
|
|
13023
|
+
const audio = new Blob([new Uint8Array(bytes)], { type });
|
|
13024
|
+
form.append("files", audio, fileName(index, type, sample.audio));
|
|
13025
|
+
}
|
|
13026
|
+
return form;
|
|
13027
|
+
}
|
|
13028
|
+
async function onlyRateLimitRetries(fn) {
|
|
13029
|
+
try {
|
|
13030
|
+
return await fn();
|
|
13031
|
+
} catch (cause) {
|
|
13032
|
+
if (!isModelKitError(cause) || !cause.retryable || cause.code === "rate_limited")
|
|
13033
|
+
throw cause;
|
|
13034
|
+
throw new ModelKitError({
|
|
13035
|
+
code: cause.code,
|
|
13036
|
+
message: cause.message,
|
|
13037
|
+
...cause.provider !== void 0 && { provider: cause.provider },
|
|
13038
|
+
...cause.model !== void 0 && { model: cause.model },
|
|
13039
|
+
...cause.status !== void 0 && { status: cause.status },
|
|
13040
|
+
...cause.body !== void 0 && { body: cause.body },
|
|
13041
|
+
cause,
|
|
13042
|
+
retryable: false
|
|
13043
|
+
});
|
|
13044
|
+
}
|
|
13045
|
+
}
|
|
13046
|
+
async function createVoice(req, ctx) {
|
|
13047
|
+
checkRow(ctx, "voice-clone");
|
|
13048
|
+
const form = await cloneForm(req, ctx);
|
|
13049
|
+
const res = await withRetry(
|
|
13050
|
+
() => onlyRateLimitRetries(
|
|
13051
|
+
() => elevenLabsFetch(ctx, "/v1/voices/add", { method: "POST", body: form })
|
|
13052
|
+
),
|
|
13053
|
+
mediaRetryOptions(ctx.call, ctx.signal)
|
|
13054
|
+
);
|
|
13055
|
+
const raw = await readBody(res);
|
|
13056
|
+
const parsed = createdVoiceSchema.safeParse(raw);
|
|
13057
|
+
if (!parsed.success) {
|
|
13058
|
+
throw new ModelKitError({
|
|
13059
|
+
code: "provider_rejected",
|
|
13060
|
+
message: "ElevenLabs returned no voice id",
|
|
13061
|
+
provider: "elevenlabs",
|
|
13062
|
+
model: ctx.model.id,
|
|
13063
|
+
status: res.status,
|
|
13064
|
+
body: raw,
|
|
13065
|
+
retryable: false
|
|
13066
|
+
});
|
|
13067
|
+
}
|
|
13068
|
+
return {
|
|
13069
|
+
voiceId: parsed.data.voice_id,
|
|
13070
|
+
state: parsed.data.requires_verification === true ? "created" : "trained",
|
|
13071
|
+
usage: usage2(ctx),
|
|
13072
|
+
raw
|
|
13073
|
+
};
|
|
13074
|
+
}
|
|
13075
|
+
var NOT_FOUND_STATUSES = /* @__PURE__ */ new Set([
|
|
13076
|
+
"voice_not_found",
|
|
13077
|
+
"voice_does_not_exist"
|
|
13078
|
+
]);
|
|
13079
|
+
function notFound(cause) {
|
|
13080
|
+
if (cause.status === 404) return true;
|
|
13081
|
+
const status = errorStatus(cause.body)?.status;
|
|
13082
|
+
return cause.status === 400 && status !== void 0 && NOT_FOUND_STATUSES.has(status);
|
|
13083
|
+
}
|
|
13084
|
+
async function deleteVoice(req, ctx) {
|
|
13085
|
+
checkRow(ctx, "voice-clone");
|
|
13086
|
+
const id = encodeURIComponent(checkVoiceId(ctx, "voiceId", req.voiceId));
|
|
13087
|
+
let attempts = 0;
|
|
13088
|
+
await withRetry(
|
|
13089
|
+
async () => {
|
|
13090
|
+
attempts += 1;
|
|
13091
|
+
try {
|
|
13092
|
+
await elevenLabsFetch(ctx, `/v1/voices/${id}`, { method: "DELETE" });
|
|
13093
|
+
} catch (cause) {
|
|
13094
|
+
if (!isModelKitError(cause) || !notFound(cause)) throw cause;
|
|
13095
|
+
if (attempts > 1) return;
|
|
13096
|
+
throw new ModelKitError({
|
|
13097
|
+
code: "provider_rejected",
|
|
13098
|
+
message: `ElevenLabs has no voice ${req.voiceId} under this key set; delete with the tier that created it`,
|
|
13099
|
+
provider: "elevenlabs",
|
|
13100
|
+
model: ctx.model.id,
|
|
13101
|
+
...cause.status !== void 0 && { status: cause.status },
|
|
13102
|
+
cause,
|
|
13103
|
+
retryable: false
|
|
13104
|
+
});
|
|
13105
|
+
}
|
|
13106
|
+
},
|
|
13107
|
+
mediaRetryOptions(ctx.call, ctx.signal)
|
|
13108
|
+
);
|
|
13109
|
+
}
|
|
13110
|
+
var elevenLabsAdapter = {
|
|
13111
|
+
id: "elevenlabs",
|
|
13112
|
+
generateSpeech,
|
|
13113
|
+
createVoice,
|
|
13114
|
+
deleteVoice
|
|
13115
|
+
};
|
|
13116
|
+
|
|
13117
|
+
// src/adapters/fish.ts
|
|
12467
13118
|
var import_zod22 = require("zod");
|
|
13119
|
+
var DEFAULT_BASE_URL2 = "https://api.fish.audio";
|
|
13120
|
+
var FISH_TTS_MODEL_IDS = /* @__PURE__ */ new Set([
|
|
13121
|
+
"s2.1-pro",
|
|
13122
|
+
"s2.1-pro-free",
|
|
13123
|
+
"drama-3"
|
|
13124
|
+
]);
|
|
13125
|
+
var FISH_VOICE_CLONE = "voice-clone";
|
|
13126
|
+
var FISH_VOICE_DESIGN = "voice-design-1";
|
|
13127
|
+
var VOICE_ID2 = /^[A-Za-z0-9_-]{1,64}$/;
|
|
13128
|
+
function fishRowRefusal(row2) {
|
|
13129
|
+
const id = row2.providerModelId;
|
|
13130
|
+
if (row2.type === "speech") {
|
|
13131
|
+
return FISH_TTS_MODEL_IDS.has(id) ? void 0 : `fish speech rows need providerModelId ${[...FISH_TTS_MODEL_IDS].join(", ")}`;
|
|
13132
|
+
}
|
|
13133
|
+
if (row2.type === "voice-clone") {
|
|
13134
|
+
return id === FISH_VOICE_CLONE ? void 0 : `fish voice-clone rows need providerModelId ${FISH_VOICE_CLONE}`;
|
|
13135
|
+
}
|
|
13136
|
+
if (row2.type === "voice-design") {
|
|
13137
|
+
return id === FISH_VOICE_DESIGN ? void 0 : `fish voice-design rows need providerModelId ${FISH_VOICE_DESIGN}`;
|
|
13138
|
+
}
|
|
13139
|
+
return `fish has no ${row2.type} rows`;
|
|
13140
|
+
}
|
|
13141
|
+
function fishError(ctx, code, message) {
|
|
13142
|
+
return new ModelKitError({
|
|
13143
|
+
code,
|
|
13144
|
+
message,
|
|
13145
|
+
provider: "fish",
|
|
13146
|
+
model: ctx.model.id,
|
|
13147
|
+
retryable: false
|
|
13148
|
+
});
|
|
13149
|
+
}
|
|
13150
|
+
function checkRow2(ctx, type) {
|
|
13151
|
+
const refusal2 = ctx.model.type === type ? fishRowRefusal(ctx.model) : void 0;
|
|
13152
|
+
if (ctx.model.type !== type || refusal2 !== void 0) {
|
|
13153
|
+
throw fishError(
|
|
13154
|
+
ctx,
|
|
13155
|
+
"unsupported_option",
|
|
13156
|
+
refusal2 ?? `${ctx.model.id} is not a ${type} row`
|
|
13157
|
+
);
|
|
13158
|
+
}
|
|
13159
|
+
}
|
|
13160
|
+
function checkVoiceId2(ctx, field, id) {
|
|
13161
|
+
if (!VOICE_ID2.test(id))
|
|
13162
|
+
throw fishError(ctx, "unsupported_option", `${field} is not a voice id`);
|
|
13163
|
+
return id;
|
|
13164
|
+
}
|
|
13165
|
+
function fishKey(ctx) {
|
|
13166
|
+
const key = ctx.keys.fish;
|
|
13167
|
+
if (!key) throw fishError(ctx, "auth", "Missing API key for fish");
|
|
13168
|
+
return key;
|
|
13169
|
+
}
|
|
13170
|
+
function fishUrl(ctx, path) {
|
|
13171
|
+
return `${ctx.endpoints?.fish ?? DEFAULT_BASE_URL2}${path}`;
|
|
13172
|
+
}
|
|
13173
|
+
async function fishFetch(ctx, path, init) {
|
|
13174
|
+
throwIfAborted(ctx.signal);
|
|
13175
|
+
const request = {
|
|
13176
|
+
method: init.method,
|
|
13177
|
+
headers: { Authorization: `Bearer ${fishKey(ctx)}`, ...init.headers }
|
|
13178
|
+
};
|
|
13179
|
+
if (init.body !== void 0) request.body = init.body;
|
|
13180
|
+
if (ctx.signal !== void 0) request.signal = ctx.signal;
|
|
13181
|
+
let res;
|
|
13182
|
+
try {
|
|
13183
|
+
res = await ctx.fetch(fishUrl(ctx, path), request);
|
|
13184
|
+
} catch (cause) {
|
|
13185
|
+
throw classifyThrown("fish", cause, ctx.model.id);
|
|
13186
|
+
}
|
|
13187
|
+
if (!res.ok) throw classifyHttpError(res.status, await readBody(res), "fish", ctx.model.id);
|
|
13188
|
+
return res;
|
|
13189
|
+
}
|
|
13190
|
+
function usage3(ctx) {
|
|
13191
|
+
return {
|
|
13192
|
+
model: ctx.model.id,
|
|
13193
|
+
provider: "fish",
|
|
13194
|
+
modality: "AUDIO",
|
|
13195
|
+
unit: ctx.model.usage.unit,
|
|
13196
|
+
quantity: 1
|
|
13197
|
+
};
|
|
13198
|
+
}
|
|
13199
|
+
function audioMime2(res, format) {
|
|
13200
|
+
const header = res.headers.get("content-type")?.split(";")[0]?.trim().toLowerCase();
|
|
13201
|
+
if (header?.startsWith("audio/")) return header;
|
|
13202
|
+
return format === "wav" ? "audio/wav" : "audio/mpeg";
|
|
13203
|
+
}
|
|
13204
|
+
async function generateSpeech2(req, ctx) {
|
|
13205
|
+
checkRow2(ctx, "speech");
|
|
13206
|
+
const format = req.outputFormat ?? "mp3";
|
|
13207
|
+
const body = { text: req.text, format };
|
|
13208
|
+
const voice = req.customVoice ?? req.voice;
|
|
13209
|
+
if (voice !== void 0) {
|
|
13210
|
+
body.reference_id = checkVoiceId2(ctx, req.customVoice ? "customVoice" : "voice", voice);
|
|
13211
|
+
}
|
|
13212
|
+
if (req.language !== void 0) body.language = req.language;
|
|
13213
|
+
const { bytes, mime } = await withRetry(
|
|
13214
|
+
async () => {
|
|
13215
|
+
const res = await fishFetch(ctx, "/v1/tts", {
|
|
13216
|
+
method: "POST",
|
|
13217
|
+
headers: { "Content-Type": "application/json", model: ctx.model.providerModelId },
|
|
13218
|
+
body: JSON.stringify(body)
|
|
13219
|
+
});
|
|
13220
|
+
let audio;
|
|
13221
|
+
try {
|
|
13222
|
+
audio = new Uint8Array(await res.arrayBuffer());
|
|
13223
|
+
} catch (cause) {
|
|
13224
|
+
throw classifyThrown("fish", cause, ctx.model.id);
|
|
13225
|
+
}
|
|
13226
|
+
return { bytes: audio, mime: audioMime2(res, format) };
|
|
13227
|
+
},
|
|
13228
|
+
mediaRetryOptions(ctx.call, ctx.signal)
|
|
13229
|
+
);
|
|
13230
|
+
if (bytes.byteLength === 0)
|
|
13231
|
+
throw fishError(ctx, "provider_rejected", "Fish TTS returned no audio");
|
|
13232
|
+
return { audio: { bytes, mime }, usage: usage3(ctx) };
|
|
13233
|
+
}
|
|
13234
|
+
var createdModelSchema = import_zod22.z.object({
|
|
13235
|
+
_id: import_zod22.z.string().min(1),
|
|
13236
|
+
state: import_zod22.z.enum(["created", "training", "trained", "failed"]).optional().catch(void 0)
|
|
13237
|
+
});
|
|
13238
|
+
function fileName2(index, mime) {
|
|
13239
|
+
const ext = mime.split("/")[1]?.replace("mpeg", "mp3").replace("x-", "") || "bin";
|
|
13240
|
+
return `sample-${index + 1}.${ext}`;
|
|
13241
|
+
}
|
|
13242
|
+
function allOrNone(ctx, field, values) {
|
|
13243
|
+
const set = values.filter((v) => v !== void 0 && v.trim() !== "");
|
|
13244
|
+
if (set.length === 0) return [];
|
|
13245
|
+
if (set.length !== values.length) {
|
|
13246
|
+
throw fishError(ctx, "missing_input", `set ${field} on every sample or on none`);
|
|
13247
|
+
}
|
|
13248
|
+
return set;
|
|
13249
|
+
}
|
|
13250
|
+
async function cloneForm2(req, ctx) {
|
|
13251
|
+
if (req.samples.length === 0) throw fishError(ctx, "missing_input", "needs a voice sample");
|
|
13252
|
+
const transcripts = allOrNone(
|
|
13253
|
+
ctx,
|
|
13254
|
+
"transcript",
|
|
13255
|
+
req.samples.map((s) => s.transcript)
|
|
13256
|
+
);
|
|
13257
|
+
const signatures = allOrNone(
|
|
13258
|
+
ctx,
|
|
13259
|
+
"designSignature",
|
|
13260
|
+
req.samples.map((s) => s.designSignature)
|
|
13261
|
+
);
|
|
13262
|
+
const form = new FormData();
|
|
13263
|
+
form.append("type", "tts");
|
|
13264
|
+
form.append("train_mode", "fast");
|
|
13265
|
+
form.append("visibility", "private");
|
|
13266
|
+
form.append("title", req.title.trim());
|
|
13267
|
+
if (req.description?.trim()) form.append("description", req.description.trim());
|
|
13268
|
+
if (req.enhance !== void 0) form.append("enhance_audio_quality", String(req.enhance));
|
|
13269
|
+
for (const [index, sample] of req.samples.entries()) {
|
|
13270
|
+
const { bytes, mime } = await mediaRefToBytes(sample.audio, ctx.fetch, {
|
|
13271
|
+
signal: ctx.signal,
|
|
13272
|
+
provider: "fish",
|
|
13273
|
+
model: ctx.model.id
|
|
13274
|
+
});
|
|
13275
|
+
const audio = new Blob([new Uint8Array(bytes)], { type: mime });
|
|
13276
|
+
form.append("voices", audio, fileName2(index, mime));
|
|
13277
|
+
}
|
|
13278
|
+
for (const text2 of transcripts) form.append("texts", text2.trim());
|
|
13279
|
+
for (const signature of signatures) form.append("voice_design_signatures", signature);
|
|
13280
|
+
return form;
|
|
13281
|
+
}
|
|
13282
|
+
async function onlyRateLimitRetries2(fn) {
|
|
13283
|
+
try {
|
|
13284
|
+
return await fn();
|
|
13285
|
+
} catch (cause) {
|
|
13286
|
+
if (!isModelKitError(cause) || !cause.retryable || cause.code === "rate_limited")
|
|
13287
|
+
throw cause;
|
|
13288
|
+
throw new ModelKitError({
|
|
13289
|
+
code: cause.code,
|
|
13290
|
+
message: cause.message,
|
|
13291
|
+
...cause.provider !== void 0 && { provider: cause.provider },
|
|
13292
|
+
...cause.model !== void 0 && { model: cause.model },
|
|
13293
|
+
...cause.status !== void 0 && { status: cause.status },
|
|
13294
|
+
...cause.body !== void 0 && { body: cause.body },
|
|
13295
|
+
cause,
|
|
13296
|
+
retryable: false
|
|
13297
|
+
});
|
|
13298
|
+
}
|
|
13299
|
+
}
|
|
13300
|
+
async function createVoice2(req, ctx) {
|
|
13301
|
+
checkRow2(ctx, "voice-clone");
|
|
13302
|
+
const form = await cloneForm2(req, ctx);
|
|
13303
|
+
const res = await withRetry(
|
|
13304
|
+
() => onlyRateLimitRetries2(() => fishFetch(ctx, "/model", { method: "POST", body: form })),
|
|
13305
|
+
mediaRetryOptions(ctx.call, ctx.signal)
|
|
13306
|
+
);
|
|
13307
|
+
const raw = await readBody(res);
|
|
13308
|
+
const parsed = createdModelSchema.safeParse(raw);
|
|
13309
|
+
if (!parsed.success) {
|
|
13310
|
+
throw new ModelKitError({
|
|
13311
|
+
code: "provider_rejected",
|
|
13312
|
+
message: "Fish returned no voice id",
|
|
13313
|
+
provider: "fish",
|
|
13314
|
+
model: ctx.model.id,
|
|
13315
|
+
status: res.status,
|
|
13316
|
+
body: raw,
|
|
13317
|
+
retryable: false
|
|
13318
|
+
});
|
|
13319
|
+
}
|
|
13320
|
+
const result = { voiceId: parsed.data._id, usage: usage3(ctx), raw };
|
|
13321
|
+
if (parsed.data.state !== void 0) result.state = parsed.data.state;
|
|
13322
|
+
return result;
|
|
13323
|
+
}
|
|
13324
|
+
var designSchema = import_zod22.z.object({
|
|
13325
|
+
candidates: import_zod22.z.array(
|
|
13326
|
+
import_zod22.z.looseObject({
|
|
13327
|
+
id: import_zod22.z.string().min(1),
|
|
13328
|
+
index: import_zod22.z.number().int(),
|
|
13329
|
+
audio_base64: import_zod22.z.string().min(1),
|
|
13330
|
+
duration_ms: import_zod22.z.number().nonnegative(),
|
|
13331
|
+
signature: import_zod22.z.string().min(1).optional()
|
|
13332
|
+
})
|
|
13333
|
+
).min(1)
|
|
13334
|
+
});
|
|
13335
|
+
async function designVoice(req, ctx) {
|
|
13336
|
+
checkRow2(ctx, "voice-design");
|
|
13337
|
+
const body = { instruction: req.prompt.trim() };
|
|
13338
|
+
if (req.previewText?.trim()) body.reference_text = req.previewText.trim();
|
|
13339
|
+
if (req.language !== void 0) body.language = req.language;
|
|
13340
|
+
if (req.count !== void 0) body.n = req.count;
|
|
13341
|
+
if (req.seed !== void 0) body.seed = req.seed;
|
|
13342
|
+
const raw = await withRetry(
|
|
13343
|
+
async () => {
|
|
13344
|
+
const res = await fishFetch(ctx, "/v1/voice-design", {
|
|
13345
|
+
method: "POST",
|
|
13346
|
+
headers: { "Content-Type": "application/json", model: ctx.model.providerModelId },
|
|
13347
|
+
body: JSON.stringify(body)
|
|
13348
|
+
});
|
|
13349
|
+
return readBody(res);
|
|
13350
|
+
},
|
|
13351
|
+
mediaRetryOptions(ctx.call, ctx.signal)
|
|
13352
|
+
);
|
|
13353
|
+
const parsed = designSchema.safeParse(raw);
|
|
13354
|
+
if (!parsed.success) {
|
|
13355
|
+
throw fishError(ctx, "provider_rejected", "Fish voice design returned no candidates");
|
|
13356
|
+
}
|
|
13357
|
+
const candidates = [...parsed.data.candidates].sort((a, b) => a.index - b.index).map((c) => ({
|
|
13358
|
+
audio: { bytes: base64ToBytes(c.audio_base64), mime: "audio/wav" },
|
|
13359
|
+
durationSeconds: c.duration_ms / 1e3,
|
|
13360
|
+
// The OpenAPI candidate has no signature field, so its stable id is the handle; Fish
|
|
13361
|
+
// rejects a clone whose signature does not verify, so a wrong one fails loudly.
|
|
13362
|
+
signature: c.signature ?? c.id
|
|
13363
|
+
}));
|
|
13364
|
+
return { candidates, usage: usage3(ctx) };
|
|
13365
|
+
}
|
|
13366
|
+
async function deleteVoice2(req, ctx) {
|
|
13367
|
+
checkRow2(ctx, "voice-clone");
|
|
13368
|
+
const id = encodeURIComponent(checkVoiceId2(ctx, "voiceId", req.voiceId));
|
|
13369
|
+
let attempts = 0;
|
|
13370
|
+
await withRetry(
|
|
13371
|
+
async () => {
|
|
13372
|
+
attempts += 1;
|
|
13373
|
+
try {
|
|
13374
|
+
await fishFetch(ctx, `/model/${id}`, { method: "DELETE" });
|
|
13375
|
+
} catch (cause) {
|
|
13376
|
+
if (!isModelKitError(cause) || cause.status !== 404) throw cause;
|
|
13377
|
+
if (attempts > 1) return;
|
|
13378
|
+
throw new ModelKitError({
|
|
13379
|
+
code: "provider_rejected",
|
|
13380
|
+
message: `Fish has no voice ${req.voiceId} under this key set; delete with the tier that created it`,
|
|
13381
|
+
provider: "fish",
|
|
13382
|
+
model: ctx.model.id,
|
|
13383
|
+
status: 404,
|
|
13384
|
+
cause,
|
|
13385
|
+
retryable: false
|
|
13386
|
+
});
|
|
13387
|
+
}
|
|
13388
|
+
},
|
|
13389
|
+
mediaRetryOptions(ctx.call, ctx.signal)
|
|
13390
|
+
);
|
|
13391
|
+
}
|
|
13392
|
+
var fishAdapter = {
|
|
13393
|
+
id: "fish",
|
|
13394
|
+
generateSpeech: generateSpeech2,
|
|
13395
|
+
createVoice: createVoice2,
|
|
13396
|
+
designVoice,
|
|
13397
|
+
deleteVoice: deleteVoice2
|
|
13398
|
+
};
|
|
13399
|
+
|
|
13400
|
+
// src/adapters/google-genai.ts
|
|
13401
|
+
var import_zod24 = require("zod");
|
|
12468
13402
|
var import_genai = require("@google/genai");
|
|
12469
13403
|
|
|
12470
13404
|
// src/adapters/google-files.ts
|
|
12471
|
-
var
|
|
13405
|
+
var import_zod23 = require("zod");
|
|
12472
13406
|
var GOOGLE_FILES_BASE = "https://generativelanguage.googleapis.com";
|
|
12473
13407
|
var GOOGLE_FILES_POLL_INTERVAL_MS = 2e3;
|
|
12474
13408
|
var GOOGLE_FILES_POLL_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
@@ -12478,17 +13412,17 @@ var GENERIC_MEDIA_TYPES = /* @__PURE__ */ new Set([
|
|
|
12478
13412
|
"binary/octet-stream",
|
|
12479
13413
|
"application/binary"
|
|
12480
13414
|
]);
|
|
12481
|
-
var uploadedFileSchema =
|
|
12482
|
-
file:
|
|
12483
|
-
uri:
|
|
12484
|
-
name:
|
|
12485
|
-
state:
|
|
12486
|
-
mimeType:
|
|
13415
|
+
var uploadedFileSchema = import_zod23.z.object({
|
|
13416
|
+
file: import_zod23.z.object({
|
|
13417
|
+
uri: import_zod23.z.string().optional(),
|
|
13418
|
+
name: import_zod23.z.string().optional(),
|
|
13419
|
+
state: import_zod23.z.string().optional(),
|
|
13420
|
+
mimeType: import_zod23.z.string().optional()
|
|
12487
13421
|
}).optional()
|
|
12488
13422
|
});
|
|
12489
|
-
var fileStateSchema =
|
|
12490
|
-
state:
|
|
12491
|
-
error:
|
|
13423
|
+
var fileStateSchema = import_zod23.z.object({
|
|
13424
|
+
state: import_zod23.z.string().optional(),
|
|
13425
|
+
error: import_zod23.z.object({ message: import_zod23.z.string().optional() }).optional()
|
|
12492
13426
|
});
|
|
12493
13427
|
function resolveMime(declared, fallback) {
|
|
12494
13428
|
const clean = declared?.split(";")[0]?.trim().toLowerCase();
|
|
@@ -12595,7 +13529,7 @@ async function startAndUpload(bytes, mimeType, opts) {
|
|
|
12595
13529
|
if (uploaded.file?.state !== void 0) ref.state = uploaded.file.state;
|
|
12596
13530
|
return ref;
|
|
12597
13531
|
}
|
|
12598
|
-
async function waitForActive(
|
|
13532
|
+
async function waitForActive(fileName3, opts) {
|
|
12599
13533
|
const pollOptions2 = {
|
|
12600
13534
|
intervalMs: GOOGLE_FILES_POLL_INTERVAL_MS,
|
|
12601
13535
|
timeoutMs: GOOGLE_FILES_POLL_TIMEOUT_MS
|
|
@@ -12608,14 +13542,14 @@ async function waitForActive(fileName, opts) {
|
|
|
12608
13542
|
retryInit.signal = opts.signal;
|
|
12609
13543
|
}
|
|
12610
13544
|
await pollUntil(async () => {
|
|
12611
|
-
const res = await opts.fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${
|
|
13545
|
+
const res = await opts.fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName3}`, retryInit);
|
|
12612
13546
|
if (res.ok) {
|
|
12613
13547
|
const json = fileStateSchema.parse(await res.json());
|
|
12614
13548
|
if (json.state === "ACTIVE") return true;
|
|
12615
13549
|
if (json.state === "FAILED") {
|
|
12616
13550
|
throw classifyHttpError(
|
|
12617
13551
|
void 0,
|
|
12618
|
-
`Files API processing failed for ${
|
|
13552
|
+
`Files API processing failed for ${fileName3}: ${json.error?.message ?? "unknown error"}`,
|
|
12619
13553
|
"google-genai",
|
|
12620
13554
|
opts.model
|
|
12621
13555
|
);
|
|
@@ -12627,9 +13561,9 @@ async function waitForActive(fileName, opts) {
|
|
|
12627
13561
|
throw classifyHttpError(res.status, text2, "google-genai", opts.model);
|
|
12628
13562
|
}, pollOptions2);
|
|
12629
13563
|
}
|
|
12630
|
-
async function deleteGoogleFile(
|
|
13564
|
+
async function deleteGoogleFile(fileName3, apiKey, fetchImpl) {
|
|
12631
13565
|
try {
|
|
12632
|
-
await fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${
|
|
13566
|
+
await fetchImpl(`${GOOGLE_FILES_BASE}/v1beta/${fileName3}`, {
|
|
12633
13567
|
method: "DELETE",
|
|
12634
13568
|
headers: { "x-goog-api-key": apiKey }
|
|
12635
13569
|
});
|
|
@@ -12709,7 +13643,7 @@ var OMNI_POLL_INTERVAL_MS = 1e4;
|
|
|
12709
13643
|
var RESULT_TIMEOUT_MS3 = 15 * 60 * 1e3;
|
|
12710
13644
|
var OMNI_INLINE_LIMIT_BYTES = 4 * 1024 * 1024;
|
|
12711
13645
|
var MEDIA_PART_INLINE_LIMIT_BYTES = 10 * 1024 * 1024;
|
|
12712
|
-
var errorTextSchema =
|
|
13646
|
+
var errorTextSchema = import_zod24.z.string();
|
|
12713
13647
|
function isGoogleGenaiVideoKnown(providerModelId) {
|
|
12714
13648
|
return providerModelId.startsWith("veo-") || providerModelId.startsWith("gemini-omni");
|
|
12715
13649
|
}
|
|
@@ -12904,7 +13838,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
|
|
|
12904
13838
|
}
|
|
12905
13839
|
};
|
|
12906
13840
|
const jobId = operation.name ?? crypto.randomUUID();
|
|
12907
|
-
const
|
|
13841
|
+
const usage5 = videoUsage2(ctx, duration, req.resolution ?? "720p");
|
|
12908
13842
|
return {
|
|
12909
13843
|
jobId,
|
|
12910
13844
|
async poll() {
|
|
@@ -12942,7 +13876,7 @@ async function generateVeoVideo(req, ctx, createGenAIClient) {
|
|
|
12942
13876
|
modelId
|
|
12943
13877
|
);
|
|
12944
13878
|
}
|
|
12945
|
-
return { video: await downloadVideo(ctx, uri, apiKey, signal), usage:
|
|
13879
|
+
return { video: await downloadVideo(ctx, uri, apiKey, signal), usage: usage5, raw: finished };
|
|
12946
13880
|
}
|
|
12947
13881
|
};
|
|
12948
13882
|
}
|
|
@@ -13053,7 +13987,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
|
|
|
13053
13987
|
return file.fileUri;
|
|
13054
13988
|
};
|
|
13055
13989
|
const cleanupUploads = async () => {
|
|
13056
|
-
for (const
|
|
13990
|
+
for (const fileName3 of uploadedNames) await deleteGoogleFile(fileName3, apiKey, ctx.fetch);
|
|
13057
13991
|
};
|
|
13058
13992
|
const callCreate = (input) => client2.interactions.create(
|
|
13059
13993
|
previousId !== void 0 ? {
|
|
@@ -13147,7 +14081,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
|
|
|
13147
14081
|
if (!(extend && !chained)) await cleanupUploads();
|
|
13148
14082
|
}
|
|
13149
14083
|
const jobId = interaction.id ?? crypto.randomUUID();
|
|
13150
|
-
const
|
|
14084
|
+
const usage5 = videoUsage2(ctx, duration, omniResolution ?? "720p");
|
|
13151
14085
|
const getInteraction = async () => {
|
|
13152
14086
|
try {
|
|
13153
14087
|
const getParams = { stream: false };
|
|
@@ -13195,7 +14129,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
|
|
|
13195
14129
|
bytes: Buffer.from(video.data, "base64"),
|
|
13196
14130
|
mime: video.mime_type ?? "video/mp4"
|
|
13197
14131
|
},
|
|
13198
|
-
usage:
|
|
14132
|
+
usage: usage5,
|
|
13199
14133
|
raw: done,
|
|
13200
14134
|
providerRef
|
|
13201
14135
|
};
|
|
@@ -13203,7 +14137,7 @@ async function generateOmniVideo(req, ctx, createGenAIClient) {
|
|
|
13203
14137
|
if (video.uri)
|
|
13204
14138
|
return {
|
|
13205
14139
|
video: await downloadVideo(ctx, video.uri, apiKey, signal),
|
|
13206
|
-
usage:
|
|
14140
|
+
usage: usage5,
|
|
13207
14141
|
raw: done,
|
|
13208
14142
|
providerRef
|
|
13209
14143
|
};
|
|
@@ -13373,15 +14307,15 @@ async function prepareGoogleMediaPart(ref, mediaType, ctx) {
|
|
|
13373
14307
|
// src/adapters/google-image.ts
|
|
13374
14308
|
var import_google2 = require("@ai-sdk/google");
|
|
13375
14309
|
var import_ai2 = require("ai");
|
|
13376
|
-
var
|
|
14310
|
+
var import_zod25 = require("zod");
|
|
13377
14311
|
var GEMINI_IMAGE_TIMEOUT_MS = 6e5;
|
|
13378
14312
|
var defaultGoogleImageDeps = {
|
|
13379
14313
|
createGoogleClient: (opts) => (0, import_google2.createGoogleGenerativeAI)(opts),
|
|
13380
14314
|
runTextGeneration: (opts) => (0, import_ai2.generateText)(opts)
|
|
13381
14315
|
};
|
|
13382
|
-
var causeChainNodeSchema =
|
|
13383
|
-
message:
|
|
13384
|
-
cause:
|
|
14316
|
+
var causeChainNodeSchema = import_zod25.z.object({
|
|
14317
|
+
message: import_zod25.z.string().optional(),
|
|
14318
|
+
cause: import_zod25.z.unknown().optional()
|
|
13385
14319
|
});
|
|
13386
14320
|
function extractBlockReason(cause) {
|
|
13387
14321
|
let current = cause;
|
|
@@ -13481,7 +14415,7 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
|
|
|
13481
14415
|
retryable: false
|
|
13482
14416
|
});
|
|
13483
14417
|
}
|
|
13484
|
-
const
|
|
14418
|
+
const usage5 = {
|
|
13485
14419
|
model: ctx.model.id,
|
|
13486
14420
|
provider: "google-image",
|
|
13487
14421
|
modality: "IMAGE",
|
|
@@ -13489,19 +14423,19 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
|
|
|
13489
14423
|
quantity: images.length,
|
|
13490
14424
|
imageQuality: "auto"
|
|
13491
14425
|
};
|
|
13492
|
-
if (req.size !== void 0)
|
|
14426
|
+
if (req.size !== void 0) usage5.imageSize = req.size;
|
|
13493
14427
|
if (result.usage?.inputTokens !== void 0)
|
|
13494
|
-
|
|
14428
|
+
usage5.inputTokens = result.usage.inputTokens;
|
|
13495
14429
|
if (result.usage?.outputTokens !== void 0)
|
|
13496
|
-
|
|
13497
|
-
return { images, usage:
|
|
14430
|
+
usage5.outputTokens = result.usage.outputTokens;
|
|
14431
|
+
return { images, usage: usage5, raw: result };
|
|
13498
14432
|
}
|
|
13499
14433
|
};
|
|
13500
14434
|
}
|
|
13501
14435
|
var googleImageAdapter = createGoogleImageAdapter();
|
|
13502
14436
|
|
|
13503
14437
|
// src/adapters/higgsfield.ts
|
|
13504
|
-
var
|
|
14438
|
+
var import_zod26 = require("zod");
|
|
13505
14439
|
|
|
13506
14440
|
// src/adapters/higgsfield-motions.ts
|
|
13507
14441
|
var MOTION_MAP = {
|
|
@@ -13720,14 +14654,14 @@ function klingEndpointFields(providerModelId) {
|
|
|
13720
14654
|
const path = (providerModelId.startsWith("/") ? providerModelId.slice(1) : providerModelId).toLowerCase();
|
|
13721
14655
|
return KLING_ENDPOINT_FIELDS.get(path) ?? UNLISTED_KLING_FIELDS;
|
|
13722
14656
|
}
|
|
13723
|
-
var klingCreateSchema =
|
|
13724
|
-
var klingStatusSchema =
|
|
13725
|
-
status:
|
|
13726
|
-
video:
|
|
14657
|
+
var klingCreateSchema = import_zod26.z.object({ status_url: import_zod26.z.string() });
|
|
14658
|
+
var klingStatusSchema = import_zod26.z.object({
|
|
14659
|
+
status: import_zod26.z.string().optional(),
|
|
14660
|
+
video: import_zod26.z.object({ url: import_zod26.z.string().optional() }).optional(),
|
|
13727
14661
|
error: JsonValueSchema.optional()
|
|
13728
14662
|
});
|
|
13729
|
-
var errorMessageSchema =
|
|
13730
|
-
var textValueSchema =
|
|
14663
|
+
var errorMessageSchema = import_zod26.z.object({ message: import_zod26.z.string().optional() });
|
|
14664
|
+
var textValueSchema = import_zod26.z.string();
|
|
13731
14665
|
function klingErrorDetail(error) {
|
|
13732
14666
|
if (error === void 0) return "unknown_error";
|
|
13733
14667
|
const asText = textValueSchema.safeParse(error);
|
|
@@ -13883,8 +14817,8 @@ async function generateKlingVideo(req, ctx) {
|
|
|
13883
14817
|
}
|
|
13884
14818
|
};
|
|
13885
14819
|
}
|
|
13886
|
-
var dopMotionOptionsSchema =
|
|
13887
|
-
modelkit:
|
|
14820
|
+
var dopMotionOptionsSchema = import_zod26.z.object({
|
|
14821
|
+
modelkit: import_zod26.z.object({ motion: import_zod26.z.string().optional() }).optional()
|
|
13888
14822
|
});
|
|
13889
14823
|
function dopMotionId(ctx) {
|
|
13890
14824
|
const parsed = dopMotionOptionsSchema.safeParse(ctx.model.providerOptions);
|
|
@@ -13900,7 +14834,7 @@ function dopMotionId(ctx) {
|
|
|
13900
14834
|
});
|
|
13901
14835
|
return id;
|
|
13902
14836
|
}
|
|
13903
|
-
var jsonRecordSchema =
|
|
14837
|
+
var jsonRecordSchema = import_zod26.z.record(import_zod26.z.string(), JsonValueSchema);
|
|
13904
14838
|
var DOP_URL_KEYS = ["url", "video_url", "output_url", "result_url", "download_url"];
|
|
13905
14839
|
var DOP_NESTED_KEYS = ["video", "result", "results"];
|
|
13906
14840
|
function dopUrl(body) {
|
|
@@ -13928,8 +14862,8 @@ function dopUrl(body) {
|
|
|
13928
14862
|
}
|
|
13929
14863
|
return void 0;
|
|
13930
14864
|
}
|
|
13931
|
-
var dopCreateSchema =
|
|
13932
|
-
var dopStatusSchema =
|
|
14865
|
+
var dopCreateSchema = import_zod26.z.object({ id: import_zod26.z.string() });
|
|
14866
|
+
var dopStatusSchema = import_zod26.z.object({ status: import_zod26.z.string().optional() });
|
|
13933
14867
|
async function generateDopVideo(req, ctx) {
|
|
13934
14868
|
const firstFrame = req.firstFrame ? refToUrl(req.firstFrame) : void 0;
|
|
13935
14869
|
if (!firstFrame) {
|
|
@@ -14056,7 +14990,7 @@ var higgsfieldAdapter = {
|
|
|
14056
14990
|
};
|
|
14057
14991
|
|
|
14058
14992
|
// src/adapters/luma.ts
|
|
14059
|
-
var
|
|
14993
|
+
var import_zod27 = require("zod");
|
|
14060
14994
|
|
|
14061
14995
|
// src/adapters/mp4-duration.ts
|
|
14062
14996
|
function mp4DurationSeconds(bytes) {
|
|
@@ -14112,7 +15046,7 @@ function findBox(bytes, from, to, type) {
|
|
|
14112
15046
|
}
|
|
14113
15047
|
|
|
14114
15048
|
// src/adapters/luma.ts
|
|
14115
|
-
var
|
|
15049
|
+
var DEFAULT_BASE_URL3 = "https://agents.lumalabs.ai";
|
|
14116
15050
|
var IMAGE_POLL_INTERVAL_MS = 3e3;
|
|
14117
15051
|
var IMAGE_TIMEOUT_MS = 5 * 6e4;
|
|
14118
15052
|
var VIDEO_POLL_INTERVAL_MS = 5e3;
|
|
@@ -14141,7 +15075,7 @@ function lumaModel(ctx) {
|
|
|
14141
15075
|
return ctx.model.providerModelId.toLowerCase();
|
|
14142
15076
|
}
|
|
14143
15077
|
function lumaBase(ctx) {
|
|
14144
|
-
return ctx.endpoints?.luma ??
|
|
15078
|
+
return ctx.endpoints?.luma ?? DEFAULT_BASE_URL3;
|
|
14145
15079
|
}
|
|
14146
15080
|
function lumaKey(ctx) {
|
|
14147
15081
|
const key = ctx.keys.luma;
|
|
@@ -14273,17 +15207,17 @@ function lumaReframeResolution(req, ctx) {
|
|
|
14273
15207
|
});
|
|
14274
15208
|
return "720p";
|
|
14275
15209
|
}
|
|
14276
|
-
var lumaGenerationSchema =
|
|
14277
|
-
id:
|
|
14278
|
-
state:
|
|
14279
|
-
output:
|
|
14280
|
-
|
|
14281
|
-
type:
|
|
14282
|
-
url:
|
|
15210
|
+
var lumaGenerationSchema = import_zod27.z.looseObject({
|
|
15211
|
+
id: import_zod27.z.string(),
|
|
15212
|
+
state: import_zod27.z.string().optional(),
|
|
15213
|
+
output: import_zod27.z.array(
|
|
15214
|
+
import_zod27.z.looseObject({
|
|
15215
|
+
type: import_zod27.z.string().optional(),
|
|
15216
|
+
url: import_zod27.z.string().optional()
|
|
14283
15217
|
})
|
|
14284
15218
|
).optional(),
|
|
14285
|
-
failure_reason:
|
|
14286
|
-
failure_code:
|
|
15219
|
+
failure_reason: import_zod27.z.string().optional().nullable(),
|
|
15220
|
+
failure_code: import_zod27.z.string().optional().nullable()
|
|
14287
15221
|
});
|
|
14288
15222
|
function lumaFailure(ctx, code, reason) {
|
|
14289
15223
|
const detail = reason ?? code ?? "unknown_error";
|
|
@@ -14715,7 +15649,7 @@ var lumaAdapter = {
|
|
|
14715
15649
|
|
|
14716
15650
|
// src/adapters/openai-image.ts
|
|
14717
15651
|
var import_openai2 = __toESM(require("openai"), 1);
|
|
14718
|
-
var
|
|
15652
|
+
var import_zod28 = require("zod");
|
|
14719
15653
|
var MAX_EDIT_REFERENCES = 16;
|
|
14720
15654
|
function aspectRatioToSize(ratio, tier) {
|
|
14721
15655
|
const TIER_LONG_EDGE = {
|
|
@@ -14798,9 +15732,9 @@ function toProviderError2(cause, ctx) {
|
|
|
14798
15732
|
ctx.model.id
|
|
14799
15733
|
);
|
|
14800
15734
|
}
|
|
14801
|
-
var openaiUsageSchema =
|
|
14802
|
-
input_tokens:
|
|
14803
|
-
output_tokens:
|
|
15735
|
+
var openaiUsageSchema = import_zod28.z.object({
|
|
15736
|
+
input_tokens: import_zod28.z.number().optional(),
|
|
15737
|
+
output_tokens: import_zod28.z.number().optional()
|
|
14804
15738
|
});
|
|
14805
15739
|
var openaiImageAdapter = {
|
|
14806
15740
|
id: "openai-image",
|
|
@@ -14925,7 +15859,7 @@ var openaiImageAdapter = {
|
|
|
14925
15859
|
const usageParsed = openaiUsageSchema.safeParse(response.usage);
|
|
14926
15860
|
const inputTokens = usageParsed.success ? usageParsed.data.input_tokens : void 0;
|
|
14927
15861
|
const outputTokens = usageParsed.success ? usageParsed.data.output_tokens : void 0;
|
|
14928
|
-
const
|
|
15862
|
+
const usage5 = {
|
|
14929
15863
|
model: ctx.model.id,
|
|
14930
15864
|
provider: "openai-image",
|
|
14931
15865
|
modality: "IMAGE",
|
|
@@ -14933,10 +15867,10 @@ var openaiImageAdapter = {
|
|
|
14933
15867
|
quantity: images.length,
|
|
14934
15868
|
imageQuality: quality
|
|
14935
15869
|
};
|
|
14936
|
-
if (inputTokens !== void 0)
|
|
14937
|
-
if (outputTokens !== void 0)
|
|
14938
|
-
if (req.size !== void 0)
|
|
14939
|
-
return { images, usage:
|
|
15870
|
+
if (inputTokens !== void 0) usage5.inputTokens = inputTokens;
|
|
15871
|
+
if (outputTokens !== void 0) usage5.outputTokens = outputTokens;
|
|
15872
|
+
if (req.size !== void 0) usage5.imageSize = req.size;
|
|
15873
|
+
return { images, usage: usage5, raw: response };
|
|
14940
15874
|
}
|
|
14941
15875
|
};
|
|
14942
15876
|
|
|
@@ -15192,16 +16126,16 @@ async function generateProdiaImage(req, ctx) {
|
|
|
15192
16126
|
new Uint8Array(await res.arrayBuffer()),
|
|
15193
16127
|
res.headers.get("content-type")
|
|
15194
16128
|
);
|
|
15195
|
-
const
|
|
16129
|
+
const usage5 = {
|
|
15196
16130
|
model: ctx.model.id,
|
|
15197
16131
|
provider: "prodia",
|
|
15198
16132
|
modality: "IMAGE",
|
|
15199
16133
|
unit: "images",
|
|
15200
16134
|
quantity: 1
|
|
15201
16135
|
};
|
|
15202
|
-
if (req.size !== void 0)
|
|
15203
|
-
if (req.quality !== void 0)
|
|
15204
|
-
return { images: [{ bytes, mime }], usage:
|
|
16136
|
+
if (req.size !== void 0) usage5.imageSize = req.size;
|
|
16137
|
+
if (req.quality !== void 0) usage5.imageQuality = req.quality;
|
|
16138
|
+
return { images: [{ bytes, mime }], usage: usage5, raw: void 0 };
|
|
15205
16139
|
}
|
|
15206
16140
|
var prodiaAdapter = {
|
|
15207
16141
|
id: "prodia",
|
|
@@ -15212,13 +16146,13 @@ var prodiaAdapter = {
|
|
|
15212
16146
|
var import_replicate = __toESM(require("replicate"), 1);
|
|
15213
16147
|
|
|
15214
16148
|
// src/adapters/replicate-http.ts
|
|
15215
|
-
var
|
|
15216
|
-
var predictionSchema =
|
|
15217
|
-
id:
|
|
15218
|
-
status:
|
|
16149
|
+
var import_zod29 = require("zod");
|
|
16150
|
+
var predictionSchema = import_zod29.z.object({
|
|
16151
|
+
id: import_zod29.z.string(),
|
|
16152
|
+
status: import_zod29.z.string(),
|
|
15219
16153
|
output: JsonValueSchema.optional(),
|
|
15220
16154
|
error: JsonValueSchema.optional(),
|
|
15221
|
-
metrics:
|
|
16155
|
+
metrics: import_zod29.z.object({ predict_time: import_zod29.z.number().optional() }).optional()
|
|
15222
16156
|
});
|
|
15223
16157
|
function createReplicateHttpClient(opts) {
|
|
15224
16158
|
async function request(path, body, signal) {
|
|
@@ -15269,7 +16203,7 @@ function createReplicateHttpClient(opts) {
|
|
|
15269
16203
|
}
|
|
15270
16204
|
|
|
15271
16205
|
// src/adapters/replicate.ts
|
|
15272
|
-
var
|
|
16206
|
+
var import_zod30 = require("zod");
|
|
15273
16207
|
var POLL_INTERVAL_MS = 1e3;
|
|
15274
16208
|
var POLL_TIMEOUT_MS = 15 * 6e4;
|
|
15275
16209
|
var defaultReplicateDeps = {
|
|
@@ -15309,8 +16243,8 @@ function route(providerModelId) {
|
|
|
15309
16243
|
if (!providerModelId.includes("/")) return { version: providerModelId };
|
|
15310
16244
|
return { model: providerModelId };
|
|
15311
16245
|
}
|
|
15312
|
-
var replicateResponseStatusSchema =
|
|
15313
|
-
response:
|
|
16246
|
+
var replicateResponseStatusSchema = import_zod30.z.object({
|
|
16247
|
+
response: import_zod30.z.object({ status: import_zod30.z.number() }).partial()
|
|
15314
16248
|
});
|
|
15315
16249
|
function replicateError(cause, ctx) {
|
|
15316
16250
|
if (isModelKitError(cause)) return cause;
|
|
@@ -15333,7 +16267,7 @@ function isUrlFn(value) {
|
|
|
15333
16267
|
function extractOutputUrl(output) {
|
|
15334
16268
|
const root = Array.isArray(output) ? output[0] : output;
|
|
15335
16269
|
if (root === void 0) throw noOutput();
|
|
15336
|
-
const asString =
|
|
16270
|
+
const asString = import_zod30.z.string().safeParse(root);
|
|
15337
16271
|
if (asString.success && asString.data) return asString.data;
|
|
15338
16272
|
if (root instanceof URL) return root.href;
|
|
15339
16273
|
if (isObjectOutput(root)) {
|
|
@@ -15342,15 +16276,15 @@ function extractOutputUrl(output) {
|
|
|
15342
16276
|
if (urlValue !== void 0 && isUrlFn(urlValue)) {
|
|
15343
16277
|
const called = urlValue();
|
|
15344
16278
|
if (called instanceof URL) return called.href;
|
|
15345
|
-
const calledString =
|
|
16279
|
+
const calledString = import_zod30.z.string().safeParse(called);
|
|
15346
16280
|
if (calledString.success && calledString.data) return calledString.data;
|
|
15347
16281
|
} else {
|
|
15348
|
-
const direct =
|
|
16282
|
+
const direct = import_zod30.z.string().safeParse(urlValue);
|
|
15349
16283
|
if (direct.success && direct.data) return direct.data;
|
|
15350
16284
|
}
|
|
15351
16285
|
}
|
|
15352
16286
|
if ("default" in root) {
|
|
15353
|
-
const fallback =
|
|
16287
|
+
const fallback = import_zod30.z.string().safeParse(root.default);
|
|
15354
16288
|
if (fallback.success && fallback.data) return fallback.data;
|
|
15355
16289
|
}
|
|
15356
16290
|
}
|
|
@@ -15411,7 +16345,7 @@ async function runPrediction(ctx, input, deps) {
|
|
|
15411
16345
|
}
|
|
15412
16346
|
return void 0;
|
|
15413
16347
|
}, pollOpts);
|
|
15414
|
-
const predictTime =
|
|
16348
|
+
const predictTime = import_zod30.z.number().safeParse(done.metrics?.predict_time);
|
|
15415
16349
|
if (done.output === void 0) throw noOutput();
|
|
15416
16350
|
return {
|
|
15417
16351
|
url: extractOutputUrl(done.output),
|
|
@@ -15657,9 +16591,9 @@ async function generateReplicateImage(req, ctx, deps) {
|
|
|
15657
16591
|
}
|
|
15658
16592
|
const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
|
|
15659
16593
|
const file = await download(ctx, url);
|
|
15660
|
-
const
|
|
15661
|
-
|
|
15662
|
-
return { images: [{ bytes: file.bytes, mime: file.mime }], usage:
|
|
16594
|
+
const usage5 = imageUsage3(ctx, req);
|
|
16595
|
+
usage5.quantity = predictTime;
|
|
16596
|
+
return { images: [{ bytes: file.bytes, mime: file.mime }], usage: usage5, raw, outputUrl: url };
|
|
15663
16597
|
}
|
|
15664
16598
|
function klingInput(req) {
|
|
15665
16599
|
const images = (req.firstFrame ? [req.firstFrame] : []).map(refToUrl);
|
|
@@ -15764,7 +16698,7 @@ async function generateReplicateVideo(req, ctx, deps) {
|
|
|
15764
16698
|
throw replicateError(cause, ctx);
|
|
15765
16699
|
}
|
|
15766
16700
|
if (current.status === "succeeded") {
|
|
15767
|
-
const predictTime =
|
|
16701
|
+
const predictTime = import_zod30.z.number().safeParse(current.metrics?.predict_time);
|
|
15768
16702
|
if (current.output === void 0) throw noOutput();
|
|
15769
16703
|
return {
|
|
15770
16704
|
url: extractOutputUrl(current.output),
|
|
@@ -15783,9 +16717,9 @@ async function generateReplicateVideo(req, ctx, deps) {
|
|
|
15783
16717
|
return void 0;
|
|
15784
16718
|
};
|
|
15785
16719
|
const toResult = (done) => {
|
|
15786
|
-
const
|
|
15787
|
-
|
|
15788
|
-
return { video: { url: done.url }, usage:
|
|
16720
|
+
const usage5 = videoUsage5(ctx, req);
|
|
16721
|
+
usage5.quantity = done.predictTime;
|
|
16722
|
+
return { video: { url: done.url }, usage: usage5, raw: done.raw };
|
|
15789
16723
|
};
|
|
15790
16724
|
return {
|
|
15791
16725
|
jobId,
|
|
@@ -15892,21 +16826,21 @@ async function generateReplicateAudio(req, ctx, deps) {
|
|
|
15892
16826
|
input = specResult.input;
|
|
15893
16827
|
}
|
|
15894
16828
|
const { url, predictTime, raw } = await runPrediction(ctx, input, deps);
|
|
15895
|
-
const
|
|
16829
|
+
const usage5 = audioUsage(ctx, req);
|
|
15896
16830
|
if (ctx.model.usage.unit === "seconds") {
|
|
15897
16831
|
const seconds3 = elevenLabsMusicDuration(req.durationSeconds);
|
|
15898
|
-
|
|
15899
|
-
|
|
16832
|
+
usage5.quantity = seconds3;
|
|
16833
|
+
usage5.durationSeconds = seconds3;
|
|
15900
16834
|
} else {
|
|
15901
|
-
|
|
16835
|
+
usage5.quantity = predictTime;
|
|
15902
16836
|
}
|
|
15903
|
-
return { audio: { url }, usage:
|
|
16837
|
+
return { audio: { url }, usage: usage5, raw: predictionRaw(raw) };
|
|
15904
16838
|
}
|
|
15905
16839
|
|
|
15906
16840
|
// src/adapters/xai-video.ts
|
|
15907
16841
|
var import_ai3 = require("ai");
|
|
15908
16842
|
var import_xai2 = require("@ai-sdk/xai");
|
|
15909
|
-
var
|
|
16843
|
+
var import_zod31 = require("zod");
|
|
15910
16844
|
var POLL_INTERVAL_MS2 = 1e4;
|
|
15911
16845
|
var POLL_TIMEOUT_MS2 = 15 * 6e4;
|
|
15912
16846
|
var defaultXaiDeps = {
|
|
@@ -15919,8 +16853,8 @@ function createXaiVideoAdapter(deps = defaultXaiDeps) {
|
|
|
15919
16853
|
};
|
|
15920
16854
|
}
|
|
15921
16855
|
var xaiVideoAdapter = createXaiVideoAdapter();
|
|
15922
|
-
var xaiResponseStatusSchema =
|
|
15923
|
-
response:
|
|
16856
|
+
var xaiResponseStatusSchema = import_zod31.z.object({
|
|
16857
|
+
response: import_zod31.z.object({ status: import_zod31.z.number() }).partial()
|
|
15924
16858
|
});
|
|
15925
16859
|
function xaiError(cause, ctx) {
|
|
15926
16860
|
const info = describeThrown(cause);
|
|
@@ -15928,12 +16862,12 @@ function xaiError(cause, ctx) {
|
|
|
15928
16862
|
const status = info.status ?? (nested.success ? nested.data.response?.status : void 0);
|
|
15929
16863
|
return classifyThrown("xai-video", cause, ctx.model.id, { status, body: info.body });
|
|
15930
16864
|
}
|
|
15931
|
-
var xaiMetaSchema =
|
|
16865
|
+
var xaiMetaSchema = import_zod31.z.object({
|
|
15932
16866
|
videoUrl: JsonValueSchema.optional(),
|
|
15933
16867
|
costInUsdTicks: JsonValueSchema.optional(),
|
|
15934
16868
|
duration: JsonValueSchema.optional()
|
|
15935
16869
|
});
|
|
15936
|
-
var xaiProviderMetadataSchema =
|
|
16870
|
+
var xaiProviderMetadataSchema = import_zod31.z.object({ xai: xaiMetaSchema });
|
|
15937
16871
|
function metaOf(result) {
|
|
15938
16872
|
const parsed = xaiProviderMetadataSchema.partial().safeParse(result.providerMetadata);
|
|
15939
16873
|
if (!parsed.success) return {};
|
|
@@ -16045,12 +16979,12 @@ async function mapResult(ctx, req, result) {
|
|
|
16045
16979
|
if (first) {
|
|
16046
16980
|
return {
|
|
16047
16981
|
video: { bytes: Uint8Array.from(first.uint8Array), mime: first.mediaType },
|
|
16048
|
-
usage:
|
|
16982
|
+
usage: usage4(ctx, req, metaOf(result)),
|
|
16049
16983
|
raw: result.providerMetadata
|
|
16050
16984
|
};
|
|
16051
16985
|
}
|
|
16052
16986
|
const meta = metaOf(result);
|
|
16053
|
-
const videoUrl =
|
|
16987
|
+
const videoUrl = import_zod31.z.string().safeParse(meta.videoUrl);
|
|
16054
16988
|
if (videoUrl.success && videoUrl.data) {
|
|
16055
16989
|
const res = await ctx.fetch(videoUrl.data);
|
|
16056
16990
|
if (!res.ok) {
|
|
@@ -16060,7 +16994,7 @@ async function mapResult(ctx, req, result) {
|
|
|
16060
16994
|
const mime = res.headers.get("content-type") ?? "video/mp4";
|
|
16061
16995
|
return {
|
|
16062
16996
|
video: { bytes: new Uint8Array(await res.arrayBuffer()), mime },
|
|
16063
|
-
usage:
|
|
16997
|
+
usage: usage4(ctx, req, meta),
|
|
16064
16998
|
raw: result.providerMetadata
|
|
16065
16999
|
};
|
|
16066
17000
|
}
|
|
@@ -16072,8 +17006,8 @@ async function mapResult(ctx, req, result) {
|
|
|
16072
17006
|
retryable: false
|
|
16073
17007
|
});
|
|
16074
17008
|
}
|
|
16075
|
-
function
|
|
16076
|
-
const costTicks =
|
|
17009
|
+
function usage4(ctx, req, meta) {
|
|
17010
|
+
const costTicks = import_zod31.z.number().safeParse(meta.costInUsdTicks);
|
|
16077
17011
|
const cost = costTicks.success ? costTicks.data / 1e10 : void 0;
|
|
16078
17012
|
const event = {
|
|
16079
17013
|
model: ctx.model.id,
|
|
@@ -16112,7 +17046,9 @@ var DEFAULT_ADAPTERS = {
|
|
|
16112
17046
|
prodia: prodiaAdapter,
|
|
16113
17047
|
higgsfield: higgsfieldAdapter,
|
|
16114
17048
|
"xai-video": xaiVideoAdapter,
|
|
16115
|
-
luma: lumaAdapter
|
|
17049
|
+
luma: lumaAdapter,
|
|
17050
|
+
fish: fishAdapter,
|
|
17051
|
+
elevenlabs: elevenLabsAdapter
|
|
16116
17052
|
};
|
|
16117
17053
|
|
|
16118
17054
|
// src/catalog/data-only.ts
|
|
@@ -16136,6 +17072,8 @@ function adapterServesType(adapter, type) {
|
|
|
16136
17072
|
if (type === "dubbing") return adapter.dub !== void 0;
|
|
16137
17073
|
if (type === "lipsync") return adapter.lipsync !== void 0;
|
|
16138
17074
|
if (type === "transcription") return adapter.transcribe !== void 0;
|
|
17075
|
+
if (type === "voice-clone") return adapter.createVoice !== void 0;
|
|
17076
|
+
if (type === "voice-design") return adapter.designVoice !== void 0;
|
|
16139
17077
|
if (type === "video-tool") return adapter.submitVideoTool !== void 0;
|
|
16140
17078
|
if (type === "model3d") return adapter.submitModel3d !== void 0;
|
|
16141
17079
|
return adapter.languageModel !== void 0;
|
|
@@ -16149,12 +17087,15 @@ var FAL_NODE_TYPES = /* @__PURE__ */ new Set([
|
|
|
16149
17087
|
"transcription",
|
|
16150
17088
|
"mask"
|
|
16151
17089
|
]);
|
|
17090
|
+
function directSpeech(row2) {
|
|
17091
|
+
return (row2.adapter === "fish" || row2.adapter === "elevenlabs") && row2.type === "speech";
|
|
17092
|
+
}
|
|
16152
17093
|
function dataOnlyCapable(row2) {
|
|
16153
17094
|
const adapter = DEFAULT_ADAPTERS[row2.adapter];
|
|
16154
17095
|
if (!adapterServesType(adapter, row2.type)) {
|
|
16155
17096
|
return { ok: false, reason: `${row2.adapter} cannot serve ${row2.type} rows` };
|
|
16156
17097
|
}
|
|
16157
|
-
if (FAL_NODE_TYPES.has(row2.type) && row2.adapter !== "fal") {
|
|
17098
|
+
if (FAL_NODE_TYPES.has(row2.type) && row2.adapter !== "fal" && !directSpeech(row2)) {
|
|
16158
17099
|
return { ok: false, reason: `only fal serves ${row2.type} rows` };
|
|
16159
17100
|
}
|
|
16160
17101
|
switch (row2.adapter) {
|
|
@@ -16232,6 +17173,14 @@ function dataOnlyCapable(row2) {
|
|
|
16232
17173
|
const reason = lumaRowRefusal(row2);
|
|
16233
17174
|
return reason === void 0 ? { ok: true } : { ok: false, reason };
|
|
16234
17175
|
}
|
|
17176
|
+
case "fish": {
|
|
17177
|
+
const reason = fishRowRefusal(row2);
|
|
17178
|
+
return reason === void 0 ? { ok: true } : { ok: false, reason };
|
|
17179
|
+
}
|
|
17180
|
+
case "elevenlabs": {
|
|
17181
|
+
const reason = elevenLabsRowRefusal(row2);
|
|
17182
|
+
return reason === void 0 ? { ok: true } : { ok: false, reason };
|
|
17183
|
+
}
|
|
16235
17184
|
default: {
|
|
16236
17185
|
return assertNever(row2.adapter);
|
|
16237
17186
|
}
|
|
@@ -16251,22 +17200,22 @@ var liveState = store[KEY] ??= {
|
|
|
16251
17200
|
var liveCatalog = liveState.catalog;
|
|
16252
17201
|
|
|
16253
17202
|
// src/catalog/load.ts
|
|
16254
|
-
var
|
|
17203
|
+
var import_zod32 = require("zod");
|
|
16255
17204
|
function rowCount() {
|
|
16256
17205
|
return liveCatalog.list({ lifecycle: ["active", "deprecated", "retired"] }).length;
|
|
16257
17206
|
}
|
|
16258
17207
|
function authHeaders(auth) {
|
|
16259
17208
|
return "bearer" in auth ? { Authorization: `Bearer ${auth.bearer}` } : { "x-api-key": auth.apiKey };
|
|
16260
17209
|
}
|
|
16261
|
-
var EnvelopeSchema =
|
|
16262
|
-
rows:
|
|
16263
|
-
revision:
|
|
17210
|
+
var EnvelopeSchema = import_zod32.z.object({
|
|
17211
|
+
rows: import_zod32.z.array(JsonValueSchema),
|
|
17212
|
+
revision: import_zod32.z.string().optional()
|
|
16264
17213
|
});
|
|
16265
17214
|
function dropReason(path, message) {
|
|
16266
17215
|
return path.length === 0 ? message : `${path.map((part) => String(part)).join(".")} ${message}`;
|
|
16267
17216
|
}
|
|
16268
17217
|
function rowId(raw) {
|
|
16269
|
-
const parsed =
|
|
17218
|
+
const parsed = import_zod32.z.object({ id: import_zod32.z.string().min(1) }).loose().safeParse(raw);
|
|
16270
17219
|
if (!parsed.success) return "?";
|
|
16271
17220
|
return parsed.data.id;
|
|
16272
17221
|
}
|
|
@@ -17182,8 +18131,17 @@ function resolveSpeechOptions(model, request, onUnsupported = "error") {
|
|
|
17182
18131
|
const warnings = [];
|
|
17183
18132
|
checkScript(model, request.text);
|
|
17184
18133
|
const resolved = { model: model.id, text: request.text };
|
|
17185
|
-
const
|
|
17186
|
-
if (
|
|
18134
|
+
const customVoice = request.customVoice?.trim();
|
|
18135
|
+
if (customVoice) {
|
|
18136
|
+
if (model.capabilities?.customVoices !== true) {
|
|
18137
|
+
throw unsupported3(model, "does not take a custom voice");
|
|
18138
|
+
}
|
|
18139
|
+
if (request.voice?.trim()) throw unsupported3(model, "takes voice or customVoice, not both");
|
|
18140
|
+
resolved.customVoice = customVoice;
|
|
18141
|
+
} else {
|
|
18142
|
+
const voice = resolveVoice(model, request.voice, onUnsupported, warnings);
|
|
18143
|
+
if (voice !== void 0) resolved.voice = voice;
|
|
18144
|
+
}
|
|
17187
18145
|
const language = resolveListed(
|
|
17188
18146
|
model,
|
|
17189
18147
|
{
|
|
@@ -17305,6 +18263,106 @@ function resolveTranscriptionOptions(model, request, onUnsupported = "error") {
|
|
|
17305
18263
|
return { request: resolved, warnings };
|
|
17306
18264
|
}
|
|
17307
18265
|
|
|
18266
|
+
// src/resolve-voice.ts
|
|
18267
|
+
function refuse(model, code, message) {
|
|
18268
|
+
return new ModelKitError({ code, message: `${model.label} ${message}`, model: model.id });
|
|
18269
|
+
}
|
|
18270
|
+
function checkSample(model, sample, index) {
|
|
18271
|
+
const limits = model.constraints.references?.audioSeconds;
|
|
18272
|
+
const length = sample.audio.durationSeconds;
|
|
18273
|
+
if (limits === void 0 || length === void 0) return;
|
|
18274
|
+
if (limits.min !== void 0 && length < limits.min || limits.max !== void 0 && length > limits.max) {
|
|
18275
|
+
const range2 = `${limits.min ?? 0}-${limits.max ?? "any"} s`;
|
|
18276
|
+
throw refuse(
|
|
18277
|
+
model,
|
|
18278
|
+
"unsupported_option",
|
|
18279
|
+
`takes samples of ${range2}; sample ${index + 1} is ${length} s`
|
|
18280
|
+
);
|
|
18281
|
+
}
|
|
18282
|
+
}
|
|
18283
|
+
function resolveVoiceCloneOptions(model, request) {
|
|
18284
|
+
const title = request.title.trim();
|
|
18285
|
+
if (!title) throw refuse(model, "missing_input", "needs a title");
|
|
18286
|
+
if (request.samples.length === 0) throw refuse(model, "missing_input", "needs a voice sample");
|
|
18287
|
+
const max = model.constraints.references?.audios;
|
|
18288
|
+
if (max !== void 0 && request.samples.length > max) {
|
|
18289
|
+
throw refuse(
|
|
18290
|
+
model,
|
|
18291
|
+
"unsupported_option",
|
|
18292
|
+
`takes up to ${max} samples; got ${request.samples.length}`
|
|
18293
|
+
);
|
|
18294
|
+
}
|
|
18295
|
+
request.samples.forEach((sample, index) => checkSample(model, sample, index));
|
|
18296
|
+
const total = model.constraints.references?.audioSeconds?.total;
|
|
18297
|
+
const seconds3 = request.samples.reduce((sum, s) => sum + (s.audio.durationSeconds ?? 0), 0);
|
|
18298
|
+
if (total !== void 0 && seconds3 > total) {
|
|
18299
|
+
throw refuse(
|
|
18300
|
+
model,
|
|
18301
|
+
"unsupported_option",
|
|
18302
|
+
`takes up to ${total} s of samples; got ${seconds3} s`
|
|
18303
|
+
);
|
|
18304
|
+
}
|
|
18305
|
+
for (const field of ["transcript", "designSignature"]) {
|
|
18306
|
+
const set = request.samples.filter((s) => s[field]?.trim()).length;
|
|
18307
|
+
if (set !== 0 && set !== request.samples.length) {
|
|
18308
|
+
throw refuse(model, "missing_input", `needs ${field} on every sample or on none`);
|
|
18309
|
+
}
|
|
18310
|
+
}
|
|
18311
|
+
return { request: { ...request, model: model.id, title }, warnings: [] };
|
|
18312
|
+
}
|
|
18313
|
+
function resolveVoiceDesignOptions(model, request, onUnsupported = "error") {
|
|
18314
|
+
const warnings = [];
|
|
18315
|
+
const prompt = request.prompt.trim();
|
|
18316
|
+
if (!prompt) throw refuse(model, "missing_input", "needs a voice description");
|
|
18317
|
+
const maxChars = promptConventions(model).maxChars;
|
|
18318
|
+
if (maxChars !== void 0 && prompt.length > maxChars) {
|
|
18319
|
+
throw refuse(
|
|
18320
|
+
model,
|
|
18321
|
+
"unsupported_option",
|
|
18322
|
+
`takes up to ${maxChars} characters; got ${prompt.length}`
|
|
18323
|
+
);
|
|
18324
|
+
}
|
|
18325
|
+
const limits = model.constraints.voiceDesign;
|
|
18326
|
+
const resolved = { model: model.id, prompt };
|
|
18327
|
+
const preview2 = request.previewText?.trim();
|
|
18328
|
+
if (preview2) {
|
|
18329
|
+
if (limits !== void 0 && preview2.length > limits.previewMaxChars) {
|
|
18330
|
+
throw refuse(
|
|
18331
|
+
model,
|
|
18332
|
+
"unsupported_option",
|
|
18333
|
+
`takes a preview line of up to ${limits.previewMaxChars} characters; got ${preview2.length}`
|
|
18334
|
+
);
|
|
18335
|
+
}
|
|
18336
|
+
resolved.previewText = preview2;
|
|
18337
|
+
}
|
|
18338
|
+
const language = request.language?.trim();
|
|
18339
|
+
if (language) resolved.language = language;
|
|
18340
|
+
if (request.seed !== void 0) resolved.seed = request.seed;
|
|
18341
|
+
const count2 = request.count ?? model.defaults.count;
|
|
18342
|
+
if (count2 !== void 0) {
|
|
18343
|
+
const cap = limits?.maxCandidates ?? count2;
|
|
18344
|
+
if (!Number.isInteger(count2) || count2 < 1 || count2 > cap) {
|
|
18345
|
+
if (onUnsupported === "error" || !Number.isInteger(count2)) {
|
|
18346
|
+
throw refuse(
|
|
18347
|
+
model,
|
|
18348
|
+
"unsupported_option",
|
|
18349
|
+
`returns 1-${cap} candidates; got ${count2}`
|
|
18350
|
+
);
|
|
18351
|
+
}
|
|
18352
|
+
const to = Math.min(Math.max(count2, 1), cap);
|
|
18353
|
+
warnings.push({
|
|
18354
|
+
code: "option_ignored",
|
|
18355
|
+
field: "count",
|
|
18356
|
+
from: String(count2),
|
|
18357
|
+
to: String(to),
|
|
18358
|
+
message: `count ${count2} replaced by ${to} for ${model.id}`
|
|
18359
|
+
});
|
|
18360
|
+
resolved.count = to;
|
|
18361
|
+
} else resolved.count = count2;
|
|
18362
|
+
}
|
|
18363
|
+
return { request: resolved, warnings };
|
|
18364
|
+
}
|
|
18365
|
+
|
|
17308
18366
|
// src/keys.ts
|
|
17309
18367
|
var ADAPTER_KEYS = {
|
|
17310
18368
|
"ai-sdk-text": [],
|
|
@@ -17317,7 +18375,9 @@ var ADAPTER_KEYS = {
|
|
|
17317
18375
|
prodia: ["prodia"],
|
|
17318
18376
|
higgsfield: ["higgsfield"],
|
|
17319
18377
|
"xai-video": ["xai"],
|
|
17320
|
-
luma: ["luma"]
|
|
18378
|
+
luma: ["luma"],
|
|
18379
|
+
fish: ["fish"],
|
|
18380
|
+
elevenlabs: ["elevenlabs"]
|
|
17321
18381
|
};
|
|
17322
18382
|
function hasAll(keys, names) {
|
|
17323
18383
|
if (!keys) return false;
|
|
@@ -17376,6 +18436,8 @@ function keysFromEnv(env, prefix = "") {
|
|
|
17376
18436
|
set("higgsfield", pick2("HIGGSFIELD_API_KEY"));
|
|
17377
18437
|
set("higgsfieldSecret", pick2("HIGGSFIELD_API_SECRET"));
|
|
17378
18438
|
set("luma", pick2("LUMA_API_KEY", "LUMA_AGENTS_API_KEY"));
|
|
18439
|
+
set("fish", pick2("FISH_AUDIO_API_KEY"));
|
|
18440
|
+
set("elevenlabs", pick2("ELEVENLABS_API_KEY"));
|
|
17379
18441
|
set("cloudflare", pick2("CLOUDFLARE_AI_GATEWAY_TOKEN", "CF_AIG_TOKEN"));
|
|
17380
18442
|
const bearer = pick2("AWS_BEARER_TOKEN_BEDROCK");
|
|
17381
18443
|
const accessKeyId = pick2("AWS_ACCESS_KEY_ID");
|
|
@@ -17398,7 +18460,7 @@ function keysFromEnv(env, prefix = "") {
|
|
|
17398
18460
|
|
|
17399
18461
|
// src/text.ts
|
|
17400
18462
|
var import_ai4 = require("ai");
|
|
17401
|
-
var
|
|
18463
|
+
var import_zod33 = require("zod");
|
|
17402
18464
|
function mergeTextProviderOptions(catalog, caller) {
|
|
17403
18465
|
const merged = {};
|
|
17404
18466
|
const catalogOptions = catalog.providerOptions ?? {};
|
|
@@ -17437,17 +18499,17 @@ function passthroughTextModel(model) {
|
|
|
17437
18499
|
pricingKind: "token"
|
|
17438
18500
|
};
|
|
17439
18501
|
}
|
|
17440
|
-
var perplexityCostSchema =
|
|
17441
|
-
perplexity:
|
|
18502
|
+
var perplexityCostSchema = import_zod33.z.object({
|
|
18503
|
+
perplexity: import_zod33.z.object({ cost: import_zod33.z.object({ totalCost: import_zod33.z.number().finite().nonnegative() }) })
|
|
17442
18504
|
});
|
|
17443
18505
|
function reportedCostUsd(metadata) {
|
|
17444
18506
|
const parsed = perplexityCostSchema.safeParse(metadata);
|
|
17445
18507
|
return parsed.success ? parsed.data.perplexity.cost.totalCost : void 0;
|
|
17446
18508
|
}
|
|
17447
|
-
function textUsageEvent(model, provider,
|
|
17448
|
-
const inputTokens =
|
|
17449
|
-
const outputTokens =
|
|
17450
|
-
const total =
|
|
18509
|
+
function textUsageEvent(model, provider, usage5, providerMetadata) {
|
|
18510
|
+
const inputTokens = usage5.inputTokens ?? 0;
|
|
18511
|
+
const outputTokens = usage5.outputTokens ?? 0;
|
|
18512
|
+
const total = usage5.totalTokens ?? inputTokens + outputTokens;
|
|
17451
18513
|
const event = {
|
|
17452
18514
|
model: model.id,
|
|
17453
18515
|
provider,
|
|
@@ -17482,7 +18544,7 @@ function createTextSteps(initial, resolve, callerProviderOptions) {
|
|
|
17482
18544
|
return { ...prepared, providerOptions };
|
|
17483
18545
|
};
|
|
17484
18546
|
}
|
|
17485
|
-
function
|
|
18547
|
+
function usage5(results) {
|
|
17486
18548
|
const grouped = /* @__PURE__ */ new Map();
|
|
17487
18549
|
for (const [index, step] of results.entries()) {
|
|
17488
18550
|
const target = steps.get(index) ?? initial;
|
|
@@ -17506,12 +18568,12 @@ function createTextSteps(initial, resolve, callerProviderOptions) {
|
|
|
17506
18568
|
}
|
|
17507
18569
|
return [...grouped.values()];
|
|
17508
18570
|
}
|
|
17509
|
-
return { wrap, usage:
|
|
18571
|
+
return { wrap, usage: usage5 };
|
|
17510
18572
|
}
|
|
17511
18573
|
|
|
17512
18574
|
// src/client.ts
|
|
17513
18575
|
var import_ai5 = require("ai");
|
|
17514
|
-
var
|
|
18576
|
+
var import_zod34 = require("zod");
|
|
17515
18577
|
|
|
17516
18578
|
// src/generated-image.ts
|
|
17517
18579
|
function toGeneratedImage(image) {
|
|
@@ -17633,9 +18695,9 @@ function providerJobMethods(kind, deps) {
|
|
|
17633
18695
|
if (!methods.result) throw missing3(adapter, ctx.model);
|
|
17634
18696
|
const result = await methods.result(sub, ctx, webhook);
|
|
17635
18697
|
const base = { ...result.usage, model: ctx.model.id, unit: ctx.model.usage.unit };
|
|
17636
|
-
const
|
|
17637
|
-
await deps.emit(
|
|
17638
|
-
return { ...result, usage:
|
|
18698
|
+
const usage5 = sub.submittedAt === void 0 ? base : deps.timed(base, sub.submittedAt);
|
|
18699
|
+
await deps.emit(usage5);
|
|
18700
|
+
return { ...result, usage: usage5 };
|
|
17639
18701
|
},
|
|
17640
18702
|
async cancel(sub, call = {}) {
|
|
17641
18703
|
const { methods, adapter, ctx } = target(sub.model, call);
|
|
@@ -17660,6 +18722,9 @@ var MEDIA_METHODS = {
|
|
|
17660
18722
|
lipsync: ["lipsync"],
|
|
17661
18723
|
dubbing: ["dub"],
|
|
17662
18724
|
transcription: ["transcribe"],
|
|
18725
|
+
// deleteVoice runs on the voice-clone row too; it checks with assertMethod("createVoice").
|
|
18726
|
+
"voice-clone": ["createVoice"],
|
|
18727
|
+
"voice-design": ["designVoice"],
|
|
17663
18728
|
"video-tool": ["submitVideoTool"],
|
|
17664
18729
|
// 3D jobs run through submitModel3d, which checks the row type itself; their preflight
|
|
17665
18730
|
// is model3dInputRefusal, not resolveOptions.
|
|
@@ -17674,6 +18739,8 @@ var METHOD_NOUN = {
|
|
|
17674
18739
|
lipsync: "a lipsync model",
|
|
17675
18740
|
dub: "a dubbing model",
|
|
17676
18741
|
transcribe: "a transcription model",
|
|
18742
|
+
createVoice: "a voice cloning model",
|
|
18743
|
+
designVoice: "a voice design model",
|
|
17677
18744
|
submitVideoTool: "a video tool"
|
|
17678
18745
|
};
|
|
17679
18746
|
function assertMethod(model, method) {
|
|
@@ -17716,6 +18783,14 @@ function resolveTranscriptionCall(model, request, onUnsupported = "error") {
|
|
|
17716
18783
|
assertMethod(model, "transcribe");
|
|
17717
18784
|
return resolveTranscriptionOptions(model, request, onUnsupported);
|
|
17718
18785
|
}
|
|
18786
|
+
function resolveVoiceCloneCall(model, request) {
|
|
18787
|
+
assertMethod(model, "createVoice");
|
|
18788
|
+
return resolveVoiceCloneOptions(model, request);
|
|
18789
|
+
}
|
|
18790
|
+
function resolveVoiceDesignCall(model, request, onUnsupported = "error") {
|
|
18791
|
+
assertMethod(model, "designVoice");
|
|
18792
|
+
return resolveVoiceDesignOptions(model, request, onUnsupported);
|
|
18793
|
+
}
|
|
17719
18794
|
|
|
17720
18795
|
// src/client-audio.ts
|
|
17721
18796
|
function noMethod(adapter, model, what) {
|
|
@@ -17805,6 +18880,49 @@ function audioNodeMethods(deps) {
|
|
|
17805
18880
|
const result = await adapter.transcribe(resolved, ctx);
|
|
17806
18881
|
return { ...result, usage: await deps.settle(model, result.usage, startedAt) };
|
|
17807
18882
|
},
|
|
18883
|
+
async createVoice(req, call = {}) {
|
|
18884
|
+
mediaRetryOptions(call);
|
|
18885
|
+
const { abortSignal, ...request } = req;
|
|
18886
|
+
const model = catalog.require(req.model);
|
|
18887
|
+
const { request: resolved, warnings } = resolveVoiceCloneCall(model, request);
|
|
18888
|
+
const { adapter, ctx } = prepare(model, call, abortSignal, warnings);
|
|
18889
|
+
if (!adapter.createVoice) throw noMethod(adapter, model, "clone a voice");
|
|
18890
|
+
const startedAt = Date.now();
|
|
18891
|
+
const result = await adapter.createVoice(resolved, ctx);
|
|
18892
|
+
return { ...result, usage: await deps.settle(model, result.usage, startedAt) };
|
|
18893
|
+
},
|
|
18894
|
+
async designVoice(req, call = {}) {
|
|
18895
|
+
mediaRetryOptions(call);
|
|
18896
|
+
const { abortSignal, ...request } = req;
|
|
18897
|
+
const model = catalog.require(req.model);
|
|
18898
|
+
const { request: resolved, warnings } = resolveVoiceDesignCall(
|
|
18899
|
+
model,
|
|
18900
|
+
request,
|
|
18901
|
+
call.onUnsupported ?? "error"
|
|
18902
|
+
);
|
|
18903
|
+
const { adapter, ctx } = prepare(model, call, abortSignal, warnings);
|
|
18904
|
+
if (!adapter.designVoice) throw noMethod(adapter, model, "design a voice");
|
|
18905
|
+
const startedAt = Date.now();
|
|
18906
|
+
const result = await adapter.designVoice(resolved, ctx);
|
|
18907
|
+
return { ...result, usage: await deps.settle(model, result.usage, startedAt) };
|
|
18908
|
+
},
|
|
18909
|
+
async deleteVoice(req, call = {}) {
|
|
18910
|
+
mediaRetryOptions(call);
|
|
18911
|
+
const { abortSignal, ...request } = req;
|
|
18912
|
+
const model = catalog.require(req.model);
|
|
18913
|
+
assertMethod(model, "createVoice");
|
|
18914
|
+
const voiceId = request.voiceId.trim();
|
|
18915
|
+
if (!voiceId) {
|
|
18916
|
+
throw new ModelKitError({
|
|
18917
|
+
code: "missing_input",
|
|
18918
|
+
message: `${model.id} requires voiceId`,
|
|
18919
|
+
model: model.id
|
|
18920
|
+
});
|
|
18921
|
+
}
|
|
18922
|
+
const { adapter, ctx } = prepare(model, call, abortSignal, []);
|
|
18923
|
+
if (!adapter.deleteVoice) throw noMethod(adapter, model, "delete a voice");
|
|
18924
|
+
await adapter.deleteVoice({ model: model.id, voiceId }, ctx);
|
|
18925
|
+
},
|
|
17808
18926
|
async dub(req, call = {}) {
|
|
17809
18927
|
mediaRetryOptions(call);
|
|
17810
18928
|
const { abortSignal, ...request } = req;
|
|
@@ -17819,10 +18937,10 @@ function audioNodeMethods(deps) {
|
|
|
17819
18937
|
const startedAt = Date.now();
|
|
17820
18938
|
const outcome = await adapter.dub(resolved, ctx);
|
|
17821
18939
|
if (outcome.kind === "audio") {
|
|
17822
|
-
const { audio, usage:
|
|
18940
|
+
const { audio, usage: usage5, raw } = outcome.result;
|
|
17823
18941
|
return {
|
|
17824
18942
|
audio,
|
|
17825
|
-
usage: await deps.settle(model,
|
|
18943
|
+
usage: await deps.settle(model, usage5, startedAt),
|
|
17826
18944
|
...raw !== void 0 && { raw }
|
|
17827
18945
|
};
|
|
17828
18946
|
}
|
|
@@ -17860,10 +18978,10 @@ function textAbortOptions(sdk, context) {
|
|
|
17860
18978
|
if (abortSignal) return { abortSignal };
|
|
17861
18979
|
return {};
|
|
17862
18980
|
}
|
|
17863
|
-
var catalogId =
|
|
17864
|
-
var exactSize =
|
|
17865
|
-
var sdkRatio =
|
|
17866
|
-
var sizeTier =
|
|
18981
|
+
var catalogId = import_zod34.z.string();
|
|
18982
|
+
var exactSize = import_zod34.z.templateLiteral([import_zod34.z.number(), "x", import_zod34.z.number()]);
|
|
18983
|
+
var sdkRatio = import_zod34.z.templateLiteral([import_zod34.z.number(), ":", import_zod34.z.number()]);
|
|
18984
|
+
var sizeTier = import_zod34.z.enum(["512", "1K", "2K", "4K"]);
|
|
17867
18985
|
function isCatalogId(model) {
|
|
17868
18986
|
return catalogId.safeParse(model).success;
|
|
17869
18987
|
}
|
|
@@ -18076,7 +19194,7 @@ function createModelKit(config, adapters) {
|
|
|
18076
19194
|
const images = result.images.map(
|
|
18077
19195
|
(file) => toGeneratedImage({ bytes: file.uint8Array, mime: file.mediaType })
|
|
18078
19196
|
);
|
|
18079
|
-
const
|
|
19197
|
+
const usage5 = timed(
|
|
18080
19198
|
{
|
|
18081
19199
|
model: model.modelId,
|
|
18082
19200
|
provider: model.provider,
|
|
@@ -18086,8 +19204,8 @@ function createModelKit(config, adapters) {
|
|
|
18086
19204
|
},
|
|
18087
19205
|
startedAt
|
|
18088
19206
|
);
|
|
18089
|
-
await emit(
|
|
18090
|
-
return { image: images[0], images, usage:
|
|
19207
|
+
await emit(usage5);
|
|
19208
|
+
return { image: images[0], images, usage: usage5, raw: result, warnings };
|
|
18091
19209
|
}
|
|
18092
19210
|
function passthroughVideo(req, call) {
|
|
18093
19211
|
const {
|
|
@@ -18163,7 +19281,7 @@ function createModelKit(config, adapters) {
|
|
|
18163
19281
|
let settled;
|
|
18164
19282
|
let failed = false;
|
|
18165
19283
|
const done = pending.then(async (result) => {
|
|
18166
|
-
const
|
|
19284
|
+
const usage5 = timed(
|
|
18167
19285
|
{
|
|
18168
19286
|
model: model.modelId,
|
|
18169
19287
|
provider: model.provider,
|
|
@@ -18176,10 +19294,10 @@ function createModelKit(config, adapters) {
|
|
|
18176
19294
|
);
|
|
18177
19295
|
settled = {
|
|
18178
19296
|
video: { bytes: result.video.uint8Array, mime: result.video.mediaType },
|
|
18179
|
-
usage:
|
|
19297
|
+
usage: usage5,
|
|
18180
19298
|
raw: result
|
|
18181
19299
|
};
|
|
18182
|
-
await emit(
|
|
19300
|
+
await emit(usage5);
|
|
18183
19301
|
return settled;
|
|
18184
19302
|
});
|
|
18185
19303
|
done.catch(() => {
|
|
@@ -18206,12 +19324,12 @@ function createModelKit(config, adapters) {
|
|
|
18206
19324
|
if (settled) return settled;
|
|
18207
19325
|
const pending = result(opts).then(
|
|
18208
19326
|
async (out) => {
|
|
18209
|
-
const
|
|
19327
|
+
const usage5 = timed(
|
|
18210
19328
|
{ ...out.usage, model: model.id, unit: model.usage.unit },
|
|
18211
19329
|
startedAt
|
|
18212
19330
|
);
|
|
18213
|
-
await emit(
|
|
18214
|
-
return { ...out, usage:
|
|
19331
|
+
await emit(usage5);
|
|
19332
|
+
return { ...out, usage: usage5 };
|
|
18215
19333
|
},
|
|
18216
19334
|
(cause) => {
|
|
18217
19335
|
settled = void 0;
|
|
@@ -18231,9 +19349,9 @@ function createModelKit(config, adapters) {
|
|
|
18231
19349
|
return context(model, signal ? { ...call, signal } : call, warnings);
|
|
18232
19350
|
},
|
|
18233
19351
|
async settle(model, event, startedAt) {
|
|
18234
|
-
const
|
|
18235
|
-
await emit(
|
|
18236
|
-
return
|
|
19352
|
+
const usage5 = timed({ ...event, model: model.id, unit: model.usage.unit }, startedAt);
|
|
19353
|
+
await emit(usage5);
|
|
19354
|
+
return usage5;
|
|
18237
19355
|
},
|
|
18238
19356
|
wrapVideoJob
|
|
18239
19357
|
});
|
|
@@ -18269,11 +19387,11 @@ function createModelKit(config, adapters) {
|
|
|
18269
19387
|
});
|
|
18270
19388
|
const startedAt = Date.now();
|
|
18271
19389
|
const result = await adapter.generateImage(request, ctx);
|
|
18272
|
-
const
|
|
19390
|
+
const usage5 = timed(
|
|
18273
19391
|
{ ...result.usage, model: model.id, unit: model.usage.unit },
|
|
18274
19392
|
startedAt
|
|
18275
19393
|
);
|
|
18276
|
-
await emit(
|
|
19394
|
+
await emit(usage5);
|
|
18277
19395
|
const images = result.images.map(toGeneratedImage);
|
|
18278
19396
|
const first = images[0];
|
|
18279
19397
|
if (!first)
|
|
@@ -18282,7 +19400,7 @@ function createModelKit(config, adapters) {
|
|
|
18282
19400
|
message: `${model.id} returned no image`,
|
|
18283
19401
|
model: model.id
|
|
18284
19402
|
});
|
|
18285
|
-
return { ...result, usage:
|
|
19403
|
+
return { ...result, usage: usage5, image: first, images, warnings };
|
|
18286
19404
|
},
|
|
18287
19405
|
async generateVideo(req, call = {}) {
|
|
18288
19406
|
mediaRetryOptions(call);
|
|
@@ -18381,12 +19499,12 @@ function createModelKit(config, adapters) {
|
|
|
18381
19499
|
}
|
|
18382
19500
|
const startedAt = Date.now();
|
|
18383
19501
|
const result = await adapter.generateAudio(resolved, ctx);
|
|
18384
|
-
const
|
|
19502
|
+
const usage5 = timed(
|
|
18385
19503
|
{ ...result.usage, model: model.id, unit: model.usage.unit },
|
|
18386
19504
|
startedAt
|
|
18387
19505
|
);
|
|
18388
|
-
await emit(
|
|
18389
|
-
return { ...result, usage:
|
|
19506
|
+
await emit(usage5);
|
|
19507
|
+
return { ...result, usage: usage5 };
|
|
18390
19508
|
},
|
|
18391
19509
|
async prepareMediaPart(modelId, ref, mediaType, call = {}) {
|
|
18392
19510
|
mediaRetryOptions(call);
|
|
@@ -18466,8 +19584,8 @@ function createModelKit(config, adapters) {
|
|
|
18466
19584
|
options.prepareStep ?? options.experimental_prepareStep
|
|
18467
19585
|
),
|
|
18468
19586
|
onFinish: async (event) => {
|
|
18469
|
-
for (const
|
|
18470
|
-
await emit(textTimed(withRowUnit(
|
|
19587
|
+
for (const usage5 of steps.usage(event.steps))
|
|
19588
|
+
await emit(textTimed(withRowUnit(usage5), event.steps.length, startedAt));
|
|
18471
19589
|
await callerOnFinish?.(event);
|
|
18472
19590
|
}
|
|
18473
19591
|
});
|
|
@@ -18586,10 +19704,12 @@ var describe = (modelId) => createDefaultModelKit().describe(modelId);
|
|
|
18586
19704
|
dataOnlyCapable,
|
|
18587
19705
|
describe,
|
|
18588
19706
|
describeThrown,
|
|
19707
|
+
elevenLabsAdapter,
|
|
18589
19708
|
experimental_generateImage,
|
|
18590
19709
|
falAdapter,
|
|
18591
19710
|
falWebhookBodySchema,
|
|
18592
19711
|
fileCatalogCache,
|
|
19712
|
+
fishAdapter,
|
|
18593
19713
|
generateAudio,
|
|
18594
19714
|
generateImage,
|
|
18595
19715
|
generateObject,
|
|
@@ -18642,6 +19762,8 @@ var describe = (modelId) => createDefaultModelKit().describe(modelId);
|
|
|
18642
19762
|
resolveTranscriptionOptions,
|
|
18643
19763
|
resolveVideoOptions,
|
|
18644
19764
|
resolveVoiceChangeOptions,
|
|
19765
|
+
resolveVoiceCloneOptions,
|
|
19766
|
+
resolveVoiceDesignOptions,
|
|
18645
19767
|
shouldRetry,
|
|
18646
19768
|
sleep,
|
|
18647
19769
|
sortCatalogRows,
|