@oadank/dsh-input-tools 0.3.3 → 0.3.5
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/assets/voice-design-samples/asmr.mp3 +0 -0
- package/assets/voice-design-samples/docu.mp3 +0 -0
- package/assets/voice-design-samples/elder.mp3 +0 -0
- package/assets/voiceclone-samples/8da38fcc-b041-4f5b-86b9-901956016f89.mp3 +0 -0
- package/lib/index.js +61 -12
- package/package.json +2 -1
- package/scripts/install-asr.ps1 +55 -10
- package/scripts/install-local-tts.ps1 +51 -9
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/lib/index.js
CHANGED
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
import { createHash, randomUUID } from 'node:crypto'
|
|
23
|
-
import { mkdir, open, readFile, unlink, writeFile } from 'node:fs/promises'
|
|
23
|
+
import { mkdir, open, readFile, unlink, writeFile, copyFile } from 'node:fs/promises'
|
|
24
24
|
import { constants, readFileSync } from 'node:fs'
|
|
25
25
|
import { homedir } from 'node:os'
|
|
26
26
|
import { fileURLToPath } from 'node:url'
|
|
@@ -34,6 +34,44 @@ const inject = ['tools', 'webServer']
|
|
|
34
34
|
|
|
35
35
|
export { name, inject }
|
|
36
36
|
|
|
37
|
+
// ──────────────────────────────────────────────────────────────
|
|
38
|
+
// [0.3.4] 自带素材(下载即用):克隆样本 + VoiceDesign 示例音频打进 npm 包 assets/,
|
|
39
|
+
// 首次加载自动拷贝到 DSH_HOME 并注册,不再依赖"手动上传/在线生成"。
|
|
40
|
+
// ──────────────────────────────────────────────────────────────
|
|
41
|
+
const PLUGIN_ROOT = join(fileURLToPath(import.meta.url), '..', '..') // .../dsh-input-tools
|
|
42
|
+
const ASSETS_DIR = join(PLUGIN_ROOT, 'assets')
|
|
43
|
+
const BUNDLED_CLONE_ID = '8da38fcc-b041-4f5b-86b9-901956016f89'
|
|
44
|
+
const BUNDLED_CLONE_SAMPLE = {
|
|
45
|
+
id: BUNDLED_CLONE_ID,
|
|
46
|
+
name: '小团团(60秒长样本)',
|
|
47
|
+
context: '一个魔性的少女萝莉音,说话自带沙雕搞怪和无厘头气质,像在撒娇又像在耍宝,情绪起伏很大:前一句还奶声奶气地撒娇卖萌,后一句就突然拔高音量夸张卖惨耍赖,再下一秒又贱兮兮地坏笑。尾音拖长上扬,带着气音和魔性笑声,喜欢用「臭猪」「你凶我」「哼」「嘿嘿嘿」这类咋咋呼呼的用词,语速忽快忽慢、节奏跳跃,吐字软糯清晰,傻白甜又可爱,让人听了忍不住想笑',
|
|
48
|
+
}
|
|
49
|
+
const VOICE_DESIGN_SAMPLE_KEYS = ['asmr', 'docu', 'elder']
|
|
50
|
+
|
|
51
|
+
let bundledInitDone = false
|
|
52
|
+
/** 首次加载把自带素材落地到 DSH_HOME:克隆样本 mp3 拷贝 + 首次安装自动注册小团团。 */
|
|
53
|
+
async function ensureBundledAssets(config, parsed) {
|
|
54
|
+
if (bundledInitDone) return config
|
|
55
|
+
bundledInitDone = true
|
|
56
|
+
try {
|
|
57
|
+
const homeDir = process.env.DSH_HOME ?? join(homedir(), '.dsh')
|
|
58
|
+
const cloneDir = join(homeDir, 'voiceclone-samples')
|
|
59
|
+
const dstClone = join(cloneDir, BUNDLED_CLONE_ID + '.mp3')
|
|
60
|
+
try {
|
|
61
|
+
await mkdir(cloneDir, { recursive: true })
|
|
62
|
+
await copyFile(join(ASSETS_DIR, 'voiceclone-samples', BUNDLED_CLONE_ID + '.mp3'), dstClone)
|
|
63
|
+
} catch { /* 包内素材缺失或拷贝失败:跳过(不阻塞启动) */ }
|
|
64
|
+
// 仅"首次安装"(配置里还没有 voiceclone 键)时注册自带样本;用户删光的 [] 不强制
|
|
65
|
+
const parsedHasClone = parsed !== null && typeof parsed === 'object' && parsed.engines?.voiceclone !== undefined
|
|
66
|
+
const samples = config?.engines?.voiceclone?.samples
|
|
67
|
+
if (!parsedHasClone && (!Array.isArray(samples) || samples.length === 0)) {
|
|
68
|
+
config.engines.voiceclone = { ...config.engines.voiceclone, enabled: true, samples: [{ ...BUNDLED_CLONE_SAMPLE, path: dstClone }] }
|
|
69
|
+
await saveVoiceConfig(config)
|
|
70
|
+
}
|
|
71
|
+
} catch { /* 初始化失败不阻塞 */ }
|
|
72
|
+
return config
|
|
73
|
+
}
|
|
74
|
+
|
|
37
75
|
// ──────────────────────────────────────────────────────────────
|
|
38
76
|
// 配置中心:~/.dsh/voice-config.json
|
|
39
77
|
// ──────────────────────────────────────────────────────────────
|
|
@@ -95,6 +133,8 @@ async function loadVoiceConfig() {
|
|
|
95
133
|
parsed = JSON.parse(await readFile(CONFIG_PATH, 'utf8'))
|
|
96
134
|
} catch { /* 首次无配置 */ }
|
|
97
135
|
cachedConfig = deepMerge(defaultVoiceConfig(), parsed)
|
|
136
|
+
// [0.3.4] 自带素材初始化(拷贝克隆样本 + 首次安装自动注册小团团)
|
|
137
|
+
await ensureBundledAssets(cachedConfig, parsed)
|
|
98
138
|
// 环境变量覆盖(兼容旧配置;显式配置值优先于 env)
|
|
99
139
|
const env = process.env
|
|
100
140
|
if (env.TTS_XIAOMI_KEY !== undefined && cachedConfig.engines.xiaomi.apiKey === '') cachedConfig.engines.xiaomi.apiKey = env.TTS_XIAOMI_KEY
|
|
@@ -961,8 +1001,8 @@ async function apply(ctx) {
|
|
|
961
1001
|
return sendJson(res, 404, { ok: false, error: '安装脚本不存在' })
|
|
962
1002
|
}
|
|
963
1003
|
}
|
|
964
|
-
// VoiceDesign
|
|
965
|
-
//
|
|
1004
|
+
// VoiceDesign 官方示例音频:[0.3.4] 优先读插件包自带素材(assets/,mp3 下载即用),
|
|
1005
|
+
// 包内缺失才回退到"小米模型在线生成 + 缓存到 ~/.dsh/voice-design-samples/ 的 wav"。
|
|
966
1006
|
if (url.pathname === '/asr/voice-design-samples' && req.method === 'GET') {
|
|
967
1007
|
const cfg = await loadVoiceConfig()
|
|
968
1008
|
const homeDir = process.env.DSH_HOME ?? join(homedir(), '.dsh')
|
|
@@ -986,20 +1026,29 @@ async function apply(ctx) {
|
|
|
986
1026
|
]
|
|
987
1027
|
const results = []
|
|
988
1028
|
for (const s of samples) {
|
|
989
|
-
|
|
990
|
-
let
|
|
991
|
-
try {
|
|
992
|
-
|
|
1029
|
+
// 1) 包内自带 mp3(首选,下载即用)
|
|
1030
|
+
let bytes = null
|
|
1031
|
+
try { bytes = await readFile(join(ASSETS_DIR, 'voice-design-samples', `${s.key}.mp3`)) } catch { /* 包内无 → 回退 */ }
|
|
1032
|
+
let mediaType = 'audio/mpeg'
|
|
1033
|
+
if (bytes === null) {
|
|
1034
|
+
// 2) 缓存 wav(在线生成过)
|
|
1035
|
+
const wavPath = join(sampleDir, `${s.key}.wav`)
|
|
1036
|
+
try { bytes = await readFile(wavPath) } catch { /* 继续回退 */ }
|
|
1037
|
+
mediaType = 'audio/wav'
|
|
1038
|
+
}
|
|
1039
|
+
if (bytes === null) {
|
|
1040
|
+
// 3) 在线生成(key 缺失会失败,示例跳过)
|
|
993
1041
|
try {
|
|
994
1042
|
const syn = await synthesizeXiaomiVoiceDesign(s.text, { context: s.instruct }, cfg)
|
|
995
1043
|
if (syn === null) throw new Error('voicedesign synth failed')
|
|
996
|
-
|
|
1044
|
+
bytes = Buffer.from(syn.data)
|
|
1045
|
+
mediaType = 'audio/wav'
|
|
997
1046
|
await mkdir(sampleDir, { recursive: true })
|
|
998
|
-
await writeFile(
|
|
999
|
-
} catch { /*
|
|
1047
|
+
await writeFile(join(sampleDir, `${s.key}.wav`), bytes)
|
|
1048
|
+
} catch { /* 模型生成失败 → 跳过 */ }
|
|
1000
1049
|
}
|
|
1001
|
-
if (
|
|
1002
|
-
results.push({ key: s.key, title: s.title, mediaType
|
|
1050
|
+
if (bytes !== null) {
|
|
1051
|
+
results.push({ key: s.key, title: s.title, mediaType, data: bytes.toString('base64') })
|
|
1003
1052
|
}
|
|
1004
1053
|
}
|
|
1005
1054
|
return sendJson(res, 200, { ok: results.length > 0, samples: results })
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oadank/dsh-input-tools",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.5",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"files": [
|
|
14
14
|
"lib",
|
|
15
15
|
"scripts",
|
|
16
|
+
"assets",
|
|
16
17
|
"README.md",
|
|
17
18
|
"cordis.patch.yml"
|
|
18
19
|
],
|
package/scripts/install-asr.ps1
CHANGED
|
@@ -58,6 +58,39 @@ New-Item -ItemType Directory -Force -Path "$InstallDir\models" | Out-Null
|
|
|
58
58
|
New-Item -ItemType Directory -Force -Path "$InstallDir\bin" | Out-Null
|
|
59
59
|
New-Item -ItemType Directory -Force -Path "$InstallDir\tmp" | Out-Null
|
|
60
60
|
|
|
61
|
+
# ---- 1b. 下载/解压工具函数(2026-08-21 增强:断点续传 + 完整性校验 + 损坏自动重试)----
|
|
62
|
+
# 之前 XDN 实测:GitHub 大文件下载中断 → 只下了 42.7MB/230MB → tar 报 Truncated → 脚本抛错退出,
|
|
63
|
+
# 用户只看到"跑到最后报错"毫无提示。现在 curl -C - 断点续传 + 解压后校验,损坏文件自动删除重下。
|
|
64
|
+
function Download-Resume {
|
|
65
|
+
param([string]$Url, [string]$OutFile)
|
|
66
|
+
for ($attempt = 1; $attempt -le 3; $attempt++) {
|
|
67
|
+
Write-Host " 下载(第 $attempt 次尝试): $Url" -ForegroundColor Yellow
|
|
68
|
+
# Windows 10+ 自带 curl.exe;-C - 断点续传;--retry 网络层重试
|
|
69
|
+
& curl.exe -L -C - --retry 3 --retry-delay 2 --connect-timeout 20 -o $OutFile $Url 2>$null
|
|
70
|
+
if ($LASTEXITCODE -eq 0) { return $true }
|
|
71
|
+
Write-Host " 下载中断(exit=$LASTEXITCODE),3 秒后重试..." -ForegroundColor Yellow
|
|
72
|
+
Start-Sleep -Seconds 3
|
|
73
|
+
}
|
|
74
|
+
return $false
|
|
75
|
+
}
|
|
76
|
+
function Expand-TarBz2 {
|
|
77
|
+
param([string]$Archive, [string]$Dest, [int]$Strip = 0)
|
|
78
|
+
$tmpDir = Join-Path $Dest ".extract-tmp"
|
|
79
|
+
New-Item -ItemType Directory -Force -Path $tmpDir | Out-Null
|
|
80
|
+
$tarArgs = @('-xjf', $Archive, '-C', $tmpDir)
|
|
81
|
+
if ($Strip -gt 0) { $tarArgs += "--strip-components=$Strip" }
|
|
82
|
+
tar @tarArgs 2>$null
|
|
83
|
+
if ($LASTEXITCODE -ne 0) {
|
|
84
|
+
Write-Host " 解压失败:压缩包损坏或不完整($Archive)" -ForegroundColor Red
|
|
85
|
+
Remove-Item -Recurse -Force $tmpDir -ErrorAction SilentlyContinue
|
|
86
|
+
Remove-Item -Force $Archive -ErrorAction SilentlyContinue
|
|
87
|
+
return $false
|
|
88
|
+
}
|
|
89
|
+
Get-ChildItem $tmpDir | Move-Item -Destination $Dest -Force -ErrorAction SilentlyContinue
|
|
90
|
+
Remove-Item -Recurse -Force $tmpDir -ErrorAction SilentlyContinue
|
|
91
|
+
return $true
|
|
92
|
+
}
|
|
93
|
+
|
|
61
94
|
# ---- 2. 检查 ffmpeg(ASR 转码必需)----
|
|
62
95
|
Write-Host "`n[1/4] 检查 ffmpeg..." -ForegroundColor Yellow
|
|
63
96
|
$ffmpeg = Get-Command ffmpeg -ErrorAction SilentlyContinue
|
|
@@ -79,12 +112,15 @@ Write-Host "`n[2/4] 下载 sherpa-onnx $Version ..." -ForegroundColor Yellow
|
|
|
79
112
|
$pkgUrl = "https://github.com/k2-fsa/sherpa-onnx/releases/download/$Version/sherpa-onnx-$Version-win-x64-shared-MD-Release.tar.bz2"
|
|
80
113
|
$pkgFile = "$InstallDir\tmp\sherpa-onnx.tar.bz2"
|
|
81
114
|
if (-not (Test-Path "$InstallDir\bin\sherpa-onnx-offline.exe")) {
|
|
82
|
-
if (-not (
|
|
83
|
-
Write-Host "
|
|
84
|
-
|
|
115
|
+
if (-not (Download-Resume $pkgUrl $pkgFile)) {
|
|
116
|
+
Write-Host " sherpa-onnx 下载失败(网络不稳定)。请检查网络后重跑本脚本" -ForegroundColor Red
|
|
117
|
+
exit 1
|
|
85
118
|
}
|
|
86
119
|
Write-Host " 解压..."
|
|
87
|
-
|
|
120
|
+
if (-not (Expand-TarBz2 $pkgFile "$InstallDir\tmp")) {
|
|
121
|
+
Write-Host " sherpa-onnx 压缩包损坏已删除,请重跑本脚本自动重新下载" -ForegroundColor Red
|
|
122
|
+
exit 1
|
|
123
|
+
}
|
|
88
124
|
# 解压后目录结构:sherpa-onnx-v1.13.6-win-x64-shared-MD-Release/ 内含 bin/ lib/
|
|
89
125
|
$extracted = Get-ChildItem "$InstallDir\tmp" -Directory | Where-Object { $_.Name -like "sherpa-onnx-*win*" } | Select-Object -First 1
|
|
90
126
|
if ($extracted) {
|
|
@@ -99,19 +135,28 @@ if (-not (Test-Path "$InstallDir\bin\sherpa-onnx-offline.exe")) {
|
|
|
99
135
|
Write-Host " sherpa-onnx 已存在,跳过下载" -ForegroundColor Green
|
|
100
136
|
}
|
|
101
137
|
|
|
102
|
-
# ---- 4. 下载 SenseVoice
|
|
138
|
+
# ---- 4. 下载 SenseVoice 模型(断点续传 + 完整性校验)----
|
|
103
139
|
Write-Host "`n[3/4] 下载 SenseVoice int8 模型..." -ForegroundColor Yellow
|
|
104
140
|
$modelDir = "$InstallDir\models\sensevoice-int8"
|
|
105
141
|
$modelUrl = "https://github.com/k2-fsa/sherpa-onnx/releases/download/asr-models/sherpa-onnx-sense-voice-zh-en-ja-ko-yue-int8-2025-09-09.tar.bz2"
|
|
106
142
|
$modelFile = "$InstallDir\tmp\sensevoice.tar.bz2"
|
|
107
143
|
if (-not (Test-Path "$modelDir\model.int8.onnx")) {
|
|
108
|
-
if (-not (
|
|
109
|
-
Write-Host "
|
|
110
|
-
|
|
144
|
+
if (-not (Download-Resume $modelUrl $modelFile)) {
|
|
145
|
+
Write-Host " SenseVoice 模型下载失败(网络不稳定)。请检查网络后重跑本脚本" -ForegroundColor Red
|
|
146
|
+
exit 1
|
|
111
147
|
}
|
|
112
148
|
New-Item -ItemType Directory -Force -Path $modelDir | Out-Null
|
|
113
149
|
Write-Host " 解压模型..."
|
|
114
|
-
|
|
150
|
+
if (-not (Expand-TarBz2 $modelFile $modelDir 1)) {
|
|
151
|
+
Write-Host " 模型压缩包损坏已删除,请重跑本脚本自动重新下载" -ForegroundColor Red
|
|
152
|
+
exit 1
|
|
153
|
+
}
|
|
154
|
+
if (-not (Test-Path "$modelDir\model.int8.onnx")) {
|
|
155
|
+
Write-Host " 解压后未找到 model.int8.onnx(压缩包异常),已清理。请重跑本脚本" -ForegroundColor Red
|
|
156
|
+
Remove-Item -Recurse -Force $modelDir -ErrorAction SilentlyContinue
|
|
157
|
+
Remove-Item -Force $modelFile -ErrorAction SilentlyContinue
|
|
158
|
+
exit 1
|
|
159
|
+
}
|
|
115
160
|
Write-Host " 模型解压完成" -ForegroundColor Green
|
|
116
161
|
} else {
|
|
117
162
|
Write-Host " 模型已存在,跳过下载" -ForegroundColor Green
|
|
@@ -168,7 +213,7 @@ const server = http.createServer(async (req, res) => {
|
|
|
168
213
|
res.writeHead(404); res.end();
|
|
169
214
|
}
|
|
170
215
|
});
|
|
171
|
-
server.listen(PORT, () => console.log('[ASR] listening on ' + PORT));
|
|
216
|
+
server.listen(PORT, '127.0.0.1', () => console.log('[ASR] listening on 127.0.0.1:' + PORT));
|
|
172
217
|
"@
|
|
173
218
|
# 服务脚本用 .cjs:插件包 package.json 声明了 "type":"module",.js 会被当 ESM 解析导致 require 报错
|
|
174
219
|
# (2026-08-21 XDN 实测:asr-service.js 抛 ReferenceError: require is not defined)
|
|
@@ -17,6 +17,36 @@
|
|
|
17
17
|
$ErrorActionPreference = "Stop"
|
|
18
18
|
$Version = "v1.13.6"
|
|
19
19
|
|
|
20
|
+
# ---- 下载/解压工具函数(2026-08-21 增强:断点续传 + 完整性校验 + 损坏自动重试)----
|
|
21
|
+
function Download-Resume {
|
|
22
|
+
param([string]$Url, [string]$OutFile)
|
|
23
|
+
for ($attempt = 1; $attempt -le 3; $attempt++) {
|
|
24
|
+
Write-Host " 下载(第 $attempt 次尝试): $Url" -ForegroundColor Yellow
|
|
25
|
+
& curl.exe -L -C - --retry 3 --retry-delay 2 --connect-timeout 20 -o $OutFile $Url 2>$null
|
|
26
|
+
if ($LASTEXITCODE -eq 0) { return $true }
|
|
27
|
+
Write-Host " 下载中断(exit=$LASTEXITCODE),3 秒后重试..." -ForegroundColor Yellow
|
|
28
|
+
Start-Sleep -Seconds 3
|
|
29
|
+
}
|
|
30
|
+
return $false
|
|
31
|
+
}
|
|
32
|
+
function Expand-TarBz2 {
|
|
33
|
+
param([string]$Archive, [string]$Dest, [int]$Strip = 0)
|
|
34
|
+
$tmpDir = Join-Path $Dest ".extract-tmp"
|
|
35
|
+
New-Item -ItemType Directory -Force -Path $tmpDir | Out-Null
|
|
36
|
+
$tarArgs = @('-xjf', $Archive, '-C', $tmpDir)
|
|
37
|
+
if ($Strip -gt 0) { $tarArgs += "--strip-components=$Strip" }
|
|
38
|
+
tar @tarArgs 2>$null
|
|
39
|
+
if ($LASTEXITCODE -ne 0) {
|
|
40
|
+
Write-Host " 解压失败:压缩包损坏或不完整($Archive)" -ForegroundColor Red
|
|
41
|
+
Remove-Item -Recurse -Force $tmpDir -ErrorAction SilentlyContinue
|
|
42
|
+
Remove-Item -Force $Archive -ErrorAction SilentlyContinue
|
|
43
|
+
return $false
|
|
44
|
+
}
|
|
45
|
+
Get-ChildItem $tmpDir | Move-Item -Destination $Dest -Force -ErrorAction SilentlyContinue
|
|
46
|
+
Remove-Item -Recurse -Force $tmpDir -ErrorAction SilentlyContinue
|
|
47
|
+
return $true
|
|
48
|
+
}
|
|
49
|
+
|
|
20
50
|
# ---- 0. 自动推导安装目录:脚本在 <插件包>/scripts/,安装到 <插件包>/sherpa-onnx/ ----
|
|
21
51
|
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
22
52
|
$PluginRoot = Split-Path -Parent $ScriptDir
|
|
@@ -62,12 +92,15 @@ $pkgUrl = "https://github.com/k2-fsa/sherpa-onnx/releases/download/$Version/sher
|
|
|
62
92
|
$pkgFile = "$InstallDir\tmp\sherpa-onnx.tar.bz2"
|
|
63
93
|
if (-not (Test-Path "$InstallDir\bin\sherpa-onnx-offline-tts.exe")) {
|
|
64
94
|
if (-not (Test-Path "$InstallDir\bin\sherpa-onnx-offline.exe")) {
|
|
65
|
-
if (-not (
|
|
66
|
-
Write-Host "
|
|
67
|
-
|
|
95
|
+
if (-not (Download-Resume $pkgUrl $pkgFile)) {
|
|
96
|
+
Write-Host " sherpa-onnx 下载失败(网络不稳定)。请检查网络后重跑本脚本" -ForegroundColor Red
|
|
97
|
+
exit 1
|
|
68
98
|
}
|
|
69
99
|
Write-Host " 解压..."
|
|
70
|
-
|
|
100
|
+
if (-not (Expand-TarBz2 $pkgFile "$InstallDir\tmp")) {
|
|
101
|
+
Write-Host " sherpa-onnx 压缩包损坏已删除,请重跑本脚本自动重新下载" -ForegroundColor Red
|
|
102
|
+
exit 1
|
|
103
|
+
}
|
|
71
104
|
$extracted = Get-ChildItem "$InstallDir\tmp" -Directory | Where-Object { $_.Name -like "sherpa-onnx-*win*" } | Select-Object -First 1
|
|
72
105
|
if ($extracted) {
|
|
73
106
|
Copy-Item "$($extracted.FullName)\bin\*" "$InstallDir\bin\" -Force
|
|
@@ -84,19 +117,28 @@ if (-not (Test-Path "$InstallDir\bin\sherpa-onnx-offline-tts.exe")) {
|
|
|
84
117
|
Write-Host " sherpa-onnx 已存在,跳过下载" -ForegroundColor Green
|
|
85
118
|
}
|
|
86
119
|
|
|
87
|
-
# ---- 4. 下载 MeloTTS
|
|
120
|
+
# ---- 4. 下载 MeloTTS 中文模型(断点续传 + 完整性校验)----
|
|
88
121
|
Write-Host "`n[3/3] 下载中文 MeloTTS VITS 模型..." -ForegroundColor Yellow
|
|
89
122
|
$modelDir = "$InstallDir\models\melo"
|
|
90
123
|
$modelUrl = "https://github.com/k2-fsa/sherpa-onnx/releases/download/tts-models/vits-melo-tts-zh_en.tar.bz2"
|
|
91
124
|
$modelFile = "$InstallDir\tmp\melo.tar.bz2"
|
|
92
125
|
if (-not (Test-Path "$modelDir\model.onnx")) {
|
|
93
|
-
if (-not (
|
|
94
|
-
Write-Host "
|
|
95
|
-
|
|
126
|
+
if (-not (Download-Resume $modelUrl $modelFile)) {
|
|
127
|
+
Write-Host " MeloTTS 模型下载失败(网络不稳定)。请检查网络后重跑本脚本" -ForegroundColor Red
|
|
128
|
+
exit 1
|
|
96
129
|
}
|
|
97
130
|
New-Item -ItemType Directory -Force -Path $modelDir | Out-Null
|
|
98
131
|
Write-Host " 解压模型..."
|
|
99
|
-
|
|
132
|
+
if (-not (Expand-TarBz2 $modelFile $modelDir 1)) {
|
|
133
|
+
Write-Host " 模型压缩包损坏已删除,请重跑本脚本自动重新下载" -ForegroundColor Red
|
|
134
|
+
exit 1
|
|
135
|
+
}
|
|
136
|
+
if (-not (Test-Path "$modelDir\model.onnx")) {
|
|
137
|
+
Write-Host " 解压后未找到 model.onnx(压缩包异常),已清理。请重跑本脚本" -ForegroundColor Red
|
|
138
|
+
Remove-Item -Recurse -Force $modelDir -ErrorAction SilentlyContinue
|
|
139
|
+
Remove-Item -Force $modelFile -ErrorAction SilentlyContinue
|
|
140
|
+
exit 1
|
|
141
|
+
}
|
|
100
142
|
Write-Host " 模型解压完成" -ForegroundColor Green
|
|
101
143
|
} else {
|
|
102
144
|
Write-Host " 模型已存在,跳过下载" -ForegroundColor Green
|