🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

音色训练流水线 InariNGT-Ofiicial/dsh-train-pipeline

DeepSeek 客户端
InariNGT-Ofiicial7 天前有提交已提供中文文档扫描:含敏感能力兼容 / 相关生态

正式版 v0.5.0 · 同时支持 DSH rc.2 / rc.3。

36.1/100
综合分
9
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/25 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

相关生态插件(非 dsh 原生,按其对应运行时安装)
git clone https://github.com/InariNGT-Ofiicial/dsh-train-pipeline.git

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:已验证
是什么
生态应用
桌面端 / Web 外壳,不以 dsh plugin add 安装
装得上吗
本站已在 dsh 0.2.1-rc.2 下真实安装成功
非静态推断
L4 · 真实安装等级说明 →
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 7 天前
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查需源码安装

仓库 package.json 标记 private,未发布到 npm,需从源码安装

展开查看检查明细 ↓

以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。

✗npm 包dsh-train-pipeline(未发布到 npm,仅可源码安装)
✓Node 引擎要求 >=18 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明

源码安装时若 pnpm 拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑。

验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/28 17:40:45

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件读取剪贴板或密钥环境变量
查看扫描证据(共 136 处,展示前 79 条)
  • 读取本地文件
    src/index.js:91
    try { entries = readdirSync(d, { withFileTypes: true }); } catch { return; }
  • 读取本地文件
    src/index.js:103
    return readdirSync(dir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name);
  • 写入本地文件
    src/index.js:114
    mkdirSync(dest, { recursive: true });
  • 读取本地文件
    src/index.js:116
    for (const e of readdirSync(src, { withFileTypes: true })) {
  • 读取本地文件
    src/index.js:123
    while (existsSync(t)) {
  • 写入本地文件
    src/index.js:128
    copyFileSync(s, t);
  • 读取本地文件
    src/index.js:153
    if (!py || !existsSync(py)) {
  • 读取本地文件
    src/index.js:160
    cwd: opts.cwd ?? (cfg.ddspDir && existsSync(cfg.ddspDir) ? cfg.ddspDir : PY_DIR),
  • 写入本地文件
    src/index.js:285
    writeFileSync(LOCAL_CONFIG, JSON.stringify(out, null, 2), 'utf8');
  • 写入本地文件
    src/index.js:858
    mkdirSync(c.ws.corpus, { recursive: true });
  • 写入本地文件
    src/index.js:859
    writeFileSync(join(c.ws.corpus, '_latest.json'),
  • 写入本地文件
    src/index.js:970
    mkdirSync(c.ws.datasets, { recursive: true });
  • 读取本地文件
    src/config.js:87
    export const isFile = (p) => { try { return !!p && existsSync(p) && statSync(p).isFile(); } catch { return false; } };
  • 读取本地文件
    src/config.js:87
    export const isFile = (p) => { try { return !!p && existsSync(p) && statSync(p).isFile(); } catch { return false; } };
  • 读取本地文件
    src/config.js:88
    export const isDir = (p) => { try { return !!p && existsSync(p) && statSync(p).isDirectory(); } catch { return false; } };
  • 读取本地文件
    src/config.js:88
    export const isDir = (p) => { try { return !!p && existsSync(p) && statSync(p).isDirectory(); } catch { return false; } };
  • 读取本地文件
    src/config.js:93
    return readdirSync(dir, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => join(dir, d.name));
  • 读取本地文件
    src/config.js:99
    return readdirSync(dir, { withFileTypes: true }).filter((d) => d.isFile()).map((d) => d.name);
  • 执行外部命令来自配置/变量
    src/execution.js:43
    child = spawn(cmd, args, { cwd, env, windowsHide: true });
  • 写入本地文件
    src/execution.js:64
    mkdirSync(dirname(logPath), { recursive: true });
  • 执行外部命令来自配置/变量
    src/execution.js:68
    child = spawn(cmd, args, {
  • 写入本地文件
    src/execution.js:75
    try { appendFileSync(logPath, `\n[spawn error] ${e?.message ?? e}\n`); } catch { }
  • 读取本地文件
    src/execution.js:95
    if (existsSync(p)) { exists = true; sizeBytes = statSync(p).size; }
  • 读取本地文件
    src/execution.js:95
    if (existsSync(p)) { exists = true; sizeBytes = statSync(p).size; }
  • 读取本地文件
    src/execution.js:110
    if (!existsSync(path)) return '';
  • 读取本地文件
    src/execution.js:111
    const text = readFileSync(path, 'utf8');
  • 读取本地文件
    src/execution.js:144
    if (!existsSync(expDir)) return [];
  • 读取本地文件
    src/execution.js:145
    return readdirSync(expDir)
  • 读取本地文件
    src/checks.js:20
    const text = readFileSync(path, 'utf8');
  • 读取本地文件
    src/hunt.js:37
    try { return readdirSync(dir, { withFileTypes: true }); } catch { return []; }
  • 读取本地文件
    src/hunt.js:41
    try { return statSync(p).isDirectory(); } catch { return false; }
  • 读取本地文件
    src/hunt.js:87
    if (!existsSync(vdf)) continue;
  • 读取本地文件
    src/hunt.js:89
    try { text = readFileSync(vdf, 'utf8'); } catch { continue; }
  • 读取本地文件
    src/hunt.js:102
    try { text = readFileSync(join(sa, e.name), 'utf8'); } catch { continue; }
  • 写入本地文件
    src/toolchain.js:108
    mkdirSync(toolsDir(cfg), { recursive: true });
  • 写入本地文件
    src/toolchain.js:109
    writeFileSync(manifestPath(cfg), JSON.stringify(all, null, 2), 'utf8');
  • 读取本地文件
    src/toolchain.js:118
    for (const d of readdirSync('C:/Windows/Microsoft.NET/Framework64')) {
  • 读取本地文件
    src/toolchain.js:131
    try { entries = readdirSync(d); } catch { continue; }
  • 读取本地文件
    src/toolchain.js:152
    try { if (bin) sizeText = fmtBytes(statSync(bin).size); } catch { }
  • 写入本地文件
    src/toolchain.js:219
    mkdirSync(cacheDir, { recursive: true });
  • 删除本地文件递归
    src/toolchain.js:232
    try { rmSync(tmp, { recursive: true, force: true }); } catch { }
  • 删除本地文件递归
    src/toolchain.js:235
    try { rmSync(targetDir, { recursive: true, force: true }); } catch { }
  • 写入本地文件
    src/toolchain.js:236
    mkdirSync(targetDir, { recursive: true });
  • 读取本地文件
    src/toolchain.js:237
    for (const e of readdirSync(tmp)) {
  • 写入本地文件
    src/toolchain.js:238
    try { renameSync(join(tmp, e), join(targetDir, e)); } catch { }
  • 删除本地文件递归
    src/toolchain.js:240
    try { rmSync(tmp, { recursive: true, force: true }); } catch { }
  • 写入本地文件
    src/toolchain.js:242
    mkdirSync(targetDir, { recursive: true });
  • 读取本地文件
    src/toolchain.js:244
    if (existsSync(join(cacheDir, a.name))) {
  • 读取本地文件
    src/toolchain.js:254
    try { top = readdirSync(targetDir).slice(0, 15); } catch { }
  • 读取本地文件
    src/net.js:121
    if (!existsSync(path)) return resolve('');
  • 读取本地文件
    src/net.js:123
    const s = createReadStream(path);
  • 写入本地文件
    src/net.js:153
    mkdirSync(dirname(dest), { recursive: true });
  • 读取本地文件
    src/net.js:162
    if (resume && existsSync(dest) && statSync(dest).size > 0) extra.unshift('-C', '-');
  • 读取本地文件
    src/net.js:162
    if (resume && existsSync(dest) && statSync(dest).size > 0) extra.unshift('-C', '-');
  • 读取本地文件
    src/net.js:169
    try { sizeBytes = existsSync(dest) ? statSync(dest).size : 0; } catch { }
  • 读取本地文件
    src/net.js:169
    try { sizeBytes = existsSync(dest) ? statSync(dest).size : 0; } catch { }
  • 删除本地文件
    src/net.js:182
    try { unlinkSync(dest); } catch { }
  • 删除本地文件
    src/net.js:191
    try { unlinkSync(dest); } catch { }
  • 写入本地文件
    src/net.js:211
    mkdirSync(destDir, { recursive: true });
  • 读取密钥环境变量
    src/net.js:245
    const token = process.env.GITHUB_TOKEN || process.env.GH_TOKEN || '';
  • 写入本地文件
    src/net.js:283
    mkdirSync(dirname(path), { recursive: true });
  • 写入本地文件
    src/net.js:284
    writeFileSync(path, JSON.stringify(all, null, 2), 'utf8');
  • 读取本地文件
    src/unpack.js:39
    try { return readdirSync(dir, { withFileTypes: true }); } catch { return []; }
  • 读取本地文件
    src/unpack.js:43
    try { return statSync(p).isDirectory(); } catch { return false; }
  • 读取本地文件
    src/unpack.js:81
    try { size += statSync(join(d, e.name)).size; } catch { }
  • 读取本地文件
    src/unpack.js:115
    const fileSize = statSync(exePath).size;
  • 读取本地文件
    src/unpack.js:158
    const total = statSync(exePath).size - offset;
  • 读取本地文件
    src/unpack.js:159
    const rs = createReadStream(exePath, { start: offset });
  • 写入本地文件
    src/unpack.js:160
    const ws = createWriteStream(destPath);
  • 写入本地文件
    src/unpack.js:459
    mkdirSync(join(outDir, '_embedded'), { recursive: true });
  • 读取本地文件
    src/sources/galgame.js:83
    try { return readdirSync(dir, { withFileTypes: true }); } catch { return []; }
  • 读取本地文件
    src/sources/galgame.js:121
    try { bytes += statSync(full).size; } catch { }
  • 读取本地文件
    src/sources/galgame.js:171
    if (!input || !existsSync(input)) return { ok: false, detail: `路径不存在: ${input}` };
  • 读取本地文件
    src/sources/galgame.js:173
    try { st = statSync(input); } catch { return { ok: false, detail: '无法读取路径' }; }
  • 读取本地文件
    src/sources/galgame.js:227
    try { return statSync(p).size >= 5 * 1024 * 1024; } catch { return false; }
  • 读取本地文件
    src/sources/galgame.js:307
    ...(vd && existsSync(vd) ? ['--voice-dir', vd] : []),
  • 读取本地文件
    src/sources/media.js:26
    try { return readdirSync(dir, { withFileTypes: true }); } catch { return []; }
  • 读取本地文件
    src/sources/media.js:54
    if (!input || !existsSync(input)) return { ok: false, detail: `路径不存在: ${input}` };
  • 读取本地文件
    src/sources/media.js:56
    try { st = statSync(input); } catch { return { ok: false, detail: '无法读取路径' }; }
扫描于 2026/11/1(0 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

依赖的 DSH / Cordis 模块
@deepseek-ai/cordis
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

DSH 本地语音数据集、DDSP Reflow 训练和翻唱流程的语音注册。Yoshino 演示检查点已在 Releases 中提供。

README

由 DeepSeek 最新模型翻译生成
dsh-train-pipeline 正式版 v0.5.0 · 同时支持 DSH rc.2 / rc.3。 兼容维护:同时支持 DSH 0.2.1-rc.2 / rc.3,保留旧版用法与设置。验证范围与复现见 DSH 兼容说明。 DeepSeek Harness(DSH)的本地音色训练插件,版本 0.5.0。19 个工具覆盖本机素材查找、指定 URL 下载、部分吉里吉里封包解包、角色盘点、数据集整理、质量检查、DDSP Reflow 预处理与训练,以及训练结果注册。 与 dsh-cover-pipeline 配套:训练插件把 model_N.pt 和 config.yaml 放入约定的音色库,翻唱插件重载后发现并使用该音色。 Git 源码树仅包含源码、合成测试生成器和文档,不包含 DDSP 工程、模型权重、游戏素材、语音、歌曲或参考音频。 芳乃模型下载:20000 步权重与配套配置 按用户要求单独提供为公开 Release 附件,使用方法与 SHA-256 见 模型说明。它不随 git clone 或 npm 包下载,插件代码的 MIT 许可不自动适用于权重。 安装 当前主要面向 Windows。需要 Node.js 18+、DSH 和可用的 DDSP-SVC 6.2 Reflow 工程及其 Python 环境。
展开完整文档(README 剩余 1 节)
dsh-train-pipeline

正式版 v0.5.0 · 同时支持 DSH rc.2 / rc.3。

兼容维护:同时支持 DSH 0.2.1-rc.2 / rc.3,保留旧版用法与设置。验证范围与复现见 DSH 兼容说明。

DeepSeek Harness(DSH)的本地音色训练插件,版本 0.5.0。19 个工具覆盖本机素材查找、指定 URL 下载、部分吉里吉里封包解包、角色盘点、数据集整理、质量检查、DDSP Reflow 预处理与训练,以及训练结果注册。

与 dsh-cover-pipeline 配套:训练插件把 model_N.pt 和 config.yaml 放入约定的音色库,翻唱插件重载后发现并使用该音色。

Git 源码树仅包含源码、合成测试生成器和文档,不包含 DDSP 工程、模型权重、游戏素材、语音、歌曲或参考音频。

芳乃模型下载:20000 步权重与配套配置 按用户要求单独提供为公开 Release 附件,使用方法与 SHA-256 见 模型说明。它不随 git clone 或 npm 包下载,插件代码的 MIT 许可不自动适用于权重。

安装

当前主要面向 Windows。需要 Node.js 18+、DSH 和可用的 DDSP-SVC 6.2 Reflow 工程及其 Python 环境。GPU 训练依赖该工程自己的 PyTorch/CUDA、预训练权重和配置;本插件不会安装 DDSP 或下载权重。

git clone https://github.com/InariNGT-Ofiicial/dsh-train-pipeline.git
cd dsh-train-pipeline
设置为自己的音频工程根目录,也可配置 train.local.json。
$env:DSH_COVER_ROOT = (Resolve-Path ../AudioWork).Path
node test/live.mjs train_doctor
dsh plugin --profile desktop add .

../AudioWork 仅为示例,应先准备自己的外部工程目录。安装后重载 DSH。环境布局、配置优先级和故障排查见 安装与配置;外部工具和权重清单见 材料说明。

使用流程

train_doctor → train_plan → train_hunt / train_fetch / train_unpack
→ train_scan → train_build → train_qc
→ train_preprocess → train_run → train_status / train_stop
→ train_infer → train_register → 翻唱插件重载

可以在 DSH 中描述目标角色与素材目录。调用方需要逐步检查工具返回的 ok、报告和产物。train_plan 提供流程规则;它不会自动强制所有前置质量门,也不意味着一次自然语言请求必然完成整条链。

train_preprocess 会更换 DDSP 工程的 data/train/audio 与 data/val/audio,先把原有音频目录移动到训练工作区的 backup/。请使用独立训练工程,避免与正在运行的任务共用数据目录。train_run 遇到已有 checkpoint 默认停止,显式 confirmOverwrite=true 才继续。

源与支持范围

| 输入 | 已实现行为 | 限制 |
| 按角色分目录的语音 | 按目录名盘点与整理;读取音频帧数计算时长 | 目录名仍需抽检;不能证明内容纯净或角色标注正确 |
| JSON / KAG3 .ks 剧本 | 启发式提取 speaker / voice 引用,报告匹配率 | 陌生格式可能漏抓;立绘名推测仅供参考 |
| 普通 XP3、部分内嵌 EXE 封包 | 调用外部 arc_unpacker,按实际落盘文件检查结果 | 不覆盖所有引擎、版本或加密方式 |
| SenrenCxCrypt 系列 | 已有静态解析/解密实现;需兼容的 GARbro Formats.dat | 本机体验版验证通过,不承诺其他游戏兼容 |
| 单角色音频目录 | 指定角色后整理 WAV 数据集 | 不自动区分 BGM 或多人对话 |
| 番剧 / 录屏 | 适配器接口已留 | 分离、VAD、声纹归属尚未实现 |

时长口径:语音目录通过 soundfile 读取 frames / samplerate,不再按压缩文件字节数估时。文件损坏或格式不支持时报告失败数量与未知时长,不把部分总和标成完整时长。剧本分支仍使用 4.2 秒/句 的粗估,并明确标注“未实测”;质量检查报告使用实际数据集时长。

工具一览

| 工具 | 用途 |
| train_sources / train_plan | 实现状态、流程与决策提示 |
| train_doctor / train_setup | 环境检查、配置建议、可选写入本机配置 |
| train_hunt | 搜索本机目录与 Steam 库,受深度和时间预算限制 |
| train_toolchain | 检查或从上游 GitHub release 安装解包工具;GUI 工具单独标识 |
| train_fetch | 下载给定 URL,记录 URL、SHA-256 与时间,不内置资源站搜索 |
| train_unpack / train_acquire | 解包、可选反编译;acquire 串接查找与角色盘点 |
| train_scan | 源识别、角色数量、语音数、时长及匹配报告 |
| train_build | 转码、单声道、重采样、只裁头 + 留尾、超长分段、尾音体检 |
| train_qc | 采样率、时长、削波、静音、粗重复检测、尾音体检;apply=true 才移动不合格文件 |
| train_preprocess | 备份旧音频,复制新数据,执行 draw.py / preprocess.py |
| train_run / train_status / train_stop | 后台训练、日志与 checkpoint 状态、停止进程 |
| train_infer | 选择已有 checkpoint 做短句推理,需人工试听 |
| train_register / train_overview | 注册模型与配置、检查工作区和音色库 |

注册布局、指定步数和翻唱调用示例见 接入翻唱插件。注册默认拒绝覆盖,缺少同一实验的 config.yaml 或空模型时失败。注册成功只证明文件可发现,不证明模型音质。

数据集留尾(为什么默认不裁句尾)

train_build 默认只裁句首静音:句尾的自然衰减原样保留,末尾再兜 0.16s 静音底。这不是口味问题,是有实测的(同一批 383 条语料,GPT-SoVITS 线上做的对照):

| 口径 | 旧的「双向裁」 | 留尾(当前默认) |
| 尾部静音中位 | 0ms | 160ms |
| 收尾电平(最后有声前 40ms,相对句内 90 分位) | −9.5dB | −24dB |
| 停在满电平(> −12dB)的样本 | 64% | 4% |
| 对应模型末三字完整念出率 | 33% | 93% |
| 对应音素错误率 | 0.197 | 0.018 |

旧的 trim_silence 是双向的:切到「最后一个有声帧 + 50ms」,等价于让每条数据都停在接近满电平。模型会把这学成「句子该在满电平处直接断」,推理时表现为吞末字、尾音没有衰减。

判据是 tail_stats(出料与 QC 都会打):

- median_end_db 收尾电平中位 —— 真人自然收尾约 −24dB;
- median_tail_ms 尾部静音中位 —— 太小说明尾巴被剃光;
- cut_ratio 收尾 > −12dB 的占比 —— 超过 0.3 判「句尾被切断」。

train_build trimTail=true 可复现旧数据集(用于和历史模型对齐),会同时打警告:这是已知缺陷,不要用在生产集上。QC 只统计比例、不逐条判废——短促句(「あっ!」)本来就会停在较高电平,逐条判死会误杀。

补静音底救不了源本身切尾。 cut_ratio 高说明源 wav 已经停在满电平,再补零没有用:必须从原始封包(ogg/opus)重建,而且不要拿已经切过的 wav 再切一次(二次切分会再丢 0.3s 左右)。

测试与验证

python -m pip install -r requirements-test.txt
可选:指定用于合成测试的 Python 解释器。
$env:DSH_TRAIN_PYTHON = (Get-Command python).Source
npm test

CPU 套件不需要 GPU、真实模型、网络或游戏素材;覆盖工具契约、路径、启动失败、KAG3/JSON 解析、合成数据集与 QC、OGG 精确时长、注册与包内容。GitHub Actions 在 Windows/Linux 运行该套件。真实 GPU 训练和下载测试需要独立环境,详见 验证范围。

本机演示曾验证《千恋*万花》体验版解包、角色目录整理、读取已有 20000 步检查点、注册和原翻唱插件调用。该演示没有重新训练模型,也不作为本仓库在其他机器上完整训练成功的保证。只发布计数与验证口径,不发布其原始素材、音频或权重。

许可

插件代码采用 MIT。py/cxdec.py 的上游算法来源及许可保留在 第三方说明。外部工具按各自许可使用;代码许可不授予游戏素材、音色、表演、训练数据或模型的使用与再分发权。
预览分享卡片长什么样 ↓InariNGT-Ofiicial/dsh-train-pipeline
分享 · DeepSeek Harness Hub
InariNGT-Ofiicial/dsh-train-pipeline

正式版 v0.5.0 · 同时支持 DSH rc.2 / rc.3。

回到顶部