kugelaudio 0.7.0 → 0.8.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 +13 -0
- package/README.md +11 -2
- package/dist/index.d.mts +121 -10
- package/dist/index.d.ts +121 -10
- package/dist/index.js +95 -17
- package/dist/index.mjs +93 -16
- package/package.json +1 -1
- package/src/client.test.ts +356 -2
- package/src/client.ts +95 -12
- package/src/index.ts +2 -0
- package/src/types.ts +128 -10
package/dist/index.js
CHANGED
|
@@ -39,7 +39,8 @@ __export(index_exports, {
|
|
|
39
39
|
classifyWsHandshakeError: () => classifyWsHandshakeError,
|
|
40
40
|
createWavBlob: () => createWavBlob,
|
|
41
41
|
createWavFile: () => createWavFile,
|
|
42
|
-
decodePCM16: () => decodePCM16
|
|
42
|
+
decodePCM16: () => decodePCM16,
|
|
43
|
+
parseSessionUsage: () => parseSessionUsage
|
|
43
44
|
});
|
|
44
45
|
module.exports = __toCommonJS(index_exports);
|
|
45
46
|
|
|
@@ -429,6 +430,23 @@ function classifyWsHandshakeError(err) {
|
|
|
429
430
|
return build(status, void 0, typeof e.message === "string" ? e.message : "");
|
|
430
431
|
}
|
|
431
432
|
|
|
433
|
+
// src/types.ts
|
|
434
|
+
function parseSessionUsage(data) {
|
|
435
|
+
const raw = data.usage;
|
|
436
|
+
const source = raw && typeof raw === "object" ? raw : data;
|
|
437
|
+
const audioSeconds = typeof source.audio_seconds === "number" ? source.audio_seconds : typeof data.total_audio_seconds === "number" ? data.total_audio_seconds : void 0;
|
|
438
|
+
if (audioSeconds === void 0) return null;
|
|
439
|
+
const costCents = typeof source.cost_cents === "number" ? source.cost_cents : null;
|
|
440
|
+
return {
|
|
441
|
+
audioSeconds,
|
|
442
|
+
costCents,
|
|
443
|
+
currency: typeof source.currency === "string" ? source.currency : void 0,
|
|
444
|
+
characters: typeof source.characters === "number" ? source.characters : void 0,
|
|
445
|
+
modelId: typeof source.model_id === "string" ? source.model_id : void 0,
|
|
446
|
+
costAvailable: costCents !== null
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
|
|
432
450
|
// src/utils.ts
|
|
433
451
|
function base64ToArrayBuffer(base64) {
|
|
434
452
|
if (typeof atob === "function") {
|
|
@@ -515,7 +533,7 @@ function getWebSocket() {
|
|
|
515
533
|
// package.json
|
|
516
534
|
var package_default = {
|
|
517
535
|
name: "kugelaudio",
|
|
518
|
-
version: "0.
|
|
536
|
+
version: "0.8.0",
|
|
519
537
|
description: "Official JavaScript/TypeScript SDK for KugelAudio TTS API",
|
|
520
538
|
main: "dist/index.js",
|
|
521
539
|
module: "dist/index.mjs",
|
|
@@ -1031,7 +1049,8 @@ var TTSResource = class {
|
|
|
1031
1049
|
durationMs: data.dur_ms,
|
|
1032
1050
|
generationMs: data.gen_ms,
|
|
1033
1051
|
rtf: data.rtf,
|
|
1034
|
-
error: data.error
|
|
1052
|
+
error: data.error,
|
|
1053
|
+
usage: parseSessionUsage(data) ?? void 0
|
|
1035
1054
|
};
|
|
1036
1055
|
pending.callbacks.onFinal?.(stats);
|
|
1037
1056
|
this.pendingRequests.delete(requestId);
|
|
@@ -1122,11 +1141,15 @@ var TTSResource = class {
|
|
|
1122
1141
|
...options.temperature !== void 0 && { temperature: options.temperature },
|
|
1123
1142
|
max_new_tokens: options.maxNewTokens ?? 2048,
|
|
1124
1143
|
sample_rate: options.sampleRate ?? 24e3,
|
|
1144
|
+
...options.outputFormat && { output_format: options.outputFormat },
|
|
1125
1145
|
normalize: options.normalize ?? true,
|
|
1126
1146
|
...options.language && { language: options.language },
|
|
1127
1147
|
...options.wordTimestamps && { word_timestamps: true },
|
|
1128
1148
|
...options.speed !== void 0 && { speed: options.speed },
|
|
1129
|
-
...options.projectId !== void 0 && { project_id: options.projectId }
|
|
1149
|
+
...options.projectId !== void 0 && { project_id: options.projectId },
|
|
1150
|
+
// [] is meaningful (explicit opt-out) and must be sent; only
|
|
1151
|
+
// undefined (use the project default) is omitted.
|
|
1152
|
+
...options.dictionaryIds !== void 0 && { dictionary_ids: options.dictionaryIds }
|
|
1130
1153
|
}));
|
|
1131
1154
|
});
|
|
1132
1155
|
}
|
|
@@ -1147,11 +1170,15 @@ var TTSResource = class {
|
|
|
1147
1170
|
cfg_scale: options.cfgScale ?? 2,
|
|
1148
1171
|
max_new_tokens: options.maxNewTokens ?? 2048,
|
|
1149
1172
|
sample_rate: options.sampleRate ?? 24e3,
|
|
1173
|
+
...options.outputFormat && { output_format: options.outputFormat },
|
|
1150
1174
|
normalize: options.normalize ?? true,
|
|
1151
1175
|
...options.language && { language: options.language },
|
|
1152
1176
|
...options.wordTimestamps && { word_timestamps: true },
|
|
1153
1177
|
...options.speed !== void 0 && { speed: options.speed },
|
|
1154
|
-
...options.projectId !== void 0 && { project_id: options.projectId }
|
|
1178
|
+
...options.projectId !== void 0 && { project_id: options.projectId },
|
|
1179
|
+
// [] is meaningful (explicit opt-out) and must be sent; only
|
|
1180
|
+
// undefined (use the project default) is omitted.
|
|
1181
|
+
...options.dictionaryIds !== void 0 && { dictionary_ids: options.dictionaryIds }
|
|
1155
1182
|
}));
|
|
1156
1183
|
};
|
|
1157
1184
|
ws.onmessage = (event) => {
|
|
@@ -1173,7 +1200,8 @@ var TTSResource = class {
|
|
|
1173
1200
|
durationMs: data.dur_ms,
|
|
1174
1201
|
generationMs: data.gen_ms,
|
|
1175
1202
|
rtf: data.rtf,
|
|
1176
|
-
error: data.error
|
|
1203
|
+
error: data.error,
|
|
1204
|
+
usage: parseSessionUsage(data) ?? void 0
|
|
1177
1205
|
};
|
|
1178
1206
|
callbacks.onFinal?.(stats);
|
|
1179
1207
|
ws.close();
|
|
@@ -1343,7 +1371,11 @@ var MultiContextSession = class {
|
|
|
1343
1371
|
this.ws = null;
|
|
1344
1372
|
this.callbacks = {};
|
|
1345
1373
|
this.contexts = /* @__PURE__ */ new Set();
|
|
1374
|
+
/** Contexts a create message has been sent for (not yet necessarily
|
|
1375
|
+
* confirmed by the server via context_created). */
|
|
1376
|
+
this.requestedContexts = /* @__PURE__ */ new Set();
|
|
1346
1377
|
this._sessionId = null;
|
|
1378
|
+
this._contextUsage = /* @__PURE__ */ new Map();
|
|
1347
1379
|
this.isStarted = false;
|
|
1348
1380
|
this.config = config || {};
|
|
1349
1381
|
}
|
|
@@ -1353,6 +1385,18 @@ var MultiContextSession = class {
|
|
|
1353
1385
|
get sessionId() {
|
|
1354
1386
|
return this._sessionId;
|
|
1355
1387
|
}
|
|
1388
|
+
/**
|
|
1389
|
+
* Per-context usage (audio time + amount charged) for a closed context, or
|
|
1390
|
+
* null if that context hasn't closed yet. Each context is its own
|
|
1391
|
+
* conversation — use this to bill per conversation. See {@link SessionUsage}.
|
|
1392
|
+
*/
|
|
1393
|
+
usageFor(contextId) {
|
|
1394
|
+
return this._contextUsage.get(contextId) ?? null;
|
|
1395
|
+
}
|
|
1396
|
+
/** Map of context_id → per-context usage for all closed contexts. */
|
|
1397
|
+
get contextUsage() {
|
|
1398
|
+
return new Map(this._contextUsage);
|
|
1399
|
+
}
|
|
1356
1400
|
/**
|
|
1357
1401
|
* Connect to the multi-context WebSocket endpoint.
|
|
1358
1402
|
*
|
|
@@ -1406,12 +1450,19 @@ var MultiContextSession = class {
|
|
|
1406
1450
|
};
|
|
1407
1451
|
this.callbacks.onChunk?.(chunk);
|
|
1408
1452
|
}
|
|
1453
|
+
if (data.final && data.context_id) {
|
|
1454
|
+
this.callbacks.onFinal?.(data.context_id);
|
|
1455
|
+
}
|
|
1409
1456
|
if (data.context_closed) {
|
|
1410
1457
|
this.contexts.delete(data.context_id);
|
|
1411
|
-
this.
|
|
1458
|
+
this.requestedContexts.delete(data.context_id);
|
|
1459
|
+
const ctxUsage = parseSessionUsage(data) ?? void 0;
|
|
1460
|
+
if (ctxUsage) this._contextUsage.set(data.context_id, ctxUsage);
|
|
1461
|
+
this.callbacks.onContextClosed?.(data.context_id, ctxUsage);
|
|
1412
1462
|
}
|
|
1413
1463
|
if (data.context_timeout) {
|
|
1414
1464
|
this.contexts.delete(data.context_id);
|
|
1465
|
+
this.requestedContexts.delete(data.context_id);
|
|
1415
1466
|
this.callbacks.onContextTimeout?.(data.context_id);
|
|
1416
1467
|
}
|
|
1417
1468
|
if (data.session_closed) {
|
|
@@ -1451,6 +1502,7 @@ var MultiContextSession = class {
|
|
|
1451
1502
|
this.ws = null;
|
|
1452
1503
|
this.isStarted = false;
|
|
1453
1504
|
this.contexts.clear();
|
|
1505
|
+
this.requestedContexts.clear();
|
|
1454
1506
|
};
|
|
1455
1507
|
});
|
|
1456
1508
|
}
|
|
@@ -1461,6 +1513,7 @@ var MultiContextSession = class {
|
|
|
1461
1513
|
if (!this.ws || this.ws.readyState !== WS_OPEN) {
|
|
1462
1514
|
throw new KugelAudioError("WebSocket not connected");
|
|
1463
1515
|
}
|
|
1516
|
+
this.requestedContexts.add(contextId);
|
|
1464
1517
|
const msg = {
|
|
1465
1518
|
text: " ",
|
|
1466
1519
|
context_id: contextId
|
|
@@ -1468,23 +1521,27 @@ var MultiContextSession = class {
|
|
|
1468
1521
|
if (!this.isStarted) {
|
|
1469
1522
|
warnIfNoLanguage(this.config.language, this.config.normalize);
|
|
1470
1523
|
if (this.config.sampleRate) msg.sample_rate = this.config.sampleRate;
|
|
1524
|
+
if (this.config.outputFormat) msg.output_format = this.config.outputFormat;
|
|
1471
1525
|
if (this.config.cfgScale) msg.cfg_scale = this.config.cfgScale;
|
|
1472
1526
|
if (this.config.temperature !== void 0) msg.temperature = this.config.temperature;
|
|
1473
1527
|
if (this.config.maxNewTokens) msg.max_new_tokens = this.config.maxNewTokens;
|
|
1474
1528
|
if (this.config.normalize !== void 0) msg.normalize = this.config.normalize;
|
|
1475
1529
|
if (this.config.language) msg.language = this.config.language;
|
|
1530
|
+
if (this.config.dictionaryIds !== void 0) msg.dictionary_ids = this.config.dictionaryIds;
|
|
1476
1531
|
if (this.config.inactivityTimeout) msg.inactivity_timeout = this.config.inactivityTimeout;
|
|
1477
1532
|
}
|
|
1533
|
+
const voiceSettings = {};
|
|
1478
1534
|
const voiceId = options?.voiceId || this.config.defaultVoiceId;
|
|
1479
|
-
if (voiceId)
|
|
1535
|
+
if (voiceId) voiceSettings.voice_id = voiceId;
|
|
1480
1536
|
if (options?.voiceSettings) {
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1537
|
+
voiceSettings.stability = options.voiceSettings.stability;
|
|
1538
|
+
voiceSettings.similarity_boost = options.voiceSettings.similarityBoost;
|
|
1539
|
+
voiceSettings.style = options.voiceSettings.style;
|
|
1540
|
+
voiceSettings.use_speaker_boost = options.voiceSettings.useSpeakerBoost;
|
|
1541
|
+
voiceSettings.speed = options.voiceSettings.speed;
|
|
1542
|
+
}
|
|
1543
|
+
if (Object.keys(voiceSettings).length > 0) {
|
|
1544
|
+
msg.voice_settings = voiceSettings;
|
|
1488
1545
|
}
|
|
1489
1546
|
this.ws.send(JSON.stringify(msg));
|
|
1490
1547
|
}
|
|
@@ -1495,7 +1552,7 @@ var MultiContextSession = class {
|
|
|
1495
1552
|
if (!this.ws || this.ws.readyState !== WS_OPEN) {
|
|
1496
1553
|
throw new KugelAudioError("WebSocket not connected");
|
|
1497
1554
|
}
|
|
1498
|
-
if (!this.
|
|
1555
|
+
if (!this.requestedContexts.has(contextId) && !this.contexts.has(contextId)) {
|
|
1499
1556
|
this.createContext(contextId);
|
|
1500
1557
|
}
|
|
1501
1558
|
this.ws.send(JSON.stringify({
|
|
@@ -1553,6 +1610,7 @@ var MultiContextSession = class {
|
|
|
1553
1610
|
this.ws = null;
|
|
1554
1611
|
this.isStarted = false;
|
|
1555
1612
|
this.contexts.clear();
|
|
1613
|
+
this.requestedContexts.clear();
|
|
1556
1614
|
}
|
|
1557
1615
|
/**
|
|
1558
1616
|
* Get active context IDs.
|
|
@@ -1571,10 +1629,19 @@ var StreamingSession = class {
|
|
|
1571
1629
|
constructor(client, config, callbacks) {
|
|
1572
1630
|
this.ws = null;
|
|
1573
1631
|
this.configSent = false;
|
|
1632
|
+
this._lastUsage = null;
|
|
1574
1633
|
this.client = client;
|
|
1575
1634
|
this.config = config;
|
|
1576
1635
|
this.callbacks = callbacks;
|
|
1577
1636
|
}
|
|
1637
|
+
/**
|
|
1638
|
+
* Per-session usage from the most recently closed session, or null before
|
|
1639
|
+
* the first session closes. Use this to bill your own customers per
|
|
1640
|
+
* conversation. See {@link SessionUsage}.
|
|
1641
|
+
*/
|
|
1642
|
+
get lastUsage() {
|
|
1643
|
+
return this._lastUsage;
|
|
1644
|
+
}
|
|
1578
1645
|
/**
|
|
1579
1646
|
* Open the WebSocket connection and authenticate.
|
|
1580
1647
|
*
|
|
@@ -1638,7 +1705,15 @@ var StreamingSession = class {
|
|
|
1638
1705
|
if (data.interrupted) {
|
|
1639
1706
|
this.callbacks.onInterrupted?.();
|
|
1640
1707
|
}
|
|
1708
|
+
if (data.final) {
|
|
1709
|
+
this.callbacks.onFinal?.(
|
|
1710
|
+
data.total_audio_seconds ?? 0,
|
|
1711
|
+
data.total_text_chunks ?? 0,
|
|
1712
|
+
data.total_audio_chunks ?? 0
|
|
1713
|
+
);
|
|
1714
|
+
}
|
|
1641
1715
|
if (data.session_closed) {
|
|
1716
|
+
this._lastUsage = parseSessionUsage(data);
|
|
1642
1717
|
this.callbacks.onSessionClosed?.(
|
|
1643
1718
|
data.total_audio_seconds ?? 0,
|
|
1644
1719
|
data.total_text_chunks ?? 0,
|
|
@@ -1706,6 +1781,7 @@ var StreamingSession = class {
|
|
|
1706
1781
|
if (this.config.temperature !== void 0) msg.temperature = this.config.temperature;
|
|
1707
1782
|
if (this.config.maxNewTokens !== void 0) msg.max_new_tokens = this.config.maxNewTokens;
|
|
1708
1783
|
if (this.config.sampleRate !== void 0) msg.sample_rate = this.config.sampleRate;
|
|
1784
|
+
if (this.config.outputFormat !== void 0) msg.output_format = this.config.outputFormat;
|
|
1709
1785
|
if (this.config.flushTimeoutMs !== void 0) msg.flush_timeout_ms = this.config.flushTimeoutMs;
|
|
1710
1786
|
if (this.config.maxBufferLength !== void 0) msg.max_buffer_length = this.config.maxBufferLength;
|
|
1711
1787
|
if (this.config.normalize !== void 0) msg.normalize = this.config.normalize;
|
|
@@ -1714,6 +1790,7 @@ var StreamingSession = class {
|
|
|
1714
1790
|
if (this.config.autoMode !== void 0) msg.auto_mode = this.config.autoMode;
|
|
1715
1791
|
if (this.config.chunkLengthSchedule?.length) msg.chunk_length_schedule = this.config.chunkLengthSchedule;
|
|
1716
1792
|
if (this.config.speed !== void 0) msg.speed = this.config.speed;
|
|
1793
|
+
if (this.config.dictionaryIds !== void 0) msg.dictionary_ids = this.config.dictionaryIds;
|
|
1717
1794
|
this.configSent = true;
|
|
1718
1795
|
}
|
|
1719
1796
|
this.ws.send(JSON.stringify(msg));
|
|
@@ -2093,5 +2170,6 @@ var KugelAudio = class _KugelAudio {
|
|
|
2093
2170
|
classifyWsHandshakeError,
|
|
2094
2171
|
createWavBlob,
|
|
2095
2172
|
createWavFile,
|
|
2096
|
-
decodePCM16
|
|
2173
|
+
decodePCM16,
|
|
2174
|
+
parseSessionUsage
|
|
2097
2175
|
});
|
package/dist/index.mjs
CHANGED
|
@@ -391,6 +391,23 @@ function classifyWsHandshakeError(err) {
|
|
|
391
391
|
return build(status, void 0, typeof e.message === "string" ? e.message : "");
|
|
392
392
|
}
|
|
393
393
|
|
|
394
|
+
// src/types.ts
|
|
395
|
+
function parseSessionUsage(data) {
|
|
396
|
+
const raw = data.usage;
|
|
397
|
+
const source = raw && typeof raw === "object" ? raw : data;
|
|
398
|
+
const audioSeconds = typeof source.audio_seconds === "number" ? source.audio_seconds : typeof data.total_audio_seconds === "number" ? data.total_audio_seconds : void 0;
|
|
399
|
+
if (audioSeconds === void 0) return null;
|
|
400
|
+
const costCents = typeof source.cost_cents === "number" ? source.cost_cents : null;
|
|
401
|
+
return {
|
|
402
|
+
audioSeconds,
|
|
403
|
+
costCents,
|
|
404
|
+
currency: typeof source.currency === "string" ? source.currency : void 0,
|
|
405
|
+
characters: typeof source.characters === "number" ? source.characters : void 0,
|
|
406
|
+
modelId: typeof source.model_id === "string" ? source.model_id : void 0,
|
|
407
|
+
costAvailable: costCents !== null
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
|
|
394
411
|
// src/utils.ts
|
|
395
412
|
function base64ToArrayBuffer(base64) {
|
|
396
413
|
if (typeof atob === "function") {
|
|
@@ -477,7 +494,7 @@ function getWebSocket() {
|
|
|
477
494
|
// package.json
|
|
478
495
|
var package_default = {
|
|
479
496
|
name: "kugelaudio",
|
|
480
|
-
version: "0.
|
|
497
|
+
version: "0.8.0",
|
|
481
498
|
description: "Official JavaScript/TypeScript SDK for KugelAudio TTS API",
|
|
482
499
|
main: "dist/index.js",
|
|
483
500
|
module: "dist/index.mjs",
|
|
@@ -993,7 +1010,8 @@ var TTSResource = class {
|
|
|
993
1010
|
durationMs: data.dur_ms,
|
|
994
1011
|
generationMs: data.gen_ms,
|
|
995
1012
|
rtf: data.rtf,
|
|
996
|
-
error: data.error
|
|
1013
|
+
error: data.error,
|
|
1014
|
+
usage: parseSessionUsage(data) ?? void 0
|
|
997
1015
|
};
|
|
998
1016
|
pending.callbacks.onFinal?.(stats);
|
|
999
1017
|
this.pendingRequests.delete(requestId);
|
|
@@ -1084,11 +1102,15 @@ var TTSResource = class {
|
|
|
1084
1102
|
...options.temperature !== void 0 && { temperature: options.temperature },
|
|
1085
1103
|
max_new_tokens: options.maxNewTokens ?? 2048,
|
|
1086
1104
|
sample_rate: options.sampleRate ?? 24e3,
|
|
1105
|
+
...options.outputFormat && { output_format: options.outputFormat },
|
|
1087
1106
|
normalize: options.normalize ?? true,
|
|
1088
1107
|
...options.language && { language: options.language },
|
|
1089
1108
|
...options.wordTimestamps && { word_timestamps: true },
|
|
1090
1109
|
...options.speed !== void 0 && { speed: options.speed },
|
|
1091
|
-
...options.projectId !== void 0 && { project_id: options.projectId }
|
|
1110
|
+
...options.projectId !== void 0 && { project_id: options.projectId },
|
|
1111
|
+
// [] is meaningful (explicit opt-out) and must be sent; only
|
|
1112
|
+
// undefined (use the project default) is omitted.
|
|
1113
|
+
...options.dictionaryIds !== void 0 && { dictionary_ids: options.dictionaryIds }
|
|
1092
1114
|
}));
|
|
1093
1115
|
});
|
|
1094
1116
|
}
|
|
@@ -1109,11 +1131,15 @@ var TTSResource = class {
|
|
|
1109
1131
|
cfg_scale: options.cfgScale ?? 2,
|
|
1110
1132
|
max_new_tokens: options.maxNewTokens ?? 2048,
|
|
1111
1133
|
sample_rate: options.sampleRate ?? 24e3,
|
|
1134
|
+
...options.outputFormat && { output_format: options.outputFormat },
|
|
1112
1135
|
normalize: options.normalize ?? true,
|
|
1113
1136
|
...options.language && { language: options.language },
|
|
1114
1137
|
...options.wordTimestamps && { word_timestamps: true },
|
|
1115
1138
|
...options.speed !== void 0 && { speed: options.speed },
|
|
1116
|
-
...options.projectId !== void 0 && { project_id: options.projectId }
|
|
1139
|
+
...options.projectId !== void 0 && { project_id: options.projectId },
|
|
1140
|
+
// [] is meaningful (explicit opt-out) and must be sent; only
|
|
1141
|
+
// undefined (use the project default) is omitted.
|
|
1142
|
+
...options.dictionaryIds !== void 0 && { dictionary_ids: options.dictionaryIds }
|
|
1117
1143
|
}));
|
|
1118
1144
|
};
|
|
1119
1145
|
ws.onmessage = (event) => {
|
|
@@ -1135,7 +1161,8 @@ var TTSResource = class {
|
|
|
1135
1161
|
durationMs: data.dur_ms,
|
|
1136
1162
|
generationMs: data.gen_ms,
|
|
1137
1163
|
rtf: data.rtf,
|
|
1138
|
-
error: data.error
|
|
1164
|
+
error: data.error,
|
|
1165
|
+
usage: parseSessionUsage(data) ?? void 0
|
|
1139
1166
|
};
|
|
1140
1167
|
callbacks.onFinal?.(stats);
|
|
1141
1168
|
ws.close();
|
|
@@ -1305,7 +1332,11 @@ var MultiContextSession = class {
|
|
|
1305
1332
|
this.ws = null;
|
|
1306
1333
|
this.callbacks = {};
|
|
1307
1334
|
this.contexts = /* @__PURE__ */ new Set();
|
|
1335
|
+
/** Contexts a create message has been sent for (not yet necessarily
|
|
1336
|
+
* confirmed by the server via context_created). */
|
|
1337
|
+
this.requestedContexts = /* @__PURE__ */ new Set();
|
|
1308
1338
|
this._sessionId = null;
|
|
1339
|
+
this._contextUsage = /* @__PURE__ */ new Map();
|
|
1309
1340
|
this.isStarted = false;
|
|
1310
1341
|
this.config = config || {};
|
|
1311
1342
|
}
|
|
@@ -1315,6 +1346,18 @@ var MultiContextSession = class {
|
|
|
1315
1346
|
get sessionId() {
|
|
1316
1347
|
return this._sessionId;
|
|
1317
1348
|
}
|
|
1349
|
+
/**
|
|
1350
|
+
* Per-context usage (audio time + amount charged) for a closed context, or
|
|
1351
|
+
* null if that context hasn't closed yet. Each context is its own
|
|
1352
|
+
* conversation — use this to bill per conversation. See {@link SessionUsage}.
|
|
1353
|
+
*/
|
|
1354
|
+
usageFor(contextId) {
|
|
1355
|
+
return this._contextUsage.get(contextId) ?? null;
|
|
1356
|
+
}
|
|
1357
|
+
/** Map of context_id → per-context usage for all closed contexts. */
|
|
1358
|
+
get contextUsage() {
|
|
1359
|
+
return new Map(this._contextUsage);
|
|
1360
|
+
}
|
|
1318
1361
|
/**
|
|
1319
1362
|
* Connect to the multi-context WebSocket endpoint.
|
|
1320
1363
|
*
|
|
@@ -1368,12 +1411,19 @@ var MultiContextSession = class {
|
|
|
1368
1411
|
};
|
|
1369
1412
|
this.callbacks.onChunk?.(chunk);
|
|
1370
1413
|
}
|
|
1414
|
+
if (data.final && data.context_id) {
|
|
1415
|
+
this.callbacks.onFinal?.(data.context_id);
|
|
1416
|
+
}
|
|
1371
1417
|
if (data.context_closed) {
|
|
1372
1418
|
this.contexts.delete(data.context_id);
|
|
1373
|
-
this.
|
|
1419
|
+
this.requestedContexts.delete(data.context_id);
|
|
1420
|
+
const ctxUsage = parseSessionUsage(data) ?? void 0;
|
|
1421
|
+
if (ctxUsage) this._contextUsage.set(data.context_id, ctxUsage);
|
|
1422
|
+
this.callbacks.onContextClosed?.(data.context_id, ctxUsage);
|
|
1374
1423
|
}
|
|
1375
1424
|
if (data.context_timeout) {
|
|
1376
1425
|
this.contexts.delete(data.context_id);
|
|
1426
|
+
this.requestedContexts.delete(data.context_id);
|
|
1377
1427
|
this.callbacks.onContextTimeout?.(data.context_id);
|
|
1378
1428
|
}
|
|
1379
1429
|
if (data.session_closed) {
|
|
@@ -1413,6 +1463,7 @@ var MultiContextSession = class {
|
|
|
1413
1463
|
this.ws = null;
|
|
1414
1464
|
this.isStarted = false;
|
|
1415
1465
|
this.contexts.clear();
|
|
1466
|
+
this.requestedContexts.clear();
|
|
1416
1467
|
};
|
|
1417
1468
|
});
|
|
1418
1469
|
}
|
|
@@ -1423,6 +1474,7 @@ var MultiContextSession = class {
|
|
|
1423
1474
|
if (!this.ws || this.ws.readyState !== WS_OPEN) {
|
|
1424
1475
|
throw new KugelAudioError("WebSocket not connected");
|
|
1425
1476
|
}
|
|
1477
|
+
this.requestedContexts.add(contextId);
|
|
1426
1478
|
const msg = {
|
|
1427
1479
|
text: " ",
|
|
1428
1480
|
context_id: contextId
|
|
@@ -1430,23 +1482,27 @@ var MultiContextSession = class {
|
|
|
1430
1482
|
if (!this.isStarted) {
|
|
1431
1483
|
warnIfNoLanguage(this.config.language, this.config.normalize);
|
|
1432
1484
|
if (this.config.sampleRate) msg.sample_rate = this.config.sampleRate;
|
|
1485
|
+
if (this.config.outputFormat) msg.output_format = this.config.outputFormat;
|
|
1433
1486
|
if (this.config.cfgScale) msg.cfg_scale = this.config.cfgScale;
|
|
1434
1487
|
if (this.config.temperature !== void 0) msg.temperature = this.config.temperature;
|
|
1435
1488
|
if (this.config.maxNewTokens) msg.max_new_tokens = this.config.maxNewTokens;
|
|
1436
1489
|
if (this.config.normalize !== void 0) msg.normalize = this.config.normalize;
|
|
1437
1490
|
if (this.config.language) msg.language = this.config.language;
|
|
1491
|
+
if (this.config.dictionaryIds !== void 0) msg.dictionary_ids = this.config.dictionaryIds;
|
|
1438
1492
|
if (this.config.inactivityTimeout) msg.inactivity_timeout = this.config.inactivityTimeout;
|
|
1439
1493
|
}
|
|
1494
|
+
const voiceSettings = {};
|
|
1440
1495
|
const voiceId = options?.voiceId || this.config.defaultVoiceId;
|
|
1441
|
-
if (voiceId)
|
|
1496
|
+
if (voiceId) voiceSettings.voice_id = voiceId;
|
|
1442
1497
|
if (options?.voiceSettings) {
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1498
|
+
voiceSettings.stability = options.voiceSettings.stability;
|
|
1499
|
+
voiceSettings.similarity_boost = options.voiceSettings.similarityBoost;
|
|
1500
|
+
voiceSettings.style = options.voiceSettings.style;
|
|
1501
|
+
voiceSettings.use_speaker_boost = options.voiceSettings.useSpeakerBoost;
|
|
1502
|
+
voiceSettings.speed = options.voiceSettings.speed;
|
|
1503
|
+
}
|
|
1504
|
+
if (Object.keys(voiceSettings).length > 0) {
|
|
1505
|
+
msg.voice_settings = voiceSettings;
|
|
1450
1506
|
}
|
|
1451
1507
|
this.ws.send(JSON.stringify(msg));
|
|
1452
1508
|
}
|
|
@@ -1457,7 +1513,7 @@ var MultiContextSession = class {
|
|
|
1457
1513
|
if (!this.ws || this.ws.readyState !== WS_OPEN) {
|
|
1458
1514
|
throw new KugelAudioError("WebSocket not connected");
|
|
1459
1515
|
}
|
|
1460
|
-
if (!this.
|
|
1516
|
+
if (!this.requestedContexts.has(contextId) && !this.contexts.has(contextId)) {
|
|
1461
1517
|
this.createContext(contextId);
|
|
1462
1518
|
}
|
|
1463
1519
|
this.ws.send(JSON.stringify({
|
|
@@ -1515,6 +1571,7 @@ var MultiContextSession = class {
|
|
|
1515
1571
|
this.ws = null;
|
|
1516
1572
|
this.isStarted = false;
|
|
1517
1573
|
this.contexts.clear();
|
|
1574
|
+
this.requestedContexts.clear();
|
|
1518
1575
|
}
|
|
1519
1576
|
/**
|
|
1520
1577
|
* Get active context IDs.
|
|
@@ -1533,10 +1590,19 @@ var StreamingSession = class {
|
|
|
1533
1590
|
constructor(client, config, callbacks) {
|
|
1534
1591
|
this.ws = null;
|
|
1535
1592
|
this.configSent = false;
|
|
1593
|
+
this._lastUsage = null;
|
|
1536
1594
|
this.client = client;
|
|
1537
1595
|
this.config = config;
|
|
1538
1596
|
this.callbacks = callbacks;
|
|
1539
1597
|
}
|
|
1598
|
+
/**
|
|
1599
|
+
* Per-session usage from the most recently closed session, or null before
|
|
1600
|
+
* the first session closes. Use this to bill your own customers per
|
|
1601
|
+
* conversation. See {@link SessionUsage}.
|
|
1602
|
+
*/
|
|
1603
|
+
get lastUsage() {
|
|
1604
|
+
return this._lastUsage;
|
|
1605
|
+
}
|
|
1540
1606
|
/**
|
|
1541
1607
|
* Open the WebSocket connection and authenticate.
|
|
1542
1608
|
*
|
|
@@ -1600,7 +1666,15 @@ var StreamingSession = class {
|
|
|
1600
1666
|
if (data.interrupted) {
|
|
1601
1667
|
this.callbacks.onInterrupted?.();
|
|
1602
1668
|
}
|
|
1669
|
+
if (data.final) {
|
|
1670
|
+
this.callbacks.onFinal?.(
|
|
1671
|
+
data.total_audio_seconds ?? 0,
|
|
1672
|
+
data.total_text_chunks ?? 0,
|
|
1673
|
+
data.total_audio_chunks ?? 0
|
|
1674
|
+
);
|
|
1675
|
+
}
|
|
1603
1676
|
if (data.session_closed) {
|
|
1677
|
+
this._lastUsage = parseSessionUsage(data);
|
|
1604
1678
|
this.callbacks.onSessionClosed?.(
|
|
1605
1679
|
data.total_audio_seconds ?? 0,
|
|
1606
1680
|
data.total_text_chunks ?? 0,
|
|
@@ -1668,6 +1742,7 @@ var StreamingSession = class {
|
|
|
1668
1742
|
if (this.config.temperature !== void 0) msg.temperature = this.config.temperature;
|
|
1669
1743
|
if (this.config.maxNewTokens !== void 0) msg.max_new_tokens = this.config.maxNewTokens;
|
|
1670
1744
|
if (this.config.sampleRate !== void 0) msg.sample_rate = this.config.sampleRate;
|
|
1745
|
+
if (this.config.outputFormat !== void 0) msg.output_format = this.config.outputFormat;
|
|
1671
1746
|
if (this.config.flushTimeoutMs !== void 0) msg.flush_timeout_ms = this.config.flushTimeoutMs;
|
|
1672
1747
|
if (this.config.maxBufferLength !== void 0) msg.max_buffer_length = this.config.maxBufferLength;
|
|
1673
1748
|
if (this.config.normalize !== void 0) msg.normalize = this.config.normalize;
|
|
@@ -1676,6 +1751,7 @@ var StreamingSession = class {
|
|
|
1676
1751
|
if (this.config.autoMode !== void 0) msg.auto_mode = this.config.autoMode;
|
|
1677
1752
|
if (this.config.chunkLengthSchedule?.length) msg.chunk_length_schedule = this.config.chunkLengthSchedule;
|
|
1678
1753
|
if (this.config.speed !== void 0) msg.speed = this.config.speed;
|
|
1754
|
+
if (this.config.dictionaryIds !== void 0) msg.dictionary_ids = this.config.dictionaryIds;
|
|
1679
1755
|
this.configSent = true;
|
|
1680
1756
|
}
|
|
1681
1757
|
this.ws.send(JSON.stringify(msg));
|
|
@@ -2054,5 +2130,6 @@ export {
|
|
|
2054
2130
|
classifyWsHandshakeError,
|
|
2055
2131
|
createWavBlob,
|
|
2056
2132
|
createWavFile,
|
|
2057
|
-
decodePCM16
|
|
2133
|
+
decodePCM16,
|
|
2134
|
+
parseSessionUsage
|
|
2058
2135
|
};
|