@dtelecom/agents-js 0.1.14 → 0.1.16
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/dist/index.d.mts +14 -2
- package/dist/index.d.ts +14 -2
- package/dist/index.js +79 -53
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +79 -53
- package/dist/index.mjs.map +1 -1
- package/dist/memory/index.d.mts +1 -1
- package/dist/memory/index.d.ts +1 -1
- package/dist/providers/index.d.mts +85 -2
- package/dist/providers/index.d.ts +85 -2
- package/dist/providers/index.js +469 -29
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/index.mjs +467 -29
- package/dist/providers/index.mjs.map +1 -1
- package/dist/{types-BVMiP1bW.d.mts → types-MPHcuMhp.d.mts} +4 -0
- package/dist/{types-BVMiP1bW.d.ts → types-MPHcuMhp.d.ts} +4 -0
- package/package.json +1 -1
package/dist/providers/index.js
CHANGED
|
@@ -33,6 +33,8 @@ __export(providers_exports, {
|
|
|
33
33
|
CartesiaTTS: () => CartesiaTTS,
|
|
34
34
|
DeepgramSTT: () => DeepgramSTT,
|
|
35
35
|
DeepgramTTS: () => DeepgramTTS,
|
|
36
|
+
DtelecomSTT: () => DtelecomSTT,
|
|
37
|
+
DtelecomTTS: () => DtelecomTTS,
|
|
36
38
|
OpenRouterLLM: () => OpenRouterLLM
|
|
37
39
|
});
|
|
38
40
|
module.exports = __toCommonJS(providers_exports);
|
|
@@ -385,8 +387,63 @@ var OpenRouterLLM = class {
|
|
|
385
387
|
let buffer = "";
|
|
386
388
|
const structured = !!this.responseFormat;
|
|
387
389
|
let jsonBuffer = "";
|
|
388
|
-
let
|
|
389
|
-
|
|
390
|
+
let segmentsYielded = false;
|
|
391
|
+
let lastUsage;
|
|
392
|
+
let inSegmentsArray = false;
|
|
393
|
+
let objectStart = -1;
|
|
394
|
+
let braceDepth = 0;
|
|
395
|
+
let scanIndex = 0;
|
|
396
|
+
let inString = false;
|
|
397
|
+
let escaped = false;
|
|
398
|
+
function extractSegments(buf) {
|
|
399
|
+
const results = [];
|
|
400
|
+
for (let i = scanIndex; i < buf.length; i++) {
|
|
401
|
+
const ch = buf[i];
|
|
402
|
+
if (escaped) {
|
|
403
|
+
escaped = false;
|
|
404
|
+
continue;
|
|
405
|
+
}
|
|
406
|
+
if (ch === "\\" && inString) {
|
|
407
|
+
escaped = true;
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
410
|
+
if (ch === '"') {
|
|
411
|
+
inString = !inString;
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
414
|
+
if (inString) continue;
|
|
415
|
+
if (!inSegmentsArray) {
|
|
416
|
+
if (ch === "[") {
|
|
417
|
+
const before = buf.slice(0, i).trimEnd();
|
|
418
|
+
if (before.endsWith(":") && buf.slice(0, i).includes('"segments"')) {
|
|
419
|
+
inSegmentsArray = true;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
continue;
|
|
423
|
+
}
|
|
424
|
+
if (ch === "{") {
|
|
425
|
+
if (braceDepth === 0) objectStart = i;
|
|
426
|
+
braceDepth++;
|
|
427
|
+
} else if (ch === "}") {
|
|
428
|
+
braceDepth--;
|
|
429
|
+
if (braceDepth === 0 && objectStart >= 0) {
|
|
430
|
+
const objStr = buf.slice(objectStart, i + 1);
|
|
431
|
+
try {
|
|
432
|
+
const seg = JSON.parse(objStr);
|
|
433
|
+
if (seg.lang && seg.text) {
|
|
434
|
+
results.push({ lang: seg.lang, text: seg.text });
|
|
435
|
+
}
|
|
436
|
+
} catch {
|
|
437
|
+
}
|
|
438
|
+
objectStart = -1;
|
|
439
|
+
}
|
|
440
|
+
} else if (ch === "]" && braceDepth === 0) {
|
|
441
|
+
inSegmentsArray = false;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
scanIndex = buf.length;
|
|
445
|
+
return results;
|
|
446
|
+
}
|
|
390
447
|
try {
|
|
391
448
|
while (true) {
|
|
392
449
|
if (signal?.aborted) break;
|
|
@@ -399,10 +456,7 @@ var OpenRouterLLM = class {
|
|
|
399
456
|
const trimmed = line.trim();
|
|
400
457
|
if (!trimmed || !trimmed.startsWith("data: ")) continue;
|
|
401
458
|
const data = trimmed.slice(6);
|
|
402
|
-
if (data === "[DONE]")
|
|
403
|
-
yield { type: "done" };
|
|
404
|
-
return;
|
|
405
|
-
}
|
|
459
|
+
if (data === "[DONE]") break;
|
|
406
460
|
try {
|
|
407
461
|
const parsed = JSON.parse(data);
|
|
408
462
|
const choice = parsed.choices?.[0];
|
|
@@ -411,31 +465,20 @@ var OpenRouterLLM = class {
|
|
|
411
465
|
if (delta?.content) {
|
|
412
466
|
if (structured) {
|
|
413
467
|
jsonBuffer += delta.content;
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
const text = match[2].replace(/\\(.)/g, (_, c) => {
|
|
419
|
-
if (c === "n") return "\n";
|
|
420
|
-
if (c === "t") return " ";
|
|
421
|
-
return c;
|
|
422
|
-
});
|
|
423
|
-
lastSegmentIndex = segmentRe.lastIndex;
|
|
424
|
-
yield { type: "segment", segment: { lang, text } };
|
|
468
|
+
const segments = extractSegments(jsonBuffer);
|
|
469
|
+
for (const seg of segments) {
|
|
470
|
+
yield { type: "segment", segment: seg };
|
|
471
|
+
segmentsYielded = true;
|
|
425
472
|
}
|
|
426
473
|
} else {
|
|
427
474
|
yield { type: "token", token: delta.content };
|
|
428
475
|
}
|
|
429
476
|
}
|
|
430
477
|
if (parsed.usage) {
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
promptTokens: parsed.usage.prompt_tokens,
|
|
435
|
-
completionTokens: parsed.usage.completion_tokens
|
|
436
|
-
}
|
|
478
|
+
lastUsage = {
|
|
479
|
+
promptTokens: parsed.usage.prompt_tokens,
|
|
480
|
+
completionTokens: parsed.usage.completion_tokens
|
|
437
481
|
};
|
|
438
|
-
return;
|
|
439
482
|
}
|
|
440
483
|
} catch {
|
|
441
484
|
}
|
|
@@ -444,10 +487,10 @@ var OpenRouterLLM = class {
|
|
|
444
487
|
} finally {
|
|
445
488
|
reader.releaseLock();
|
|
446
489
|
}
|
|
447
|
-
if (structured &&
|
|
448
|
-
log2.warn(`
|
|
490
|
+
if (structured && !segmentsYielded && jsonBuffer.length > 0) {
|
|
491
|
+
log2.warn(`LLM returned no segments. Raw JSON: "${jsonBuffer.slice(0, 300)}"`);
|
|
449
492
|
}
|
|
450
|
-
yield { type: "done" };
|
|
493
|
+
yield { type: "done", ...lastUsage ? { usage: lastUsage } : {} };
|
|
451
494
|
}
|
|
452
495
|
};
|
|
453
496
|
|
|
@@ -770,13 +813,21 @@ var DeepgramTTS = class {
|
|
|
770
813
|
}
|
|
771
814
|
async *synthesize(text, signal) {
|
|
772
815
|
if (signal?.aborted) return;
|
|
773
|
-
const
|
|
816
|
+
const rawSegments = this.multiLanguage ? parseLangSegments(text, this.defaultLang) : [{ lang: this.defaultLang, text }];
|
|
817
|
+
const segments = [];
|
|
818
|
+
for (const seg of rawSegments) {
|
|
819
|
+
if (!seg.text.trim()) continue;
|
|
820
|
+
if (!/\p{L}/u.test(seg.text) && segments.length > 0) {
|
|
821
|
+
segments[segments.length - 1].text += seg.text;
|
|
822
|
+
} else {
|
|
823
|
+
segments.push(seg);
|
|
824
|
+
}
|
|
825
|
+
}
|
|
774
826
|
const silenceBytes = Math.round(this.sampleRate * 0.2) * 2;
|
|
775
827
|
const silence = Buffer.alloc(silenceBytes);
|
|
776
828
|
let prevLang = null;
|
|
777
829
|
for (const segment of segments) {
|
|
778
830
|
if (signal?.aborted) break;
|
|
779
|
-
if (!segment.text.trim()) continue;
|
|
780
831
|
const lang = this.models[segment.lang] ? segment.lang : this.defaultLang;
|
|
781
832
|
if (prevLang !== null && lang !== prevLang) {
|
|
782
833
|
yield silence;
|
|
@@ -904,11 +955,400 @@ var DeepgramTTS = class {
|
|
|
904
955
|
return promise;
|
|
905
956
|
}
|
|
906
957
|
};
|
|
958
|
+
|
|
959
|
+
// src/providers/dtelecom-stt.ts
|
|
960
|
+
var import_ws4 = __toESM(require("ws"));
|
|
961
|
+
var log5 = createLogger("DtelecomSTT");
|
|
962
|
+
var KEEPALIVE_INTERVAL_MS2 = 5e3;
|
|
963
|
+
var DtelecomSTT = class {
|
|
964
|
+
options;
|
|
965
|
+
constructor(options) {
|
|
966
|
+
if (!options.serverUrl) {
|
|
967
|
+
throw new Error("DtelecomSTT requires a serverUrl");
|
|
968
|
+
}
|
|
969
|
+
this.options = options;
|
|
970
|
+
}
|
|
971
|
+
createStream(options) {
|
|
972
|
+
const language = options?.language ?? this.options.language ?? "auto";
|
|
973
|
+
return new DtelecomSTTStream(this.options, language);
|
|
974
|
+
}
|
|
975
|
+
};
|
|
976
|
+
var DtelecomSTTStream = class extends BaseSTTStream {
|
|
977
|
+
ws = null;
|
|
978
|
+
serverUrl;
|
|
979
|
+
forceWhisper;
|
|
980
|
+
_ready = false;
|
|
981
|
+
_closed = false;
|
|
982
|
+
pendingAudio = [];
|
|
983
|
+
keepAliveTimer = null;
|
|
984
|
+
language;
|
|
985
|
+
constructor(options, language) {
|
|
986
|
+
super();
|
|
987
|
+
this.serverUrl = options.serverUrl;
|
|
988
|
+
this.language = language;
|
|
989
|
+
this.forceWhisper = options.forceWhisper ?? false;
|
|
990
|
+
this.connect();
|
|
991
|
+
}
|
|
992
|
+
sendAudio(pcm16) {
|
|
993
|
+
if (this._closed) return;
|
|
994
|
+
if (!this._ready) {
|
|
995
|
+
this.pendingAudio.push(pcm16);
|
|
996
|
+
return;
|
|
997
|
+
}
|
|
998
|
+
if (this.ws?.readyState === import_ws4.default.OPEN) {
|
|
999
|
+
this.ws.send(pcm16);
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
/**
|
|
1003
|
+
* Switch language mid-session.
|
|
1004
|
+
* Sends a reconfigure message to the server; clears buffers and updates model routing.
|
|
1005
|
+
*/
|
|
1006
|
+
setLanguage(language, options) {
|
|
1007
|
+
if (this._closed) return;
|
|
1008
|
+
this.language = language;
|
|
1009
|
+
const config = { type: "config", language };
|
|
1010
|
+
if (options?.forceWhisper) {
|
|
1011
|
+
config.model = "whisper";
|
|
1012
|
+
}
|
|
1013
|
+
if (this.ws?.readyState === import_ws4.default.OPEN) {
|
|
1014
|
+
this.ws.send(JSON.stringify(config));
|
|
1015
|
+
log5.info(`Reconfiguring STT: language=${language}${options?.forceWhisper ? ", model=whisper" : ""}`);
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
async close() {
|
|
1019
|
+
if (this._closed) return;
|
|
1020
|
+
this._closed = true;
|
|
1021
|
+
this._ready = false;
|
|
1022
|
+
this.pendingAudio = [];
|
|
1023
|
+
this.stopKeepAlive();
|
|
1024
|
+
if (this.ws) {
|
|
1025
|
+
this.ws.close();
|
|
1026
|
+
this.ws = null;
|
|
1027
|
+
}
|
|
1028
|
+
log5.debug("DtelecomSTT stream closed");
|
|
1029
|
+
}
|
|
1030
|
+
connect() {
|
|
1031
|
+
log5.debug(`Connecting to dTelecom STT: ${this.serverUrl}`);
|
|
1032
|
+
this.ws = new import_ws4.default(this.serverUrl);
|
|
1033
|
+
this.ws.on("open", () => {
|
|
1034
|
+
log5.info("dTelecom STT WebSocket connected");
|
|
1035
|
+
const config = { type: "config", language: this.language };
|
|
1036
|
+
if (this.forceWhisper) {
|
|
1037
|
+
config.model = "whisper";
|
|
1038
|
+
}
|
|
1039
|
+
this.ws.send(JSON.stringify(config));
|
|
1040
|
+
});
|
|
1041
|
+
this.ws.on("message", (data, isBinary) => {
|
|
1042
|
+
if (isBinary) return;
|
|
1043
|
+
try {
|
|
1044
|
+
const msg = JSON.parse(data.toString());
|
|
1045
|
+
this.handleMessage(msg);
|
|
1046
|
+
} catch (err) {
|
|
1047
|
+
log5.error("Failed to parse dTelecom STT message:", err);
|
|
1048
|
+
}
|
|
1049
|
+
});
|
|
1050
|
+
this.ws.on("error", (err) => {
|
|
1051
|
+
log5.error("dTelecom STT WebSocket error:", err);
|
|
1052
|
+
this.emit("error", err instanceof Error ? err : new Error(String(err)));
|
|
1053
|
+
});
|
|
1054
|
+
this.ws.on("close", (code, reason) => {
|
|
1055
|
+
log5.debug(`dTelecom STT WebSocket closed: ${code} ${reason.toString()}`);
|
|
1056
|
+
this._ready = false;
|
|
1057
|
+
this.stopKeepAlive();
|
|
1058
|
+
if (!this._closed) {
|
|
1059
|
+
log5.info("dTelecom STT connection lost, reconnecting in 1s...");
|
|
1060
|
+
setTimeout(() => {
|
|
1061
|
+
if (!this._closed) this.connect();
|
|
1062
|
+
}, 1e3);
|
|
1063
|
+
}
|
|
1064
|
+
});
|
|
1065
|
+
}
|
|
1066
|
+
handleMessage(msg) {
|
|
1067
|
+
const type = msg.type;
|
|
1068
|
+
if (type === "ready") {
|
|
1069
|
+
this.handleReady(msg);
|
|
1070
|
+
} else if (type === "transcription") {
|
|
1071
|
+
this.handleTranscription(msg);
|
|
1072
|
+
} else if (type === "vad_event") {
|
|
1073
|
+
this.handleVadEvent(msg);
|
|
1074
|
+
} else if (type === "pong") {
|
|
1075
|
+
} else if (type === "error") {
|
|
1076
|
+
const errData = msg.error;
|
|
1077
|
+
const errorMsg = msg.message || (typeof errData === "string" ? errData : JSON.stringify(errData)) || "Unknown STT error";
|
|
1078
|
+
log5.error(`dTelecom STT error: ${errorMsg}`);
|
|
1079
|
+
this.emit("error", new Error(errorMsg));
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
handleReady(msg) {
|
|
1083
|
+
const clientId = msg.client_id;
|
|
1084
|
+
const lang = msg.language;
|
|
1085
|
+
log5.info(`dTelecom STT ready: client_id=${clientId}, language=${lang}`);
|
|
1086
|
+
this._ready = true;
|
|
1087
|
+
for (const buf of this.pendingAudio) {
|
|
1088
|
+
if (this.ws?.readyState === import_ws4.default.OPEN) {
|
|
1089
|
+
this.ws.send(buf);
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
this.pendingAudio = [];
|
|
1093
|
+
this.startKeepAlive();
|
|
1094
|
+
}
|
|
1095
|
+
handleTranscription(msg) {
|
|
1096
|
+
const text = msg.text ?? "";
|
|
1097
|
+
const isFinal = msg.is_final ?? false;
|
|
1098
|
+
const language = msg.language;
|
|
1099
|
+
const latencyMs = msg.latency_ms;
|
|
1100
|
+
if (!text) return;
|
|
1101
|
+
if (isFinal && latencyMs !== void 0) {
|
|
1102
|
+
log5.info(`stt_final: ${latencyMs.toFixed(0)}ms "${text.slice(0, 50)}"`);
|
|
1103
|
+
}
|
|
1104
|
+
this.emit("transcription", {
|
|
1105
|
+
text,
|
|
1106
|
+
isFinal,
|
|
1107
|
+
language,
|
|
1108
|
+
sttDuration: isFinal ? latencyMs : void 0
|
|
1109
|
+
});
|
|
1110
|
+
}
|
|
1111
|
+
handleVadEvent(msg) {
|
|
1112
|
+
const event = msg.event;
|
|
1113
|
+
log5.debug(`VAD event: ${event}`);
|
|
1114
|
+
if (event === "speech_start") {
|
|
1115
|
+
this.emit("transcription", {
|
|
1116
|
+
text: "",
|
|
1117
|
+
isFinal: false
|
|
1118
|
+
});
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
startKeepAlive() {
|
|
1122
|
+
this.stopKeepAlive();
|
|
1123
|
+
this.keepAliveTimer = setInterval(() => {
|
|
1124
|
+
if (this.ws?.readyState === import_ws4.default.OPEN) {
|
|
1125
|
+
this.ws.send(JSON.stringify({ type: "ping" }));
|
|
1126
|
+
}
|
|
1127
|
+
}, KEEPALIVE_INTERVAL_MS2);
|
|
1128
|
+
}
|
|
1129
|
+
stopKeepAlive() {
|
|
1130
|
+
if (this.keepAliveTimer) {
|
|
1131
|
+
clearInterval(this.keepAliveTimer);
|
|
1132
|
+
this.keepAliveTimer = null;
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
};
|
|
1136
|
+
|
|
1137
|
+
// src/providers/dtelecom-tts.ts
|
|
1138
|
+
var import_ws5 = __toESM(require("ws"));
|
|
1139
|
+
var log6 = createLogger("DtelecomTTS");
|
|
1140
|
+
var DtelecomTTS = class {
|
|
1141
|
+
serverUrl;
|
|
1142
|
+
voices;
|
|
1143
|
+
defaultLang;
|
|
1144
|
+
speed;
|
|
1145
|
+
ws = null;
|
|
1146
|
+
connectPromise = null;
|
|
1147
|
+
flushState = null;
|
|
1148
|
+
/** Default language code for untagged text (e.g. 'en'). */
|
|
1149
|
+
get defaultLanguage() {
|
|
1150
|
+
return this.defaultLang;
|
|
1151
|
+
}
|
|
1152
|
+
constructor(options) {
|
|
1153
|
+
if (!options.serverUrl) {
|
|
1154
|
+
throw new Error("DtelecomTTS requires a serverUrl");
|
|
1155
|
+
}
|
|
1156
|
+
if (!options.voices || Object.keys(options.voices).length === 0) {
|
|
1157
|
+
throw new Error("DtelecomTTS requires at least one voice config");
|
|
1158
|
+
}
|
|
1159
|
+
this.serverUrl = options.serverUrl;
|
|
1160
|
+
this.voices = { ...options.voices };
|
|
1161
|
+
this.defaultLang = options.defaultLanguage ?? Object.keys(this.voices)[0];
|
|
1162
|
+
this.speed = options.speed ?? 1;
|
|
1163
|
+
}
|
|
1164
|
+
/** Pre-connect WebSocket to TTS server. */
|
|
1165
|
+
async warmup() {
|
|
1166
|
+
log6.info("Warming up TTS connection...");
|
|
1167
|
+
const start = performance.now();
|
|
1168
|
+
try {
|
|
1169
|
+
await this.ensureConnection();
|
|
1170
|
+
log6.info(`TTS warmup complete in ${(performance.now() - start).toFixed(0)}ms`);
|
|
1171
|
+
} catch (err) {
|
|
1172
|
+
log6.warn("TTS warmup failed (non-fatal):", err);
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
/** Close WebSocket connection. */
|
|
1176
|
+
close() {
|
|
1177
|
+
if (this.ws) {
|
|
1178
|
+
log6.debug("Closing TTS WebSocket");
|
|
1179
|
+
this.ws.close();
|
|
1180
|
+
this.ws = null;
|
|
1181
|
+
}
|
|
1182
|
+
this.connectPromise = null;
|
|
1183
|
+
this.flushState = null;
|
|
1184
|
+
}
|
|
1185
|
+
/** Strip SSML lang tags from text for display/events. */
|
|
1186
|
+
cleanText(text) {
|
|
1187
|
+
return parseLangSegments(text, this.defaultLang).map((s) => s.text).join(" ").replace(/\s+/g, " ").trim();
|
|
1188
|
+
}
|
|
1189
|
+
async *synthesize(text, signal) {
|
|
1190
|
+
if (signal?.aborted) return;
|
|
1191
|
+
const rawSegments = parseLangSegments(text, this.defaultLang);
|
|
1192
|
+
const segments = [];
|
|
1193
|
+
for (const seg of rawSegments) {
|
|
1194
|
+
if (!seg.text.trim()) continue;
|
|
1195
|
+
if (!/\p{L}/u.test(seg.text) && segments.length > 0) {
|
|
1196
|
+
segments[segments.length - 1].text += seg.text;
|
|
1197
|
+
} else {
|
|
1198
|
+
segments.push(seg);
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
const silenceBytes = Math.round(48e3 * 0.2) * 2;
|
|
1202
|
+
const silence = Buffer.alloc(silenceBytes);
|
|
1203
|
+
let prevLang = null;
|
|
1204
|
+
for (const segment of segments) {
|
|
1205
|
+
if (signal?.aborted) break;
|
|
1206
|
+
const lang = this.voices[segment.lang] ? segment.lang : this.defaultLang;
|
|
1207
|
+
if (prevLang !== null && lang !== prevLang) {
|
|
1208
|
+
yield silence;
|
|
1209
|
+
}
|
|
1210
|
+
prevLang = lang;
|
|
1211
|
+
yield* this.synthesizeSegment(lang, segment.text, signal);
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
async *synthesizeSegment(lang, text, signal) {
|
|
1215
|
+
await this.ensureConnection();
|
|
1216
|
+
const ws = this.ws;
|
|
1217
|
+
if (!ws || ws.readyState !== import_ws5.default.OPEN) {
|
|
1218
|
+
throw new Error("dTelecom TTS WebSocket not connected");
|
|
1219
|
+
}
|
|
1220
|
+
const state = { chunks: [], done: false, cleared: false, error: null, wake: null };
|
|
1221
|
+
this.flushState = state;
|
|
1222
|
+
const onAbort = () => {
|
|
1223
|
+
state.done = true;
|
|
1224
|
+
state.wake?.();
|
|
1225
|
+
if (ws.readyState === import_ws5.default.OPEN) {
|
|
1226
|
+
try {
|
|
1227
|
+
ws.send(JSON.stringify({ type: "clear" }));
|
|
1228
|
+
} catch {
|
|
1229
|
+
}
|
|
1230
|
+
}
|
|
1231
|
+
};
|
|
1232
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
1233
|
+
const voiceConfig = this.voices[lang];
|
|
1234
|
+
const msg = { text };
|
|
1235
|
+
if (voiceConfig) {
|
|
1236
|
+
msg.voice = voiceConfig.voice;
|
|
1237
|
+
msg.lang_code = voiceConfig.langCode;
|
|
1238
|
+
msg.speed = this.speed;
|
|
1239
|
+
}
|
|
1240
|
+
log6.info(`TTS send [${lang}]: voice=${voiceConfig?.voice ?? "default"} lang_code=${voiceConfig?.langCode ?? "default"} "${text.slice(0, 60)}"`);
|
|
1241
|
+
ws.send(JSON.stringify(msg));
|
|
1242
|
+
try {
|
|
1243
|
+
while (true) {
|
|
1244
|
+
if (signal?.aborted) break;
|
|
1245
|
+
if (state.error) throw state.error;
|
|
1246
|
+
if (state.chunks.length > 0) {
|
|
1247
|
+
yield state.chunks.shift();
|
|
1248
|
+
continue;
|
|
1249
|
+
}
|
|
1250
|
+
if (state.done) break;
|
|
1251
|
+
await new Promise((resolve) => {
|
|
1252
|
+
state.wake = resolve;
|
|
1253
|
+
});
|
|
1254
|
+
state.wake = null;
|
|
1255
|
+
}
|
|
1256
|
+
while (state.chunks.length > 0) {
|
|
1257
|
+
yield state.chunks.shift();
|
|
1258
|
+
}
|
|
1259
|
+
} finally {
|
|
1260
|
+
signal?.removeEventListener("abort", onAbort);
|
|
1261
|
+
this.flushState = null;
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
/** Ensure a WebSocket connection exists and is open. */
|
|
1265
|
+
ensureConnection() {
|
|
1266
|
+
if (this.ws && this.ws.readyState === import_ws5.default.OPEN) {
|
|
1267
|
+
return Promise.resolve();
|
|
1268
|
+
}
|
|
1269
|
+
if (this.connectPromise) return this.connectPromise;
|
|
1270
|
+
this.connectPromise = new Promise((resolve, reject) => {
|
|
1271
|
+
log6.debug(`Connecting to dTelecom TTS: ${this.serverUrl}`);
|
|
1272
|
+
const ws = new import_ws5.default(this.serverUrl);
|
|
1273
|
+
ws.on("open", () => {
|
|
1274
|
+
this.ws = ws;
|
|
1275
|
+
this.connectPromise = null;
|
|
1276
|
+
const defaultVoice = this.voices[this.defaultLang];
|
|
1277
|
+
if (defaultVoice) {
|
|
1278
|
+
ws.send(JSON.stringify({
|
|
1279
|
+
config: {
|
|
1280
|
+
voice: defaultVoice.voice,
|
|
1281
|
+
lang_code: defaultVoice.langCode,
|
|
1282
|
+
speed: this.speed
|
|
1283
|
+
}
|
|
1284
|
+
}));
|
|
1285
|
+
}
|
|
1286
|
+
log6.info("dTelecom TTS WebSocket connected");
|
|
1287
|
+
resolve();
|
|
1288
|
+
});
|
|
1289
|
+
ws.on("message", (data, isBinary) => {
|
|
1290
|
+
const state = this.flushState;
|
|
1291
|
+
if (!state) return;
|
|
1292
|
+
if (isBinary) {
|
|
1293
|
+
const buf = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
1294
|
+
state.chunks.push(buf);
|
|
1295
|
+
state.wake?.();
|
|
1296
|
+
} else {
|
|
1297
|
+
try {
|
|
1298
|
+
const msg = JSON.parse(data.toString());
|
|
1299
|
+
if (msg.type === "done") {
|
|
1300
|
+
state.done = true;
|
|
1301
|
+
state.wake?.();
|
|
1302
|
+
} else if (msg.type === "cleared") {
|
|
1303
|
+
state.cleared = true;
|
|
1304
|
+
state.done = true;
|
|
1305
|
+
state.wake?.();
|
|
1306
|
+
} else if (msg.type === "generating") {
|
|
1307
|
+
log6.debug(`TTS generating: "${msg.text?.slice(0, 40)}"`);
|
|
1308
|
+
} else if (msg.type === "error") {
|
|
1309
|
+
const errorMsg = msg.message || "Unknown TTS error";
|
|
1310
|
+
log6.error(`dTelecom TTS error: ${errorMsg}`);
|
|
1311
|
+
state.error = new Error(errorMsg);
|
|
1312
|
+
state.wake?.();
|
|
1313
|
+
}
|
|
1314
|
+
} catch {
|
|
1315
|
+
log6.warn("Failed to parse dTelecom TTS message");
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
});
|
|
1319
|
+
ws.on("error", (err) => {
|
|
1320
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
1321
|
+
log6.error("dTelecom TTS WebSocket error:", error);
|
|
1322
|
+
const state = this.flushState;
|
|
1323
|
+
if (state) {
|
|
1324
|
+
state.error = error;
|
|
1325
|
+
state.wake?.();
|
|
1326
|
+
}
|
|
1327
|
+
this.ws = null;
|
|
1328
|
+
this.connectPromise = null;
|
|
1329
|
+
reject(error);
|
|
1330
|
+
});
|
|
1331
|
+
ws.on("close", (code, reason) => {
|
|
1332
|
+
log6.debug(`dTelecom TTS WebSocket closed: ${code} ${reason.toString()}`);
|
|
1333
|
+
this.ws = null;
|
|
1334
|
+
this.connectPromise = null;
|
|
1335
|
+
const state = this.flushState;
|
|
1336
|
+
if (state) {
|
|
1337
|
+
state.done = true;
|
|
1338
|
+
state.wake?.();
|
|
1339
|
+
}
|
|
1340
|
+
});
|
|
1341
|
+
});
|
|
1342
|
+
return this.connectPromise;
|
|
1343
|
+
}
|
|
1344
|
+
};
|
|
907
1345
|
// Annotate the CommonJS export names for ESM import in node:
|
|
908
1346
|
0 && (module.exports = {
|
|
909
1347
|
CartesiaTTS,
|
|
910
1348
|
DeepgramSTT,
|
|
911
1349
|
DeepgramTTS,
|
|
1350
|
+
DtelecomSTT,
|
|
1351
|
+
DtelecomTTS,
|
|
912
1352
|
OpenRouterLLM
|
|
913
1353
|
});
|
|
914
1354
|
//# sourceMappingURL=index.js.map
|