@goodandready/dsh-voice 0.8.15 → 0.8.17

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.js CHANGED
@@ -123,6 +123,8 @@ window.__ModuleLoader__.load({
123
123
  'general': 'General',
124
124
  'whisperEndpoint': 'Local whisper: endpoint',
125
125
  'whisperEndpointHint': 'POST /inference of a whisper.cpp server',
126
+ 'deepgramEndpoint': 'Deepgram: base URL',
127
+ 'deepgramEndpointHint': 'Base URL for Deepgram or self-hosted deployment (default https://api.deepgram.com)',
126
128
  'whisperBin': 'Local whisper: binary',
127
129
  'whisperBinHint': 'used when autostart is on',
128
130
  'whisperModel': 'Local whisper: model',
@@ -268,6 +270,8 @@ window.__ModuleLoader__.load({
268
270
  'general': 'Общее',
269
271
  'whisperEndpoint': 'Локальный whisper: endpoint',
270
272
  'whisperEndpointHint': 'POST /inference сервера whisper.cpp',
273
+ 'deepgramEndpoint': 'Deepgram: базовый URL',
274
+ 'deepgramEndpointHint': 'Базовый адрес Deepgram или self-hosted развёртывания (по умолчанию https://api.deepgram.com)',
271
275
  'whisperBin': 'Локальный whisper: бинарь',
272
276
  'whisperBinHint': 'используется при автозапуске',
273
277
  'whisperModel': 'Локальный whisper: модель',
@@ -1885,6 +1889,7 @@ window.__ModuleLoader__.load({
1885
1889
  textField('whisperUrl', t('whisperEndpoint'), t('whisperEndpointHint')),
1886
1890
  textField('whisperBin', t('whisperBin'), t('whisperBinHint')),
1887
1891
  textField('whisperModel', t('whisperModel'), t('whisperBinHint')),
1892
+ textField('deepgramBaseUrl', t('deepgramEndpoint'), t('deepgramEndpointHint')),
1888
1893
  React.createElement('label', { className: 'dvs-field' }, t('whisperAutostart'),
1889
1894
  React.createElement('input', {
1890
1895
  type: 'checkbox', checked: !!(draft && draft.autoStart), disabled: !writable,
@@ -2061,37 +2066,18 @@ window.__ModuleLoader__.load({
2061
2066
  }
2062
2067
 
2063
2068
  function registerSettings(ctx) {
2064
- // Слот объявлен пакетом настроек ядра; вкладка перебирает пространства
2065
- // настроек, поэтому ключ регистрации обязан равняться NS, не id пакета:
2066
- // не равен карточка не появится вовсе, молча.
2067
- const tryPluginItem = () => {
2068
- try {
2069
- ctx.slots.inject('settings.plugin.item', () => ctx.slots.register(
2070
- {
2071
- name: 'settings.plugin.item',
2072
- key: NS,
2073
- // locale в записи слота — то, из-за чего компонент получает props.t.
2074
- locale: NS,
2075
- inject: () => ({ ctx: ctx }),
2076
- },
2077
- PluginCard,
2078
- ))
2079
- return true
2080
- } catch (e) { return false }
2081
- }
2082
- if (tryPluginItem()) return
2083
- // Запасной путь: в этой сборке слота нет — остаёмся боковым
2084
- // разделом, чтобы настройки не пропали.
2085
- ctx.slots.inject('settings.section', () => ctx.slots.register(
2069
+ // Карточка настроек во вкладке «Настройки Плагины → Настройки плагинов» (#18).
2070
+ // Ключ регистрации обязан равняться NS (пространству настроек), иначе
2071
+ // вкладка молча пропустит слот.
2072
+ ctx.slots.inject('settings.plugin.item', () => ctx.slots.register(
2086
2073
  {
2087
- name: 'settings.section',
2088
- id: '@goodandready/dsh-voice',
2089
- order: 30,
2074
+ name: 'settings.plugin.item',
2075
+ key: NS,
2076
+ // locale в записи слота — то, из-за чего компонент получает props.t.
2090
2077
  locale: NS,
2091
- label: () => t('title'),
2092
2078
  inject: () => ({ ctx: ctx }),
2093
2079
  },
2094
- VoiceSection,
2080
+ PluginCard,
2095
2081
  ))
2096
2082
  }
2097
2083
 
package/lib/index.js CHANGED
@@ -97,6 +97,9 @@ export const Config = z.object({
97
97
  customProviders: z.array(CustomProvider).default([])
98
98
  .description('Own recognition providers, usable in both chains next to the built-in ones.'),
99
99
  deepgramKeyEnv: z.string().default('DEEPGRAM_API_KEY'),
100
+ deepgramBaseUrl: z.string().default('https://api.deepgram.com')
101
+ .description('Deepgram-compatible host. Point this at a private/self-hosted Deepgram deployment '
102
+ + 'instead of the public api.deepgram.com endpoint.'),
100
103
  groqKeyEnv: z.string().default('GROQ_API_KEY'),
101
104
  hfTokenEnv: z.string().default('HF_TOKEN'),
102
105
  whisperUrl: z.string().default('http://127.0.0.1:8001/inference'),
@@ -438,6 +441,7 @@ export function apply(ctx, baseConfig) {
438
441
  contextGlossary: cfg.contextGlossary !== false,
439
442
  sensevoiceUrl: cfg.sensevoiceUrl,
440
443
  sensevoiceAutostart: !!cfg.sensevoiceAutostart,
444
+ deepgramBaseUrl: cfg.deepgramBaseUrl || 'https://api.deepgram.com',
441
445
  realtimeStreaming: !!cfg.realtimeStreaming,
442
446
  realtimeProvider: cfg.realtimeProvider || 'openai',
443
447
  realtimeModel: cfg.realtimeModel || 'gpt-4o-realtime-preview',
package/lib/providers.js CHANGED
@@ -116,7 +116,8 @@ export function makeProviders(deps, req) {
116
116
  const key = await resolveKey(cfg.deepgramKeyEnv)
117
117
  if (!key) return { ok: false, provider: 'deepgram', reason: `no ${cfg.deepgramKeyEnv}` }
118
118
  const model = pickModel(models, 'deepgram')
119
- const url = `https://api.deepgram.com/v1/listen?model=${encodeURIComponent(model)}`
119
+ const base = String(cfg.deepgramBaseUrl || 'https://api.deepgram.com').replace(/\/+$/, '')
120
+ const url = `${base}/v1/listen?model=${encodeURIComponent(model)}`
120
121
  + (!isAutoLang(lang) ? `&language=${encodeURIComponent(lang)}` : '') + '&smart_format=true'
121
122
  const res = await fetchImpl(url, {
122
123
  method: 'POST',
@@ -184,7 +185,13 @@ export function makeProviders(deps, req) {
184
185
  }
185
186
  const form = new FormData()
186
187
  form.append('file', new Blob([sendBytes], { type: sendMime }), fileName(sendMime))
187
- if (!isAutoLang(lang)) form.append('language', lang)
188
+ // Unlike OpenAI-compatible APIs, whisper.cpp inherits its server's default
189
+ // language when the form omits this field (normally `en`). Send `auto`
190
+ // explicitly so every request detects the spoken language.
191
+ form.append('language', isAutoLang(lang) ? 'auto' : lang)
192
+ // Also override a server started with --translate: this plugin always needs
193
+ // a transcript in the spoken language, never Whisper's English translation.
194
+ form.append('translate', 'false')
188
195
  if (vocab) form.append('prompt', vocab)
189
196
  form.append('response_format', 'json')
190
197
  const res = await fetchImpl(cfg.whisperUrl, { method: 'POST', body: form, signal })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@goodandready/dsh-voice",
3
- "version": "0.8.15",
3
+ "version": "0.8.17",
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",