speechflow 2.4.0 → 2.4.2
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/.ase/service.log +531 -0
- package/.ase/service.yaml +1 -0
- package/.ase/task/TASK-flush.md +44 -0
- package/CHANGELOG.md +33 -2
- package/README.md +10 -9
- package/etc/speechflow.yaml +1 -1
- package/etc/stx.conf +21 -21
- package/package.json +9 -5
- package/speechflow-cli/dst/speechflow-main-api.js +8 -1
- package/speechflow-cli/dst/speechflow-main-api.js.map +1 -1
- package/speechflow-cli/dst/speechflow-main-cli.js +2 -2
- package/speechflow-cli/dst/speechflow-main-cli.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-ffmpeg.js +2 -0
- package/speechflow-cli/dst/speechflow-node-a2a-ffmpeg.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-gender.js +2 -1
- package/speechflow-cli/dst/speechflow-node-a2a-gender.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-meter.js +28 -12
- package/speechflow-cli/dst/speechflow-node-a2a-meter.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-mute.js +5 -1
- package/speechflow-cli/dst/speechflow-node-a2a-mute.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2a-pitch.js +9 -15
- package/speechflow-cli/dst/speechflow-node-a2a-pitch.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-a2t-deepgram.d.ts +3 -0
- package/speechflow-cli/dst/speechflow-node-a2t-deepgram.js +149 -101
- package/speechflow-cli/dst/speechflow-node-a2t-deepgram.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-google.js +3 -0
- package/speechflow-cli/dst/speechflow-node-t2t-google.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-opus.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-proofread.js +17 -9
- package/speechflow-cli/dst/speechflow-node-t2t-proofread.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-t2t-sentence.js +20 -3
- package/speechflow-cli/dst/speechflow-node-t2t-sentence.js.map +1 -1
- package/speechflow-cli/dst/speechflow-node-xio-exec.js +6 -4
- package/speechflow-cli/dst/speechflow-node-xio-exec.js.map +1 -1
- package/speechflow-cli/dst/speechflow-util-llm.js +9 -2
- package/speechflow-cli/dst/speechflow-util-llm.js.map +1 -1
- package/speechflow-cli/etc/oxlint.jsonc +5 -0
- package/speechflow-cli/etc/stx.conf +6 -6
- package/speechflow-cli/package.json +53 -43
- package/speechflow-cli/src/speechflow-main-api.ts +8 -1
- package/speechflow-cli/src/speechflow-main-cli.ts +1 -1
- package/speechflow-cli/src/speechflow-node-a2a-ffmpeg.ts +3 -1
- package/speechflow-cli/src/speechflow-node-a2a-gender.ts +3 -2
- package/speechflow-cli/src/speechflow-node-a2a-meter.ts +30 -13
- package/speechflow-cli/src/speechflow-node-a2a-mute.ts +6 -1
- package/speechflow-cli/src/speechflow-node-a2a-pitch.ts +12 -20
- package/speechflow-cli/src/speechflow-node-a2t-deepgram.ts +162 -108
- package/speechflow-cli/src/speechflow-node-t2t-google.ts +3 -0
- package/speechflow-cli/src/speechflow-node-t2t-opus.ts +1 -1
- package/speechflow-cli/src/speechflow-node-t2t-proofread.ts +17 -9
- package/speechflow-cli/src/speechflow-node-t2t-sentence.ts +21 -3
- package/speechflow-cli/src/speechflow-node-xio-exec.ts +7 -5
- package/speechflow-cli/src/speechflow-util-llm.ts +11 -3
- package/speechflow-ui-db/dst/app-font-fa-brands-400.woff2 +0 -0
- package/speechflow-ui-db/dst/app-font-fa-regular-400.woff2 +0 -0
- package/speechflow-ui-db/dst/app-font-fa-solid-900.woff2 +0 -0
- package/speechflow-ui-db/dst/app-font-fa-v4compatibility.woff2 +0 -0
- package/speechflow-ui-db/dst/index.css +1 -1
- package/speechflow-ui-db/dst/index.js +579 -57
- package/speechflow-ui-db/etc/stx.conf +5 -4
- package/speechflow-ui-db/etc/vite-client.mts +1 -1
- package/speechflow-ui-db/package.json +27 -22
- package/speechflow-ui-st/dst/app-font-fa-brands-400.woff2 +0 -0
- package/speechflow-ui-st/dst/app-font-fa-regular-400.woff2 +0 -0
- package/speechflow-ui-st/dst/app-font-fa-solid-900.woff2 +0 -0
- package/speechflow-ui-st/dst/app-font-fa-v4compatibility.woff2 +0 -0
- package/speechflow-ui-st/dst/index.css +1 -1
- package/speechflow-ui-st/dst/index.js +593 -71
- package/speechflow-ui-st/etc/stx.conf +5 -4
- package/speechflow-ui-st/etc/vite-client.mts +6 -0
- package/speechflow-ui-st/package.json +27 -22
- package/speechflow-ui-st/src/app.vue +3 -3
- package/speechflow-cli/package.d/sherpa-onnx+1.12.25.patch +0 -12
- /package/speechflow-cli/package.d/{@typescript-eslint+typescript-estree+8.59.3.patch → @typescript-eslint+typescript-estree+8.64.0.patch} +0 -0
- /package/speechflow-ui-db/package.d/{@typescript-eslint+typescript-estree+8.59.3.patch → @typescript-eslint+typescript-estree+8.64.0.patch} +0 -0
- /package/speechflow-ui-st/package.d/{@typescript-eslint+typescript-estree+8.59.3.patch → @typescript-eslint+typescript-estree+8.64.0.patch} +0 -0
|
@@ -119,12 +119,14 @@ export default class SpeechFlowNodeT2TProofread extends SpeechFlowNode {
|
|
|
119
119
|
const cfg = this.setup[this.params.lang]
|
|
120
120
|
if (!cfg)
|
|
121
121
|
throw new Error(`unsupported language: ${this.params.lang}`)
|
|
122
|
-
this.log("info", `
|
|
123
|
-
|
|
122
|
+
this.log("info", `input: "${text}"`)
|
|
123
|
+
const output = await llm.complete({
|
|
124
124
|
system: cfg.systemPrompt,
|
|
125
125
|
messages: cfg.chat,
|
|
126
126
|
prompt: text
|
|
127
127
|
})
|
|
128
|
+
this.log("info", `output: "${output}"`)
|
|
129
|
+
return output
|
|
128
130
|
}
|
|
129
131
|
|
|
130
132
|
/* establish a transform stream and connect it to LLM */
|
|
@@ -141,14 +143,20 @@ export default class SpeechFlowNodeT2TProofread extends SpeechFlowNode {
|
|
|
141
143
|
callback()
|
|
142
144
|
}
|
|
143
145
|
else {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
146
|
+
if (chunk.kind === "final") {
|
|
147
|
+
proofread(chunk.payload).then((payload) => {
|
|
148
|
+
const chunkNew = chunk.clone()
|
|
149
|
+
chunkNew.payload = payload
|
|
150
|
+
this.push(chunkNew)
|
|
151
|
+
callback()
|
|
152
|
+
}).catch((error: unknown) => {
|
|
153
|
+
callback(util.ensureError(error))
|
|
154
|
+
})
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
this.push(chunk)
|
|
148
158
|
callback()
|
|
149
|
-
}
|
|
150
|
-
callback(util.ensureError(error))
|
|
151
|
-
})
|
|
159
|
+
}
|
|
152
160
|
}
|
|
153
161
|
},
|
|
154
162
|
final (callback) {
|
|
@@ -324,12 +324,30 @@ export default class SpeechFlowNodeT2TSentence extends SpeechFlowNode {
|
|
|
324
324
|
return
|
|
325
325
|
}
|
|
326
326
|
if (element.chunk.kind === "intermediate") {
|
|
327
|
-
|
|
328
|
-
|
|
327
|
+
/* the trailing element is a (speculative) intermediate chunk:
|
|
328
|
+
if the newly arrived chunk carries the very same intermediate
|
|
329
|
+
payload (Deepgram re-sends identical intermediates), treat it
|
|
330
|
+
as a no-op to avoid churning the queue (delete+append) and
|
|
331
|
+
re-emitting an unchanged preview */
|
|
332
|
+
if (chunk.kind === "intermediate"
|
|
333
|
+
&& (element.chunk.payload as string) === (chunk.payload as string)) {
|
|
334
|
+
self.lastChunkTime = Date.now()
|
|
335
|
+
callback()
|
|
336
|
+
return
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/* remove the trailing intermediate silently, so the
|
|
340
|
+
transient half-mutated queue (intermediate deleted, but
|
|
341
|
+
replacement not yet appended) does NOT emit a "write"
|
|
342
|
+
event and trigger a premature flush that would emit a
|
|
343
|
+
truncated preview and oscillate the dashboard preview */
|
|
344
|
+
self.queue.silently(() => {
|
|
345
|
+
self.queueRecv.walk(-1)
|
|
346
|
+
self.queueRecv.delete()
|
|
347
|
+
})
|
|
329
348
|
}
|
|
330
349
|
}
|
|
331
350
|
}
|
|
332
|
-
previewedPayload = ""
|
|
333
351
|
self.queueRecv.append({ type: "text-frame", chunk, complete: false })
|
|
334
352
|
self.lastChunkTime = Date.now()
|
|
335
353
|
callback()
|
|
@@ -93,7 +93,7 @@ export default class SpeechFlowNodeXIOExec extends SpeechFlowNode {
|
|
|
93
93
|
})
|
|
94
94
|
|
|
95
95
|
/* handle subprocess errors */
|
|
96
|
-
this.subprocess.on("error", (err) => {
|
|
96
|
+
this.subprocess.nodeChildProcess.on("error", (err: Error) => {
|
|
97
97
|
this.log("error", `subprocess error: ${err.message}`)
|
|
98
98
|
/* NOTICE: do not emit("error") on the node itself, since nothing
|
|
99
99
|
listens for it and it would become an uncaughtException tearing
|
|
@@ -104,7 +104,7 @@ export default class SpeechFlowNodeXIOExec extends SpeechFlowNode {
|
|
|
104
104
|
})
|
|
105
105
|
|
|
106
106
|
/* handle subprocess exit */
|
|
107
|
-
this.subprocess.on("exit", (code, signal) => {
|
|
107
|
+
this.subprocess.nodeChildProcess.on("exit", (code: number | null, signal: string | null) => {
|
|
108
108
|
if (code !== 0 && code !== null)
|
|
109
109
|
this.log("warning", `subprocess exited with code ${code}`)
|
|
110
110
|
else if (signal)
|
|
@@ -126,10 +126,12 @@ export default class SpeechFlowNodeXIOExec extends SpeechFlowNode {
|
|
|
126
126
|
/* dispatch according to mode */
|
|
127
127
|
if (this.params.mode === "rw") {
|
|
128
128
|
/* bidirectional mode: both stdin and stdout */
|
|
129
|
+
/* NOTICE: the object form of Stream.Duplex.from() accepts Node streams at
|
|
130
|
+
run-time, but @types/node types it for Web streams only, so we have to cast */
|
|
129
131
|
this.stream = Stream.Duplex.from({
|
|
130
132
|
readable: this.subprocess.stdout,
|
|
131
133
|
writable: this.subprocess.stdin
|
|
132
|
-
})
|
|
134
|
+
} as unknown as Parameters<typeof Stream.Duplex.from>[0])
|
|
133
135
|
const wrapper1 = util.createTransformStreamForWritableSide(this.params.type, highWaterMark)
|
|
134
136
|
const wrapper2 = util.createTransformStreamForReadableSide(
|
|
135
137
|
this.params.type, () => this.timeZero, highWaterMark,
|
|
@@ -176,8 +178,8 @@ export default class SpeechFlowNodeXIOExec extends SpeechFlowNode {
|
|
|
176
178
|
}
|
|
177
179
|
|
|
178
180
|
/* remove event listeners to prevent errors during kill sequence */
|
|
179
|
-
this.subprocess.removeAllListeners("error")
|
|
180
|
-
this.subprocess.removeAllListeners("exit")
|
|
181
|
+
this.subprocess.nodeChildProcess.removeAllListeners("error")
|
|
182
|
+
this.subprocess.nodeChildProcess.removeAllListeners("exit")
|
|
181
183
|
|
|
182
184
|
/* wait for subprocess to exit gracefully */
|
|
183
185
|
const ac2 = new AbortController()
|
|
@@ -61,7 +61,7 @@ export class LLM extends EventEmitter {
|
|
|
61
61
|
api: "",
|
|
62
62
|
model: "",
|
|
63
63
|
key: "",
|
|
64
|
-
timeout:
|
|
64
|
+
timeout: 240 * 1000,
|
|
65
65
|
temperature: 0.7,
|
|
66
66
|
maxTokens: 1024,
|
|
67
67
|
cacheDir: "",
|
|
@@ -333,10 +333,18 @@ export class LLM extends EventEmitter {
|
|
|
333
333
|
throw new Error(`failed to perform HuggingFace Transformers text generation: ${err}`, { cause: err })
|
|
334
334
|
})
|
|
335
335
|
const single = Array.isArray(result) ? result[0] : result
|
|
336
|
-
const generatedText = (single as Transformers.
|
|
337
|
-
const
|
|
336
|
+
const generatedText = (single as Transformers.TextGenerationOutput[number]).generated_text
|
|
337
|
+
const messageContent = typeof generatedText === "string" ?
|
|
338
338
|
generatedText :
|
|
339
339
|
generatedText.at(-1)?.content
|
|
340
|
+
|
|
341
|
+
/* flatten the potentially multi-modal message content into plain text */
|
|
342
|
+
const content = typeof messageContent === "string" ?
|
|
343
|
+
messageContent :
|
|
344
|
+
messageContent
|
|
345
|
+
?.filter((part) => part.type === "text")
|
|
346
|
+
.map((part) => part.text as string)
|
|
347
|
+
.join("")
|
|
340
348
|
if (!content)
|
|
341
349
|
throw new Error("HuggingFace Transformers API returned empty content")
|
|
342
350
|
return content
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|