speechflow 1.4.5 → 1.5.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.
Files changed (166) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +220 -7
  3. package/etc/claude.md +70 -0
  4. package/etc/speechflow.yaml +5 -3
  5. package/etc/stx.conf +7 -0
  6. package/package.json +7 -6
  7. package/speechflow-cli/dst/speechflow-node-a2a-compressor-wt.d.ts +1 -0
  8. package/speechflow-cli/dst/speechflow-node-a2a-compressor-wt.js +155 -0
  9. package/speechflow-cli/dst/speechflow-node-a2a-compressor-wt.js.map +1 -0
  10. package/speechflow-cli/dst/speechflow-node-a2a-compressor.d.ts +15 -0
  11. package/speechflow-cli/dst/speechflow-node-a2a-compressor.js +287 -0
  12. package/speechflow-cli/dst/speechflow-node-a2a-compressor.js.map +1 -0
  13. package/speechflow-cli/dst/speechflow-node-a2a-dynamics-wt.d.ts +1 -0
  14. package/speechflow-cli/dst/speechflow-node-a2a-dynamics-wt.js +208 -0
  15. package/speechflow-cli/dst/speechflow-node-a2a-dynamics-wt.js.map +1 -0
  16. package/speechflow-cli/dst/speechflow-node-a2a-dynamics.d.ts +15 -0
  17. package/speechflow-cli/dst/speechflow-node-a2a-dynamics.js +312 -0
  18. package/speechflow-cli/dst/speechflow-node-a2a-dynamics.js.map +1 -0
  19. package/speechflow-cli/dst/speechflow-node-a2a-expander-wt.d.ts +1 -0
  20. package/speechflow-cli/dst/speechflow-node-a2a-expander-wt.js +161 -0
  21. package/speechflow-cli/dst/speechflow-node-a2a-expander-wt.js.map +1 -0
  22. package/speechflow-cli/dst/speechflow-node-a2a-expander.d.ts +13 -0
  23. package/speechflow-cli/dst/speechflow-node-a2a-expander.js +208 -0
  24. package/speechflow-cli/dst/speechflow-node-a2a-expander.js.map +1 -0
  25. package/speechflow-cli/dst/speechflow-node-a2a-ffmpeg.js +13 -3
  26. package/speechflow-cli/dst/speechflow-node-a2a-ffmpeg.js.map +1 -1
  27. package/speechflow-cli/dst/speechflow-node-a2a-filler.d.ts +14 -0
  28. package/speechflow-cli/dst/speechflow-node-a2a-filler.js +233 -0
  29. package/speechflow-cli/dst/speechflow-node-a2a-filler.js.map +1 -0
  30. package/speechflow-cli/dst/speechflow-node-a2a-gain.d.ts +12 -0
  31. package/speechflow-cli/dst/speechflow-node-a2a-gain.js +125 -0
  32. package/speechflow-cli/dst/speechflow-node-a2a-gain.js.map +1 -0
  33. package/speechflow-cli/dst/speechflow-node-a2a-gender.d.ts +0 -1
  34. package/speechflow-cli/dst/speechflow-node-a2a-gender.js +28 -12
  35. package/speechflow-cli/dst/speechflow-node-a2a-gender.js.map +1 -1
  36. package/speechflow-cli/dst/speechflow-node-a2a-meter.d.ts +1 -0
  37. package/speechflow-cli/dst/speechflow-node-a2a-meter.js +12 -8
  38. package/speechflow-cli/dst/speechflow-node-a2a-meter.js.map +1 -1
  39. package/speechflow-cli/dst/speechflow-node-a2a-mute.js +2 -1
  40. package/speechflow-cli/dst/speechflow-node-a2a-mute.js.map +1 -1
  41. package/speechflow-cli/dst/speechflow-node-a2a-rnnoise-wt.d.ts +1 -0
  42. package/speechflow-cli/dst/speechflow-node-a2a-rnnoise-wt.js +55 -0
  43. package/speechflow-cli/dst/speechflow-node-a2a-rnnoise-wt.js.map +1 -0
  44. package/speechflow-cli/dst/speechflow-node-a2a-rnnoise.d.ts +14 -0
  45. package/speechflow-cli/dst/speechflow-node-a2a-rnnoise.js +184 -0
  46. package/speechflow-cli/dst/speechflow-node-a2a-rnnoise.js.map +1 -0
  47. package/speechflow-cli/dst/speechflow-node-a2a-speex.d.ts +14 -0
  48. package/speechflow-cli/dst/speechflow-node-a2a-speex.js +156 -0
  49. package/speechflow-cli/dst/speechflow-node-a2a-speex.js.map +1 -0
  50. package/speechflow-cli/dst/speechflow-node-a2a-vad.js +3 -3
  51. package/speechflow-cli/dst/speechflow-node-a2a-vad.js.map +1 -1
  52. package/speechflow-cli/dst/speechflow-node-a2a-wav.js +22 -17
  53. package/speechflow-cli/dst/speechflow-node-a2a-wav.js.map +1 -1
  54. package/speechflow-cli/dst/speechflow-node-a2t-awstranscribe.d.ts +18 -0
  55. package/speechflow-cli/dst/speechflow-node-a2t-awstranscribe.js +317 -0
  56. package/speechflow-cli/dst/speechflow-node-a2t-awstranscribe.js.map +1 -0
  57. package/speechflow-cli/dst/speechflow-node-a2t-deepgram.js +15 -13
  58. package/speechflow-cli/dst/speechflow-node-a2t-deepgram.js.map +1 -1
  59. package/speechflow-cli/dst/speechflow-node-a2t-openaitranscribe.d.ts +19 -0
  60. package/speechflow-cli/dst/speechflow-node-a2t-openaitranscribe.js +351 -0
  61. package/speechflow-cli/dst/speechflow-node-a2t-openaitranscribe.js.map +1 -0
  62. package/speechflow-cli/dst/speechflow-node-t2a-awspolly.d.ts +16 -0
  63. package/speechflow-cli/dst/speechflow-node-t2a-awspolly.js +171 -0
  64. package/speechflow-cli/dst/speechflow-node-t2a-awspolly.js.map +1 -0
  65. package/speechflow-cli/dst/speechflow-node-t2a-elevenlabs.js +19 -14
  66. package/speechflow-cli/dst/speechflow-node-t2a-elevenlabs.js.map +1 -1
  67. package/speechflow-cli/dst/speechflow-node-t2a-kokoro.js +11 -6
  68. package/speechflow-cli/dst/speechflow-node-t2a-kokoro.js.map +1 -1
  69. package/speechflow-cli/dst/speechflow-node-t2t-awstranslate.d.ts +13 -0
  70. package/speechflow-cli/dst/speechflow-node-t2t-awstranslate.js +141 -0
  71. package/speechflow-cli/dst/speechflow-node-t2t-awstranslate.js.map +1 -0
  72. package/speechflow-cli/dst/speechflow-node-t2t-deepl.js +13 -15
  73. package/speechflow-cli/dst/speechflow-node-t2t-deepl.js.map +1 -1
  74. package/speechflow-cli/dst/speechflow-node-t2t-format.js +10 -15
  75. package/speechflow-cli/dst/speechflow-node-t2t-format.js.map +1 -1
  76. package/speechflow-cli/dst/speechflow-node-t2t-ollama.js +44 -31
  77. package/speechflow-cli/dst/speechflow-node-t2t-ollama.js.map +1 -1
  78. package/speechflow-cli/dst/speechflow-node-t2t-openai.js +44 -45
  79. package/speechflow-cli/dst/speechflow-node-t2t-openai.js.map +1 -1
  80. package/speechflow-cli/dst/speechflow-node-t2t-sentence.js +8 -8
  81. package/speechflow-cli/dst/speechflow-node-t2t-sentence.js.map +1 -1
  82. package/speechflow-cli/dst/speechflow-node-t2t-subtitle.js +10 -12
  83. package/speechflow-cli/dst/speechflow-node-t2t-subtitle.js.map +1 -1
  84. package/speechflow-cli/dst/speechflow-node-t2t-transformers.js +22 -27
  85. package/speechflow-cli/dst/speechflow-node-t2t-transformers.js.map +1 -1
  86. package/speechflow-cli/dst/speechflow-node-x2x-filter.d.ts +1 -0
  87. package/speechflow-cli/dst/speechflow-node-x2x-filter.js +50 -15
  88. package/speechflow-cli/dst/speechflow-node-x2x-filter.js.map +1 -1
  89. package/speechflow-cli/dst/speechflow-node-x2x-trace.js +17 -18
  90. package/speechflow-cli/dst/speechflow-node-x2x-trace.js.map +1 -1
  91. package/speechflow-cli/dst/speechflow-node-xio-device.js +13 -21
  92. package/speechflow-cli/dst/speechflow-node-xio-device.js.map +1 -1
  93. package/speechflow-cli/dst/speechflow-node-xio-mqtt.d.ts +1 -0
  94. package/speechflow-cli/dst/speechflow-node-xio-mqtt.js +22 -16
  95. package/speechflow-cli/dst/speechflow-node-xio-mqtt.js.map +1 -1
  96. package/speechflow-cli/dst/speechflow-node-xio-websocket.js +19 -19
  97. package/speechflow-cli/dst/speechflow-node-xio-websocket.js.map +1 -1
  98. package/speechflow-cli/dst/speechflow-node.d.ts +6 -3
  99. package/speechflow-cli/dst/speechflow-node.js +13 -2
  100. package/speechflow-cli/dst/speechflow-node.js.map +1 -1
  101. package/speechflow-cli/dst/speechflow-utils-audio-wt.d.ts +1 -0
  102. package/speechflow-cli/dst/speechflow-utils-audio-wt.js +124 -0
  103. package/speechflow-cli/dst/speechflow-utils-audio-wt.js.map +1 -0
  104. package/speechflow-cli/dst/speechflow-utils-audio.d.ts +13 -0
  105. package/speechflow-cli/dst/speechflow-utils-audio.js +137 -0
  106. package/speechflow-cli/dst/speechflow-utils-audio.js.map +1 -0
  107. package/speechflow-cli/dst/speechflow-utils.d.ts +18 -0
  108. package/speechflow-cli/dst/speechflow-utils.js +123 -35
  109. package/speechflow-cli/dst/speechflow-utils.js.map +1 -1
  110. package/speechflow-cli/dst/speechflow.js +69 -14
  111. package/speechflow-cli/dst/speechflow.js.map +1 -1
  112. package/speechflow-cli/etc/oxlint.jsonc +112 -11
  113. package/speechflow-cli/etc/stx.conf +2 -2
  114. package/speechflow-cli/etc/tsconfig.json +1 -1
  115. package/speechflow-cli/package.d/@shiguredo+rnnoise-wasm+2025.1.5.patch +25 -0
  116. package/speechflow-cli/package.json +102 -94
  117. package/speechflow-cli/src/lib.d.ts +24 -0
  118. package/speechflow-cli/src/speechflow-node-a2a-compressor-wt.ts +151 -0
  119. package/speechflow-cli/src/speechflow-node-a2a-compressor.ts +303 -0
  120. package/speechflow-cli/src/speechflow-node-a2a-expander-wt.ts +158 -0
  121. package/speechflow-cli/src/speechflow-node-a2a-expander.ts +212 -0
  122. package/speechflow-cli/src/speechflow-node-a2a-ffmpeg.ts +13 -3
  123. package/speechflow-cli/src/speechflow-node-a2a-filler.ts +223 -0
  124. package/speechflow-cli/src/speechflow-node-a2a-gain.ts +98 -0
  125. package/speechflow-cli/src/speechflow-node-a2a-gender.ts +31 -17
  126. package/speechflow-cli/src/speechflow-node-a2a-meter.ts +13 -9
  127. package/speechflow-cli/src/speechflow-node-a2a-mute.ts +3 -2
  128. package/speechflow-cli/src/speechflow-node-a2a-rnnoise-wt.ts +62 -0
  129. package/speechflow-cli/src/speechflow-node-a2a-rnnoise.ts +164 -0
  130. package/speechflow-cli/src/speechflow-node-a2a-speex.ts +137 -0
  131. package/speechflow-cli/src/speechflow-node-a2a-vad.ts +3 -3
  132. package/speechflow-cli/src/speechflow-node-a2a-wav.ts +20 -13
  133. package/speechflow-cli/src/speechflow-node-a2t-awstranscribe.ts +308 -0
  134. package/speechflow-cli/src/speechflow-node-a2t-deepgram.ts +15 -13
  135. package/speechflow-cli/src/speechflow-node-a2t-openaitranscribe.ts +337 -0
  136. package/speechflow-cli/src/speechflow-node-t2a-awspolly.ts +187 -0
  137. package/speechflow-cli/src/speechflow-node-t2a-elevenlabs.ts +19 -14
  138. package/speechflow-cli/src/speechflow-node-t2a-kokoro.ts +12 -7
  139. package/speechflow-cli/src/speechflow-node-t2t-awstranslate.ts +152 -0
  140. package/speechflow-cli/src/speechflow-node-t2t-deepl.ts +13 -15
  141. package/speechflow-cli/src/speechflow-node-t2t-format.ts +10 -15
  142. package/speechflow-cli/src/speechflow-node-t2t-ollama.ts +55 -42
  143. package/speechflow-cli/src/speechflow-node-t2t-openai.ts +58 -58
  144. package/speechflow-cli/src/speechflow-node-t2t-sentence.ts +10 -10
  145. package/speechflow-cli/src/speechflow-node-t2t-subtitle.ts +15 -16
  146. package/speechflow-cli/src/speechflow-node-t2t-transformers.ts +27 -32
  147. package/speechflow-cli/src/speechflow-node-x2x-filter.ts +20 -16
  148. package/speechflow-cli/src/speechflow-node-x2x-trace.ts +20 -19
  149. package/speechflow-cli/src/speechflow-node-xio-device.ts +15 -23
  150. package/speechflow-cli/src/speechflow-node-xio-mqtt.ts +23 -16
  151. package/speechflow-cli/src/speechflow-node-xio-websocket.ts +19 -19
  152. package/speechflow-cli/src/speechflow-node.ts +21 -8
  153. package/speechflow-cli/src/speechflow-utils-audio-wt.ts +172 -0
  154. package/speechflow-cli/src/speechflow-utils-audio.ts +147 -0
  155. package/speechflow-cli/src/speechflow-utils.ts +125 -32
  156. package/speechflow-cli/src/speechflow.ts +74 -17
  157. package/speechflow-ui-db/dst/index.js +31 -31
  158. package/speechflow-ui-db/etc/eslint.mjs +0 -1
  159. package/speechflow-ui-db/etc/tsc-client.json +3 -3
  160. package/speechflow-ui-db/package.json +11 -10
  161. package/speechflow-ui-db/src/app.vue +20 -6
  162. package/speechflow-ui-st/dst/index.js +26 -26
  163. package/speechflow-ui-st/etc/eslint.mjs +0 -1
  164. package/speechflow-ui-st/etc/tsc-client.json +3 -3
  165. package/speechflow-ui-st/package.json +11 -10
  166. package/speechflow-ui-st/src/app.vue +5 -12
@@ -0,0 +1,351 @@
1
+ "use strict";
2
+ /*
3
+ ** SpeechFlow - Speech Processing Flow Graph
4
+ ** Copyright (c) 2024-2025 Dr. Ralf S. Engelschall <rse@engelschall.com>
5
+ ** Licensed under GPL 3.0 <https://spdx.org/licenses/GPL-3.0-only>
6
+ */
7
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
+ if (k2 === undefined) k2 = k;
9
+ var desc = Object.getOwnPropertyDescriptor(m, k);
10
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
11
+ desc = { enumerable: true, get: function() { return m[k]; } };
12
+ }
13
+ Object.defineProperty(o, k2, desc);
14
+ }) : (function(o, m, k, k2) {
15
+ if (k2 === undefined) k2 = k;
16
+ o[k2] = m[k];
17
+ }));
18
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
19
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
20
+ }) : function(o, v) {
21
+ o["default"] = v;
22
+ });
23
+ var __importStar = (this && this.__importStar) || (function () {
24
+ var ownKeys = function(o) {
25
+ ownKeys = Object.getOwnPropertyNames || function (o) {
26
+ var ar = [];
27
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
28
+ return ar;
29
+ };
30
+ return ownKeys(o);
31
+ };
32
+ return function (mod) {
33
+ if (mod && mod.__esModule) return mod;
34
+ var result = {};
35
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
36
+ __setModuleDefault(result, mod);
37
+ return result;
38
+ };
39
+ })();
40
+ var __importDefault = (this && this.__importDefault) || function (mod) {
41
+ return (mod && mod.__esModule) ? mod : { "default": mod };
42
+ };
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ /* standard dependencies */
45
+ const node_stream_1 = __importDefault(require("node:stream"));
46
+ /* external dependencies */
47
+ const openai_1 = __importDefault(require("openai"));
48
+ const luxon_1 = require("luxon");
49
+ const speex_resampler_1 = __importDefault(require("speex-resampler"));
50
+ const ws_1 = __importDefault(require("ws"));
51
+ /* internal dependencies */
52
+ const speechflow_node_1 = __importStar(require("./speechflow-node"));
53
+ const utils = __importStar(require("./speechflow-utils"));
54
+ /* SpeechFlow node for OpenAI Transcribe speech-to-text conversion */
55
+ class SpeechFlowNodeOpenAITranscribe extends speechflow_node_1.default {
56
+ /* declare official node name */
57
+ static name = "openaitranscribe";
58
+ /* internal state */
59
+ static speexInitialized = false;
60
+ openai = null;
61
+ ws = null;
62
+ queue = null;
63
+ resampler = null;
64
+ destroyed = false;
65
+ connectionTimeout = null;
66
+ /* construct node */
67
+ constructor(id, cfg, opts, args) {
68
+ super(id, cfg, opts, args);
69
+ /* declare node configuration parameters */
70
+ this.configure({
71
+ key: { type: "string", val: process.env.SPEECHFLOW_OPENAI_KEY },
72
+ api: { type: "string", val: "https://api.openai.com/v1", match: /^https?:\/\/.+/ },
73
+ model: { type: "string", val: "gpt-4o-mini-transcribe" },
74
+ language: { type: "string", val: "de", match: /^(?:en|de)$/ },
75
+ interim: { type: "boolean", val: false }
76
+ });
77
+ /* declare node input/output format */
78
+ this.input = "audio";
79
+ this.output = "text";
80
+ }
81
+ /* one-time status of node */
82
+ async status() {
83
+ return {};
84
+ }
85
+ /* open node */
86
+ async open() {
87
+ /* sanity check situation */
88
+ if (this.config.audioBitDepth !== 16 || !this.config.audioLittleEndian)
89
+ throw new Error("OpenAI transcribe node currently supports PCM-S16LE audio only");
90
+ /* clear destruction flag */
91
+ this.destroyed = false;
92
+ /* create queue for results */
93
+ this.queue = new utils.SingleQueue();
94
+ /* create a store for the meta information */
95
+ const metastore = new utils.TimeStore();
96
+ /* establish resampler from our standard audio sample rate (48Khz)
97
+ to OpenAI's maximum 24Khz input sample rate */
98
+ if (!SpeechFlowNodeOpenAITranscribe.speexInitialized) {
99
+ /* at least once initialize resampler */
100
+ await speex_resampler_1.default.initPromise;
101
+ SpeechFlowNodeOpenAITranscribe.speexInitialized = true;
102
+ }
103
+ this.resampler = new speex_resampler_1.default(1, this.config.audioSampleRate, 24000, 7);
104
+ /* instantiate OpenAI API */
105
+ this.openai = new openai_1.default({
106
+ baseURL: this.params.api,
107
+ apiKey: this.params.key,
108
+ dangerouslyAllowBrowser: true
109
+ });
110
+ /* open the WebSocket connection for streaming */
111
+ const url = `${this.params.api.replace(/^http/, "ws")}/realtime?intent=transcription`;
112
+ this.ws = new ws_1.default.WebSocket(url, {
113
+ headers: {
114
+ Authorization: `Bearer ${this.params.key}`,
115
+ "OpenAI-Beta": "realtime=v1"
116
+ }
117
+ });
118
+ const sendMessage = (obj) => {
119
+ this.ws?.send(JSON.stringify(obj));
120
+ };
121
+ /* wait for OpenAI API to be available */
122
+ await new Promise((resolve, reject) => {
123
+ this.connectionTimeout = setTimeout(() => {
124
+ if (this.connectionTimeout !== null) {
125
+ this.connectionTimeout = null;
126
+ reject(new Error("OpenAI: timeout waiting for connection open"));
127
+ }
128
+ }, 8000);
129
+ this.ws.once("open", () => {
130
+ this.log("info", "connection open");
131
+ if (this.connectionTimeout !== null) {
132
+ clearTimeout(this.connectionTimeout);
133
+ this.connectionTimeout = null;
134
+ }
135
+ resolve(true);
136
+ });
137
+ this.ws.once("error", (err) => {
138
+ if (this.connectionTimeout !== null) {
139
+ clearTimeout(this.connectionTimeout);
140
+ this.connectionTimeout = null;
141
+ }
142
+ reject(err);
143
+ });
144
+ });
145
+ /* configure session */
146
+ sendMessage({
147
+ type: "transcription_session.update",
148
+ session: {
149
+ input_audio_format: "pcm16",
150
+ input_audio_transcription: {
151
+ model: this.params.model,
152
+ language: this.params.language
153
+ },
154
+ turn_detection: {
155
+ type: "server_vad",
156
+ threshold: 0.5,
157
+ prefix_padding_ms: 300,
158
+ silence_duration_ms: 500
159
+ }
160
+ }
161
+ });
162
+ /* hook onto session events */
163
+ this.ws.on("open", () => {
164
+ this.log("info", "WebSocket connection opened");
165
+ sendMessage({ type: "transcription.create" });
166
+ });
167
+ this.ws.on("close", () => {
168
+ this.log("info", "WebSocket connection closed");
169
+ this.queue.write(null);
170
+ });
171
+ this.ws.on("error", (err) => {
172
+ this.log("error", `WebSocket connection error: ${err}`);
173
+ });
174
+ let text = "";
175
+ this.ws.on("message", (data) => {
176
+ let ev;
177
+ try {
178
+ ev = JSON.parse(data.toString());
179
+ }
180
+ catch (err) {
181
+ this.log("warning", `failed to parse WebSocket message: ${err}`);
182
+ return;
183
+ }
184
+ if (!(typeof ev === "object" && ev !== null)) {
185
+ this.log("warning", "received invalid WebSocket message");
186
+ return;
187
+ }
188
+ switch (ev.type) {
189
+ case "transcription_session.created":
190
+ break;
191
+ case "conversation.item.created":
192
+ text = "";
193
+ break;
194
+ case "conversation.item.input_audio_transcription.delta": {
195
+ text += ev.delta;
196
+ if (this.params.interim) {
197
+ const start = luxon_1.DateTime.now().diff(this.timeOpen); // FIXME: OpenAI does not provide timestamps
198
+ const end = start; // FIXME: OpenAI does not provide timestamps
199
+ const metas = metastore.fetch(start, end);
200
+ const meta = metas.reduce((prev, curr) => {
201
+ curr.forEach((val, key) => { prev.set(key, val); });
202
+ return prev;
203
+ }, new Map());
204
+ const chunk = new speechflow_node_1.SpeechFlowChunk(start, end, "intermediate", "text", text);
205
+ chunk.meta = meta;
206
+ this.queue.write(chunk);
207
+ }
208
+ break;
209
+ }
210
+ case "conversation.item.input_audio_transcription.completed": {
211
+ text = ev.transcript;
212
+ const start = luxon_1.DateTime.now().diff(this.timeOpen); // FIXME: OpenAI does not provide timestamps
213
+ const end = start; // FIXME: OpenAI does not provide timestamps
214
+ const metas = metastore.fetch(start, end);
215
+ const meta = metas.reduce((prev, curr) => {
216
+ curr.forEach((val, key) => { prev.set(key, val); });
217
+ return prev;
218
+ }, new Map());
219
+ metastore.prune(start);
220
+ const chunk = new speechflow_node_1.SpeechFlowChunk(start, end, "final", "text", text);
221
+ chunk.meta = meta;
222
+ this.queue.write(chunk);
223
+ text = "";
224
+ break;
225
+ }
226
+ case "input_audio_buffer.speech_started":
227
+ this.log("info", "VAD: speech started");
228
+ break;
229
+ case "input_audio_buffer.speech_stopped":
230
+ this.log("info", "VAD: speech stopped");
231
+ break;
232
+ case "input_audio_buffer.committed":
233
+ this.log("info", "input buffer committed");
234
+ break;
235
+ case "error":
236
+ this.log("error", `error: ${ev.error?.message}`);
237
+ break;
238
+ default:
239
+ break;
240
+ }
241
+ });
242
+ /* remember opening time to receive time zero offset */
243
+ this.timeOpen = luxon_1.DateTime.now();
244
+ /* provide Duplex stream and internally attach to OpenAI API */
245
+ const self = this;
246
+ this.stream = new node_stream_1.default.Duplex({
247
+ writableObjectMode: true,
248
+ readableObjectMode: true,
249
+ decodeStrings: false,
250
+ highWaterMark: 1,
251
+ write(chunk, encoding, callback) {
252
+ if (self.destroyed || self.ws === null) {
253
+ callback(new Error("stream already destroyed"));
254
+ return;
255
+ }
256
+ if (chunk.type !== "audio")
257
+ callback(new Error("expected audio input chunk"));
258
+ else if (!Buffer.isBuffer(chunk.payload))
259
+ callback(new Error("expected Buffer input chunk"));
260
+ else {
261
+ if (chunk.payload.byteLength > 0) {
262
+ self.log("debug", `send data (${chunk.payload.byteLength} bytes)`);
263
+ if (chunk.meta.size > 0)
264
+ metastore.store(chunk.timestampStart, chunk.timestampEnd, chunk.meta);
265
+ try {
266
+ const payload = self.resampler.processChunk(chunk.payload);
267
+ const audioB64 = payload.toString("base64");
268
+ sendMessage({
269
+ type: "input_audio_buffer.append",
270
+ audio: audioB64 /* intentionally discard all time information */
271
+ });
272
+ }
273
+ catch (error) {
274
+ callback(error instanceof Error ? error : new Error("failed to send to OpenAI transcribe"));
275
+ return;
276
+ }
277
+ }
278
+ callback();
279
+ }
280
+ },
281
+ read(size) {
282
+ if (self.destroyed || self.queue === null) {
283
+ this.push(null);
284
+ return;
285
+ }
286
+ self.queue.read().then((chunk) => {
287
+ if (self.destroyed) {
288
+ this.push(null);
289
+ return;
290
+ }
291
+ if (chunk === null) {
292
+ self.log("info", "received EOF signal");
293
+ this.push(null);
294
+ }
295
+ else {
296
+ self.log("debug", `received data (${chunk.payload.length} bytes)`);
297
+ this.push(chunk);
298
+ }
299
+ }).catch((error) => {
300
+ if (!self.destroyed)
301
+ self.log("error", `queue read error: ${error.message}`);
302
+ });
303
+ },
304
+ final(callback) {
305
+ if (self.destroyed || self.ws === null) {
306
+ callback();
307
+ return;
308
+ }
309
+ try {
310
+ sendMessage({ type: "input_audio_buffer.commit" });
311
+ self.ws.close();
312
+ /* NOTICE: do not push null here -- let the OpenAI close event handle it */
313
+ callback();
314
+ }
315
+ catch (error) {
316
+ self.log("warning", `error closing OpenAI connection: ${error}`);
317
+ callback(error instanceof Error ? error : new Error("failed to close OpenAI connection"));
318
+ }
319
+ }
320
+ });
321
+ }
322
+ /* close node */
323
+ async close() {
324
+ /* indicate destruction first to stop all async operations */
325
+ this.destroyed = true;
326
+ /* clear connection timeout */
327
+ if (this.connectionTimeout !== null) {
328
+ clearTimeout(this.connectionTimeout);
329
+ this.connectionTimeout = null;
330
+ }
331
+ /* signal EOF to any pending read operations */
332
+ if (this.queue !== null) {
333
+ this.queue.write(null);
334
+ this.queue = null;
335
+ }
336
+ /* close OpenAI connection */
337
+ if (this.ws !== null) {
338
+ this.ws.close();
339
+ this.ws = null;
340
+ }
341
+ if (this.openai !== null)
342
+ this.openai = null;
343
+ /* close stream */
344
+ if (this.stream !== null) {
345
+ this.stream.destroy();
346
+ this.stream = null;
347
+ }
348
+ }
349
+ }
350
+ exports.default = SpeechFlowNodeOpenAITranscribe;
351
+ //# sourceMappingURL=speechflow-node-a2t-openaitranscribe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"speechflow-node-a2t-openaitranscribe.js","sourceRoot":"","sources":["../src/speechflow-node-a2t-openaitranscribe.ts"],"names":[],"mappings":";AAAA;;;;EAIE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEF,6BAA6B;AAC7B,8DAAgC;AAEhC,6BAA6B;AAC7B,oDAA2C;AAC3C,iCAA0C;AAC1C,sEAAoD;AACpD,4CAAuC;AAEvC,6BAA6B;AAC7B,qEAAmE;AACnE,0DAAoE;AAEpE,uEAAuE;AACvE,MAAqB,8BAA+B,SAAQ,yBAAc;IACtE,kCAAkC;IAC3B,MAAM,CAAC,IAAI,GAAG,kBAAkB,CAAA;IAEvC,sBAAsB;IACd,MAAM,CAAC,gBAAgB,GAAG,KAAK,CAAA;IAC/B,MAAM,GAAsB,IAAI,CAAA;IAChC,EAAE,GAAgC,IAAI,CAAA;IACtC,KAAK,GAA0D,IAAI,CAAA;IACnE,SAAS,GAA2B,IAAI,CAAA;IACxC,SAAS,GAAK,KAAK,CAAA;IACnB,iBAAiB,GAAyC,IAAI,CAAA;IAEtE,sBAAsB;IACtB,YAAa,EAAU,EAAE,GAA4B,EAAE,IAA6B,EAAE,IAAW;QAC7F,KAAK,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;QAE1B,6CAA6C;QAC7C,IAAI,CAAC,SAAS,CAAC;YACX,GAAG,EAAO,EAAE,IAAI,EAAE,QAAQ,EAAG,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,qBAAqB,EAAE;YACrE,GAAG,EAAO,EAAE,IAAI,EAAE,QAAQ,EAAG,GAAG,EAAE,2BAA2B,EAAE,KAAK,EAAE,gBAAgB,EAAE;YACxF,KAAK,EAAK,EAAE,IAAI,EAAE,QAAQ,EAAG,GAAG,EAAE,wBAAwB,EAAE;YAC5D,QAAQ,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAG,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE;YAC9D,OAAO,EAAG,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE,KAAK,EAAE;SAC5C,CAAC,CAAA;QAEF,wCAAwC;QACxC,IAAI,CAAC,KAAK,GAAI,OAAO,CAAA;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;IACxB,CAAC;IAED,+BAA+B;IAC/B,KAAK,CAAC,MAAM;QACR,OAAO,EAAE,CAAA;IACb,CAAC;IAED,iBAAiB;IACjB,KAAK,CAAC,IAAI;QACN,8BAA8B;QAC9B,IAAI,IAAI,CAAC,MAAM,CAAC,aAAa,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,iBAAiB;YAClE,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAA;QAErF,8BAA8B;QAC9B,IAAI,CAAC,SAAS,GAAG,KAAK,CAAA;QAEtB,gCAAgC;QAChC,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,WAAW,EAA0B,CAAA;QAE5D,+CAA+C;QAC/C,MAAM,SAAS,GAAG,IAAI,KAAK,CAAC,SAAS,EAAoB,CAAA;QAEzD;2DACmD;QACnD,IAAI,CAAC,8BAA8B,CAAC,gBAAgB,EAAE,CAAC;YACnD,0CAA0C;YAC1C,MAAM,yBAAc,CAAC,WAAW,CAAA;YAChC,8BAA8B,CAAC,gBAAgB,GAAG,IAAI,CAAA;QAC1D,CAAC;QACD,IAAI,CAAC,SAAS,GAAG,IAAI,yBAAc,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,eAAe,EAAE,KAAK,EAAE,CAAC,CAAC,CAAA;QAE7E,8BAA8B;QAC9B,IAAI,CAAC,MAAM,GAAG,IAAI,gBAAM,CAAC;YACrB,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,GAAG;YACxB,MAAM,EAAG,IAAI,CAAC,MAAM,CAAC,GAAG;YACxB,uBAAuB,EAAE,IAAI;SAChC,CAAC,CAAA;QAEF,mDAAmD;QACnD,MAAM,GAAG,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,gCAAgC,CAAA;QACrF,IAAI,CAAC,EAAE,GAAG,IAAI,YAAE,CAAC,SAAS,CAAC,GAAG,EAAE;YAC5B,OAAO,EAAE;gBACL,aAAa,EAAE,UAAU,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE;gBAC1C,aAAa,EAAE,aAAa;aAC/B;SACJ,CAAC,CAAA;QACF,MAAM,WAAW,GAAG,CAAC,GAAQ,EAAE,EAAE;YAC7B,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAA;QACtC,CAAC,CAAA;QAED,2CAA2C;QAC3C,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAClC,IAAI,CAAC,iBAAiB,GAAG,UAAU,CAAC,GAAG,EAAE;gBACrC,IAAI,IAAI,CAAC,iBAAiB,KAAK,IAAI,EAAE,CAAC;oBAClC,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAA;oBAC7B,MAAM,CAAC,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC,CAAA;gBACpE,CAAC;YACL,CAAC,EAAE,IAAI,CAAC,CAAA;YACR,IAAI,CAAC,EAAG,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE;gBACvB,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAA;gBACnC,IAAI,IAAI,CAAC,iBAAiB,KAAK,IAAI,EAAE,CAAC;oBAClC,YAAY,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAA;oBACpC,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAA;gBACjC,CAAC;gBACD,OAAO,CAAC,IAAI,CAAC,CAAA;YACjB,CAAC,CAAC,CAAA;YACF,IAAI,CAAC,EAAG,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBAC3B,IAAI,IAAI,CAAC,iBAAiB,KAAK,IAAI,EAAE,CAAC;oBAClC,YAAY,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAA;oBACpC,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAA;gBACjC,CAAC;gBACD,MAAM,CAAC,GAAG,CAAC,CAAA;YACf,CAAC,CAAC,CAAA;QACN,CAAC,CAAC,CAAA;QAEF,yBAAyB;QACzB,WAAW,CAAC;YACR,IAAI,EAAE,8BAA8B;YACpC,OAAO,EAAE;gBACL,kBAAkB,EAAE,OAAO;gBAC3B,yBAAyB,EAAE;oBACvB,KAAK,EAAK,IAAI,CAAC,MAAM,CAAC,KAAK;oBAC3B,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,QAAQ;iBACjC;gBACD,cAAc,EAAE;oBACZ,IAAI,EAAE,YAAY;oBAClB,SAAS,EAAE,GAAG;oBACd,iBAAiB,EAAE,GAAG;oBACtB,mBAAmB,EAAE,GAAG;iBAC3B;aACJ;SACJ,CAAC,CAAA;QAEF,gCAAgC;QAChC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,EAAE;YACpB,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,6BAA6B,CAAC,CAAA;YAC/C,WAAW,CAAC,EAAE,IAAI,EAAE,sBAAsB,EAAE,CAAC,CAAA;QACjD,CAAC,CAAC,CAAA;QACF,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACrB,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,6BAA6B,CAAC,CAAA;YAC/C,IAAI,CAAC,KAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;QAC3B,CAAC,CAAC,CAAA;QACF,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACxB,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,+BAA+B,GAAG,EAAE,CAAC,CAAA;QAC3D,CAAC,CAAC,CAAA;QACF,IAAI,IAAI,GAAG,EAAE,CAAA;QACb,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,EAAE;YAC3B,IAAI,EAAO,CAAA;YACX,IAAI,CAAC;gBACD,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAA;YACpC,CAAC;YACD,OAAO,GAAG,EAAE,CAAC;gBACT,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,sCAAsC,GAAG,EAAE,CAAC,CAAA;gBAChE,OAAM;YACV,CAAC;YACD,IAAI,CAAC,CAAC,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;gBAC3C,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,oCAAoC,CAAC,CAAA;gBACzD,OAAM;YACV,CAAC;YACD,QAAQ,EAAE,CAAC,IAAI,EAAE,CAAC;gBACd,KAAK,+BAA+B;oBAChC,MAAK;gBACT,KAAK,2BAA2B;oBAC5B,IAAI,GAAG,EAAE,CAAA;oBACT,MAAK;gBACT,KAAK,mDAAmD,CAAC,CAAC,CAAC;oBACvD,IAAI,IAAI,EAAE,CAAC,KAAe,CAAA;oBAC1B,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;wBACtB,MAAM,KAAK,GAAG,gBAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,QAAS,CAAC,CAAA,CAAC,4CAA4C;wBAC9F,MAAM,GAAG,GAAK,KAAK,CAAA,CAA+B,4CAA4C;wBAC9F,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;wBACzC,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAsB,EAAE,IAAsB,EAAE,EAAE;4BACzE,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA,CAAC,CAAC,CAAC,CAAA;4BAClD,OAAO,IAAI,CAAA;wBACf,CAAC,EAAE,IAAI,GAAG,EAAe,CAAC,CAAA;wBAC1B,MAAM,KAAK,GAAG,IAAI,iCAAe,CAAC,KAAK,EAAE,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,IAAI,CAAC,CAAA;wBAC3E,KAAK,CAAC,IAAI,GAAG,IAAI,CAAA;wBACjB,IAAI,CAAC,KAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;oBAC5B,CAAC;oBACD,MAAK;gBACT,CAAC;gBACD,KAAK,uDAAuD,CAAC,CAAC,CAAC;oBAC3D,IAAI,GAAG,EAAE,CAAC,UAAoB,CAAA;oBAC9B,MAAM,KAAK,GAAG,gBAAQ,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,QAAS,CAAC,CAAA,CAAC,4CAA4C;oBAC9F,MAAM,GAAG,GAAK,KAAK,CAAA,CAA+B,4CAA4C;oBAC9F,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAA;oBACzC,MAAM,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAsB,EAAE,IAAsB,EAAE,EAAE;wBACzE,IAAI,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA,CAAC,CAAC,CAAC,CAAA;wBAClD,OAAO,IAAI,CAAA;oBACf,CAAC,EAAE,IAAI,GAAG,EAAe,CAAC,CAAA;oBAC1B,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;oBACtB,MAAM,KAAK,GAAG,IAAI,iCAAe,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,CAAA;oBACpE,KAAK,CAAC,IAAI,GAAG,IAAI,CAAA;oBACjB,IAAI,CAAC,KAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;oBACxB,IAAI,GAAG,EAAE,CAAA;oBACT,MAAK;gBACT,CAAC;gBACD,KAAK,mCAAmC;oBACpC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAA;oBACvC,MAAK;gBACT,KAAK,mCAAmC;oBACpC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAA;oBACvC,MAAK;gBACT,KAAK,8BAA8B;oBAC/B,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAA;oBAC1C,MAAK;gBACT,KAAK,OAAO;oBACR,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,UAAU,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,CAAC,CAAA;oBAChD,MAAK;gBACT;oBACI,MAAK;YACb,CAAC;QACL,CAAC,CAAC,CAAA;QAEF,yDAAyD;QACzD,IAAI,CAAC,QAAQ,GAAG,gBAAQ,CAAC,GAAG,EAAE,CAAA;QAE9B,iEAAiE;QACjE,MAAM,IAAI,GAAG,IAAI,CAAA;QACjB,IAAI,CAAC,MAAM,GAAG,IAAI,qBAAM,CAAC,MAAM,CAAC;YAC5B,kBAAkB,EAAE,IAAI;YACxB,kBAAkB,EAAE,IAAI;YACxB,aAAa,EAAO,KAAK;YACzB,aAAa,EAAO,CAAC;YACrB,KAAK,CAAE,KAAsB,EAAE,QAAQ,EAAE,QAAQ;gBAC7C,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC;oBACrC,QAAQ,CAAC,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC,CAAA;oBAC/C,OAAM;gBACV,CAAC;gBACD,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO;oBACtB,QAAQ,CAAC,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC,CAAA;qBAChD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,OAAO,CAAC;oBACpC,QAAQ,CAAC,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC,CAAA;qBACjD,CAAC;oBACF,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;wBAC/B,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,cAAc,KAAK,CAAC,OAAO,CAAC,UAAU,SAAS,CAAC,CAAA;wBAClE,IAAI,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC;4BACnB,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,CAAC,YAAY,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;wBACzE,IAAI,CAAC;4BACD,MAAM,OAAO,GAAG,IAAI,CAAC,SAAU,CAAC,YAAY,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;4BAC3D,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;4BAC3C,WAAW,CAAC;gCACR,IAAI,EAAE,2BAA2B;gCACjC,KAAK,EAAE,QAAQ,CAAC,gDAAgD;6BACnE,CAAC,CAAA;wBACN,CAAC;wBACD,OAAO,KAAK,EAAE,CAAC;4BACX,QAAQ,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC,CAAA;4BAC3F,OAAM;wBACV,CAAC;oBACL,CAAC;oBACD,QAAQ,EAAE,CAAA;gBACd,CAAC;YACL,CAAC;YACD,IAAI,CAAE,IAAI;gBACN,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;oBACxC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;oBACf,OAAM;gBACV,CAAC;gBACD,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE;oBAC7B,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;wBACjB,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;wBACf,OAAM;oBACV,CAAC;oBACD,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;wBACjB,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAA;wBACvC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;oBACnB,CAAC;yBACI,CAAC;wBACF,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,kBAAkB,KAAK,CAAC,OAAO,CAAC,MAAM,SAAS,CAAC,CAAA;wBAClE,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;oBACpB,CAAC;gBACL,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;oBACf,IAAI,CAAC,IAAI,CAAC,SAAS;wBACf,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,qBAAqB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;gBAC/D,CAAC,CAAC,CAAA;YACN,CAAC;YACD,KAAK,CAAE,QAAQ;gBACX,IAAI,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC;oBACrC,QAAQ,EAAE,CAAA;oBACV,OAAM;gBACV,CAAC;gBACD,IAAI,CAAC;oBACD,WAAW,CAAC,EAAE,IAAI,EAAE,2BAA2B,EAAE,CAAC,CAAA;oBAClD,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAA;oBACf,6EAA6E;oBAC7E,QAAQ,EAAE,CAAA;gBACd,CAAC;gBACD,OAAO,KAAK,EAAE,CAAC;oBACX,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,oCAAoC,KAAK,EAAE,CAAC,CAAA;oBAChE,QAAQ,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC,CAAA;gBAC7F,CAAC;YACL,CAAC;SACJ,CAAC,CAAA;IACN,CAAC;IAED,kBAAkB;IAClB,KAAK,CAAC,KAAK;QACP,+DAA+D;QAC/D,IAAI,CAAC,SAAS,GAAG,IAAI,CAAA;QAErB,gCAAgC;QAChC,IAAI,IAAI,CAAC,iBAAiB,KAAK,IAAI,EAAE,CAAC;YAClC,YAAY,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAA;YACpC,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAA;QACjC,CAAC;QAED,iDAAiD;QACjD,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YACtB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;YACtB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;QACrB,CAAC;QAED,+BAA+B;QAC/B,IAAI,IAAI,CAAC,EAAE,KAAK,IAAI,EAAE,CAAC;YACnB,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAA;YACf,IAAI,CAAC,EAAE,GAAG,IAAI,CAAA;QAClB,CAAC;QACD,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI;YACpB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAA;QAEtB,oBAAoB;QACpB,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;YACvB,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAA;YACrB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAA;QACtB,CAAC;IACL,CAAC;;AA3TL,iDA4TC"}
@@ -0,0 +1,16 @@
1
+ import SpeechFlowNode from "./speechflow-node";
2
+ export default class SpeechFlowNodeAWSPolly extends SpeechFlowNode {
3
+ static name: string;
4
+ private client;
5
+ private static speexInitialized;
6
+ private destroyed;
7
+ private resampler;
8
+ constructor(id: string, cfg: {
9
+ [id: string]: any;
10
+ }, opts: {
11
+ [id: string]: any;
12
+ }, args: any[]);
13
+ status(): Promise<{}>;
14
+ open(): Promise<void>;
15
+ close(): Promise<void>;
16
+ }
@@ -0,0 +1,171 @@
1
+ "use strict";
2
+ /*
3
+ ** SpeechFlow - Speech Processing Flow Graph
4
+ ** Copyright (c) 2024-2025 Dr. Ralf S. Engelschall <rse@engelschall.com>
5
+ ** Licensed under GPL 3.0 <https://spdx.org/licenses/GPL-3.0-only>
6
+ */
7
+ var __importDefault = (this && this.__importDefault) || function (mod) {
8
+ return (mod && mod.__esModule) ? mod : { "default": mod };
9
+ };
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ /* standard dependencies */
12
+ const node_stream_1 = __importDefault(require("node:stream"));
13
+ /* external dependencies */
14
+ const get_stream_1 = require("get-stream");
15
+ const speex_resampler_1 = __importDefault(require("speex-resampler"));
16
+ const client_polly_1 = require("@aws-sdk/client-polly");
17
+ /* internal dependencies */
18
+ const speechflow_node_1 = __importDefault(require("./speechflow-node"));
19
+ /* SpeechFlow node for AWS Polly text-to-speech conversion */
20
+ class SpeechFlowNodeAWSPolly extends speechflow_node_1.default {
21
+ /* declare official node name */
22
+ static name = "awspolly";
23
+ /* internal state */
24
+ client = null;
25
+ static speexInitialized = false;
26
+ destroyed = false;
27
+ resampler = null;
28
+ /* construct node */
29
+ constructor(id, cfg, opts, args) {
30
+ super(id, cfg, opts, args);
31
+ /* declare node configuration parameters */
32
+ this.configure({
33
+ key: { type: "string", val: process.env.SPEECHFLOW_AMAZON_KEY },
34
+ secKey: { type: "string", val: process.env.SPEECHFLOW_AMAZON_KEY_SEC },
35
+ region: { type: "string", val: "eu-central-1" },
36
+ voice: { type: "string", val: "Amy", pos: 0, match: /^(?:Amy|Danielle|Joanna|Matthew|Ruth|Stephen|Vicki|Daniel)$/ },
37
+ language: { type: "string", val: "en", pos: 1, match: /^(?:de|en)$/ }
38
+ });
39
+ /* sanity check parameters */
40
+ if (!this.params.key)
41
+ throw new Error("AWS Access Key not configured");
42
+ if (!this.params.secKey)
43
+ throw new Error("AWS Secret Access Key not configured");
44
+ /* declare node input/output format */
45
+ this.input = "text";
46
+ this.output = "audio";
47
+ }
48
+ /* one-time status of node */
49
+ async status() {
50
+ return {};
51
+ }
52
+ /* open node */
53
+ async open() {
54
+ /* clear destruction flag */
55
+ this.destroyed = false;
56
+ /* establish AWS Polly connection */
57
+ this.client = new client_polly_1.PollyClient({
58
+ region: this.params.region,
59
+ credentials: {
60
+ accessKeyId: this.params.key,
61
+ secretAccessKey: this.params.secKey
62
+ }
63
+ });
64
+ if (this.client === null)
65
+ throw new Error("failed to establish AWS Polly client");
66
+ /* list of voices */
67
+ const voices = {
68
+ "Amy": { language: "en", languageCode: "en-GB", engine: "generative" },
69
+ "Danielle": { language: "en", languageCode: "en-US", engine: "generative" },
70
+ "Joanna": { language: "en", languageCode: "en-US", engine: "generative" },
71
+ "Matthew": { language: "en", languageCode: "en-US", engine: "generative" },
72
+ "Ruth": { language: "en", languageCode: "en-US", engine: "generative" },
73
+ "Stephen": { language: "en", languageCode: "en-US", engine: "generative" },
74
+ "Vicki": { language: "de", languageCode: "de-DE", engine: "generative" },
75
+ "Daniel": { language: "de", languageCode: "de-DE", engine: "generative" },
76
+ };
77
+ const voiceConfig = voices[this.params.voice];
78
+ if (voiceConfig === undefined)
79
+ throw new Error("unsupported voice");
80
+ if (voiceConfig.language !== this.params.language)
81
+ throw new Error(`voice does only support language "${voiceConfig.language}"`);
82
+ /* perform text-to-speech operation with AWS Polly API */
83
+ const textToSpeech = async (text) => {
84
+ const cmd = new client_polly_1.SynthesizeSpeechCommand({
85
+ LanguageCode: voiceConfig.languageCode,
86
+ Engine: voiceConfig.engine,
87
+ VoiceId: this.params.voice,
88
+ OutputFormat: "pcm",
89
+ SampleRate: "16000", /* maximum supported for PCM output */
90
+ TextType: "text",
91
+ Text: text
92
+ });
93
+ const res = await this.client.send(cmd);
94
+ const stream = res.AudioStream;
95
+ if (stream === null)
96
+ throw new Error("stream not returned");
97
+ const buffer = await (0, get_stream_1.getStreamAsBuffer)(stream);
98
+ const bufferResampled = this.resampler.processChunk(buffer);
99
+ return bufferResampled;
100
+ };
101
+ /* establish resampler from AWS Polly's maximum 16Khz output
102
+ (for PCM output) to our standard audio sample rate (48KHz) */
103
+ if (!SpeechFlowNodeAWSPolly.speexInitialized) {
104
+ /* at least once initialize resampler */
105
+ await speex_resampler_1.default.initPromise;
106
+ SpeechFlowNodeAWSPolly.speexInitialized = true;
107
+ }
108
+ this.resampler = new speex_resampler_1.default(1, 16000, this.config.audioSampleRate, 7);
109
+ /* create transform stream and connect it to the AWS Polly API */
110
+ const self = this;
111
+ this.stream = new node_stream_1.default.Transform({
112
+ writableObjectMode: true,
113
+ readableObjectMode: true,
114
+ decodeStrings: false,
115
+ highWaterMark: 1,
116
+ transform(chunk, encoding, callback) {
117
+ if (self.destroyed) {
118
+ callback(new Error("stream already destroyed"));
119
+ return;
120
+ }
121
+ if (Buffer.isBuffer(chunk.payload))
122
+ callback(new Error("invalid chunk payload type"));
123
+ else if (chunk.payload.length > 0) {
124
+ self.log("debug", `send data (${chunk.payload.length} bytes): "${chunk.payload}"`);
125
+ textToSpeech(chunk.payload).then((buffer) => {
126
+ if (self.destroyed)
127
+ throw new Error("stream destroyed during processing");
128
+ const chunkNew = chunk.clone();
129
+ chunkNew.type = "audio";
130
+ chunkNew.payload = buffer;
131
+ this.push(chunkNew);
132
+ callback();
133
+ }).catch((error) => {
134
+ callback(error instanceof Error ?
135
+ error : new Error(`failed to send to AWS Polly: ${String(error)}`));
136
+ });
137
+ }
138
+ else
139
+ callback();
140
+ },
141
+ final(callback) {
142
+ if (self.destroyed) {
143
+ callback();
144
+ return;
145
+ }
146
+ this.push(null);
147
+ callback();
148
+ }
149
+ });
150
+ }
151
+ /* close node */
152
+ async close() {
153
+ /* indicate destruction */
154
+ this.destroyed = true;
155
+ /* destroy resampler */
156
+ if (this.resampler !== null)
157
+ this.resampler = null;
158
+ /* destroy AWS Polly API */
159
+ if (this.client !== null) {
160
+ this.client.destroy();
161
+ this.client = null;
162
+ }
163
+ /* destroy stream */
164
+ if (this.stream !== null) {
165
+ this.stream.destroy();
166
+ this.stream = null;
167
+ }
168
+ }
169
+ }
170
+ exports.default = SpeechFlowNodeAWSPolly;
171
+ //# sourceMappingURL=speechflow-node-t2a-awspolly.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"speechflow-node-t2a-awspolly.js","sourceRoot":"","sources":["../src/speechflow-node-t2a-awspolly.ts"],"names":[],"mappings":"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"}
@@ -80,10 +80,17 @@ class SpeechFlowNodeElevenlabs extends speechflow_node_1.default {
80
80
  }
81
81
  /* one-time status of node */
82
82
  async status() {
83
- const elevenlabs = new ElevenLabs.ElevenLabsClient({ apiKey: this.params.key });
84
- const subscription = await elevenlabs.user.subscription.get();
85
- const percent = subscription.characterCount / subscription.characterLimit;
86
- return { usage: `${percent.toFixed(2)}%` };
83
+ try {
84
+ const elevenlabs = new ElevenLabs.ElevenLabsClient({ apiKey: this.params.key });
85
+ const subscription = await elevenlabs.user.subscription.get();
86
+ const percent = subscription.characterLimit > 0
87
+ ? subscription.characterCount / subscription.characterLimit
88
+ : 0;
89
+ return { usage: `${percent.toFixed(2)}%` };
90
+ }
91
+ catch (_error) {
92
+ return { usage: "unknown" };
93
+ }
87
94
  }
88
95
  /* open node */
89
96
  async open() {
@@ -112,15 +119,15 @@ class SpeechFlowNodeElevenlabs extends speechflow_node_1.default {
112
119
  /* determine voice for text-to-speech operation
113
120
  (for details see https://elevenlabs.io/text-to-speech) */
114
121
  const voices = await this.elevenlabs.voices.getAll();
115
- let voice = voices.voices.find((voice) => voice.name === this.params.voice);
122
+ let voice = voices.voices.find((v) => v.name === this.params.voice);
116
123
  if (voice === undefined) {
117
- voice = voices.voices.find((voice) => voice.name.startsWith(this.params.voice));
124
+ voice = voices.voices.find((v) => (v.name ?? "").startsWith(this.params.voice));
118
125
  if (voice === undefined)
119
126
  throw new Error(`invalid ElevenLabs voice "${this.params.voice}"`);
120
127
  }
121
- const info = Object.keys(voice.labels ?? {}).length > 0 ?
122
- (", " + Object.entries(voice.labels)
123
- .map(([key, val]) => `${key}: "${val}"`).join(", ")) : "";
128
+ const labels = voice.labels ?? {};
129
+ const info = Object.keys(labels).length > 0 ?
130
+ ", " + Object.entries(labels).map(([key, val]) => `${key}: "${val}"`).join(", ") : "";
124
131
  this.log("info", `selected voice: name: "${voice.name}"${info}`);
125
132
  /* perform text-to-speech operation with Elevenlabs API */
126
133
  const model = this.params.optimize === "quality" ?
@@ -160,11 +167,9 @@ class SpeechFlowNodeElevenlabs extends speechflow_node_1.default {
160
167
  decodeStrings: false,
161
168
  highWaterMark: 1,
162
169
  transform(chunk, encoding, callback) {
163
- if (self.destroyed) {
170
+ if (self.destroyed)
164
171
  callback(new Error("stream already destroyed"));
165
- return;
166
- }
167
- if (Buffer.isBuffer(chunk.payload))
172
+ else if (Buffer.isBuffer(chunk.payload))
168
173
  callback(new Error("invalid chunk payload type"));
169
174
  else {
170
175
  (async () => {
@@ -179,12 +184,12 @@ class SpeechFlowNodeElevenlabs extends speechflow_node_1.default {
179
184
  }
180
185
  };
181
186
  try {
182
- const stream = await speechStream(chunk.payload);
183
187
  if (self.destroyed) {
184
188
  clearProcessTimeout();
185
189
  callback(new Error("stream destroyed during processing"));
186
190
  return;
187
191
  }
192
+ const stream = await speechStream(chunk.payload);
188
193
  const buffer = await (0, get_stream_1.getStreamAsBuffer)(stream);
189
194
  if (self.destroyed) {
190
195
  clearProcessTimeout();