@oadank/dsh-input-tools 0.3.15 → 0.3.16

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
@@ -909,14 +909,15 @@ window.__ModuleLoader__.load({
909
909
  // 分区标题(语音图标已移到各服务商卡片前)
910
910
  h("div", { style: { display: "flex", alignItems: "center", gap: "8px", fontSize: "15px", fontWeight: 700, color: "var(--dsw-alias-label-primary,#e6e9ef)" } },
911
911
  "语音服务"),
912
- // [2026-08-21] 试听失败错误提示;[2026-08-22] 改为 fixed 顶部弹窗 Toast(醒目,6s 自动消失)
912
+ // [2026-08-21] 试听失败错误提示;[2026-08-22] fixed 顶部弹窗 Toast + 限高滚动(错误堆栈超长不撑爆)
913
913
  previewErr !== null ? h("div", {
914
914
  style: {
915
915
  position: "fixed", top: "24px", left: "50%", transform: "translateX(-50%)", zIndex: 9999,
916
916
  background: "rgba(229,72,77,.95)", color: "#fff", borderRadius: "10px",
917
917
  padding: "10px 18px", fontSize: "13px", lineHeight: "1.5",
918
- boxShadow: "0 6px 24px rgba(0,0,0,.45)", maxWidth: "440px", whiteSpace: "pre-wrap",
919
- pointerEvents: "none",
918
+ boxShadow: "0 6px 24px rgba(0,0,0,.45)",
919
+ maxWidth: "520px", maxHeight: "45vh", overflowY: "auto",
920
+ whiteSpace: "pre-wrap", wordBreak: "break-word", pointerEvents: "none",
920
921
  },
921
922
  }, "试听失败:" + previewErr) : null,
922
923
  // [2026-08-21] 语音能力状态面板(安装即用 vs dsh 原生契约支持)
package/lib/index.js CHANGED
@@ -426,6 +426,28 @@ async function synthesizeXiaomiVoiceClone(text, cfg, globalCfg, voiceDesc) {
426
426
  return toMp3(new Uint8Array(Buffer.from(data, 'base64')), 'audio/wav')
427
427
  }
428
428
 
429
+ // [2026-08-22] 解析 Windows 命令行参数(正确处理双引号:引号内空格不拆、剥掉引号)。
430
+ // 之前用 command.split(/\s+/) 拆参数,用户填的带引号路径会被整段含引号传给
431
+ // execFileSync → node 把 "C:\...\local-tts.mjs" 当成相对路径拼上 cwd →
432
+ // Cannot find module 'D:\opt\...\"C:\Users\...'。本函数根治该问题。
433
+ function splitCommandLine(cmd) {
434
+ const args = []
435
+ let cur = ''
436
+ let inQuote = false
437
+ for (let i = 0; i < cmd.length; i++) {
438
+ const ch = cmd[i]
439
+ if (ch === '"') {
440
+ inQuote = !inQuote
441
+ } else if (ch === ' ' || ch === '\t') {
442
+ if (inQuote) { cur += ch } else if (cur !== '') { args.push(cur); cur = '' }
443
+ } else {
444
+ cur += ch
445
+ }
446
+ }
447
+ if (cur !== '') args.push(cur)
448
+ return args
449
+ }
450
+
429
451
  // ── local 本地 MeloTTS:HTTP 常驻服务优先,CMD 兜底 ──
430
452
  async function synthesizeLocalVoice(text, cfg) {
431
453
  const url = cfg?.url?.trim() ?? ''
@@ -442,7 +464,7 @@ async function synthesizeLocalVoice(text, cfg) {
442
464
  }
443
465
  const command = cfg?.cmd?.trim() ?? ''
444
466
  if (command === '') return null
445
- const parts = command.split(/\s+/)
467
+ const parts = splitCommandLine(command)
446
468
  const bin = parts[0]
447
469
  if (bin === undefined) return null
448
470
  const rest = parts.slice(1)
@@ -523,7 +545,7 @@ async function transcribeAudio(base64Audio, cfg) {
523
545
  }
524
546
  // 2) 本地命令(sherpa-onnx-offline.exe,结果输出到 stderr,需合并双流解析)
525
547
  if (asr.mode === 'cmd' && (asr.cmd ?? '').trim() !== '') {
526
- const parts = asr.cmd.trim().split(/\s+/)
548
+ const parts = splitCommandLine(asr.cmd.trim())
527
549
  const bin = parts[0]
528
550
  if (bin === undefined) return { ok: false, error: '命令格式错误' }
529
551
  const { spawnSync } = await import('node:child_process')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oadank/dsh-input-tools",
3
- "version": "0.3.15",
3
+ "version": "0.3.16",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -6,28 +6,35 @@
6
6
  # 3. ffmpeg(无则用 winget 安装)
7
7
  # 4. 注册 nssm 服务 asr(端口 18790,开机自启)
8
8
  #
9
- # 安装位置:自动放在本插件包目录下的 sherpa-onnx/(脚本位于
10
- # <插件包>/scripts/install-asr.ps1,自动推导到 <插件包>/sherpa-onnx)
11
- # ——所有人装插件后路径都统一,不会乱。
9
+ # 安装位置(2026-08-22 改):默认装到**独立目录**,不装插件包目录——
10
+ # 插件包(profile 副本或源码 internal-plugins)会随升级/重装被覆盖,
11
+ # 模型放里面会丢。默认顺序:
12
+ # 1) -InstallDir 参数显式指定(最高优先)
13
+ # 2) 检测已有 sherpa-onnx(之前装过则复用):~\.dsh\sherpa-onnx / C:\D\opt\sherpa-onnx / D:\opt\deepseek-harness\asr
14
+ # 3) 以上都没有 → ~\.dsh\sherpa-onnx(dsh 数据目录,跨升级保留)
12
15
  # 用法:以管理员身份打开 PowerShell,执行:
13
- # powershell -ExecutionPolicy Bypass -File "<插件包>\scripts\install-asr.ps1"
14
- # 可选参数:-Port 18790(自定义端口)
16
+ # powershell -ExecutionPolicy Bypass -File "<脚本路径>\install-asr.ps1"
17
+ # 可选参数:-Port 18790(自定义端口);-InstallDir "D:\opt\my-sherpa"(自定义安装目录)
15
18
  # ============================================================
16
19
  param(
17
- [int]$Port = 18790
20
+ [int]$Port = 18790,
21
+ [string]$InstallDir = ""
18
22
  )
19
23
 
20
24
  $ErrorActionPreference = "Stop"
21
25
  $Version = "v1.13.6"
22
26
 
23
- # ---- 0. 自动推导安装目录:脚本在 <插件包>/scripts/,安装到 <插件包>/sherpa-onnx/ ----
24
- $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
25
- $PluginRoot = Split-Path -Parent $ScriptDir
26
- $InstallDir = Join-Path $PluginRoot "sherpa-onnx"
27
+ # ---- 0. 确定安装目录(独立目录,不装插件包内)----
28
+ if ($InstallDir -eq "") {
29
+ foreach ($c in @("$env:USERPROFILE\.dsh\sherpa-onnx", "C:\D\opt\sherpa-onnx", "D:\opt\deepseek-harness\asr")) {
30
+ if (Test-Path (Join-Path $c "bin")) { $InstallDir = $c; break }
31
+ }
32
+ if ($InstallDir -eq "") { $InstallDir = Join-Path $env:USERPROFILE ".dsh\sherpa-onnx" }
33
+ }
27
34
 
28
35
  Write-Host "==== dsh ASR 一键安装 ====" -ForegroundColor Cyan
29
- Write-Host "插件包目录: $PluginRoot"
30
36
  Write-Host "安装目录: $InstallDir"
37
+ Write-Host " (独立目录,不随插件升级/重装被覆盖)" -ForegroundColor DarkGray
31
38
  Write-Host "服务端口: $Port"
32
39
 
33
40
  # ---- 0b. 幂等保护:已完整安装则直接退出(不下载、不注册、不碰任何现有配置)----
@@ -7,13 +7,22 @@
7
7
  # 4. 生成 local-tts.mjs 启动脚本(与插件"本地命令"契约一致:
8
8
  # node local-tts.mjs <文本> → stdout 输出 mp3 音频字节)
9
9
  #
10
- # 安装位置:自动放在本插件包目录下的 sherpa-onnx/(脚本位于
11
- # <插件包>/scripts/install-local-tts.ps1,自动推导到 <插件包>/sherpa-onnx)
12
- # ——与 ASR 安装共用同一目录,两个 exe 一次下载全有。
10
+ # 安装位置(2026-08-22 改):默认装到**独立目录**,不装插件包目录——
11
+ # 插件包(profile 副本或源码 internal-plugins)会随升级/重装被覆盖,
12
+ # 模型放里面会丢。默认顺序:
13
+ # 1) -InstallDir 参数显式指定(最高优先,可指定源码 internal-plugins 等任意位置)
14
+ # 2) 检测已有 sherpa-onnx(ASR 装过则复用同一份,省一次下载):
15
+ # ~\.dsh\sherpa-onnx / C:\D\opt\sherpa-onnx / D:\opt\deepseek-harness\asr
16
+ # 3) 以上都没有 → ~\.dsh\sherpa-onnx(dsh 数据目录,跨升级保留)
13
17
  # 用法:以管理员身份打开 PowerShell,执行:
14
- # powershell -ExecutionPolicy Bypass -File "<插件包>\scripts\install-local-tts.ps1"
18
+ # powershell -ExecutionPolicy Bypass -File "<脚本路径>\install-local-tts.ps1"
19
+ # 或指定安装目录:... install-local-tts.ps1 -InstallDir "D:\opt\my-sherpa"
15
20
  # 装完后到 dsh 设置 → 语音服务 → 本地 TTS,把提示的命令填进「本地命令」。
16
21
  # ============================================================
22
+ param(
23
+ [string]$InstallDir = ""
24
+ )
25
+
17
26
  $ErrorActionPreference = "Stop"
18
27
  $Version = "v1.13.6"
19
28
 
@@ -57,14 +66,18 @@ function Expand-TarBz2 {
57
66
  return $true
58
67
  }
59
68
 
60
- # ---- 0. 自动推导安装目录:脚本在 <插件包>/scripts/,安装到 <插件包>/sherpa-onnx/ ----
61
- $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
62
- $PluginRoot = Split-Path -Parent $ScriptDir
63
- $InstallDir = Join-Path $PluginRoot "sherpa-onnx"
69
+ # ---- 0. 确定安装目录(独立目录,不装插件包内)----
70
+ if ($InstallDir -eq "") {
71
+ # 复用已有 sherpa-onnx(ASR 装过则共用,省一次下载)
72
+ foreach ($c in @("$env:USERPROFILE\.dsh\sherpa-onnx", "C:\D\opt\sherpa-onnx", "D:\opt\deepseek-harness\asr")) {
73
+ if (Test-Path (Join-Path $c "bin")) { $InstallDir = $c; break }
74
+ }
75
+ if ($InstallDir -eq "") { $InstallDir = Join-Path $env:USERPROFILE ".dsh\sherpa-onnx" }
76
+ }
64
77
 
65
78
  Write-Host "==== dsh 本地 TTS 一键安装 ====" -ForegroundColor Cyan
66
- Write-Host "插件包目录: $PluginRoot"
67
79
  Write-Host "安装目录: $InstallDir"
80
+ Write-Host " (独立目录,不随插件升级/重装被覆盖;与 ASR 共用同一份 sherpa-onnx)" -ForegroundColor DarkGray
68
81
 
69
82
  # ---- 0b. 幂等保护:已完整安装则直接退出 ----
70
83
  $exeExists = Test-Path "$InstallDir\bin\sherpa-onnx-offline-tts.exe"
@@ -198,14 +211,16 @@ try {
198
211
  }
199
212
  '@
200
213
  $launcher = $launcherTemplate.Replace('__SHERPA__', $exePath).Replace('__BASE__', $basePath)
201
- $launcherFile = "$PluginRoot\local-tts.mjs"
214
+ $launcherFile = Join-Path $InstallDir "local-tts.mjs"
202
215
  Set-Content -Path $launcherFile -Value $launcher -Encoding UTF8
203
216
  Write-Host " local-tts.mjs: $launcherFile" -ForegroundColor Green
204
217
 
205
- # ---- 6. 完成提示 ----
218
+ # ---- 6. 完成提示(命令只在路径含空格时才加引号;插件已能正确处理引号)----
206
219
  Write-Host "`n==== 安装完成 ====" -ForegroundColor Cyan
207
220
  $nodeExe = (Get-Command node).Source
208
- $cmdLine = "$nodeExe `"$launcherFile`""
221
+ $nodePart = if ($nodeExe -match ' ') { "`"$nodeExe`"" } else { $nodeExe }
222
+ $launcherPart = if ($launcherFile -match ' ') { "`"$launcherFile`"" } else { $launcherFile }
223
+ $cmdLine = "$nodePart $launcherPart"
209
224
  Write-Host "请到 dsh 设置 → 语音服务 → 本地 TTS,把下面这行填进「本地命令」:"
210
225
  Write-Host ""
211
226
  Write-Host " $cmdLine" -ForegroundColor Green