@memef1f1y/dsh-plugin-tts 0.6.0

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.
Files changed (44) hide show
  1. package/.github/workflows/test.yml +33 -0
  2. package/ANALYSIS.md +205 -0
  3. package/LICENSE +21 -0
  4. package/PR-REVIEW.md +75 -0
  5. package/README.md +297 -0
  6. package/README.zh.md +263 -0
  7. package/Snipaste_2026-08-16_13-28-10.png +0 -0
  8. package/Snipaste_2026-08-16_13-28-23.png +0 -0
  9. package/Snipaste_2026-08-16_13-28-37.png +0 -0
  10. package/Snipaste_2026-08-16_13-29-01.png +0 -0
  11. package/Snipaste_2026-08-16_13-29-11.png +0 -0
  12. package/TODO.md +23 -0
  13. package/cordis.patch.yml +4 -0
  14. package/docs/CLOUD-GUIDE.md +216 -0
  15. package/docs/COSYVOICE-GUIDE.md +216 -0
  16. package/docs/EDGE-GUIDE.md +166 -0
  17. package/docs/HOST-CONTRACT.md +36 -0
  18. package/docs/INDEX-TTS2-GUIDE.md +208 -0
  19. package/docs/RVC-GUIDE.md +390 -0
  20. package/docs/USER-GUIDE.md +334 -0
  21. package/docs/acceptance-checklist.md +148 -0
  22. package/docs/adaptive-chunked-playback.md +194 -0
  23. package/docs/macos-test-prompt.md +230 -0
  24. package/docs/windows-gpu-verify-prompt.md +151 -0
  25. package/lib/client.js +7036 -0
  26. package/lib/index.mjs +3288 -0
  27. package/logo.png +0 -0
  28. package/package.json +52 -0
  29. package/pnpm-workspace.yaml +7 -0
  30. package/rvc-server.py +564 -0
  31. package/tests/README.md +45 -0
  32. package/tests/client-load.mjs +393 -0
  33. package/tests/e2e-compact-index.mjs +86 -0
  34. package/tests/e2e-index-ab.mjs +138 -0
  35. package/tests/e2e-real-rvc.mjs +122 -0
  36. package/tests/i18n-keys.mjs +82 -0
  37. package/tests/mock-registry.mjs +50 -0
  38. package/tests/package-runtime-patch.mjs +88 -0
  39. package/tests/rvc-server-live.mjs +230 -0
  40. package/tests/smoke.mjs +1107 -0
  41. package/tools/gen-ui-preview.mjs +174 -0
  42. package/tools/mac-verify.sh +158 -0
  43. package/tools/make-pack.mjs +155 -0
  44. package/tools/package-runtime.py +214 -0
@@ -0,0 +1,216 @@
1
+ # CosyVoice 指南(本地提示音频克隆 / CosyVoice Guide)
2
+
3
+ > dsh-plugin-tts 的 CosyVoice 能力专册。CosyVoice 是纯本地零样本克隆:用一段提示音频 + 它的文字稿,直接按该音色朗读任意新文本。
4
+ > 主 README:[中文](../README.zh.md) / [English](../README.md) · 使用手册:[《执行手册》](USER-GUIDE.md)
5
+ >
6
+ > 🤖 **给 AI Agent 的说明**:本文档可直接喂给 AI Agent 照着落地。如果觉得晦涩难懂,或想直接脱手实现,
7
+ > 把本文档全文粘贴给你的 AI Agent,让它按文末「给 AI Agent 的落地附录」一步步执行验证即可。
8
+
9
+ **目录**
10
+ - [CosyVoice 是什么](#cosyvoice-是什么)
11
+ - [开始前准备](#开始前准备)
12
+ - [启动本地 CosyVoice 服务](#启动本地-cosyvoice-服务)
13
+ - [设置面板配置](#设置面板配置)
14
+ - [提示音频与文字稿(最关键)](#提示音频与文字稿最关键)
15
+ - [长文本分块播放](#长文本分块播放)
16
+ - [设置项详解](#设置项详解)
17
+ - [CosyVoice 疑难排查](#cosyvoice-疑难排查)
18
+ - [隐私与版权提示](#隐私与版权提示)
19
+ - [给 AI Agent 的落地附录](#给-ai-agent-的落地附录)
20
+ - [English](#english)
21
+
22
+ ---
23
+
24
+ <a name="cosyvoice-是什么"></a>
25
+ ## CosyVoice 是什么
26
+
27
+ CosyVoice 是本地运行的零样本语音克隆:给它一段提示音频(告诉它“是谁的声音”),
28
+ 再给新文本,它就用同一个声音读出新文本。
29
+
30
+ ```
31
+ 新文本 + 提示音频(+ 提示音频的文字稿)→ 本机 CosyVoice 服务 → wav → 播放
32
+ ```
33
+
34
+ 与 Index-TTS2 的区别只在配套方式:CosyVoice 要求同时提供提示音频的**文字稿**(transcript),
35
+ 且对多语提示稿的完整性更敏感;与 RVC 的区别:不需要 Edge TTS 原声,直接合成。
36
+ 全程在本机完成,不上传。
37
+
38
+ ---
39
+
40
+ <a name="开始前准备"></a>
41
+ ## 开始前准备
42
+
43
+ | 需要 | 是什么 | 必须吗 |
44
+ |---|---|---|
45
+ | 本地 CosyVoice 服务包 | 提供 HTTP API 的本地合成服务 | ✅ 必须 |
46
+ | 提示音频 | 决定朗读是谁的声音的音频片段 | ✅ 必须(至少一段) |
47
+ | 提示音频的文字稿 | 提示音频里说的内容,按顺序全文 | ✅ 必须(多语必须全语种写全) |
48
+ | 独立显卡 | 加速合成;没有也能用 CPU 跑,只是更慢 | ❌ 可选 |
49
+
50
+ > 提示音频一般用 5-20 秒清晰人声最佳;单人、安静、无背景音乐、无混响最稳。
51
+
52
+ ---
53
+
54
+ <a name="启动本地-cosyvoice-服务"></a>
55
+ ## 启动本地 CosyVoice 服务
56
+
57
+ 步骤是通行的三段式,与具体安装位置无关:
58
+
59
+ 1. 解压 / 准备好本地服务包到任意位置;
60
+ 2. 运行服务包内的 CosyVoice 启动脚本(一般是一个一键启动脚本),保持启动后的窗口 / 终端**别关**;
61
+ 3. 看到服务就绪提示(默认监听本地回环地址上的 CosyVoice 端口)后再回到插件配置。
62
+
63
+ 通用说明:
64
+
65
+ - **服务地址** 默认指向本地回环地址上的 CosyVoice 端口;只有把服务改到其他端口 / 其他机器时才需要改;
66
+ - 想换提示音频不需要重启服务,在设置面板里重新选择即可;
67
+ - 提示端口被占用(`Address already in use` / 端口冲突)= 旧服务还在跑,先关旧的再启动;
68
+ - 首次合成较慢是正常的(模型加载 + 预热),之后会快。
69
+
70
+ 服务至少提供四类接口(插件依次用到):健康检查、提示音频列表、提示音频上传、文本合成。
71
+ 只要这四类接口可达,插件就能工作,不关心服务包具体放在哪个目录。
72
+
73
+ ---
74
+
75
+ <a name="设置面板配置"></a>
76
+ ## 设置面板配置
77
+
78
+ 打开 **设置 → 插件 → 语音**:
79
+
80
+ - **TTS提供者** 选「**本地克隆(CosyVoice)**」;
81
+ - **服务地址**:一般保持默认(本地 CosyVoice 服务的地址);
82
+ - **提示音频**:点「**刷新音色**」拉取服务端的提示音频列表,然后选中一段;
83
+ - **提示音频文字稿**:填写所选提示音频里说的内容(见下一节);
84
+ - 点面板底部「试听测试」输入一句话试听,确认是想要的声音。
85
+
86
+ ---
87
+
88
+ <a name="提示音频与文字稿最关键"></a>
89
+ ## 提示音频与文字稿(最关键)
90
+
91
+ 这是 CosyVoice 用好与否的分水岭:
92
+
93
+ 1. **提示音频怎么选**
94
+ - 优先单人、安静、无音乐、无混响的人声;
95
+ - 5-20 秒最稳;过短容易不稳定,过长增加加载负担;
96
+ - 新增音频后点「刷新音色」同步;也可用面板上传常见语音格式,上传后自动存入服务端的提示音频区。
97
+ 2. **文字稿怎么写**
98
+ - 按**顺序**、**全文**填写提示音频里说的内容,不要只写一半;
99
+ - **多语提示音频必须把每个语种都写全**:例如提示音频里中英日三段都有,就必须中英日三段全写,
100
+ 缺一段模型会把缺的那段复读一遍再读新文字;
101
+ - 不确定的地方宁可换一段内容明确的提示音频,也不要留空蒙混。
102
+ 3. **直接填写**:也支持直接粘贴服务端已有的提示音频文件名;上传入口支持常见语音容器格式。
103
+
104
+ ---
105
+
106
+ <a name="长文本分块播放"></a>
107
+ ## 长文本分块播放
108
+
109
+ 长回复会自动按句切块、边合成边播放:先合成前几块立即开播,其余块在播放的同时后台合成,
110
+ 块间连续播放。短文本走单文件链路,零额外开销。播放期间按钮会显示 chunk 进度。
111
+
112
+ ---
113
+
114
+ <a name="设置项详解"></a>
115
+ ## 设置项详解
116
+
117
+ | 设置项 | 作用 | 建议 |
118
+ |---|---|---|
119
+ | 服务地址 | 本地 CosyVoice 服务的地址 | 一般保持默认 |
120
+ | 提示音频 | 决定朗读是谁的声音 | 用「刷新音色」同步列表后选择 |
121
+ | 提示音频文字稿 | 提示音频的内容全文 | 必须按顺序写全;多语全写 |
122
+ | 语速 | 合成语速 | `1.0` = 正常;`0.5` 慢速 ~ `2.0` 快速 |
123
+ | 随机种子 | 控制合成随机性 | `0` = 每次随机;填固定值可复现同一次合成 |
124
+ | 试听文本 | 面板底部的试听输入 | 换提示音频 / 改文字稿后务必试听一句确认 |
125
+
126
+ > 语速只改变合成节奏,不改变音色;种子只影响可复现性,不影响音质。
127
+
128
+ ---
129
+
130
+ <a name="cosyvoice-疑难排查"></a>
131
+ ## CosyVoice 疑难排查
132
+
133
+ > 💡 设置面板有「**诊断**」按钮:一键检查本地 CosyVoice 服务与提示音频是否正常,
134
+ > 并按「连接 / 协议 / 音色」分类给出可读提示。
135
+
136
+ | 症状 | 最常见原因 | 怎么办 |
137
+ |---|---|---|
138
+ | 提示无法连接本地服务 | 服务窗口没开 / 被关了 / 服务地址不对 | 重新运行服务包的启动脚本并保留窗口;确认「服务地址」与服务实际端口一致 |
139
+ | 点「刷新音色」为空 | 服务端提示音频区没有音频 / 服务未就绪 | 往提示音频区放入音频或用面板上传后再刷新;确认服务已完全启动 |
140
+ | 提示音频列表读取失败 | 服务未就绪或接口异常 | 等服务就绪后重试;看服务端窗口的报错 |
141
+ | 合成失败 / 返回音频过小 | 文本为空、提示音频损坏、服务端异常 | 先换一段提示音频 + 短文本试听;仍失败看服务端窗口报错 |
142
+ | 模型把提示稿复读一遍再读新文字 | 多语提示音频的文字稿没写全 | 把提示音频里每个语种的内容都补全到文字稿 |
143
+ | 首次合成等很久 | 正常:模型加载 + 预热 | 等它;之后会快 |
144
+ | 反馈问题时请附带 | 定位需要的信息 | F12 控制台 `[tts]` 开头的行;`copy(JSON.stringify(__dshTtsDebug.dump()))` 的输出;服务端窗口的红色报错 |
145
+
146
+ ---
147
+
148
+ <a name="隐私与版权提示"></a>
149
+ ## 隐私与版权提示
150
+
151
+ CosyVoice 全程本地合成,音频与文本不上传。只使用你有权使用的提示音频(自己录制的、
152
+ 或已获授权的);未经同意克隆他人声音可能涉及法律与平台规则问题。
153
+
154
+ ---
155
+
156
+ <a name="给-ai-agent-的落地附录"></a>
157
+ ## 给 AI Agent 的落地附录
158
+
159
+ > 以下契约对所有机器通用,不含任何个人路径。按顺序执行即可打通本地服务与 dsh 的联通。
160
+
161
+ - **provider id**:`cosyvoice`(`/speak` 的 `provider` 字段就填这个)。
162
+ - **默认服务地址**:`http://127.0.0.1:7890`(回环地址 + 默认端口;只有改过端口 / 远端部署才改)。
163
+ - **本地服务最小接口**(插件只依赖这四个,目录位置不重要):
164
+ `GET /health`(存活)、`GET /voices` → `{ voices: [] }`(提示音频列表)、
165
+ `POST /upload`(上传提示音频)、`POST /tts`(合成,body 含 `text` / `prompt` / `prompt_text` / `speed` / `seed`,
166
+ 返回 `{ audio_base64 }`)。
167
+ - **经插件 Host 中转的调用**(前端不直连本地服务):
168
+ 提示音频列表 `GET /dsh-tts-api/cosy-voices?baseUrl=<服务地址>`;
169
+ 上传提示音频 `POST /dsh-tts-api/cosy-upload`;
170
+ 服务地址持久化 `GET /dsh-tts-api/cosy-config` / `POST /dsh-tts-api/cosy-config-save`;
171
+ 合成 `POST /dsh-tts-api/speak` body `{ text, provider: "cosyvoice", custom: { baseUrl, voice, promptText, speed, seed } }`
172
+ → 短文本 `{ url }`,长文本 `{ jobId, chunks, total }`(后续块 `GET /dsh-tts-api/rvc-next?job=<jobId>`)。
173
+ - **文字稿必填校验**:`promptText` 必须与所选提示音频的内容按序全文一致;多语提示音频缺任一段都会复读,
174
+ 这是联通成功但“读错”的头号原因,先查它再查服务。
175
+ - **诊断验证**:`POST /dsh-tts-api/diagnose` body `{ cosyBaseUrl }` → 看 `checks` 里
176
+ `cosy-server`(服务是否在线)与 `cosy-voice`(提示音频是否非空)。
177
+ - **验收标准**:提示音频列表非空 → 任选一段 + 写对文字稿合成一句短文本能播 → 一句长文本能出 `chunks` 且首块可播。
178
+
179
+ ---
180
+
181
+ <a name="english"></a>
182
+ ## English
183
+
184
+ CosyVoice is local zero-shot voice cloning: a prompt clip (+ its transcript) defines the voice,
185
+ and any new text is read in that voice — all on your own machine, no Edge TTS base voice needed.
186
+
187
+ ### Quick start
188
+ 1. **Prepare**: a local CosyVoice service bundle, at least one prompt clip (5-20s of clean speech works best),
189
+ and its transcript.
190
+ 2. **Start the service** (keep the window open): run the bundle's launcher, wait until it reports ready
191
+ on its loopback port.
192
+ 3. **Configure**: 设置 → 插件 → 语音 → provider = local CosyVoice; keep the service URL default;
193
+ click Refresh voices, pick a prompt clip, fill its **full transcript in order**, and preview one sentence.
194
+
195
+ ### The transcript rule (most important)
196
+ - Write **everything** the prompt clip says, **in order**.
197
+ - **Multilingual prompts must include every language part**: if the clip speaks three languages,
198
+ all three transcripts are required — otherwise the model re-reads the missing part before the new text.
199
+ - When in doubt, switch to a clip whose content you can transcribe exactly.
200
+
201
+ ### Settings explained (abridged)
202
+ | Setting | Effect | Guidance |
203
+ |---|---|---|
204
+ | Service URL | Local CosyVoice address | keep default |
205
+ | Prompt audio | Who reads | refresh then pick |
206
+ | Prompt transcript | What the prompt clip says | full, in order, all languages |
207
+ | Speed | Synthesis pace | 1.0 normal (0.5 slow ~ 2.0 fast) |
208
+ | Seed | Randomness | 0 = random each time; fixed = reproducible |
209
+
210
+ ### Troubleshooting
211
+ - Cannot connect → the service window is closed or the URL/port mismatches; restart it and keep it open.
212
+ - Empty prompt list → no prompt clips on the server yet; add or upload one, then refresh.
213
+ - Model repeats the prompt before new text → the transcript is incomplete; complete every language part.
214
+ - First synthesis is slow → normal (model load + warmup).
215
+
216
+ > ⚠️ Privacy & rights: fully local — nothing is uploaded. Only clone voices you have the right to use.
@@ -0,0 +1,166 @@
1
+ # Edge TTS 指南(默认在线朗读 / Edge TTS Guide)
2
+
3
+ > dsh-plugin-tts 的 Edge TTS 能力专册。Edge TTS 是插件的默认提供者,开箱即用,无需本地服务与模型。
4
+ > 主 README:[中文](../README.zh.md) / [English](../README.md) · 使用手册:[《执行手册》](USER-GUIDE.md)
5
+ >
6
+ > 🤖 **给 AI Agent 的说明**:本文档可直接喂给 AI Agent 照着落地。如果觉得晦涩难懂,或想直接脱手实现,
7
+ > 把本文档全文粘贴给你的 AI Agent,让它按文末「给 AI Agent 的落地附录」一步步执行验证即可。
8
+
9
+ **目录**
10
+ - [Edge TTS 是什么](#edge-tts-是什么)
11
+ - [开始前准备](#开始前准备)
12
+ - [设置面板配置](#设置面板配置)
13
+ - [长文本流式播放](#长文本流式播放)
14
+ - [设置项详解](#设置项详解)
15
+ - [Edge TTS 疑难排查](#edge-tts-疑难排查)
16
+ - [隐私与使用提示](#隐私与使用提示)
17
+ - [给 AI Agent 的落地附录](#给-ai-agent-的落地附录)
18
+ - [English](#english)
19
+
20
+ ---
21
+
22
+ <a name="edge-tts-是什么"></a>
23
+ ## Edge TTS 是什么
24
+
25
+ Edge TTS 是微软提供的免费在线合成端点:把要朗读的文本发送过去,返回一段朗读音频后播放。
26
+
27
+ 链路只有一步:
28
+
29
+ ```
30
+ 消息文本 → Edge TTS 在线合成 → mp3 → 播放
31
+ ```
32
+
33
+ 特点是零配置:不需要本地服务、不需要下载模型、不需要 API Key,只要本机能访问外网即可用。
34
+ 它是其他本地音色(如 RVC)的“原声”来源,也是审批语音提醒的固定通道。
35
+
36
+ ---
37
+
38
+ <a name="开始前准备"></a>
39
+ ## 开始前准备
40
+
41
+ | 需要 | 是什么 | 必须吗 |
42
+ |---|---|---|
43
+ | 可访问外网的网络 | 合成请求需要到达在线端点 | ✅ 必须 |
44
+ | 任意现代浏览器 | 播放与自动播放解锁在浏览器内完成 | ✅ 必须 |
45
+ | 本地服务 / 模型文件 | 不需要 | ❌ 不需要 |
46
+
47
+ > 如果网络无法访问在线端点,请改用纯本地的提供者(Index-TTS2 / CosyVoice / RVC)。
48
+
49
+ ---
50
+
51
+ <a name="设置面板配置"></a>
52
+ ## 设置面板配置
53
+
54
+ 打开 **设置 → 插件 → 语音**:
55
+
56
+ - **TTS提供者** 选「**Edge TTS**」(默认即此项);
57
+ - **朗读音色**:从下拉列表选一个喜欢的声音(中文 / 繁体 / 英文 / 日韩法等分组);
58
+ - **声音调节**:语速 / 音调 / 音量,`0` 表示默认,直接作用于本次合成;
59
+ - **试听测试**:在面板底部输入一句话点 ▶,马上听效果。
60
+
61
+ 日常朗读入口与所有提供者共用:
62
+
63
+ - 每条 AI 回复左下角的喇叭按钮 = 朗读本条 / 再点停止;
64
+ - 输入框旁的喇叭开关 = 新回复自动朗读;
65
+ - 选中消息内一段文本 = 悬浮「朗读选中」只读该片段。
66
+
67
+ ---
68
+
69
+ <a name="长文本流式播放"></a>
70
+ ## 长文本流式播放
71
+
72
+ 长回复不会等整段合成完才出声。插件把文本按句切成多块:
73
+
74
+ 1. 第一块合成完成后立即开播,其余块在播放的同时后台合成——**边播边合成**;
75
+ 2. 切分会避开 URL / 邮箱 / 小数 / 版本号等原子 token,不会把它们从中间切断;
76
+ 3. 末尾的极短句会并入前一块,避免听感像结巴;
77
+ 4. 播放期间按钮会显示 chunk 进度;停止 / 切换消息会立即取消后续块的合成。
78
+
79
+ 短文本(预估朗读时长较短)走单文件链路,零额外开销。
80
+
81
+ ---
82
+
83
+ <a name="设置项详解"></a>
84
+ ## 设置项详解
85
+
86
+ | 设置项 | 作用 | 建议 |
87
+ |---|---|---|
88
+ | 朗读音色 | 决定朗读是谁的声音 | 按语种偏好选;列表外的旧音色可能已被端点移除 |
89
+ | 语速 | 朗读快慢 | `0` = 默认;±10-20% 听感自然 |
90
+ | 音调 | 声音高低 | `0` = 默认;负值更低沉,正值更明亮 |
91
+ | 音量 | 朗读响度 | `0` = 默认;负值更轻,正值更响 |
92
+ | 朗读原始 Markdown 符号 | 默认清洗代码块 / 表格 / 链接等符号后朗读;开启后逐字读出原始符号 | 阅读类场景保持关闭;读源码时开启 |
93
+ | 播放速度(mini 播放器) | 播放中的变速(1x / 1.25x / 1.5x),不重新合成 | 按听感切换 |
94
+ | 审批语音提醒的提醒音色 | 审批事件播报用的独立音色,不跟随主朗读音色 | 选一个辨识度高的声音 |
95
+
96
+ > 合成音频为 `audio-24khz-48kbitrate-mono-mp3`;同一文本 + 同一音色在同一会话内会复用缓存,不重复合成。
97
+
98
+ ---
99
+
100
+ <a name="edge-tts-疑难排查"></a>
101
+ ## Edge TTS 疑难排查
102
+
103
+ > 💡 设置面板有「**诊断**」按钮:一键检查 Edge TTS 在线合成是否正常,并按「连接 / 协议 / 音色」分类给出可读提示。
104
+
105
+ | 症状 | 最常见原因 | 怎么办 |
106
+ |---|---|---|
107
+ | 点朗读没声音 | 浏览器自动播放限制 / 系统音量 | 先在页面任意处点一下再试;检查系统音量与浏览器标签页静音状态 |
108
+ | 报 403 / 合成失败 | 在线端点协议或版本校验变更,或网络 / 代理拦截 | 过一会儿重试;仍失败则检查网络 / 代理设置,并反馈诊断日志 |
109
+ | 提示 `1007 Unsupported voice` | 所选音色已被端点移除 | 换用列表内的现行音色;插件会自动回退到默认音色 |
110
+ | 合成超时(约 45 秒) | 端点无响应或网络黑洞 | 检查网络 / 代理后重试;瞬时抖动会自动重试一次 |
111
+ | 试听按钮一直转 | 网络不通或合成未返回 | 看红字提示;确认网络可达后再试 |
112
+ | 反馈朗读问题时请附带 | 定位需要的信息 | 页面按 F12 打开控制台,复制 `[tts]` 开头的行;再运行 `copy(JSON.stringify(__dshTtsDebug.dump()))` 一并提供 |
113
+
114
+ ---
115
+
116
+ <a name="隐私与使用提示"></a>
117
+ ## 隐私与使用提示
118
+
119
+ Edge TTS 会把要朗读的文本发送到微软在线端点作合成(个人使用没问题;商用 / 高并发请留意微软服务条款)。
120
+ 合成音频写入系统临时目录,由系统自动清理;同一会话内的重复朗读会复用缓存,重启后首次朗读会重新合成。
121
+
122
+ ---
123
+
124
+ <a name="给-ai-agent-的落地附录"></a>
125
+ ## 给 AI Agent 的落地附录
126
+
127
+ > 以下契约对所有机器通用,不含任何个人路径。按顺序执行即可打通。
128
+
129
+ - **provider id**:`edge-tts`(`/speak` 的 `provider` 字段就填这个;缺省也按它处理)。
130
+ - **无需本地服务**:没有 `baseUrl`,没有模型文件,跳过一切“启动服务”步骤。
131
+ - **合成调用**(经插件 Host 中转,前端不直连微软端点):
132
+ `POST /dsh-tts-api/speak` body `{ text, voice, provider: "edge-tts", prosody: { rate, pitch, volume } }`
133
+ → 短文本返回 `{ url }`,长文本返回 `{ jobId, chunks, total }`(后续块用 `GET /dsh-tts-api/rvc-next?job=<jobId>` 逐块拉取)。
134
+ - **音频播放**:`GET /dsh-tts-audio/<id>`(`id` 取自返回的 `url` 尾段)。
135
+ - **诊断验证**:`POST /dsh-tts-api/diagnose` body `{}` → 看 `checks` 里 `id === "edge"` 一项;
136
+ `ok: true` 即联通,`cls === "voice"` 换音色,`cls === "protocol"/"connect"` 查网络。
137
+ - **验收标准**:任选列表内音色合成一句短文本能播;一句长文本能出 `chunks` 且首块可播。
138
+
139
+ ---
140
+
141
+ <a name="english"></a>
142
+ ## English
143
+
144
+ Edge TTS is the default provider: free online synthesis, no local service, no model, no API key —
145
+ just network access to the online endpoint.
146
+
147
+ ### Quick start
148
+ 1. **Prepare**: network access to the online endpoint. Nothing to install.
149
+ 2. **Configure**: 设置 → 插件 → 语音 → provider = Edge TTS; pick a voice; rate/pitch/volume `0` = default.
150
+ 3. **Read**: the speaker button under a message reads it; the composer toggle auto-reads new replies;
151
+ selecting text shows a "read selection" chip.
152
+
153
+ ### Key capabilities
154
+ - **Progressive long reads**: long replies are sentence-split; the first chunk plays while the rest
155
+ synthesize; atomic tokens (URLs / emails / decimals / versions) are never split mid-token.
156
+ - **Clean reads**: message Markdown (code blocks, tables, links, quotes, task lists) is cleaned before
157
+ synthesis; an opt-in toggle reads raw Markdown verbatim for source code.
158
+ - **In-session cache**: repeating the same text + voice reuses the cached audio instead of re-synthesizing.
159
+
160
+ ### Troubleshooting
161
+ - No sound → browser autoplay policy / system volume; interact with the page once first.
162
+ - 403 / synthesis failure → endpoint protocol check changed or network/proxy interception; retry later.
163
+ - `1007 Unsupported voice` → the voice was removed by the endpoint; pick a listed voice.
164
+
165
+ > ⚠️ Privacy: Edge TTS sends the text-to-read to Microsoft's endpoint for online synthesis.
166
+ > Check Microsoft's terms for commercial / heavy usage.
@@ -0,0 +1,36 @@
1
+ # DSH 宿主插槽契约(实测记录)
2
+
3
+ > 本文件是 2026-09 用控制台日志反推出的真实契约,不是官方文档。
4
+ > 宿主升级后可能漂移——插件代码已按“多形态兼容 + DOM 兜底”来写,
5
+ > 漂移时看控制台 `[tts]` 日志即可重新定位(方法见末尾)。
6
+
7
+ ## 1. 涉及的插槽与 props
8
+
9
+ | 插槽 | props(含标准钩子) |
10
+ |---|---|
11
+ | `conversation.chat.assistant-actions`(单条朗读按钮) | `inputActions, messageId, sessionId, useChat, useConversation, useInput, usePanelInfo, useProjection, useResource, useSession, useSessionPendingInteraction, useSessions, useTrajectory, useWorkspaces` |
12
+ | `conversation.input.left`(自动朗读开关) | 同上(无 `messageId`) |
13
+
14
+ `messageId` 与下述 `eventNodes[].messageId` 精确对应,是按钮定位正文的主键。
15
+
16
+ ## 2. 快照形状(`hook(s => s)` 所见)
17
+
18
+ - **`useSession`**:`{sessionId, queue, pendingSubmissions, running, subagent, removed, openState, openError, hasMore, loadingOlder, promptError, blank}`——**只有队列/运行状态,没有消息**。切勿用它找正文。
19
+ - **`useTrajectory`**:`{eventNodes, eventLocations, requests, callSchemas, partial, runningCalls}`——**正文主数据源**。`eventNodes[]` 形如 `{kind, seq, messageId, time, turn, step, blocks, usage, …}`,`kind` 区分 `assistant/user`,AI 正文在 `blocks: [{kind: "text", text}]`,`seq` 单调递增。`partial` 非空表示正在流式。
20
+ - **`useChat`**:`{order: string[](id 顺序), nodes: 内部 store(`byKey` 实测为空), locations, navigation, timeline{turnOrder, turns}, legacy{nodes(与 eventNodes 同源的数组镜像)}}`——备用链路。
21
+ - **`useConversation`**:`{views: {eventDefinitions, viewDefinitions, contexts, contextsByKind, contextsBySeq, contextsByTarget, inputs, locationIndex, …}, activeTargets}`——视图元数据,不是消息。
22
+ - **`useProjection`**:实测返回空。
23
+ - **`useResource`**:`{status, value, failure}`。
24
+
25
+ ## 3. 客户端据此实现的规则(`lib/client.js`)
26
+
27
+ - 按钮:`messageId` 跨所有快照按 id 找 → `blocks` 正文 → 找不到走 DOM 逐层上爬(首个 ≥20 字祖先即气泡);按钮永不 `disabled`,真没文本弹 toast。
28
+ - 自动朗读:只看 `useTrajectory.eventNodes`(优先)等内容源的新增;**切会话静默重建基线;一次新增 >3 条按历史同步静默跟进;朗读必须过活体闩**(本页面生命周期内见过 `running/queue/pending/partial`,或用户侧增长已陈化 ≥2 秒)——三者缺一即历史,必须安静。
29
+ - 空会话基线记为 -1,保证新会话首条回复正常朗读。
30
+
31
+ ## 4. 契约漂移时的取证方法
32
+
33
+ 1. 确认构建号:控制台应有 `[tts] client build <tag> loaded`(没有 = 跑的是旧包,先硬刷新/重启 `dsh web`)。
34
+ 2. 挂载形状:`[tts] slot: <插槽> props: …` 行列出各钩子的数据形状(只含键名/数量/首节点正文长度,不含正文)。
35
+ 3. 自动朗读判决:每次触发会打 `[tts] auto-read speak key=… fresh=… src=… seq=…`,`src` 即放行的 feeder。
36
+ 4. 一键打包:控制台运行 `copy(JSON.stringify(__dshTtsDebug.dump()))`,把剪贴板内容贴到 issue。
@@ -0,0 +1,208 @@
1
+ # Index-TTS2 指南(本地参考音频音色 / Index-TTS2 Guide)
2
+
3
+ > dsh-plugin-tts 的 Index-TTS2 能力专册。Index-TTS2 是纯本地合成:音色来自参考音频,不需要 Edge TTS 原声。
4
+ > 主 README:[中文](../README.zh.md) / [English](../README.md) · 使用手册:[《执行手册》](USER-GUIDE.md)
5
+ >
6
+ > 🤖 **给 AI Agent 的说明**:本文档可直接喂给 AI Agent 照着落地。如果觉得晦涩难懂,或想直接脱手实现,
7
+ > 把本文档全文粘贴给你的 AI Agent,让它按文末「给 AI Agent 的落地附录」一步步执行验证即可。
8
+
9
+ **目录**
10
+ - [Index-TTS2 是什么](#index-tts2-是什么)
11
+ - [开始前准备](#开始前准备)
12
+ - [启动本地 Index-TTS2 服务](#启动本地-index-tts2-服务)
13
+ - [设置面板配置](#设置面板配置)
14
+ - [参考音频与上传](#参考音频与上传)
15
+ - [长文本分块播放](#长文本分块播放)
16
+ - [设置项详解](#设置项详解)
17
+ - [Index-TTS2 疑难排查](#index-tts2-疑难排查)
18
+ - [隐私与版权提示](#隐私与版权提示)
19
+ - [给 AI Agent 的落地附录](#给-ai-agent-的落地附录)
20
+ - [English](#english)
21
+
22
+ ---
23
+
24
+ <a name="index-tts2-是什么"></a>
25
+ ## Index-TTS2 是什么
26
+
27
+ Index-TTS2 是本地运行的文本转语音服务:输入文本 + 一段参考音频,直接合成出带有该参考音色的朗读。
28
+
29
+ ```
30
+ 消息文本 + 参考音频 → 本机 Index-TTS2 服务 → wav → 播放
31
+ ```
32
+
33
+ 与 RVC 的区别:RVC 是“先合成再变声”(需要原声),Index-TTS2 是“直接按参考音色合成”(不需要原声)。
34
+ 全程在本机完成,参考音频与合成文本不会上传到任何地方。
35
+
36
+ ---
37
+
38
+ <a name="开始前准备"></a>
39
+ ## 开始前准备
40
+
41
+ | 需要 | 是什么 | 必须吗 |
42
+ |---|---|---|
43
+ | 本地 Index-TTS2 服务包 | 提供 HTTP API 的本地合成服务 | ✅ 必须 |
44
+ | 参考音频 | 决定朗读是谁的声音的音频片段 | ✅ 必须(至少一段) |
45
+ | 独立显卡 | 加速合成;没有也能用 CPU 跑,只是更慢 | ❌ 可选 |
46
+
47
+ > 参考音频一般用清晰人声,数秒到数十秒即可;越干净、越接近目标说话人的日常语速,合成效果越稳定。
48
+
49
+ ---
50
+
51
+ <a name="启动本地-index-tts2-服务"></a>
52
+ ## 启动本地 Index-TTS2 服务
53
+
54
+ 步骤是通行的三段式,与具体安装位置无关:
55
+
56
+ 1. 解压 / 准备好本地服务包到任意位置;
57
+ 2. 运行服务包内的 API 启动脚本(一般是一个一键启动脚本),保持启动后的窗口 / 终端**别关**;
58
+ 3. 看到服务就绪提示(默认监听本地回环地址上的 Index-TTS2 端口)后再回到插件配置。
59
+
60
+ 通用说明:
61
+
62
+ - **服务地址** 默认指向本地回环地址上的 Index-TTS2 端口;只有把服务改到其他端口 / 其他机器时才需要改;
63
+ - 想换参考音频不需要重启服务,在设置面板里重新选择即可;
64
+ - 提示端口被占用(`Address already in use` / 端口冲突)= 旧服务还在跑,先关旧的再启动;
65
+ - 首次合成较慢是正常的(模型加载 + 预热),之后会快。
66
+
67
+ 服务至少提供三类接口(插件依次用到):健康检查、参考音色列表、文本合成任务。
68
+ 只要这三类接口可达,插件就能工作,不关心服务包具体放在哪个目录。
69
+
70
+ ---
71
+
72
+ <a name="设置面板配置"></a>
73
+ ## 设置面板配置
74
+
75
+ 打开 **设置 → 插件 → 语音**:
76
+
77
+ - **TTS提供者** 选「**本地音色(Index-TTS2)**」;
78
+ - **服务地址**:一般保持默认(本地 Index-TTS2 服务的地址);
79
+ - **参考音色**:点「**刷新音色**」拉取服务端的参考音频列表,然后选中一段;
80
+ - 点面板底部「试听测试」输入一句话试听,确认是想要的声音。
81
+
82
+ ---
83
+
84
+ <a name="参考音频与上传"></a>
85
+ ## 参考音频与上传
86
+
87
+ - **选择**:下拉列表来自服务端当前可用的参考音频;新增音频后点「刷新音色」同步;
88
+ - **上传**:面板提供上传入口,支持常见的语音容器格式(如 wav / mp3 / flac / m4a / ogg);
89
+ 上传后自动存入服务端的参考音频区并可直接选用;
90
+ - **直接填写**:也支持直接粘贴服务端已有的参考音频文件名;
91
+ - **挑选建议**:优先用单人、安静、无背景音乐、无混响的人声片段;过短(1-2 秒)容易不稳定,
92
+ 过长(数分钟)会增加加载负担,中等长度最稳。
93
+
94
+ ---
95
+
96
+ <a name="长文本分块播放"></a>
97
+ ## 长文本分块播放
98
+
99
+ 长回复会自动按句切块、边合成边播放:先合成前几块立即开播,其余块在播放的同时后台合成,
100
+ 块间连续播放。首次长文本不需要额外的测速等待;播放期间按钮会显示 chunk 进度。
101
+ 短文本走单文件链路,零额外开销。
102
+
103
+ ---
104
+
105
+ <a name="设置项详解"></a>
106
+ ## 设置项详解
107
+
108
+ | 设置项 | 作用 | 建议 |
109
+ |---|---|---|
110
+ | 服务地址 | 本地 Index-TTS2 服务的地址 | 一般保持默认 |
111
+ | 参考音色 | 决定朗读是谁的声音 | 用「刷新音色」同步列表后选择 |
112
+ | 朗读前清洗文本 | 去掉 Markdown / 链接 / HTML 等符号再合成 | 阅读类场景建议开启;读源码时关闭 |
113
+ | 情感控制 | `跟随参考音频` / `情感参考音频` / `情感向量` / `情感文本描述` | 默认跟随参考音频;有明确情绪需求再切换 |
114
+ | 情感参考音频 | 用另一段音频的情绪来读 | 仅在情感控制选对应模式时生效 |
115
+ | 情感强度 | 情感参考的影响强度 | 默认中等;越大越夸张 |
116
+ | 情感描述文本 | 用文字描述情绪(如“开心地朗读”) | 仅在对应模式下生效 |
117
+ | 随机情感 | 每次合成加入一点情感随机性 | 想要拟人感可开;要稳定复现则关闭 |
118
+ | 单段最大文本 | 长文本按语义切段时每段的最大文本量 | 默认即可;越大越连贯、越小越稳 |
119
+ | 随机性 / Top-P / Top-K | 采样发散程度与截断 | 默认即可;越大越发散、越小越稳定 |
120
+ | 试听文本 | 面板底部的试听输入 | 换参考音频后务必试听一句确认 |
121
+
122
+ > 高级采样参数(Top-P / Top-K / 温度 / beam / 重复惩罚等)一般不用改;只有在合成不稳定
123
+ > (吞字、复读、断句异常)时再小幅调整。
124
+
125
+ ---
126
+
127
+ <a name="index-tts2-疑难排查"></a>
128
+ ## Index-TTS2 疑难排查
129
+
130
+ > 💡 设置面板有「**诊断**」按钮:一键检查本地 Index-TTS2 服务与参考音色是否正常,
131
+ > 并按「连接 / 协议 / 音色」分类给出可读提示。
132
+
133
+ | 症状 | 最常见原因 | 怎么办 |
134
+ |---|---|---|
135
+ | 提示无法连接本地服务 | 服务窗口没开 / 被关了 / 服务地址不对 | 重新运行服务包的启动脚本并保留窗口;确认「服务地址」与服务实际端口一致 |
136
+ | 点「刷新音色」为空 | 服务端参考音频区没有音频 / 服务未就绪 | 往参考音频区放入音频或用面板上传后再刷新;确认服务已完全启动 |
137
+ | 提示参考音频列表读取失败 | 服务未就绪或接口异常 | 等服务就绪后重试;看服务端窗口的报错 |
138
+ | 合成失败 / 返回音频过小 | 文本为空、参考音频损坏、服务端异常 | 先换一段参考音频 + 短文本试听;仍失败看服务端窗口报错 |
139
+ | 首次合成等很久 | 正常:模型加载 + 预热 | 等它;之后会快 |
140
+ | 音色不像 / 情绪不对 | 参考音频质量差或情感模式选错 | 换更干净的参考音频;情感控制先用“跟随参考音频” |
141
+ | 反馈问题时请附带 | 定位需要的信息 | F12 控制台 `[tts]` 开头的行;`copy(JSON.stringify(__dshTtsDebug.dump()))` 的输出;服务端窗口的红色报错 |
142
+
143
+ ---
144
+
145
+ <a name="隐私与版权提示"></a>
146
+ ## 隐私与版权提示
147
+
148
+ Index-TTS2 全程本地合成,音频与文本不上传。只使用你有权使用的参考音频(自己录制的、
149
+ 或已获授权的);未经同意克隆他人声音可能涉及法律与平台规则问题。
150
+
151
+ ---
152
+
153
+ <a name="给-ai-agent-的落地附录"></a>
154
+ ## 给 AI Agent 的落地附录
155
+
156
+ > 以下契约对所有机器通用,不含任何个人路径。按顺序执行即可打通本地服务与 dsh 的联通。
157
+
158
+ - **provider id**:`index-tts2`(`/speak` 的 `provider` 字段就填这个)。
159
+ - **默认服务地址**:`http://127.0.0.1:7880`(回环地址 + 默认端口;只有改过端口 / 远端部署才改)。
160
+ - **本地服务最小接口**(插件只依赖这三个,目录位置不重要):
161
+ `GET /health`(存活)、`GET /api/v1/voices` → `{ voices: [] }`(参考音频列表)、
162
+ `POST /api/v1/tts/tasks`(合成,body 含 `text` / `prompt_audio` 及清洗与采样参数,返回 wav 字节)。
163
+ - **经插件 Host 中转的调用**(前端不直连本地服务):
164
+ 音色列表 `GET /dsh-tts-api/index-voices?baseUrl=<服务地址>`;
165
+ 上传参考音频 `POST /dsh-tts-api/index-upload`;
166
+ 服务地址持久化 `GET /dsh-tts-api/index-config` / `POST /dsh-tts-api/index-config-save`;
167
+ 合成 `POST /dsh-tts-api/speak` body `{ text, provider: "index-tts2", custom: { baseUrl, voice } }`
168
+ → 短文本 `{ url }`,长文本 `{ jobId, chunks, total }`(后续块 `GET /dsh-tts-api/rvc-next?job=<jobId>`)。
169
+ - **诊断验证**:`POST /dsh-tts-api/diagnose` body `{ indexBaseUrl }` → 看 `checks` 里
170
+ `index-server`(服务是否在线)与 `index-voice`(参考音频是否非空);`warn = 空列表`,补音频再刷新。
171
+ - **验收标准**:音色列表非空 → 任选一段合成一句短文本能播 → 一句长文本能出 `chunks` 且首块可播。
172
+
173
+ ---
174
+
175
+ <a name="english"></a>
176
+ ## English
177
+
178
+ Index-TTS2 is local text-to-speech with reference-audio timbre: text + a reference clip
179
+ synthesizes directly into that voice, with no Edge TTS base voice needed — all on your own machine.
180
+
181
+ ### Quick start
182
+ 1. **Prepare**: a local Index-TTS2 service bundle and at least one reference clip (clean speech works best).
183
+ 2. **Start the service** (keep the window open): run the bundle's API launcher, wait until it reports ready
184
+ on its loopback port.
185
+ 3. **Configure**: 设置 → 插件 → 语音 → provider = local Index-TTS2; keep the service URL default;
186
+ click Refresh voices, pick a reference clip, and preview one sentence.
187
+
188
+ ### Key capabilities
189
+ - **Reference-audio voices**: the voice list comes from the server; new clips appear after Refresh;
190
+ the panel also uploads common audio containers into the server's reference area.
191
+ - **Chunked long reads**: long replies are sentence-split and play while the rest synthesize.
192
+ - **Emotion control**: follow the reference / emotion reference clip / emotion vector / emotion text,
193
+ plus strength and an optional randomization toggle.
194
+
195
+ ### Settings explained (abridged)
196
+ | Setting | Effect | Guidance |
197
+ |---|---|---|
198
+ | Service URL | Local Index-TTS2 address | keep default |
199
+ | Reference voice | Who reads | refresh then pick |
200
+ | Clean text | Strip Markdown/links/HTML before synthesis | on for reading |
201
+ | Emotion | How emotion is controlled | follow reference by default |
202
+
203
+ ### Troubleshooting
204
+ - Cannot connect → the service window is closed or the URL/port mismatches; restart it and keep it open.
205
+ - Empty voice list → no reference clips on the server yet; add or upload one, then refresh.
206
+ - First synthesis is slow → normal (model load + warmup).
207
+
208
+ > ⚠️ Privacy & rights: fully local — nothing is uploaded. Only clone voices you have the right to use.