语音工坊 · dsh-plugin-voice-studio
把「说话、唱歌、换音色、发到 QQ」做成一件事的 DeepSeek Harness 插件。
- 语音合成:本地 IndexTTS / GPT-SoVITS,在线硅基流动 / MiniMax / 小米 MiMo / OpenAI 兼容
- 参考音色库:上传、路径导入、整目录导入;文件复制进插件目录,同名可替换或另存
- 歌曲翻唱:找歌 → 人声分离 → RVC 换声 → 混音母带,全自动
- 情绪控制:接入 DSH 情绪插件,没有也能用内置词典
- QQ 发送:生成后交给
qq-bridge的qq_send_voice发出,不接管 QQ 连接 - 随机语音:偶尔用语音代替文字回复(唱歌不走随机)
设置页在 设置 → 语音工坊;Agent 通过
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 Worker | 模型/换声/分离/进程控制 | http://<IP>:7870 |
独立 Python 服务,跑在 RVC/MSST 机器上,慢任务不卡 DSH |
| RVC WebUI(直连回退) | 歌曲换声 | http://<IP>:7897 |
没有 worker 时直接调它的 Gradio /run/* 接口 |
| RVC API(旧,可选) | 仅用于人声分离 | http://<IP>:7866 |
兼容保留;新部署请用 rvc-worker |
| 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
快速开始
- 配置一个语音提供商:设置 → 语音工坊 → 语音合成,选择提供商并填写地址(本地填
baseUrl,在线填apiKey)。 - 导入参考音色:语音合成页选「参考音色」,或到「参考音色」页上传/导入一个 3~15 秒的干净人声。
- 试听:语音合成页底部输入文字,点「生成」,确认能出声、音色正确。
- (可选)翻唱:在 RVC 机器上启动
server/rvc-api.py,歌曲翻唱页填它的地址,点「重新扫描模型」;输入本机绝对路径开始翻唱。 - (可选)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 取消)、两步删除。
- 删除音色会清空引用它的提供商默认值。
情绪系统
- 调用方显式传
emotion/intensity(工具参数或设置页); - 已安装的 DSH 情绪插件:
- Host Service:
ctx.get('emotion' | 'emotions' | 'sentiment' | 'affect')上的classify/detect等; - 工具:
get_mood(dsh-emotion提供); - HTTP:
POST {DSH}/emotion/api/state;
- Host Service:
- 内置词典(开心/生气/悲伤/害怕/厌恶/低落/惊喜/平静)。
映射到各引擎:
| 维度 | IndexTTS 向量 | MiniMax enum | CosyVoice / MiMo / OpenAI |
|---|---|---|---|
| 开心 | 喜 | happy |
风格指令 |
| 生气 | 怒 | angry |
风格指令 |
| 悲伤 | 哀 | sad |
风格指令 |
| 害怕 | 惧 | fearful |
风格指令 |
| 厌恶 | 厌恶 | disgusted |
风格指令 |
| 低落 | 低落 | sad |
风格指令 |
| 惊喜 | 惊喜 | surprised |
风格指令 |
| 平静 | 平静 | calm |
风格指令 |
GPT-SoVITS 与 RVC 没有情绪参数,结果里会如实标注「该提供商无情绪参数」。
歌曲翻唱
流程:给歌(本机路径)→ 分离 → RVC 换声(HTTP)→ 混音母带(本地)。
- 给歌:
song只接受本机绝对路径(如D:\music\song.wav)。 - 分离:优先
rvc-worker(/v1/separate,PyMSS/MSST);其次 MSST_WebUI;再其次直连 RVC。 - 换声:优先
rvc-worker(/v1/convert,模型热缓存);没有 worker 时直接调 RVC WebUI 的 Gradio 接口(infer_refresh/infer_change_voice/infer_convert)。 - 混音:本地纯 Node(
lib/wav.js)按分离人声的 RMS 对齐后与伴奏相加、峰值 −1 dB;如果本机有 ffmpeg, 再做 loudnorm(默认I=-11.5:TP=-1.0:LRA=11)并输出 320 kbps MP3,没有就只出 WAV。
rvc-worker(独立服务,跑在 RVC/MSST 机器上)
RVC WebUI 是 Gradio 应用,分离是流式生成器且队列路由被关闭,HTTP 无法等待完成;
rvc-worker 直接 import RVC 的 VC 类与 PyMSS,提供任务化 API(含 SSE 进度、进程控制),
彻底摆脱 Gradio 的交互限制,也能跨机器部署。
# RVC 机器上(默认 0.0.0.0:7870)
runtime\python.exe rvc-worker\worker.py --port 7870 --token CHANGE_ME \
--rvc-root D:\path\to\RVC --msst-root D:\path\to\MSST_WebUI
| 端点 | 用途 |
|---|---|
GET /v1/health |
RVC/MSST 可用性、GPU、任务与进程状态 |
GET /v1/models |
模型/索引清单 |
POST /v1/files / GET /v1/files/{id} |
上传/下载文件 |
POST /v1/convert |
干声换声 → WAV |
POST /v1/separate |
人声/伴奏分离(PyMSS) |
POST /v1/jobs、GET /v1/jobs/{id}、/events |
异步任务 + SSE 进度 |
| `POST /v1/process/{rvc-webui | msst}/{start |
GET /v1/logs |
子进程日志 |
完整契约见 rvc-worker 仓库的 API.md。插件设置页填 RVC Worker 地址 + Worker Token 即可,
填了以后模型列表、换声、分离全部走 worker;没有 worker 时自动回退到 WebUI 直连。
设置页还提供 「Worker 进程」面板:检查进程、启动/重启/停止 RVC WebUI 与 MSST_WebUI
(对应 worker 的 /v1/process/*,DSH 侧经 /tts-studio/api/worker/process 代理)。
回退:直连 RVC WebUI
rvcUrl 填 WebUI 地址(如 http://192.168.1.10:7897)也能换声:
- 模型列表:
POST /run/infer_refresh→data[0].choices - 索引:
POST /run/infer_change_voice - 转换:
POST /run/infer_convert(音频 base64 进,/file=<路径>下载)
但分离不行(见上),此时需要 msstUrl 或 separateUrl(兼容旧 server/rvc-api.py)。
参数(设置页 → 歌曲翻唱)
| 字段 | 默认 | 说明 |
|---|---|---|
workerUrl |
空 | rvc-worker 地址,例如 http://192.168.1.10:7870;配置后优先使用 |
workerToken |
空 | 与 worker 的 --token 一致 |
rvcUrl |
空 | 没有 worker 时的直连地址(WebUI 或旧 RVC API) |
separateUrl |
空 | 可选:仅分离用的旧 RVC API 地址 |
msstUrl |
空 | 可选:MSST_WebUI 地址 |
model |
第一个模型 | 模型 id |
index |
自动匹配 | 索引路径;留空自动匹配 |
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
- 生成音频;
- 复制进
<qq-bridge>/audio/voice-studio/(自动读取 bridge 的socialV2.voice.dir与体积上限); - 用调用方传入的
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 Worker / RVC 地址(自动区分 WebUI / API);MSST 填了才测;QQ 启用才测 qq-bridge。
- 打开即渲染:模型清单走本地缓存(
~/.dsh-voice-studio/rvc-cache.json),刷新在后台进行,RVC 离线也不会卡住设置页。 - 服务签名校验:
/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。
Agent 工具参考
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 的分离是流式生成器 | 用 rvc-worker(推荐),或配置 msstUrl / separateUrl |
| QQ 里说「语音库是空的」 | 模型先查了 qq_list_voices |
已在系统提示词中要求直接调用 voice_generate |
qq_send_voice 不存在 |
bridge 语音开关关闭 / 未重启 | 设置页打开开关并重启 qq-bridge |
| bridge 日志「事件流 0 帧」 | dsh.baseUrl 是上一次的端口 |
状态页一键同步 + 重启 qq-bridge |
已知限制
- 语音/视频接收仍为占位文本(桥接侧限制),本插件只负责「发出」。
- IndexTTS 与 MSST 默认都想用 7860,必须错开端口。
- 不装 rvc-worker 时,RVC WebUI 的分离接口无法程序化等待,只能走 MSST 或旧
server/rvc-api.py;跨机全自动推荐 worker。 - 跨机器访问时 WebUI 需以
--listen打开,并放行对应端口。 - qq-bridge 的 preset 白名单是对方项目文件,升级/重跑
setup-dsh.mjs后可能需要重新加入四个工具名。
许可证
MIT © 2026 keduoli-lovely
No comments yet. Be the first to write one.