speechflow 1.7.0 → 1.7.1
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 +5 -0
- package/README.md +49 -38
- package/package.json +3 -3
- package/speechflow-cli/dst/speechflow-main-api.js +6 -5
- package/speechflow-cli/dst/speechflow-main-api.js.map +1 -1
- package/speechflow-cli/dst/speechflow-main-graph.js +7 -8
- package/speechflow-cli/dst/speechflow-main-graph.js.map +1 -1
- package/speechflow-cli/dst/speechflow-main-status.js +3 -7
- package/speechflow-cli/dst/speechflow-main-status.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-compressor-wt.js +3 -0
- package/speechflow-cli/dst/speechflow-node-a2a-compressor-wt.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-compressor.js +4 -2
- package/speechflow-cli/dst/speechflow-node-a2a-compressor.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-expander-wt.js +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-expander.js +4 -2
- package/speechflow-cli/dst/speechflow-node-a2a-expander.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-gender.js +2 -2
- package/speechflow-cli/dst/speechflow-node-a2a-gender.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-pitch.js +1 -2
- package/speechflow-cli/dst/speechflow-node-a2a-pitch.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-wav.js +8 -1
- package/speechflow-cli/dst/speechflow-node-a2a-wav.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2t-amazon.d.ts +0 -1
- package/speechflow-cli/dst/speechflow-node-a2t-amazon.js +1 -6
- package/speechflow-cli/dst/speechflow-node-a2t-amazon.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2t-deepgram.d.ts +0 -1
- package/speechflow-cli/dst/speechflow-node-a2t-deepgram.js +9 -9
- package/speechflow-cli/dst/speechflow-node-a2t-deepgram.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2t-openai.js +6 -4
- package/speechflow-cli/dst/speechflow-node-a2t-openai.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2a-amazon.js +6 -11
- package/speechflow-cli/dst/speechflow-node-t2a-amazon.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2a-elevenlabs.js +6 -5
- package/speechflow-cli/dst/speechflow-node-t2a-elevenlabs.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2a-kokoro.d.ts +2 -0
- package/speechflow-cli/dst/speechflow-node-t2a-kokoro.js +19 -6
- package/speechflow-cli/dst/speechflow-node-t2a-kokoro.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-x2x-filter.d.ts +1 -0
- package/speechflow-cli/dst/speechflow-node-x2x-filter.js +10 -0
- package/speechflow-cli/dst/speechflow-node-x2x-filter.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-x2x-trace.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-xio-device.js +3 -3
- package/speechflow-cli/dst/speechflow-node-xio-device.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-xio-file.js +1 -1
- package/speechflow-cli/dst/speechflow-node-xio-file.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-xio-mqtt.js +2 -1
- package/speechflow-cli/dst/speechflow-node-xio-mqtt.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-xio-websocket.js +2 -1
- package/speechflow-cli/dst/speechflow-node-xio-websocket.js.map +1 -1
- package/speechflow-cli/dst/speechflow-util-audio.js +1 -1
- package/speechflow-cli/dst/speechflow-util-audio.js.map +1 -1
- package/speechflow-cli/dst/speechflow-util-error.d.ts +0 -1
- package/speechflow-cli/dst/speechflow-util-error.js +0 -7
- package/speechflow-cli/dst/speechflow-util-error.js.map +1 -1
- package/speechflow-cli/dst/speechflow-util-misc.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-util-misc.js +4 -4
- package/speechflow-cli/dst/speechflow-util-misc.js.map +1 -1
- package/speechflow-cli/dst/speechflow-util-queue.js +3 -3
- package/speechflow-cli/dst/speechflow-util-queue.js.map +1 -1
- package/speechflow-cli/dst/speechflow-util-stream.js +4 -2
- package/speechflow-cli/dst/speechflow-util-stream.js.map +1 -1
- package/speechflow-cli/src/speechflow-main-api.ts +6 -5
- package/speechflow-cli/src/speechflow-main-graph.ts +9 -8
- package/speechflow-cli/src/speechflow-main-status.ts +4 -8
- package/speechflow-cli/src/speechflow-node-a2a-compressor-wt.ts +4 -0
- package/speechflow-cli/src/speechflow-node-a2a-compressor.ts +4 -2
- package/speechflow-cli/src/speechflow-node-a2a-expander-wt.ts +1 -1
- package/speechflow-cli/src/speechflow-node-a2a-expander.ts +4 -2
- package/speechflow-cli/src/speechflow-node-a2a-gender.ts +2 -2
- package/speechflow-cli/src/speechflow-node-a2a-pitch.ts +1 -2
- package/speechflow-cli/src/speechflow-node-a2a-wav.ts +9 -2
- package/speechflow-cli/src/speechflow-node-a2t-amazon.ts +6 -11
- package/speechflow-cli/src/speechflow-node-a2t-deepgram.ts +13 -12
- package/speechflow-cli/src/speechflow-node-a2t-openai.ts +8 -4
- package/speechflow-cli/src/speechflow-node-t2a-amazon.ts +7 -11
- package/speechflow-cli/src/speechflow-node-t2a-elevenlabs.ts +6 -5
- package/speechflow-cli/src/speechflow-node-t2a-kokoro.ts +22 -6
- package/speechflow-cli/src/speechflow-node-x2x-filter.ts +16 -3
- package/speechflow-cli/src/speechflow-node-x2x-trace.ts +3 -3
- package/speechflow-cli/src/speechflow-node-xio-device.ts +4 -7
- package/speechflow-cli/src/speechflow-node-xio-file.ts +1 -1
- package/speechflow-cli/src/speechflow-node-xio-mqtt.ts +3 -2
- package/speechflow-cli/src/speechflow-node-xio-websocket.ts +2 -1
- package/speechflow-cli/src/speechflow-util-audio-wt.ts +4 -4
- package/speechflow-cli/src/speechflow-util-audio.ts +5 -5
- package/speechflow-cli/src/speechflow-util-error.ts +0 -7
- package/speechflow-cli/src/speechflow-util-misc.ts +4 -4
- package/speechflow-cli/src/speechflow-util-queue.ts +4 -4
- package/speechflow-cli/src/speechflow-util-stream.ts +5 -3
|
@@ -28,10 +28,10 @@ export default class SpeechFlowNodeX2XTrace extends SpeechFlowNode {
|
|
|
28
28
|
|
|
29
29
|
/* declare node configuration parameters */
|
|
30
30
|
this.configure({
|
|
31
|
-
type: { type: "string", pos: 0, val: "audio",
|
|
32
|
-
name: { type: "string", pos: 1, val: "trace"
|
|
31
|
+
type: { type: "string", pos: 0, val: "audio", match: /^(?:audio|text)$/ },
|
|
32
|
+
name: { type: "string", pos: 1, val: "trace" },
|
|
33
33
|
mode: { type: "string", pos: 2, val: "filter", match: /^(?:filter|sink)$/ },
|
|
34
|
-
dashboard: { type: "string", val: ""
|
|
34
|
+
dashboard: { type: "string", val: "" }
|
|
35
35
|
})
|
|
36
36
|
|
|
37
37
|
/* sanity check parameters */
|
|
@@ -20,10 +20,7 @@ export default class SpeechFlowNodeXIODevice extends SpeechFlowNode {
|
|
|
20
20
|
public static name = "xio-device"
|
|
21
21
|
|
|
22
22
|
/* internal state */
|
|
23
|
-
private io: PortAudio.IoStreamRead
|
|
24
|
-
| PortAudio.IoStreamWrite
|
|
25
|
-
| PortAudio.IoStreamDuplex
|
|
26
|
-
| null = null
|
|
23
|
+
private io: PortAudio.IoStreamRead | PortAudio.IoStreamWrite | PortAudio.IoStreamDuplex | null = null
|
|
27
24
|
|
|
28
25
|
/* construct node */
|
|
29
26
|
constructor (id: string, cfg: { [ id: string ]: any }, opts: { [ id: string ]: any }, args: any[]) {
|
|
@@ -87,7 +84,7 @@ export default class SpeechFlowNodeXIODevice extends SpeechFlowNode {
|
|
|
87
84
|
return device
|
|
88
85
|
}
|
|
89
86
|
|
|
90
|
-
/* NOTICE: "
|
|
87
|
+
/* NOTICE: "naudiodon" actually implements Stream.{Readable,Writable,Duplex}, but
|
|
91
88
|
declares just its sub-interface NodeJS.{Readable,Writable,Duplex}Stream,
|
|
92
89
|
so it is correct to cast it back to Stream.{Readable,Writable,Duplex}
|
|
93
90
|
in the following device stream setup functions! */
|
|
@@ -211,7 +208,7 @@ export default class SpeechFlowNodeXIODevice extends SpeechFlowNode {
|
|
|
211
208
|
throw error
|
|
212
209
|
}
|
|
213
210
|
await Promise.race([
|
|
214
|
-
util.
|
|
211
|
+
util.timeout(2 * 1000, "PortAudio abort timeout"),
|
|
215
212
|
new Promise<void>((resolve) => {
|
|
216
213
|
this.io!.abort(() => {
|
|
217
214
|
resolve()
|
|
@@ -219,7 +216,7 @@ export default class SpeechFlowNodeXIODevice extends SpeechFlowNode {
|
|
|
219
216
|
}).catch(catchHandler)
|
|
220
217
|
])
|
|
221
218
|
await Promise.race([
|
|
222
|
-
util.
|
|
219
|
+
util.timeout(2 * 1000, "PortAudio quit timeout"),
|
|
223
220
|
new Promise<void>((resolve) => {
|
|
224
221
|
this.io!.quit(() => {
|
|
225
222
|
resolve()
|
|
@@ -97,7 +97,8 @@ export default class SpeechFlowNodeXIOMQTT extends SpeechFlowNode {
|
|
|
97
97
|
this.log("info", `connection re-opened to MQTT ${this.params.url}`)
|
|
98
98
|
})
|
|
99
99
|
this.broker.on("disconnect", (packet: MQTT.IDisconnectPacket) => {
|
|
100
|
-
|
|
100
|
+
const reasonCode = packet.reasonCode ?? 0
|
|
101
|
+
this.log("info", `connection closed to MQTT ${this.params.url} (reason code: ${reasonCode})`)
|
|
101
102
|
})
|
|
102
103
|
this.chunkQueue = new util.SingleQueue<SpeechFlowChunk>()
|
|
103
104
|
this.broker.on("message", (topic: string, payload: Buffer, packet: MQTT.IPublishPacket) => {
|
|
@@ -107,7 +108,7 @@ export default class SpeechFlowNodeXIOMQTT extends SpeechFlowNode {
|
|
|
107
108
|
const chunk = util.streamChunkDecode(payload)
|
|
108
109
|
this.chunkQueue!.write(chunk)
|
|
109
110
|
}
|
|
110
|
-
catch (_err:
|
|
111
|
+
catch (_err: unknown) {
|
|
111
112
|
this.log("warning", `received invalid CBOR chunk from MQTT ${this.params.url}`)
|
|
112
113
|
}
|
|
113
114
|
})
|
|
@@ -175,7 +175,8 @@ export default class SpeechFlowNodeXIOWebSocket extends SpeechFlowNode {
|
|
|
175
175
|
this.log("info", `connection closed to URL ${this.params.connect}`)
|
|
176
176
|
})
|
|
177
177
|
this.client.addEventListener("error", (ev: ErrorEvent) => {
|
|
178
|
-
|
|
178
|
+
const error = util.ensureError(ev.error)
|
|
179
|
+
this.log("error", `error of connection on URL ${this.params.connect}: ${error.message}`)
|
|
179
180
|
})
|
|
180
181
|
const chunkQueue = new util.SingleQueue<SpeechFlowChunk>()
|
|
181
182
|
this.client.addEventListener("message", (ev: MessageEvent) => {
|
|
@@ -38,7 +38,7 @@ class AudioSourceProcessor extends AudioWorkletProcessor {
|
|
|
38
38
|
private currentOffset = 0
|
|
39
39
|
|
|
40
40
|
/* node construction */
|
|
41
|
-
constructor() {
|
|
41
|
+
constructor () {
|
|
42
42
|
super()
|
|
43
43
|
|
|
44
44
|
/* receive input chunks */
|
|
@@ -50,7 +50,7 @@ class AudioSourceProcessor extends AudioWorkletProcessor {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
/* process audio frame */
|
|
53
|
-
process(
|
|
53
|
+
process (
|
|
54
54
|
inputs: Float32Array[][], /* unused */
|
|
55
55
|
outputs: Float32Array[][],
|
|
56
56
|
parameters: Record<string, Float32Array> /* unused */
|
|
@@ -117,7 +117,7 @@ class AudioCaptureProcessor extends AudioWorkletProcessor {
|
|
|
117
117
|
private activeCaptures = new Map<string, { data: number[], expectedSamples: number }>()
|
|
118
118
|
|
|
119
119
|
/* node construction */
|
|
120
|
-
constructor() {
|
|
120
|
+
constructor () {
|
|
121
121
|
super()
|
|
122
122
|
|
|
123
123
|
/* receive start of capturing command */
|
|
@@ -133,7 +133,7 @@ class AudioCaptureProcessor extends AudioWorkletProcessor {
|
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
/* process audio frame */
|
|
136
|
-
process(
|
|
136
|
+
process (
|
|
137
137
|
inputs: Float32Array[][],
|
|
138
138
|
outputs: Float32Array[][], /* unused */
|
|
139
139
|
parameters: Record<string, Float32Array> /* unused */
|
|
@@ -133,7 +133,7 @@ export async function processInt16ArrayInSegments (
|
|
|
133
133
|
}
|
|
134
134
|
|
|
135
135
|
/* update envelope (smoothed amplitude contour) for single channel */
|
|
136
|
-
export function updateEnvelopeForChannel(
|
|
136
|
+
export function updateEnvelopeForChannel (
|
|
137
137
|
env: number[],
|
|
138
138
|
sampleRate: number,
|
|
139
139
|
chan: number,
|
|
@@ -182,7 +182,7 @@ export class WebAudio {
|
|
|
182
182
|
}>()
|
|
183
183
|
|
|
184
184
|
/* construct object */
|
|
185
|
-
constructor(
|
|
185
|
+
constructor (
|
|
186
186
|
public sampleRate: number,
|
|
187
187
|
public channels: number
|
|
188
188
|
) {
|
|
@@ -215,7 +215,7 @@ export class WebAudio {
|
|
|
215
215
|
numberOfInputs: 1,
|
|
216
216
|
numberOfOutputs: 0
|
|
217
217
|
})
|
|
218
|
-
this.captureNode
|
|
218
|
+
this.captureNode.port.addEventListener("message", (event) => {
|
|
219
219
|
const { type, chunkId, data } = event.data ?? {}
|
|
220
220
|
if (type === "capture-complete") {
|
|
221
221
|
const promise = this.pendingPromises.get(chunkId)
|
|
@@ -232,7 +232,7 @@ export class WebAudio {
|
|
|
232
232
|
|
|
233
233
|
/* start ports */
|
|
234
234
|
this.sourceNode.port.start()
|
|
235
|
-
this.captureNode
|
|
235
|
+
this.captureNode.port.start()
|
|
236
236
|
}
|
|
237
237
|
|
|
238
238
|
/* process single audio chunk */
|
|
@@ -242,7 +242,7 @@ export class WebAudio {
|
|
|
242
242
|
const timeout = setTimeout(() => {
|
|
243
243
|
this.pendingPromises.delete(chunkId)
|
|
244
244
|
reject(new Error("processing timeout"))
|
|
245
|
-
}, (int16Array.length / this.audioContext.sampleRate) * 1000 + 250)
|
|
245
|
+
}, (int16Array.length / this.channels / this.audioContext.sampleRate) * 1000 + 250)
|
|
246
246
|
if (this.captureNode !== null)
|
|
247
247
|
this.pendingPromises.set(chunkId, { resolve, reject, timeout })
|
|
248
248
|
try {
|
|
@@ -4,13 +4,6 @@
|
|
|
4
4
|
** Licensed under GPL 3.0 <https://spdx.org/licenses/GPL-3.0-only>
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
/* helper function for promise-based timeout */
|
|
8
|
-
export function timeoutPromise<T = void> (duration: number = 10 * 1000, info = "timeout") {
|
|
9
|
-
return new Promise<T>((resolve, reject) => {
|
|
10
|
-
setTimeout(() => { reject(new Error(info)) }, duration)
|
|
11
|
-
})
|
|
12
|
-
}
|
|
13
|
-
|
|
14
7
|
/* helper function for retrieving an Error object */
|
|
15
8
|
export function ensureError (error: unknown, prefix?: string, debug = false): Error {
|
|
16
9
|
if (error instanceof Error && prefix === undefined && debug === false)
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
/* sleep: wait a duration of time and then resolve */
|
|
8
8
|
export function sleep (durationMs: number) {
|
|
9
|
-
return new Promise<void>((resolve
|
|
9
|
+
return new Promise<void>((resolve) => {
|
|
10
10
|
setTimeout(() => {
|
|
11
11
|
resolve()
|
|
12
12
|
}, durationMs)
|
|
@@ -14,10 +14,10 @@ export function sleep (durationMs: number) {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
/* timeout: wait a duration of time and then reject */
|
|
17
|
-
export function timeout (durationMs: number) {
|
|
18
|
-
return new Promise<never>((
|
|
17
|
+
export function timeout (durationMs: number, info = "timeout") {
|
|
18
|
+
return new Promise<never>((_resolve, reject) => {
|
|
19
19
|
setTimeout(() => {
|
|
20
|
-
reject(new Error(
|
|
20
|
+
reject(new Error(info))
|
|
21
21
|
}, durationMs)
|
|
22
22
|
})
|
|
23
23
|
}
|
|
@@ -34,7 +34,7 @@ export class SingleQueue<T> extends EventEmitter {
|
|
|
34
34
|
this.emit("dequeue")
|
|
35
35
|
}
|
|
36
36
|
read () {
|
|
37
|
-
return new Promise<T>((resolve
|
|
37
|
+
return new Promise<T>((resolve) => {
|
|
38
38
|
const tryToConsume = () => {
|
|
39
39
|
const item = this.queue.pop()
|
|
40
40
|
if (item !== undefined)
|
|
@@ -69,7 +69,7 @@ export class DoubleQueue<T0, T1> extends EventEmitter {
|
|
|
69
69
|
this.notify()
|
|
70
70
|
}
|
|
71
71
|
read () {
|
|
72
|
-
return new Promise<[ T0, T1 ]>((resolve
|
|
72
|
+
return new Promise<[ T0, T1 ]>((resolve) => {
|
|
73
73
|
const consume = (): [ T0, T1 ] | undefined => {
|
|
74
74
|
if (this.queue0.length > 0 && this.queue1.length > 0) {
|
|
75
75
|
const item0 = this.queue0.pop() as T0
|
|
@@ -90,7 +90,7 @@ export class DoubleQueue<T0, T1> extends EventEmitter {
|
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
-
/* queue element
|
|
93
|
+
/* queue element */
|
|
94
94
|
export type QueueElement = { type: string }
|
|
95
95
|
|
|
96
96
|
/* queue pointer */
|
|
@@ -228,7 +228,7 @@ export class Queue<T extends QueueElement> extends EventEmitter {
|
|
|
228
228
|
}
|
|
229
229
|
pointerDelete (name: string): void {
|
|
230
230
|
if (!this.pointers.has(name))
|
|
231
|
-
throw new Error("pointer not
|
|
231
|
+
throw new Error("pointer does not exist")
|
|
232
232
|
this.pointers.delete(name)
|
|
233
233
|
}
|
|
234
234
|
trim (): void {
|
|
@@ -204,7 +204,7 @@ export class StreamWrapper extends Stream.Transform {
|
|
|
204
204
|
}
|
|
205
205
|
|
|
206
206
|
/* helper function for destruction of a stream */
|
|
207
|
-
export async function destroyStream(
|
|
207
|
+
export async function destroyStream (
|
|
208
208
|
stream: Stream.Readable | Stream.Writable | Stream.Duplex | Stream.Transform
|
|
209
209
|
) {
|
|
210
210
|
/* signal the end for a writable stream */
|
|
@@ -217,8 +217,10 @@ export async function destroyStream(
|
|
|
217
217
|
new Promise<void>((resolve) => {
|
|
218
218
|
stream.end(() => { resolve() })
|
|
219
219
|
}),
|
|
220
|
-
util.
|
|
221
|
-
])
|
|
220
|
+
util.timeout(5000, "stream end timeout")
|
|
221
|
+
]).catch(() => {
|
|
222
|
+
/* ignore timeout -- stream will be destroyed anyway */
|
|
223
|
+
})
|
|
222
224
|
|
|
223
225
|
/* destroy the stream */
|
|
224
226
|
stream.destroy()
|