一个轻量、常驻本地的 Windows 与 macOS 语音桥接器。它监听 Codex 正在写入的可见消息,可选择 StepFun 或 Mosi 合成语音,并在播报期间暂停支持的音乐应用,结束后恢复播放。
Note
这是一个非官方社区项目。它不会修改 Codex,也不会读取或朗读内部推理、工具输出和用户输入。
长时间和 AI 协作时,人不应该一直盯着窗口确认任务有没有进展。Codex Voice Companion 把重要消息主动念出来,让你可以继续写作、思考或听音乐:
- 可选择朗读阶段性进度、最终完成消息,或两者都读。
- 同一条 Codex 消息即使同时出现为两种 JSONL 记录,也只会播报一次。
- Fork 新任务时会跳过从父任务复制的历史,只朗读 fork 后新增的消息。
- 超过 150 字的完成消息可先由 StepFun 压缩成 100~150 字的口语摘要。
- StepFun 与 Mosi 两条 TTS 链路可通过一个配置项切换,未启用的链路不会被调用。
- Windows 可暂停系统媒体会话;macOS 可暂停 Apple Music、Spotify 等支持脚本控制的应用。
- 支持音色、音量增益和
0.5×~2.0×本地播放速度。 - 登录 Windows 或 macOS 后自动启动,无需管理员权限。
- 消息严格排队,避免多条语音互相重叠。
- 没有可用扬声器或耳机时,在摘要与语音 API 之前跳过播报,避免无效消耗。
- API Key、个人音色和试听音频默认不进入 Git。
flowchart LR
A["Codex 可见消息"] --> B["本地只读监听"]
B --> C["清理 Markdown 与敏感文本"]
C --> D["StepFun 压缩长完成消息"]
D --> E["StepFun / Mosi TTS 合成"]
E --> F["暂停支持的媒体"]
F --> G["系统原生播放器播报"]
G --> H["恢复原媒体"]
- Windows 10/11,或 macOS 12 及以上版本(Intel / Apple Silicon)
- Node.js 20 或更高版本
- Codex Desktop 或 Codex CLI,并存在 Codex session 目录
- 至少选择一个语音提供方:StepFun Step Plan 或 Mosi Platform
- 使用 Mosi 时需要 Mosi API Key 与 ready 状态音色;使用 StepFun 时需要 Step Plan API Key
项目没有第三方 npm 依赖,克隆后即可运行。
Windows PowerShell:
git clone https://github.com/YunfanGoForIt/codex-tts.git
cd codex-tts
Copy-Item .env.example .env
Copy-Item tts.config.example.json tts.config.jsonmacOS Terminal:
git clone https://github.com/YunfanGoForIt/codex-tts.git
cd codex-tts
cp .env.example .env
cp tts.config.example.json tts.config.json在 macOS 上,建议克隆到 ~/Developer 等普通目录,避免将长期运行的 LaunchAgent 放在受额外隐私保护的 Desktop、Documents 或 iCloud Drive 目录中。
默认模板使用 Mosi。若要使用 StepFun,在 .env 中设置:
TTS_PROVIDER=stepfun
STEPFUN_API_KEY=your_stepfun_api_key
STEPFUN_TTS_MODEL=stepaudio-2.5-tts
STEPFUN_TTS_VOICE=yuanqishaonv也可以继续使用原来的 Mosi 链路:
TTS_PROVIDER=mosi
MOSI_API_KEY=your_api_key
MOSI_VOICE_ID=your_voice_id然后依次检查环境、试听和启动:
npm run doctor
npm run speak -- "Codex 语音陪伴已连接"
npm startnpm start 会在当前窗口持续运行并显示结构化日志。若要隐藏窗口后台运行:
npm run start:background下面的命令会安装当前用户级自启动项,并立即启动服务:
npm run install:autostart不同系统写入的位置:
| 系统 | 自启动机制 | 位置 |
|---|---|---|
| Windows | 当前用户注册表 Run 项 | HKCU\Software\Microsoft\Windows\CurrentVersion\Run\CodexMosiTTS |
| macOS | 当前用户 LaunchAgent | ~/Library/LaunchAgents/io.github.yunfangoforit.codex-tts.plist |
不需要管理员权限。停止服务或彻底移除自启动:
npm run stop
npm run uninstall:autostartmacOS 13 及以上版本可能会在“系统设置 → 通用 → 登录项”中显示该后台项目。npm run stop 只停止本次运行,保留自启动配置;下次登录仍会恢复。npm run uninstall:autostart 才会删除配置。
推荐默认只朗读最终完成消息,减少工作过程中的打断:
{
"speakCommentary": false,
"speakFinalAnswer": true
}若希望阶段性进度也播报,将 speakCommentary 改为 true。修改 tts.config.json 后重启后台服务生效:
npm run stop
npm run start:backgroundWindows 后台启动会保留 PID 文件中登记的唯一实例,并自动停止同一项目遗留的旧实例;即使旧版本升级前没有登记 PID,也不会继续与新版同时播报。直接运行 npm start 时,跨平台运行锁会拒绝第二个实例。
也可以在 .env 中设置。TTS_PHASES 的优先级最高:
# 只读最终消息
TTS_PHASES=final_answer
# 或同时读取进度与最终消息
# TTS_PHASES=commentary,final_answer默认开启最终消息压缩。超过 150 字时,程序会先调用 StepFun 文字模型,只保留任务结果、关键改动、验证状态和必要限制,再交给当前启用的 TTS 提供方合成;短消息不会被扩写。
可以把 Key 直接放在 .env:
STEPFUN_API_KEY=your_stepfun_api_key
STEPFUN_CHAT_MODEL=step-3.7-flash
TTS_SUMMARIZE_FINAL=true
TTS_FINAL_SUMMARY_MIN_CHARS=100
TTS_FINAL_SUMMARY_MAX_CHARS=150也可以让程序读取另一个本地密钥文件,避免复制 Key:
STEPFUN_SECRET_FILE=C:\path\to\StepfunAI.txt密钥文件支持 StepPlan-api-key=... 或 STEPFUN_API_KEY=...。StepFun 超时、限流、返回异常或没有配置 Key 时,会自动改用本地截取式摘要,并继续保证不超过 150 字,不会恢复朗读整篇长消息。
单独测试压缩链路:
npm run summarize -- "这里放一段较长的任务完成消息"TTS_PROVIDER 或 tts.config.json 中的 ttsProvider 可以设为 stepfun 或 mosi。切换后重启后台服务即可;另一条实现与配置会完整保留,但不会收到合成请求。
{
"ttsProvider": "stepfun",
"stepfunTtsModel": "stepaudio-2.5-tts",
"stepfunTtsVoice": "yuanqishaonv",
"stepfunTtsInstruction": "自然、轻快、温暖,像可靠的年轻女性助手,清晰播报任务结果,不过度夸张。",
"stepfunTtsSpeed": 1.0,
"stepfunTtsVolume": 1.0
}StepFun TTS 使用 Step Plan 的 /step_plan/v1/audio/speech,输出 48 kHz WAV,并启用适合播报的增强文本归一化。服务端语速默认保持 1.0;项目现有的 playbackRate 仍负责最终播放倍速,避免两次倍速相乘。
列出账户可用音色:
npm run voices该命令会按当前提供方列出音色。Mosi 返回账户音色;StepFun 返回项目内置的官方音色清单。将 ID 写入 MOSI_VOICE_ID 或 STEPFUN_TTS_VOICE,也可以写入本地 tts.config.json。环境变量优先于本地 JSON 配置。
{
"ttsProvider": "stepfun",
"stepfunTtsVoice": "yuanqishaonv",
"playbackGainDb": 4,
"playbackRate": 1.2,
"speakCommentary": false,
"speakFinalAnswer": true
}playbackRate:本地播放倍速,范围0.5~2.0,无需 TTS 服务端支持。playbackGainDb:数字增益,范围-12~+12 dB,带峰值保护。- Windows 自动选择 PowerShell 原生播放器;macOS 使用系统自带的
afplay。两端均支持倍速。 - 增益只影响 TTS 音频,不会修改系统或音乐应用的音量。
当前批量试听命令保留原有 Mosi 账户音色工作流;StepFun 官方音色可先用 npm run voices 查看,再逐个修改 STEPFUN_TTS_VOICE 并运行 npm run speak。Mosi 的真实 voice ID 属于个人配置,因此仓库只提供模板。先创建本地清单:
Windows:
Copy-Item voice-samples.config.example.json voice-samples.config.jsonmacOS:
cp voice-samples.config.example.json voice-samples.config.json填入想对比的音色后运行:
npm run samples程序会为每个音色生成统一文案的 WAV、试听清单和播放列表,默认保存到 voice-samples/。该目录与本地清单均已被 .gitignore 排除。
也可以显式传入清单和输出目录:
npm run samples -- ./my-voices.json ./voice-samples/my-comparison配置优先级为:进程环境变量 → .env → tts.config.json → 内置默认值。
| 配置项 | 默认值 | 说明 |
|---|---|---|
TTS_PROVIDER |
mosi |
当前语音合成提供方:stepfun 或 mosi |
MOSI_API_KEY |
无 | Mosi API Key;也兼容 MOSI-API-KEY |
MOSI_VOICE_ID |
自动选择 | 指定音色 ID |
MOSI_VOICE_NAME |
无 | 按名称匹配音色 |
MOSI_MODEL |
moss-tts |
合成模型 |
TTS_SPEAK_COMMENTARY |
true |
是否朗读阶段性消息 |
TTS_SPEAK_FINAL_ANSWER |
true |
是否朗读最终完成消息 |
TTS_PHASES |
未设置 | 直接指定 commentary、final_answer 或两者 |
TTS_THREAD_SOURCES |
user,automation |
监听普通任务和 Codex 自动化任务 |
TTS_SUMMARIZE_FINAL |
true |
是否压缩超过上限的最终消息 |
TTS_FINAL_SUMMARY_MIN_CHARS |
100 |
长完成消息的目标最短字数 |
TTS_FINAL_SUMMARY_MAX_CHARS |
150 |
最终播报正文的最大字数 |
STEPFUN_API_KEY |
无 | StepFun API Key;也可改用本地密钥文件 |
STEPFUN_SECRET_FILE |
无 | 包含 StepFun Key 的本地文件路径 |
STEPFUN_CHAT_MODEL |
step-3.7-flash |
完成消息压缩模型 |
STEPFUN_TTS_MODEL |
stepaudio-2.5-tts |
StepFun 语音合成模型 |
STEPFUN_TTS_VOICE |
yuanqishaonv |
StepFun 官方或自定义音色 ID |
STEPFUN_TTS_INSTRUCTION |
自然、轻快、温暖 | StepAudio 2.5 全局表达指令,最多 200 字 |
STEPFUN_TTS_SPEED |
1.0 |
StepFun 服务端语速,范围 0.5~2.0 |
STEPFUN_TTS_VOLUME |
1.0 |
StepFun 服务端音量,范围 0.1~2.0 |
STEPFUN_TTS_TEXT_NORMALIZATION |
enhanced |
standard 或更适合播报的 enhanced |
STEPFUN_TTS_SAMPLE_RATE |
48000 |
8000 / 16000 / 22050 / 24000 / 48000 |
TTS_MAX_CHARS_PER_REQUEST |
500 |
长消息分段长度 |
TTS_REQUIRE_AUDIO_OUTPUT |
true |
没有活动音频输出设备时跳过摘要和语音 API |
TTS_AUDIO_OUTPUT_CACHE_MS |
2000 |
音频设备状态的短期缓存时间 |
TTS_AUDIO_OUTPUT_CHECK_TIMEOUT_MS |
3000 |
单次系统音频端点检测超时 |
TTS_PAUSE_OTHER_MEDIA |
true |
播报时暂停其他媒体 |
TTS_MEDIA_PAUSE_MAX_MS |
900000 |
异常情况下恢复媒体的保护时间 |
TTS_PLAYBACK_GAIN_DB |
4 |
TTS 音频增益,范围 -12~+12 |
TTS_PLAYBACK_RATE |
1.0 |
本地播放速度,范围 0.5~2.0 |
TTS_PLAYER |
auto |
auto / powershell / python / afplay / none |
TTS_MACOS_MEDIA_APPS |
Music、Spotify | macOS 上尝试暂停的可脚本控制应用标识,以逗号分隔 |
TTS_LOG_LEVEL |
info |
debug / info / warn / error |
完整示例见 .env.example 和 tts.config.example.json。
- API Key 只从环境变量或本地
.env读取,日志不会记录 Key。 - 发送前会移除代码块、URL、Markdown 噪音和记忆引用,并遮蔽常见密钥、Bearer Token 与密码字段。
- 日志只记录消息类型、字数、耗时和错误代码,不记录消息原文或会话 ID。
- Codex 会话文件始终留在本机,本项目以只读方式监听它们。
- 为完成语音合成,经过清理的可见消息文本只会发送到当前选中的 StepFun 或 Mosi TTS;停用的提供方不会收到请求。
- 开启 AI 压缩并配置 StepFun Key 后,较长的最终消息会先发送到 StepFun 文字模型;使用 StepFun TTS 时,压缩后的文本还会发送到 StepFun 语音接口。
- StepFun Key 可从另一个本地文件动态读取;Key 和文件内容不会进入日志。
- 临时 WAV 位于系统临时目录下的
codex-mosi-tts,播放后删除;崩溃遗留文件会在下次启动时清理。 .env、tts.config.json、.runtime/、voice-samples/和常见音频文件默认不会提交到 Git。
Codex 尚未将本地 session JSONL 定义为稳定公开接口。本项目兼容当前常见的 event_msg 与备用 response_item 事件形状,并会跨形状去重;未来 Codex 更新后若不再播报,可能需要同步调整监听器。
| 能力 | Windows | macOS |
|---|---|---|
| 播放 | PowerShell 原生媒体接口;原速时可选 Python winsound |
系统 /usr/bin/afplay |
| 倍速 | 0.5×~2.0× |
0.5×~2.0× |
| 暂停其他媒体 | Windows Global System Media Transport Controls,可覆盖多数浏览器和音乐应用 | Automation,默认支持 Apple Music 与 Spotify |
| 登录自启动 | HKCU Run | launchd LaunchAgent |
两端都只恢复本程序确实暂停的来源。macOS 第一次控制 Music 或 Spotify 时会显示 Automation 授权提示;请点击“允许”,之后可在“系统设置 → 隐私与安全性 → 自动化”中调整。
macOS 没有供普通命令行程序使用的稳定公开全局媒体会话控制接口,因此当前版本不会盲目发送播放/暂停媒体键。Chrome、Safari 中的网易云音乐等网页声音可以正常与 TTS 同时播放,但暂时不会自动暂停。TTS_MACOS_MEDIA_APPS 可以加入其他实现 player state、pause、play AppleScript 接口的应用标识。
Important
Windows 路径已做真实端到端运行验证;macOS 路径已通过自动化的平台模拟、播放命令、配置和 LaunchAgent 生成测试,但本仓库的当前开发环境不是 Mac。首次在 MacBook 安装后请先运行 npm run doctor 与 npm run speak 完成设备侧验收。
先运行:
npm run doctor
npm run check后台日志位于:
.runtime/bridge.log
.runtime/bridge-error.log
常见情况:
Mosi API key is missing:当前TTS_PROVIDER=mosi,请配置 Mosi Key,或切换为stepfun。StepFun API key is missing:当前TTS_PROVIDER=stepfun,请配置STEPFUN_API_KEY或STEPFUN_SECRET_FILE。- 找不到 ready 音色:访问 Mossland 音色库,再设置
MOSI_VOICE_ID。 - 摘要显示
local_fallback:检查STEPFUN_API_KEY或STEPFUN_SECRET_FILE;程序仍会用本地摘要继续播报。 - 一条消息先摘要、后全文播报:通常是升级前的旧进程仍在监听。运行
npm run stop后再运行npm run start:background;Windows 脚本会停止该项目的全部 bridge 实例并只启动一个。 - Fork 后从头重播父任务历史:请更新到
0.4.1或更高版本,并重启后台服务。 - 能合成但没有声音:检查系统默认输出设备,并运行
npm run speak单独测试播放。 - Windows 音乐没有暂停:确认应用能出现在系统媒体控制面板中。
- macOS Music/Spotify 没有暂停:在“系统设置 → 隐私与安全性 → 自动化”中允许 Terminal 或 Node 控制对应应用。
- macOS 自启动报错:确认项目不在受保护或同步中的目录,并重新执行
npm run install:autostart。 - macOS 更新或重新安装 Node.js 后自启动失效:LaunchAgent 保存了 Node 的绝对路径,请重新执行
npm run install:autostart。 - 重启后没有自动运行:重新执行
npm run install:autostart,并查看.runtime/bridge-error.log。
codex-tts/
├─ src/ # 监听、文本清理、StepFun/Mosi 客户端与播放队列
├─ scripts/ # 后台运行、自启动、媒体控制与音色试听
├─ test/ # Node.js 单元测试
├─ .env.example # 环境变量模板
├─ tts.config.example.json # 本地偏好模板
└─ README.md
MIT © 2026 YunfanGoForIt