@goodandready/dsh-voice 0.8.19 → 0.8.21
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/client-src/10-locale.js +14 -0
- package/lib/client-src/40-recording.js +3 -0
- package/lib/client-src/70-settings.js +347 -222
- package/lib/client.js +364 -222
- package/lib/index.js +8 -4
- package/lib/providers.js +16 -5
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -213,7 +213,10 @@ export function apply(ctx, baseConfig) {
|
|
|
213
213
|
try {
|
|
214
214
|
const controller = new AbortController()
|
|
215
215
|
const t = setTimeout(() => controller.abort(), 2000)
|
|
216
|
-
const
|
|
216
|
+
const rawUrl = String(live().whisperUrl || '').trim()
|
|
217
|
+
const base = rawUrl.includes('/inference') ? rawUrl.split('/inference')[0] : rawUrl.replace(/\/+$/, '')
|
|
218
|
+
if (!base) return false
|
|
219
|
+
const res = await fetch(base + '/', { signal: controller.signal })
|
|
217
220
|
clearTimeout(t)
|
|
218
221
|
return res.ok
|
|
219
222
|
} catch { return false }
|
|
@@ -266,7 +269,8 @@ export function apply(ctx, baseConfig) {
|
|
|
266
269
|
if (!cfg.sensevoiceModel) return false
|
|
267
270
|
if (await sensevoiceAlive()) return true
|
|
268
271
|
try {
|
|
269
|
-
|
|
272
|
+
let port = '6006'
|
|
273
|
+
try { port = new URL(cfg.sensevoiceUrl).port || '6006' } catch { /* invalid URL */ }
|
|
270
274
|
const spec = ctx.shell.resolve({
|
|
271
275
|
command: `${JSON.stringify(cfg.sensevoiceBin)}`
|
|
272
276
|
+ ` --sense-voice-model=${JSON.stringify(cfg.sensevoiceModel)}`
|
|
@@ -533,7 +537,7 @@ export function apply(ctx, baseConfig) {
|
|
|
533
537
|
+ 'Use for voice messages, recordings, interviews.',
|
|
534
538
|
parameters: {
|
|
535
539
|
file_path: { type: 'string', required: true, description: 'Absolute path to the audio file (wav, mp3, m4a, ogg, flac, webm).' },
|
|
536
|
-
language: { type: 'string', description: `Recognition language code. Default: ${baseConfig.message.language}.` },
|
|
540
|
+
language: { type: 'string', description: `Recognition language code. Default: ${(baseConfig && baseConfig.message && baseConfig.message.language) || 'ru'}.` },
|
|
537
541
|
},
|
|
538
542
|
output: {
|
|
539
543
|
schema: {
|
|
@@ -549,7 +553,7 @@ export function apply(ctx, baseConfig) {
|
|
|
549
553
|
},
|
|
550
554
|
},
|
|
551
555
|
isConcurrencySafe: () => false,
|
|
552
|
-
timeoutMs:
|
|
556
|
+
timeoutMs: 365000,
|
|
553
557
|
async execute(args, exec) {
|
|
554
558
|
const cfg = live()
|
|
555
559
|
const filePath = String(args.file_path || '').trim()
|
package/lib/providers.js
CHANGED
|
@@ -102,6 +102,17 @@ function isAutoLang(lang) {
|
|
|
102
102
|
return !lang || lang === 'auto' || String(lang).includes(',')
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
+
async function readErrorDetail(res, defaultLabel) {
|
|
106
|
+
let detail = `HTTP ${res.status}`
|
|
107
|
+
try {
|
|
108
|
+
const e = await res.json()
|
|
109
|
+
if (e?.error) detail = typeof e.error === 'string' ? e.error : (e.error.message || JSON.stringify(e.error))
|
|
110
|
+
else if (e?.message) detail = e.message
|
|
111
|
+
else if (e?.err_msg) detail = e.err_msg
|
|
112
|
+
} catch { /* not json */ }
|
|
113
|
+
return `${defaultLabel} ${detail}`
|
|
114
|
+
}
|
|
115
|
+
|
|
105
116
|
export function makeProviders(deps, req) {
|
|
106
117
|
const { resolveKey, fetchImpl, cfg } = deps
|
|
107
118
|
const { bytes, mime, lang, signal, models } = req
|
|
@@ -122,7 +133,7 @@ export function makeProviders(deps, req) {
|
|
|
122
133
|
body: bytes,
|
|
123
134
|
signal,
|
|
124
135
|
})
|
|
125
|
-
if (!res.ok) throw new Error(
|
|
136
|
+
if (!res.ok) throw new Error(await readErrorDetail(res, 'Deepgram'))
|
|
126
137
|
const data = await res.json()
|
|
127
138
|
const text = (data?.results?.channels?.[0]?.alternatives?.[0]?.transcript || '').trim()
|
|
128
139
|
return { ok: text.length > 0, provider: 'deepgram', text, reason: text ? '' : 'empty transcript' }
|
|
@@ -142,7 +153,7 @@ export function makeProviders(deps, req) {
|
|
|
142
153
|
body: form,
|
|
143
154
|
signal,
|
|
144
155
|
})
|
|
145
|
-
if (!res.ok) throw new Error(
|
|
156
|
+
if (!res.ok) throw new Error(await readErrorDetail(res, 'Groq'))
|
|
146
157
|
const data = await res.json()
|
|
147
158
|
const text = (data?.text || '').trim()
|
|
148
159
|
return { ok: text.length > 0, provider: 'groq', text, reason: text ? '' : 'empty transcript' }
|
|
@@ -158,7 +169,7 @@ export function makeProviders(deps, req) {
|
|
|
158
169
|
body: bytes,
|
|
159
170
|
signal,
|
|
160
171
|
})
|
|
161
|
-
if (!res.ok) throw new Error(
|
|
172
|
+
if (!res.ok) throw new Error(await readErrorDetail(res, 'HF'))
|
|
162
173
|
const data = await res.json()
|
|
163
174
|
const text = (data?.text || '').trim()
|
|
164
175
|
return { ok: text.length > 0, provider: 'hf', text, reason: text ? '' : 'empty transcript' }
|
|
@@ -286,7 +297,7 @@ export function makeProviders(deps, req) {
|
|
|
286
297
|
const res = await fetchImpl(`${base}/audio/transcriptions`, {
|
|
287
298
|
method: 'POST', headers, body: form, signal,
|
|
288
299
|
})
|
|
289
|
-
if (!res.ok) throw new Error(
|
|
300
|
+
if (!res.ok) throw new Error(await readErrorDetail(res, label))
|
|
290
301
|
const data = await res.json()
|
|
291
302
|
return (data?.text || '').trim()
|
|
292
303
|
}
|
|
@@ -319,7 +330,7 @@ export function makeProviders(deps, req) {
|
|
|
319
330
|
}),
|
|
320
331
|
signal,
|
|
321
332
|
})
|
|
322
|
-
if (!res.ok) throw new Error(
|
|
333
|
+
if (!res.ok) throw new Error(await readErrorDetail(res, label))
|
|
323
334
|
const data = await res.json()
|
|
324
335
|
return String(data?.choices?.[0]?.message?.content || '').trim()
|
|
325
336
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-voice",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.21",
|
|
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",
|