@goodandready/dsh-voice 0.8.37 → 0.8.38
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/lib/index.js +64 -15
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -217,16 +217,6 @@ export function apply(ctx, baseConfig) {
|
|
|
217
217
|
let getConfig = readEntryConfig
|
|
218
218
|
const live = () => BaseConfig(structuredClone(getConfig() ?? {})) ?? readEntryConfig()
|
|
219
219
|
|
|
220
|
-
ctx.inject(['settings'], (sctx) => {
|
|
221
|
-
try {
|
|
222
|
-
scope = sctx.settings.register(NS, Config, { base: baseConfig })
|
|
223
|
-
if (scope && typeof scope.get === 'function') {
|
|
224
|
-
getConfig = () => scope.get() ?? readEntryConfig()
|
|
225
|
-
}
|
|
226
|
-
} catch { /* modern DSH handles settings via SettingsForms */ }
|
|
227
|
-
sctx.effect(() => () => { getConfig = readEntryConfig; scope = null })
|
|
228
|
-
})
|
|
229
|
-
|
|
230
220
|
async function resolveKey(ref) {
|
|
231
221
|
try {
|
|
232
222
|
const resolved = await ctx.credentials.resolve(credentialRef(ref))
|
|
@@ -269,12 +259,27 @@ export function apply(ctx, baseConfig) {
|
|
|
269
259
|
stdoutMaxBytes: 4 * 1024 * 1024,
|
|
270
260
|
})
|
|
271
261
|
child = ctx.shell.start(spec)
|
|
272
|
-
|
|
262
|
+
if (child && typeof child.on === 'function') {
|
|
263
|
+
child.on('error', (err) => {
|
|
264
|
+
whisperError = err?.message || String(err)
|
|
265
|
+
})
|
|
266
|
+
child.on('exit', (code) => {
|
|
267
|
+
if (code !== 0 && code !== null) {
|
|
268
|
+
whisperError = `whisper server process exited with code ${code}`
|
|
269
|
+
}
|
|
270
|
+
})
|
|
271
|
+
}
|
|
272
|
+
// Wait for it to become healthy (up to 30s for cold model loading on Metal/CPU).
|
|
273
|
+
for (let i = 0; i < 60; i++) {
|
|
273
274
|
await new Promise((r) => setTimeout(r, 500))
|
|
274
275
|
if (await whisperAlive()) {
|
|
275
276
|
whisperError = null
|
|
276
277
|
return true
|
|
277
278
|
}
|
|
279
|
+
if (child && child.exitCode !== null && child.exitCode !== undefined) {
|
|
280
|
+
whisperError = `whisper server process exited prematurely with code ${child.exitCode}`
|
|
281
|
+
return false
|
|
282
|
+
}
|
|
278
283
|
}
|
|
279
284
|
whisperError = 'whisper server process started but failed health check on port 8001'
|
|
280
285
|
return false
|
|
@@ -285,8 +290,6 @@ export function apply(ctx, baseConfig) {
|
|
|
285
290
|
finally { startingWhisper = false }
|
|
286
291
|
}
|
|
287
292
|
|
|
288
|
-
startWhisper().catch(() => {})
|
|
289
|
-
|
|
290
293
|
// SenseVoice-ONNX / Sherpa-ONNX: autostart and health check.
|
|
291
294
|
let sensevoiceChild = null
|
|
292
295
|
let sensevoiceError = null
|
|
@@ -325,12 +328,27 @@ export function apply(ctx, baseConfig) {
|
|
|
325
328
|
stdoutMaxBytes: 4 * 1024 * 1024,
|
|
326
329
|
})
|
|
327
330
|
sensevoiceChild = ctx.shell.start(spec)
|
|
328
|
-
|
|
331
|
+
if (sensevoiceChild && typeof sensevoiceChild.on === 'function') {
|
|
332
|
+
sensevoiceChild.on('error', (err) => {
|
|
333
|
+
sensevoiceError = err?.message || String(err)
|
|
334
|
+
})
|
|
335
|
+
sensevoiceChild.on('exit', (code) => {
|
|
336
|
+
if (code !== 0 && code !== null) {
|
|
337
|
+
sensevoiceError = `sensevoice process exited with code ${code}`
|
|
338
|
+
}
|
|
339
|
+
})
|
|
340
|
+
}
|
|
341
|
+
// Wait for it to become healthy (up to 30s).
|
|
342
|
+
for (let i = 0; i < 60; i++) {
|
|
329
343
|
await new Promise((r) => setTimeout(r, 500))
|
|
330
344
|
if (await sensevoiceAlive()) {
|
|
331
345
|
sensevoiceError = null
|
|
332
346
|
return true
|
|
333
347
|
}
|
|
348
|
+
if (sensevoiceChild && sensevoiceChild.exitCode !== null && sensevoiceChild.exitCode !== undefined) {
|
|
349
|
+
sensevoiceError = `sensevoice process exited prematurely with code ${sensevoiceChild.exitCode}`
|
|
350
|
+
return false
|
|
351
|
+
}
|
|
334
352
|
}
|
|
335
353
|
sensevoiceError = 'sensevoice process started but failed health check'
|
|
336
354
|
return false
|
|
@@ -341,7 +359,38 @@ export function apply(ctx, baseConfig) {
|
|
|
341
359
|
finally { startingSensevoice = false }
|
|
342
360
|
}
|
|
343
361
|
|
|
344
|
-
|
|
362
|
+
function triggerAutostart() {
|
|
363
|
+
startWhisper().catch((err) => {
|
|
364
|
+
ctx.logger?.debug?.('whisper autostart failed: %s', err?.message || err)
|
|
365
|
+
})
|
|
366
|
+
startSensevoice().catch((err) => {
|
|
367
|
+
ctx.logger?.debug?.('sensevoice autostart failed: %s', err?.message || err)
|
|
368
|
+
})
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
ctx.inject(['settings'], (sctx) => {
|
|
372
|
+
try {
|
|
373
|
+
scope = sctx.settings.register(NS, Config, { base: baseConfig })
|
|
374
|
+
if (scope && typeof scope.get === 'function') {
|
|
375
|
+
getConfig = () => scope.get() ?? readEntryConfig()
|
|
376
|
+
}
|
|
377
|
+
if (scope && typeof scope.watch === 'function') {
|
|
378
|
+
scope.watch(() => {
|
|
379
|
+
triggerAutostart()
|
|
380
|
+
})
|
|
381
|
+
}
|
|
382
|
+
} catch { /* modern DSH handles settings via SettingsForms */ }
|
|
383
|
+
sctx.effect(() => () => { getConfig = readEntryConfig; scope = null })
|
|
384
|
+
triggerAutostart()
|
|
385
|
+
})
|
|
386
|
+
|
|
387
|
+
if (typeof ctx.on === 'function') {
|
|
388
|
+
ctx.on('loader/volatile-update', () => triggerAutostart())
|
|
389
|
+
ctx.on('settings/document-updated', () => triggerAutostart())
|
|
390
|
+
ctx.on('config', () => triggerAutostart())
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
triggerAutostart()
|
|
345
394
|
|
|
346
395
|
// Provider health and latency stats (Latency & Health Dashboard).
|
|
347
396
|
const statsTracker = createStatsTracker()
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-voice",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.38",
|
|
4
4
|
"description": "Voice input for DeepSeek Harness: dictation chunked by pauses and voice messages, each with its own provider fallback chain (Deepgram, Groq, HuggingFace, local whisper.cpp, plus any OpenAI-compatible API of your own).",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|