speechflow 1.6.3 → 1.6.4

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 (43) hide show
  1. package/.claude/settings.local.json +3 -0
  2. package/CHANGELOG.md +10 -0
  3. package/README.md +82 -45
  4. package/etc/speechflow.yaml +19 -14
  5. package/package.json +5 -5
  6. package/speechflow-cli/dst/speechflow-node-a2a-compressor.js +2 -1
  7. package/speechflow-cli/dst/speechflow-node-a2a-compressor.js.map +1 -1
  8. package/speechflow-cli/dst/speechflow-node-a2a-expander.js +2 -1
  9. package/speechflow-cli/dst/speechflow-node-a2a-expander.js.map +1 -1
  10. package/speechflow-cli/dst/speechflow-node-a2a-gender.js +4 -14
  11. package/speechflow-cli/dst/speechflow-node-a2a-gender.js.map +1 -1
  12. package/speechflow-cli/dst/speechflow-node-a2a-meter.js +11 -8
  13. package/speechflow-cli/dst/speechflow-node-a2a-meter.js.map +1 -1
  14. package/speechflow-cli/dst/speechflow-node-x2x-trace.d.ts +1 -0
  15. package/speechflow-cli/dst/speechflow-node-x2x-trace.js +22 -2
  16. package/speechflow-cli/dst/speechflow-node-x2x-trace.js.map +1 -1
  17. package/speechflow-cli/etc/stx.conf +6 -10
  18. package/speechflow-cli/package.json +13 -13
  19. package/speechflow-cli/src/speechflow-node-a2a-compressor.ts +2 -1
  20. package/speechflow-cli/src/speechflow-node-a2a-expander.ts +2 -1
  21. package/speechflow-cli/src/speechflow-node-a2a-meter.ts +11 -8
  22. package/speechflow-cli/src/speechflow-node-x2x-trace.ts +25 -2
  23. package/speechflow-ui-db/dst/index.js +24 -33
  24. package/speechflow-ui-db/package.json +12 -10
  25. package/speechflow-ui-db/src/app.vue +16 -2
  26. package/speechflow-ui-st/.claude/settings.local.json +3 -0
  27. package/speechflow-ui-st/dst/app-font-TypoPRO-SourceSansPro-BoldIt.eot +0 -0
  28. package/speechflow-ui-st/dst/app-font-TypoPRO-SourceSansPro-BoldIt.ttf +0 -0
  29. package/speechflow-ui-st/dst/app-font-TypoPRO-SourceSansPro-BoldIt.woff +0 -0
  30. package/speechflow-ui-st/dst/app-font-TypoPRO-SourceSansPro-RegularIt.eot +0 -0
  31. package/speechflow-ui-st/dst/app-font-TypoPRO-SourceSansPro-RegularIt.ttf +0 -0
  32. package/speechflow-ui-st/dst/app-font-TypoPRO-SourceSansPro-RegularIt.woff +0 -0
  33. package/speechflow-ui-st/dst/app-font-TypoPRO-SourceSansPro-Semibold.eot +0 -0
  34. package/speechflow-ui-st/dst/app-font-TypoPRO-SourceSansPro-Semibold.ttf +0 -0
  35. package/speechflow-ui-st/dst/app-font-TypoPRO-SourceSansPro-Semibold.woff +0 -0
  36. package/speechflow-ui-st/dst/app-font-TypoPRO-SourceSansPro-SemiboldIt.eot +0 -0
  37. package/speechflow-ui-st/dst/app-font-TypoPRO-SourceSansPro-SemiboldIt.ttf +0 -0
  38. package/speechflow-ui-st/dst/app-font-TypoPRO-SourceSansPro-SemiboldIt.woff +0 -0
  39. package/speechflow-ui-st/dst/index.css +2 -2
  40. package/speechflow-ui-st/dst/index.js +26 -28
  41. package/speechflow-ui-st/package.json +11 -10
  42. package/speechflow-ui-st/src/app.vue +142 -48
  43. package/speechflow-ui-st/src/index.ts +4 -0
@@ -16,6 +16,8 @@ const speechflow_node_1 = __importDefault(require("./speechflow-node"));
16
16
  class SpeechFlowNodeX2XTrace extends speechflow_node_1.default {
17
17
  /* declare official node name */
18
18
  static name = "x2x-trace";
19
+ /* internal state */
20
+ destroyed = false;
19
21
  /* construct node */
20
22
  constructor(id, cfg, opts, args) {
21
23
  super(id, cfg, opts, args);
@@ -23,6 +25,7 @@ class SpeechFlowNodeX2XTrace extends speechflow_node_1.default {
23
25
  this.configure({
24
26
  type: { type: "string", pos: 0, val: "audio", match: /^(?:audio|text)$/ },
25
27
  name: { type: "string", pos: 1, val: "trace" },
28
+ mode: { type: "string", pos: 2, val: "filter", match: /^(?:filter|sink)$/ },
26
29
  dashboard: { type: "string", val: "" }
27
30
  });
28
31
  /* sanity check parameters */
@@ -30,7 +33,10 @@ class SpeechFlowNodeX2XTrace extends speechflow_node_1.default {
30
33
  throw new Error("only trace nodes of type \"text\" can export to dashboard");
31
34
  /* declare node input/output format */
32
35
  this.input = this.params.type;
33
- this.output = this.params.type;
36
+ if (this.params.mode === "filter")
37
+ this.output = this.params.type;
38
+ else if (this.params.mode === "sink")
39
+ this.output = "none";
34
40
  }
35
41
  /* open node */
36
42
  async open() {
@@ -41,6 +47,8 @@ class SpeechFlowNodeX2XTrace extends speechflow_node_1.default {
41
47
  else
42
48
  this.log(level, msg);
43
49
  };
50
+ /* clear destruction flag */
51
+ this.destroyed = false;
44
52
  /* helper functions for formatting */
45
53
  const fmtTime = (t) => t.toFormat("hh:mm:ss.SSS");
46
54
  const fmtMeta = (meta) => {
@@ -64,6 +72,10 @@ class SpeechFlowNodeX2XTrace extends speechflow_node_1.default {
64
72
  highWaterMark: 1,
65
73
  transform(chunk, encoding, callback) {
66
74
  let error;
75
+ if (self.destroyed) {
76
+ callback(new Error("stream already destroyed"));
77
+ return;
78
+ }
67
79
  if (Buffer.isBuffer(chunk.payload)) {
68
80
  if (self.params.type === "audio")
69
81
  log("debug", fmtChunkBase(chunk) +
@@ -84,7 +96,9 @@ class SpeechFlowNodeX2XTrace extends speechflow_node_1.default {
84
96
  else
85
97
  error = new Error(`${self.params.type} chunk: seen String instead of Buffer chunk type`);
86
98
  }
87
- if (error !== undefined)
99
+ if (self.params.mode === "sink")
100
+ callback();
101
+ else if (error !== undefined)
88
102
  callback(error);
89
103
  else {
90
104
  this.push(chunk, encoding);
@@ -92,6 +106,10 @@ class SpeechFlowNodeX2XTrace extends speechflow_node_1.default {
92
106
  }
93
107
  },
94
108
  final(callback) {
109
+ if (self.destroyed || self.params.mode === "sink") {
110
+ callback();
111
+ return;
112
+ }
95
113
  this.push(null);
96
114
  callback();
97
115
  }
@@ -104,6 +122,8 @@ class SpeechFlowNodeX2XTrace extends speechflow_node_1.default {
104
122
  this.stream.destroy();
105
123
  this.stream = null;
106
124
  }
125
+ /* indicate destruction */
126
+ this.destroyed = true;
107
127
  }
108
128
  }
109
129
  exports.default = SpeechFlowNodeX2XTrace;
@@ -1 +1 @@
1
- {"version":3,"file":"speechflow-node-x2x-trace.js","sourceRoot":"","sources":["../src/speechflow-node-x2x-trace.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"speechflow-node-x2x-trace.js","sourceRoot":"","sources":["../src/speechflow-node-x2x-trace.ts"],"names":[],"mappings":"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"}
@@ -17,9 +17,9 @@ patch-apply
17
17
  # [speechflow-cli] multiview-style development dashboard
18
18
  dev
19
19
  stmux -w always -m beep -e "built.in.+ms" -- \
20
- [ -s 35% "stx lint-watch" : \
20
+ [ -s 50% "stx lint-watch" : \
21
21
  -s 15% "stx build-watch" : \
22
- -s 30% "stx server-delay server-watch" ]
22
+ -s 25% "stx server-watch" ]
23
23
 
24
24
  # [speechflow-cli] static code analysis (linting)
25
25
  lint:
@@ -37,7 +37,7 @@ build
37
37
  tsc --project etc/tsconfig.json
38
38
 
39
39
  # [speechflow-cli] code compilation/transpiling (building) with file watching
40
- build-watch
40
+ build-watch : build
41
41
  nodemon --exec "stx build" --watch src --ext ts
42
42
 
43
43
  # [speechflow-cli] build all-in-one packages
@@ -54,18 +54,14 @@ build-pkg
54
54
  shx mv speechflow-macos-x64 speechflow-mac-x64 && \
55
55
  shx mv speechflow-macos-arm64 speechflow-mac-a64
56
56
 
57
- # [speechflow-cli] (internal) wait for server
58
- server-delay
59
- delay 2.0
60
-
61
57
  # [speechflow-cli] run program
62
58
  server
63
- node --enable-source-maps dst/speechflow.js -v info -c studio@etc/speechflow.yaml "$@"
59
+ cd .. && npm start test
64
60
 
65
61
  # [speechflow-cli] run program with file watching
66
62
  server-watch
67
- cross-env NODE_OPTIONS="--enable-source-maps" \
68
- nodemon --exec "stx server" --watch dst --ext ts --delay 1.0
63
+ delay 4.0
64
+ cross-env nodemon --exec "stx server" --watch dst --ext ts --delay 1.0
69
65
 
70
66
  # [speechflow-cli] remove all files regularly generated
71
67
  clean
@@ -22,16 +22,16 @@
22
22
  "@gpeng/naudiodon": "2.4.1",
23
23
  "@deepgram/sdk": "4.11.2",
24
24
  "deepl-node": "1.19.0",
25
- "@elevenlabs/elevenlabs-js": "2.14.0",
25
+ "@elevenlabs/elevenlabs-js": "2.15.0",
26
26
  "stream-transform": "3.4.0",
27
27
  "get-stream": "9.0.1",
28
28
  "@dotenvx/dotenvx": "1.49.0",
29
29
  "speex-resampler": "3.0.1",
30
30
  "@sapphi-red/speex-preprocess-wasm": "0.4.0",
31
31
  "@shiguredo/rnnoise-wasm": "2025.1.5",
32
- "@aws-sdk/client-transcribe-streaming": "3.883.0",
33
- "@aws-sdk/client-translate": "3.883.0",
34
- "@aws-sdk/client-polly": "3.883.0",
32
+ "@aws-sdk/client-transcribe-streaming": "3.888.0",
33
+ "@aws-sdk/client-translate": "3.888.0",
34
+ "@aws-sdk/client-polly": "3.888.0",
35
35
  "@google-cloud/translate": "9.2.0",
36
36
  "node-web-audio-api": "1.0.4",
37
37
  "object-path": "0.11.8",
@@ -46,7 +46,7 @@
46
46
  "hapi-plugin-websocket": "2.4.11",
47
47
  "@opensumi/reconnecting-websocket": "4.4.0",
48
48
  "ollama": "0.5.17",
49
- "openai": "5.19.1",
49
+ "openai": "5.20.2",
50
50
  "@rse/ffmpeg": "1.4.2",
51
51
  "ffmpeg-stream": "1.0.1",
52
52
  "installed-packages": "1.0.13",
@@ -58,7 +58,7 @@
58
58
  "pure-uuid": "1.8.1",
59
59
  "wavefile": "11.0.0",
60
60
  "audio-inspect": "0.0.4",
61
- "@huggingface/transformers": "3.7.2",
61
+ "@huggingface/transformers": "3.7.3",
62
62
  "kokoro-js": "1.2.1",
63
63
  "@ericedouard/vad-node-realtime": "0.2.0",
64
64
  "osc-js": "2.4.1",
@@ -66,7 +66,7 @@
66
66
  "node-interval-tree": "2.1.2",
67
67
  "wrap-text": "1.0.10",
68
68
  "cli-table3": "0.6.5",
69
- "@rse/stx": "1.1.0"
69
+ "@rse/stx": "1.1.1"
70
70
  },
71
71
  "devDependencies": {
72
72
  "eslint": "9.35.0",
@@ -75,15 +75,15 @@
75
75
  "eslint-plugin-promise": "7.2.1",
76
76
  "eslint-plugin-import": "2.32.0",
77
77
  "eslint-plugin-node": "11.1.0",
78
- "typescript-eslint": "8.42.0",
79
- "@typescript-eslint/eslint-plugin": "8.42.0",
80
- "@typescript-eslint/parser": "8.42.0",
81
- "oxlint": "1.14.0",
82
- "eslint-plugin-oxlint": "1.14.0",
78
+ "typescript-eslint": "8.43.0",
79
+ "@typescript-eslint/eslint-plugin": "8.43.0",
80
+ "@typescript-eslint/parser": "8.43.0",
81
+ "oxlint": "1.15.0",
82
+ "eslint-plugin-oxlint": "1.15.0",
83
83
  "@biomejs/biome": "2.0.6",
84
84
  "eslint-config-biome": "2.1.3",
85
85
 
86
- "@types/node": "24.3.1",
86
+ "@types/node": "24.3.3",
87
87
  "@types/yargs": "17.0.33",
88
88
  "@types/js-yaml": "4.0.9",
89
89
  "@types/object-path": "0.11.4",
@@ -255,7 +255,8 @@ export default class SpeechFlowNodeA2ACompressor extends SpeechFlowNode {
255
255
  this.push(chunk)
256
256
  callback()
257
257
  }).catch((error: unknown) => {
258
- callback(util.ensureError(error, "compression failed"))
258
+ if (!self.destroyed)
259
+ callback(util.ensureError(error, "compression failed"))
259
260
  })
260
261
  }
261
262
  },
@@ -176,7 +176,8 @@ export default class SpeechFlowNodeA2AExpander extends SpeechFlowNode {
176
176
  this.push(chunk)
177
177
  callback()
178
178
  }).catch((error: unknown) => {
179
- callback(util.ensureError(error, "expansion failed"))
179
+ if (!self.destroyed)
180
+ callback(util.ensureError(error, "expansion failed"))
180
181
  })
181
182
  }
182
183
  },
@@ -33,12 +33,16 @@ export default class SpeechFlowNodeA2AMeter extends SpeechFlowNode {
33
33
  /* declare node configuration parameters */
34
34
  this.configure({
35
35
  interval: { type: "number", pos: 0, val: 250 },
36
+ mode: { type: "string", pos: 1, val: "filter", match: /^(?:filter|sink)$/ },
36
37
  dashboard: { type: "string", val: "" }
37
38
  })
38
39
 
39
40
  /* declare node input/output format */
40
41
  this.input = "audio"
41
- this.output = "audio"
42
+ if (this.params.mode === "filter")
43
+ this.output = "audio"
44
+ else if (this.params.mode === "sink")
45
+ this.output = "none"
42
46
  }
43
47
 
44
48
  /* open node */
@@ -53,7 +57,7 @@ export default class SpeechFlowNodeA2AMeter extends SpeechFlowNode {
53
57
  /* internal state */
54
58
  const sampleWindowDuration = 3 /* LUFS-S requires 3s */
55
59
  const sampleWindowSize = Math.floor(this.config.audioSampleRate * sampleWindowDuration)
56
- let sampleWindow = new Float32Array(sampleWindowSize)
60
+ const sampleWindow = new Float32Array(sampleWindowSize)
57
61
  sampleWindow.fill(0, 0, sampleWindowSize)
58
62
  let lufss = -60
59
63
  let rms = -60
@@ -66,10 +70,8 @@ export default class SpeechFlowNodeA2AMeter extends SpeechFlowNode {
66
70
  /* define chunk processing function */
67
71
  const processChunk = (chunkData: Float32Array) => {
68
72
  /* update internal audio sample sliding window */
69
- const newWindow = new Float32Array(sampleWindowSize)
70
- newWindow.set(sampleWindow.slice(chunkData.length), 0)
71
- newWindow.set(chunkData, sampleWindowSize - chunkData.length)
72
- sampleWindow = newWindow
73
+ sampleWindow.set(sampleWindow.subarray(chunkData.length), 0)
74
+ sampleWindow.set(chunkData, sampleWindowSize - chunkData.length)
73
75
 
74
76
  /* calculate the LUFS-S and RMS metric */
75
77
  const audioData = {
@@ -151,7 +153,8 @@ export default class SpeechFlowNodeA2AMeter extends SpeechFlowNode {
151
153
  self.chunkBuffer = newBuffer
152
154
 
153
155
  /* pass-through original audio chunk */
154
- this.push(chunk)
156
+ if (self.params.mode === "filter")
157
+ this.push(chunk)
155
158
  callback()
156
159
  }
157
160
  catch (error) {
@@ -160,7 +163,7 @@ export default class SpeechFlowNodeA2AMeter extends SpeechFlowNode {
160
163
  }
161
164
  },
162
165
  final (callback) {
163
- if (self.destroyed) {
166
+ if (self.destroyed || self.params.mode === "sink") {
164
167
  callback()
165
168
  return
166
169
  }
@@ -18,6 +18,9 @@ export default class SpeechFlowNodeX2XTrace extends SpeechFlowNode {
18
18
  /* declare official node name */
19
19
  public static name = "x2x-trace"
20
20
 
21
+ /* internal state */
22
+ private destroyed = false
23
+
21
24
  /* construct node */
22
25
  constructor (id: string, cfg: { [ id: string ]: any }, opts: { [ id: string ]: any }, args: any[]) {
23
26
  super(id, cfg, opts, args)
@@ -26,6 +29,7 @@ export default class SpeechFlowNodeX2XTrace extends SpeechFlowNode {
26
29
  this.configure({
27
30
  type: { type: "string", pos: 0, val: "audio", match: /^(?:audio|text)$/ },
28
31
  name: { type: "string", pos: 1, val: "trace" },
32
+ mode: { type: "string", pos: 2, val: "filter", match: /^(?:filter|sink)$/ },
29
33
  dashboard: { type: "string", val: "" }
30
34
  })
31
35
 
@@ -35,7 +39,10 @@ export default class SpeechFlowNodeX2XTrace extends SpeechFlowNode {
35
39
 
36
40
  /* declare node input/output format */
37
41
  this.input = this.params.type
38
- this.output = this.params.type
42
+ if (this.params.mode === "filter")
43
+ this.output = this.params.type
44
+ else if (this.params.mode === "sink")
45
+ this.output = "none"
39
46
  }
40
47
 
41
48
  /* open node */
@@ -48,6 +55,9 @@ export default class SpeechFlowNodeX2XTrace extends SpeechFlowNode {
48
55
  this.log(level, msg)
49
56
  }
50
57
 
58
+ /* clear destruction flag */
59
+ this.destroyed = false
60
+
51
61
  /* helper functions for formatting */
52
62
  const fmtTime = (t: Duration) => t.toFormat("hh:mm:ss.SSS")
53
63
  const fmtMeta = (meta: Map<string, any>) => {
@@ -74,6 +84,10 @@ export default class SpeechFlowNodeX2XTrace extends SpeechFlowNode {
74
84
  highWaterMark: 1,
75
85
  transform (chunk: SpeechFlowChunk, encoding, callback) {
76
86
  let error: Error | undefined
87
+ if (self.destroyed) {
88
+ callback(new Error("stream already destroyed"))
89
+ return
90
+ }
77
91
  if (Buffer.isBuffer(chunk.payload)) {
78
92
  if (self.params.type === "audio")
79
93
  log("debug", fmtChunkBase(chunk) +
@@ -94,7 +108,9 @@ export default class SpeechFlowNodeX2XTrace extends SpeechFlowNode {
94
108
  else
95
109
  error = new Error(`${self.params.type} chunk: seen String instead of Buffer chunk type`)
96
110
  }
97
- if (error !== undefined)
111
+ if (self.params.mode === "sink")
112
+ callback()
113
+ else if (error !== undefined)
98
114
  callback(error)
99
115
  else {
100
116
  this.push(chunk, encoding)
@@ -102,6 +118,10 @@ export default class SpeechFlowNodeX2XTrace extends SpeechFlowNode {
102
118
  }
103
119
  },
104
120
  final (callback) {
121
+ if (self.destroyed || self.params.mode === "sink") {
122
+ callback()
123
+ return
124
+ }
105
125
  this.push(null)
106
126
  callback()
107
127
  }
@@ -115,5 +135,8 @@ export default class SpeechFlowNodeX2XTrace extends SpeechFlowNode {
115
135
  this.stream.destroy()
116
136
  this.stream = null
117
137
  }
138
+
139
+ /* indicate destruction */
140
+ this.destroyed = true
118
141
  }
119
142
  }