speechflow 0.9.9 → 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.
- package/CHANGELOG.md +8 -0
- package/README.md +48 -1
- package/dst/speechflow-node-a2a-ffmpeg.js +1 -0
- package/dst/speechflow-node-a2a-ffmpeg.js.map +1 -0
- package/dst/{speechflow-node-gemma.d.ts → speechflow-node-a2a-meter.d.ts} +2 -3
- package/dst/speechflow-node-a2a-meter.js +147 -0
- package/dst/speechflow-node-a2a-meter.js.map +1 -0
- package/dst/speechflow-node-a2a-mute.d.ts +16 -0
- package/dst/speechflow-node-a2a-mute.js +90 -0
- package/dst/speechflow-node-a2a-mute.js.map +1 -0
- package/dst/speechflow-node-a2a-vad.js +130 -289
- package/dst/speechflow-node-a2a-vad.js.map +1 -0
- package/dst/speechflow-node-a2a-wav.js +1 -0
- package/dst/speechflow-node-a2a-wav.js.map +1 -0
- package/dst/speechflow-node-a2t-deepgram.js +2 -1
- package/dst/speechflow-node-a2t-deepgram.js.map +1 -0
- package/dst/speechflow-node-t2a-elevenlabs.js +1 -0
- package/dst/speechflow-node-t2a-elevenlabs.js.map +1 -0
- package/dst/speechflow-node-t2a-kokoro.js +1 -0
- package/dst/speechflow-node-t2a-kokoro.js.map +1 -0
- package/dst/speechflow-node-t2t-deepl.js +1 -0
- package/dst/speechflow-node-t2t-deepl.js.map +1 -0
- package/dst/speechflow-node-t2t-format.js +1 -0
- package/dst/speechflow-node-t2t-format.js.map +1 -0
- package/dst/speechflow-node-t2t-ollama.js +1 -0
- package/dst/speechflow-node-t2t-ollama.js.map +1 -0
- package/dst/speechflow-node-t2t-openai.js +1 -0
- package/dst/speechflow-node-t2t-openai.js.map +1 -0
- package/dst/speechflow-node-t2t-subtitle.js +1 -0
- package/dst/speechflow-node-t2t-subtitle.js.map +1 -0
- package/dst/speechflow-node-t2t-transformers.js +10 -6
- package/dst/speechflow-node-t2t-transformers.js.map +1 -0
- package/dst/speechflow-node-x2x-trace.js +1 -0
- package/dst/speechflow-node-x2x-trace.js.map +1 -0
- package/dst/speechflow-node-xio-device.js +1 -0
- package/dst/speechflow-node-xio-device.js.map +1 -0
- package/dst/speechflow-node-xio-file.js +1 -0
- package/dst/speechflow-node-xio-file.js.map +1 -0
- package/dst/speechflow-node-xio-mqtt.js +1 -0
- package/dst/speechflow-node-xio-mqtt.js.map +1 -0
- package/dst/speechflow-node-xio-websocket.js +1 -0
- package/dst/speechflow-node-xio-websocket.js.map +1 -0
- package/dst/speechflow-node.d.ts +3 -0
- package/dst/speechflow-node.js +10 -0
- package/dst/speechflow-node.js.map +1 -0
- package/dst/speechflow-utils.d.ts +33 -0
- package/dst/speechflow-utils.js +183 -1
- package/dst/speechflow-utils.js.map +1 -0
- package/dst/speechflow.js +209 -6
- package/dst/speechflow.js.map +1 -0
- package/etc/speechflow.yaml +5 -3
- package/etc/stx.conf +1 -1
- package/etc/tsconfig.json +2 -2
- package/package.json +14 -8
- package/src/speechflow-node-a2a-meter.ts +125 -0
- package/src/speechflow-node-a2a-mute.ts +101 -0
- package/src/speechflow-node-a2a-vad.ts +266 -0
- package/src/speechflow-node-a2t-deepgram.ts +1 -1
- package/src/speechflow-node-t2t-transformers.ts +12 -7
- package/src/speechflow-node-xio-websocket.ts +5 -5
- package/src/speechflow-node.ts +12 -0
- package/src/speechflow-utils.ts +195 -0
- package/src/speechflow.ts +193 -6
- package/dst/speechflow-node-deepgram.d.ts +0 -12
- package/dst/speechflow-node-deepgram.js +0 -220
- package/dst/speechflow-node-deepl.d.ts +0 -12
- package/dst/speechflow-node-deepl.js +0 -128
- package/dst/speechflow-node-device.d.ts +0 -13
- package/dst/speechflow-node-device.js +0 -205
- package/dst/speechflow-node-elevenlabs.d.ts +0 -13
- package/dst/speechflow-node-elevenlabs.js +0 -182
- package/dst/speechflow-node-ffmpeg.d.ts +0 -13
- package/dst/speechflow-node-ffmpeg.js +0 -152
- package/dst/speechflow-node-file.d.ts +0 -11
- package/dst/speechflow-node-file.js +0 -176
- package/dst/speechflow-node-format.d.ts +0 -11
- package/dst/speechflow-node-format.js +0 -80
- package/dst/speechflow-node-gemma.js +0 -213
- package/dst/speechflow-node-mqtt.d.ts +0 -13
- package/dst/speechflow-node-mqtt.js +0 -181
- package/dst/speechflow-node-opus.d.ts +0 -12
- package/dst/speechflow-node-opus.js +0 -135
- package/dst/speechflow-node-subtitle.d.ts +0 -12
- package/dst/speechflow-node-subtitle.js +0 -96
- package/dst/speechflow-node-t2t-gemma.d.ts +0 -13
- package/dst/speechflow-node-t2t-gemma.js +0 -233
- package/dst/speechflow-node-t2t-opus.d.ts +0 -12
- package/dst/speechflow-node-t2t-opus.js +0 -135
- package/dst/speechflow-node-trace.d.ts +0 -11
- package/dst/speechflow-node-trace.js +0 -88
- package/dst/speechflow-node-wav.d.ts +0 -11
- package/dst/speechflow-node-wav.js +0 -170
- package/dst/speechflow-node-websocket.d.ts +0 -13
- package/dst/speechflow-node-websocket.js +0 -275
- package/dst/speechflow-node-whisper-common.d.ts +0 -34
- package/dst/speechflow-node-whisper-common.js +0 -7
- package/dst/speechflow-node-whisper-ggml.d.ts +0 -1
- package/dst/speechflow-node-whisper-ggml.js +0 -97
- package/dst/speechflow-node-whisper-onnx.d.ts +0 -1
- package/dst/speechflow-node-whisper-onnx.js +0 -131
- package/dst/speechflow-node-whisper-worker-ggml.d.ts +0 -1
- package/dst/speechflow-node-whisper-worker-ggml.js +0 -97
- package/dst/speechflow-node-whisper-worker-onnx.d.ts +0 -1
- package/dst/speechflow-node-whisper-worker-onnx.js +0 -131
- package/dst/speechflow-node-whisper-worker.d.ts +0 -1
- package/dst/speechflow-node-whisper-worker.js +0 -116
- package/dst/speechflow-node-whisper-worker2.d.ts +0 -1
- package/dst/speechflow-node-whisper-worker2.js +0 -82
- package/dst/speechflow-node-whisper.d.ts +0 -19
- package/dst/speechflow-node-whisper.js +0 -604
|
@@ -1,182 +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 ElevenLabs = __importStar(require("@elevenlabs/elevenlabs-js"));
|
|
48
|
-
const get_stream_1 = require("get-stream");
|
|
49
|
-
const speex_resampler_1 = __importDefault(require("speex-resampler"));
|
|
50
|
-
/* internal dependencies */
|
|
51
|
-
const speechflow_node_1 = __importDefault(require("./speechflow-node"));
|
|
52
|
-
/* SpeechFlow node for Elevenlabs text-to-speech conversion */
|
|
53
|
-
class SpeechFlowNodeElevenlabs extends speechflow_node_1.default {
|
|
54
|
-
/* declare official node name */
|
|
55
|
-
static name = "elevenlabs";
|
|
56
|
-
/* internal state */
|
|
57
|
-
elevenlabs = null;
|
|
58
|
-
static speexInitialized = false;
|
|
59
|
-
/* construct node */
|
|
60
|
-
constructor(id, cfg, opts, args) {
|
|
61
|
-
super(id, cfg, opts, args);
|
|
62
|
-
/* declare node configuration parameters */
|
|
63
|
-
this.configure({
|
|
64
|
-
key: { type: "string", val: process.env.SPEECHFLOW_KEY_ELEVENLABS },
|
|
65
|
-
voice: { type: "string", val: "Brian", pos: 0, match: /^(?:.+)$/ },
|
|
66
|
-
language: { type: "string", val: "en", pos: 1, match: /^(?:de|en)$/ },
|
|
67
|
-
speed: { type: "number", val: 1.05, pos: 2, match: (n) => n >= 0.7 && n <= 1.2 },
|
|
68
|
-
optimize: { type: "string", val: "latency", pos: 3, match: /^(?:latency|quality)$/ }
|
|
69
|
-
});
|
|
70
|
-
/* declare node input/output format */
|
|
71
|
-
this.input = "text";
|
|
72
|
-
this.output = "audio";
|
|
73
|
-
}
|
|
74
|
-
/* open node */
|
|
75
|
-
async open() {
|
|
76
|
-
/* establish ElevenLabs API connection */
|
|
77
|
-
this.elevenlabs = new ElevenLabs.ElevenLabsClient({
|
|
78
|
-
apiKey: this.params.key
|
|
79
|
-
});
|
|
80
|
-
/* determine maximum sample rate of ElevenLabs tier */
|
|
81
|
-
const maxSampleRates = {
|
|
82
|
-
"free": 16000,
|
|
83
|
-
"starter": 22050,
|
|
84
|
-
"creator": 24000,
|
|
85
|
-
"independent_publisher": 44100,
|
|
86
|
-
"growing_business": 44100,
|
|
87
|
-
"enterprise": 44100
|
|
88
|
-
};
|
|
89
|
-
const sub = await this.elevenlabs.user.subscription.get();
|
|
90
|
-
const tier = (sub.tier ?? "free");
|
|
91
|
-
this.log("info", `determined ElevenLabs tier: "${tier}"`);
|
|
92
|
-
let maxSampleRate = 16000;
|
|
93
|
-
if (maxSampleRates[tier] !== undefined)
|
|
94
|
-
maxSampleRate = maxSampleRates[tier];
|
|
95
|
-
this.log("info", `determined maximum audio sample rate: ${maxSampleRate}`);
|
|
96
|
-
/* determine voice for text-to-speech operation
|
|
97
|
-
(for details see https://elevenlabs.io/text-to-speech) */
|
|
98
|
-
const voices = await this.elevenlabs.voices.getAll();
|
|
99
|
-
let voice = voices.voices.find((voice) => voice.name === this.params.voice);
|
|
100
|
-
if (voice === undefined) {
|
|
101
|
-
voice = voices.voices.find((voice) => voice.name.startsWith(this.params.voice));
|
|
102
|
-
if (voice === undefined)
|
|
103
|
-
throw new Error(`invalid ElevenLabs voice "${this.params.voice}"`);
|
|
104
|
-
}
|
|
105
|
-
const info = Object.keys(voice.labels ?? {}).length > 0 ?
|
|
106
|
-
(", " + Object.entries(voice.labels)
|
|
107
|
-
.map(([key, val]) => `${key}: "${val}"`).join(", ")) : "";
|
|
108
|
-
this.log("info", `selected voice: name: "${voice.name}"${info}`);
|
|
109
|
-
/* perform text-to-speech operation with Elevenlabs API */
|
|
110
|
-
const model = this.params.optimize === "quality" ?
|
|
111
|
-
"eleven_multilingual_v2" :
|
|
112
|
-
"eleven_flash_v2_5";
|
|
113
|
-
const speechStream = (text) => {
|
|
114
|
-
this.log("info", `ElevenLabs: send text "${text}"`);
|
|
115
|
-
return this.elevenlabs.textToSpeech.convert(voice.voiceId, {
|
|
116
|
-
text,
|
|
117
|
-
modelId: model,
|
|
118
|
-
languageCode: this.params.language,
|
|
119
|
-
outputFormat: `pcm_${maxSampleRate}`,
|
|
120
|
-
seed: 815, /* arbitrary, but fixated by us */
|
|
121
|
-
voiceSettings: {
|
|
122
|
-
speed: this.params.speed
|
|
123
|
-
}
|
|
124
|
-
}, {
|
|
125
|
-
timeoutInSeconds: 30,
|
|
126
|
-
maxRetries: 10
|
|
127
|
-
});
|
|
128
|
-
};
|
|
129
|
-
/* establish resampler from ElevenLabs's maximum 24Khz
|
|
130
|
-
output to our standard audio sample rate (48KHz) */
|
|
131
|
-
if (!SpeechFlowNodeElevenlabs.speexInitialized) {
|
|
132
|
-
/* at least once initialize resampler */
|
|
133
|
-
await speex_resampler_1.default.initPromise;
|
|
134
|
-
SpeechFlowNodeElevenlabs.speexInitialized = true;
|
|
135
|
-
}
|
|
136
|
-
const resampler = new speex_resampler_1.default(1, maxSampleRate, this.config.audioSampleRate, 7);
|
|
137
|
-
/* create transform stream and connect it to the ElevenLabs API */
|
|
138
|
-
const log = (level, msg) => { this.log(level, msg); };
|
|
139
|
-
this.stream = new node_stream_1.default.Transform({
|
|
140
|
-
writableObjectMode: true,
|
|
141
|
-
readableObjectMode: true,
|
|
142
|
-
decodeStrings: false,
|
|
143
|
-
transform(chunk, encoding, callback) {
|
|
144
|
-
if (Buffer.isBuffer(chunk.payload))
|
|
145
|
-
callback(new Error("invalid chunk payload type"));
|
|
146
|
-
else {
|
|
147
|
-
speechStream(chunk.payload).then((stream) => {
|
|
148
|
-
(0, get_stream_1.getStreamAsBuffer)(stream).then((buffer) => {
|
|
149
|
-
const bufferResampled = resampler.processChunk(buffer);
|
|
150
|
-
log("info", `ElevenLabs: received audio (buffer length: ${buffer.byteLength})`);
|
|
151
|
-
const chunkNew = chunk.clone();
|
|
152
|
-
chunkNew.type = "audio";
|
|
153
|
-
chunkNew.payload = bufferResampled;
|
|
154
|
-
this.push(chunkNew);
|
|
155
|
-
callback();
|
|
156
|
-
}).catch((error) => {
|
|
157
|
-
callback(error);
|
|
158
|
-
});
|
|
159
|
-
}).catch((error) => {
|
|
160
|
-
callback(error);
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
},
|
|
164
|
-
final(callback) {
|
|
165
|
-
this.push(null);
|
|
166
|
-
callback();
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
/* close node */
|
|
171
|
-
async close() {
|
|
172
|
-
/* destroy stream */
|
|
173
|
-
if (this.stream !== null) {
|
|
174
|
-
this.stream.destroy();
|
|
175
|
-
this.stream = null;
|
|
176
|
-
}
|
|
177
|
-
/* destroy ElevenLabs API */
|
|
178
|
-
if (this.elevenlabs !== null)
|
|
179
|
-
this.elevenlabs = null;
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
exports.default = SpeechFlowNodeElevenlabs;
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import SpeechFlowNode from "./speechflow-node";
|
|
2
|
-
export default class SpeechFlowNodeFFmpeg extends SpeechFlowNode {
|
|
3
|
-
static name: string;
|
|
4
|
-
private ffmpegBinary;
|
|
5
|
-
private ffmpeg;
|
|
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,152 +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 ffmpeg_1 = __importDefault(require("@rse/ffmpeg"));
|
|
48
|
-
const ffmpeg_stream_1 = require("ffmpeg-stream");
|
|
49
|
-
/* internal dependencies */
|
|
50
|
-
const speechflow_node_1 = __importDefault(require("./speechflow-node"));
|
|
51
|
-
const utils = __importStar(require("./speechflow-utils"));
|
|
52
|
-
/* SpeechFlow node for FFmpeg */
|
|
53
|
-
class SpeechFlowNodeFFmpeg extends speechflow_node_1.default {
|
|
54
|
-
/* declare official node name */
|
|
55
|
-
static name = "ffmpeg";
|
|
56
|
-
/* internal state */
|
|
57
|
-
ffmpegBinary = ffmpeg_1.default.supported ? ffmpeg_1.default.binary : "ffmpeg";
|
|
58
|
-
ffmpeg = 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
|
-
src: { type: "string", pos: 0, val: "pcm", match: /^(?:pcm|wav|mp3|opus)$/ },
|
|
65
|
-
dst: { type: "string", pos: 1, val: "wav", match: /^(?:pcm|wav|mp3|opus)$/ }
|
|
66
|
-
});
|
|
67
|
-
/* declare node input/output format */
|
|
68
|
-
this.input = "audio";
|
|
69
|
-
this.output = "audio";
|
|
70
|
-
}
|
|
71
|
-
/* open node */
|
|
72
|
-
async open() {
|
|
73
|
-
/* sanity check situation */
|
|
74
|
-
if (this.params.src === this.params.dst)
|
|
75
|
-
throw new Error("source and destination formats should not be the same");
|
|
76
|
-
/* instantiate FFmpeg sub-process */
|
|
77
|
-
this.ffmpeg = new ffmpeg_stream_1.Converter(this.ffmpegBinary);
|
|
78
|
-
const streamInput = this.ffmpeg.createInputStream({
|
|
79
|
-
/* FFmpeg input options */
|
|
80
|
-
"fflags": "nobuffer",
|
|
81
|
-
"flags": "low_delay",
|
|
82
|
-
"probesize": 32,
|
|
83
|
-
"analyzeduration": 0,
|
|
84
|
-
...(this.params.src === "pcm" ? {
|
|
85
|
-
"f": "s16le",
|
|
86
|
-
"ar": this.config.audioSampleRate,
|
|
87
|
-
"ac": this.config.audioChannels
|
|
88
|
-
} : {}),
|
|
89
|
-
...(this.params.src === "wav" ? {
|
|
90
|
-
"f": "wav"
|
|
91
|
-
} : {}),
|
|
92
|
-
...(this.params.src === "mp3" ? {
|
|
93
|
-
"f": "mp3"
|
|
94
|
-
} : {}),
|
|
95
|
-
...(this.params.src === "opus" ? {
|
|
96
|
-
"f": "opus"
|
|
97
|
-
} : {})
|
|
98
|
-
});
|
|
99
|
-
const streamOutput = this.ffmpeg.createOutputStream({
|
|
100
|
-
/* FFmpeg output options */
|
|
101
|
-
"flush_packets": 1,
|
|
102
|
-
...(this.params.dst === "pcm" ? {
|
|
103
|
-
"c:a": "pcm_s16le",
|
|
104
|
-
"ar": this.config.audioSampleRate,
|
|
105
|
-
"ac": this.config.audioChannels,
|
|
106
|
-
"f": "s16le",
|
|
107
|
-
} : {}),
|
|
108
|
-
...(this.params.dst === "wav" ? {
|
|
109
|
-
"f": "wav"
|
|
110
|
-
} : {}),
|
|
111
|
-
...(this.params.dst === "mp3" ? {
|
|
112
|
-
"c:a": "libmp3lame",
|
|
113
|
-
"b:a": "192k",
|
|
114
|
-
"f": "mp3"
|
|
115
|
-
} : {}),
|
|
116
|
-
...(this.params.dst === "opus" ? {
|
|
117
|
-
"acodec": "libopus",
|
|
118
|
-
"f": "opus"
|
|
119
|
-
} : {})
|
|
120
|
-
});
|
|
121
|
-
this.ffmpeg.run();
|
|
122
|
-
/* establish a duplex stream and connect it to FFmpeg */
|
|
123
|
-
this.stream = node_stream_1.default.Duplex.from({
|
|
124
|
-
writable: streamInput,
|
|
125
|
-
readable: streamOutput
|
|
126
|
-
});
|
|
127
|
-
/* wrap streams with conversions for chunk vs plain audio */
|
|
128
|
-
const wrapper1 = utils.createTransformStreamForWritableSide();
|
|
129
|
-
const wrapper2 = utils.createTransformStreamForReadableSide("audio", () => this.timeZero);
|
|
130
|
-
this.stream = node_stream_1.default.compose(wrapper1, this.stream, wrapper2);
|
|
131
|
-
}
|
|
132
|
-
/* close node */
|
|
133
|
-
async close() {
|
|
134
|
-
/* close duplex stream */
|
|
135
|
-
if (this.stream !== null) {
|
|
136
|
-
await new Promise((resolve) => {
|
|
137
|
-
if (this.stream instanceof node_stream_1.default.Duplex)
|
|
138
|
-
this.stream.end(() => { resolve(); });
|
|
139
|
-
else
|
|
140
|
-
resolve();
|
|
141
|
-
});
|
|
142
|
-
this.stream.destroy();
|
|
143
|
-
this.stream = null;
|
|
144
|
-
}
|
|
145
|
-
/* shutdown FFmpeg */
|
|
146
|
-
if (this.ffmpeg !== null) {
|
|
147
|
-
this.ffmpeg.kill();
|
|
148
|
-
this.ffmpeg = null;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
exports.default = SpeechFlowNodeFFmpeg;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import SpeechFlowNode from "./speechflow-node";
|
|
2
|
-
export default class SpeechFlowNodeFile 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,176 +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_fs_1 = __importDefault(require("node:fs"));
|
|
46
|
-
const node_stream_1 = __importDefault(require("node:stream"));
|
|
47
|
-
/* internal dependencies */
|
|
48
|
-
const speechflow_node_1 = __importDefault(require("./speechflow-node"));
|
|
49
|
-
const utils = __importStar(require("./speechflow-utils"));
|
|
50
|
-
/* SpeechFlow node for file access */
|
|
51
|
-
class SpeechFlowNodeFile extends speechflow_node_1.default {
|
|
52
|
-
/* declare official node name */
|
|
53
|
-
static name = "file";
|
|
54
|
-
/* construct node */
|
|
55
|
-
constructor(id, cfg, opts, args) {
|
|
56
|
-
super(id, cfg, opts, args);
|
|
57
|
-
/* declare node configuration parameters */
|
|
58
|
-
this.configure({
|
|
59
|
-
path: { type: "string", pos: 0 },
|
|
60
|
-
mode: { type: "string", pos: 1, val: "r", match: /^(?:r|w|rw)$/ },
|
|
61
|
-
type: { type: "string", pos: 2, val: "audio", match: /^(?:audio|text)$/ }
|
|
62
|
-
});
|
|
63
|
-
/* declare node input/output format */
|
|
64
|
-
if (this.params.mode === "rw") {
|
|
65
|
-
this.input = this.params.type;
|
|
66
|
-
this.output = this.params.type;
|
|
67
|
-
}
|
|
68
|
-
else if (this.params.mode === "r") {
|
|
69
|
-
this.input = "none";
|
|
70
|
-
this.output = this.params.type;
|
|
71
|
-
}
|
|
72
|
-
else if (this.params.mode === "w") {
|
|
73
|
-
this.input = this.params.type;
|
|
74
|
-
this.output = "none";
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
/* open node */
|
|
78
|
-
async open() {
|
|
79
|
-
if (this.params.mode === "rw") {
|
|
80
|
-
if (this.params.path === "-") {
|
|
81
|
-
/* standard I/O */
|
|
82
|
-
if (this.params.type === "audio") {
|
|
83
|
-
process.stdin.setEncoding();
|
|
84
|
-
process.stdout.setEncoding();
|
|
85
|
-
}
|
|
86
|
-
else {
|
|
87
|
-
process.stdin.setEncoding(this.config.textEncoding);
|
|
88
|
-
process.stdout.setEncoding(this.config.textEncoding);
|
|
89
|
-
}
|
|
90
|
-
this.stream = node_stream_1.default.Duplex.from({
|
|
91
|
-
readable: process.stdin,
|
|
92
|
-
writable: process.stdout
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
else {
|
|
96
|
-
/* file I/O */
|
|
97
|
-
if (this.params.type === "audio") {
|
|
98
|
-
this.stream = node_stream_1.default.Duplex.from({
|
|
99
|
-
readable: node_fs_1.default.createReadStream(this.params.path),
|
|
100
|
-
writable: node_fs_1.default.createWriteStream(this.params.path)
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
else {
|
|
104
|
-
this.stream = node_stream_1.default.Duplex.from({
|
|
105
|
-
readable: node_fs_1.default.createReadStream(this.params.path, { encoding: this.config.textEncoding }),
|
|
106
|
-
writable: node_fs_1.default.createWriteStream(this.params.path, { encoding: this.config.textEncoding })
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
/* convert regular stream into object-mode stream */
|
|
111
|
-
const wrapper1 = utils.createTransformStreamForWritableSide();
|
|
112
|
-
const wrapper2 = utils.createTransformStreamForReadableSide(this.params.type, () => this.timeZero);
|
|
113
|
-
this.stream = node_stream_1.default.compose(wrapper1, this.stream, wrapper2);
|
|
114
|
-
}
|
|
115
|
-
else if (this.params.mode === "r") {
|
|
116
|
-
if (this.params.path === "-") {
|
|
117
|
-
/* standard I/O */
|
|
118
|
-
if (this.params.type === "audio")
|
|
119
|
-
process.stdin.setEncoding();
|
|
120
|
-
else
|
|
121
|
-
process.stdin.setEncoding(this.config.textEncoding);
|
|
122
|
-
this.stream = process.stdin;
|
|
123
|
-
}
|
|
124
|
-
else {
|
|
125
|
-
/* file I/O */
|
|
126
|
-
if (this.params.type === "audio")
|
|
127
|
-
this.stream = node_fs_1.default.createReadStream(this.params.path);
|
|
128
|
-
else
|
|
129
|
-
this.stream = node_fs_1.default.createReadStream(this.params.path, { encoding: this.config.textEncoding });
|
|
130
|
-
}
|
|
131
|
-
/* convert regular stream into object-mode stream */
|
|
132
|
-
const wrapper = utils.createTransformStreamForReadableSide(this.params.type, () => this.timeZero);
|
|
133
|
-
this.stream.pipe(wrapper);
|
|
134
|
-
this.stream = wrapper;
|
|
135
|
-
}
|
|
136
|
-
else if (this.params.mode === "w") {
|
|
137
|
-
if (this.params.path === "-") {
|
|
138
|
-
/* standard I/O */
|
|
139
|
-
if (this.params.type === "audio")
|
|
140
|
-
process.stdout.setEncoding();
|
|
141
|
-
else
|
|
142
|
-
process.stdout.setEncoding(this.config.textEncoding);
|
|
143
|
-
this.stream = process.stdout;
|
|
144
|
-
}
|
|
145
|
-
else {
|
|
146
|
-
/* file I/O */
|
|
147
|
-
if (this.params.type === "audio")
|
|
148
|
-
this.stream = node_fs_1.default.createWriteStream(this.params.path);
|
|
149
|
-
else
|
|
150
|
-
this.stream = node_fs_1.default.createWriteStream(this.params.path, { encoding: this.config.textEncoding });
|
|
151
|
-
}
|
|
152
|
-
/* convert regular stream into object-mode stream */
|
|
153
|
-
const wrapper = utils.createTransformStreamForWritableSide();
|
|
154
|
-
wrapper.pipe(this.stream);
|
|
155
|
-
this.stream = wrapper;
|
|
156
|
-
}
|
|
157
|
-
else
|
|
158
|
-
throw new Error(`invalid file mode "${this.params.mode}"`);
|
|
159
|
-
}
|
|
160
|
-
/* close node */
|
|
161
|
-
async close() {
|
|
162
|
-
/* shutdown stream */
|
|
163
|
-
if (this.stream !== null) {
|
|
164
|
-
await new Promise((resolve) => {
|
|
165
|
-
if (this.stream instanceof node_stream_1.default.Writable || this.stream instanceof node_stream_1.default.Duplex)
|
|
166
|
-
this.stream.end(() => { resolve(); });
|
|
167
|
-
else
|
|
168
|
-
resolve();
|
|
169
|
-
});
|
|
170
|
-
if (this.params.path !== "-")
|
|
171
|
-
this.stream.destroy();
|
|
172
|
-
this.stream = null;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
exports.default = SpeechFlowNodeFile;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import SpeechFlowNode from "./speechflow-node";
|
|
2
|
-
export default class SpeechFlowNodeFormat 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,80 +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_stream_1 = __importDefault(require("node:stream"));
|
|
13
|
-
/* external dependencies */
|
|
14
|
-
const wrap_text_1 = __importDefault(require("wrap-text"));
|
|
15
|
-
/* internal dependencies */
|
|
16
|
-
const speechflow_node_1 = __importDefault(require("./speechflow-node"));
|
|
17
|
-
/* SpeechFlow node for text-to-text formatting */
|
|
18
|
-
class SpeechFlowNodeFormat extends speechflow_node_1.default {
|
|
19
|
-
/* declare official node name */
|
|
20
|
-
static name = "format";
|
|
21
|
-
/* construct node */
|
|
22
|
-
constructor(id, cfg, opts, args) {
|
|
23
|
-
super(id, cfg, opts, args);
|
|
24
|
-
/* declare node configuration parameters */
|
|
25
|
-
this.configure({
|
|
26
|
-
width: { type: "number", val: 80 }
|
|
27
|
-
});
|
|
28
|
-
/* declare node input/output format */
|
|
29
|
-
this.input = "text";
|
|
30
|
-
this.output = "text";
|
|
31
|
-
}
|
|
32
|
-
/* open node */
|
|
33
|
-
async open() {
|
|
34
|
-
/* provide text-to-text formatter */
|
|
35
|
-
const format = async (text) => {
|
|
36
|
-
text = (0, wrap_text_1.default)(text, this.params.width);
|
|
37
|
-
text = text.replace(/([^\n])$/, "$1\n");
|
|
38
|
-
return text;
|
|
39
|
-
};
|
|
40
|
-
/* establish a duplex stream and connect it to DeepL translation */
|
|
41
|
-
this.stream = new node_stream_1.default.Transform({
|
|
42
|
-
readableObjectMode: true,
|
|
43
|
-
writableObjectMode: true,
|
|
44
|
-
decodeStrings: false,
|
|
45
|
-
transform(chunk, encoding, callback) {
|
|
46
|
-
if (Buffer.isBuffer(chunk.payload))
|
|
47
|
-
callback(new Error("invalid chunk payload type"));
|
|
48
|
-
else {
|
|
49
|
-
if (chunk.payload === "") {
|
|
50
|
-
this.push(chunk);
|
|
51
|
-
callback();
|
|
52
|
-
}
|
|
53
|
-
else {
|
|
54
|
-
format(chunk.payload).then((payload) => {
|
|
55
|
-
const chunkNew = chunk.clone();
|
|
56
|
-
chunkNew.payload = payload;
|
|
57
|
-
this.push(chunkNew);
|
|
58
|
-
callback();
|
|
59
|
-
}).catch((err) => {
|
|
60
|
-
callback(err);
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
},
|
|
65
|
-
final(callback) {
|
|
66
|
-
this.push(null);
|
|
67
|
-
callback();
|
|
68
|
-
}
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
/* open node */
|
|
72
|
-
async close() {
|
|
73
|
-
/* close stream */
|
|
74
|
-
if (this.stream !== null) {
|
|
75
|
-
this.stream.destroy();
|
|
76
|
-
this.stream = null;
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
exports.default = SpeechFlowNodeFormat;
|