speechflow 0.9.8 → 1.0.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 (114) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/LICENSE.txt +674 -0
  3. package/README.md +114 -17
  4. package/dst/speechflow-node-a2a-ffmpeg.js +1 -0
  5. package/dst/speechflow-node-a2a-ffmpeg.js.map +1 -0
  6. package/dst/{speechflow-node-deepl.d.ts → speechflow-node-a2a-meter.d.ts} +2 -2
  7. package/dst/speechflow-node-a2a-meter.js +147 -0
  8. package/dst/speechflow-node-a2a-meter.js.map +1 -0
  9. package/dst/speechflow-node-a2a-mute.d.ts +16 -0
  10. package/dst/speechflow-node-a2a-mute.js +90 -0
  11. package/dst/speechflow-node-a2a-mute.js.map +1 -0
  12. package/dst/{speechflow-node-whisper.d.ts → speechflow-node-a2a-vad.d.ts} +2 -5
  13. package/dst/speechflow-node-a2a-vad.js +272 -0
  14. package/dst/speechflow-node-a2a-vad.js.map +1 -0
  15. package/dst/speechflow-node-a2a-wav.js +1 -0
  16. package/dst/speechflow-node-a2a-wav.js.map +1 -0
  17. package/dst/speechflow-node-a2t-deepgram.js +2 -1
  18. package/dst/speechflow-node-a2t-deepgram.js.map +1 -0
  19. package/dst/speechflow-node-t2a-elevenlabs.js +1 -0
  20. package/dst/speechflow-node-t2a-elevenlabs.js.map +1 -0
  21. package/dst/{speechflow-node-elevenlabs.d.ts → speechflow-node-t2a-kokoro.d.ts} +2 -2
  22. package/dst/speechflow-node-t2a-kokoro.js +148 -0
  23. package/dst/speechflow-node-t2a-kokoro.js.map +1 -0
  24. package/dst/speechflow-node-t2t-deepl.js +1 -0
  25. package/dst/speechflow-node-t2t-deepl.js.map +1 -0
  26. package/dst/speechflow-node-t2t-format.js +1 -0
  27. package/dst/speechflow-node-t2t-format.js.map +1 -0
  28. package/dst/{speechflow-node-gemma.d.ts → speechflow-node-t2t-ollama.d.ts} +1 -1
  29. package/dst/{speechflow-node-gemma.js → speechflow-node-t2t-ollama.js} +41 -8
  30. package/dst/speechflow-node-t2t-ollama.js.map +1 -0
  31. package/dst/{speechflow-node-t2t-gemma.d.ts → speechflow-node-t2t-openai.d.ts} +2 -2
  32. package/dst/{speechflow-node-t2t-gemma.js → speechflow-node-t2t-openai.js} +43 -30
  33. package/dst/speechflow-node-t2t-openai.js.map +1 -0
  34. package/dst/speechflow-node-t2t-subtitle.js +1 -0
  35. package/dst/speechflow-node-t2t-subtitle.js.map +1 -0
  36. package/dst/{speechflow-node-opus.d.ts → speechflow-node-t2t-transformers.d.ts} +3 -1
  37. package/dst/speechflow-node-t2t-transformers.js +264 -0
  38. package/dst/speechflow-node-t2t-transformers.js.map +1 -0
  39. package/dst/speechflow-node-x2x-trace.js +3 -2
  40. package/dst/speechflow-node-x2x-trace.js.map +1 -0
  41. package/dst/speechflow-node-xio-device.js +1 -0
  42. package/dst/speechflow-node-xio-device.js.map +1 -0
  43. package/dst/speechflow-node-xio-file.js +1 -0
  44. package/dst/speechflow-node-xio-file.js.map +1 -0
  45. package/dst/speechflow-node-xio-mqtt.js +1 -0
  46. package/dst/speechflow-node-xio-mqtt.js.map +1 -0
  47. package/dst/speechflow-node-xio-websocket.js +1 -0
  48. package/dst/speechflow-node-xio-websocket.js.map +1 -0
  49. package/dst/speechflow-node.d.ts +3 -0
  50. package/dst/speechflow-node.js +10 -0
  51. package/dst/speechflow-node.js.map +1 -0
  52. package/dst/speechflow-utils.d.ts +33 -0
  53. package/dst/speechflow-utils.js +183 -1
  54. package/dst/speechflow-utils.js.map +1 -0
  55. package/dst/speechflow.js +295 -46
  56. package/dst/speechflow.js.map +1 -0
  57. package/etc/speechflow.yaml +14 -5
  58. package/etc/stx.conf +1 -1
  59. package/etc/tsconfig.json +2 -2
  60. package/package.json +17 -10
  61. package/src/speechflow-node-a2a-meter.ts +125 -0
  62. package/src/speechflow-node-a2a-mute.ts +101 -0
  63. package/src/speechflow-node-a2a-vad.ts +266 -0
  64. package/src/speechflow-node-a2t-deepgram.ts +1 -1
  65. package/src/speechflow-node-t2a-kokoro.ts +160 -0
  66. package/src/{speechflow-node-t2t-gemma.ts → speechflow-node-t2t-ollama.ts} +44 -10
  67. package/src/speechflow-node-t2t-openai.ts +246 -0
  68. package/src/speechflow-node-t2t-transformers.ts +249 -0
  69. package/src/speechflow-node-x2x-trace.ts +2 -2
  70. package/src/speechflow-node-xio-websocket.ts +5 -5
  71. package/src/speechflow-node.ts +12 -0
  72. package/src/speechflow-utils.ts +195 -0
  73. package/src/speechflow.ts +279 -46
  74. package/dst/speechflow-node-deepgram.d.ts +0 -12
  75. package/dst/speechflow-node-deepgram.js +0 -220
  76. package/dst/speechflow-node-deepl.js +0 -128
  77. package/dst/speechflow-node-device.d.ts +0 -13
  78. package/dst/speechflow-node-device.js +0 -205
  79. package/dst/speechflow-node-elevenlabs.js +0 -182
  80. package/dst/speechflow-node-ffmpeg.d.ts +0 -13
  81. package/dst/speechflow-node-ffmpeg.js +0 -152
  82. package/dst/speechflow-node-file.d.ts +0 -11
  83. package/dst/speechflow-node-file.js +0 -176
  84. package/dst/speechflow-node-format.d.ts +0 -11
  85. package/dst/speechflow-node-format.js +0 -80
  86. package/dst/speechflow-node-mqtt.d.ts +0 -13
  87. package/dst/speechflow-node-mqtt.js +0 -181
  88. package/dst/speechflow-node-opus.js +0 -135
  89. package/dst/speechflow-node-subtitle.d.ts +0 -12
  90. package/dst/speechflow-node-subtitle.js +0 -96
  91. package/dst/speechflow-node-t2t-opus.d.ts +0 -12
  92. package/dst/speechflow-node-t2t-opus.js +0 -135
  93. package/dst/speechflow-node-trace.d.ts +0 -11
  94. package/dst/speechflow-node-trace.js +0 -88
  95. package/dst/speechflow-node-wav.d.ts +0 -11
  96. package/dst/speechflow-node-wav.js +0 -170
  97. package/dst/speechflow-node-websocket.d.ts +0 -13
  98. package/dst/speechflow-node-websocket.js +0 -275
  99. package/dst/speechflow-node-whisper-common.d.ts +0 -34
  100. package/dst/speechflow-node-whisper-common.js +0 -7
  101. package/dst/speechflow-node-whisper-ggml.d.ts +0 -1
  102. package/dst/speechflow-node-whisper-ggml.js +0 -97
  103. package/dst/speechflow-node-whisper-onnx.d.ts +0 -1
  104. package/dst/speechflow-node-whisper-onnx.js +0 -131
  105. package/dst/speechflow-node-whisper-worker-ggml.d.ts +0 -1
  106. package/dst/speechflow-node-whisper-worker-ggml.js +0 -97
  107. package/dst/speechflow-node-whisper-worker-onnx.d.ts +0 -1
  108. package/dst/speechflow-node-whisper-worker-onnx.js +0 -131
  109. package/dst/speechflow-node-whisper-worker.d.ts +0 -1
  110. package/dst/speechflow-node-whisper-worker.js +0 -116
  111. package/dst/speechflow-node-whisper-worker2.d.ts +0 -1
  112. package/dst/speechflow-node-whisper-worker2.js +0 -82
  113. package/dst/speechflow-node-whisper.js +0 -604
  114. package/src/speechflow-node-t2t-opus.ts +0 -111
@@ -1,11 +0,0 @@
1
- import SpeechFlowNode from "./speechflow-node";
2
- export default class SpeechFlowNodeWAV extends SpeechFlowNode {
3
- static name: string;
4
- constructor(id: string, cfg: {
5
- [id: string]: any;
6
- }, opts: {
7
- [id: string]: any;
8
- }, args: any[]);
9
- open(): Promise<void>;
10
- close(): Promise<void>;
11
- }
@@ -1,170 +0,0 @@
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 wav_1 = __importDefault(require("wav"));
48
- /* internal dependencies */
49
- const speechflow_node_1 = __importDefault(require("./speechflow-node"));
50
- const utils = __importStar(require("./speechflow-utils"));
51
- /* utility class for wrapping a custom stream into a regular Transform stream */
52
- class StreamWrapper extends node_stream_1.default.Transform {
53
- foreignStream;
54
- constructor(foreignStream, options = {}) {
55
- options.readableObjectMode = true;
56
- options.writableObjectMode = true;
57
- super(options);
58
- this.foreignStream = foreignStream;
59
- this.foreignStream.on("data", (chunk) => {
60
- this.push(chunk);
61
- });
62
- this.foreignStream.on("error", (err) => {
63
- this.emit("error", err);
64
- });
65
- this.foreignStream.on("end", () => {
66
- this.push(null);
67
- });
68
- }
69
- _transform(chunk, encoding, callback) {
70
- try {
71
- const canContinue = this.foreignStream.write(chunk);
72
- if (canContinue)
73
- callback();
74
- else
75
- this.foreignStream.once("drain", callback);
76
- }
77
- catch (err) {
78
- callback(err);
79
- }
80
- }
81
- _flush(callback) {
82
- try {
83
- if (typeof this.foreignStream.end === "function")
84
- this.foreignStream.end();
85
- callback();
86
- }
87
- catch (err) {
88
- callback(err);
89
- }
90
- }
91
- }
92
- /* SpeechFlow node for WAV format conversion */
93
- class SpeechFlowNodeWAV extends speechflow_node_1.default {
94
- /* declare official node name */
95
- static name = "wav";
96
- /* construct node */
97
- constructor(id, cfg, opts, args) {
98
- super(id, cfg, opts, args);
99
- /* declare node configuration parameters */
100
- this.configure({
101
- mode: { type: "string", pos: 1, val: "encode", match: /^(?:encode|decode)$/ }
102
- });
103
- /* declare node input/output format */
104
- this.input = "audio";
105
- this.output = "audio";
106
- }
107
- /* open node */
108
- async open() {
109
- if (this.params.mode === "encode") {
110
- /* convert raw/PCM to WAV/PCM */
111
- /* NOTICE: as this is a continuous stream, the resulting WAV header is not 100%
112
- conforming to the WAV standard, as it has to use a zero duration information.
113
- This cannot be changed in a stream-based processing. */
114
- const writer = new wav_1.default.Writer({
115
- format: 0x0001 /* PCM */,
116
- channels: this.config.audioChannels,
117
- sampleRate: this.config.audioSampleRate,
118
- bitDepth: this.config.audioBitDepth
119
- });
120
- this.stream = new StreamWrapper(writer);
121
- }
122
- else if (this.params.mode === "decode") {
123
- /* convert WAV/PCM to raw/PCM */
124
- const reader = new wav_1.default.Reader();
125
- reader.on("format", (format) => {
126
- this.log("info", `WAV audio stream: format=${format.audioFormat === 0x0001 ? "PCM" :
127
- "0x" + format.audioFormat.toString(16).padStart(4, "0")} ` +
128
- `bitDepth=${format.bitDepth} ` +
129
- `signed=${format.signed ? "yes" : "no"} ` +
130
- `endian=${format.endianness} ` +
131
- `sampleRate=${format.sampleRate} ` +
132
- `channels=${format.channels}`);
133
- if (format.audioFormat !== 0x0001 /* PCM */)
134
- throw new Error("WAV not based on PCM format");
135
- if (format.bitDepth !== 16)
136
- throw new Error("WAV not based on 16 bit samples");
137
- if (!format.signed)
138
- throw new Error("WAV not based on signed integers");
139
- if (format.endianness !== "LE")
140
- throw new Error("WAV not based on little endianness");
141
- if (format.sampleRate !== 48000)
142
- throw new Error("WAV not based on 48Khz sample rate");
143
- if (format.channels !== 1)
144
- throw new Error("WAV not based on mono channel");
145
- });
146
- this.stream = new StreamWrapper(reader);
147
- }
148
- else
149
- throw new Error(`invalid operation mode "${this.params.mode}"`);
150
- /* convert regular stream into object-mode stream */
151
- const wrapper1 = utils.createTransformStreamForWritableSide();
152
- const wrapper2 = utils.createTransformStreamForReadableSide("audio", () => this.timeZero);
153
- this.stream = node_stream_1.default.compose(wrapper1, this.stream, wrapper2);
154
- }
155
- /* close node */
156
- async close() {
157
- /* shutdown stream */
158
- if (this.stream !== null) {
159
- await new Promise((resolve) => {
160
- if (this.stream instanceof node_stream_1.default.Duplex)
161
- this.stream.end(() => { resolve(); });
162
- else
163
- resolve();
164
- });
165
- this.stream.destroy();
166
- this.stream = null;
167
- }
168
- }
169
- }
170
- exports.default = SpeechFlowNodeWAV;
@@ -1,13 +0,0 @@
1
- import SpeechFlowNode from "./speechflow-node";
2
- export default class SpeechFlowNodeWebsocket extends SpeechFlowNode {
3
- static name: string;
4
- private server;
5
- private client;
6
- constructor(id: string, cfg: {
7
- [id: string]: any;
8
- }, opts: {
9
- [id: string]: any;
10
- }, args: any[]);
11
- open(): Promise<void>;
12
- close(): Promise<void>;
13
- }
@@ -1,275 +0,0 @@
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 ws_1 = __importDefault(require("ws"));
48
- const reconnecting_websocket_1 = __importDefault(require("@opensumi/reconnecting-websocket"));
49
- /* internal dependencies */
50
- const speechflow_node_1 = __importDefault(require("./speechflow-node"));
51
- const utils = __importStar(require("./speechflow-utils"));
52
- /* SpeechFlow node for Websocket networking */
53
- class SpeechFlowNodeWebsocket extends speechflow_node_1.default {
54
- /* declare official node name */
55
- static name = "websocket";
56
- /* internal state */
57
- server = null;
58
- client = null;
59
- /* construct node */
60
- constructor(id, cfg, opts, args) {
61
- super(id, cfg, opts, args);
62
- /* declare node configuration parameters */
63
- this.configure({
64
- listen: { type: "string", val: "", match: /^(?:|ws:\/\/(.+?):(\d+))$/ },
65
- connect: { type: "string", val: "", match: /^(?:|ws:\/\/(.+?):(\d+)(?:\/.*)?)$/ },
66
- mode: { type: "string", val: "r", match: /^(?:r|w|rw)$/ },
67
- type: { type: "string", val: "text", match: /^(?:audio|text)$/ }
68
- });
69
- /* sanity check usage */
70
- if (this.params.listen !== "" && this.params.connect !== "")
71
- throw new Error("Websocket node cannot listen and connect at the same time");
72
- else if (this.params.listen === "" && this.params.connect === "")
73
- throw new Error("Websocket node requires either listen or connect mode");
74
- /* declare node input/output format */
75
- if (this.params.mode === "rw") {
76
- this.input = this.params.type;
77
- this.output = this.params.type;
78
- }
79
- else if (this.params.mode === "r") {
80
- this.input = "none";
81
- this.output = this.params.type;
82
- }
83
- else if (this.params.mode === "w") {
84
- this.input = this.params.type;
85
- this.output = "none";
86
- }
87
- }
88
- /* open node */
89
- async open() {
90
- if (this.params.listen !== "") {
91
- /* listen locally on a Websocket port */
92
- const url = new URL(this.params.listen);
93
- const websockets = new Set();
94
- const chunkQueue = new utils.SingleQueue();
95
- const server = new ws_1.default.WebSocketServer({
96
- host: url.hostname,
97
- port: Number.parseInt(url.port),
98
- path: url.pathname
99
- });
100
- server.on("listening", () => {
101
- this.log("info", `listening on URL ${this.params.listen}`);
102
- });
103
- server.on("connection", (ws, request) => {
104
- const peer = `${request.socket.remoteAddress}:${request.socket.remotePort}`;
105
- this.log("info", `connection opened on URL ${this.params.listen} by peer ${peer}`);
106
- websockets.add(ws);
107
- ws.on("close", () => {
108
- this.log("info", `connection closed on URL ${this.params.listen} by peer ${peer}`);
109
- websockets.delete(ws);
110
- });
111
- ws.on("error", (error) => {
112
- this.log("error", `error of connection on URL ${this.params.listen} for peer ${peer}: ${error.message}`);
113
- });
114
- ws.on("message", (data, isBinary) => {
115
- if (this.params.mode === "w") {
116
- this.log("warning", `connection on URL ${this.params.listen} by peer ${peer}: ` +
117
- "received remote data on write-only node");
118
- return;
119
- }
120
- if (!isBinary) {
121
- this.log("warning", `connection on URL ${this.params.listen} by peer ${peer}: ` +
122
- "received non-binary message");
123
- return;
124
- }
125
- let buffer;
126
- if (Buffer.isBuffer(data))
127
- buffer = data;
128
- else if (data instanceof ArrayBuffer)
129
- buffer = Buffer.from(data);
130
- else
131
- buffer = Buffer.concat(data);
132
- const chunk = utils.streamChunkDecode(buffer);
133
- chunkQueue.write(chunk);
134
- });
135
- });
136
- server.on("error", (error) => {
137
- this.log("error", `error of some connection on URL ${this.params.listen}: ${error.message}`);
138
- });
139
- const type = this.params.type;
140
- const mode = this.params.mode;
141
- this.stream = new node_stream_1.default.Duplex({
142
- writableObjectMode: true,
143
- readableObjectMode: true,
144
- decodeStrings: false,
145
- write(chunk, encoding, callback) {
146
- if (mode === "r")
147
- callback(new Error("write operation on read-only node"));
148
- else if (chunk.type !== type)
149
- callback(new Error(`written chunk is not of ${type} type`));
150
- else if (websockets.size === 0)
151
- callback(new Error("still no Websocket connections available"));
152
- else {
153
- const data = utils.streamChunkEncode(chunk);
154
- const results = [];
155
- for (const websocket of websockets.values()) {
156
- results.push(new Promise((resolve, reject) => {
157
- websocket.send(data, (error) => {
158
- if (error)
159
- reject(error);
160
- else
161
- resolve();
162
- });
163
- }));
164
- }
165
- Promise.all(results).then(() => {
166
- callback();
167
- }).catch((errors) => {
168
- const error = new Error(errors.map((e) => e.message).join("; "));
169
- callback(error);
170
- });
171
- }
172
- },
173
- read(size) {
174
- if (mode === "w")
175
- throw new Error("read operation on write-only node");
176
- chunkQueue.read().then((chunk) => {
177
- this.push(chunk, "binary");
178
- });
179
- }
180
- });
181
- }
182
- else if (this.params.connect !== "") {
183
- /* connect remotely to a Websocket port */
184
- this.client = new reconnecting_websocket_1.default(this.params.connect, [], {
185
- WebSocket: ws_1.default,
186
- WebSocketOptions: {},
187
- reconnectionDelayGrowFactor: 1.3,
188
- maxReconnectionDelay: 4000,
189
- minReconnectionDelay: 1000,
190
- connectionTimeout: 4000,
191
- minUptime: 5000
192
- });
193
- this.client.addEventListener("open", (ev) => {
194
- this.log("info", `connection opened to URL ${this.params.connect}`);
195
- });
196
- this.client.addEventListener("close", (ev) => {
197
- this.log("info", `connection closed to URL ${this.params.connect}`);
198
- });
199
- this.client.addEventListener("error", (ev) => {
200
- this.log("error", `error of connection on URL ${this.params.connect}: ${ev.error.message}`);
201
- });
202
- const chunkQueue = new utils.SingleQueue();
203
- this.client.addEventListener("message", (ev) => {
204
- if (this.params.mode === "w") {
205
- this.log("warning", `connection to URL ${this.params.listen}: ` +
206
- "received remote data on write-only node");
207
- return;
208
- }
209
- if (!(ev.data instanceof ArrayBuffer)) {
210
- this.log("warning", `connection to URL ${this.params.listen}: ` +
211
- "received non-binary message");
212
- return;
213
- }
214
- const buffer = Buffer.from(ev.data);
215
- const chunk = utils.streamChunkDecode(buffer);
216
- chunkQueue.write(chunk);
217
- });
218
- const client = this.client;
219
- client.binaryType = "arraybuffer";
220
- const type = this.params.type;
221
- const mode = this.params.mode;
222
- this.stream = new node_stream_1.default.Duplex({
223
- writableObjectMode: true,
224
- readableObjectMode: true,
225
- decodeStrings: false,
226
- write(chunk, encoding, callback) {
227
- if (mode === "r")
228
- callback(new Error("write operation on read-only node"));
229
- else if (chunk.type !== type)
230
- callback(new Error(`written chunk is not of ${type} type`));
231
- else if (!client.OPEN)
232
- callback(new Error("still no Websocket connection available"));
233
- const data = utils.streamChunkEncode(chunk);
234
- client.send(data);
235
- callback();
236
- },
237
- read(size) {
238
- if (mode === "w")
239
- throw new Error("read operation on write-only node");
240
- if (!client.OPEN)
241
- throw new Error("still no Websocket connection available");
242
- chunkQueue.read().then((chunk) => {
243
- this.push(chunk, "binary");
244
- });
245
- }
246
- });
247
- }
248
- }
249
- /* close node */
250
- async close() {
251
- /* close Websocket server */
252
- if (this.server !== null) {
253
- await new Promise((resolve, reject) => {
254
- this.server.close((error) => {
255
- if (error)
256
- reject(error);
257
- else
258
- resolve();
259
- });
260
- });
261
- this.server = null;
262
- }
263
- /* close Websocket client */
264
- if (this.client !== null) {
265
- this.client.close();
266
- this.client = null;
267
- }
268
- /* close stream */
269
- if (this.stream !== null) {
270
- this.stream.destroy();
271
- this.stream = null;
272
- }
273
- }
274
- }
275
- exports.default = SpeechFlowNodeWebsocket;
@@ -1,34 +0,0 @@
1
- export type TranscriptionTaskRequest = {
2
- type: "intermediate" | "final";
3
- id: number;
4
- language: string;
5
- audio: Float32Array;
6
- };
7
- export type TranscriptionTaskResponse = {
8
- type: "intermediate" | "final";
9
- id: number;
10
- language: string;
11
- text: string;
12
- };
13
- export type WorkerRequest = {
14
- type: "open";
15
- cacheDir: string;
16
- model: string;
17
- } | {
18
- type: "task-request";
19
- task: TranscriptionTaskRequest;
20
- } | {
21
- type: "close";
22
- };
23
- export type WorkerResponse = {
24
- type: "log";
25
- message: string;
26
- } | {
27
- type: "error";
28
- message: string;
29
- } | {
30
- type: "ok";
31
- } | {
32
- type: "task-response";
33
- task: TranscriptionTaskResponse;
34
- };
@@ -1,7 +0,0 @@
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
- Object.defineProperty(exports, "__esModule", { value: true });
@@ -1 +0,0 @@
1
- export {};
@@ -1,97 +0,0 @@
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_worker_threads_1 = __importDefault(require("node:worker_threads"));
13
- /* external dependencies */
14
- const smart_whisper_1 = require("smart-whisper");
15
- /* utility function for sending a log message */
16
- const log = (message) => node_worker_threads_1.default.parentPort.postMessage({ type: "log", message });
17
- /* internal state */
18
- let whisper = null;
19
- /* OpenAI Whisper models (GGML variants for Whisper.cpp) */
20
- const models = {
21
- "v1-tiny": { model: "tiny" },
22
- "v1-base": { model: "base" },
23
- "v1-small": { model: "small" },
24
- "v1-medium": { model: "medium" },
25
- "v2-large": { model: "large-v2" },
26
- "v3-large": { model: "large-v3" },
27
- "v3-large-turbo": { model: "large-v3-turbo" }
28
- };
29
- /* thread communication hook */
30
- node_worker_threads_1.default.parentPort?.on("message", async (request) => {
31
- let response = null;
32
- if (request.type === "open") {
33
- /* initialize Whisper */
34
- const model = models[request.model]?.model;
35
- if (!model)
36
- response = { type: "error", message: `unknown Whisper model "${request.model}"` };
37
- else {
38
- log(`loading Whisper model "${request.model}": BEGIN`);
39
- const name = await smart_whisper_1.manager.download(model);
40
- const resolved = smart_whisper_1.manager.resolve(name);
41
- whisper = new smart_whisper_1.Whisper(resolved, {
42
- gpu: true,
43
- offload: 120 * 60
44
- });
45
- if (whisper === null) {
46
- log(`loading Whisper model "${request.model}": FAILED`);
47
- response = { type: "error", message: "failed to open Whisper" };
48
- }
49
- else {
50
- await whisper.load();
51
- log(`loading Whisper model "${request.model}": SUCCESS`);
52
- response = { type: "ok" };
53
- }
54
- }
55
- }
56
- else if (request.type === "task-request") {
57
- log(`${request.task.type} transcription task ${request.task.id}": START`);
58
- const task = await whisper.transcribe(request.task.audio, {
59
- language: request.task.language,
60
- n_threads: 16,
61
- no_timestamps: false,
62
- speed_up: true,
63
- suppress_non_speech_tokens: true,
64
- suppress_blank: true,
65
- debug_mode: false,
66
- print_special: false,
67
- print_progress: false,
68
- print_realtime: false,
69
- print_timestamps: false
70
- });
71
- task.on("transcribed", (result) => {
72
- console.log("TRANSCRIBED", JSON.stringify(result));
73
- });
74
- const result = await task.result;
75
- log(`${request.task.type} transcription task ${request.task.id}": END`);
76
- console.log("RESULT", result);
77
- const text = result[0].text;
78
- const taskResponse = {
79
- type: request.task.type,
80
- id: request.task.id,
81
- language: request.task.language,
82
- text: text ?? ""
83
- };
84
- response = { type: "task-response", task: taskResponse };
85
- }
86
- else if (request.type === "close") {
87
- /* shutdown Whisper */
88
- if (whisper !== null) {
89
- log("unloading Whisper model: BEGIN");
90
- await whisper.free();
91
- whisper = null;
92
- log("unloading Whisper model: END");
93
- }
94
- }
95
- if (response !== null)
96
- node_worker_threads_1.default.parentPort.postMessage(response);
97
- });
@@ -1 +0,0 @@
1
- export {};