koishi-plugin-local-vitspro 0.1.0 → 0.1.1
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/CHANGELOG.md +4 -0
- package/package.json +2 -1
- package/readme.md +91 -106
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-local-vitspro",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "多后端 TTS 聚合插件:自动解包 chatluna 消息、长文本切片与音频拼接、按实测推理速度自适应超时与熔断,支持 vits-simple-api / GPT-SoVITS / fish-audio / QQ 声聊",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"types": "lib/index.d.ts",
|
|
@@ -89,3 +89,4 @@
|
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
|
package/readme.md
CHANGED
|
@@ -1,24 +1,78 @@
|
|
|
1
1
|
# koishi-plugin-local-vitspro
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/koishi-plugin-local-vitspro)
|
|
4
|
+
[](https://www.npmjs.com/package/koishi-plugin-local-vitspro)
|
|
5
|
+
[](https://github.com/bigxingyun/koishi-plugin-local-vitspro/blob/main/LICENSE)
|
|
6
|
+
[](https://github.com/bigxingyun/koishi-plugin-local-vitspro)
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
Koishi 的多后端 TTS 聚合插件。把 `vits-simple-api`、`GPT-SoVITS v2`、`fish-audio`、`QQ 声聊` 收进同一个 `vits` 服务,供 [chatluna](https://github.com/ChatLunaLab/chatluna)、[chatluna-character](https://github.com/ChatLunaLab/chatluna-character) 直接调用。
|
|
6
9
|
|
|
7
|
-
|
|
8
|
-
2. **熔断不合理**:按「后端实测推理速度 × 本次文本长度」计算超时,失败后有限退避 + 半开探测,每次降级都有提示;
|
|
9
|
-
3. **长文本直接推理**:插件层切片(中文逗号 / 中文句号 / 英文逗号 / 英文句号 / 不切),再把音频拼回一条。
|
|
10
|
+
它重点解决三件事:
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
- **长句不被序列化格式切碎**——chatluna 传来的 `<message><voice>…</voice></message>` 会被解包成纯文本,整段合成;
|
|
13
|
+
- **超时按后端真实速度算**——用基准测速拟合「字数 → 耗时」,不同后端、不同文本长度给不同预算,而不是拍一个固定 60 秒;
|
|
14
|
+
- **后端抽风时快速降级**——有限退避 + 半开探测,降级有提示、可查状态,不会把 bot 卡住。
|
|
12
15
|
|
|
13
|
-
|
|
16
|
+
## 工作机制
|
|
17
|
+
|
|
18
|
+
### 1. 输入归一化
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
<output><message quote="123"><voice id="1">今天天气不错…</voice></message></output>
|
|
22
|
+
│ 解包容器 / 反转义 / 去 Markdown / 去元素 / 去 emoji
|
|
23
|
+
▼
|
|
24
|
+
今天天气不错…
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
`<voice id>` 会作为讲者提示;二次序列化的 `<message>` 也能还原。
|
|
28
|
+
|
|
29
|
+
### 2. 长文本切片
|
|
30
|
+
|
|
31
|
+
整段不超过 `split.maxSegmentChars`(默认 120)就不切;超过才在窗口内找**最后一个句末标点**切开:
|
|
32
|
+
|
|
33
|
+
- 支持 `zh_period`(中文句号)/ `zh_comma`(中文逗号)/ `en_period`(英文句号)/ `en_comma`(英文逗号)/ `none`(不切);
|
|
34
|
+
- 引号、括号、URL、小数、英文缩写内部不切;
|
|
35
|
+
- 过短的段并入相邻段,段数超过上限时合并尾段。
|
|
36
|
+
|
|
37
|
+
### 3. 音频聚合
|
|
38
|
+
|
|
39
|
+
多段合成后,若都是**同参数 PCM WAV**,直接拼接成一条语音;参数不一致(或 mp3 等格式)时降级为多段发送,首段作为回复、其余用 `session.send()` 补发。
|
|
40
|
+
|
|
41
|
+
### 4. 自适应超时
|
|
42
|
+
|
|
43
|
+
`vitsbench` 按长度阶梯(默认 6 / 12 / 24 字)实测后端,最小二乘拟合:
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
估算耗时 = a + b × 字数
|
|
47
|
+
超时 = clamp(overhead + factor × 估算耗时, min, max)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
拟合结果写回内存,下一条消息立即生效。也可以用 `timeout.mode = manual` 固定超时,两者是并列模式。
|
|
51
|
+
|
|
52
|
+
### 5. 熔断与降级
|
|
53
|
+
|
|
54
|
+
每个后端一份状态机:连续失败到阈值进入 `open`,冷却后只放一个探测请求(`half-open`),成功即恢复。
|
|
55
|
+
|
|
56
|
+
- `AUTH`(401/403)一次即永久熔断,`tts on` 或改配置才恢复;
|
|
57
|
+
- `BAD_REQUEST`(400/422)不熔断,只降级并记日志;
|
|
58
|
+
- 降级提示按原因 10 分钟节流;
|
|
59
|
+
- 工具路径(chatluna-character)抛 `VitsDegradeError` 让调用方用解析好的文字兜底;服务路径(chatluna 渲染器)直接回纯文本,避免整条回复被 `middleware_error` 吃掉。
|
|
14
60
|
|
|
15
61
|
## 安装
|
|
16
62
|
|
|
63
|
+
在 Koishi 控制台的「插件市场」搜索 `local-vitspro` 安装,或:
|
|
64
|
+
|
|
17
65
|
```bash
|
|
18
66
|
npm i koishi-plugin-local-vitspro
|
|
19
67
|
```
|
|
20
68
|
|
|
21
|
-
|
|
69
|
+
升级:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
npm update koishi-plugin-local-vitspro
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 最小配置
|
|
22
76
|
|
|
23
77
|
```yaml
|
|
24
78
|
plugins:
|
|
@@ -28,6 +82,7 @@ plugins:
|
|
|
28
82
|
- type: vits-simple-api
|
|
29
83
|
label: 本地
|
|
30
84
|
url: http://127.0.0.1:23456
|
|
85
|
+
autoPullSpeaker: true
|
|
31
86
|
speakers:
|
|
32
87
|
- name: 测试
|
|
33
88
|
id: 0
|
|
@@ -35,130 +90,60 @@ plugins:
|
|
|
35
90
|
languages: [ZH]
|
|
36
91
|
```
|
|
37
92
|
|
|
38
|
-
|
|
93
|
+
配好后发 `tts speakers` 确认讲者,再发 `vitsbench` 让超时模型吃到真实速度。
|
|
39
94
|
|
|
40
|
-
##
|
|
95
|
+
## 支持的后端
|
|
41
96
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
| 配置 | 默认 | 说明 |
|
|
45
|
-
| --- | --- | --- |
|
|
46
|
-
| `defaultSpeaker` | 空 | 不指定讲者时用谁;`tts speakers` 可查完整 key |
|
|
47
|
-
| `backends[]` | `[]` | 后端列表,`type` 决定字段(见下) |
|
|
48
|
-
| `split.mode` | `zh_period` | 切片模式:`none` / `zh_period` / `zh_comma` / `en_period` / `en_comma` |
|
|
49
|
-
| `split.maxSegmentChars` | `120` | 单段上限;整段文本低于该值时不会切 |
|
|
50
|
-
| `aggregate.type` | `auto` | `auto` 能拼就拼(WAV 同参数),否则多段发送 |
|
|
51
|
-
| `timeout.mode` | `auto` | `auto` 按测速模型算超时;`manual` 用固定 `timeout.manual` |
|
|
52
|
-
| `breaker.mode` | `auto` | `auto` 退避 + 半开;`manual` 固定冷却;`off` 永不熔断 |
|
|
53
|
-
| `degrade.tool` | `error` | 工具路径(character)降级时抛错,让它用解析好的文字兜底 |
|
|
54
|
-
| `degrade.service` | `text` | chatluna 渲染器路径降级时回文字(抛错会丢掉整条回复) |
|
|
55
|
-
| `toolCall.minChars` / `maxChars` | `2` / `300` | 工具调用低于/高于该字数不合成 |
|
|
56
|
-
|
|
57
|
-
**后端字段速查**
|
|
58
|
-
|
|
59
|
-
| 后端 | 必填 | 常用 |
|
|
97
|
+
| 后端 | 必填 | 说明 |
|
|
60
98
|
| --- | --- | --- |
|
|
61
|
-
| `vits-simple-api` | `url` | `
|
|
62
|
-
| `GPT-SoVITS2` | `url` | `
|
|
63
|
-
| `fish-audio` | `apiKey` |
|
|
64
|
-
| `qq-voice` | `accountId` |
|
|
65
|
-
|
|
66
|
-
讲者条目允许写任意额外字段:vits-simple-api 的 `noise` / `noise_w` / `length` / `sdp_ratio` / `preset` / `prompt_lang` / `reference_audio`,GPT-SoVITS 的 `speed` / `top_k` / `temperature` 等都会被透传。
|
|
67
|
-
|
|
68
|
-
### 文件模式
|
|
69
|
-
|
|
70
|
-
后端多、想直接改文本时,可以设 `backendsSource: file`,插件会读 `backendsFile`(默认 `data/local-vitspro/config.yml`)并在文件变化后热更新。文件结构就是 `backends[]` 的 YAML 数组。
|
|
71
|
-
|
|
72
|
-
> 文件模式只读自己的路径,**不会**读取旧插件(luna-vits / local-vits)的 `data/local-vits/`,也不提供旧配置迁移。
|
|
73
|
-
|
|
74
|
-
## 启动顺序(后端比 Koishi 启动慢)
|
|
75
|
-
|
|
76
|
-
TTS 后端经常比 Koishi 晚几十秒才监听端口,所以:
|
|
77
|
-
|
|
78
|
-
- 插件加载时会拉一次讲者;**拉不到不会把空列表当成成功**,而是标记为「未拉全」;
|
|
79
|
-
- 之后按 5s → 9s → 16s… 指数退避在后台重试,最长 2 分钟一次,拉到即停;
|
|
80
|
-
- 讲者列表还有 60s 的 TTL:后端新增了讲者,最多一分钟后自动生效;
|
|
81
|
-
- 真实消息进来时如果还没有讲者,会先强制刷新一次(5s 冷却),仍拿不到才降级为文字;
|
|
82
|
-
- 手动补拉:`tts reload` / `tts speakers`(`authority: 3`)。
|
|
99
|
+
| `vits-simple-api` | `url` | 支持 `X-API-KEY`、HTTP Basic Auth、自动拉取讲者(`/voice/speakers`) |
|
|
100
|
+
| `GPT-SoVITS2` | `url` | `/tts` v2 接口,按需切换 GPT / SoVITS 底模 |
|
|
101
|
+
| `fish-audio` | `apiKey` | 云端服务,按 `reference_id` 选音色 |
|
|
102
|
+
| `qq-voice` | `accountId` | QQ 声聊,仅群聊,依赖 OneBot |
|
|
83
103
|
|
|
84
|
-
|
|
104
|
+
讲者条目可以写任意额外参数(`noise`、`noise_w`、`length`、`sdp_ratio`、`preset`、`prompt_text`、`speed` 等),会透传给对应后端。
|
|
85
105
|
|
|
86
106
|
## 指令
|
|
87
107
|
|
|
88
108
|
| 指令 | 说明 | 权限 |
|
|
89
109
|
| --- | --- | --- |
|
|
90
|
-
| `vitspro <text>`(别名 `lunavits`) | 合成语音,`-s
|
|
91
|
-
| `vitsbench [backend]` |
|
|
110
|
+
| `vitspro <text>`(别名 `lunavits`) | 合成语音,`-s` 指定讲者 | 1 |
|
|
111
|
+
| `vitsbench [backend]` | 基准测速并写回超时模型,`-n` 次数、`-s` 讲者、`-r` 清样本、`-f` 清熔断 | 3 |
|
|
92
112
|
| `tts` | 状态:后端、讲者数、拟合参数、熔断、建议超时 | 3 |
|
|
93
|
-
| `tts on` / `tts off`
|
|
113
|
+
| `tts on` / `tts off` | 开启并清熔断 / 临时关闭语音 | 3 |
|
|
94
114
|
| `tts speakers` | 讲者列表(含 `id`),会强制重新拉取 | 3 |
|
|
95
|
-
| `tts reload` |
|
|
96
|
-
| `tts debug <text>` |
|
|
115
|
+
| `tts reload` | 立即重新拉取讲者列表 | 3 |
|
|
116
|
+
| `tts debug <text>` | 打印归一化、切片、决策与超时,不发请求 | 3 |
|
|
97
117
|
| `tts reset [backend]` | 清空测速样本与熔断状态 | 3 |
|
|
98
118
|
|
|
99
|
-
##
|
|
119
|
+
## 与 chatluna 配合
|
|
100
120
|
|
|
101
|
-
`
|
|
121
|
+
插件实现了 `@initencounter/vits` 的 `vits` 服务,chatluna 与 chatluna-character 不需要改动,直接选 `voice` / `mixed-voice` 渲染模式即可。
|
|
102
122
|
|
|
103
|
-
|
|
104
|
-
估算耗时 = a + b × 字数
|
|
105
|
-
超时 = clamp(overhead + factor × 估算耗时, min, max)
|
|
106
|
-
```
|
|
123
|
+
另外可选注册 chatluna 工具 `vits_say`(`chatlunaTool.enabled`),让模型主动把某句话变成语音。依赖全部是可选 peer + 动态 `import`,没装 chatluna 也能正常加载。
|
|
107
124
|
|
|
108
|
-
|
|
125
|
+
## 常见问题
|
|
109
126
|
|
|
110
|
-
|
|
111
|
-
基准测试:1 个后端,每档 2 次取中位
|
|
112
|
-
· 本地
|
|
113
|
-
6 字:1.2s(成功 2 次)
|
|
114
|
-
12 字:1.7s(成功 2 次)
|
|
115
|
-
24 字:2.8s(成功 2 次)
|
|
116
|
-
拟合:a=720ms b=83.0ms/字 · 样本 6 · 建议超时(60字) 10.7s · closed
|
|
117
|
-
```
|
|
127
|
+
**后端比 Koishi 启动慢,讲者列表空着**
|
|
118
128
|
|
|
119
|
-
|
|
129
|
+
不会。拉取失败会标记为「未拉全」并后台按 5s → 9s → 16s… 退避重试,最长 2 分钟一次;拉到即停,最多一分钟后还会自动刷新。也可以手动 `tts reload`。
|
|
120
130
|
|
|
121
|
-
|
|
122
|
-
- `AUTH`(401/403)一次即永久熔断,`tts on` 或改配置才恢复;
|
|
123
|
-
- `BAD_REQUEST`(400/422)不熔断,只降级;
|
|
124
|
-
- 降级时按 `notice.interval`(默认 10 分钟)给一次中文提示。
|
|
131
|
+
**没声音 / 只有文字**
|
|
125
132
|
|
|
126
|
-
|
|
133
|
+
先发 `tts` 看后端状态与熔断;`AUTH` 熔断检查账密或 API Key;再用 `tts debug <文本>` 看决策与超时。降级时会有一次中文提示(可关)。
|
|
127
134
|
|
|
128
|
-
|
|
129
|
-
- 引号 / 括号 / URL / 小数 / 英文缩写内部不切;
|
|
130
|
-
- 过短的段并入相邻段,段数超过 `split.maxSegments` 时合并尾段;
|
|
131
|
-
- 多段音频:WAV 且参数(编码/声道/采样率/位深)一致才拼接,否则 `aggregate.type=auto` 降级为多段发送(`multi` 时首段作为返回值,其余用 `session.send` 补发)。
|
|
135
|
+
**一句长话变成了好几条语音**
|
|
132
136
|
|
|
133
|
-
|
|
137
|
+
说明 WAV 参数不一致、走了多段降级。确认后端都返回同采样率 WAV,或把 `aggregate.type` 设为 `concat` 观察日志。
|
|
134
138
|
|
|
135
|
-
|
|
136
|
-
- 越界(太短 / 太长)或熔断时按 `degrade.tool` 处理,默认抛 `VitsDegradeError`(带 `code` 与已归一化的 `text`)。character 会用它解析好的文字元素兜底,所以用户看到的仍是干净文字;
|
|
137
|
-
- **chatluna 核心渲染器路径**(`outputMode = voice`):没有标记、带 `session`,走 `degrade.service`,默认回纯文本——因为这条路径抛错会被 chatluna 的 `_handleMiddlewareError` 接住并替换成 `middleware_error`,整条回复会丢;
|
|
138
|
-
- 可选注册 chatluna 工具 `vits_say`(`chatlunaTool.enabled`):装了 `koishi-plugin-chatluna` 才会注册,依赖全部动态 `import`,没装不影响加载。
|
|
139
|
+
**想用旧插件的配置**
|
|
139
140
|
|
|
140
|
-
|
|
141
|
+
不支持迁移,也不读取旧路径。直接在控制台按上面的示例配一遍,或把后端列表写成 YAML 并设 `backendsSource: file`。
|
|
141
142
|
|
|
142
|
-
|
|
143
|
-
- gradio 后端暂不支持(需要时会单开一个里程碑);
|
|
144
|
-
- 不做自动翻译(旧插件的 `autoTranslate` 未迁移);
|
|
145
|
-
- 不做音频转码:只拼 PCM WAV,mp3 等格式走多段发送;
|
|
146
|
-
- QQ 声聊依赖 OneBot 的 `send_group_ai_record`,私有实现差异较大。
|
|
143
|
+
## 来源
|
|
147
144
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
```bash
|
|
151
|
-
npm i
|
|
152
|
-
npm run typecheck # tsc --noEmit
|
|
153
|
-
npm run test # vitest(117 个用例,纯 Node,不需要 koishi 运行时)
|
|
154
|
-
npm run smoke # 构建产物 + 真实 koishi Context 冒烟(11 项)
|
|
155
|
-
npm run verify # 以上三个一起跑
|
|
156
|
-
```
|
|
157
|
-
|
|
158
|
-
> `smoke` 走 CJS:koishi 4.18 的 ESM 产物在 Node 24 下加载会因 loader 的 default 互操作失败,而 koishi 实际加载插件用的就是 CJS。
|
|
145
|
+
本项目改自 [SilverWolfHoney/koishi-plugin-local-vits](https://github.com/SilverWolfHoney/koishi-plugin-local-vits)——它是 [ChatLunaLab/luna-vits](https://github.com/ChatLunaLab/luna-vits) 的本地化改版,多后端抽象、适配器思路与指令设计都来自上游,感谢原作者。
|
|
159
146
|
|
|
160
147
|
## License
|
|
161
148
|
|
|
162
|
-
MIT
|
|
163
|
-
|
|
164
|
-
|
|
149
|
+
[MIT](./LICENSE)
|