speechflow 1.6.7 → 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 +15 -0
- package/README.md +77 -52
- package/etc/secretlint.json +7 -0
- package/etc/speechflow.yaml +13 -4
- package/etc/stx.conf +3 -2
- package/package.json +8 -6
- package/speechflow-cli/dst/speechflow-main-api.js +9 -8
- package/speechflow-cli/dst/speechflow-main-api.js.map +1 -1
- package/speechflow-cli/dst/speechflow-main-graph.js +13 -14
- package/speechflow-cli/dst/speechflow-main-graph.js.map +1 -1
- package/speechflow-cli/dst/speechflow-main-status.js +38 -8
- 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-ffmpeg.js +2 -2
- package/speechflow-cli/dst/speechflow-node-a2a-ffmpeg.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-filler.js +46 -17
- package/speechflow-cli/dst/speechflow-node-a2a-filler.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-gain.js +0 -5
- package/speechflow-cli/dst/speechflow-node-a2a-gain.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-gender.js +3 -4
- package/speechflow-cli/dst/speechflow-node-a2a-gender.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-mute.js +0 -5
- package/speechflow-cli/dst/speechflow-node-a2a-mute.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-rnnoise.js +0 -5
- package/speechflow-cli/dst/speechflow-node-a2a-rnnoise.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-speex.js +0 -5
- package/speechflow-cli/dst/speechflow-node-a2a-speex.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-wav.js +8 -2
- 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 +17 -19
- 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 +30 -25
- package/speechflow-cli/dst/speechflow-node-a2t-deepgram.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2t-openai.js +79 -48
- 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 +45 -44
- 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 -7
- package/speechflow-cli/dst/speechflow-node-t2a-kokoro.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-amazon.js +1 -2
- package/speechflow-cli/dst/speechflow-node-t2t-amazon.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-deepl.js +0 -1
- package/speechflow-cli/dst/speechflow-node-t2t-deepl.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-format.js +0 -1
- package/speechflow-cli/dst/speechflow-node-t2t-format.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-google.js +0 -1
- package/speechflow-cli/dst/speechflow-node-t2t-google.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-modify.js +0 -1
- package/speechflow-cli/dst/speechflow-node-t2t-modify.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-ollama.js +0 -1
- package/speechflow-cli/dst/speechflow-node-t2t-ollama.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-openai.js +0 -1
- package/speechflow-cli/dst/speechflow-node-t2t-openai.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-subtitle.js +173 -29
- package/speechflow-cli/dst/speechflow-node-t2t-subtitle.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 -1
- package/speechflow-cli/dst/speechflow-node-x2x-filter.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-x2x-trace.js +0 -5
- package/speechflow-cli/dst/speechflow-node-x2x-trace.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-xio-device.js +5 -5
- package/speechflow-cli/dst/speechflow-node-xio-device.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-xio-file.js +4 -4
- package/speechflow-cli/dst/speechflow-node-xio-file.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-xio-mqtt.js +9 -3
- package/speechflow-cli/dst/speechflow-node-xio-mqtt.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-xio-websocket.js +16 -5
- package/speechflow-cli/dst/speechflow-node-xio-websocket.js.map +1 -1
- package/speechflow-cli/dst/speechflow-util-audio.js +3 -3
- 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 +2 -0
- package/speechflow-cli/dst/speechflow-util-misc.js +26 -0
- package/speechflow-cli/dst/speechflow-util-misc.js.map +1 -0
- package/speechflow-cli/dst/speechflow-util-queue.d.ts +9 -2
- package/speechflow-cli/dst/speechflow-util-queue.js +36 -15
- package/speechflow-cli/dst/speechflow-util-queue.js.map +1 -1
- package/speechflow-cli/dst/speechflow-util-stream.d.ts +2 -2
- package/speechflow-cli/dst/speechflow-util-stream.js +17 -19
- package/speechflow-cli/dst/speechflow-util-stream.js.map +1 -1
- package/speechflow-cli/dst/speechflow-util.d.ts +1 -0
- package/speechflow-cli/dst/speechflow-util.js +1 -0
- package/speechflow-cli/dst/speechflow-util.js.map +1 -1
- package/speechflow-cli/etc/oxlint.jsonc +6 -1
- package/speechflow-cli/etc/stx.conf +1 -0
- package/speechflow-cli/package.json +28 -27
- package/speechflow-cli/src/speechflow-main-api.ts +9 -11
- package/speechflow-cli/src/speechflow-main-graph.ts +15 -16
- package/speechflow-cli/src/speechflow-main-status.ts +6 -10
- 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-ffmpeg.ts +4 -2
- package/speechflow-cli/src/speechflow-node-a2a-filler.ts +57 -20
- package/speechflow-cli/src/speechflow-node-a2a-gain.ts +0 -5
- package/speechflow-cli/src/speechflow-node-a2a-gender.ts +3 -4
- package/speechflow-cli/src/speechflow-node-a2a-mute.ts +0 -5
- package/speechflow-cli/src/speechflow-node-a2a-pitch.ts +1 -2
- package/speechflow-cli/src/speechflow-node-a2a-rnnoise.ts +0 -5
- package/speechflow-cli/src/speechflow-node-a2a-speex.ts +0 -5
- package/speechflow-cli/src/speechflow-node-a2a-wav.ts +9 -3
- package/speechflow-cli/src/speechflow-node-a2t-amazon.ts +27 -27
- package/speechflow-cli/src/speechflow-node-a2t-deepgram.ts +37 -28
- package/speechflow-cli/src/speechflow-node-a2t-openai.ts +92 -56
- package/speechflow-cli/src/speechflow-node-t2a-amazon.ts +7 -11
- package/speechflow-cli/src/speechflow-node-t2a-elevenlabs.ts +47 -43
- package/speechflow-cli/src/speechflow-node-t2a-kokoro.ts +22 -7
- package/speechflow-cli/src/speechflow-node-t2t-amazon.ts +1 -2
- package/speechflow-cli/src/speechflow-node-t2t-deepl.ts +0 -1
- package/speechflow-cli/src/speechflow-node-t2t-format.ts +0 -1
- package/speechflow-cli/src/speechflow-node-t2t-google.ts +0 -1
- package/speechflow-cli/src/speechflow-node-t2t-modify.ts +0 -1
- package/speechflow-cli/src/speechflow-node-t2t-ollama.ts +0 -1
- package/speechflow-cli/src/speechflow-node-t2t-openai.ts +0 -1
- package/speechflow-cli/src/speechflow-node-t2t-subtitle.ts +205 -33
- package/speechflow-cli/src/speechflow-node-x2x-filter.ts +16 -4
- package/speechflow-cli/src/speechflow-node-x2x-trace.ts +3 -8
- package/speechflow-cli/src/speechflow-node-xio-device.ts +6 -9
- package/speechflow-cli/src/speechflow-node-xio-file.ts +4 -4
- package/speechflow-cli/src/speechflow-node-xio-mqtt.ts +10 -4
- package/speechflow-cli/src/speechflow-node-xio-websocket.ts +16 -5
- package/speechflow-cli/src/speechflow-util-audio-wt.ts +4 -4
- package/speechflow-cli/src/speechflow-util-audio.ts +7 -7
- package/speechflow-cli/src/speechflow-util-error.ts +0 -7
- package/speechflow-cli/src/speechflow-util-misc.ts +23 -0
- package/speechflow-cli/src/speechflow-util-queue.ts +40 -20
- package/speechflow-cli/src/speechflow-util-stream.ts +29 -24
- package/speechflow-cli/src/speechflow-util.ts +1 -0
- package/speechflow-ui-db/dst/index.css +1 -5
- package/speechflow-ui-db/dst/index.js +14 -58
- package/speechflow-ui-db/etc/stx.conf +5 -16
- package/speechflow-ui-db/package.json +16 -15
- package/speechflow-ui-st/dst/index.css +1 -5
- package/speechflow-ui-st/dst/index.js +31 -160
- package/speechflow-ui-st/etc/stx.conf +5 -16
- package/speechflow-ui-st/package.json +17 -16
|
@@ -91,7 +91,7 @@ export function convertBufToI16 (buf: Buffer, littleEndian = true) {
|
|
|
91
91
|
return arr
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
/* helper function: convert
|
|
94
|
+
/* helper function: convert Int16Array in PCM/I16 to Buffer */
|
|
95
95
|
export function convertI16ToBuf (arr: Int16Array, littleEndian = true) {
|
|
96
96
|
if (arr.length === 0)
|
|
97
97
|
return Buffer.alloc(0)
|
|
@@ -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 {
|
|
@@ -252,7 +252,7 @@ export class WebAudio {
|
|
|
252
252
|
|
|
253
253
|
/* start capture first */
|
|
254
254
|
if (this.captureNode !== null) {
|
|
255
|
-
this.captureNode
|
|
255
|
+
this.captureNode.port.postMessage({
|
|
256
256
|
type: "start-capture",
|
|
257
257
|
chunkId,
|
|
258
258
|
expectedSamples: int16Array.length
|
|
@@ -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)
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/*
|
|
2
|
+
** SpeechFlow - Speech Processing Flow Graph
|
|
3
|
+
** Copyright (c) 2024-2025 Dr. Ralf S. Engelschall <rse@engelschall.com>
|
|
4
|
+
** Licensed under GPL 3.0 <https://spdx.org/licenses/GPL-3.0-only>
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/* sleep: wait a duration of time and then resolve */
|
|
8
|
+
export function sleep (durationMs: number) {
|
|
9
|
+
return new Promise<void>((resolve) => {
|
|
10
|
+
setTimeout(() => {
|
|
11
|
+
resolve()
|
|
12
|
+
}, durationMs)
|
|
13
|
+
})
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/* timeout: wait a duration of time and then reject */
|
|
17
|
+
export function timeout (durationMs: number, info = "timeout") {
|
|
18
|
+
return new Promise<never>((_resolve, reject) => {
|
|
19
|
+
setTimeout(() => {
|
|
20
|
+
reject(new Error(info))
|
|
21
|
+
}, durationMs)
|
|
22
|
+
})
|
|
23
|
+
}
|
|
@@ -34,12 +34,10 @@ export class SingleQueue<T> extends EventEmitter {
|
|
|
34
34
|
this.emit("dequeue")
|
|
35
35
|
}
|
|
36
36
|
read () {
|
|
37
|
-
return new Promise<T>((resolve
|
|
38
|
-
const consume = () =>
|
|
39
|
-
this.queue.length > 0 ? this.queue.pop()! : null
|
|
37
|
+
return new Promise<T>((resolve) => {
|
|
40
38
|
const tryToConsume = () => {
|
|
41
|
-
const item =
|
|
42
|
-
if (item !==
|
|
39
|
+
const item = this.queue.pop()
|
|
40
|
+
if (item !== undefined)
|
|
43
41
|
resolve(item)
|
|
44
42
|
else
|
|
45
43
|
this.once("dequeue", tryToConsume)
|
|
@@ -47,6 +45,11 @@ export class SingleQueue<T> extends EventEmitter {
|
|
|
47
45
|
tryToConsume()
|
|
48
46
|
})
|
|
49
47
|
}
|
|
48
|
+
drain () {
|
|
49
|
+
const items = this.queue
|
|
50
|
+
this.queue = new Array<T>()
|
|
51
|
+
return items
|
|
52
|
+
}
|
|
50
53
|
}
|
|
51
54
|
|
|
52
55
|
/* helper class for double-item queue */
|
|
@@ -66,18 +69,18 @@ export class DoubleQueue<T0, T1> extends EventEmitter {
|
|
|
66
69
|
this.notify()
|
|
67
70
|
}
|
|
68
71
|
read () {
|
|
69
|
-
return new Promise<[ T0, T1 ]>((resolve
|
|
70
|
-
const consume = (): [ T0, T1 ] |
|
|
72
|
+
return new Promise<[ T0, T1 ]>((resolve) => {
|
|
73
|
+
const consume = (): [ T0, T1 ] | undefined => {
|
|
71
74
|
if (this.queue0.length > 0 && this.queue1.length > 0) {
|
|
72
75
|
const item0 = this.queue0.pop() as T0
|
|
73
76
|
const item1 = this.queue1.pop() as T1
|
|
74
77
|
return [ item0, item1 ]
|
|
75
78
|
}
|
|
76
|
-
return
|
|
79
|
+
return undefined
|
|
77
80
|
}
|
|
78
81
|
const tryToConsume = () => {
|
|
79
82
|
const items = consume()
|
|
80
|
-
if (items !==
|
|
83
|
+
if (items !== undefined)
|
|
81
84
|
resolve(items)
|
|
82
85
|
else
|
|
83
86
|
this.once("dequeue", tryToConsume)
|
|
@@ -87,7 +90,7 @@ export class DoubleQueue<T0, T1> extends EventEmitter {
|
|
|
87
90
|
}
|
|
88
91
|
}
|
|
89
92
|
|
|
90
|
-
/* queue element
|
|
93
|
+
/* queue element */
|
|
91
94
|
export type QueueElement = { type: string }
|
|
92
95
|
|
|
93
96
|
/* queue pointer */
|
|
@@ -225,7 +228,7 @@ export class Queue<T extends QueueElement> extends EventEmitter {
|
|
|
225
228
|
}
|
|
226
229
|
pointerDelete (name: string): void {
|
|
227
230
|
if (!this.pointers.has(name))
|
|
228
|
-
throw new Error("pointer not
|
|
231
|
+
throw new Error("pointer does not exist")
|
|
229
232
|
this.pointers.delete(name)
|
|
230
233
|
}
|
|
231
234
|
trim (): void {
|
|
@@ -273,12 +276,12 @@ export class TimeStore<T> extends EventEmitter {
|
|
|
273
276
|
|
|
274
277
|
/* asynchronous queue */
|
|
275
278
|
export class AsyncQueue<T> {
|
|
276
|
-
private queue: Array<T
|
|
277
|
-
private resolvers: (
|
|
278
|
-
write (v: T
|
|
279
|
-
const
|
|
280
|
-
if (
|
|
281
|
-
resolve(v)
|
|
279
|
+
private queue: Array<T> = []
|
|
280
|
+
private resolvers: { resolve: (v: T) => void, reject: (err: Error) => void }[] = []
|
|
281
|
+
write (v: T) {
|
|
282
|
+
const resolver = this.resolvers.shift()
|
|
283
|
+
if (resolver)
|
|
284
|
+
resolver.resolve(v)
|
|
282
285
|
else
|
|
283
286
|
this.queue.push(v)
|
|
284
287
|
}
|
|
@@ -286,11 +289,14 @@ export class AsyncQueue<T> {
|
|
|
286
289
|
if (this.queue.length > 0)
|
|
287
290
|
return this.queue.shift()!
|
|
288
291
|
else
|
|
289
|
-
return new Promise<T
|
|
292
|
+
return new Promise<T>((resolve, reject) => this.resolvers.push({ resolve, reject }))
|
|
293
|
+
}
|
|
294
|
+
empty () {
|
|
295
|
+
return this.queue.length === 0
|
|
290
296
|
}
|
|
291
297
|
destroy () {
|
|
292
|
-
for (const
|
|
293
|
-
|
|
298
|
+
for (const resolver of this.resolvers)
|
|
299
|
+
resolver.reject(new Error("AsyncQueue destroyed"))
|
|
294
300
|
this.resolvers = []
|
|
295
301
|
this.queue = []
|
|
296
302
|
}
|
|
@@ -318,3 +324,17 @@ export class CachedRegExp {
|
|
|
318
324
|
return this.cache.size
|
|
319
325
|
}
|
|
320
326
|
}
|
|
327
|
+
|
|
328
|
+
/* set of promises */
|
|
329
|
+
export class PromiseSet<T> {
|
|
330
|
+
private promises = new Set<Promise<T>>()
|
|
331
|
+
add (promise: Promise<T>) {
|
|
332
|
+
this.promises.add(promise)
|
|
333
|
+
promise.finally(() => {
|
|
334
|
+
this.promises.delete(promise)
|
|
335
|
+
}).catch(() => {})
|
|
336
|
+
}
|
|
337
|
+
async awaitAll () {
|
|
338
|
+
await Promise.all(this.promises)
|
|
339
|
+
}
|
|
340
|
+
}
|
|
@@ -16,38 +16,43 @@ import { SpeechFlowChunk } from "./speechflow-node"
|
|
|
16
16
|
import * as util from "./speechflow-util"
|
|
17
17
|
|
|
18
18
|
/* create a Duplex/Transform stream which has
|
|
19
|
-
object-mode
|
|
20
|
-
|
|
19
|
+
object-mode on Writable side and
|
|
20
|
+
buffer/string-mode on Readable side */
|
|
21
|
+
export function createTransformStreamForWritableSide (
|
|
22
|
+
type: "text" | "audio",
|
|
23
|
+
readableHighWaterMark?: number
|
|
24
|
+
) {
|
|
21
25
|
return new Stream.Transform({
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
writableObjectMode: true,
|
|
27
|
+
readableObjectMode: false,
|
|
28
|
+
writableHighWaterMark: 1,
|
|
29
|
+
readableHighWaterMark: readableHighWaterMark ?? (type === "audio" ? 19200 /* 400ms */ : 65536 /* 64KB */),
|
|
30
|
+
decodeStrings: false,
|
|
26
31
|
transform (chunk: SpeechFlowChunk, encoding, callback) {
|
|
27
32
|
this.push(chunk.payload)
|
|
28
33
|
callback()
|
|
29
34
|
},
|
|
30
35
|
final (callback) {
|
|
31
|
-
this.push(null)
|
|
32
36
|
callback()
|
|
33
37
|
}
|
|
34
38
|
})
|
|
35
39
|
}
|
|
36
40
|
|
|
37
41
|
/* create a Duplex/Transform stream which has
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
buffer/string-mode on Writable side and
|
|
43
|
+
object-mode on Readable side */
|
|
44
|
+
export function createTransformStreamForReadableSide (
|
|
45
|
+
type: "text" | "audio",
|
|
46
|
+
getTimeZero: () => DateTime,
|
|
47
|
+
writableHighWaterMark?: number
|
|
48
|
+
) {
|
|
40
49
|
return new Stream.Transform({
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
50
|
+
writableObjectMode: false,
|
|
51
|
+
readableObjectMode: true,
|
|
52
|
+
writableHighWaterMark: writableHighWaterMark ?? (type === "audio" ? 19200 /* 400ms */ : 65536 /* 64KB */),
|
|
53
|
+
readableHighWaterMark: 1,
|
|
54
|
+
decodeStrings: false,
|
|
45
55
|
transform (chunk: Buffer | string, encoding, callback) {
|
|
46
|
-
if (chunk === null) {
|
|
47
|
-
this.push(null)
|
|
48
|
-
callback()
|
|
49
|
-
return
|
|
50
|
-
}
|
|
51
56
|
const timeZero = getTimeZero()
|
|
52
57
|
const start = DateTime.now().diff(timeZero)
|
|
53
58
|
let end = start
|
|
@@ -61,7 +66,6 @@ export function createTransformStreamForReadableSide (type: "text" | "audio", ge
|
|
|
61
66
|
callback()
|
|
62
67
|
},
|
|
63
68
|
final (callback) {
|
|
64
|
-
this.push(null)
|
|
65
69
|
callback()
|
|
66
70
|
}
|
|
67
71
|
})
|
|
@@ -110,8 +114,7 @@ export function streamChunkEncode (chunk: SpeechFlowChunk) {
|
|
|
110
114
|
}
|
|
111
115
|
if (chunk.meta.size > 0)
|
|
112
116
|
data.meta = Array.from(chunk.meta.entries())
|
|
113
|
-
|
|
114
|
-
return _data
|
|
117
|
+
return CBOR.encode(data)
|
|
115
118
|
}
|
|
116
119
|
|
|
117
120
|
/* decode/unserialize chunk of data */
|
|
@@ -201,7 +204,7 @@ export class StreamWrapper extends Stream.Transform {
|
|
|
201
204
|
}
|
|
202
205
|
|
|
203
206
|
/* helper function for destruction of a stream */
|
|
204
|
-
export async function destroyStream(
|
|
207
|
+
export async function destroyStream (
|
|
205
208
|
stream: Stream.Readable | Stream.Writable | Stream.Duplex | Stream.Transform
|
|
206
209
|
) {
|
|
207
210
|
/* signal the end for a writable stream */
|
|
@@ -214,8 +217,10 @@ export async function destroyStream(
|
|
|
214
217
|
new Promise<void>((resolve) => {
|
|
215
218
|
stream.end(() => { resolve() })
|
|
216
219
|
}),
|
|
217
|
-
util.
|
|
218
|
-
])
|
|
220
|
+
util.timeout(5000, "stream end timeout")
|
|
221
|
+
]).catch(() => {
|
|
222
|
+
/* ignore timeout -- stream will be destroyed anyway */
|
|
223
|
+
})
|
|
219
224
|
|
|
220
225
|
/* destroy the stream */
|
|
221
226
|
stream.destroy()
|