feishu-voice-bridge 2026.3.31

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/.env.example ADDED
@@ -0,0 +1,21 @@
1
+ # 说明:
2
+ # 1. 该文件只作为变量清单示例,不会被插件自动加载。
3
+ # 2. 请通过 shell、launchd、CI Secret 或 OpenClaw 本地配置注入真实值。
4
+ # 3. 不要把真实密钥提交到仓库。
5
+
6
+ FEISHU_APP_ID=your_feishu_app_id
7
+ FEISHU_APP_SECRET=your_feishu_app_secret
8
+ FEISHU_CHAT_ID=ou_or_oc_target_id
9
+
10
+ # 可选:覆盖 OpenClaw 本地配置文件路径
11
+ OPENCLAW_JSON=/path/to/openclaw.json
12
+
13
+ # 可选:语音转写默认参数
14
+ OPENCLAW_STT_LANGUAGE=zh-CN
15
+ OPENCLAW_STT_MODEL=small
16
+
17
+ # 可选:Whisper 运行参数
18
+ WHISPER_MODEL=small
19
+ WHISPER_MODEL_DIR=/path/to/whisper-models
20
+ WHISPER_BEAM_SIZE=5
21
+ WHISPER_BEST_OF=5
package/CHANGELOG.md ADDED
@@ -0,0 +1,22 @@
1
+ # 更新日志
2
+
3
+ ## 2026.3.31
4
+
5
+ ### 原生能力对齐重构
6
+
7
+ - 重构插件内部结构,拆分为运行时探测、会话路由、状态存储、回复分发、文本清洗、摘要处理等独立模块。
8
+ - 自动语音回复继续优先复用 OpenClaw 原生 `messages.tts` 链路。
9
+ - 长文本语音回复摘要调整为“原生摘要优先,规则摘要兜底”模式。
10
+ - 飞书入站语音转写现在优先调用 OpenClaw 原生 `api.runtime.stt.transcribeAudioFile(...)`。
11
+ - 原生 TTS / STT 不可用时,仍保留脚本兜底能力。
12
+ - 继续跳过 emoji、Markdown、代码块等不适合语音朗读的内容。
13
+ - 增加运行时能力探测日志,便于确认当前是否命中 native TTS / STT / summary。
14
+ - 修复发布清单,确保打包时包含 `lib/` 与相关运行文件。
15
+ - 补充 README 与回归测试,`npm test`、`npm run check` 均已通过。
16
+
17
+ ### 早期更新
18
+
19
+ - 新增长文本语音摘要能力,避免超长回复被直接截断。
20
+ - 补充 `maxCapturedReplyChars` 与 `voiceReplySummary*` 相关配置项。
21
+ - 将项目内介绍性文档、注释和插件描述统一为中文。
22
+ - 补齐插件项目基础文件:`package.json`、`.gitignore`、`LICENSE`、`CHANGELOG.md`。
@@ -0,0 +1,57 @@
1
+ # 贡献指南
2
+
3
+ 感谢你参与维护 `feishu-voice-bridge`。
4
+
5
+ ## 开发原则
6
+
7
+ - 优先遵循 OpenClaw 官方插件机制,不修改渠道插件核心实现。
8
+ - 飞书特有逻辑尽量收敛在本插件内部。
9
+ - 文本、语音和最终用户可见回复必须尽量保持一致。
10
+ - 新增能力时,优先补测试,再补实现。
11
+
12
+ ## 本地开发
13
+
14
+ ### 环境要求
15
+
16
+ - Node.js 20 及以上
17
+ - `ffmpeg`
18
+ - `edge-tts`
19
+ - `whisper`
20
+
21
+ ### 常用命令
22
+
23
+ ```bash
24
+ npm test
25
+ npm run check
26
+ ```
27
+
28
+ ## 提交规范
29
+
30
+ - 文档、配置、代码和测试尽量同一批次提交,避免上下文割裂。
31
+ - 如果改动影响语音发送策略,请同步更新 `README.md` 和 `CHANGELOG.md`。
32
+ - 如果新增配置项,请同步更新:
33
+ - `openclaw.plugin.json`
34
+ - `README.md`
35
+ - 对应测试
36
+
37
+ ## 敏感信息要求
38
+
39
+ - 不要提交真实的 `appId`、`appSecret`、token、聊天标识或任何其他生产凭证。
40
+ - `.env.example` 只保留变量名和占位值,不写入真实配置。
41
+ - 如果需要展示日志,请先脱敏 `Authorization`、`tenant_access_token`、`file_key` 等字段。
42
+
43
+ ## 测试要求
44
+
45
+ - 修改 `index.js` 中的桥接逻辑后,至少运行一次 `npm test`。
46
+ - 修改脚本参数或帮助文本后,检查 `README.md` 中的示例是否仍然准确。
47
+ - 如果修复的是飞书语音时序问题,建议补一条对应的回归测试。
48
+
49
+ ## 发布前检查
50
+
51
+ 发布前建议确认以下事项:
52
+
53
+ 1. `npm test` 通过。
54
+ 2. `README.md` 中的配置示例与当前实现一致。
55
+ 3. `openclaw.plugin.json` 中的配置 schema 已同步更新。
56
+ 4. `CHANGELOG.md` 已记录本次版本变化。
57
+ 5. 需要的 git tag 已创建。
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alpar Wen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,308 @@
1
+ # 飞书语音桥接插件
2
+
3
+ `feishu-voice-bridge` 是一个 OpenClaw 原生插件,用于:
4
+
5
+ 1. 注册 `feishu-voice` TTS provider
6
+ 2. 注册飞书语音转写 provider
7
+ 3. 在飞书场景把最终文本回复补发为语音消息
8
+
9
+ ## 安装
10
+
11
+ 推荐方式:
12
+
13
+ ```bash
14
+ git clone git@github.com:alpar/feishu-voice-bridge.git ~/feishu-voice-bridge
15
+ openclaw plugins install ~/feishu-voice-bridge
16
+ ```
17
+
18
+ 开发场景也可以 link:
19
+
20
+ ```bash
21
+ openclaw plugins install -l ~/feishu-voice-bridge
22
+ ```
23
+
24
+ 如果你不走 `openclaw plugins install`,而是手动复制到默认扩展目录,推荐放在:
25
+
26
+ ```bash
27
+ ~/.openclaw/extensions/feishu-voice-bridge
28
+ ```
29
+
30
+ 安装后可检查:
31
+
32
+ ```bash
33
+ openclaw plugins info feishu-voice-bridge
34
+ ```
35
+
36
+ ## 依赖安装
37
+
38
+ 系统依赖:
39
+
40
+ ```bash
41
+ yum install -y ffmpeg # CentOS / OpenCloudOS
42
+ apt-get install -y ffmpeg # Ubuntu / Debian
43
+ brew install ffmpeg # macOS
44
+ ```
45
+
46
+ Python 依赖:
47
+
48
+ ```bash
49
+ python3 -m pip install edge-tts
50
+ python3 -m pip install openai-whisper # 可选
51
+ ```
52
+
53
+ 依赖检查:
54
+
55
+ ```bash
56
+ python3 --version
57
+ ffmpeg -version
58
+ ffprobe -version
59
+ edge-tts --help >/dev/null && echo "edge-tts ok"
60
+ whisper --help >/dev/null && echo "whisper ok" # 可选
61
+ ```
62
+
63
+ 脚本链路检查:
64
+
65
+ ```bash
66
+ cd ~/feishu-voice-bridge
67
+ bash scripts/send_voice.sh -t "这是一条测试语音" --no-send -o /tmp/feishu-voice-test.opus
68
+ test -f /tmp/feishu-voice-test.opus && echo "tts script ok"
69
+ ```
70
+
71
+ 如果你使用的是复制安装,也可以进入:
72
+
73
+ ```bash
74
+ cd ~/.openclaw/extensions/feishu-voice-bridge
75
+ ```
76
+
77
+ 如安装了 Whisper,可继续测试:
78
+
79
+ ```bash
80
+ bash scripts/openclaw_stt.sh /tmp/feishu-voice-test.opus
81
+ ```
82
+
83
+ ## 配置
84
+
85
+ OpenClaw 配置文件通常位于:
86
+
87
+ ```bash
88
+ ~/.openclaw/openclaw.json
89
+ ```
90
+
91
+ 必填配置只有两部分:
92
+
93
+ 1. `channels.feishu.*`
94
+ 2. `plugins.entries.feishu-voice-bridge.*`
95
+
96
+ `messages.tts.*` 是可选增强配置。
97
+
98
+ ### 最小可运行配置
99
+
100
+ 这是推荐默认示例,和你当前使用方式一致:
101
+
102
+ ```json5
103
+ {
104
+ channels: {
105
+ feishu: {
106
+ appId: "cli_xxxxxxxxxxxxx",
107
+ appSecret: "xxxxxxxxxxxxx"
108
+ }
109
+ },
110
+ messages: {
111
+ tts: false
112
+ },
113
+ plugins: {
114
+ entries: {
115
+ "feishu-voice-bridge": {
116
+ enabled: true,
117
+ config: {
118
+ voiceReplyEnabled: true,
119
+ voiceReplyMode: "inbound",
120
+ voiceReplyWindowMs: 1200000,
121
+ voiceReplyCooldownMs: 30000,
122
+ voiceReplyDebounceMs: 2500,
123
+ maxReplyChars: 280,
124
+ maxCapturedReplyChars: 6000,
125
+ voiceReplySummaryEnabled: true,
126
+ voiceReplySummaryMaxSentences: 3
127
+ }
128
+ }
129
+ }
130
+ }
131
+ }
132
+ ```
133
+
134
+ 说明:
135
+
136
+ - `messages.tts: false` 是合法配置
137
+ - 插件仍可工作,并使用自己的脚本完成语音合成
138
+ - 超长文本仍会走插件内置摘要逻辑
139
+
140
+ ### 可选:启用原生 TTS 复用
141
+
142
+ 如果你希望优先复用 OpenClaw 原生 TTS / 摘要模型,把上面的 `messages.tts` 改成:
143
+
144
+ ```json5
145
+ {
146
+ messages: {
147
+ tts: {
148
+ provider: "edge",
149
+ mode: "final",
150
+ auto: "off",
151
+ summaryModel: "openai/gpt-4.1-mini",
152
+ providers: {
153
+ microsoft: {
154
+ voice: "zh-CN-XiaoxiaoNeural",
155
+ rate: "+20%",
156
+ pitch: "0"
157
+ }
158
+ }
159
+ }
160
+ }
161
+ }
162
+ ```
163
+
164
+ 注意:
165
+
166
+ - `messages.tts: false` 和 `messages.tts: {...}` 二选一
167
+ - 不需要原生 TTS 复用时,保持 `messages.tts: false` 即可
168
+
169
+ ### 常用插件配置
170
+
171
+ ```json5
172
+ {
173
+ plugins: {
174
+ entries: {
175
+ "feishu-voice-bridge": {
176
+ enabled: true,
177
+ config: {
178
+ defaultVoice: "zh-CN-XiaoxiaoNeural",
179
+ defaultRate: "+20",
180
+ defaultPitch: "0",
181
+ voiceReplySummaryPrefix: "语音摘要:",
182
+ voiceReplySummarySuffix: "(完整内容请查看文字回复)",
183
+ promptToolTtsForText: false
184
+ }
185
+ }
186
+ }
187
+ }
188
+ }
189
+ ```
190
+
191
+ 常用字段:
192
+
193
+ - `voiceReplyEnabled`:是否启用自动语音回复
194
+ - `voiceReplyMode`:`inbound` / `always` / `off`
195
+ - `voiceReplyWindowMs`:最近一次飞书入站消息后的语音回复窗口
196
+ - `voiceReplyCooldownMs`:两次自动语音回复最小间隔
197
+ - `voiceReplyDebounceMs`:等待文本稳定后再发送
198
+ - `maxReplyChars`:最终朗读文本上限
199
+ - `maxCapturedReplyChars`:摘要前缓存文本上限
200
+ - `voiceReplySummaryEnabled`:长文本是否改为摘要朗读
201
+ - `voiceReplySummaryMaxSentences`:摘要最多保留几句
202
+
203
+ 如果没有配置 `channels.feishu.appId` 或 `channels.feishu.appSecret`,插件即使已加载,也无法发送飞书语音。
204
+
205
+ ## 生效
206
+
207
+ 修改配置后重启:
208
+
209
+ ```bash
210
+ openclaw gateway restart
211
+ ```
212
+
213
+ ## 验证
214
+
215
+ 先做本地自检:
216
+
217
+ ```bash
218
+ cd ~/feishu-voice-bridge
219
+ npm run check
220
+ npm test
221
+ ```
222
+
223
+ 如果你使用的是复制安装,也可以在 `~/.openclaw/extensions/feishu-voice-bridge` 下执行。
224
+
225
+ 再确认插件已加载:
226
+
227
+ ```bash
228
+ openclaw plugins info feishu-voice-bridge
229
+ ```
230
+
231
+ 重点看:
232
+
233
+ - 插件状态为已加载
234
+ - `speech` 中有 `feishu-voice`
235
+ - `media-understanding` 中有 `feishu-voice`
236
+ - 如果你是直接手动放入扩展目录、但没有通过 `openclaw plugins install` 建立安装记录,看到 `loaded without install/load-path provenance` 警告是正常的
237
+ - 如果你使用的是 `openclaw plugins install -l <path>`,通常应由 `plugins.load.paths` 管理,不建议把它和上面的警告视为同一种情况
238
+
239
+ ## 功能测试
240
+
241
+ 建议按顺序测试:
242
+
243
+ 1. 发一条飞书语音给机器人
244
+ 2. 确认能转写并正常回文本
245
+ 3. 确认插件额外补发了一条飞书语音
246
+ 4. 发一条超长问题,确认语音读的是摘要
247
+ 5. 发一条包含 emoji 的文本,确认语音会跳过 emoji
248
+
249
+ `voiceReplyMode: "inbound"` 下,自动语音回复只会在最近一次飞书入站消息后的窗口内触发。
250
+
251
+ ## 常见问题
252
+
253
+ - 拉了代码但没执行 `openclaw plugins install <path>`
254
+ - 插件未正确安装,或源码目录没有通过 `plugins.load.paths` 加入加载路径
255
+ - 没配置 `channels.feishu.appId` / `channels.feishu.appSecret`
256
+ - 改完配置没有重启 Gateway
257
+ - 本机缺少 `ffmpeg` / `ffprobe` / `edge-tts`
258
+ - 误以为 `.env.example` 会被自动加载
259
+
260
+ ## 排查
261
+
262
+ 建议按这个顺序排查:
263
+
264
+ ```bash
265
+ cd ~/feishu-voice-bridge
266
+ npm run check
267
+ npm test
268
+ openclaw plugins info feishu-voice-bridge
269
+ ```
270
+
271
+ 如果你使用的是复制安装,也可以改为进入 `~/.openclaw/extensions/feishu-voice-bridge` 后执行。
272
+
273
+ 如果还不对,再执行:
274
+
275
+ ```bash
276
+ openclaw status --all
277
+ ```
278
+
279
+ 再看日志关键词:
280
+
281
+ - `runtime ready: nativeTts=...`
282
+ - `feishu-voice synthesized via OpenClaw TTS`
283
+ - `feishu-voice transcribed via OpenClaw runtime`
284
+ - `feishu-voice auto reply sent`
285
+ - `feishu-voice skip auto reply: ...`
286
+
287
+ ## 安全说明
288
+
289
+ 插件运行时读取的是:
290
+
291
+ - `channels.feishu.appId`
292
+ - `channels.feishu.appSecret`
293
+
294
+ 手工调用 `scripts/send_voice.sh` 时,还会读取:
295
+
296
+ - `FEISHU_APP_ID`
297
+ - `FEISHU_APP_SECRET`
298
+ - `FEISHU_CHAT_ID`
299
+ - `OPENCLAW_JSON`
300
+
301
+ 不要把真实密钥、token、聊天标识提交进仓库。
302
+
303
+ ## 开发命令
304
+
305
+ ```bash
306
+ npm run check
307
+ npm test
308
+ ```
package/index.js ADDED
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+
3
+ const { resolvePluginConfig } = require("./lib/config");
4
+ const { loadGeneratedAudioArtifact } = require("./lib/audio");
5
+ const { createPluginRuntime, logRuntimeReadiness } = require("./lib/runtime");
6
+ const {
7
+ extractAssistantTextFromAgentMessage,
8
+ extractMessageSentText,
9
+ mergeVoiceReplyCandidate,
10
+ prepareVoiceReplyText
11
+ } = require("./lib/text");
12
+ const { buildMediaUnderstandingProvider, buildProvider } = require("./lib/providers");
13
+ const { registerVoiceReplyHooks } = require("./lib/voice-reply-hooks");
14
+
15
+ // 入口文件只负责组装插件,复杂逻辑拆到 lib/ 下,便于后续单独维护和测试。
16
+ const plugin = {
17
+ id: "feishu-voice-bridge",
18
+ name: "飞书语音桥接插件(STT + TTS)",
19
+ description: "OpenClaw 原生飞书语音桥接插件,提供本地 STT、TTS 与官方语音链路兼容能力。",
20
+ register(api) {
21
+ const cfg = resolvePluginConfig(api);
22
+ cfg.runtime = createPluginRuntime(cfg, api.runtime || null);
23
+ logRuntimeReadiness(cfg.runtime, api.logger);
24
+ api.registerSpeechProvider(buildProvider(cfg, api.logger, cfg.runtime));
25
+ api.registerMediaUnderstandingProvider(buildMediaUnderstandingProvider(cfg, api.logger, cfg.runtime));
26
+ registerVoiceReplyHooks(api, cfg);
27
+ }
28
+ };
29
+
30
+ module.exports = plugin;
31
+ module.exports.default = plugin;
32
+ module.exports.__private = {
33
+ extractAssistantTextFromAgentMessage,
34
+ extractMessageSentText,
35
+ loadGeneratedAudioArtifact,
36
+ mergeVoiceReplyCandidate,
37
+ prepareVoiceReplyText,
38
+ registerVoiceReplyHooks
39
+ };