UNlawrence/hermes-weixin-voice

GitHub: UNlawrence/hermes-weixin-voice

Hermes 微信 Agent 的双向语音 I/O 层,结合神经 STT/TTS 与腾讯 SILK_V3 编解码实现语音消息的收发,并附带对 iLink Bot 出站语音渲染问题的实证分析。

Stars: 1 | Forks: 0

# Hermes Weixin 语音 `hermes-weixin-voice` 是 Hermes 微信 agent 的双向语音 I/O 层:它让 agent 能够**听到**传入的微信语音消息,并**说出**回复发送到聊天中。 它是一个本地 Python 包,将神经 TTS、神经 STT、腾讯 SILK_V3 codec 以及 iLink bot 传输协议结合到一个单一的 pipeline 中。它还通过证据记录了公共 iLink bot 路径在何处停止渲染出站*原生*语音气泡,以及剩余的选项有哪些。 ## 它的功能 ``` ┌──────────────────────── inbound (STT) ────────────────────────┐ WeChat voice message → SILK_V3 → 16 kHz PCM → faster-whisper → text └───────────────────────────────────────────────────────────────┘ ┌──────────────────────── outbound (TTS) ───────────────────────┐ agent reply text → Piper (local) | edge-tts (cloud, free) → 24 kHz PCM → SILK_V3 (Tencent) ↓ AES-128-ECB ↓ iLink CDN upload ↓ ITEM_VOICE / ITEM_FILE send └───────────────────────────────────────────────────────────────┘ ``` ### 端到端演示(真实输出) ``` $ python -c "..." # synthesize → encode → transcribe round trip IN: 今天天气真好,我们一起去公园散步吧 OUT: 今天天氣真好,我們一起去公園散步吧。 duration_ms: 3900 ``` 相同的 TTS 路径会生成一个结构有效的腾讯 SILK_V3 文件(`\x02#!SILK_V3` 魔数,~24 kHz,持续时间与播放匹配),iLink 层可以将其上传并发送到目标 wxid。 ## 状态 | 功能 | 状态 | 备注 | |---|---|---| | **TTS**(文本 → 语音) | ✅ 已验证 | Piper(本地,ONNX)或 edge-tts(Microsoft 云,免费)→ 24 kHz 单声道 → SILK_V3 腾讯变体 | | **STT**(语音 → 文本) | ✅ 已验证 | SILK / WAV / MP3 → faster-whisper(`base`, int8, CPU) | | **微信文件附件发送** | ✅ 已验证 | `ITEM_FILE` 端到端到达目标聊天 | | **微信原生语音气泡** | ⚠️ 未解决 | `ITEM_VOICE` API 调用成功,但个人微信客户端无法渲染 — 见[分析](#engineering-findings) | | **Doctor / 本地诊断** | ✅ 已验证 | ffmpeg、base URL、token、context token 预检 | 测试套件:`27 passed, 1 skipped`(跳过的是一个受网络限制的 TTS 测试,可通过 `HV_RUN_NETWORK_TESTS=1` 运行)。 ## 快速开始 macOS: ``` git clone https://github.com/UNlawrence/hermes-weixin-voice-clean.git hermes-voice cd hermes-voice ./install.command # or: ./scripts/install.sh ``` 安装程序会: - 如果缺失,则安装 `uv` - 如果可用,则通过 Homebrew 安装 `ffmpeg` - 安装 `hermes-voice`、`hermes-voice-doctor` 和 `hermes-voice-stt` 命令 - 将 Hermes 技能复制到 `~/.hermes/skills/hermes-voice` 在安装过程中,系统会提示您选择一个 Piper TTS 语音模型(默认:`zh_CN-huayan-medium`,约 63 MB)。首次调用 STT 会从 HuggingFace 下载 faster-whisper `base` 模型(约 145 MB)。这两个缓存都是本地的 — 首次安装后,agent 将**完全离线**运行。 要再次运行设置或稍后更改语音: ``` UV_CACHE_DIR=.uv-cache uv run hermes-voice-setup ``` ## 命令 ### TTS — 发送合成的回复 ``` UV_CACHE_DIR=.uv-cache uv run hermes-voice wxid_xxx "今天天气真好" ``` 输出:合成文本,编码为 SILK_V3,通过 iLink 上传,并打印 `{msg_id, duration_ms, silk_size, silk_md5, cleaned_text}`。 ### STT — 转录音频文件 ``` UV_CACHE_DIR=.uv-cache uv run hermes-voice-stt /path/to/voice.silk --language zh ``` 通过 header 字节自动检测 SILK;否则将文件交给 ffmpeg 处理(支持 WAV/MP3/M4A/OGG 等格式)。 ### 生成真实的 `.silk` 测试文件 ``` UV_CACHE_DIR=.uv-cache uv run python scripts/generate_test_silk.py \ --text "这是一条测试语音" --keep-wav ``` 打印 `md5`、`first16_hex`、`duration_ms`。适用于独立于网络路径调试 SILK encoder。 ### Doctor — 检查本地前置条件 ``` UV_CACHE_DIR=.uv-cache uv run hermes-voice-doctor UV_CACHE_DIR=.uv-cache uv run hermes-voice-doctor wxid_xxx ``` 检查 ffmpeg、iLink base URL、token、Hermes 账户配置,以及可选地检查目标 wxid 是否存在 context token。 ### 文件附件回退(验证可靠) ``` UV_CACHE_DIR=.uv-cache uv run hermes-voice wxid_xxx \ --send-audio-file /tmp/voice.wav ``` 将音频作为 `ITEM_FILE` 发送。这是目前可靠的交付形态 — 请参阅下方的调查结果。 ## Programmatic API ``` import asyncio from hermes_voice import ( send_voice_from_text, # TTS → SILK → iLink send transcribe, # SILK/WAV/MP3 bytes → text ) async def main(): # Outbound result = await send_voice_from_text("你好,我是 Hermes", "wxid_xxx") print(result.msg_id, result.duration_ms) # Inbound voice_bytes = open("/path/to/wechat_voice.silk", "rb").read() text = await transcribe(voice_bytes, language="zh") print(text) asyncio.run(main()) ``` ## 工程调查结果 本项目用于追踪通过公共 iLink bot 基础设施的个人微信账号的完整出站语音路径。完整的说明在 [WEIXIN_VOICE_ANALYSIS.md](WEIXIN_VOICE_ANALYSIS.md) 中;简短版本如下: 1. **本地编码是正确的。** 生成的 `.silk` 文件具有有效的腾讯 `SILK_V3` header、预期的持续时间以及稳定的 size/md5。 2. **原生语音 payload 是正确的。** 包含 `voice_item.media` 的 AES-128-ECB 密文的 `ITEM_VOICE` 请求通过 iLink CDN 顺利上传;`sendmessage` 返回 `ret=0`。 3. **个人微信客户端仍然无法渲染它。** 一项受控的 A/B 测试(标记文本 + 立即发送语音)显示文本已到达,而语音并未出现在接收者的客户端中。 4. **`ITEM_FILE` 音频附件确实可以到达。** 相同的媒体字节,相同的目标,不同的 `item.type` — 每次都能交付。 简化结论:在公共 iLink bot 路径上的 `ITEM_VOICE` 在 API 层被接受,但目前个人微信客户端无法渲染。音频文件附件路径是目前经过验证的可靠形态。 ## 路线图 / 待验证假设 这些是值得测试的剩余假设: 1. 公共 iLink bot 出站 `ITEM_VOICE` 被 API 基础设施接受,但在个人客户端渲染之前被过滤。 2. 公共参考实现暴露了语音 payload schema,但不保证支持个人客户端交付。 3. 可能需要额外的私有/内部字段才能真正支持出站语音气泡。 4. 如果产品需求严格界定为“微信语音气泡”,目前最可信的剩余路径是微信客户端自动化:驱动官方客户端自行录制并发送音频。 ## 配置 优先级顺序: 1. `.env` 中的 `HV_*` 值 2. `~/.hermes/weixin/accounts/*.json` 中的本地 Hermes Weixin 账户配置 3. 回退默认值 `.env` 示例: ``` HV_ILINK_BASE_URL=http://127.0.0.1:8080 HV_ILINK_TOKEN= # TTS 引擎:"piper"(本地,离线)或 "edge"(Microsoft 云端,免费,无需 key)。 HV_TTS_ENGINE=piper # Piper 配置(当 HV_TTS_ENGINE=piper)。由 `hermes-voice-setup` 设置。 HV_TTS_MODEL_PATH= # edge-tts 配置(当 HV_TTS_ENGINE=edge) HV_TTS_VOICE=zh-CN-XiaoxiaoNeural HV_TTS_RATE=+0% HV_TTS_PITCH=+0Hz # STT(本地 faster-whisper,完全离线) HV_STT_MODEL=base # tiny / base / small / medium / large-v3 HV_STT_COMPUTE_TYPE=int8 # int8 / int8_float16 / float16 / float32 HV_STT_DEVICE=cpu # cpu / cuda / auto ``` 如果您已经使用 Hermes Weixin,iLink 字段将从现有账户配置中自动加载;通常您不需要手动填写它们。 ## 开发 ``` UV_CACHE_DIR=.uv-cache uv run pytest ``` `slow` 标记涵盖了 STT 往返测试(TTS → SILK → STT),该测试会在首次运行时下载 Whisper 模型。 ## 范围 此代码库是: - Hermes 微信 agent 的可用双向语音 I/O 层 - 可复现的 SILK / iLink 实验环境 - 基于证据的分析,说明公共 iLink bot 出站语音交付目前在个人微信客户端上的停止点 它**不是**一个即插即用的原生语音气泡发送器 — 该路径仍未解决,上文的文档解释了原因。 ## 许可证 MIT — 请参阅 [LICENSE](LICENSE)。
标签:CNCF毕业项目, Python, 人工智能, 安全规则引擎, 微信机器人, 无后门, 用户模式Hook绕过, 语音合成, 语音识别, 逆向工具, 音频编解码