speechflow 1.6.5 → 1.6.6
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 +12 -0
- package/README.md +23 -0
- package/etc/stx.conf +5 -0
- package/package.json +3 -3
- package/speechflow-cli/dst/speechflow-node-a2a-compressor.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-compressor.js +12 -11
- package/speechflow-cli/dst/speechflow-node-a2a-compressor.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-expander.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-expander.js +12 -11
- package/speechflow-cli/dst/speechflow-node-a2a-expander.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-ffmpeg.js +2 -8
- package/speechflow-cli/dst/speechflow-node-a2a-ffmpeg.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-filler.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-filler.js +18 -16
- package/speechflow-cli/dst/speechflow-node-a2a-filler.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-gain.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-gain.js +8 -8
- package/speechflow-cli/dst/speechflow-node-a2a-gain.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-gender.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-gender.js +38 -34
- package/speechflow-cli/dst/speechflow-node-a2a-gender.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-meter.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-meter.js +11 -11
- package/speechflow-cli/dst/speechflow-node-a2a-meter.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-mute.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-mute.js +44 -10
- package/speechflow-cli/dst/speechflow-node-a2a-mute.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-pitch.d.ts +13 -0
- package/speechflow-cli/dst/speechflow-node-a2a-pitch.js +213 -0
- package/speechflow-cli/dst/speechflow-node-a2a-pitch.js.map +1 -0
- package/speechflow-cli/dst/speechflow-node-a2a-pitch2-wt.d.ts +1 -0
- package/speechflow-cli/dst/speechflow-node-a2a-pitch2-wt.js +149 -0
- package/speechflow-cli/dst/speechflow-node-a2a-pitch2-wt.js.map +1 -0
- package/speechflow-cli/dst/speechflow-node-a2a-pitch2.d.ts +13 -0
- package/speechflow-cli/dst/speechflow-node-a2a-pitch2.js +202 -0
- package/speechflow-cli/dst/speechflow-node-a2a-pitch2.js.map +1 -0
- package/speechflow-cli/dst/speechflow-node-a2a-rnnoise.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-rnnoise.js +12 -11
- package/speechflow-cli/dst/speechflow-node-a2a-rnnoise.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-speex.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-speex.js +13 -12
- package/speechflow-cli/dst/speechflow-node-a2a-speex.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-vad.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-vad.js +24 -23
- package/speechflow-cli/dst/speechflow-node-a2a-vad.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-wav.js +35 -7
- package/speechflow-cli/dst/speechflow-node-a2a-wav.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2t-amazon.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-a2t-amazon.js +16 -16
- package/speechflow-cli/dst/speechflow-node-a2t-amazon.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2t-deepgram.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-a2t-deepgram.js +16 -16
- package/speechflow-cli/dst/speechflow-node-a2t-deepgram.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2t-openai.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-a2t-openai.js +15 -15
- package/speechflow-cli/dst/speechflow-node-a2t-openai.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2a-amazon.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-t2a-amazon.js +9 -9
- package/speechflow-cli/dst/speechflow-node-t2a-amazon.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2a-elevenlabs.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-t2a-elevenlabs.js +13 -12
- package/speechflow-cli/dst/speechflow-node-t2a-elevenlabs.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2a-kokoro.js +4 -4
- package/speechflow-cli/dst/speechflow-node-t2a-kokoro.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-amazon.js +3 -3
- package/speechflow-cli/dst/speechflow-node-t2t-amazon.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-deepl.js +2 -2
- package/speechflow-cli/dst/speechflow-node-t2t-deepl.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-format.js +36 -2
- package/speechflow-cli/dst/speechflow-node-t2t-format.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-google.js +2 -2
- package/speechflow-cli/dst/speechflow-node-t2t-google.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-modify.js +5 -5
- package/speechflow-cli/dst/speechflow-node-t2t-modify.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-ollama.js +2 -2
- package/speechflow-cli/dst/speechflow-node-t2t-ollama.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-openai.js +2 -2
- package/speechflow-cli/dst/speechflow-node-t2t-openai.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-sentence.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-sentence.js +13 -13
- package/speechflow-cli/dst/speechflow-node-t2t-sentence.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-subtitle.js +2 -2
- package/speechflow-cli/dst/speechflow-node-t2t-subtitle.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-transformers.js +2 -2
- package/speechflow-cli/dst/speechflow-node-t2t-transformers.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-x2x-filter.js +2 -2
- package/speechflow-cli/dst/speechflow-node-x2x-filter.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-x2x-trace.d.ts +1 -1
- package/speechflow-cli/dst/speechflow-node-x2x-trace.js +42 -8
- package/speechflow-cli/dst/speechflow-node-x2x-trace.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-xio-device.js +3 -2
- package/speechflow-cli/dst/speechflow-node-xio-device.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-xio-file.js +19 -18
- package/speechflow-cli/dst/speechflow-node-xio-file.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-xio-mqtt.js +13 -13
- package/speechflow-cli/dst/speechflow-node-xio-mqtt.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-xio-websocket.js +8 -8
- package/speechflow-cli/dst/speechflow-node-xio-websocket.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node.js +6 -6
- package/speechflow-cli/dst/speechflow-node.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-stream.d.ts +1 -0
- package/speechflow-cli/dst/speechflow-util-stream.js +22 -2
- package/speechflow-cli/dst/speechflow-util-stream.js.map +1 -1
- package/speechflow-cli/etc/tsconfig.json +1 -0
- package/speechflow-cli/package.json +14 -14
- package/speechflow-cli/src/speechflow-node-a2a-compressor.ts +13 -12
- package/speechflow-cli/src/speechflow-node-a2a-expander.ts +13 -12
- package/speechflow-cli/src/speechflow-node-a2a-ffmpeg.ts +2 -8
- package/speechflow-cli/src/speechflow-node-a2a-filler.ts +19 -17
- package/speechflow-cli/src/speechflow-node-a2a-gain.ts +8 -8
- package/speechflow-cli/src/speechflow-node-a2a-gender.ts +42 -36
- package/speechflow-cli/src/speechflow-node-a2a-meter.ts +11 -11
- package/speechflow-cli/src/speechflow-node-a2a-mute.ts +11 -10
- package/speechflow-cli/src/speechflow-node-a2a-pitch.ts +221 -0
- package/speechflow-cli/src/speechflow-node-a2a-rnnoise.ts +13 -12
- package/speechflow-cli/src/speechflow-node-a2a-speex.ts +14 -13
- package/speechflow-cli/src/speechflow-node-a2a-vad.ts +24 -23
- package/speechflow-cli/src/speechflow-node-a2a-wav.ts +2 -7
- package/speechflow-cli/src/speechflow-node-a2t-amazon.ts +16 -16
- package/speechflow-cli/src/speechflow-node-a2t-deepgram.ts +16 -16
- package/speechflow-cli/src/speechflow-node-a2t-openai.ts +15 -15
- package/speechflow-cli/src/speechflow-node-t2a-amazon.ts +9 -9
- package/speechflow-cli/src/speechflow-node-t2a-elevenlabs.ts +13 -12
- package/speechflow-cli/src/speechflow-node-t2a-kokoro.ts +4 -4
- package/speechflow-cli/src/speechflow-node-t2t-amazon.ts +3 -3
- package/speechflow-cli/src/speechflow-node-t2t-deepl.ts +2 -2
- package/speechflow-cli/src/speechflow-node-t2t-format.ts +3 -2
- package/speechflow-cli/src/speechflow-node-t2t-google.ts +2 -2
- package/speechflow-cli/src/speechflow-node-t2t-modify.ts +6 -6
- package/speechflow-cli/src/speechflow-node-t2t-ollama.ts +2 -2
- package/speechflow-cli/src/speechflow-node-t2t-openai.ts +2 -2
- package/speechflow-cli/src/speechflow-node-t2t-sentence.ts +13 -13
- package/speechflow-cli/src/speechflow-node-t2t-subtitle.ts +2 -2
- package/speechflow-cli/src/speechflow-node-t2t-transformers.ts +2 -2
- package/speechflow-cli/src/speechflow-node-x2x-filter.ts +2 -2
- package/speechflow-cli/src/speechflow-node-x2x-trace.ts +10 -9
- package/speechflow-cli/src/speechflow-node-xio-device.ts +4 -3
- package/speechflow-cli/src/speechflow-node-xio-file.ts +20 -19
- package/speechflow-cli/src/speechflow-node-xio-mqtt.ts +14 -14
- package/speechflow-cli/src/speechflow-node-xio-websocket.ts +10 -10
- package/speechflow-cli/src/speechflow-node.ts +6 -6
- package/speechflow-cli/src/speechflow-util-audio.ts +1 -1
- package/speechflow-cli/src/speechflow-util-stream.ts +30 -5
- package/speechflow-ui-db/dst/index.js +20 -20
- package/speechflow-ui-db/package.json +7 -7
- package/speechflow-ui-st/dst/index.js +40 -40
- package/speechflow-ui-st/package.json +8 -8
|
@@ -70,7 +70,7 @@ export default class SpeechFlowNodeA2TAmazon extends SpeechFlowNode {
|
|
|
70
70
|
/* internal state */
|
|
71
71
|
private client: TranscribeStreamingClient | null = null
|
|
72
72
|
private clientStream: AsyncIterable<TranscriptResultStream> | null = null
|
|
73
|
-
private
|
|
73
|
+
private closing = false
|
|
74
74
|
private initTimeout: ReturnType<typeof setTimeout> | null = null
|
|
75
75
|
private connectionTimeout: ReturnType<typeof setTimeout> | null = null
|
|
76
76
|
private queue: util.SingleQueue<SpeechFlowChunk | null> | null = null
|
|
@@ -111,7 +111,7 @@ export default class SpeechFlowNodeA2TAmazon extends SpeechFlowNode {
|
|
|
111
111
|
throw new Error("Amazon Transcribe node currently supports PCM-S16LE audio only")
|
|
112
112
|
|
|
113
113
|
/* clear destruction flag */
|
|
114
|
-
this.
|
|
114
|
+
this.closing = false
|
|
115
115
|
|
|
116
116
|
/* create queue for results */
|
|
117
117
|
this.queue = new util.SingleQueue<SpeechFlowChunk | null>()
|
|
@@ -130,7 +130,7 @@ export default class SpeechFlowNodeA2TAmazon extends SpeechFlowNode {
|
|
|
130
130
|
if (this.client === null)
|
|
131
131
|
throw new Error("failed to establish Amazon Transcribe client")
|
|
132
132
|
|
|
133
|
-
/*
|
|
133
|
+
/* create an AudioStream for Amazon Transcribe */
|
|
134
134
|
const audioQueue = new AsyncQueue<Uint8Array>()
|
|
135
135
|
const audioStream = (async function *(q: AsyncQueue<Uint8Array>): AsyncIterable<AudioStream> {
|
|
136
136
|
for await (const chunk of q) {
|
|
@@ -140,7 +140,7 @@ export default class SpeechFlowNodeA2TAmazon extends SpeechFlowNode {
|
|
|
140
140
|
|
|
141
141
|
/* start streaming */
|
|
142
142
|
const ensureAudioStreamActive = async () => {
|
|
143
|
-
if (this.clientStream !== null || this.
|
|
143
|
+
if (this.clientStream !== null || this.closing)
|
|
144
144
|
return
|
|
145
145
|
const language: LanguageCode = this.params.language === "de" ? "de-DE" : "en-US"
|
|
146
146
|
const command = new StartStreamTranscriptionCommand({
|
|
@@ -172,7 +172,7 @@ export default class SpeechFlowNodeA2TAmazon extends SpeechFlowNode {
|
|
|
172
172
|
const tsStart = Duration.fromMillis((result.StartTime ?? 0) * 1000).plus(this.timeZeroOffset)
|
|
173
173
|
const tsEnd = Duration.fromMillis((result.EndTime ?? 0) * 1000).plus(this.timeZeroOffset)
|
|
174
174
|
const metas = metastore.fetch(tsStart, tsEnd)
|
|
175
|
-
const meta = metas.reduce((prev: Map<string, any>, curr: Map<string, any>) => {
|
|
175
|
+
const meta = metas.toReversed().reduce((prev: Map<string, any>, curr: Map<string, any>) => {
|
|
176
176
|
curr.forEach((val, key) => { prev.set(key, val) })
|
|
177
177
|
return prev
|
|
178
178
|
}, new Map<string, any>())
|
|
@@ -210,7 +210,7 @@ export default class SpeechFlowNodeA2TAmazon extends SpeechFlowNode {
|
|
|
210
210
|
decodeStrings: false,
|
|
211
211
|
highWaterMark: 1,
|
|
212
212
|
write (chunk: SpeechFlowChunk, encoding, callback) {
|
|
213
|
-
if (self.
|
|
213
|
+
if (self.closing || self.client === null) {
|
|
214
214
|
callback(new Error("stream already destroyed"))
|
|
215
215
|
return
|
|
216
216
|
}
|
|
@@ -223,7 +223,7 @@ export default class SpeechFlowNodeA2TAmazon extends SpeechFlowNode {
|
|
|
223
223
|
self.log("debug", `send data (${chunk.payload.byteLength} bytes)`)
|
|
224
224
|
if (chunk.meta.size > 0)
|
|
225
225
|
metastore.store(chunk.timestampStart, chunk.timestampEnd, chunk.meta)
|
|
226
|
-
audioQueue.push(new Uint8Array(chunk.payload)) /*
|
|
226
|
+
audioQueue.push(new Uint8Array(chunk.payload)) /* intentionally discard all time information */
|
|
227
227
|
ensureAudioStreamActive().catch((error: unknown) => {
|
|
228
228
|
self.log("error", `failed to start audio stream: ${util.ensureError(error).message}`)
|
|
229
229
|
})
|
|
@@ -232,12 +232,12 @@ export default class SpeechFlowNodeA2TAmazon extends SpeechFlowNode {
|
|
|
232
232
|
}
|
|
233
233
|
},
|
|
234
234
|
read (size) {
|
|
235
|
-
if (self.
|
|
235
|
+
if (self.closing || self.queue === null) {
|
|
236
236
|
this.push(null)
|
|
237
237
|
return
|
|
238
238
|
}
|
|
239
239
|
self.queue.read().then((chunk) => {
|
|
240
|
-
if (self.
|
|
240
|
+
if (self.closing || self.queue === null) {
|
|
241
241
|
this.push(null)
|
|
242
242
|
return
|
|
243
243
|
}
|
|
@@ -250,12 +250,12 @@ export default class SpeechFlowNodeA2TAmazon extends SpeechFlowNode {
|
|
|
250
250
|
this.push(chunk)
|
|
251
251
|
}
|
|
252
252
|
}).catch((error: unknown) => {
|
|
253
|
-
if (!self.
|
|
253
|
+
if (!self.closing && self.queue !== null)
|
|
254
254
|
self.log("error", `queue read error: ${util.ensureError(error).message}`)
|
|
255
255
|
})
|
|
256
256
|
},
|
|
257
257
|
final (callback) {
|
|
258
|
-
if (self.
|
|
258
|
+
if (self.closing || self.client === null) {
|
|
259
259
|
callback()
|
|
260
260
|
return
|
|
261
261
|
}
|
|
@@ -263,7 +263,7 @@ export default class SpeechFlowNodeA2TAmazon extends SpeechFlowNode {
|
|
|
263
263
|
() => self.client!.destroy(),
|
|
264
264
|
(error: Error) => self.log("warning", `error closing Amazon Transcribe connection: ${error}`)
|
|
265
265
|
)
|
|
266
|
-
audioQueue.push(null) /*
|
|
266
|
+
audioQueue.push(null) /* do not push null to stream, let Amazon Transcribe do it */
|
|
267
267
|
audioQueue.destroy()
|
|
268
268
|
callback()
|
|
269
269
|
}
|
|
@@ -272,8 +272,8 @@ export default class SpeechFlowNodeA2TAmazon extends SpeechFlowNode {
|
|
|
272
272
|
|
|
273
273
|
/* close node */
|
|
274
274
|
async close () {
|
|
275
|
-
/* indicate
|
|
276
|
-
this.
|
|
275
|
+
/* indicate closing first to stop all async operations */
|
|
276
|
+
this.closing = true
|
|
277
277
|
|
|
278
278
|
/* cleanup all timers */
|
|
279
279
|
if (this.initTimeout !== null) {
|
|
@@ -297,9 +297,9 @@ export default class SpeechFlowNodeA2TAmazon extends SpeechFlowNode {
|
|
|
297
297
|
this.client = null
|
|
298
298
|
}
|
|
299
299
|
|
|
300
|
-
/*
|
|
300
|
+
/* shutdown stream */
|
|
301
301
|
if (this.stream !== null) {
|
|
302
|
-
this.stream
|
|
302
|
+
await util.destroyStream(this.stream)
|
|
303
303
|
this.stream = null
|
|
304
304
|
}
|
|
305
305
|
}
|
|
@@ -22,7 +22,7 @@ export default class SpeechFlowNodeA2TDeepgram extends SpeechFlowNode {
|
|
|
22
22
|
|
|
23
23
|
/* internal state */
|
|
24
24
|
private dg: Deepgram.LiveClient | null = null
|
|
25
|
-
private
|
|
25
|
+
private closing = false
|
|
26
26
|
private initTimeout: ReturnType<typeof setTimeout> | null = null
|
|
27
27
|
private connectionTimeout: ReturnType<typeof setTimeout> | null = null
|
|
28
28
|
private queue: util.SingleQueue<SpeechFlowChunk | null> | null = null
|
|
@@ -75,7 +75,7 @@ export default class SpeechFlowNodeA2TDeepgram extends SpeechFlowNode {
|
|
|
75
75
|
throw new Error("Deepgram node currently supports PCM-S16LE audio only")
|
|
76
76
|
|
|
77
77
|
/* clear destruction flag */
|
|
78
|
-
this.
|
|
78
|
+
this.closing = false
|
|
79
79
|
|
|
80
80
|
/* create queue for results */
|
|
81
81
|
this.queue = new util.SingleQueue<SpeechFlowChunk | null>()
|
|
@@ -114,7 +114,7 @@ export default class SpeechFlowNodeA2TDeepgram extends SpeechFlowNode {
|
|
|
114
114
|
|
|
115
115
|
/* hook onto Deepgram API events */
|
|
116
116
|
this.dg.on(Deepgram.LiveTranscriptionEvents.Transcript, async (data) => {
|
|
117
|
-
if (this.
|
|
117
|
+
if (this.closing || this.queue === null)
|
|
118
118
|
return
|
|
119
119
|
const text = (data.channel?.alternatives[0]?.transcript ?? "") as string
|
|
120
120
|
const words = (data.channel?.alternatives[0]?.words ?? []) as
|
|
@@ -130,7 +130,7 @@ export default class SpeechFlowNodeA2TDeepgram extends SpeechFlowNode {
|
|
|
130
130
|
const start = Duration.fromMillis(data.start * 1000).plus(this.timeZeroOffset)
|
|
131
131
|
const end = start.plus({ seconds: data.duration })
|
|
132
132
|
const metas = metastore.fetch(start, end)
|
|
133
|
-
const meta = metas.reduce((prev: Map<string, any>, curr: Map<string, any>) => {
|
|
133
|
+
const meta = metas.toReversed().reduce((prev: Map<string, any>, curr: Map<string, any>) => {
|
|
134
134
|
curr.forEach((val, key) => { prev.set(key, val) })
|
|
135
135
|
return prev
|
|
136
136
|
}, new Map<string, any>())
|
|
@@ -156,12 +156,12 @@ export default class SpeechFlowNodeA2TDeepgram extends SpeechFlowNode {
|
|
|
156
156
|
})
|
|
157
157
|
this.dg.on(Deepgram.LiveTranscriptionEvents.Close, () => {
|
|
158
158
|
this.log("info", "connection close")
|
|
159
|
-
if (!this.
|
|
159
|
+
if (!this.closing && this.queue !== null)
|
|
160
160
|
this.queue.write(null)
|
|
161
161
|
})
|
|
162
162
|
this.dg.on(Deepgram.LiveTranscriptionEvents.Error, (error: Error) => {
|
|
163
163
|
this.log("error", `error: ${error.message}`)
|
|
164
|
-
if (!this.
|
|
164
|
+
if (!this.closing && this.queue !== null)
|
|
165
165
|
this.queue.write(null)
|
|
166
166
|
this.emit("error")
|
|
167
167
|
})
|
|
@@ -193,7 +193,7 @@ export default class SpeechFlowNodeA2TDeepgram extends SpeechFlowNode {
|
|
|
193
193
|
decodeStrings: false,
|
|
194
194
|
highWaterMark: 1,
|
|
195
195
|
write (chunk: SpeechFlowChunk, encoding, callback) {
|
|
196
|
-
if (self.
|
|
196
|
+
if (self.closing || self.dg === null) {
|
|
197
197
|
callback(new Error("stream already destroyed"))
|
|
198
198
|
return
|
|
199
199
|
}
|
|
@@ -210,7 +210,7 @@ export default class SpeechFlowNodeA2TDeepgram extends SpeechFlowNode {
|
|
|
210
210
|
self.dg.send(chunk.payload.buffer) /* intentionally discard all time information */
|
|
211
211
|
}
|
|
212
212
|
catch (error) {
|
|
213
|
-
callback(error
|
|
213
|
+
callback(util.ensureError(error, "failed to send to Deepgram"))
|
|
214
214
|
return
|
|
215
215
|
}
|
|
216
216
|
}
|
|
@@ -218,12 +218,12 @@ export default class SpeechFlowNodeA2TDeepgram extends SpeechFlowNode {
|
|
|
218
218
|
}
|
|
219
219
|
},
|
|
220
220
|
read (size) {
|
|
221
|
-
if (self.
|
|
221
|
+
if (self.closing || self.queue === null) {
|
|
222
222
|
this.push(null)
|
|
223
223
|
return
|
|
224
224
|
}
|
|
225
225
|
self.queue.read().then((chunk) => {
|
|
226
|
-
if (self.
|
|
226
|
+
if (self.closing || self.queue === null) {
|
|
227
227
|
this.push(null)
|
|
228
228
|
return
|
|
229
229
|
}
|
|
@@ -236,12 +236,12 @@ export default class SpeechFlowNodeA2TDeepgram extends SpeechFlowNode {
|
|
|
236
236
|
this.push(chunk)
|
|
237
237
|
}
|
|
238
238
|
}).catch((error: unknown) => {
|
|
239
|
-
if (!self.
|
|
239
|
+
if (!self.closing && self.queue !== null)
|
|
240
240
|
self.log("error", `queue read error: ${util.ensureError(error).message}`)
|
|
241
241
|
})
|
|
242
242
|
},
|
|
243
243
|
final (callback) {
|
|
244
|
-
if (self.
|
|
244
|
+
if (self.closing || self.dg === null) {
|
|
245
245
|
callback()
|
|
246
246
|
return
|
|
247
247
|
}
|
|
@@ -259,8 +259,8 @@ export default class SpeechFlowNodeA2TDeepgram extends SpeechFlowNode {
|
|
|
259
259
|
|
|
260
260
|
/* close node */
|
|
261
261
|
async close () {
|
|
262
|
-
/* indicate
|
|
263
|
-
this.
|
|
262
|
+
/* indicate closing first to stop all async operations */
|
|
263
|
+
this.closing = true
|
|
264
264
|
|
|
265
265
|
/* cleanup all timers */
|
|
266
266
|
if (this.initTimeout !== null) {
|
|
@@ -272,9 +272,9 @@ export default class SpeechFlowNodeA2TDeepgram extends SpeechFlowNode {
|
|
|
272
272
|
this.connectionTimeout = null
|
|
273
273
|
}
|
|
274
274
|
|
|
275
|
-
/*
|
|
275
|
+
/* shutdown stream */
|
|
276
276
|
if (this.stream !== null) {
|
|
277
|
-
this.stream
|
|
277
|
+
await util.destroyStream(this.stream)
|
|
278
278
|
this.stream = null
|
|
279
279
|
}
|
|
280
280
|
|
|
@@ -27,7 +27,7 @@ export default class SpeechFlowNodeA2TOpenAI extends SpeechFlowNode {
|
|
|
27
27
|
private ws: ws.WebSocket | null = null
|
|
28
28
|
private queue: util.SingleQueue<SpeechFlowChunk | null> | null = null
|
|
29
29
|
private resampler: SpeexResampler | null = null
|
|
30
|
-
private
|
|
30
|
+
private closing = false
|
|
31
31
|
private connectionTimeout: ReturnType<typeof setTimeout> | null = null
|
|
32
32
|
|
|
33
33
|
/* construct node */
|
|
@@ -60,7 +60,7 @@ export default class SpeechFlowNodeA2TOpenAI extends SpeechFlowNode {
|
|
|
60
60
|
throw new Error("OpenAI transcribe node currently supports PCM-S16LE audio only")
|
|
61
61
|
|
|
62
62
|
/* clear destruction flag */
|
|
63
|
-
this.
|
|
63
|
+
this.closing = false
|
|
64
64
|
|
|
65
65
|
/* create queue for results */
|
|
66
66
|
this.queue = new util.SingleQueue<SpeechFlowChunk | null>()
|
|
@@ -172,7 +172,7 @@ export default class SpeechFlowNodeA2TOpenAI extends SpeechFlowNode {
|
|
|
172
172
|
const start = DateTime.now().diff(this.timeOpen!) // FIXME: OpenAI does not provide timestamps
|
|
173
173
|
const end = start // FIXME: OpenAI does not provide timestamps
|
|
174
174
|
const metas = metastore.fetch(start, end)
|
|
175
|
-
const meta = metas.reduce((prev: Map<string, any>, curr: Map<string, any>) => {
|
|
175
|
+
const meta = metas.toReversed().reduce((prev: Map<string, any>, curr: Map<string, any>) => {
|
|
176
176
|
curr.forEach((val, key) => { prev.set(key, val) })
|
|
177
177
|
return prev
|
|
178
178
|
}, new Map<string, any>())
|
|
@@ -187,7 +187,7 @@ export default class SpeechFlowNodeA2TOpenAI extends SpeechFlowNode {
|
|
|
187
187
|
const start = DateTime.now().diff(this.timeOpen!) // FIXME: OpenAI does not provide timestamps
|
|
188
188
|
const end = start // FIXME: OpenAI does not provide timestamps
|
|
189
189
|
const metas = metastore.fetch(start, end)
|
|
190
|
-
const meta = metas.reduce((prev: Map<string, any>, curr: Map<string, any>) => {
|
|
190
|
+
const meta = metas.toReversed().reduce((prev: Map<string, any>, curr: Map<string, any>) => {
|
|
191
191
|
curr.forEach((val, key) => { prev.set(key, val) })
|
|
192
192
|
return prev
|
|
193
193
|
}, new Map<string, any>())
|
|
@@ -226,7 +226,7 @@ export default class SpeechFlowNodeA2TOpenAI extends SpeechFlowNode {
|
|
|
226
226
|
decodeStrings: false,
|
|
227
227
|
highWaterMark: 1,
|
|
228
228
|
write (chunk: SpeechFlowChunk, encoding, callback) {
|
|
229
|
-
if (self.
|
|
229
|
+
if (self.closing || self.ws === null) {
|
|
230
230
|
callback(new Error("stream already destroyed"))
|
|
231
231
|
return
|
|
232
232
|
}
|
|
@@ -248,7 +248,7 @@ export default class SpeechFlowNodeA2TOpenAI extends SpeechFlowNode {
|
|
|
248
248
|
})
|
|
249
249
|
}
|
|
250
250
|
catch (error) {
|
|
251
|
-
callback(error
|
|
251
|
+
callback(util.ensureError(error, "failed to send to OpenAI transcribe"))
|
|
252
252
|
return
|
|
253
253
|
}
|
|
254
254
|
}
|
|
@@ -256,12 +256,12 @@ export default class SpeechFlowNodeA2TOpenAI extends SpeechFlowNode {
|
|
|
256
256
|
}
|
|
257
257
|
},
|
|
258
258
|
read (size) {
|
|
259
|
-
if (self.
|
|
259
|
+
if (self.closing || self.queue === null) {
|
|
260
260
|
this.push(null)
|
|
261
261
|
return
|
|
262
262
|
}
|
|
263
263
|
self.queue.read().then((chunk) => {
|
|
264
|
-
if (self.
|
|
264
|
+
if (self.closing || self.queue === null) {
|
|
265
265
|
this.push(null)
|
|
266
266
|
return
|
|
267
267
|
}
|
|
@@ -274,12 +274,12 @@ export default class SpeechFlowNodeA2TOpenAI extends SpeechFlowNode {
|
|
|
274
274
|
this.push(chunk)
|
|
275
275
|
}
|
|
276
276
|
}).catch((error: unknown) => {
|
|
277
|
-
if (!self.
|
|
277
|
+
if (!self.closing && self.queue !== null)
|
|
278
278
|
self.log("error", `queue read error: ${util.ensureError(error).message}`)
|
|
279
279
|
})
|
|
280
280
|
},
|
|
281
281
|
final (callback) {
|
|
282
|
-
if (self.
|
|
282
|
+
if (self.closing || self.ws === null) {
|
|
283
283
|
callback()
|
|
284
284
|
return
|
|
285
285
|
}
|
|
@@ -291,7 +291,7 @@ export default class SpeechFlowNodeA2TOpenAI extends SpeechFlowNode {
|
|
|
291
291
|
}
|
|
292
292
|
catch (error) {
|
|
293
293
|
self.log("warning", `error closing OpenAI connection: ${error}`)
|
|
294
|
-
callback(error
|
|
294
|
+
callback(util.ensureError(error, "failed to close OpenAI connection"))
|
|
295
295
|
}
|
|
296
296
|
}
|
|
297
297
|
})
|
|
@@ -299,8 +299,8 @@ export default class SpeechFlowNodeA2TOpenAI extends SpeechFlowNode {
|
|
|
299
299
|
|
|
300
300
|
/* close node */
|
|
301
301
|
async close () {
|
|
302
|
-
/* indicate
|
|
303
|
-
this.
|
|
302
|
+
/* indicate closing first to stop all async operations */
|
|
303
|
+
this.closing = true
|
|
304
304
|
|
|
305
305
|
/* clear connection timeout */
|
|
306
306
|
if (this.connectionTimeout !== null) {
|
|
@@ -322,9 +322,9 @@ export default class SpeechFlowNodeA2TOpenAI extends SpeechFlowNode {
|
|
|
322
322
|
if (this.openai !== null)
|
|
323
323
|
this.openai = null
|
|
324
324
|
|
|
325
|
-
/*
|
|
325
|
+
/* shutdown stream */
|
|
326
326
|
if (this.stream !== null) {
|
|
327
|
-
this.stream
|
|
327
|
+
await util.destroyStream(this.stream)
|
|
328
328
|
this.stream = null
|
|
329
329
|
}
|
|
330
330
|
}
|
|
@@ -26,7 +26,7 @@ export default class SpeechFlowNodeT2AAmazon extends SpeechFlowNode {
|
|
|
26
26
|
|
|
27
27
|
/* internal state */
|
|
28
28
|
private client: PollyClient | null = null
|
|
29
|
-
private
|
|
29
|
+
private closing = false
|
|
30
30
|
private resampler: SpeexResampler | null = null
|
|
31
31
|
|
|
32
32
|
/* construct node */
|
|
@@ -61,7 +61,7 @@ export default class SpeechFlowNodeT2AAmazon extends SpeechFlowNode {
|
|
|
61
61
|
/* open node */
|
|
62
62
|
async open () {
|
|
63
63
|
/* clear destruction flag */
|
|
64
|
-
this.
|
|
64
|
+
this.closing = false
|
|
65
65
|
|
|
66
66
|
/* establish AWS Polly connection */
|
|
67
67
|
this.client = new PollyClient({
|
|
@@ -123,7 +123,7 @@ export default class SpeechFlowNodeT2AAmazon extends SpeechFlowNode {
|
|
|
123
123
|
decodeStrings: false,
|
|
124
124
|
highWaterMark: 1,
|
|
125
125
|
transform (chunk: SpeechFlowChunk, encoding, callback) {
|
|
126
|
-
if (self.
|
|
126
|
+
if (self.closing) {
|
|
127
127
|
callback(new Error("stream already destroyed"))
|
|
128
128
|
return
|
|
129
129
|
}
|
|
@@ -132,7 +132,7 @@ export default class SpeechFlowNodeT2AAmazon extends SpeechFlowNode {
|
|
|
132
132
|
else if (chunk.payload.length > 0) {
|
|
133
133
|
self.log("debug", `send data (${chunk.payload.length} bytes): "${chunk.payload}"`)
|
|
134
134
|
textToSpeech(chunk.payload as string).then((buffer) => {
|
|
135
|
-
if (self.
|
|
135
|
+
if (self.closing)
|
|
136
136
|
throw new Error("stream destroyed during processing")
|
|
137
137
|
const chunkNew = chunk.clone()
|
|
138
138
|
chunkNew.type = "audio"
|
|
@@ -147,7 +147,7 @@ export default class SpeechFlowNodeT2AAmazon extends SpeechFlowNode {
|
|
|
147
147
|
callback()
|
|
148
148
|
},
|
|
149
149
|
final (callback) {
|
|
150
|
-
if (self.
|
|
150
|
+
if (self.closing) {
|
|
151
151
|
callback()
|
|
152
152
|
return
|
|
153
153
|
}
|
|
@@ -159,8 +159,8 @@ export default class SpeechFlowNodeT2AAmazon extends SpeechFlowNode {
|
|
|
159
159
|
|
|
160
160
|
/* close node */
|
|
161
161
|
async close () {
|
|
162
|
-
/* indicate
|
|
163
|
-
this.
|
|
162
|
+
/* indicate closing */
|
|
163
|
+
this.closing = true
|
|
164
164
|
|
|
165
165
|
/* destroy resampler */
|
|
166
166
|
if (this.resampler !== null)
|
|
@@ -171,9 +171,9 @@ export default class SpeechFlowNodeT2AAmazon extends SpeechFlowNode {
|
|
|
171
171
|
this.client.destroy()
|
|
172
172
|
this.client = null
|
|
173
173
|
}
|
|
174
|
-
/*
|
|
174
|
+
/* shutdown stream */
|
|
175
175
|
if (this.stream !== null) {
|
|
176
|
-
this.stream
|
|
176
|
+
await util.destroyStream(this.stream)
|
|
177
177
|
this.stream = null
|
|
178
178
|
}
|
|
179
179
|
}
|
|
@@ -14,6 +14,7 @@ import SpeexResampler from "speex-resampler"
|
|
|
14
14
|
|
|
15
15
|
/* internal dependencies */
|
|
16
16
|
import SpeechFlowNode, { SpeechFlowChunk } from "./speechflow-node"
|
|
17
|
+
import * as util from "./speechflow-util"
|
|
17
18
|
|
|
18
19
|
/* SpeechFlow node for Elevenlabs text-to-speech conversion */
|
|
19
20
|
export default class SpeechFlowNodeT2AElevenlabs extends SpeechFlowNode {
|
|
@@ -22,7 +23,7 @@ export default class SpeechFlowNodeT2AElevenlabs extends SpeechFlowNode {
|
|
|
22
23
|
|
|
23
24
|
/* internal state */
|
|
24
25
|
private elevenlabs: ElevenLabs.ElevenLabsClient | null = null
|
|
25
|
-
private
|
|
26
|
+
private closing = false
|
|
26
27
|
private resampler: SpeexResampler | null = null
|
|
27
28
|
|
|
28
29
|
/* construct node */
|
|
@@ -67,7 +68,7 @@ export default class SpeechFlowNodeT2AElevenlabs extends SpeechFlowNode {
|
|
|
67
68
|
/* open node */
|
|
68
69
|
async open () {
|
|
69
70
|
/* clear destruction flag */
|
|
70
|
-
this.
|
|
71
|
+
this.closing = false
|
|
71
72
|
|
|
72
73
|
/* establish ElevenLabs API connection */
|
|
73
74
|
this.elevenlabs = new ElevenLabs.ElevenLabsClient({
|
|
@@ -116,7 +117,7 @@ export default class SpeechFlowNodeT2AElevenlabs extends SpeechFlowNode {
|
|
|
116
117
|
modelId: model,
|
|
117
118
|
languageCode: this.params.language,
|
|
118
119
|
outputFormat: `pcm_${maxSampleRate}` as ElevenLabs.ElevenLabs.OutputFormat,
|
|
119
|
-
seed: 815, /*
|
|
120
|
+
seed: 815, /* arbitrary, but fixated by us */
|
|
120
121
|
voiceSettings: {
|
|
121
122
|
speed: this.params.speed,
|
|
122
123
|
stability: this.params.stability,
|
|
@@ -140,7 +141,7 @@ export default class SpeechFlowNodeT2AElevenlabs extends SpeechFlowNode {
|
|
|
140
141
|
decodeStrings: false,
|
|
141
142
|
highWaterMark: 1,
|
|
142
143
|
transform (chunk: SpeechFlowChunk, encoding, callback) {
|
|
143
|
-
if (self.
|
|
144
|
+
if (self.closing)
|
|
144
145
|
callback(new Error("stream already destroyed"))
|
|
145
146
|
else if (Buffer.isBuffer(chunk.payload))
|
|
146
147
|
callback(new Error("invalid chunk payload type"))
|
|
@@ -157,14 +158,14 @@ export default class SpeechFlowNodeT2AElevenlabs extends SpeechFlowNode {
|
|
|
157
158
|
}
|
|
158
159
|
}
|
|
159
160
|
try {
|
|
160
|
-
if (self.
|
|
161
|
+
if (self.closing) {
|
|
161
162
|
clearProcessTimeout()
|
|
162
163
|
callback(new Error("stream destroyed during processing"))
|
|
163
164
|
return
|
|
164
165
|
}
|
|
165
166
|
const stream = await speechStream(chunk.payload as string)
|
|
166
167
|
const buffer = await getStreamAsBuffer(stream)
|
|
167
|
-
if (self.
|
|
168
|
+
if (self.closing) {
|
|
168
169
|
clearProcessTimeout()
|
|
169
170
|
callback(new Error("stream destroyed during processing"))
|
|
170
171
|
return
|
|
@@ -180,13 +181,13 @@ export default class SpeechFlowNodeT2AElevenlabs extends SpeechFlowNode {
|
|
|
180
181
|
}
|
|
181
182
|
catch (error) {
|
|
182
183
|
clearProcessTimeout()
|
|
183
|
-
callback(error
|
|
184
|
+
callback(util.ensureError(error, "ElevenLabs processing failed"))
|
|
184
185
|
}
|
|
185
186
|
})()
|
|
186
187
|
}
|
|
187
188
|
},
|
|
188
189
|
final (callback) {
|
|
189
|
-
if (self.
|
|
190
|
+
if (self.closing) {
|
|
190
191
|
callback()
|
|
191
192
|
return
|
|
192
193
|
}
|
|
@@ -198,12 +199,12 @@ export default class SpeechFlowNodeT2AElevenlabs extends SpeechFlowNode {
|
|
|
198
199
|
|
|
199
200
|
/* close node */
|
|
200
201
|
async close () {
|
|
201
|
-
/* indicate
|
|
202
|
-
this.
|
|
202
|
+
/* indicate closing */
|
|
203
|
+
this.closing = true
|
|
203
204
|
|
|
204
|
-
/*
|
|
205
|
+
/* shutdown stream */
|
|
205
206
|
if (this.stream !== null) {
|
|
206
|
-
this.stream
|
|
207
|
+
await util.destroyStream(this.stream)
|
|
207
208
|
this.stream = null
|
|
208
209
|
}
|
|
209
210
|
|
|
@@ -119,7 +119,7 @@ export default class SpeechFlowNodeT2AKokoro extends SpeechFlowNode {
|
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
/* create transform stream and connect it to the Kokoro API */
|
|
122
|
-
const
|
|
122
|
+
const self = this
|
|
123
123
|
this.stream = new Stream.Transform({
|
|
124
124
|
writableObjectMode: true,
|
|
125
125
|
readableObjectMode: true,
|
|
@@ -130,7 +130,7 @@ export default class SpeechFlowNodeT2AKokoro extends SpeechFlowNode {
|
|
|
130
130
|
callback(new Error("invalid chunk payload type"))
|
|
131
131
|
else {
|
|
132
132
|
text2speech(chunk.payload).then((buffer) => {
|
|
133
|
-
log("info", `Kokoro: received audio (buffer length: ${buffer.byteLength})`)
|
|
133
|
+
self.log("info", `Kokoro: received audio (buffer length: ${buffer.byteLength})`)
|
|
134
134
|
chunk = chunk.clone()
|
|
135
135
|
chunk.type = "audio"
|
|
136
136
|
chunk.payload = buffer
|
|
@@ -150,9 +150,9 @@ export default class SpeechFlowNodeT2AKokoro extends SpeechFlowNode {
|
|
|
150
150
|
|
|
151
151
|
/* close node */
|
|
152
152
|
async close () {
|
|
153
|
-
/*
|
|
153
|
+
/* shutdown stream */
|
|
154
154
|
if (this.stream !== null) {
|
|
155
|
-
this.stream
|
|
155
|
+
await util.destroyStream(this.stream)
|
|
156
156
|
this.stream = null
|
|
157
157
|
}
|
|
158
158
|
|
|
@@ -101,7 +101,7 @@ export default class SpeechFlowNodeT2TAmazon extends SpeechFlowNode {
|
|
|
101
101
|
await new Promise((resolve) => setTimeout(resolve, delayMs))
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
|
-
throw
|
|
104
|
+
throw util.ensureError(lastError)
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
/* establish a duplex stream and connect it to AWS Translate */
|
|
@@ -143,9 +143,9 @@ export default class SpeechFlowNodeT2TAmazon extends SpeechFlowNode {
|
|
|
143
143
|
this.client = null
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
-
/*
|
|
146
|
+
/* shutdown stream */
|
|
147
147
|
if (this.stream !== null) {
|
|
148
|
-
this.stream
|
|
148
|
+
await util.destroyStream(this.stream)
|
|
149
149
|
this.stream = null
|
|
150
150
|
}
|
|
151
151
|
}
|
|
@@ -108,9 +108,9 @@ export default class SpeechFlowNodeT2TDeepL extends SpeechFlowNode {
|
|
|
108
108
|
|
|
109
109
|
/* close node */
|
|
110
110
|
async close () {
|
|
111
|
-
/*
|
|
111
|
+
/* shutdown stream */
|
|
112
112
|
if (this.stream !== null) {
|
|
113
|
-
this.stream
|
|
113
|
+
await util.destroyStream(this.stream)
|
|
114
114
|
this.stream = null
|
|
115
115
|
}
|
|
116
116
|
|
|
@@ -12,6 +12,7 @@ import wrapText from "wrap-text"
|
|
|
12
12
|
|
|
13
13
|
/* internal dependencies */
|
|
14
14
|
import SpeechFlowNode, { SpeechFlowChunk } from "./speechflow-node"
|
|
15
|
+
import * as util from "./speechflow-util"
|
|
15
16
|
|
|
16
17
|
/* SpeechFlow node for text-to-text formatting */
|
|
17
18
|
export default class SpeechFlowNodeT2TFormat extends SpeechFlowNode {
|
|
@@ -71,9 +72,9 @@ export default class SpeechFlowNodeT2TFormat extends SpeechFlowNode {
|
|
|
71
72
|
|
|
72
73
|
/* close node */
|
|
73
74
|
async close () {
|
|
74
|
-
/*
|
|
75
|
+
/* shutdown stream */
|
|
75
76
|
if (this.stream !== null) {
|
|
76
|
-
this.stream
|
|
77
|
+
await util.destroyStream(this.stream)
|
|
77
78
|
this.stream = null
|
|
78
79
|
}
|
|
79
80
|
}
|
|
@@ -118,9 +118,9 @@ export default class SpeechFlowNodeT2TGoogle extends SpeechFlowNode {
|
|
|
118
118
|
|
|
119
119
|
/* close node */
|
|
120
120
|
async close () {
|
|
121
|
-
/*
|
|
121
|
+
/* shutdown stream */
|
|
122
122
|
if (this.stream !== null) {
|
|
123
|
-
this.stream
|
|
123
|
+
await util.destroyStream(this.stream)
|
|
124
124
|
this.stream = null
|
|
125
125
|
}
|
|
126
126
|
|
|
@@ -26,6 +26,10 @@ export default class SpeechFlowNodeT2TModify extends SpeechFlowNode {
|
|
|
26
26
|
replace: { type: "string", val: "" }
|
|
27
27
|
})
|
|
28
28
|
|
|
29
|
+
/* sanity check parameters */
|
|
30
|
+
if (this.params.match === "")
|
|
31
|
+
throw new Error("match parameter cannot be empty")
|
|
32
|
+
|
|
29
33
|
/* declare node input/output format */
|
|
30
34
|
this.input = "text"
|
|
31
35
|
this.output = "text"
|
|
@@ -33,10 +37,6 @@ export default class SpeechFlowNodeT2TModify extends SpeechFlowNode {
|
|
|
33
37
|
|
|
34
38
|
/* open node */
|
|
35
39
|
async open () {
|
|
36
|
-
/* validate parameters */
|
|
37
|
-
if (this.params.match === "")
|
|
38
|
-
throw new Error("match parameter cannot be empty")
|
|
39
|
-
|
|
40
40
|
/* compile regex pattern */
|
|
41
41
|
const regex = util.run("compiling regex pattern",
|
|
42
42
|
() => new RegExp(this.params.match, "g"))
|
|
@@ -75,9 +75,9 @@ export default class SpeechFlowNodeT2TModify extends SpeechFlowNode {
|
|
|
75
75
|
|
|
76
76
|
/* close node */
|
|
77
77
|
async close () {
|
|
78
|
-
/*
|
|
78
|
+
/* shutdown stream */
|
|
79
79
|
if (this.stream !== null) {
|
|
80
|
-
this.stream
|
|
80
|
+
await util.destroyStream(this.stream)
|
|
81
81
|
this.stream = null
|
|
82
82
|
}
|
|
83
83
|
}
|
|
@@ -266,9 +266,9 @@ export default class SpeechFlowNodeT2TOllama extends SpeechFlowNode {
|
|
|
266
266
|
|
|
267
267
|
/* close node */
|
|
268
268
|
async close () {
|
|
269
|
-
/*
|
|
269
|
+
/* shutdown stream */
|
|
270
270
|
if (this.stream !== null) {
|
|
271
|
-
this.stream
|
|
271
|
+
await util.destroyStream(this.stream)
|
|
272
272
|
this.stream = null
|
|
273
273
|
}
|
|
274
274
|
|