kugelaudio 0.6.0 → 0.7.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 +17 -0
- package/dist/index.d.mts +6 -3
- package/dist/index.d.ts +6 -3
- package/dist/index.js +92 -12
- package/dist/index.mjs +92 -12
- package/package.json +1 -1
- package/src/client.test.ts +65 -1
- package/src/client.ts +24 -7
- package/src/errors.ts +16 -4
- package/src/types.ts +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
## [kugelaudio-v0.7.0](https://github.com/Kugelaudio/KugelAudio/compare/js-sdk-v0.6.1...js-sdk-v0.7.0) (2026-06-06)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
* **ingress:** add request observability metadata ([#1321](https://github.com/Kugelaudio/KugelAudio/issues/1321)) ([a9c5178](https://github.com/Kugelaudio/KugelAudio/commit/a9c5178193cb8b746a8bbd9b566b11f7b1d00f6d))
|
|
6
|
+
* **sdks:** default all SDKs to kugel-3 model ([#1323](https://github.com/Kugelaudio/KugelAudio/issues/1323)) ([c4de212](https://github.com/Kugelaudio/KugelAudio/commit/c4de212c91e16326a15dbee5622acacc83ed85bb))
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **js-sdk:** type SDK metadata fetch mock ([#1334](https://github.com/Kugelaudio/KugelAudio/issues/1334)) ([e8f6f59](https://github.com/Kugelaudio/KugelAudio/commit/e8f6f59595e123eaae8b44670c94fb4e7bc8d06c))
|
|
11
|
+
|
|
12
|
+
## [kugelaudio-v0.6.1](https://github.com/Kugelaudio/KugelAudio/compare/js-sdk-v0.6.0...js-sdk-v0.6.1) (2026-06-04)
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
|
|
16
|
+
* **python-sdk:** propagate ingress errors through SDK integrations ([#1313](https://github.com/Kugelaudio/KugelAudio/issues/1313)) ([3ae2e03](https://github.com/Kugelaudio/KugelAudio/commit/3ae2e03745b49cca0712c20d9a658c160f4b6f38))
|
|
17
|
+
|
|
1
18
|
## [kugelaudio-v0.6.0](https://github.com/Kugelaudio/KugelAudio/compare/js-sdk-v0.5.0...js-sdk-v0.6.0) (2026-06-01)
|
|
2
19
|
|
|
3
20
|
### Features
|
package/dist/index.d.mts
CHANGED
|
@@ -217,7 +217,7 @@ interface WordTimestamp {
|
|
|
217
217
|
interface GenerateOptions {
|
|
218
218
|
/** Text to synthesize */
|
|
219
219
|
text: string;
|
|
220
|
-
/** Model to use: 'kugel-
|
|
220
|
+
/** Model to use. Default: 'kugel-3'. Legacy ids (kugel-2.5, kugel-1-turbo, …) still accepted; they alias to kugel-3 server-side. */
|
|
221
221
|
modelId?: string;
|
|
222
222
|
/** Voice ID to use */
|
|
223
223
|
voiceId?: number;
|
|
@@ -296,7 +296,7 @@ interface GenerateOptions {
|
|
|
296
296
|
interface StreamConfig {
|
|
297
297
|
/** Voice ID to use */
|
|
298
298
|
voiceId?: number;
|
|
299
|
-
/** Model ID
|
|
299
|
+
/** Model ID. Default: 'kugel-3'. Legacy ids still accepted; they alias to kugel-3 server-side. */
|
|
300
300
|
modelId?: string;
|
|
301
301
|
/** CFG scale for generation */
|
|
302
302
|
cfgScale?: number;
|
|
@@ -1224,6 +1224,8 @@ declare const ErrorCodes: {
|
|
|
1224
1224
|
readonly VALIDATION: "VALIDATION_ERROR";
|
|
1225
1225
|
readonly INTERNAL: "INTERNAL_ERROR";
|
|
1226
1226
|
readonly NOT_FOUND: "NOT_FOUND";
|
|
1227
|
+
readonly MISSING_VOICE_ID: "MISSING_VOICE_ID";
|
|
1228
|
+
readonly TOO_MANY_CONTEXTS: "TOO_MANY_CONTEXTS";
|
|
1227
1229
|
};
|
|
1228
1230
|
type ErrorCode = typeof ErrorCodes[keyof typeof ErrorCodes];
|
|
1229
1231
|
declare const WsCloseCodes: {
|
|
@@ -1305,11 +1307,12 @@ interface HttpResponseLike {
|
|
|
1305
1307
|
declare function classifyHttpError(status: number, bodyText: string, headers: HttpResponseLike['headers']): KugelAudioError;
|
|
1306
1308
|
/**
|
|
1307
1309
|
* Build a `KugelAudioError` from a server-sent WebSocket error frame
|
|
1308
|
-
* (`{error, error_code,
|
|
1310
|
+
* (`{error, error_code, code}`).
|
|
1309
1311
|
*/
|
|
1310
1312
|
declare function classifyWsFrame(data: {
|
|
1311
1313
|
error?: string;
|
|
1312
1314
|
error_code?: string;
|
|
1315
|
+
code?: number;
|
|
1313
1316
|
retry_after?: number;
|
|
1314
1317
|
}): KugelAudioError;
|
|
1315
1318
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -217,7 +217,7 @@ interface WordTimestamp {
|
|
|
217
217
|
interface GenerateOptions {
|
|
218
218
|
/** Text to synthesize */
|
|
219
219
|
text: string;
|
|
220
|
-
/** Model to use: 'kugel-
|
|
220
|
+
/** Model to use. Default: 'kugel-3'. Legacy ids (kugel-2.5, kugel-1-turbo, …) still accepted; they alias to kugel-3 server-side. */
|
|
221
221
|
modelId?: string;
|
|
222
222
|
/** Voice ID to use */
|
|
223
223
|
voiceId?: number;
|
|
@@ -296,7 +296,7 @@ interface GenerateOptions {
|
|
|
296
296
|
interface StreamConfig {
|
|
297
297
|
/** Voice ID to use */
|
|
298
298
|
voiceId?: number;
|
|
299
|
-
/** Model ID
|
|
299
|
+
/** Model ID. Default: 'kugel-3'. Legacy ids still accepted; they alias to kugel-3 server-side. */
|
|
300
300
|
modelId?: string;
|
|
301
301
|
/** CFG scale for generation */
|
|
302
302
|
cfgScale?: number;
|
|
@@ -1224,6 +1224,8 @@ declare const ErrorCodes: {
|
|
|
1224
1224
|
readonly VALIDATION: "VALIDATION_ERROR";
|
|
1225
1225
|
readonly INTERNAL: "INTERNAL_ERROR";
|
|
1226
1226
|
readonly NOT_FOUND: "NOT_FOUND";
|
|
1227
|
+
readonly MISSING_VOICE_ID: "MISSING_VOICE_ID";
|
|
1228
|
+
readonly TOO_MANY_CONTEXTS: "TOO_MANY_CONTEXTS";
|
|
1227
1229
|
};
|
|
1228
1230
|
type ErrorCode = typeof ErrorCodes[keyof typeof ErrorCodes];
|
|
1229
1231
|
declare const WsCloseCodes: {
|
|
@@ -1305,11 +1307,12 @@ interface HttpResponseLike {
|
|
|
1305
1307
|
declare function classifyHttpError(status: number, bodyText: string, headers: HttpResponseLike['headers']): KugelAudioError;
|
|
1306
1308
|
/**
|
|
1307
1309
|
* Build a `KugelAudioError` from a server-sent WebSocket error frame
|
|
1308
|
-
* (`{error, error_code,
|
|
1310
|
+
* (`{error, error_code, code}`).
|
|
1309
1311
|
*/
|
|
1310
1312
|
declare function classifyWsFrame(data: {
|
|
1311
1313
|
error?: string;
|
|
1312
1314
|
error_code?: string;
|
|
1315
|
+
code?: number;
|
|
1313
1316
|
retry_after?: number;
|
|
1314
1317
|
}): KugelAudioError;
|
|
1315
1318
|
/**
|
package/dist/index.js
CHANGED
|
@@ -233,7 +233,9 @@ var ErrorCodes = {
|
|
|
233
233
|
EMPTY_AUDIO: "EMPTY_AUDIO",
|
|
234
234
|
VALIDATION: "VALIDATION_ERROR",
|
|
235
235
|
INTERNAL: "INTERNAL_ERROR",
|
|
236
|
-
NOT_FOUND: "NOT_FOUND"
|
|
236
|
+
NOT_FOUND: "NOT_FOUND",
|
|
237
|
+
MISSING_VOICE_ID: "MISSING_VOICE_ID",
|
|
238
|
+
TOO_MANY_CONTEXTS: "TOO_MANY_CONTEXTS"
|
|
237
239
|
};
|
|
238
240
|
var WsCloseCodes = {
|
|
239
241
|
UNAUTHORIZED: 4001,
|
|
@@ -317,10 +319,10 @@ function build(status, errorCode, message, opts = {}) {
|
|
|
317
319
|
if (errorCode === ErrorCodes.INSUFFICIENT_CREDITS || status === 402) {
|
|
318
320
|
return new InsufficientCreditsError(message || void 0, common);
|
|
319
321
|
}
|
|
320
|
-
if (errorCode === ErrorCodes.RATE_LIMITED || status === 429) {
|
|
322
|
+
if (errorCode === ErrorCodes.RATE_LIMITED || errorCode === ErrorCodes.TOO_MANY_CONTEXTS || status === 429) {
|
|
321
323
|
return new RateLimitError(message || void 0, common);
|
|
322
324
|
}
|
|
323
|
-
if (errorCode === ErrorCodes.VALIDATION || status === 400) {
|
|
325
|
+
if (errorCode === ErrorCodes.VALIDATION || errorCode === ErrorCodes.MISSING_VOICE_ID || status === 400) {
|
|
324
326
|
return new ValidationError(message || "Request validation failed.", common);
|
|
325
327
|
}
|
|
326
328
|
if (errorCode === ErrorCodes.MODEL_UNAVAILABLE || status === 503) {
|
|
@@ -380,8 +382,9 @@ function classifyHttpError(status, bodyText, headers) {
|
|
|
380
382
|
function classifyWsFrame(data) {
|
|
381
383
|
const errorCode = data.error_code;
|
|
382
384
|
const message = data.error ?? "Server reported an error.";
|
|
385
|
+
const status = typeof data.code === "number" ? data.code : void 0;
|
|
383
386
|
const retryAfter = typeof data.retry_after === "number" ? data.retry_after : void 0;
|
|
384
|
-
return build(
|
|
387
|
+
return build(status, errorCode, message, { retryAfter });
|
|
385
388
|
}
|
|
386
389
|
function classifyWsClose(code, reason) {
|
|
387
390
|
const reasonTxt = (reason ?? "").trim();
|
|
@@ -509,10 +512,75 @@ function getWebSocket() {
|
|
|
509
512
|
);
|
|
510
513
|
}
|
|
511
514
|
|
|
515
|
+
// package.json
|
|
516
|
+
var package_default = {
|
|
517
|
+
name: "kugelaudio",
|
|
518
|
+
version: "0.7.0",
|
|
519
|
+
description: "Official JavaScript/TypeScript SDK for KugelAudio TTS API",
|
|
520
|
+
main: "dist/index.js",
|
|
521
|
+
module: "dist/index.mjs",
|
|
522
|
+
types: "dist/index.d.ts",
|
|
523
|
+
exports: {
|
|
524
|
+
".": {
|
|
525
|
+
types: "./dist/index.d.ts",
|
|
526
|
+
import: "./dist/index.mjs",
|
|
527
|
+
require: "./dist/index.js"
|
|
528
|
+
}
|
|
529
|
+
},
|
|
530
|
+
files: [
|
|
531
|
+
"dist",
|
|
532
|
+
"src",
|
|
533
|
+
"LICENSE",
|
|
534
|
+
"CHANGELOG.md"
|
|
535
|
+
],
|
|
536
|
+
scripts: {
|
|
537
|
+
build: "tsup src/index.ts --format cjs,esm --dts",
|
|
538
|
+
dev: "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
539
|
+
lint: "eslint src/",
|
|
540
|
+
test: "vitest run",
|
|
541
|
+
"test:watch": "vitest",
|
|
542
|
+
prepublishOnly: "npm run build"
|
|
543
|
+
},
|
|
544
|
+
keywords: [
|
|
545
|
+
"tts",
|
|
546
|
+
"text-to-speech",
|
|
547
|
+
"audio",
|
|
548
|
+
"streaming",
|
|
549
|
+
"websocket",
|
|
550
|
+
"kugelaudio"
|
|
551
|
+
],
|
|
552
|
+
author: "KugelAudio <hello@kugelaudio.com>",
|
|
553
|
+
license: "MIT",
|
|
554
|
+
repository: {
|
|
555
|
+
type: "git",
|
|
556
|
+
url: "https://github.com/Kugelaudio/KugelAudio",
|
|
557
|
+
directory: "sdks/js"
|
|
558
|
+
},
|
|
559
|
+
homepage: "https://kugelaudio.com",
|
|
560
|
+
bugs: {
|
|
561
|
+
url: "https://github.com/Kugelaudio/KugelAudio/issues"
|
|
562
|
+
},
|
|
563
|
+
devDependencies: {
|
|
564
|
+
"@types/node": "^25.3.2",
|
|
565
|
+
tsup: "^8.0.0",
|
|
566
|
+
typescript: "^6.0.2",
|
|
567
|
+
vitest: "^4.0.18"
|
|
568
|
+
},
|
|
569
|
+
engines: {
|
|
570
|
+
node: ">=18.0.0"
|
|
571
|
+
},
|
|
572
|
+
dependencies: {
|
|
573
|
+
tsx: "^4.21.0",
|
|
574
|
+
ws: "^8.18.0"
|
|
575
|
+
}
|
|
576
|
+
};
|
|
577
|
+
|
|
512
578
|
// src/client.ts
|
|
513
579
|
var DEFAULT_API_URL = "https://api.kugelaudio.com";
|
|
514
580
|
var EU_API_URL = "https://api.eu.kugelaudio.com";
|
|
515
581
|
var SUPPORTED_REGIONS = ["eu", "us", "global"];
|
|
582
|
+
var SDK_NAME = "js";
|
|
583
|
+
var SDK_VERSION = package_default.version;
|
|
516
584
|
var REGION_PREFIXES = ["eu-", "us-", "global-"];
|
|
517
585
|
function parseApiKey(apiKey) {
|
|
518
586
|
for (const prefix of REGION_PREFIXES) {
|
|
@@ -522,6 +590,16 @@ function parseApiKey(apiKey) {
|
|
|
522
590
|
}
|
|
523
591
|
return { cleanKey: apiKey };
|
|
524
592
|
}
|
|
593
|
+
function sdkHeaders() {
|
|
594
|
+
return {
|
|
595
|
+
"X-KugelAudio-SDK": SDK_NAME,
|
|
596
|
+
"X-KugelAudio-SDK-Version": SDK_VERSION
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
function appendSdkQuery(url) {
|
|
600
|
+
const separator = url.includes("?") ? "&" : "?";
|
|
601
|
+
return `${url}${separator}sdk=${encodeURIComponent(SDK_NAME)}&sdk_version=${encodeURIComponent(SDK_VERSION)}`;
|
|
602
|
+
}
|
|
525
603
|
function createWs(url) {
|
|
526
604
|
const WS = getWebSocket();
|
|
527
605
|
return new WS(url);
|
|
@@ -890,7 +968,7 @@ var TTSResource = class {
|
|
|
890
968
|
if (this.client.orgId !== void 0) {
|
|
891
969
|
url += `&org_id=${this.client.orgId}`;
|
|
892
970
|
}
|
|
893
|
-
return url;
|
|
971
|
+
return appendSdkQuery(url);
|
|
894
972
|
}
|
|
895
973
|
/**
|
|
896
974
|
* Get or create a WebSocket connection for connection pooling.
|
|
@@ -1038,7 +1116,7 @@ var TTSResource = class {
|
|
|
1038
1116
|
callbacks.onOpen?.();
|
|
1039
1117
|
ws.send(JSON.stringify({
|
|
1040
1118
|
text: options.text,
|
|
1041
|
-
model_id: options.modelId || "kugel-
|
|
1119
|
+
model_id: options.modelId || "kugel-3",
|
|
1042
1120
|
voice_id: options.voiceId,
|
|
1043
1121
|
cfg_scale: options.cfgScale ?? 2,
|
|
1044
1122
|
...options.temperature !== void 0 && { temperature: options.temperature },
|
|
@@ -1064,7 +1142,7 @@ var TTSResource = class {
|
|
|
1064
1142
|
callbacks.onOpen?.();
|
|
1065
1143
|
ws.send(JSON.stringify({
|
|
1066
1144
|
text: options.text,
|
|
1067
|
-
model_id: options.modelId || "kugel-
|
|
1145
|
+
model_id: options.modelId || "kugel-3",
|
|
1068
1146
|
voice_id: options.voiceId,
|
|
1069
1147
|
cfg_scale: options.cfgScale ?? 2,
|
|
1070
1148
|
max_new_tokens: options.maxNewTokens ?? 2048,
|
|
@@ -1294,7 +1372,7 @@ var MultiContextSession = class {
|
|
|
1294
1372
|
} else {
|
|
1295
1373
|
authParam = "api_key";
|
|
1296
1374
|
}
|
|
1297
|
-
const url = `${wsUrl}/ws/tts/multi?${authParam}=${this.client.apiKey}
|
|
1375
|
+
const url = appendSdkQuery(`${wsUrl}/ws/tts/multi?${authParam}=${this.client.apiKey}`);
|
|
1298
1376
|
this.ws = createWs(url);
|
|
1299
1377
|
const ws = this.ws;
|
|
1300
1378
|
ws.onmessage = (event) => {
|
|
@@ -1303,7 +1381,7 @@ var MultiContextSession = class {
|
|
|
1303
1381
|
const data = JSON.parse(messageData);
|
|
1304
1382
|
if (data.error) {
|
|
1305
1383
|
this.callbacks.onError?.(
|
|
1306
|
-
|
|
1384
|
+
classifyWsFrame(data),
|
|
1307
1385
|
data.context_id
|
|
1308
1386
|
);
|
|
1309
1387
|
return;
|
|
@@ -1515,7 +1593,7 @@ var StreamingSession = class {
|
|
|
1515
1593
|
} else {
|
|
1516
1594
|
authParam = "api_key";
|
|
1517
1595
|
}
|
|
1518
|
-
const url = `${wsUrl}/ws/tts/stream?${authParam}=${this.client.apiKey}
|
|
1596
|
+
const url = appendSdkQuery(`${wsUrl}/ws/tts/stream?${authParam}=${this.client.apiKey}`);
|
|
1519
1597
|
this.ws = createWs(url);
|
|
1520
1598
|
const ws = this.ws;
|
|
1521
1599
|
ws.onmessage = (event) => {
|
|
@@ -1919,7 +1997,8 @@ var KugelAudio = class _KugelAudio {
|
|
|
1919
1997
|
const headers = {
|
|
1920
1998
|
"Content-Type": "application/json",
|
|
1921
1999
|
"X-API-Key": this._apiKey,
|
|
1922
|
-
"Authorization": `Bearer ${this._apiKey}
|
|
2000
|
+
"Authorization": `Bearer ${this._apiKey}`,
|
|
2001
|
+
...sdkHeaders()
|
|
1923
2002
|
};
|
|
1924
2003
|
const controller = new AbortController();
|
|
1925
2004
|
const timeoutId = setTimeout(() => controller.abort(), this._timeout);
|
|
@@ -1959,7 +2038,8 @@ var KugelAudio = class _KugelAudio {
|
|
|
1959
2038
|
const url = `${this._apiUrl}${path}`;
|
|
1960
2039
|
const headers = {
|
|
1961
2040
|
"X-API-Key": this._apiKey,
|
|
1962
|
-
"Authorization": `Bearer ${this._apiKey}
|
|
2041
|
+
"Authorization": `Bearer ${this._apiKey}`,
|
|
2042
|
+
...sdkHeaders()
|
|
1963
2043
|
};
|
|
1964
2044
|
const controller = new AbortController();
|
|
1965
2045
|
const timeoutId = setTimeout(() => controller.abort(), this._timeout);
|
package/dist/index.mjs
CHANGED
|
@@ -195,7 +195,9 @@ var ErrorCodes = {
|
|
|
195
195
|
EMPTY_AUDIO: "EMPTY_AUDIO",
|
|
196
196
|
VALIDATION: "VALIDATION_ERROR",
|
|
197
197
|
INTERNAL: "INTERNAL_ERROR",
|
|
198
|
-
NOT_FOUND: "NOT_FOUND"
|
|
198
|
+
NOT_FOUND: "NOT_FOUND",
|
|
199
|
+
MISSING_VOICE_ID: "MISSING_VOICE_ID",
|
|
200
|
+
TOO_MANY_CONTEXTS: "TOO_MANY_CONTEXTS"
|
|
199
201
|
};
|
|
200
202
|
var WsCloseCodes = {
|
|
201
203
|
UNAUTHORIZED: 4001,
|
|
@@ -279,10 +281,10 @@ function build(status, errorCode, message, opts = {}) {
|
|
|
279
281
|
if (errorCode === ErrorCodes.INSUFFICIENT_CREDITS || status === 402) {
|
|
280
282
|
return new InsufficientCreditsError(message || void 0, common);
|
|
281
283
|
}
|
|
282
|
-
if (errorCode === ErrorCodes.RATE_LIMITED || status === 429) {
|
|
284
|
+
if (errorCode === ErrorCodes.RATE_LIMITED || errorCode === ErrorCodes.TOO_MANY_CONTEXTS || status === 429) {
|
|
283
285
|
return new RateLimitError(message || void 0, common);
|
|
284
286
|
}
|
|
285
|
-
if (errorCode === ErrorCodes.VALIDATION || status === 400) {
|
|
287
|
+
if (errorCode === ErrorCodes.VALIDATION || errorCode === ErrorCodes.MISSING_VOICE_ID || status === 400) {
|
|
286
288
|
return new ValidationError(message || "Request validation failed.", common);
|
|
287
289
|
}
|
|
288
290
|
if (errorCode === ErrorCodes.MODEL_UNAVAILABLE || status === 503) {
|
|
@@ -342,8 +344,9 @@ function classifyHttpError(status, bodyText, headers) {
|
|
|
342
344
|
function classifyWsFrame(data) {
|
|
343
345
|
const errorCode = data.error_code;
|
|
344
346
|
const message = data.error ?? "Server reported an error.";
|
|
347
|
+
const status = typeof data.code === "number" ? data.code : void 0;
|
|
345
348
|
const retryAfter = typeof data.retry_after === "number" ? data.retry_after : void 0;
|
|
346
|
-
return build(
|
|
349
|
+
return build(status, errorCode, message, { retryAfter });
|
|
347
350
|
}
|
|
348
351
|
function classifyWsClose(code, reason) {
|
|
349
352
|
const reasonTxt = (reason ?? "").trim();
|
|
@@ -471,10 +474,75 @@ function getWebSocket() {
|
|
|
471
474
|
);
|
|
472
475
|
}
|
|
473
476
|
|
|
477
|
+
// package.json
|
|
478
|
+
var package_default = {
|
|
479
|
+
name: "kugelaudio",
|
|
480
|
+
version: "0.7.0",
|
|
481
|
+
description: "Official JavaScript/TypeScript SDK for KugelAudio TTS API",
|
|
482
|
+
main: "dist/index.js",
|
|
483
|
+
module: "dist/index.mjs",
|
|
484
|
+
types: "dist/index.d.ts",
|
|
485
|
+
exports: {
|
|
486
|
+
".": {
|
|
487
|
+
types: "./dist/index.d.ts",
|
|
488
|
+
import: "./dist/index.mjs",
|
|
489
|
+
require: "./dist/index.js"
|
|
490
|
+
}
|
|
491
|
+
},
|
|
492
|
+
files: [
|
|
493
|
+
"dist",
|
|
494
|
+
"src",
|
|
495
|
+
"LICENSE",
|
|
496
|
+
"CHANGELOG.md"
|
|
497
|
+
],
|
|
498
|
+
scripts: {
|
|
499
|
+
build: "tsup src/index.ts --format cjs,esm --dts",
|
|
500
|
+
dev: "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
501
|
+
lint: "eslint src/",
|
|
502
|
+
test: "vitest run",
|
|
503
|
+
"test:watch": "vitest",
|
|
504
|
+
prepublishOnly: "npm run build"
|
|
505
|
+
},
|
|
506
|
+
keywords: [
|
|
507
|
+
"tts",
|
|
508
|
+
"text-to-speech",
|
|
509
|
+
"audio",
|
|
510
|
+
"streaming",
|
|
511
|
+
"websocket",
|
|
512
|
+
"kugelaudio"
|
|
513
|
+
],
|
|
514
|
+
author: "KugelAudio <hello@kugelaudio.com>",
|
|
515
|
+
license: "MIT",
|
|
516
|
+
repository: {
|
|
517
|
+
type: "git",
|
|
518
|
+
url: "https://github.com/Kugelaudio/KugelAudio",
|
|
519
|
+
directory: "sdks/js"
|
|
520
|
+
},
|
|
521
|
+
homepage: "https://kugelaudio.com",
|
|
522
|
+
bugs: {
|
|
523
|
+
url: "https://github.com/Kugelaudio/KugelAudio/issues"
|
|
524
|
+
},
|
|
525
|
+
devDependencies: {
|
|
526
|
+
"@types/node": "^25.3.2",
|
|
527
|
+
tsup: "^8.0.0",
|
|
528
|
+
typescript: "^6.0.2",
|
|
529
|
+
vitest: "^4.0.18"
|
|
530
|
+
},
|
|
531
|
+
engines: {
|
|
532
|
+
node: ">=18.0.0"
|
|
533
|
+
},
|
|
534
|
+
dependencies: {
|
|
535
|
+
tsx: "^4.21.0",
|
|
536
|
+
ws: "^8.18.0"
|
|
537
|
+
}
|
|
538
|
+
};
|
|
539
|
+
|
|
474
540
|
// src/client.ts
|
|
475
541
|
var DEFAULT_API_URL = "https://api.kugelaudio.com";
|
|
476
542
|
var EU_API_URL = "https://api.eu.kugelaudio.com";
|
|
477
543
|
var SUPPORTED_REGIONS = ["eu", "us", "global"];
|
|
544
|
+
var SDK_NAME = "js";
|
|
545
|
+
var SDK_VERSION = package_default.version;
|
|
478
546
|
var REGION_PREFIXES = ["eu-", "us-", "global-"];
|
|
479
547
|
function parseApiKey(apiKey) {
|
|
480
548
|
for (const prefix of REGION_PREFIXES) {
|
|
@@ -484,6 +552,16 @@ function parseApiKey(apiKey) {
|
|
|
484
552
|
}
|
|
485
553
|
return { cleanKey: apiKey };
|
|
486
554
|
}
|
|
555
|
+
function sdkHeaders() {
|
|
556
|
+
return {
|
|
557
|
+
"X-KugelAudio-SDK": SDK_NAME,
|
|
558
|
+
"X-KugelAudio-SDK-Version": SDK_VERSION
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
function appendSdkQuery(url) {
|
|
562
|
+
const separator = url.includes("?") ? "&" : "?";
|
|
563
|
+
return `${url}${separator}sdk=${encodeURIComponent(SDK_NAME)}&sdk_version=${encodeURIComponent(SDK_VERSION)}`;
|
|
564
|
+
}
|
|
487
565
|
function createWs(url) {
|
|
488
566
|
const WS = getWebSocket();
|
|
489
567
|
return new WS(url);
|
|
@@ -852,7 +930,7 @@ var TTSResource = class {
|
|
|
852
930
|
if (this.client.orgId !== void 0) {
|
|
853
931
|
url += `&org_id=${this.client.orgId}`;
|
|
854
932
|
}
|
|
855
|
-
return url;
|
|
933
|
+
return appendSdkQuery(url);
|
|
856
934
|
}
|
|
857
935
|
/**
|
|
858
936
|
* Get or create a WebSocket connection for connection pooling.
|
|
@@ -1000,7 +1078,7 @@ var TTSResource = class {
|
|
|
1000
1078
|
callbacks.onOpen?.();
|
|
1001
1079
|
ws.send(JSON.stringify({
|
|
1002
1080
|
text: options.text,
|
|
1003
|
-
model_id: options.modelId || "kugel-
|
|
1081
|
+
model_id: options.modelId || "kugel-3",
|
|
1004
1082
|
voice_id: options.voiceId,
|
|
1005
1083
|
cfg_scale: options.cfgScale ?? 2,
|
|
1006
1084
|
...options.temperature !== void 0 && { temperature: options.temperature },
|
|
@@ -1026,7 +1104,7 @@ var TTSResource = class {
|
|
|
1026
1104
|
callbacks.onOpen?.();
|
|
1027
1105
|
ws.send(JSON.stringify({
|
|
1028
1106
|
text: options.text,
|
|
1029
|
-
model_id: options.modelId || "kugel-
|
|
1107
|
+
model_id: options.modelId || "kugel-3",
|
|
1030
1108
|
voice_id: options.voiceId,
|
|
1031
1109
|
cfg_scale: options.cfgScale ?? 2,
|
|
1032
1110
|
max_new_tokens: options.maxNewTokens ?? 2048,
|
|
@@ -1256,7 +1334,7 @@ var MultiContextSession = class {
|
|
|
1256
1334
|
} else {
|
|
1257
1335
|
authParam = "api_key";
|
|
1258
1336
|
}
|
|
1259
|
-
const url = `${wsUrl}/ws/tts/multi?${authParam}=${this.client.apiKey}
|
|
1337
|
+
const url = appendSdkQuery(`${wsUrl}/ws/tts/multi?${authParam}=${this.client.apiKey}`);
|
|
1260
1338
|
this.ws = createWs(url);
|
|
1261
1339
|
const ws = this.ws;
|
|
1262
1340
|
ws.onmessage = (event) => {
|
|
@@ -1265,7 +1343,7 @@ var MultiContextSession = class {
|
|
|
1265
1343
|
const data = JSON.parse(messageData);
|
|
1266
1344
|
if (data.error) {
|
|
1267
1345
|
this.callbacks.onError?.(
|
|
1268
|
-
|
|
1346
|
+
classifyWsFrame(data),
|
|
1269
1347
|
data.context_id
|
|
1270
1348
|
);
|
|
1271
1349
|
return;
|
|
@@ -1477,7 +1555,7 @@ var StreamingSession = class {
|
|
|
1477
1555
|
} else {
|
|
1478
1556
|
authParam = "api_key";
|
|
1479
1557
|
}
|
|
1480
|
-
const url = `${wsUrl}/ws/tts/stream?${authParam}=${this.client.apiKey}
|
|
1558
|
+
const url = appendSdkQuery(`${wsUrl}/ws/tts/stream?${authParam}=${this.client.apiKey}`);
|
|
1481
1559
|
this.ws = createWs(url);
|
|
1482
1560
|
const ws = this.ws;
|
|
1483
1561
|
ws.onmessage = (event) => {
|
|
@@ -1881,7 +1959,8 @@ var KugelAudio = class _KugelAudio {
|
|
|
1881
1959
|
const headers = {
|
|
1882
1960
|
"Content-Type": "application/json",
|
|
1883
1961
|
"X-API-Key": this._apiKey,
|
|
1884
|
-
"Authorization": `Bearer ${this._apiKey}
|
|
1962
|
+
"Authorization": `Bearer ${this._apiKey}`,
|
|
1963
|
+
...sdkHeaders()
|
|
1885
1964
|
};
|
|
1886
1965
|
const controller = new AbortController();
|
|
1887
1966
|
const timeoutId = setTimeout(() => controller.abort(), this._timeout);
|
|
@@ -1921,7 +2000,8 @@ var KugelAudio = class _KugelAudio {
|
|
|
1921
2000
|
const url = `${this._apiUrl}${path}`;
|
|
1922
2001
|
const headers = {
|
|
1923
2002
|
"X-API-Key": this._apiKey,
|
|
1924
|
-
"Authorization": `Bearer ${this._apiKey}
|
|
2003
|
+
"Authorization": `Bearer ${this._apiKey}`,
|
|
2004
|
+
...sdkHeaders()
|
|
1925
2005
|
};
|
|
1926
2006
|
const controller = new AbortController();
|
|
1927
2007
|
const timeoutId = setTimeout(() => controller.abort(), this._timeout);
|
package/package.json
CHANGED
package/src/client.test.ts
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
10
10
|
import { KugelAudio } from './client';
|
|
11
|
+
import { RateLimitError } from './errors';
|
|
11
12
|
|
|
12
13
|
// ---------------------------------------------------------------------------
|
|
13
14
|
// Minimal WebSocket mock
|
|
@@ -17,6 +18,7 @@ type WsListener = (event: { data: string }) => void;
|
|
|
17
18
|
type WsCloseListener = (event: { code: number }) => void;
|
|
18
19
|
|
|
19
20
|
interface MockWs {
|
|
21
|
+
url: string;
|
|
20
22
|
readyState: number;
|
|
21
23
|
onopen: (() => void) | null;
|
|
22
24
|
onmessage: WsListener | null;
|
|
@@ -32,6 +34,7 @@ let mockWs: MockWs;
|
|
|
32
34
|
vi.mock('./websocket', () => ({
|
|
33
35
|
getWebSocket: () => {
|
|
34
36
|
return class MockWebSocket {
|
|
37
|
+
url: string;
|
|
35
38
|
readyState = 0; // CONNECTING
|
|
36
39
|
onopen: (() => void) | null = null;
|
|
37
40
|
onmessage: WsListener | null = null;
|
|
@@ -41,7 +44,8 @@ vi.mock('./websocket', () => ({
|
|
|
41
44
|
close = vi.fn();
|
|
42
45
|
ping = vi.fn();
|
|
43
46
|
|
|
44
|
-
constructor() {
|
|
47
|
+
constructor(url: string) {
|
|
48
|
+
this.url = url;
|
|
45
49
|
mockWs = this as unknown as MockWs;
|
|
46
50
|
// Simulate async open
|
|
47
51
|
setTimeout(() => {
|
|
@@ -246,6 +250,43 @@ describe('KugelAudio multi-region', () => {
|
|
|
246
250
|
});
|
|
247
251
|
});
|
|
248
252
|
|
|
253
|
+
describe('KugelAudio SDK metadata', () => {
|
|
254
|
+
it('adds SDK metadata headers to HTTP requests', async () => {
|
|
255
|
+
const originalFetch = globalThis.fetch;
|
|
256
|
+
const fetchMock = vi.fn<typeof fetch>(async () => ({
|
|
257
|
+
ok: true,
|
|
258
|
+
json: async () => ({ models: [] }),
|
|
259
|
+
} as Response));
|
|
260
|
+
globalThis.fetch = fetchMock;
|
|
261
|
+
|
|
262
|
+
try {
|
|
263
|
+
const client = new KugelAudio({ apiKey: 'ka_test123' });
|
|
264
|
+
await client.models.list();
|
|
265
|
+
} finally {
|
|
266
|
+
globalThis.fetch = originalFetch;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
270
|
+
const [, init] = fetchMock.mock.calls[0];
|
|
271
|
+
expect(init).toMatchObject({
|
|
272
|
+
headers: {
|
|
273
|
+
'X-KugelAudio-SDK': 'js',
|
|
274
|
+
'X-KugelAudio-SDK-Version': '0.6.1',
|
|
275
|
+
},
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it('adds SDK metadata query params to WebSocket URLs', async () => {
|
|
280
|
+
const client = new KugelAudio({ apiKey: 'ka_test123' });
|
|
281
|
+
|
|
282
|
+
client.tts.toReadable({ text: 'metadata test' });
|
|
283
|
+
await new Promise<void>((r) => setTimeout(r, 10));
|
|
284
|
+
|
|
285
|
+
expect(mockWs.url).toContain('sdk=js');
|
|
286
|
+
expect(mockWs.url).toContain('sdk_version=0.6.1');
|
|
287
|
+
});
|
|
288
|
+
});
|
|
289
|
+
|
|
249
290
|
// ---------------------------------------------------------------------------
|
|
250
291
|
// Keepalive ping tests
|
|
251
292
|
// ---------------------------------------------------------------------------
|
|
@@ -660,4 +701,27 @@ describe('MultiContextSession closeContext', () => {
|
|
|
660
701
|
expect(sent.close_context).toBe(true);
|
|
661
702
|
expect(sent.immediate).toBeUndefined();
|
|
662
703
|
});
|
|
704
|
+
|
|
705
|
+
it('maps ingress context-cap errors to typed callback errors', async () => {
|
|
706
|
+
const errors: Array<{ contextId?: string; error: Error }> = [];
|
|
707
|
+
const session = client.tts.createMultiContextSession({ defaultVoiceId: 1 });
|
|
708
|
+
await session.connect({
|
|
709
|
+
onError: (error, contextId) => errors.push({ contextId, error }),
|
|
710
|
+
});
|
|
711
|
+
|
|
712
|
+
mockWs.onmessage?.({
|
|
713
|
+
data: JSON.stringify({
|
|
714
|
+
error: 'Too many concurrent contexts',
|
|
715
|
+
error_code: 'TOO_MANY_CONTEXTS',
|
|
716
|
+
code: 429,
|
|
717
|
+
context_id: 'ctx1',
|
|
718
|
+
}),
|
|
719
|
+
});
|
|
720
|
+
|
|
721
|
+
expect(errors).toHaveLength(1);
|
|
722
|
+
expect(errors[0].contextId).toBe('ctx1');
|
|
723
|
+
expect(errors[0].error).toBeInstanceOf(RateLimitError);
|
|
724
|
+
expect((errors[0].error as RateLimitError).statusCode).toBe(429);
|
|
725
|
+
expect((errors[0].error as RateLimitError).errorCode).toBe('TOO_MANY_CONTEXTS');
|
|
726
|
+
});
|
|
663
727
|
});
|
package/src/client.ts
CHANGED
|
@@ -33,10 +33,13 @@ import { base64ToArrayBuffer } from './utils';
|
|
|
33
33
|
import { getWebSocket } from './websocket';
|
|
34
34
|
|
|
35
35
|
import type { Region } from './types';
|
|
36
|
+
import packageJson from '../package.json';
|
|
36
37
|
|
|
37
38
|
const DEFAULT_API_URL = 'https://api.kugelaudio.com';
|
|
38
39
|
const EU_API_URL = 'https://api.eu.kugelaudio.com';
|
|
39
40
|
const SUPPORTED_REGIONS = ['eu', 'us', 'global'] as const;
|
|
41
|
+
const SDK_NAME = 'js';
|
|
42
|
+
const SDK_VERSION = packageJson.version;
|
|
40
43
|
|
|
41
44
|
const REGION_PREFIXES = ['eu-', 'us-', 'global-'] as const;
|
|
42
45
|
|
|
@@ -49,6 +52,18 @@ function parseApiKey(apiKey: string): { cleanKey: string; detectedRegion?: Regio
|
|
|
49
52
|
return { cleanKey: apiKey };
|
|
50
53
|
}
|
|
51
54
|
|
|
55
|
+
function sdkHeaders(): Record<string, string> {
|
|
56
|
+
return {
|
|
57
|
+
'X-KugelAudio-SDK': SDK_NAME,
|
|
58
|
+
'X-KugelAudio-SDK-Version': SDK_VERSION,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function appendSdkQuery(url: string): string {
|
|
63
|
+
const separator = url.includes('?') ? '&' : '?';
|
|
64
|
+
return `${url}${separator}sdk=${encodeURIComponent(SDK_NAME)}&sdk_version=${encodeURIComponent(SDK_VERSION)}`;
|
|
65
|
+
}
|
|
66
|
+
|
|
52
67
|
/**
|
|
53
68
|
* Create a new WebSocket instance.
|
|
54
69
|
* Lazily resolves the constructor to avoid top-level side-effects
|
|
@@ -491,7 +506,7 @@ class TTSResource {
|
|
|
491
506
|
if (this.client.orgId !== undefined) {
|
|
492
507
|
url += `&org_id=${this.client.orgId}`;
|
|
493
508
|
}
|
|
494
|
-
return url;
|
|
509
|
+
return appendSdkQuery(url);
|
|
495
510
|
}
|
|
496
511
|
|
|
497
512
|
/**
|
|
@@ -692,7 +707,7 @@ class TTSResource {
|
|
|
692
707
|
|
|
693
708
|
ws.send(JSON.stringify({
|
|
694
709
|
text: options.text,
|
|
695
|
-
model_id: options.modelId || 'kugel-
|
|
710
|
+
model_id: options.modelId || 'kugel-3',
|
|
696
711
|
voice_id: options.voiceId,
|
|
697
712
|
cfg_scale: options.cfgScale ?? 2.0,
|
|
698
713
|
...(options.temperature !== undefined && { temperature: options.temperature }),
|
|
@@ -724,7 +739,7 @@ class TTSResource {
|
|
|
724
739
|
// Send TTS request
|
|
725
740
|
ws.send(JSON.stringify({
|
|
726
741
|
text: options.text,
|
|
727
|
-
model_id: options.modelId || 'kugel-
|
|
742
|
+
model_id: options.modelId || 'kugel-3',
|
|
728
743
|
voice_id: options.voiceId,
|
|
729
744
|
cfg_scale: options.cfgScale ?? 2.0,
|
|
730
745
|
max_new_tokens: options.maxNewTokens ?? 2048,
|
|
@@ -873,7 +888,7 @@ class TTSResource {
|
|
|
873
888
|
}
|
|
874
889
|
}
|
|
875
890
|
|
|
876
|
-
private parseError(data: { error?: string; error_code?: string; retry_after?: number }): Error {
|
|
891
|
+
private parseError(data: { error?: string; error_code?: string; code?: number; retry_after?: number }): Error {
|
|
877
892
|
return classifyWsFrame(data);
|
|
878
893
|
}
|
|
879
894
|
|
|
@@ -1003,7 +1018,7 @@ class MultiContextSession {
|
|
|
1003
1018
|
authParam = 'api_key';
|
|
1004
1019
|
}
|
|
1005
1020
|
|
|
1006
|
-
const url = `${wsUrl}/ws/tts/multi?${authParam}=${this.client.apiKey}
|
|
1021
|
+
const url = appendSdkQuery(`${wsUrl}/ws/tts/multi?${authParam}=${this.client.apiKey}`);
|
|
1007
1022
|
this.ws = createWs(url);
|
|
1008
1023
|
const ws = this.ws;
|
|
1009
1024
|
|
|
@@ -1019,7 +1034,7 @@ class MultiContextSession {
|
|
|
1019
1034
|
|
|
1020
1035
|
if (data.error) {
|
|
1021
1036
|
this.callbacks.onError?.(
|
|
1022
|
-
|
|
1037
|
+
classifyWsFrame(data),
|
|
1023
1038
|
data.context_id
|
|
1024
1039
|
);
|
|
1025
1040
|
return;
|
|
@@ -1317,7 +1332,7 @@ class StreamingSession {
|
|
|
1317
1332
|
authParam = 'api_key';
|
|
1318
1333
|
}
|
|
1319
1334
|
|
|
1320
|
-
const url = `${wsUrl}/ws/tts/stream?${authParam}=${this.client.apiKey}
|
|
1335
|
+
const url = appendSdkQuery(`${wsUrl}/ws/tts/stream?${authParam}=${this.client.apiKey}`);
|
|
1321
1336
|
this.ws = createWs(url);
|
|
1322
1337
|
const ws = this.ws;
|
|
1323
1338
|
|
|
@@ -1865,6 +1880,7 @@ export class KugelAudio {
|
|
|
1865
1880
|
'Content-Type': 'application/json',
|
|
1866
1881
|
'X-API-Key': this._apiKey,
|
|
1867
1882
|
'Authorization': `Bearer ${this._apiKey}`,
|
|
1883
|
+
...sdkHeaders(),
|
|
1868
1884
|
};
|
|
1869
1885
|
|
|
1870
1886
|
const controller = new AbortController();
|
|
@@ -1913,6 +1929,7 @@ export class KugelAudio {
|
|
|
1913
1929
|
const headers: Record<string, string> = {
|
|
1914
1930
|
'X-API-Key': this._apiKey,
|
|
1915
1931
|
'Authorization': `Bearer ${this._apiKey}`,
|
|
1932
|
+
...sdkHeaders(),
|
|
1916
1933
|
};
|
|
1917
1934
|
|
|
1918
1935
|
const controller = new AbortController();
|
package/src/errors.ts
CHANGED
|
@@ -17,6 +17,8 @@ export const ErrorCodes = {
|
|
|
17
17
|
VALIDATION: 'VALIDATION_ERROR',
|
|
18
18
|
INTERNAL: 'INTERNAL_ERROR',
|
|
19
19
|
NOT_FOUND: 'NOT_FOUND',
|
|
20
|
+
MISSING_VOICE_ID: 'MISSING_VOICE_ID',
|
|
21
|
+
TOO_MANY_CONTEXTS: 'TOO_MANY_CONTEXTS',
|
|
20
22
|
} as const;
|
|
21
23
|
export type ErrorCode = typeof ErrorCodes[keyof typeof ErrorCodes];
|
|
22
24
|
|
|
@@ -175,10 +177,18 @@ function build(
|
|
|
175
177
|
if (errorCode === ErrorCodes.INSUFFICIENT_CREDITS || status === 402) {
|
|
176
178
|
return new InsufficientCreditsError(message || undefined, common);
|
|
177
179
|
}
|
|
178
|
-
if (
|
|
180
|
+
if (
|
|
181
|
+
errorCode === ErrorCodes.RATE_LIMITED ||
|
|
182
|
+
errorCode === ErrorCodes.TOO_MANY_CONTEXTS ||
|
|
183
|
+
status === 429
|
|
184
|
+
) {
|
|
179
185
|
return new RateLimitError(message || undefined, common);
|
|
180
186
|
}
|
|
181
|
-
if (
|
|
187
|
+
if (
|
|
188
|
+
errorCode === ErrorCodes.VALIDATION ||
|
|
189
|
+
errorCode === ErrorCodes.MISSING_VOICE_ID ||
|
|
190
|
+
status === 400
|
|
191
|
+
) {
|
|
182
192
|
return new ValidationError(message || 'Request validation failed.', common);
|
|
183
193
|
}
|
|
184
194
|
if (errorCode === ErrorCodes.MODEL_UNAVAILABLE || status === 503) {
|
|
@@ -263,17 +273,19 @@ export function classifyHttpError(
|
|
|
263
273
|
|
|
264
274
|
/**
|
|
265
275
|
* Build a `KugelAudioError` from a server-sent WebSocket error frame
|
|
266
|
-
* (`{error, error_code,
|
|
276
|
+
* (`{error, error_code, code}`).
|
|
267
277
|
*/
|
|
268
278
|
export function classifyWsFrame(data: {
|
|
269
279
|
error?: string;
|
|
270
280
|
error_code?: string;
|
|
281
|
+
code?: number;
|
|
271
282
|
retry_after?: number;
|
|
272
283
|
}): KugelAudioError {
|
|
273
284
|
const errorCode = data.error_code;
|
|
274
285
|
const message = data.error ?? 'Server reported an error.';
|
|
286
|
+
const status = typeof data.code === 'number' ? data.code : undefined;
|
|
275
287
|
const retryAfter = typeof data.retry_after === 'number' ? data.retry_after : undefined;
|
|
276
|
-
return build(
|
|
288
|
+
return build(status, errorCode, message, { retryAfter });
|
|
277
289
|
}
|
|
278
290
|
|
|
279
291
|
/**
|
package/src/types.ts
CHANGED
|
@@ -240,7 +240,7 @@ export interface WordTimestamp {
|
|
|
240
240
|
export interface GenerateOptions {
|
|
241
241
|
/** Text to synthesize */
|
|
242
242
|
text: string;
|
|
243
|
-
/** Model to use: 'kugel-
|
|
243
|
+
/** Model to use. Default: 'kugel-3'. Legacy ids (kugel-2.5, kugel-1-turbo, …) still accepted; they alias to kugel-3 server-side. */
|
|
244
244
|
modelId?: string;
|
|
245
245
|
/** Voice ID to use */
|
|
246
246
|
voiceId?: number;
|
|
@@ -320,7 +320,7 @@ export interface GenerateOptions {
|
|
|
320
320
|
export interface StreamConfig {
|
|
321
321
|
/** Voice ID to use */
|
|
322
322
|
voiceId?: number;
|
|
323
|
-
/** Model ID
|
|
323
|
+
/** Model ID. Default: 'kugel-3'. Legacy ids still accepted; they alias to kugel-3 server-side. */
|
|
324
324
|
modelId?: string;
|
|
325
325
|
/** CFG scale for generation */
|
|
326
326
|
cfgScale?: number;
|