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

语音工坊 keduoli-lovely/dsh-plugin-voice-studio

DeepSeek Harness
keduoli-lovely4 天前有提交已提供中文文档扫描:含敏感能力

合成语音、翻唱歌曲并发送到 QQ 的语音工具

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

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

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add keduoli-lovely/dsh-plugin-voice-studio
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:仅索引
是什么
dsh 原生插件 · platform
装得上吗
本站尚未做安装检查
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 4 天前
档位由哪些信号合成

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

验证判据与等级说明 →
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

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

可执行外部命令读写/删除本地文件发起外部网络请求
查看扫描证据(共 58 处,展示前 55 条)
  • 写入本地文件
    index.js:33
    appendFileSync(join(new Store().dir, 'boot.log'), `${new Date().toISOString()} ${message}\n`)
  • 发起网络请求
    index.js:295
    const response = await fetch(target, { signal: AbortSignal.timeout(5000) })
  • 读取本地文件
    index.js:490
    if (!existsSync(wanted)) throw Object.assign(new Error('file not found'), { status: 404 })
  • 发起网络请求
    client.js:254
    var response = await fetch(path, Object.assign({ cache: 'no-store' }, options, {
  • 读取本地文件
    lib/cover.js:32
    if (!existsSync(wanted)) {
  • 读取本地文件
    lib/cover.js:71
    entries = readdirSync(dir, { withFileTypes: true })
  • 读取本地文件
    lib/cover.js:85
    return { vocal: readFileSync(vocal), instrumental: readFileSync(instrumental), engine: 'MSST_WebUI' }
  • 读取本地文件
    lib/cover.js:100
    const result = await rvcSeparate(store, { song: readFileSync(songPath) })
  • 读取本地文件
    lib/cover.js:151
    await writeFile(outWav, readFileSync(mastered))
  • 写入本地文件
    lib/cover.js:151
    await writeFile(outWav, readFileSync(mastered))
  • 写入本地文件
    lib/cover.js:254
    await writeFile(outWav, encodeWav24(mixed.sampleRate, mixed.channels, mixed.samples))
  • 发起网络请求
    lib/rvc.js:76
    const response = await fetch(`${base}/run/${name}`, {
  • 发起网络请求
    lib/rvc.js:154
    const response = await fetch(url, { signal: AbortSignal.timeout(10 * 60 * 1000) })
  • 发起网络请求
    lib/rvc.js:207
    const response = await fetch(`${base}/convert`, {
  • 发起网络请求
    lib/rvc.js:224
    const response = await fetch(`${base}/separate`, {
  • 发起网络请求
    lib/emotion.js:174
    const response = await fetch(`${String(origin).replace(/ $/, '')}/emotion/api/state`, {
  • 读取本地文件
    lib/qq.js:37
    return { root, file, config: JSON.parse(readFileSync(file, 'utf8')) }
  • 写入本地文件
    lib/qq.js:85
    writeFileSync(found.file, JSON.stringify(found.config, null, 2), 'utf8')
  • 写入本地文件
    lib/qq.js:101
    writeFileSync(found.file, JSON.stringify(cfg, null, 2), 'utf8')
  • 读取本地文件
    lib/qq.js:109
    const stat = statSync(file)
  • 写入本地文件
    lib/qq.js:114
    mkdirSync(targetDir, { recursive: true })
  • 写入本地文件
    lib/qq.js:118
    copyFileSync(file, join(targetDir, name))
  • 读取本地文件
    lib/qq.js:127
    if (!file || !existsSync(file)) return { sent: false, reason: `没有可发送的文件:${file || '(空)'}` }
  • 读取本地文件
    lib/store.js:350
    const info = statSync(sourcePath)
  • 读取本地文件
    lib/store.js:352
    bytes = await readFile(sourcePath)
  • 写入本地文件
    lib/store.js:374
    await writeFile(target, bytes)
  • 写入本地文件
    lib/store.js:396
    await writeFile(target, bytes)
  • 读取本地文件
    lib/store.js:420
    for (const entry of readdirSync(current, { withFileTypes: true })) {
  • 写入本地文件
    lib/store.js:459
    await writeFile(join(this.dir, 'deleted.log'), `${new Date().toISOString()} ${voice.file}\n`, { flag: 'a' }).catch(() => {})
  • 读取本地文件
    lib/tts.js:44
    const bytes = await readFile(filePath)
  • 发起网络请求
    lib/tts.js:58
    const response = await fetch(url, {
  • 发起网络请求
    lib/tts.js:88
    const start = await fetch(prefix, {
  • 发起网络请求
    lib/tts.js:106
    const stream = await fetch(`${prefix}/${eventId}`, { signal: controller.signal })
  • 读取本地文件
    lib/tts.js:156
    if (serverPath && existsSync(serverPath)) {
  • 读取本地文件
    lib/tts.js:157
    await writeFile(destFile, await readFile(serverPath))
  • 写入本地文件
    lib/tts.js:157
    await writeFile(destFile, await readFile(serverPath))
  • 写入本地文件
    lib/tts.js:162
    await writeFile(destFile, bytes)
  • 写入本地文件
    lib/tts.js:243
    await writeFile(outFile, bytes)
  • 写入本地文件
    lib/tts.js:269
    await writeFile(outFile, bytes)
  • 写入本地文件
    lib/tts.js:313
    await writeFile(outFile, bytes)
  • 写入本地文件
    lib/tts.js:315
    await writeFile(outFile, Buffer.from(audio, 'hex'))
  • 读取本地文件
    lib/tts.js:432
    const bytes = existsSync(outFile) ? (await import('node:fs')).statSync(outFile).size : 0
  • 写入本地文件
    lib/util.js:38
    mkdirSync(dir, { recursive: true })
  • 读取本地文件
    lib/util.js:104
    const raw = await readFile(file, 'utf8')
  • 写入本地文件
    lib/util.js:124
    renameSync(tmp, file)
  • 读取本地文件
    lib/util.js:132
    return statSync(file).size
  • 读取本地文件
    lib/util.js:142
    stat = statSync(filePath)
  • 读取本地文件
    lib/util.js:175
    createReadStream(filePath, { start, end }).pipe(res)
  • 读取本地文件
    lib/util.js:183
    createReadStream(filePath).pipe(res)
  • 执行外部命令来自配置/变量
    lib/util.js:192
    child = spawn(cmd, args, {
  • 发起网络请求
    lib/util.js:258
    const response = await fetch(url, { ...rest, signal: controller.signal })
  • 发起网络请求
    lib/util.js:284
    const response = await fetch(url, { ...rest, signal: controller.signal })
  • 发起网络请求
    lib/util.js:304
    const response = await fetch(url, { signal: controller.signal })
  • 删除本地文件
    lib/util.js:316
    await unlink(file)
  • 执行外部命令来自配置/变量
    lib/wav.js:176
    child = spawn(String(bin || 'ffmpeg'), args, { windowsHide: true, stdio: 'ignore' })
扫描于 2026/11/2(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库

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

给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

语音工坊 · DeepSeek Harness 插件:多提供商语音合成 + 参考音色库 + RVC 歌曲翻唱 + 情绪控制 + qq-bridge 语音发送(含随机语音回复)

README

由 DeepSeek 最新模型翻译生成
语音工坊 · dsh-plugin-voice-studio DeepSeek Harness 插件,把「说话、唱歌、换音色、发到 QQ」做成一件事。 - 语音合成:本地 IndexTTS / GPT-SoVITS,在线硅基流动 / MiniMax / 小米 MiMo / OpenAI 兼容 - 参考音色库:上传、路径导入、整目录导入;文件复制进插件目录,同名可替换或另存 - 歌曲翻唱:找歌 → 人声分离 → RVC 换声 → 混音母带,全自动 - 情绪控制:接入 DSH 情绪插件,没有也能用内置词典 - QQ 发送:生成后交给 qq-bridge 的 qq_send_voice 发出,不接管 QQ 连接 - 随机语音:偶尔用语音代替文字回复(唱歌不走随机) 设置页在 设置 → 语音工坊;智能体通过 voice_generate / song_cover / voice_studio_info / voice_random_check 四个工具使用同一套配置。
展开完整文档(README 剩余 1 节)
语音工坊 · dsh-plugin-voice-studio

DeepSeek Harness 插件,把「说话、唱歌、换音色、发到 QQ」做成一件事。

- 语音合成:本地 IndexTTS / GPT-SoVITS,在线硅基流动 / MiniMax / 小米 MiMo / OpenAI 兼容
- 参考音色库:上传、路径导入、整目录导入;文件复制进插件目录,同名可替换或另存
- 歌曲翻唱:找歌 → 人声分离 → RVC 换声 → 混音母带,全自动
- 情绪控制:接入 DSH 情绪插件,没有也能用内置词典
- QQ 发送:生成后交给 qq-bridge 的 qq_send_voice 发出,不接管 QQ 连接
- 随机语音:偶尔用语音代替文字回复(唱歌不走随机)

设置页在 设置 → 语音工坊;智能体通过 voice_generate / song_cover / voice_studio_info / voice_random_check 四个工具使用同一套配置。

目录

- 功能特性
- 环境要求
- 安装
- 快速开始
- 语音合成
- 参考音色库
- 情绪系统
- 歌曲翻唱
- QQ 发送:交给 qq-bridge
- 随机语音回复
- 状态页
- Agent 工具参考
- HTTP API
- 数据目录
- 开发
- 故障排查
- 已知限制
- 许可证

功能特性

| 能力 | 说明 |
| 多服务商 TTS | 6 个内置适配器,配置统一为 baseUrl / apiKey / model / voice(本地服务商用 refAudioId) |
| 参考音色库 | 音频复制到 ~/.dsh-voice-studio/refs/,不引用原路径;同名导入返回 409 VOICE_CONFLICT,页面选择替换或另存 |
| 情绪 | 显式参数 → DSH 情绪插件(Service / get_mood 工具 / POST /emotion/api/state)→ 内置词典;按引擎映射 |
| 歌曲翻唱 | RVC 全程走 HTTP(模型列表/转换/分离),RVC 可与 DSH 分开部署;混音在本地用纯 Node 完成,按原人声 RMS 对齐并可选 loudnorm |
| QQ 发送 | 渲染 → 复制进 qq-bridge 语音库 → 调用其 qq_send_voice;缺 key/token 时给出可执行的下一步 |
| 随机语音 | 宿主端概率 + 冷却 + 每小时上限,命中才计数;唱歌永不随机 |
| 可观测 | 状态页显示 DSH 地址/端口、qq-bridge 配置的 DSH 地址是否一致,并按「当前选择」探测服务 |
| 零第三方依赖 | 插件只用 Node 内置模块;RVC 侧跑一个自带的 server/rvc-api.py(FastAPI),混音不再需要本地 Python |

环境要求

- DeepSeek Harness ≥ 0.1.7(桌面版或 web profile;插件通过 settings.section 出现在设置里)
- Node.js ≥ 18(宿主自带即可,插件无需额外安装依赖)
- 可选的本机服务(按需启用,缺哪个就少哪项能力,不会导致插件加载失败):

| 服务 | 用途 | 默认地址 | 备注 |
| IndexTTS 2.x WebUI | 本地语音合成(情绪向量) | http://127.0.0.1:7860 | Gradio,调用 gen_single |
| GPT-SoVITS api_v2.py | 本地语音合成 | http://127.0.0.1:9880 | 9874 是 WebUI,没有 TTS API |
| MSST_WebUI | 人声/伴奏分离(可选) | 留空 | 不填则用分离服务 server/rvc-api.py |
| RVC WebUI | 歌曲换声(模型/索引/推理) | http://<IP>:7897 | 直接调用它的 Gradio /run/ 接口,无需附加服务 |
| RVC API(可选) | 仅用于人声分离 | http://<IP>:7866 | 需要自动分离时启动 server/rvc-api.py |
| qq-bridge | QQ 收发与语音发送 | 仓库目录 + 内置 3100 控制台 | 见 QQ 发送 |

安装

方式一:从 GitHub 安装

dsh plugin --profile web add github:keduoli-lovely/dsh-plugin-voice-studio

方式二:本地目录安装

dsh plugin --profile web add /path/to/dsh-plugin-voice-studio

安装后刷新设置页即可看到「语音工坊」。

快速开始

1. 配置一个语音服务商:设置 → 语音工坊 → 语音合成,选择服务商并填写地址(本地填 baseUrl,在线填 apiKey)。
2. 导入参考音色:语音合成页选「参考音色」,或到「参考音色」页上传/导入一个 3~15 秒的干净人声。
3. 试听:语音合成页底部输入文字,点「生成」,确认能出声、音色正确。
4. (可选)翻唱:在 RVC 机器上启动 server/rvc-api.py,歌曲翻唱页填它的地址,点「重新扫描模型」;输入本机绝对路径开始翻唱。
5. (可选)QQ:QQ 发送页启用并确认 qq-bridge 路径;点「把当前 DSH 地址写入 qq-bridge」,重启 qq-bridge。

语音合成

| 提供商 id | 类型 | 端点 | 认证 | 情绪 |
| indextts | 本地 | POST {base}/gradio_api/call/gen_single | 无 | 8 维情绪向量 |
| gptsovits | 本地 | GET/POST {base}/tts | 无 | 无(靠参考音频) |
| siliconflow | 在线 | POST {base}/audio/speech → 二进制 | Authorization: Bearer | 指令前缀 <指令> <\|endofprompt\|> 正文 |
| minimax | 在线 | POST {base}/t2a_v2 → JSON | Authorization: Bearer | voice_setting.emotion(9 值枚举) |
| mimo | 在线 | POST {base}/chat/completions + audio | api-key 或 Bearer | user 消息风格指令 |
| openai | 在线 | POST {base}/audio/speech → 二进制 | Authorization: Bearer | instructions |

提供商配置示例(~/.dsh-voice-studio/config.json):

{
"tts": {
"provider": "indextts",
"providers": {
"indextts": { "baseUrl": "http://127.0.0.1:7860", "refAudioId": "v_xxx", "lang": "ZH", "emoWeight": 0.8 },
"gptsovits": { "baseUrl": "http://127.0.0.1:9880", "refAudioId": "v_xxx", "promptText": "参考音频对应的文本" },
"siliconflow": { "baseUrl": "https://api.siliconflow.cn/v1", "apiKey": "sk-...", "model": "FunAudioLLM/CosyVoice2-0.5B", "voice": "FunAudioLLM/CosyVoice2-0.5B:alex" },
"minimax": { "baseUrl": "https://api.minimax.cn/v1", "apiKey": "eyJ...", "model": "speech-2.8-hd", "voice": "female-shaonv" },
"mimo": { "baseUrl": "https://api.xiaomimimo.com/v1", "apiKey": "...", "model": "mimo-v2.5-tts", "voice": "冰糖" },
"openai": { "baseUrl": "https://api.openai.com/v1", "apiKey": "sk-...", "model": "gpt-4o-mini-tts", "voice": "alloy" }
}
}
}

要点

- 本地提供商必须先有参考音色;未配置默认音色时自动使用库里第一个可用音色。
- GPT-SoVITS 需要先运行 api_v2.py;其 WebUI(9874)只提供 UI,没有 TTS API。
- MiniMax 返回的是 hex 编码音频,插件会自动解码;同时校验 base_resp.status_code。
- MiMo 是 Chat Completions 形态(不是 /v1/audio/speech),插件按协议分支处理。

参考音色库

- 上传(浏览器文件选择)、从路径导入、批量导入目录(递归,最多 200 个)。
- 文件复制到 ~/.dsh-voice-studio/refs/,不引用原路径,原文件可随时搬走。
- 同名导入返回 409 { code: "VOICE_CONFLICT", existing },页面弹窗选择 替换 或 另存为新音色(自动加序号),目录不会无限膨胀。
- 列表每行:播放按钮 + 时长(不加载原生音频控件),行内「重命名」(Enter 保存 / Esc 取消)、两步删除。
- 删除音色会清空引用它的提供商默认值。

情绪系统

来源链(缺插件也绝不失败):

1. 调用方显式传 emotion / intensity(工具参数或设置页);
2. 已安装的 DSH 情绪插件:
- Host Service:ctx.get('emotion' | 'emotions' | 'sentiment' | 'affect') 上的 classify / detect 等;
- 工具:get_mood(dsh-emotion 提供);
- HTTP:POST {DSH}/emotion/api/state;
3. 内置词典(开心/生气/悲伤/害怕/厌恶/低落/惊喜/平静)。

映射到各引擎:

| 维度 | IndexTTS 向量 | MiniMax enum | CosyVoice / MiMo / OpenAI |
| 开心 | 喜 | happy | 风格指令 |
| 生气 | 怒 | angry | 风格指令 |
| 悲伤 | 哀 | sad | 风格指令 |
| 害怕 | 惧 | fearful | 风格指令 |
| 厌恶 | 厌恶 | disgusted | 风格指令 |
| 低落 | 低落 | sad | 风格指令 |
| 惊喜 | 惊喜 | surprised | 风格指令 |
| 平静 | 平静 | calm | 风格指令 |
GPT-SoVITS 和 RVC 没有情绪参数,结果里会如实标注「该服务商无情绪参数」。

歌曲翻唱

流程:给歌(本机路径)→ 分离 → RVC 换声(HTTP)→ 混音母带(本地)。

1. 给歌:song 只接受本机绝对路径(如 D:\music\song.wav)。音乐目录匹配、链接下载、yt-dlp 已移除。
2. 分离:配置了 msstUrl 就先试 MSST_WebUI;否则用「分离服务地址」(server/rvc-api.py 的 /separate)。
3. 换声:插件直接调用 RVC WebUI 的 Gradio 接口,不需要额外进程:
- 模型列表:POST /run/infer_refresh → data[0].choices
- 索引:POST /run/infer_change_voice(顺带加载模型,返回自动匹配的索引路径)
- 转换:POST /run/infer_convert(音频以 base64 传入,结果以 /file=<路径> 下载)
4. 混音:本地纯 Node(lib/wav.js)按分离人声的 RMS 对齐后与伴奏相加、峰值 −1 dB;如果本机有 ffmpeg,再做 loudnorm(默认 I=-11.5:TP=-1.0:LRA=11)并输出 320 kbps MP3,没有就只出 WAV。

RVC 地址会自动识别:同一条 URL 既可以是 WebUI,也可以是 server/rvc-api.py。

为什么分离还需要一个小服务?

RVC WebUI 的「分离」按钮对应的是 Gradio 的流式生成器(pymss_separate),而这一版 WebUI 关闭了 Gradio 队列路由(/queue/join 返回 404),HTTP 调用只会拿到第一帧「正在加载模型」就结束,无法等待它跑完。
换声/取模型这类一次性接口不受影响,所以插件的做法是:

| 环节 | 走哪里 | 是否需要附加服务 |
| 模型列表 / 索引 / 换声 | RVC WebUI 的 /run/ | 不需要 |
| 人声分离(PyMSS) | MSST_WebUI,或 server/rvc-api.py 的 /separate | 需要其中一个 |

如果只想用一个地址、不跑任何附加服务:装 MSST_WebUI 并把地址填到 msstUrl 即可(插件优先用 MSST 分离)。

可选的分离服务(server/rvc-api.py)

在 RVC 根目录运行(默认 7866,绑定 0.0.0.0)
cd D:\path\to\RVC
<插件目录>\server\start-rvc-api.bat 7866

或直接命令 runtime\python.exe <插件目录>\server\rvc-api.py --host 0.0.0.0 --port 7866 --rvc-root D:\path\to\RVC

浏览器打开 http://<RVC机器IP>:7866/ 应看到 {"service":"dsh-voice-studio RVC API", ...}。

| 端点 | 用途 |
| GET / | 服务自述(确认不是 WebUI) |
| GET /health | 存活与模型数量 |
| GET /models | 模型/索引清单 |
| POST /convert | multipart:file + model/index/f0_method/f0_up_key/index_rate/rms_mix/protect → WAV |
| POST /separate | multipart:file → { vocal, instrumental }(base64 WAV,PyMSS) |

脚本会自动把 TEMP/TMP/NUMBA_CACHE_DIR 指到自己的临时目录(RVC 整合包的 TEMP\ 常常不可写)。

参数(设置页 → 歌曲翻唱)

| 字段 | 默认 | 说明 |
| rvcUrl | 空 | RVC WebUI 或 RVC API 地址,自动识别,例如 http://192.168.1.10:7897 |
| separateUrl | 空 | 可选:仅分离用的 RVC API 地址(server/rvc-api.py) |
| msstUrl | 空 | 可选:MSST_WebUI 地址,优先用于分离 |
| model | 第一个模型 | 模型 id(WebUI 模式下即 xxx.pth) |
| index | 自动匹配 | 索引路径;WebUI 模式下留空会用 infer_change_voice 的结果 |
| f0Method | rmvpe | rmvpe / fcpe / pm |
| f0UpKey | 0 | 升降调(半音) |
| indexRate | 0.75 | 索引混合比例 |
| rmsMix | 0.25 | 音量包络混合 |
| protect | 0.33 | 辅音保护 |
| ffmpegPath | 空 | 本机 ffmpeg 路径;留空用 PATH,缺失时只输出 WAV |
| loudness | I=-11.5:TP=-1.0:LRA=11 | loudnorm 参数 |

QQ 发送:交给 qq-bridge

本插件不接管 QQ 连接。部署形态是:

QQ ⟶ SnowLuma(OneBot v11 WS)⟶ qq-bridge ⟶ DSH Web API(agent 对话) ⟵ 本插件:生成音频 → 放入语音库 → 调用 qq_send_voice

1. 生成音频;
2. 复制进 <qq-bridge>/audio/voice-studio/(自动读取 bridge 的 socialV2.voice.dir 与体积上限);
3. 用调用方传入的 qq_key / qq_token 调用 mcp__snowluma__qq_send_voice 完成发送。

必须满足的三件事(设置页 QQ 页签均可检查):

| 项 | 位置 | 说明 |
| bridge 语音开关 | config.json → socialV2.voice.enabled 与 socialV2.tools.sendVoice | 设置页有「打开 bridge 语音开关」按钮;改完重启 qq-bridge |
| QQ 会话工具白名单 | plugins/qq-agent-presets/qq-tool-restrict.mjs 的 SAFE_EXACT | 需包含 voice_generate / song_cover / voice_studio_info / voice_random_check,否则 QQ 会话里这些工具会被 guard 拒绝 |
| DSH 地址 | config.json → dsh.baseUrl | DSH 桌面版每次启动换端口;状态页显示当前端口与是否一致,可一键写入 |

语音库为空是正常状态:voice_generate 会现场生成并入库,不要先调用 qq_list_voices 判断能不能发。

随机语音回复

- 设置 → 语音工坊 → QQ → 「随机语音回复」:开关、概率(默认 0.12)、冷却秒数(600)、每小时上限(6)。
- 模型在 QQ 会话每次回复前调用 voice_random_check:命中且回复适合朗读(短、无代码/列表/链接)时,改用 voice_generate 发语音代替文字。
- 冷却与每小时上限在宿主端持久化,命中才计数;唱歌不走随机。

状态页

- 只探测当前选择:TTS 只测选中的提供商;翻唱测 RVC 地址(自动区分 WebUI / RVC API);MSST 填了才测;QQ 启用才测 qq-bridge。
- 服务签名校验:/config 必须包含 gen_single(IndexTTS)或 run_inference_single(MSST),避免两个服务共用 7860 时误报 OK。
- DSH 端口:显示 http://127.0.0.1:<port>、qq-bridge 配置的 dsh.baseUrl 与一致性;不一致时可一键同步(写 dsh.baseUrl,重启 qq-bridge 生效)。
- 完整清单:POST /tts-studio/api/probe?all=1。

智能体工具参考

voice_generate

| 参数 | 类型 | 必填 | 说明 |
| text | string | ✅ | 要朗读的文本 |
| voice | string | | 参考音色 id 或名称 |
| provider | string | | 提供商 id |
| emotion | string | | 情绪标签 |
| intensity | number | | 情绪强度 0–1 |
| speed | number | | 语速倍数 |
| lang | string | | 本地提供商语言码 |
| send_to_qq | boolean | | 生成后交给 qq-bridge 发送 |
| qq_key / qq_token | string | | QQ 会话凭据(来自唤醒提示) |

song_cover

song(标题/路径/链接,必填)、model、index、key_shift、send_to_qq、qq_key、qq_token。
同步执行整条流水线,返回混音后的 MP3/WAV 路径。

voice_studio_info

action:providers | voices | models | probe | settings。

voice_random_check

无参数,返回 { voice: boolean, reason }。

HTTP API

| 方法 | 路径 | 说明 |
| GET | /tts-studio/api/state | 设置、音色库、RVC 模型、bridge 状态、DSH 地址 |
| PUT/POST | /tts-studio/api/settings | 保存设置(深合并,不会重置未提及的段) |
| GET/POST | /tts-studio/api/voices | 列表 / 上传 / 导入目录 / 删除 / 重命名 |
| GET | /tts-studio/api/voice-audio?id= | 试听参考音色(支持 Range) |
| GET | /tts-studio/api/audio?path= | 播放生成结果(限定数据目录内) |
| POST | /tts-studio/api/tts | 生成语音(可带 sendToQQ / qqKey / qqToken) |
| POST | /tts-studio/api/cover | 启动翻唱任务 |
| GET | /tts-studio/api/jobs?id= | 查询翻唱进度 |
| POST | /tts-studio/api/probe?all=1 | 探测服务(默认只测当前选择) |
| GET/POST | /tts-studio/api/qq | QQ 状态 / 发送测试 |
| POST | /tts-studio/api/qq/bridge-enable | 打开 qq-bridge 两个语音开关 |
| POST | /tts-studio/api/qq/sync-dsh-url | 把当前 DSH 地址写入 qq-bridge |
| GET | /tts-studio/api/models | 从 RVC WebUI(或 RVC API)拉取模型/索引清单 |

数据目录

~/.dsh-voice-studio/
config.json 设置(原子写 + 串行化) refs/ 参考音色副本 out/ 生成的语音与翻唱成品 tmp/ 每次任务的分离开临时文件 boot.log 插件激活/注册/提示词诊断

可用 DSH_VOICE_STUDIO_DATA 覆盖整个数据目录。

开发

index.js Host 插件:路由、工具、系统提示词 client.js Client 插件:设置页(settings.section) lib/store.js 配置 + 参考音色库 lib/tts.js 6 个提供商适配器 + Gradio 客户端 lib/cover.js 翻唱流水线编排(找歌/分离/换声/混音) lib/rvc.js RVC 客户端(WebUI Gradio + RVC API 双后端) lib/wav.js WAV 编解码 + 重采样 + 混音(纯 Node) lib/qq.js qq-bridge 交付 + OneBot/shell 兜底 lib/emotion.js 情绪来源链 + 引擎映射 server/rvc-api.py RVC 侧 HTTP 服务(FastAPI)

本地验证:

node --check index.js client.js lib/*.js
python -m py_compile server/rvc-api.py
npm pack # 产出安装包

故障排查

| 现象 | 原因 | 处理 |
| 插件已装但没出现在设置里 | 客户端 bundle 需页面加载 | 刷新设置页 / 重启 DSH |
| cannot get property "webServer" without inject | 插件未声明依赖 | 本仓库已修复(apply.inject),旧版本请升级 |
| 本地 TTS 报 fetch failed | 服务没开或地址错 | 启动 IndexTTS / GPT-SoVITS api_v2.py,检查端口 |
| 旧版 plugin_manager 保存设置后音色库清空 | patch 合并重置了数组 | 本仓库已修复(深合并) |
| 翻唱只出 WAV 没有 MP3 | 本机 ffmpeg 不在 PATH | 在设置页填 ffmpegPath,或把 ffmpeg 加入 PATH |
| 翻唱报「无法等待分离完成」 | RVC WebUI 的分离是流式生成器 | 配置 msstUrl(MSST_WebUI)或 separateUrl(server/rvc-api.py) |
| QQ 里说「语音库是空的」 | 模型先查了 qq_list_voices | 已在系统提示词中要求直接调用 voice_generate |
| qq_send_voice 不存在 | bridge 语音开关关闭 / 未重启 | 设置页打开开关并重启 qq-bridge |
| bridge 日志「事件流 0 帧」 | dsh.baseUrl 是上一次的端口 | 状态页一键同步 + 重启 qq-bridge |

已知限制

- 语音/视频接收仍为占位文本(桥接侧限制),本插件只负责「发出」。
- IndexTTS 与 MSST 默认都想用 7860,必须错开端口。
- RVC WebUI 的分离接口是流式生成器(Gradio 队列被关闭),插件无法程序化等待;自动分离需要 MSST 或 server/rvc-api.py。
- 跨机器访问时 WebUI 需以 --listen 打开,并放行对应端口。
- qq-bridge 的 preset 白名单是对方项目文件,升级/重跑 setup-dsh.mjs 后可能需要重新加入四个工具名。

许可证

MIT © 2026 keduoli-lovely
预览分享卡片长什么样 ↓keduoli-lovely/dsh-plugin-voice-studio
分享 · DeepSeek Harness Hub
keduoli-lovely/dsh-plugin-voice-studio

合成语音、翻唱歌曲并发送到 QQ 的语音工具

这是你的仓库?认领条目

回到顶部