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.
Files changed (89) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/README.md +49 -38
  3. package/package.json +3 -3
  4. package/speechflow-cli/dst/speechflow-main-api.js +6 -5
  5. package/speechflow-cli/dst/speechflow-main-api.js.map +1 -1
  6. package/speechflow-cli/dst/speechflow-main-graph.js +7 -8
  7. package/speechflow-cli/dst/speechflow-main-graph.js.map +1 -1
  8. package/speechflow-cli/dst/speechflow-main-status.js +3 -7
  9. package/speechflow-cli/dst/speechflow-main-status.js.map +1 -1
  10. package/speechflow-cli/dst/speechflow-node-a2a-compressor-wt.js +3 -0
  11. package/speechflow-cli/dst/speechflow-node-a2a-compressor-wt.js.map +1 -1
  12. package/speechflow-cli/dst/speechflow-node-a2a-compressor.js +4 -2
  13. package/speechflow-cli/dst/speechflow-node-a2a-compressor.js.map +1 -1
  14. package/speechflow-cli/dst/speechflow-node-a2a-expander-wt.js +1 -1
  15. package/speechflow-cli/dst/speechflow-node-a2a-expander.js +4 -2
  16. package/speechflow-cli/dst/speechflow-node-a2a-expander.js.map +1 -1
  17. package/speechflow-cli/dst/speechflow-node-a2a-gender.js +2 -2
  18. package/speechflow-cli/dst/speechflow-node-a2a-gender.js.map +1 -1
  19. package/speechflow-cli/dst/speechflow-node-a2a-pitch.js +1 -2
  20. package/speechflow-cli/dst/speechflow-node-a2a-pitch.js.map +1 -1
  21. package/speechflow-cli/dst/speechflow-node-a2a-wav.js +8 -1
  22. package/speechflow-cli/dst/speechflow-node-a2a-wav.js.map +1 -1
  23. package/speechflow-cli/dst/speechflow-node-a2t-amazon.d.ts +0 -1
  24. package/speechflow-cli/dst/speechflow-node-a2t-amazon.js +1 -6
  25. package/speechflow-cli/dst/speechflow-node-a2t-amazon.js.map +1 -1
  26. package/speechflow-cli/dst/speechflow-node-a2t-deepgram.d.ts +0 -1
  27. package/speechflow-cli/dst/speechflow-node-a2t-deepgram.js +9 -9
  28. package/speechflow-cli/dst/speechflow-node-a2t-deepgram.js.map +1 -1
  29. package/speechflow-cli/dst/speechflow-node-a2t-openai.js +6 -4
  30. package/speechflow-cli/dst/speechflow-node-a2t-openai.js.map +1 -1
  31. package/speechflow-cli/dst/speechflow-node-t2a-amazon.js +6 -11
  32. package/speechflow-cli/dst/speechflow-node-t2a-amazon.js.map +1 -1
  33. package/speechflow-cli/dst/speechflow-node-t2a-elevenlabs.js +6 -5
  34. package/speechflow-cli/dst/speechflow-node-t2a-elevenlabs.js.map +1 -1
  35. package/speechflow-cli/dst/speechflow-node-t2a-kokoro.d.ts +2 -0
  36. package/speechflow-cli/dst/speechflow-node-t2a-kokoro.js +19 -6
  37. package/speechflow-cli/dst/speechflow-node-t2a-kokoro.js.map +1 -1
  38. package/speechflow-cli/dst/speechflow-node-x2x-filter.d.ts +1 -0
  39. package/speechflow-cli/dst/speechflow-node-x2x-filter.js +10 -0
  40. package/speechflow-cli/dst/speechflow-node-x2x-filter.js.map +1 -1
  41. package/speechflow-cli/dst/speechflow-node-x2x-trace.js.map +1 -1
  42. package/speechflow-cli/dst/speechflow-node-xio-device.js +3 -3
  43. package/speechflow-cli/dst/speechflow-node-xio-device.js.map +1 -1
  44. package/speechflow-cli/dst/speechflow-node-xio-file.js +1 -1
  45. package/speechflow-cli/dst/speechflow-node-xio-file.js.map +1 -1
  46. package/speechflow-cli/dst/speechflow-node-xio-mqtt.js +2 -1
  47. package/speechflow-cli/dst/speechflow-node-xio-mqtt.js.map +1 -1
  48. package/speechflow-cli/dst/speechflow-node-xio-websocket.js +2 -1
  49. package/speechflow-cli/dst/speechflow-node-xio-websocket.js.map +1 -1
  50. package/speechflow-cli/dst/speechflow-util-audio.js +1 -1
  51. package/speechflow-cli/dst/speechflow-util-audio.js.map +1 -1
  52. package/speechflow-cli/dst/speechflow-util-error.d.ts +0 -1
  53. package/speechflow-cli/dst/speechflow-util-error.js +0 -7
  54. package/speechflow-cli/dst/speechflow-util-error.js.map +1 -1
  55. package/speechflow-cli/dst/speechflow-util-misc.d.ts +1 -1
  56. package/speechflow-cli/dst/speechflow-util-misc.js +4 -4
  57. package/speechflow-cli/dst/speechflow-util-misc.js.map +1 -1
  58. package/speechflow-cli/dst/speechflow-util-queue.js +3 -3
  59. package/speechflow-cli/dst/speechflow-util-queue.js.map +1 -1
  60. package/speechflow-cli/dst/speechflow-util-stream.js +4 -2
  61. package/speechflow-cli/dst/speechflow-util-stream.js.map +1 -1
  62. package/speechflow-cli/src/speechflow-main-api.ts +6 -5
  63. package/speechflow-cli/src/speechflow-main-graph.ts +9 -8
  64. package/speechflow-cli/src/speechflow-main-status.ts +4 -8
  65. package/speechflow-cli/src/speechflow-node-a2a-compressor-wt.ts +4 -0
  66. package/speechflow-cli/src/speechflow-node-a2a-compressor.ts +4 -2
  67. package/speechflow-cli/src/speechflow-node-a2a-expander-wt.ts +1 -1
  68. package/speechflow-cli/src/speechflow-node-a2a-expander.ts +4 -2
  69. package/speechflow-cli/src/speechflow-node-a2a-gender.ts +2 -2
  70. package/speechflow-cli/src/speechflow-node-a2a-pitch.ts +1 -2
  71. package/speechflow-cli/src/speechflow-node-a2a-wav.ts +9 -2
  72. package/speechflow-cli/src/speechflow-node-a2t-amazon.ts +6 -11
  73. package/speechflow-cli/src/speechflow-node-a2t-deepgram.ts +13 -12
  74. package/speechflow-cli/src/speechflow-node-a2t-openai.ts +8 -4
  75. package/speechflow-cli/src/speechflow-node-t2a-amazon.ts +7 -11
  76. package/speechflow-cli/src/speechflow-node-t2a-elevenlabs.ts +6 -5
  77. package/speechflow-cli/src/speechflow-node-t2a-kokoro.ts +22 -6
  78. package/speechflow-cli/src/speechflow-node-x2x-filter.ts +16 -3
  79. package/speechflow-cli/src/speechflow-node-x2x-trace.ts +3 -3
  80. package/speechflow-cli/src/speechflow-node-xio-device.ts +4 -7
  81. package/speechflow-cli/src/speechflow-node-xio-file.ts +1 -1
  82. package/speechflow-cli/src/speechflow-node-xio-mqtt.ts +3 -2
  83. package/speechflow-cli/src/speechflow-node-xio-websocket.ts +2 -1
  84. package/speechflow-cli/src/speechflow-util-audio-wt.ts +4 -4
  85. package/speechflow-cli/src/speechflow-util-audio.ts +5 -5
  86. package/speechflow-cli/src/speechflow-util-error.ts +0 -7
  87. package/speechflow-cli/src/speechflow-util-misc.ts +4 -4
  88. package/speechflow-cli/src/speechflow-util-queue.ts +4 -4
  89. 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", match: /^(?:audio|text)$/ },
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: "naudion" actually implements Stream.{Readable,Writable,Duplex}, but
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.timeoutPromise(2 * 1000, "PortAudio abort timeout"),
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.timeoutPromise(2 * 1000, "PortAudio quit timeout"),
219
+ util.timeout(2 * 1000, "PortAudio quit timeout"),
223
220
  new Promise<void>((resolve) => {
224
221
  this.io!.quit(() => {
225
222
  resolve()
@@ -210,7 +210,7 @@ export default class SpeechFlowNodeXIOFile extends SpeechFlowNode {
210
210
  else resolve()
211
211
  })
212
212
  }),
213
- util.timeoutPromise(5000)
213
+ util.timeout(5000)
214
214
  ])
215
215
  }
216
216
  }
@@ -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
- this.log("info", `connection closed to MQTT ${this.params.url}`)
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: any) {
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
- this.log("error", `error of connection on URL ${this.params.connect}: ${ev.error.message}`)
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!.port.addEventListener("message", (event) => {
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!.port.start()
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, reject) => {
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>((resolve, reject) => {
17
+ export function timeout (durationMs: number, info = "timeout") {
18
+ return new Promise<never>((_resolve, reject) => {
19
19
  setTimeout(() => {
20
- reject(new Error("timeout"))
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, reject) => {
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, reject) => {
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 exists")
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.timeoutPromise(5000, "stream end timeout")
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()