@dtelecom/agents-js 0.2.0 → 0.2.2
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 +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +90 -36
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +90 -36
- package/dist/index.mjs.map +1 -1
- package/dist/providers/index.d.mts +41 -1
- package/dist/providers/index.d.ts +41 -1
- package/dist/providers/index.js +242 -51
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/index.mjs +241 -51
- package/dist/providers/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/providers/index.mjs
CHANGED
|
@@ -403,9 +403,198 @@ var OpenRouterLLM = class {
|
|
|
403
403
|
}
|
|
404
404
|
};
|
|
405
405
|
|
|
406
|
+
// src/providers/openai-llm.ts
|
|
407
|
+
var log3 = createLogger("OpenAILLM");
|
|
408
|
+
var OPENAI_URL = "https://api.openai.com/v1/chat/completions";
|
|
409
|
+
var OpenAILLM = class {
|
|
410
|
+
apiKey;
|
|
411
|
+
model;
|
|
412
|
+
maxTokens;
|
|
413
|
+
temperature;
|
|
414
|
+
responseFormat;
|
|
415
|
+
constructor(options) {
|
|
416
|
+
if (!options.apiKey) {
|
|
417
|
+
throw new Error("OpenAILLM requires an apiKey");
|
|
418
|
+
}
|
|
419
|
+
this.apiKey = options.apiKey;
|
|
420
|
+
this.model = options.model;
|
|
421
|
+
this.maxTokens = options.maxTokens ?? 512;
|
|
422
|
+
this.temperature = options.temperature ?? 0.7;
|
|
423
|
+
this.responseFormat = options.responseFormat;
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* Warm up the LLM by sending the system prompt and a short message.
|
|
427
|
+
* Primes the HTTP/TLS connection and model loading on the provider side.
|
|
428
|
+
*/
|
|
429
|
+
async warmup(systemPrompt) {
|
|
430
|
+
log3.info("Warming up LLM connection...");
|
|
431
|
+
const start = performance.now();
|
|
432
|
+
const messages = [
|
|
433
|
+
{ role: "system", content: systemPrompt },
|
|
434
|
+
{ role: "user", content: "Hello" }
|
|
435
|
+
];
|
|
436
|
+
try {
|
|
437
|
+
const gen = this.chat(messages);
|
|
438
|
+
for await (const chunk of gen) {
|
|
439
|
+
if (chunk.type === "done") break;
|
|
440
|
+
}
|
|
441
|
+
log3.info(`LLM warmup complete in ${(performance.now() - start).toFixed(0)}ms`);
|
|
442
|
+
} catch (err) {
|
|
443
|
+
log3.warn("LLM warmup failed (non-fatal):", err);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
async *chat(messages, signal, options) {
|
|
447
|
+
const body = {
|
|
448
|
+
model: this.model,
|
|
449
|
+
messages,
|
|
450
|
+
max_tokens: this.maxTokens,
|
|
451
|
+
temperature: this.temperature,
|
|
452
|
+
stream: true,
|
|
453
|
+
stream_options: { include_usage: true }
|
|
454
|
+
};
|
|
455
|
+
if (this.responseFormat && !options?.plainText) {
|
|
456
|
+
body.response_format = this.responseFormat;
|
|
457
|
+
}
|
|
458
|
+
log3.debug(`LLM request: model=${this.model}, messages=${messages.length}`);
|
|
459
|
+
const response = await fetch(OPENAI_URL, {
|
|
460
|
+
method: "POST",
|
|
461
|
+
headers: {
|
|
462
|
+
"Content-Type": "application/json",
|
|
463
|
+
"Authorization": `Bearer ${this.apiKey}`
|
|
464
|
+
},
|
|
465
|
+
body: JSON.stringify(body),
|
|
466
|
+
signal
|
|
467
|
+
});
|
|
468
|
+
if (!response.ok) {
|
|
469
|
+
const errorText = await response.text();
|
|
470
|
+
throw new Error(`OpenAI API error ${response.status}: ${errorText}`);
|
|
471
|
+
}
|
|
472
|
+
if (!response.body) {
|
|
473
|
+
throw new Error("OpenAI response has no body");
|
|
474
|
+
}
|
|
475
|
+
const reader = response.body.getReader();
|
|
476
|
+
const decoder = new TextDecoder();
|
|
477
|
+
let buffer = "";
|
|
478
|
+
const structured = !!this.responseFormat && !options?.plainText;
|
|
479
|
+
let jsonBuffer = "";
|
|
480
|
+
let segmentsYielded = false;
|
|
481
|
+
let lastUsage;
|
|
482
|
+
let inSegmentsArray = false;
|
|
483
|
+
let objectStart = -1;
|
|
484
|
+
let braceDepth = 0;
|
|
485
|
+
let scanIndex = 0;
|
|
486
|
+
let inString = false;
|
|
487
|
+
let escaped = false;
|
|
488
|
+
function extractSegments(buf) {
|
|
489
|
+
const results = [];
|
|
490
|
+
for (let i = scanIndex; i < buf.length; i++) {
|
|
491
|
+
const ch = buf[i];
|
|
492
|
+
if (escaped) {
|
|
493
|
+
escaped = false;
|
|
494
|
+
continue;
|
|
495
|
+
}
|
|
496
|
+
if (ch === "\\" && inString) {
|
|
497
|
+
escaped = true;
|
|
498
|
+
continue;
|
|
499
|
+
}
|
|
500
|
+
if (ch === '"') {
|
|
501
|
+
inString = !inString;
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
504
|
+
if (inString) continue;
|
|
505
|
+
if (!inSegmentsArray) {
|
|
506
|
+
if (ch === "[") {
|
|
507
|
+
const before = buf.slice(0, i).trimEnd();
|
|
508
|
+
if (before.endsWith(":") && buf.slice(0, i).includes('"segments"')) {
|
|
509
|
+
inSegmentsArray = true;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
continue;
|
|
513
|
+
}
|
|
514
|
+
if (ch === "{") {
|
|
515
|
+
if (braceDepth === 0) objectStart = i;
|
|
516
|
+
braceDepth++;
|
|
517
|
+
} else if (ch === "}") {
|
|
518
|
+
braceDepth--;
|
|
519
|
+
if (braceDepth === 0 && objectStart >= 0) {
|
|
520
|
+
const objStr = buf.slice(objectStart, i + 1);
|
|
521
|
+
try {
|
|
522
|
+
const seg = JSON.parse(objStr);
|
|
523
|
+
if (seg.lang && seg.text) {
|
|
524
|
+
results.push({ lang: seg.lang, text: seg.text });
|
|
525
|
+
}
|
|
526
|
+
} catch {
|
|
527
|
+
}
|
|
528
|
+
objectStart = -1;
|
|
529
|
+
}
|
|
530
|
+
} else if (ch === "]" && braceDepth === 0) {
|
|
531
|
+
inSegmentsArray = false;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
scanIndex = buf.length;
|
|
535
|
+
return results;
|
|
536
|
+
}
|
|
537
|
+
try {
|
|
538
|
+
while (true) {
|
|
539
|
+
if (signal?.aborted) break;
|
|
540
|
+
const { done, value } = await reader.read();
|
|
541
|
+
if (done) break;
|
|
542
|
+
buffer += decoder.decode(value, { stream: true });
|
|
543
|
+
const lines = buffer.split("\n");
|
|
544
|
+
buffer = lines.pop() ?? "";
|
|
545
|
+
for (const line of lines) {
|
|
546
|
+
const trimmed = line.trim();
|
|
547
|
+
if (!trimmed || !trimmed.startsWith("data: ")) continue;
|
|
548
|
+
const data = trimmed.slice(6);
|
|
549
|
+
if (data === "[DONE]") break;
|
|
550
|
+
try {
|
|
551
|
+
const parsed = JSON.parse(data);
|
|
552
|
+
const choice = parsed.choices?.[0];
|
|
553
|
+
if (!choice) {
|
|
554
|
+
if (parsed.usage) {
|
|
555
|
+
lastUsage = {
|
|
556
|
+
promptTokens: parsed.usage.prompt_tokens,
|
|
557
|
+
completionTokens: parsed.usage.completion_tokens
|
|
558
|
+
};
|
|
559
|
+
}
|
|
560
|
+
continue;
|
|
561
|
+
}
|
|
562
|
+
const delta = choice.delta;
|
|
563
|
+
if (delta?.content) {
|
|
564
|
+
if (structured) {
|
|
565
|
+
jsonBuffer += delta.content;
|
|
566
|
+
const segments = extractSegments(jsonBuffer);
|
|
567
|
+
for (const seg of segments) {
|
|
568
|
+
yield { type: "segment", segment: seg };
|
|
569
|
+
segmentsYielded = true;
|
|
570
|
+
}
|
|
571
|
+
} else {
|
|
572
|
+
yield { type: "token", token: delta.content };
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
if (parsed.usage) {
|
|
576
|
+
lastUsage = {
|
|
577
|
+
promptTokens: parsed.usage.prompt_tokens,
|
|
578
|
+
completionTokens: parsed.usage.completion_tokens
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
} catch {
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
} finally {
|
|
586
|
+
reader.releaseLock();
|
|
587
|
+
}
|
|
588
|
+
if (structured && !segmentsYielded && jsonBuffer.length > 0) {
|
|
589
|
+
log3.warn(`LLM returned no segments. Raw JSON: "${jsonBuffer.slice(0, 300)}"`);
|
|
590
|
+
}
|
|
591
|
+
yield { type: "done", ...lastUsage ? { usage: lastUsage } : {} };
|
|
592
|
+
}
|
|
593
|
+
};
|
|
594
|
+
|
|
406
595
|
// src/providers/cartesia-tts.ts
|
|
407
596
|
import WebSocket2 from "ws";
|
|
408
|
-
var
|
|
597
|
+
var log4 = createLogger("CartesiaTTS");
|
|
409
598
|
var CARTESIA_WS_BASE = "wss://api.cartesia.ai/tts/websocket";
|
|
410
599
|
var DEFAULT_API_VERSION = "2024-06-10";
|
|
411
600
|
var DEFAULT_MODEL = "sonic-3";
|
|
@@ -444,7 +633,7 @@ var CartesiaTTS = class {
|
|
|
444
633
|
/** Close the WebSocket connection to allow clean process exit. */
|
|
445
634
|
close() {
|
|
446
635
|
if (this.ws) {
|
|
447
|
-
|
|
636
|
+
log4.debug("Closing Cartesia WebSocket");
|
|
448
637
|
this.ws.close();
|
|
449
638
|
this.ws = null;
|
|
450
639
|
}
|
|
@@ -453,17 +642,17 @@ var CartesiaTTS = class {
|
|
|
453
642
|
}
|
|
454
643
|
/** Pre-connect the WebSocket so first synthesize() doesn't pay connection cost. */
|
|
455
644
|
async warmup() {
|
|
456
|
-
|
|
645
|
+
log4.info("Warming up TTS connection...");
|
|
457
646
|
const start = performance.now();
|
|
458
647
|
try {
|
|
459
648
|
await this.ensureConnection();
|
|
460
|
-
|
|
649
|
+
log4.info(`TTS warmup complete in ${(performance.now() - start).toFixed(0)}ms`);
|
|
461
650
|
} catch (err) {
|
|
462
|
-
|
|
651
|
+
log4.warn("TTS warmup failed (non-fatal):", err);
|
|
463
652
|
}
|
|
464
653
|
}
|
|
465
654
|
async *synthesize(text, signal) {
|
|
466
|
-
|
|
655
|
+
log4.debug(`Synthesizing: "${text.slice(0, 60)}"`);
|
|
467
656
|
await this.ensureConnection();
|
|
468
657
|
if (!this.ws || this.ws.readyState !== WebSocket2.OPEN) {
|
|
469
658
|
throw new Error("Cartesia WebSocket not connected");
|
|
@@ -534,12 +723,12 @@ var CartesiaTTS = class {
|
|
|
534
723
|
if (this.connectPromise) return this.connectPromise;
|
|
535
724
|
this.connectPromise = new Promise((resolve, reject) => {
|
|
536
725
|
const url = `${CARTESIA_WS_BASE}?api_key=${this.apiKey}&cartesia_version=${this.apiVersion}`;
|
|
537
|
-
|
|
726
|
+
log4.debug("Connecting to Cartesia...");
|
|
538
727
|
this.ws = new WebSocket2(url);
|
|
539
728
|
this.ws.on("open", () => {
|
|
540
729
|
this._connected = true;
|
|
541
730
|
this.connectPromise = null;
|
|
542
|
-
|
|
731
|
+
log4.info("Cartesia WebSocket connected");
|
|
543
732
|
resolve();
|
|
544
733
|
});
|
|
545
734
|
this.ws.on("message", (data) => {
|
|
@@ -547,12 +736,12 @@ var CartesiaTTS = class {
|
|
|
547
736
|
const msg = JSON.parse(data.toString());
|
|
548
737
|
this.handleMessage(msg);
|
|
549
738
|
} catch (err) {
|
|
550
|
-
|
|
739
|
+
log4.error("Failed to parse Cartesia message:", err);
|
|
551
740
|
}
|
|
552
741
|
});
|
|
553
742
|
this.ws.on("error", (err) => {
|
|
554
743
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
555
|
-
|
|
744
|
+
log4.error("Cartesia WebSocket error:", error);
|
|
556
745
|
for (const ctx of this.contexts.values()) {
|
|
557
746
|
ctx.error = error;
|
|
558
747
|
ctx.wake?.();
|
|
@@ -562,7 +751,7 @@ var CartesiaTTS = class {
|
|
|
562
751
|
reject(error);
|
|
563
752
|
});
|
|
564
753
|
this.ws.on("close", (code, reason) => {
|
|
565
|
-
|
|
754
|
+
log4.debug(`Cartesia WebSocket closed: ${code} ${reason.toString()}`);
|
|
566
755
|
this._connected = false;
|
|
567
756
|
this.connectPromise = null;
|
|
568
757
|
for (const ctx of this.contexts.values()) {
|
|
@@ -587,12 +776,12 @@ var CartesiaTTS = class {
|
|
|
587
776
|
ctx.wake?.();
|
|
588
777
|
}
|
|
589
778
|
} else if (type === "done") {
|
|
590
|
-
|
|
779
|
+
log4.debug(`Cartesia synthesis done for ${contextId} (${ctx.chunks.length} chunks pending)`);
|
|
591
780
|
ctx.done = true;
|
|
592
781
|
ctx.wake?.();
|
|
593
782
|
} else if (type === "error") {
|
|
594
783
|
const errorMsg = msg.error ?? "Unknown Cartesia error";
|
|
595
|
-
|
|
784
|
+
log4.error(`Cartesia error for ${contextId}: ${errorMsg}`);
|
|
596
785
|
ctx.error = new Error(`Cartesia TTS error: ${errorMsg}`);
|
|
597
786
|
ctx.wake?.();
|
|
598
787
|
}
|
|
@@ -601,7 +790,7 @@ var CartesiaTTS = class {
|
|
|
601
790
|
|
|
602
791
|
// src/providers/deepgram-tts.ts
|
|
603
792
|
import WebSocket3 from "ws";
|
|
604
|
-
var
|
|
793
|
+
var log5 = createLogger("DeepgramTTS");
|
|
605
794
|
var DEEPGRAM_WS_BASE = "wss://api.deepgram.com/v1/speak";
|
|
606
795
|
var DEFAULT_SAMPLE_RATE2 = 48e3;
|
|
607
796
|
function parseLangSegments(text, defaultLang) {
|
|
@@ -698,7 +887,7 @@ var DeepgramTTS = class {
|
|
|
698
887
|
/** Close all WebSocket connections to allow clean process exit. */
|
|
699
888
|
close() {
|
|
700
889
|
for (const [lang, ws] of this.connections) {
|
|
701
|
-
|
|
890
|
+
log5.debug(`Closing WebSocket for [${lang}]`);
|
|
702
891
|
ws.close();
|
|
703
892
|
}
|
|
704
893
|
this.connections.clear();
|
|
@@ -707,13 +896,13 @@ var DeepgramTTS = class {
|
|
|
707
896
|
}
|
|
708
897
|
/** Pre-connect all language WebSocket connections. */
|
|
709
898
|
async warmup() {
|
|
710
|
-
|
|
899
|
+
log5.info("Warming up TTS connections...");
|
|
711
900
|
const start = performance.now();
|
|
712
901
|
try {
|
|
713
902
|
await Promise.all(Object.keys(this.models).map((lang) => this.ensureConnection(lang)));
|
|
714
|
-
|
|
903
|
+
log5.info(`TTS warmup complete in ${(performance.now() - start).toFixed(0)}ms`);
|
|
715
904
|
} catch (err) {
|
|
716
|
-
|
|
905
|
+
log5.warn("TTS warmup failed (non-fatal):", err);
|
|
717
906
|
}
|
|
718
907
|
}
|
|
719
908
|
/** Strip SSML lang tags from text for display/events. */
|
|
@@ -746,7 +935,7 @@ var DeepgramTTS = class {
|
|
|
746
935
|
}
|
|
747
936
|
}
|
|
748
937
|
async *synthesizeSegment(lang, text, signal) {
|
|
749
|
-
|
|
938
|
+
log5.debug(`Synthesizing [${lang}]: "${text.slice(0, 60)}"`);
|
|
750
939
|
await this.ensureConnection(lang);
|
|
751
940
|
const ws = this.connections.get(lang);
|
|
752
941
|
if (!ws || ws.readyState !== WebSocket3.OPEN) {
|
|
@@ -804,7 +993,7 @@ var DeepgramTTS = class {
|
|
|
804
993
|
}
|
|
805
994
|
const promise = new Promise((resolve, reject) => {
|
|
806
995
|
const url = `${DEEPGRAM_WS_BASE}?model=${encodeURIComponent(model)}&encoding=linear16&sample_rate=${this.sampleRate}`;
|
|
807
|
-
|
|
996
|
+
log5.debug(`Connecting to Deepgram for [${lang}]: ${model}`);
|
|
808
997
|
const ws = new WebSocket3(url, {
|
|
809
998
|
headers: {
|
|
810
999
|
Authorization: `Token ${this.apiKey}`
|
|
@@ -813,7 +1002,7 @@ var DeepgramTTS = class {
|
|
|
813
1002
|
ws.on("open", () => {
|
|
814
1003
|
this.connections.set(lang, ws);
|
|
815
1004
|
this.connectPromises.delete(lang);
|
|
816
|
-
|
|
1005
|
+
log5.info(`Deepgram WebSocket connected for [${lang}] (${model})`);
|
|
817
1006
|
resolve();
|
|
818
1007
|
});
|
|
819
1008
|
ws.on("message", (data, isBinary) => {
|
|
@@ -830,16 +1019,16 @@ var DeepgramTTS = class {
|
|
|
830
1019
|
state.flushed = true;
|
|
831
1020
|
state.wake?.();
|
|
832
1021
|
} else if (msg.type === "Warning" || msg.type === "Error") {
|
|
833
|
-
|
|
1022
|
+
log5.warn(`Deepgram [${lang}] ${msg.type}: ${msg.description || msg.message || JSON.stringify(msg)}`);
|
|
834
1023
|
}
|
|
835
1024
|
} catch {
|
|
836
|
-
|
|
1025
|
+
log5.warn(`Failed to parse Deepgram message for [${lang}]`);
|
|
837
1026
|
}
|
|
838
1027
|
}
|
|
839
1028
|
});
|
|
840
1029
|
ws.on("error", (err) => {
|
|
841
1030
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
842
|
-
|
|
1031
|
+
log5.error(`Deepgram WebSocket error [${lang}]:`, error);
|
|
843
1032
|
const state = this.flushStates.get(lang);
|
|
844
1033
|
if (state) {
|
|
845
1034
|
state.error = error;
|
|
@@ -850,7 +1039,7 @@ var DeepgramTTS = class {
|
|
|
850
1039
|
reject(error);
|
|
851
1040
|
});
|
|
852
1041
|
ws.on("close", (code, reason) => {
|
|
853
|
-
|
|
1042
|
+
log5.debug(`Deepgram WebSocket closed [${lang}]: ${code} ${reason.toString()}`);
|
|
854
1043
|
this.connections.delete(lang);
|
|
855
1044
|
this.connectPromises.delete(lang);
|
|
856
1045
|
const state = this.flushStates.get(lang);
|
|
@@ -867,7 +1056,7 @@ var DeepgramTTS = class {
|
|
|
867
1056
|
|
|
868
1057
|
// src/providers/dtelecom-stt.ts
|
|
869
1058
|
import WebSocket4 from "ws";
|
|
870
|
-
var
|
|
1059
|
+
var log6 = createLogger("DtelecomSTT");
|
|
871
1060
|
var KEEPALIVE_INTERVAL_MS2 = 5e3;
|
|
872
1061
|
var DtelecomSTT = class {
|
|
873
1062
|
options;
|
|
@@ -926,7 +1115,7 @@ var DtelecomSTTStream = class extends BaseSTTStream {
|
|
|
926
1115
|
}
|
|
927
1116
|
if (this.ws?.readyState === WebSocket4.OPEN) {
|
|
928
1117
|
this.ws.send(JSON.stringify(config));
|
|
929
|
-
|
|
1118
|
+
log6.info(`Reconfiguring STT: language=${language}${options?.forceWhisper ? ", model=whisper" : ""}`);
|
|
930
1119
|
}
|
|
931
1120
|
}
|
|
932
1121
|
async close() {
|
|
@@ -939,15 +1128,15 @@ var DtelecomSTTStream = class extends BaseSTTStream {
|
|
|
939
1128
|
this.ws.close();
|
|
940
1129
|
this.ws = null;
|
|
941
1130
|
}
|
|
942
|
-
|
|
1131
|
+
log6.debug("DtelecomSTT stream closed");
|
|
943
1132
|
}
|
|
944
1133
|
connect() {
|
|
945
1134
|
const url = this.serverUrl.replace(/\/$/, "") + "/v1/stream";
|
|
946
1135
|
const wsUrl = url.replace("https://", "wss://").replace("http://", "ws://");
|
|
947
|
-
|
|
1136
|
+
log6.debug(`Connecting to dTelecom STT: ${wsUrl}`);
|
|
948
1137
|
this.ws = new WebSocket4(wsUrl);
|
|
949
1138
|
this.ws.on("open", () => {
|
|
950
|
-
|
|
1139
|
+
log6.info("dTelecom STT WebSocket connected");
|
|
951
1140
|
const config = {
|
|
952
1141
|
type: "config",
|
|
953
1142
|
language: this.language,
|
|
@@ -964,19 +1153,19 @@ var DtelecomSTTStream = class extends BaseSTTStream {
|
|
|
964
1153
|
const msg = JSON.parse(data.toString());
|
|
965
1154
|
this.handleMessage(msg);
|
|
966
1155
|
} catch (err) {
|
|
967
|
-
|
|
1156
|
+
log6.error("Failed to parse dTelecom STT message:", err);
|
|
968
1157
|
}
|
|
969
1158
|
});
|
|
970
1159
|
this.ws.on("error", (err) => {
|
|
971
|
-
|
|
1160
|
+
log6.error("dTelecom STT WebSocket error:", err);
|
|
972
1161
|
this.emit("error", err instanceof Error ? err : new Error(String(err)));
|
|
973
1162
|
});
|
|
974
1163
|
this.ws.on("close", (code, reason) => {
|
|
975
|
-
|
|
1164
|
+
log6.debug(`dTelecom STT WebSocket closed: ${code} ${reason.toString()}`);
|
|
976
1165
|
this._ready = false;
|
|
977
1166
|
this.stopKeepAlive();
|
|
978
1167
|
if (!this._closed) {
|
|
979
|
-
|
|
1168
|
+
log6.info("dTelecom STT connection lost, reconnecting in 1s...");
|
|
980
1169
|
setTimeout(() => {
|
|
981
1170
|
if (!this._closed) this.connect();
|
|
982
1171
|
}, 1e3);
|
|
@@ -995,14 +1184,14 @@ var DtelecomSTTStream = class extends BaseSTTStream {
|
|
|
995
1184
|
} else if (type === "error") {
|
|
996
1185
|
const errData = msg.error;
|
|
997
1186
|
const errorMsg = msg.message || (typeof errData === "string" ? errData : JSON.stringify(errData)) || "Unknown STT error";
|
|
998
|
-
|
|
1187
|
+
log6.error(`dTelecom STT error: ${errorMsg}`);
|
|
999
1188
|
this.emit("error", new Error(errorMsg));
|
|
1000
1189
|
}
|
|
1001
1190
|
}
|
|
1002
1191
|
handleReady(msg) {
|
|
1003
1192
|
const clientId = msg.client_id;
|
|
1004
1193
|
const lang = msg.language;
|
|
1005
|
-
|
|
1194
|
+
log6.info(`dTelecom STT ready: client_id=${clientId}, language=${lang}`);
|
|
1006
1195
|
this._ready = true;
|
|
1007
1196
|
for (const buf of this.pendingAudio) {
|
|
1008
1197
|
if (this.ws?.readyState === WebSocket4.OPEN) {
|
|
@@ -1019,7 +1208,7 @@ var DtelecomSTTStream = class extends BaseSTTStream {
|
|
|
1019
1208
|
const latencyMs = msg.latency_ms;
|
|
1020
1209
|
if (!text) return;
|
|
1021
1210
|
if (isFinal && latencyMs !== void 0) {
|
|
1022
|
-
|
|
1211
|
+
log6.info(`stt_final: ${latencyMs.toFixed(0)}ms "${text.slice(0, 50)}"`);
|
|
1023
1212
|
}
|
|
1024
1213
|
this.emit("transcription", {
|
|
1025
1214
|
text,
|
|
@@ -1030,7 +1219,7 @@ var DtelecomSTTStream = class extends BaseSTTStream {
|
|
|
1030
1219
|
}
|
|
1031
1220
|
handleVadEvent(msg) {
|
|
1032
1221
|
const event = msg.event;
|
|
1033
|
-
|
|
1222
|
+
log6.debug(`VAD event: ${event}`);
|
|
1034
1223
|
if (event === "speech_start") {
|
|
1035
1224
|
this.emit("transcription", {
|
|
1036
1225
|
text: "",
|
|
@@ -1056,7 +1245,7 @@ var DtelecomSTTStream = class extends BaseSTTStream {
|
|
|
1056
1245
|
|
|
1057
1246
|
// src/providers/dtelecom-tts.ts
|
|
1058
1247
|
import WebSocket5 from "ws";
|
|
1059
|
-
var
|
|
1248
|
+
var log7 = createLogger("DtelecomTTS");
|
|
1060
1249
|
var DtelecomTTS = class {
|
|
1061
1250
|
serverUrl;
|
|
1062
1251
|
sessionKey;
|
|
@@ -1088,19 +1277,19 @@ var DtelecomTTS = class {
|
|
|
1088
1277
|
}
|
|
1089
1278
|
/** Pre-connect WebSocket to TTS server. */
|
|
1090
1279
|
async warmup() {
|
|
1091
|
-
|
|
1280
|
+
log7.info("Warming up TTS connection...");
|
|
1092
1281
|
const start = performance.now();
|
|
1093
1282
|
try {
|
|
1094
1283
|
await this.ensureConnection();
|
|
1095
|
-
|
|
1284
|
+
log7.info(`TTS warmup complete in ${(performance.now() - start).toFixed(0)}ms`);
|
|
1096
1285
|
} catch (err) {
|
|
1097
|
-
|
|
1286
|
+
log7.warn("TTS warmup failed (non-fatal):", err);
|
|
1098
1287
|
}
|
|
1099
1288
|
}
|
|
1100
1289
|
/** Close WebSocket connection. */
|
|
1101
1290
|
close() {
|
|
1102
1291
|
if (this.ws) {
|
|
1103
|
-
|
|
1292
|
+
log7.debug("Closing TTS WebSocket");
|
|
1104
1293
|
this.ws.close();
|
|
1105
1294
|
this.ws = null;
|
|
1106
1295
|
}
|
|
@@ -1162,7 +1351,7 @@ var DtelecomTTS = class {
|
|
|
1162
1351
|
msg.lang_code = voiceConfig.langCode;
|
|
1163
1352
|
msg.speed = this.speed;
|
|
1164
1353
|
}
|
|
1165
|
-
|
|
1354
|
+
log7.info(`TTS send [${lang}]: voice=${voiceConfig?.voice ?? "default"} lang_code=${voiceConfig?.langCode ?? "default"} "${text.slice(0, 60)}"`);
|
|
1166
1355
|
ws.send(JSON.stringify(msg));
|
|
1167
1356
|
try {
|
|
1168
1357
|
while (true) {
|
|
@@ -1195,7 +1384,7 @@ var DtelecomTTS = class {
|
|
|
1195
1384
|
this.connectPromise = new Promise((resolve, reject) => {
|
|
1196
1385
|
const url = this.serverUrl.replace(/\/$/, "") + "/v1/stream";
|
|
1197
1386
|
const wsUrl = url.replace("https://", "wss://").replace("http://", "ws://");
|
|
1198
|
-
|
|
1387
|
+
log7.debug(`Connecting to dTelecom TTS: ${wsUrl}`);
|
|
1199
1388
|
const ws = new WebSocket5(wsUrl);
|
|
1200
1389
|
ws.on("open", () => {
|
|
1201
1390
|
this.ws = ws;
|
|
@@ -1212,7 +1401,7 @@ var DtelecomTTS = class {
|
|
|
1212
1401
|
};
|
|
1213
1402
|
}
|
|
1214
1403
|
ws.send(JSON.stringify(msg));
|
|
1215
|
-
|
|
1404
|
+
log7.info("dTelecom TTS WebSocket connected");
|
|
1216
1405
|
resolve();
|
|
1217
1406
|
});
|
|
1218
1407
|
ws.on("message", (data, isBinary) => {
|
|
@@ -1233,21 +1422,21 @@ var DtelecomTTS = class {
|
|
|
1233
1422
|
state.done = true;
|
|
1234
1423
|
state.wake?.();
|
|
1235
1424
|
} else if (msg.type === "generating") {
|
|
1236
|
-
|
|
1425
|
+
log7.debug(`TTS generating: "${msg.text?.slice(0, 40)}"`);
|
|
1237
1426
|
} else if (msg.type === "error") {
|
|
1238
1427
|
const errorMsg = msg.message || "Unknown TTS error";
|
|
1239
|
-
|
|
1428
|
+
log7.error(`dTelecom TTS error: ${errorMsg}`);
|
|
1240
1429
|
state.error = new Error(errorMsg);
|
|
1241
1430
|
state.wake?.();
|
|
1242
1431
|
}
|
|
1243
1432
|
} catch {
|
|
1244
|
-
|
|
1433
|
+
log7.warn("Failed to parse dTelecom TTS message");
|
|
1245
1434
|
}
|
|
1246
1435
|
}
|
|
1247
1436
|
});
|
|
1248
1437
|
ws.on("error", (err) => {
|
|
1249
1438
|
const error = err instanceof Error ? err : new Error(String(err));
|
|
1250
|
-
|
|
1439
|
+
log7.error("dTelecom TTS WebSocket error:", error);
|
|
1251
1440
|
const state = this.flushState;
|
|
1252
1441
|
if (state) {
|
|
1253
1442
|
state.error = error;
|
|
@@ -1258,7 +1447,7 @@ var DtelecomTTS = class {
|
|
|
1258
1447
|
reject(error);
|
|
1259
1448
|
});
|
|
1260
1449
|
ws.on("close", (code, reason) => {
|
|
1261
|
-
|
|
1450
|
+
log7.debug(`dTelecom TTS WebSocket closed: ${code} ${reason.toString()}`);
|
|
1262
1451
|
this.ws = null;
|
|
1263
1452
|
this.connectPromise = null;
|
|
1264
1453
|
const state = this.flushState;
|
|
@@ -1277,6 +1466,7 @@ export {
|
|
|
1277
1466
|
DeepgramTTS,
|
|
1278
1467
|
DtelecomSTT,
|
|
1279
1468
|
DtelecomTTS,
|
|
1469
|
+
OpenAILLM,
|
|
1280
1470
|
OpenRouterLLM
|
|
1281
1471
|
};
|
|
1282
1472
|
//# sourceMappingURL=index.mjs.map
|