@deepseek-ai/dsh-experimental-client-ui-voice-input 0.1.7-alpha.2 → 0.1.7-rc.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/README.i18n.yaml CHANGED
@@ -1,6 +1,37 @@
1
- # Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
2
- # side as of the last confirmed-consistent state. Both languages carry equal authority;
3
- # after editing either side, bring the other along and re-record with:
1
+ # Bilingual-pair consistency record for README.md (docs/i18n/README.md): per heading
2
+ # section, a hash of its English and Chinese blocks outside code blocks and generated regions.
3
+ # After editing either side, bring the other along and re-record with:
4
4
  # pnpm run verify-translation-pairing --write packages/experimental/client-ui-voice-input/README.md
5
- README.md: 4d859f4d9837c249c564abfbba0682f1493502d9
6
- README.zh.md: 84a02e4f620feb35706de5b3bc10ec291f32c423
5
+ /:
6
+ en: 03616f946faebe55
7
+ zh: 293309d5ea63305e
8
+ /deepseek-ai-dsh-experimental-client-ui-voice-input:
9
+ en: e9ad8d109a27c143
10
+ zh: cb09880ab2ce8942
11
+ /deepseek-ai-dsh-experimental-client-ui-voice-input/summary:
12
+ en: a75bfd33f96a2e7a
13
+ zh: 6866534c6a3e0662
14
+ /deepseek-ai-dsh-experimental-client-ui-voice-input/table-of-contents:
15
+ en: d152484eb41ac6b4
16
+ zh: 364c80ee00a374ff
17
+ /deepseek-ai-dsh-experimental-client-ui-voice-input/use-this-package:
18
+ en: 44f25ad14ceda123
19
+ zh: 43c4680be42af1cf
20
+ /deepseek-ai-dsh-experimental-client-ui-voice-input/understand-the-implementation:
21
+ en: 18807008bccfdb6e
22
+ zh: bb5a82c92d4aa056
23
+ /deepseek-ai-dsh-experimental-client-ui-voice-input/further-exploration:
24
+ en: 5c64426add9d79d6
25
+ zh: 4e06aa2ead8d2ccd
26
+ /deepseek-ai-dsh-experimental-client-ui-voice-input/model-experience:
27
+ en: 3c5a85f8b7129ce8
28
+ zh: d5f491ca88d9a810
29
+ /deepseek-ai-dsh-experimental-client-ui-voice-input/model-experience/kv-cache-effect:
30
+ en: b5ec79db2e1d0dbc
31
+ zh: e5aff567ae5ee6fc
32
+ /deepseek-ai-dsh-experimental-client-ui-voice-input/known-limitations-and-deferred-work:
33
+ en: e6d37618956f3ff8
34
+ zh: ebb74dd513ece5e3
35
+ /deepseek-ai-dsh-experimental-client-ui-voice-input/known-limitations-and-deferred-work/dev-note:
36
+ en: 0225ba087c5266f3
37
+ zh: 4e706f1b2b984e63
package/README.md CHANGED
@@ -9,7 +9,7 @@ English | [中文](README.zh.md)
9
9
 
10
10
  ## Summary
11
11
 
12
- This optional browser plugin adds an outline microphone icon between the model selector and Send. Clicking it opens a recording toolbar with measured audio levels, Cancel and Stop. The waveform stays shorter than the recording buttons. Stopping transcribes into the draft. Recognition preferences and model preparation live in plugin settings; language choices come from the selected provider.
12
+ This optional browser plugin adds an outline microphone icon between the model selector and Send. When recognition is ready, clicking it opens a recording toolbar with measured audio levels, Cancel and Stop. The waveform stays shorter than the recording buttons. Stopping transcribes into the draft. Recognition preferences and model preparation live in plugin settings; language choices come from the selected provider.
13
13
 
14
14
  ## Table of Contents
15
15
 
@@ -25,7 +25,9 @@ This optional browser plugin adds an outline microphone icon between the model s
25
25
  <a id="use-this-package"></a>
26
26
  ## Use this package
27
27
 
28
- Enable the [voice input bundle](../voice-input-bundle/README.md) from Plugins. After cache inspection, missing models trigger a setup prompt with Go to setup and Later actions. Go to setup opens bundle details; Download and prepare starts installation there. Intact cached models need no prompt or repeated installation. Before preparation, local providers can show their estimated disk, memory and setup-time requirements. The preparation summary starts collapsed; expand it to inspect completed, current and pending steps. Once ready, click the microphone, allow access and click Stop to transcribe. Cancel or Escape discards capture. Recognition feedback stays inside the toolbar. Provider and language preferences are saved from bundle details through the Settings service. Browser microphone access requires HTTPS or loopback and operating-system permission.
28
+ Enable the [voice input bundle](../voice-input-bundle/README.md) from Plugins. After cache inspection, missing models trigger a setup prompt with Go to setup and Later actions. Go to setup opens bundle details; Download and prepare starts installation there. Intact cached models need no prompt or repeated installation. Before recognition is ready, guidance appears only on click, with no microphone tooltip. Clicking the microphone opens the same guidance dialog; its action opens the voice bundle details without recording or downloading. Cache inspection, preparation in progress, failures and disconnected services instead offer navigation to status, progress or error details. The dialog moves focus to its navigation action and keeps Tab traversal inside it; Later or Escape restores the previous focus without changing or submitting the draft. Before preparation, local providers can show their estimated disk, memory and setup-time requirements. The preparation summary starts collapsed; expand it to inspect completed, current and pending steps. Once ready, click the microphone, allow access and click Stop to transcribe. Cancel or Escape discards capture. Recognition feedback stays inside the toolbar. Provider and language preferences are saved from bundle details through the Settings service. Browser microphone access requires HTTPS or loopback and operating-system permission.
29
+
30
+ Before downloading or retrying, **Model download source** offers Automatic and the origins advertised by the Host. SenseVoice normally offers Hugging Face and HF-Mirror; a fixed private deployment exposes only its configured origin. Manual selection uses only that source, while Automatic preserves the provider’s comparison and fallback policy. The choice is retained for retries in the current card, without changing deployment configuration or recognition preferences. Source controls are unavailable during preparation and hidden when resources are ready.
29
31
 
30
32
  -----
31
33
 
package/README.zh.md CHANGED
@@ -9,7 +9,7 @@ kind: "package-reference"
9
9
 
10
10
  ## 概述
11
11
 
12
- 此可选浏览器插件在模型选择器与发送按钮之间添加空心麦克风图标。点击后展开录音栏,显示实际音量以及取消、停止按钮。声波高度低于录音按钮高度。停止后转写到草稿。识别偏好和模型准备放在插件设置中;语言选项来自所选 Provider。
12
+ 此可选浏览器插件在模型选择器与发送按钮之间添加空心麦克风图标。识别就绪后,点击展开录音栏,显示实际音量以及取消、停止按钮。声波高度低于录音按钮高度。停止后转写到草稿。识别偏好和模型准备放在插件设置中;语言选项来自所选 Provider。
13
13
 
14
14
  ## 目录
15
15
 
@@ -25,7 +25,9 @@ kind: "package-reference"
25
25
  <a id="use-this-package"></a>
26
26
  ## 使用此包
27
27
 
28
- 在插件管理页启用[语音输入 Bundle](../voice-input-bundle/README.zh.md)。缓存检查后,缺少模型时弹出安装引导,可选择“前往安装”或“稍后”。“前往安装”打开 Bundle 详情,再点击“下载并准备”才开始安装。缓存完整时不弹引导,也无需重复安装。准备前,本地 Provider 可展示磁盘、内存与安装时间的估算。准备摘要默认折叠;展开后可查看已完成、当前和未开始的步骤。就绪后点击麦克风,允许访问,再点击停止以转写。取消或 Escape 丢弃录音。识别反馈留在工具栏内部。Provider 和语言偏好在 Bundle 详情中通过 Settings 服务保存。浏览器麦克风访问需要 HTTPS 或环回地址,以及操作系统权限。
28
+ 在插件管理页启用[语音输入 Bundle](../voice-input-bundle/README.zh.md)。缓存检查后,缺少模型时弹出安装引导,可选择“前往安装”或“稍后”。“前往安装”打开 Bundle 详情,再点击“下载并准备”才开始安装。缓存完整时不弹引导,也无需重复安装。识别未就绪时不显示麦克风悬停提示,点击后才打开同一个引导弹窗;点击引导按钮进入语音 Bundle 详情,不会录音或下载。缓存检查、正在准备、准备失败或服务断连时,弹窗改为引导查看状态、进度或错误详情。弹窗将焦点移到导航按钮,并将 Tab 切换约束在弹窗内;选择“稍后”或按 Escape 关闭时恢复此前焦点,不改变或提交草稿。准备前,本地 Provider 可展示磁盘、内存与安装时间的估算。准备摘要默认折叠;展开后可查看已完成、当前和未开始的步骤。就绪后点击麦克风,允许访问,再点击停止以转写。取消或 Escape 丢弃录音。识别反馈留在工具栏内部。Provider 和语言偏好在 Bundle 详情中通过 Settings 服务保存。浏览器麦克风访问需要 HTTPS 或环回地址,以及操作系统权限。
29
+
30
+ 下载或重试前,**模型下载源**提供自动选择及 Host 公布的源。SenseVoice 默认提供 Hugging Face 和 HF-Mirror;固定私有部署仅显示配置的源。手动选择只使用指定源,自动选择沿用提供方的比较与回退策略。当前卡片中的重试会保留选择,不修改部署配置或识别偏好。准备期间不能改源,资源就绪后隐藏源选择器。
29
31
 
30
32
  -----
31
33
 
package/lib/client.js CHANGED
@@ -614,6 +614,7 @@ window.__ModuleLoader__.load({
614
614
  };
615
615
  const integer = /^-?\d+$/;
616
616
  const number$1 = /^-?\d+(?:\.\d+)?$/;
617
+ const _undefined$2 = /^undefined$/i;
617
618
  const lowercase = /^[^A-Z]*$/;
618
619
  const uppercase = /^[^a-z]*$/;
619
620
  //#endregion
@@ -1408,6 +1409,22 @@ window.__ModuleLoader__.load({
1408
1409
  $ZodCheckNumberFormat.init(inst, def);
1409
1410
  $ZodNumber.init(inst, def);
1410
1411
  });
1412
+ const $ZodUndefined = /*@__PURE__*/ $constructor("$ZodUndefined", (inst, def) => {
1413
+ $ZodType.init(inst, def);
1414
+ inst._zod.pattern = _undefined$2;
1415
+ inst._zod.values = new Set([void 0]);
1416
+ inst._zod.parse = (payload, _ctx) => {
1417
+ const input = payload.value;
1418
+ if (typeof input === "undefined") return payload;
1419
+ payload.issues.push({
1420
+ expected: "undefined",
1421
+ code: "invalid_type",
1422
+ input,
1423
+ inst
1424
+ });
1425
+ return payload;
1426
+ };
1427
+ });
1411
1428
  const $ZodUnknown = /*@__PURE__*/ $constructor("$ZodUnknown", (inst, def) => {
1412
1429
  $ZodType.init(inst, def);
1413
1430
  inst._zod.parse = (payload) => payload;
@@ -2472,6 +2489,13 @@ window.__ModuleLoader__.load({
2472
2489
  });
2473
2490
  }
2474
2491
  // @__NO_SIDE_EFFECTS__
2492
+ function _undefined$1(Class, params) {
2493
+ return new Class({
2494
+ type: "undefined",
2495
+ ...normalizeParams(params)
2496
+ });
2497
+ }
2498
+ // @__NO_SIDE_EFFECTS__
2475
2499
  function _unknown(Class) {
2476
2500
  return new Class({ type: "unknown" });
2477
2501
  }
@@ -3024,6 +3048,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
3024
3048
  else if (typeof maximum === "number") json.maximum = maximum;
3025
3049
  if (typeof multipleOf === "number") json.multipleOf = multipleOf;
3026
3050
  };
3051
+ const undefinedProcessor = (_schema, ctx, _json, _params) => {
3052
+ if (ctx.unrepresentable === "throw") throw new Error("Undefined cannot be represented in JSON Schema");
3053
+ };
3027
3054
  const voidProcessor = (_schema, ctx, _json, _params) => {
3028
3055
  if (ctx.unrepresentable === "throw") throw new Error("Void cannot be represented in JSON Schema");
3029
3056
  };
@@ -3676,6 +3703,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
3676
3703
  function int(params) {
3677
3704
  return /* @__PURE__ */ _int(ZodNumberFormat, params);
3678
3705
  }
3706
+ const ZodUndefined = /*@__PURE__*/ $constructor("ZodUndefined", (inst, def) => {
3707
+ $ZodUndefined.init(inst, def);
3708
+ ZodType.init(inst, def);
3709
+ inst._zod.processJSONSchema = (ctx, json, params) => undefinedProcessor(inst, ctx, json, params);
3710
+ });
3711
+ function _undefined(params) {
3712
+ return /* @__PURE__ */ _undefined$1(ZodUndefined, params);
3713
+ }
3679
3714
  const ZodUnknown = /*@__PURE__*/ $constructor("ZodUnknown", (inst, def) => {
3680
3715
  $ZodUnknown.init(inst, def);
3681
3716
  ZodType.init(inst, def);
@@ -4204,7 +4239,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4204
4239
  "expectedMemoryBytes": number().readonly(),
4205
4240
  "minimumMinutes": number().readonly(),
4206
4241
  "maximumMinutes": number().readonly()
4207
- }).readonly().optional()
4242
+ }).readonly().optional(),
4243
+ "downloadSources": array(string()).readonly().optional()
4208
4244
  })).readonly(),
4209
4245
  "selection": object({
4210
4246
  "providerId": intersection(string(), unknown()).readonly(),
@@ -4375,7 +4411,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4375
4411
  "expectedMemoryBytes": number().readonly(),
4376
4412
  "minimumMinutes": number().readonly(),
4377
4413
  "maximumMinutes": number().readonly()
4378
- }).readonly().optional()
4414
+ }).readonly().optional(),
4415
+ "downloadSources": array(string()).readonly().optional()
4379
4416
  })).readonly(),
4380
4417
  "selection": object({
4381
4418
  "providerId": intersection(string(), unknown()).readonly(),
@@ -4384,6 +4421,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4384
4421
  });
4385
4422
  let _deepseek_ai_dsh_experimental_api_speech_to_text_speech_prepare_parameter_0$schema$value;
4386
4423
  const _deepseek_ai_dsh_experimental_api_speech_to_text_speech_prepare_parameter_0$schema = () => _deepseek_ai_dsh_experimental_api_speech_to_text_speech_prepare_parameter_0$schema$value ??= intersection(string(), unknown());
4424
+ let _deepseek_ai_dsh_experimental_api_speech_to_text_speech_prepare_parameter_1$schema$value;
4425
+ const _deepseek_ai_dsh_experimental_api_speech_to_text_speech_prepare_parameter_1$schema = () => _deepseek_ai_dsh_experimental_api_speech_to_text_speech_prepare_parameter_1$schema$value ??= union([_undefined(), object({ "downloadSource": string().readonly().optional() })]);
4387
4426
  let _deepseek_ai_dsh_experimental_api_speech_to_text_speech_prepare_result$schema$value;
4388
4427
  const _deepseek_ai_dsh_experimental_api_speech_to_text_speech_prepare_result$schema = () => _deepseek_ai_dsh_experimental_api_speech_to_text_speech_prepare_result$schema$value ??= _void();
4389
4428
  let _deepseek_ai_dsh_experimental_api_speech_to_text_speech_transcribe_parameter_0$schema$value;
@@ -4424,7 +4463,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4424
4463
  },
4425
4464
  sourceLocation: {
4426
4465
  "file": "packages/experimental/api-speech-to-text/src/index.ts",
4427
- "line": 79,
4466
+ "line": 80,
4428
4467
  "column": 3
4429
4468
  }
4430
4469
  },
@@ -4508,6 +4547,16 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4508
4547
  typeSymbol: "@deepseek-ai/dsh-experimental-speech-to-text/types#SpeechProviderId",
4509
4548
  create: _deepseek_ai_dsh_experimental_api_speech_to_text_speech_prepare_parameter_0$schema
4510
4549
  }
4550
+ }, {
4551
+ name: "options",
4552
+ wire: "options",
4553
+ source: "json",
4554
+ acceptsUndefined: true,
4555
+ codec: {
4556
+ mode: "strict",
4557
+ typeSymbol: "@deepseek-ai/dsh-experimental-speech-to-text/types#SpeechPreparationOptions",
4558
+ create: _deepseek_ai_dsh_experimental_api_speech_to_text_speech_prepare_parameter_1$schema
4559
+ }
4511
4560
  }],
4512
4561
  result: {
4513
4562
  mode: "strict",
@@ -4516,7 +4565,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4516
4565
  },
4517
4566
  sourceLocation: {
4518
4567
  "file": "packages/experimental/api-speech-to-text/src/index.ts",
4519
- "line": 71,
4568
+ "line": 72,
4520
4569
  "column": 3
4521
4570
  }
4522
4571
  },
@@ -4544,7 +4593,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4544
4593
  },
4545
4594
  sourceLocation: {
4546
4595
  "file": "packages/experimental/api-speech-to-text/src/index.ts",
4547
- "line": 88,
4596
+ "line": 89,
4548
4597
  "column": 9
4549
4598
  }
4550
4599
  }
@@ -4753,7 +4802,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4753
4802
  };
4754
4803
  //#endregion
4755
4804
  //#region \0dsh-css:/home/runner/work/deepseek-harness/deepseek-harness/packages/experimental/client-ui-voice-input/src/client/VoiceInput.module.css.mjs
4756
- const css = ".ddpbLW_trigger{flex:none;width:28px;padding:0}.ddpbLW_triggerAnchor{flex:none;display:inline-flex}.ddpbLW_captureRow{align-items:center;gap:12px;width:100%;min-width:0;min-height:34px;display:flex}.ddpbLW_roundButton{corner-shape:round;background:var(--dsw-specific-selector);border-radius:50%;flex:none;width:32px;height:32px;padding:0}.ddpbLW_roundButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.ddpbLW_waveform{width:0;min-width:24px;height:24px;color:var(--dsw-alias-label-secondary);flex:1;display:block}.ddpbLW_activityMessage{min-width:0;color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;flex:1;align-items:center;gap:8px;font-size:12px;display:flex;overflow:hidden}.ddpbLW_inlineAction{flex:none}.ddpbLW_preparation{border:.5px solid var(--dsw-alias-border-l1);border-radius:10px;flex-direction:column;gap:10px;margin:12px 0;padding:14px;font-size:13px;display:flex}.ddpbLW_preparation p{margin:0}.ddpbLW_preparationActions{gap:8px;display:flex}.ddpbLW_preparationActions:empty{display:none}.ddpbLW_preparationError{color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;font-size:12px}.ddpbLW_downloadFailure{overflow-wrap:anywhere;gap:6px;display:grid}.ddpbLW_summaryRow{flex-wrap:wrap;gap:4px;height:auto;min-height:28px}.ddpbLW_summaryTitle{flex:1;min-width:0}.ddpbLW_metric{color:var(--dsw-alias-label-tertiary);font-size:12px}.ddpbLW_progress{width:100%;height:6px;accent-color:var(--dsw-alias-state-business-primary)}.ddpbLW_steps{flex-direction:column;gap:14px;margin:0;padding:16px 0 2px;list-style:none;display:flex}.ddpbLW_steps li{align-items:flex-start;gap:10px;line-height:18px;display:flex}.ddpbLW_steps li>:first-child{margin-top:1px}.ddpbLW_steps li[data-step-state=pending]{color:var(--dsw-alias-label-tertiary)}.ddpbLW_stepBody{flex:1;min-width:0}.ddpbLW_stepProgress{flex-direction:column;gap:6px;margin-top:6px;display:flex}.ddpbLW_stepProgress small{color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere;font-size:11px}.ddpbLW_preferences{gap:12px;margin:18px 0;font-size:13px;display:grid}.ddpbLW_preferences label{grid-template-columns:100px minmax(120px,280px);align-items:center;gap:12px;display:grid}.ddpbLW_preferences select{border:.5px solid var(--dsw-alias-border-l1);color:inherit;font:inherit;background:0 0;border-radius:6px;padding:6px 10px}.ddpbLW_preferences p{margin:0}.ddpbLW_settingsCard{border:.5px solid var(--dsw-alias-border-l1);border-radius:10px;padding:16px;list-style:none}.ddpbLW_settingsCard>p{color:var(--dsw-alias-label-secondary);margin:8px 0 0;font-size:13px}.ddpbLW_setupEstimate{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary);border-radius:8px;gap:10px;padding:12px;line-height:1.6;display:grid}.ddpbLW_setupEstimate dl{gap:6px;margin:0;display:grid}.ddpbLW_setupEstimate dl>div{grid-template-columns:72px minmax(0,1fr);gap:10px;display:grid}.ddpbLW_setupEstimate dt{color:var(--dsw-alias-label-tertiary)}.ddpbLW_setupEstimate dd{margin:0}.ddpbLW_setupEstimate small{color:var(--dsw-alias-label-tertiary);font-size:12px}";
4805
+ const css = ".ddpbLW_trigger{flex:none;width:28px;padding:0}.ddpbLW_triggerAnchor{flex:none;display:inline-flex}.ddpbLW_captureRow{align-items:center;gap:12px;width:100%;min-width:0;min-height:34px;display:flex}.ddpbLW_roundButton{corner-shape:round;background:var(--dsw-specific-selector);border-radius:50%;flex:none;width:32px;height:32px;padding:0}.ddpbLW_roundButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-solid)}.ddpbLW_waveform{width:0;min-width:24px;height:24px;color:var(--dsw-alias-label-secondary);flex:1;display:block}.ddpbLW_activityMessage{min-width:0;color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;flex:1;align-items:center;gap:8px;font-size:12px;display:flex;overflow:hidden}.ddpbLW_inlineAction{flex:none}.ddpbLW_preparation{border:.5px solid var(--dsw-alias-border-l1);border-radius:10px;flex-direction:column;gap:10px;margin:12px 0;padding:14px;font-size:13px;display:flex}.ddpbLW_preparation p{margin:0}.ddpbLW_preparationActions{gap:8px;display:flex}.ddpbLW_preparationActions:empty{display:none}.ddpbLW_preparationError{color:var(--dsw-alias-state-error-primary);overflow-wrap:anywhere;font-size:12px}.ddpbLW_downloadFailure{overflow-wrap:anywhere;gap:6px;display:grid}.ddpbLW_summaryRow{flex-wrap:wrap;gap:4px;height:auto;min-height:28px}.ddpbLW_summaryTitle{flex:1;min-width:0}.ddpbLW_metric{color:var(--dsw-alias-label-tertiary);font-size:12px}.ddpbLW_progress{width:100%;height:6px;accent-color:var(--dsw-alias-state-business-primary)}.ddpbLW_steps{flex-direction:column;gap:14px;margin:0;padding:16px 0 2px;list-style:none;display:flex}.ddpbLW_steps li{align-items:flex-start;gap:10px;line-height:18px;display:flex}.ddpbLW_steps li>:first-child{margin-top:1px}.ddpbLW_steps li[data-step-state=pending]{color:var(--dsw-alias-label-tertiary)}.ddpbLW_stepBody{flex:1;min-width:0}.ddpbLW_stepProgress{flex-direction:column;gap:6px;margin-top:6px;display:flex}.ddpbLW_stepProgress small{color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere;font-size:11px}.ddpbLW_preferences{gap:12px;margin:18px 0;font-size:13px;display:grid}.ddpbLW_preferences label,.ddpbLW_sourceChoice label{grid-template-columns:100px minmax(120px,280px);align-items:center;gap:12px;display:grid}.ddpbLW_preferences select,.ddpbLW_sourceChoice select{border:.5px solid var(--dsw-alias-border-l1);color:inherit;font:inherit;background:0 0;border-radius:6px;padding:6px 10px}.ddpbLW_sourceChoice{gap:6px;display:grid}.ddpbLW_preferences p{margin:0}.ddpbLW_settingsCard{border:.5px solid var(--dsw-alias-border-l1);border-radius:10px;padding:16px;list-style:none}.ddpbLW_settingsCard>p{color:var(--dsw-alias-label-secondary);margin:8px 0 0;font-size:13px}.ddpbLW_setupEstimate{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary);border-radius:8px;gap:10px;padding:12px;line-height:1.6;display:grid}.ddpbLW_setupEstimate dl{gap:6px;margin:0;display:grid}.ddpbLW_setupEstimate dl>div{grid-template-columns:72px minmax(0,1fr);gap:10px;display:grid}.ddpbLW_setupEstimate dt{color:var(--dsw-alias-label-tertiary)}.ddpbLW_setupEstimate dd{margin:0}.ddpbLW_setupEstimate small{color:var(--dsw-alias-label-tertiary);font-size:12px}";
4757
4806
  const tagId = "@deepseek-ai/dsh-experimental-client-ui-voice-input/VoiceInput.module.css";
4758
4807
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
4759
4808
  const tag = document.createElement("style");
@@ -4776,6 +4825,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4776
4825
  "roundButton": "ddpbLW_roundButton",
4777
4826
  "settingsCard": "ddpbLW_settingsCard",
4778
4827
  "setupEstimate": "ddpbLW_setupEstimate",
4828
+ "sourceChoice": "ddpbLW_sourceChoice",
4779
4829
  "stepBody": "ddpbLW_stepBody",
4780
4830
  "stepProgress": "ddpbLW_stepProgress",
4781
4831
  "steps": "ddpbLW_steps",
@@ -4837,6 +4887,33 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4837
4887
  });
4838
4888
  }
4839
4889
  //#endregion
4890
+ //#region lib/types/client/VoiceSetupDialog.js
4891
+ /** Shared modal for voice activation and unavailable recognition. */
4892
+ /**
4893
+ * Guide activation or microphone clicks to the existing plugin details.
4894
+ * @param props - visibility, installation need and navigation callbacks.
4895
+ * @returns a dismissible prompt that never starts preparation or recording.
4896
+ */
4897
+ function VoiceSetupDialog({ open, needsInstallation, onDismiss, onOpenDetails, t }) {
4898
+ return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
4899
+ open,
4900
+ title: t(needsInstallation ? "setupPrompt.title" : "setupPrompt.unavailableTitle"),
4901
+ closeLabel: t("cancel"),
4902
+ onClose: onDismiss,
4903
+ footer: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
4904
+ variant: "ghost",
4905
+ onClick: onDismiss,
4906
+ children: t("setupPrompt.later")
4907
+ }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
4908
+ variant: "primary",
4909
+ "data-modal-autofocus": true,
4910
+ onClick: onOpenDetails,
4911
+ children: t(needsInstallation ? "setupPrompt.open" : "setupPrompt.details")
4912
+ })] }),
4913
+ children: (0, react_jsx_runtime.jsx)("p", { children: t(needsInstallation ? "setupPrompt.body" : "setupPrompt.unavailableBody") })
4914
+ });
4915
+ }
4916
+ //#endregion
4840
4917
  //#region lib/types/client/VoiceInput.js
4841
4918
  /** Click-to-record toolbar activity; transcripts remain in the original Session draft. */
4842
4919
  async function disposeRecording(capture) {
@@ -4845,11 +4922,15 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4845
4922
  } catch (_error) {}
4846
4923
  }
4847
4924
  /** Render a compact microphone or an expanded capture, transcription, or retry row. */
4848
- function VoiceInput({ sessionId, inputActions, locked, onActiveChange, createRecording, transcribe, useSpeechReadiness, t }) {
4925
+ function VoiceInput({ sessionId, inputActions, locked, onActiveChange, createRecording, transcribe, openSettings, useSpeechReadiness, t }) {
4849
4926
  const readiness = useSpeechReadiness((value) => value), catalog = readiness.catalog;
4850
4927
  const provider = catalog?.providers.find((item) => item.id === catalog.selection.providerId);
4851
4928
  const usable = readiness.connected && (provider?.preparation.phase === "ready" || provider?.preparation.phase === "standby" || provider?.preparation.phase === "waking");
4852
4929
  const [phase, setPhase] = (0, react.useState)("idle"), [message, setMessage] = (0, react.useState)(""), [pending, setPending] = (0, react.useState)("");
4930
+ const [setupOpen, setSetupOpen] = (0, react.useState)(false);
4931
+ (0, react.useEffect)(() => {
4932
+ if (usable) setSetupOpen(false);
4933
+ }, [usable]);
4853
4934
  const current = (0, react.useRef)(), generation = (0, react.useRef)(0);
4854
4935
  const expanded = phase !== "idle";
4855
4936
  (0, react.useLayoutEffect)(() => {
@@ -4870,11 +4951,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4870
4951
  setPending("");
4871
4952
  setMessage("");
4872
4953
  setPhase("idle");
4954
+ setSetupOpen(false);
4873
4955
  };
4874
4956
  (0, react.useEffect)(() => {
4875
4957
  setPending("");
4876
4958
  setMessage("");
4877
4959
  setPhase("idle");
4960
+ setSetupOpen(false);
4878
4961
  const blur = () => {
4879
4962
  if (current.current?.phase === "recording") cancel();
4880
4963
  };
@@ -4987,8 +5070,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4987
5070
  }
4988
5071
  }
4989
5072
  };
4990
- if (!expanded) return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
4991
- label: t(usable ? "dictate" : "prepareRequired"),
5073
+ if (!expanded) return (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
5074
+ label: t("dictate"),
5075
+ disabled: !usable,
4992
5076
  side: "top",
4993
5077
  portal: true,
4994
5078
  children: (0, react_jsx_runtime.jsx)("span", {
@@ -4996,18 +5080,31 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
4996
5080
  children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
4997
5081
  className: VoiceInput_module_css_default.trigger,
4998
5082
  size: "sm",
4999
- disabled: !usable || locked,
5000
- "aria-label": t("start"),
5083
+ disabled: locked,
5084
+ "aria-label": t(usable ? "start" : "setupPrompt.trigger"),
5085
+ "aria-haspopup": usable ? void 0 : "dialog",
5001
5086
  onMouseDown: (event) => {
5002
5087
  event.preventDefault();
5003
5088
  },
5004
5089
  onClick: () => {
5005
- start();
5090
+ if (usable) start();
5091
+ else setSetupOpen(true);
5006
5092
  },
5007
5093
  children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconMicrophoneOutlineRegular, { size: 18 })
5008
5094
  })
5009
5095
  })
5010
- });
5096
+ }), (0, react_jsx_runtime.jsx)(VoiceSetupDialog, {
5097
+ open: setupOpen && !usable,
5098
+ needsInstallation: readiness.connected && provider?.location === "host-local" && provider.preparation.phase === "unprepared",
5099
+ onDismiss: () => {
5100
+ setSetupOpen(false);
5101
+ },
5102
+ onOpenDetails: () => {
5103
+ setSetupOpen(false);
5104
+ openSettings();
5105
+ },
5106
+ t
5107
+ })] });
5011
5108
  return (0, react_jsx_runtime.jsxs)("div", {
5012
5109
  className: VoiceInput_module_css_default.captureRow,
5013
5110
  "data-voice-activity": phase,
@@ -5075,6 +5172,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5075
5172
  "setupPrompt.body": "语音输入插件已开启。首次使用需要在本机下载并准备识别模型,请前往插件详情页查看空间、内存和时间说明,再开始安装。",
5076
5173
  "setupPrompt.later": "稍后",
5077
5174
  "setupPrompt.open": "前往安装",
5175
+ "setupPrompt.trigger": "打开语音输入引导",
5176
+ "setupPrompt.details": "前往语音插件设置",
5177
+ "setupPrompt.unavailableTitle": "语音识别尚未就绪",
5178
+ "setupPrompt.unavailableBody": "请前往语音插件详情页查看识别服务状态、准备进度或错误信息",
5078
5179
  "setup.local": "将在运行 DSH 的机器上下载本地模型,无需安装 Python 或编译工具。",
5079
5180
  "setup.disk": "硬盘空间",
5080
5181
  "setup.diskValue": "建议预留约 {gb} GB,包含模型、运行时和下载缓存",
@@ -5122,6 +5223,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5122
5223
  "downloadAdvice.storage": "请检查运行 DSH 的机器的剩余磁盘空间,以及模型目录的写入权限后重试。",
5123
5224
  "downloadAdvice.unknown": "请检查运行 DSH 的机器的网络、磁盘空间和模型目录权限后重试。",
5124
5225
  downloadSource: "下载来源:{source}",
5226
+ sourceChoice: "模型下载源",
5227
+ sourceAuto: "自动选择(推荐)",
5228
+ sourceHuggingFace: "Hugging Face",
5229
+ sourceMirror: "HF-Mirror(国内镜像)",
5230
+ sourceAutoHelp: "优先使用响应较快的源,下载失败时自动尝试其他源。",
5231
+ sourceManualHelp: "仅从所选源下载;已下载并通过校验的文件会复用。",
5125
5232
  downloadCode: "错误码:{code}",
5126
5233
  "reconnecting": "正在连接语音服务…",
5127
5234
  "preparation.unprepared": "首次使用需要下载本地识别模型。",
@@ -5133,7 +5240,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5133
5240
  "preparation.cancelled": "准备已取消,已完成的下载会保留。",
5134
5241
  "preparation.cancelling": "正在取消准备…",
5135
5242
  cloudReady: "云端语音识别已就绪。",
5136
- prepareRequired: "请先在语音插件设置中准备识别服务",
5137
5243
  discard: "丢弃识别文字",
5138
5244
  transcribingShort: "识别中…",
5139
5245
  wakingShort: "唤醒中…",
@@ -5153,7 +5259,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5153
5259
  requesting: "请允许使用麦克风…",
5154
5260
  recording: "正在录音…",
5155
5261
  interrupted: "录音中断,请重试。",
5156
- local: "音频在运行 DSH 的机器上识别。首次准备默认从 Hugging Face 下载模型,该机器需要能访问 Hugging Face 及其模型下载服务。如需代理,请在该机器上配置。",
5262
+ local: "音频在运行 DSH 的机器上识别。需要下载模型时,请确保该机器能访问所选下载源及其文件服务。如需代理,请在该机器上配置。",
5157
5263
  cloud: "音频将发送至所选云端服务。",
5158
5264
  empty: "未识别到语音",
5159
5265
  cancelled: "已取消语音输入。",
@@ -5170,6 +5276,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5170
5276
  "setupPrompt.body": "Voice input is enabled. First use requires downloading and preparing local recognition models. Open the plugin details to review disk space, memory and time estimates before starting setup.",
5171
5277
  "setupPrompt.later": "Later",
5172
5278
  "setupPrompt.open": "Go to setup",
5279
+ "setupPrompt.trigger": "Open voice input setup",
5280
+ "setupPrompt.details": "Open voice plugin settings",
5281
+ "setupPrompt.unavailableTitle": "Speech recognition is not ready",
5282
+ "setupPrompt.unavailableBody": "Open the voice plugin details to check recognition status, preparation progress, or errors.",
5173
5283
  "setup.local": "Local models will be downloaded to the machine running DSH. No Python or compiler is required.",
5174
5284
  "setup.disk": "Disk space",
5175
5285
  "setup.diskValue": "Allow about {gb} GB for models, runtime, and download caches",
@@ -5217,6 +5327,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5217
5327
  "downloadAdvice.storage": "Check available disk space and write permission for the model directory on the machine running DSH, then retry.",
5218
5328
  "downloadAdvice.unknown": "Check the network, disk space and model directory permissions on the machine running DSH, then retry.",
5219
5329
  downloadSource: "Download source: {source}",
5330
+ sourceChoice: "Model download source",
5331
+ sourceAuto: "Automatic (recommended)",
5332
+ sourceHuggingFace: "Hugging Face",
5333
+ sourceMirror: "HF-Mirror (China mirror)",
5334
+ sourceAutoHelp: "Prefer the first responding source and try another if a download fails.",
5335
+ sourceManualHelp: "Download only from the selected source. Verified downloaded files are reused.",
5220
5336
  downloadCode: "Error code: {code}",
5221
5337
  "reconnecting": "Connecting to speech recognition…",
5222
5338
  "preparation.unprepared": "First use downloads the local recognition models.",
@@ -5228,7 +5344,6 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5228
5344
  "preparation.cancelled": "Preparation cancelled. Completed downloads are retained.",
5229
5345
  "preparation.cancelling": "Cancelling preparation…",
5230
5346
  cloudReady: "Cloud speech recognition is ready.",
5231
- prepareRequired: "Prepare recognition in the voice plugin settings first",
5232
5347
  discard: "Discard transcript",
5233
5348
  transcribingShort: "Transcribing…",
5234
5349
  wakingShort: "Waking…",
@@ -5248,7 +5363,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5248
5363
  requesting: "Allow microphone access to continue…",
5249
5364
  recording: "Recording…",
5250
5365
  interrupted: "Recording was interrupted. Please try again.",
5251
- local: "Audio is recognized on the machine running DSH. First setup downloads models from Hugging Face by default, so that machine must be able to access Hugging Face and its model download services. If a proxy is needed, configure it on that machine.",
5366
+ local: "Audio is recognized on the machine running DSH. If models need downloading, that machine must be able to reach the selected source and its file services. Configure a proxy on that machine if needed.",
5252
5367
  cloud: "Audio will be sent to the selected cloud service.",
5253
5368
  empty: "No speech recognized",
5254
5369
  cancelled: "Voice input cancelled.",
@@ -5367,6 +5482,15 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5367
5482
  function PreparationCard({ provider, connected, prepare, cancelPreparation, t }) {
5368
5483
  const state = provider.preparation;
5369
5484
  const [expanded, setExpanded] = (0, react.useState)(false), [now, setNow] = (0, react.useState)(Date.now), [error, setError] = (0, react.useState)("");
5485
+ const [source, setSource] = (0, react.useState)(""), [submitting, setSubmitting] = (0, react.useState)(false);
5486
+ const sources = provider.downloadSources ?? [];
5487
+ const [firstSource = ""] = sources;
5488
+ const selectedSource = sources.includes(source) ? source : sources.length === 1 ? firstSource : "";
5489
+ const canPrepare = [
5490
+ "unprepared",
5491
+ "cancelled",
5492
+ "failed"
5493
+ ].includes(state.phase);
5370
5494
  const current = state.steps?.find((step) => step.status === "running" || step.status === "failed" || step.status === "cancelled");
5371
5495
  const preparing = preparationTone(state) === "ongoing";
5372
5496
  const startedAt = current?.startedAt ?? ("startedAt" in state ? state.startedAt : void 0);
@@ -5381,10 +5505,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5381
5505
  }, [preparing, startedAt]);
5382
5506
  const run = async (action) => {
5383
5507
  setError("");
5508
+ setSubmitting(true);
5384
5509
  try {
5385
5510
  await action();
5386
5511
  } catch (failure) {
5387
5512
  setError(failure instanceof Error ? failure.message : String(failure));
5513
+ } finally {
5514
+ setSubmitting(false);
5388
5515
  }
5389
5516
  };
5390
5517
  const metric = state.phase === "downloading" ? byteText(state, t) : preparing && startedAt !== void 0 ? t("elapsed", { seconds: String(Math.max(0, Math.floor((now - startedAt) / 1e3))) }) : "";
@@ -5469,24 +5596,41 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5469
5596
  state,
5470
5597
  t
5471
5598
  }),
5599
+ canPrepare && sources.length > 0 && (0, react_jsx_runtime.jsxs)("div", {
5600
+ className: VoiceInput_module_css_default.sourceChoice,
5601
+ children: [(0, react_jsx_runtime.jsxs)("label", { children: [t("sourceChoice"), (0, react_jsx_runtime.jsxs)("select", {
5602
+ "aria-label": t("sourceChoice"),
5603
+ value: selectedSource,
5604
+ disabled: !connected || submitting || sources.length === 1,
5605
+ onChange: (event) => {
5606
+ setSource(event.target.value);
5607
+ },
5608
+ children: [sources.length > 1 && (0, react_jsx_runtime.jsx)("option", {
5609
+ value: "",
5610
+ children: t("sourceAuto")
5611
+ }), sources.map((origin) => (0, react_jsx_runtime.jsx)("option", {
5612
+ value: origin,
5613
+ children: origin === "https://huggingface.co" ? t("sourceHuggingFace") : origin === "https://hf-mirror.com" ? t("sourceMirror") : origin
5614
+ }, origin))]
5615
+ })] }), (0, react_jsx_runtime.jsx)("small", {
5616
+ className: VoiceInput_module_css_default.metric,
5617
+ children: t(selectedSource === "" ? "sourceAutoHelp" : "sourceManualHelp")
5618
+ })]
5619
+ }),
5472
5620
  (0, react_jsx_runtime.jsxs)("div", {
5473
5621
  className: VoiceInput_module_css_default.preparationActions,
5474
- children: [[
5475
- "unprepared",
5476
- "cancelled",
5477
- "failed"
5478
- ].includes(state.phase) && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
5622
+ children: [canPrepare && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
5479
5623
  variant: "outline",
5480
5624
  size: "sm",
5481
- disabled: !connected,
5625
+ disabled: !connected || submitting,
5482
5626
  onClick: () => {
5483
- run(() => prepare(provider.id));
5627
+ run(() => selectedSource === "" ? prepare(provider.id) : prepare(provider.id, { downloadSource: selectedSource }));
5484
5628
  },
5485
5629
  children: t(state.phase === "unprepared" ? "prepare" : "retryPrepare")
5486
5630
  }), preparing && state.phase !== "waking" && (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
5487
5631
  variant: "ghost",
5488
5632
  size: "sm",
5489
- disabled: !connected || state.phase === "cancelling",
5633
+ disabled: !connected || submitting || state.phase === "cancelling",
5490
5634
  onClick: () => {
5491
5635
  run(() => cancelPreparation(provider.id));
5492
5636
  },
@@ -5575,7 +5719,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5575
5719
  }
5576
5720
  //#endregion
5577
5721
  //#region lib/types/client/VoiceSetupPrompt.js
5578
- /** First-use guidance after explicit enablement, once the Host finishes inspecting its cache. */
5722
+ /** Activation guidance after the Host inspects local recognition resources. */
5579
5723
  /**
5580
5724
  * Offer navigation to installation without starting a download.
5581
5725
  * @param props - activation navigation and the shared Host readiness observer.
@@ -5593,21 +5737,12 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5593
5737
  needsSetup,
5594
5738
  onDismiss
5595
5739
  ]);
5596
- return (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
5740
+ return (0, react_jsx_runtime.jsx)(VoiceSetupDialog, {
5597
5741
  open: needsSetup,
5598
- title: t("setupPrompt.title"),
5599
- closeLabel: t("cancel"),
5600
- onClose: onDismiss,
5601
- footer: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
5602
- variant: "ghost",
5603
- onClick: onDismiss,
5604
- children: t("setupPrompt.later")
5605
- }), (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
5606
- variant: "primary",
5607
- onClick: onOpenDetails,
5608
- children: t("setupPrompt.open")
5609
- })] }),
5610
- children: (0, react_jsx_runtime.jsx)("p", { children: t("setupPrompt.body") })
5742
+ needsInstallation: true,
5743
+ onDismiss,
5744
+ onOpenDetails,
5745
+ t
5611
5746
  });
5612
5747
  }
5613
5748
  //#endregion
@@ -5615,7 +5750,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5615
5750
  const inject = [
5616
5751
  "remote",
5617
5752
  "slots",
5618
- "locale"
5753
+ "locale",
5754
+ "pluginNavigation"
5619
5755
  ];
5620
5756
  function registerUi(ctx) {
5621
5757
  ctx.effect(() => ctx.locale.register(NS, {
@@ -5629,6 +5765,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5629
5765
  await Promise.all([...recordings].map((recording) => recording.dispose()));
5630
5766
  });
5631
5767
  const actions = {
5768
+ openSettings: () => {
5769
+ ctx.pluginNavigation.openBundle("@deepseek-ai/dsh-experimental-voice-input-bundle");
5770
+ },
5632
5771
  hooks: { speechReadiness: readiness.state },
5633
5772
  createRecording: () => {
5634
5773
  const recording = new Recording(() => {
@@ -5642,8 +5781,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5642
5781
  const result = await ctx.remote.speech.configure(patch);
5643
5782
  if (!result.ok) throw result.error;
5644
5783
  },
5645
- prepare: async (providerId) => {
5646
- const result = await ctx.remote.speech.prepare(providerId);
5784
+ prepare: async (providerId, options) => {
5785
+ const result = await ctx.remote.speech.prepare(providerId, options);
5647
5786
  if (!result.ok) throw result.error;
5648
5787
  },
5649
5788
  cancelPreparation: async (providerId) => {
@@ -5680,7 +5819,8 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
5680
5819
  const ui = ctx.inject([
5681
5820
  "remote.speech",
5682
5821
  "slots",
5683
- "locale"
5822
+ "locale",
5823
+ "pluginNavigation"
5684
5824
  ], registerUi);
5685
5825
  try {
5686
5826
  await ui;
@@ -10,5 +10,5 @@ export type PreparationCardProps = Pick<InjectFace<VoiceInputInjected>, 'prepare
10
10
  /** Render a collapsed current-step summary or all Host-owned preparation steps. */
11
11
  export declare function PreparationCard({ provider, connected, prepare, cancelPreparation, t }: PreparationCardProps): import("react").JSX.Element;
12
12
  /** Recognition preferences and preparation cards shared by plugin details and Settings. */
13
- export declare function VoicePreparation({ useSpeechReadiness, ...props }: InjectFace<VoiceInputInjected> & PropsLocale<typeof NS>): import("react").JSX.Element;
13
+ export declare function VoicePreparation({ useSpeechReadiness, ...props }: Pick<InjectFace<VoiceInputInjected>, 'useSpeechReadiness' | 'configure' | 'prepare' | 'cancelPreparation'> & PropsLocale<typeof NS>): import("react").JSX.Element;
14
14
  //# sourceMappingURL=PreparationCard.d.ts.map
@@ -1,16 +1,18 @@
1
1
  import type { HostObservable, InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
2
2
  import type { TranscriptionRequest } from '@deepseek-ai/dsh-experimental-api-speech-to-text/types';
3
- import type { SpeechProviderId, SpeechSelectionPatch, Transcript } from '@deepseek-ai/dsh-experimental-speech-to-text/types';
3
+ import type { SpeechPreparationOptions, SpeechProviderId, SpeechSelectionPatch, Transcript } from '@deepseek-ai/dsh-experimental-speech-to-text/types';
4
4
  import type { RemoteResult } from '@deepseek-ai/dsh-typert-protocol';
5
5
  import { type Recording } from './audio.ts';
6
6
  import type { SpeechReadiness } from './readiness.ts';
7
7
  import { NS } from './locales.ts';
8
8
  /** Host calls injected without exposing a Cordis Context to React. */
9
9
  export interface VoiceInputActions {
10
+ /** Open the voice bundle details without starting preparation. */
11
+ openSettings: () => void;
10
12
  /** @returns one microphone operation owned by the plugin lifecycle. */
11
13
  createRecording: () => Recording;
12
14
  transcribe: (request: TranscriptionRequest, signal: AbortSignal) => Promise<RemoteResult<Transcript>>;
13
- prepare: (providerId: SpeechProviderId) => Promise<void>;
15
+ prepare: (providerId: SpeechProviderId, options?: SpeechPreparationOptions) => Promise<void>;
14
16
  cancelPreparation: (providerId: SpeechProviderId) => Promise<void>;
15
17
  configure: (patch: SpeechSelectionPatch) => Promise<void>;
16
18
  }
@@ -23,5 +25,5 @@ export interface VoiceInputInjected extends VoiceInputActions {
23
25
  /** Composer-owned expansion and draft actions; preferences stay in plugin settings. */
24
26
  export type VoiceInputProps = Pick<PropsRuntime<'conversation.input.activity'>, 'sessionId' | 'inputActions' | 'locked' | 'onActiveChange'> & PropsLocale<typeof NS> & InjectFace<VoiceInputInjected>;
25
27
  /** Render a compact microphone or an expanded capture, transcription, or retry row. */
26
- export declare function VoiceInput({ sessionId, inputActions, locked, onActiveChange, createRecording, transcribe, useSpeechReadiness, t }: VoiceInputProps): import("react").JSX.Element;
28
+ export declare function VoiceInput({ sessionId, inputActions, locked, onActiveChange, createRecording, transcribe, openSettings, useSpeechReadiness, t }: VoiceInputProps): import("react").JSX.Element;
27
29
  //# sourceMappingURL=VoiceInput.d.ts.map
@@ -0,0 +1,14 @@
1
+ import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
2
+ import type { NS } from './locales.ts';
3
+ type VoiceSetupDialogProps = PropsLocale<typeof NS> & Pick<PropsRuntime<'plugins.bundle.activation'>, 'onDismiss' | 'onOpenDetails'> & {
4
+ open: boolean;
5
+ needsInstallation: boolean;
6
+ };
7
+ /**
8
+ * Guide activation or microphone clicks to the existing plugin details.
9
+ * @param props - visibility, installation need and navigation callbacks.
10
+ * @returns a dismissible prompt that never starts preparation or recording.
11
+ */
12
+ export declare function VoiceSetupDialog({ open, needsInstallation, onDismiss, onOpenDetails, t }: VoiceSetupDialogProps): import("react").JSX.Element;
13
+ export {};
14
+ //# sourceMappingURL=VoiceSetupDialog.d.ts.map
@@ -7,6 +7,10 @@ export declare const zh: {
7
7
  readonly 'setupPrompt.body': "语音输入插件已开启。首次使用需要在本机下载并准备识别模型,请前往插件详情页查看空间、内存和时间说明,再开始安装。";
8
8
  readonly 'setupPrompt.later': "稍后";
9
9
  readonly 'setupPrompt.open': "前往安装";
10
+ readonly 'setupPrompt.trigger': "打开语音输入引导";
11
+ readonly 'setupPrompt.details': "前往语音插件设置";
12
+ readonly 'setupPrompt.unavailableTitle': "语音识别尚未就绪";
13
+ readonly 'setupPrompt.unavailableBody': "请前往语音插件详情页查看识别服务状态、准备进度或错误信息";
10
14
  readonly 'setup.local': "将在运行 DSH 的机器上下载本地模型,无需安装 Python 或编译工具。";
11
15
  readonly 'setup.disk': "硬盘空间";
12
16
  readonly 'setup.diskValue': "建议预留约 {gb} GB,包含模型、运行时和下载缓存";
@@ -54,6 +58,12 @@ export declare const zh: {
54
58
  readonly 'downloadAdvice.storage': "请检查运行 DSH 的机器的剩余磁盘空间,以及模型目录的写入权限后重试。";
55
59
  readonly 'downloadAdvice.unknown': "请检查运行 DSH 的机器的网络、磁盘空间和模型目录权限后重试。";
56
60
  readonly downloadSource: "下载来源:{source}";
61
+ readonly sourceChoice: "模型下载源";
62
+ readonly sourceAuto: "自动选择(推荐)";
63
+ readonly sourceHuggingFace: "Hugging Face";
64
+ readonly sourceMirror: "HF-Mirror(国内镜像)";
65
+ readonly sourceAutoHelp: "优先使用响应较快的源,下载失败时自动尝试其他源。";
66
+ readonly sourceManualHelp: "仅从所选源下载;已下载并通过校验的文件会复用。";
57
67
  readonly downloadCode: "错误码:{code}";
58
68
  readonly reconnecting: "正在连接语音服务…";
59
69
  readonly 'preparation.unprepared': "首次使用需要下载本地识别模型。";
@@ -65,7 +75,6 @@ export declare const zh: {
65
75
  readonly 'preparation.cancelled': "准备已取消,已完成的下载会保留。";
66
76
  readonly 'preparation.cancelling': "正在取消准备…";
67
77
  readonly cloudReady: "云端语音识别已就绪。";
68
- readonly prepareRequired: "请先在语音插件设置中准备识别服务";
69
78
  readonly discard: "丢弃识别文字";
70
79
  readonly transcribingShort: "识别中…";
71
80
  readonly wakingShort: "唤醒中…";
@@ -85,7 +94,7 @@ export declare const zh: {
85
94
  readonly requesting: "请允许使用麦克风…";
86
95
  readonly recording: "正在录音…";
87
96
  readonly interrupted: "录音中断,请重试。";
88
- readonly local: "音频在运行 DSH 的机器上识别。首次准备默认从 Hugging Face 下载模型,该机器需要能访问 Hugging Face 及其模型下载服务。如需代理,请在该机器上配置。";
97
+ readonly local: "音频在运行 DSH 的机器上识别。需要下载模型时,请确保该机器能访问所选下载源及其文件服务。如需代理,请在该机器上配置。";
89
98
  readonly cloud: "音频将发送至所选云端服务。";
90
99
  readonly empty: "未识别到语音";
91
100
  readonly cancelled: "已取消语音输入。";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-experimental-client-ui-voice-input",
3
3
  "description": "Record speech and insert editable text into the conversation draft",
4
- "version": "0.1.7-alpha.2",
4
+ "version": "0.1.7-rc.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -33,22 +33,22 @@
33
33
  "license": "MIT",
34
34
  "dependencies": {},
35
35
  "peerDependencies": {
36
+ "@deepseek-ai/dsh-api-remotes": "0.1.7-rc.2",
36
37
  "@deepseek-ai/cordis": "~4.0.4",
37
- "@deepseek-ai/dsh-api-remotes": "0.1.7-alpha.2",
38
- "@deepseek-ai/dsh-api-session-controller": "0.1.7-alpha.2",
39
- "@deepseek-ai/dsh-client-locale": "0.1.7-alpha.2",
40
- "@deepseek-ai/dsh-client-ui-conversation": "0.1.7-alpha.2",
41
- "@deepseek-ai/dsh-client-ui-primitives": "0.1.7-alpha.2",
42
- "@deepseek-ai/dsh-client-ui-session": "0.1.7-alpha.2",
43
- "@deepseek-ai/dsh-client-ui-slots": "0.1.7-alpha.2",
44
- "@deepseek-ai/dsh-session": "0.1.7-alpha.2",
45
- "@deepseek-ai/dsh-typert-protocol": "0.1.7-alpha.2",
46
- "@deepseek-ai/dsh-client-ui-renderer": "0.1.7-alpha.2",
47
- "@deepseek-ai/dsh-experimental-api-speech-to-text": "0.1.7-alpha.2",
48
- "@deepseek-ai/dsh-experimental-speech-to-text": "0.1.7-alpha.2",
49
- "@deepseek-ai/dsh-api-gateway": "0.1.7-alpha.2",
50
- "@deepseek-ai/dsh-client-store": "0.1.7-alpha.2",
51
- "@deepseek-ai/dsh-client-ui-plugin-manager": "0.1.7-alpha.2"
38
+ "@deepseek-ai/dsh-api-session-controller": "0.1.7-rc.2",
39
+ "@deepseek-ai/dsh-client-locale": "0.1.7-rc.2",
40
+ "@deepseek-ai/dsh-client-ui-conversation": "0.1.7-rc.2",
41
+ "@deepseek-ai/dsh-client-ui-renderer": "0.1.7-rc.2",
42
+ "@deepseek-ai/dsh-client-ui-session": "0.1.7-rc.2",
43
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.7-rc.2",
44
+ "@deepseek-ai/dsh-client-ui-primitives": "0.1.7-rc.2",
45
+ "@deepseek-ai/dsh-session": "0.1.7-rc.2",
46
+ "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2",
47
+ "@deepseek-ai/dsh-experimental-api-speech-to-text": "0.1.7-rc.2",
48
+ "@deepseek-ai/dsh-api-gateway": "0.1.7-rc.2",
49
+ "@deepseek-ai/dsh-client-store": "0.1.7-rc.2",
50
+ "@deepseek-ai/dsh-client-ui-plugin-manager": "0.1.7-rc.2",
51
+ "@deepseek-ai/dsh-experimental-speech-to-text": "0.1.7-rc.2"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@types/react": "~18.3.1",
@@ -56,22 +56,22 @@
56
56
  "react-dom": "^18.2.0",
57
57
  "@testing-library/react": "^16.1.0",
58
58
  "@deepseek-ai/cordis": "~4.0.4",
59
- "@deepseek-ai/dsh-api-remotes": "0.1.7-alpha.2",
60
- "@deepseek-ai/dsh-api-session-controller": "0.1.7-alpha.2",
61
- "@deepseek-ai/dsh-client-locale": "0.1.7-alpha.2",
62
- "@deepseek-ai/dsh-client-ui-conversation": "0.1.7-alpha.2",
63
- "@deepseek-ai/dsh-client-ui-primitives": "0.1.7-alpha.2",
64
- "@deepseek-ai/dsh-client-ui-renderer": "0.1.7-alpha.2",
65
- "@deepseek-ai/dsh-client-ui-session": "0.1.7-alpha.2",
66
- "@deepseek-ai/dsh-client-ui-slots": "0.1.7-alpha.2",
67
- "@deepseek-ai/dsh-session": "0.1.7-alpha.2",
68
- "@deepseek-ai/dsh-typert-protocol": "0.1.7-alpha.2",
69
- "@deepseek-ai/dsh-experimental-speech-to-text": "0.1.7-alpha.2",
70
- "@deepseek-ai/dsh-client-test-runtime": "0.1.7-alpha.2",
71
- "@deepseek-ai/dsh-api-gateway": "0.1.7-alpha.2",
72
- "@deepseek-ai/dsh-client-store": "0.1.7-alpha.2",
73
- "@deepseek-ai/dsh-client-ui-plugin-manager": "0.1.7-alpha.2",
74
- "@deepseek-ai/dsh-experimental-api-speech-to-text": "0.1.7-alpha.2"
59
+ "@deepseek-ai/dsh-api-remotes": "0.1.7-rc.2",
60
+ "@deepseek-ai/dsh-api-session-controller": "0.1.7-rc.2",
61
+ "@deepseek-ai/dsh-client-locale": "0.1.7-rc.2",
62
+ "@deepseek-ai/dsh-client-ui-conversation": "0.1.7-rc.2",
63
+ "@deepseek-ai/dsh-client-ui-primitives": "0.1.7-rc.2",
64
+ "@deepseek-ai/dsh-client-ui-renderer": "0.1.7-rc.2",
65
+ "@deepseek-ai/dsh-client-ui-session": "0.1.7-rc.2",
66
+ "@deepseek-ai/dsh-client-ui-slots": "0.1.7-rc.2",
67
+ "@deepseek-ai/dsh-session": "0.1.7-rc.2",
68
+ "@deepseek-ai/dsh-experimental-api-speech-to-text": "0.1.7-rc.2",
69
+ "@deepseek-ai/dsh-experimental-speech-to-text": "0.1.7-rc.2",
70
+ "@deepseek-ai/dsh-api-gateway": "0.1.7-rc.2",
71
+ "@deepseek-ai/dsh-client-store": "0.1.7-rc.2",
72
+ "@deepseek-ai/dsh-typert-protocol": "0.1.7-rc.2",
73
+ "@deepseek-ai/dsh-client-ui-plugin-manager": "0.1.7-rc.2",
74
+ "@deepseek-ai/dsh-client-test-runtime": "0.1.7-rc.2"
75
75
  },
76
76
  "dsh": {
77
77
  "client": {