前一天,我刚写完一篇关于 ChatGPT 和 Codex 任务完成提示音的文章。
当时的结论其实很明确:
- Codex 改用 CLI 后,任务完成提示音正常;
- Firefox 里的
Reply Chime测试音可以正常播放,但真实 ChatGPT 回复完成后没有声音; ChatGPT Done Sound by MAXIOL LTD反而能在真实回复结束后响一声,所以我暂时把它作为 ChatGPT 的提示音方案。
甚至因为第一次测试效果不错,我还给 ChatGPT Done Sound by MAXIOL LTD 留了 5 星评价。
但只过了一天,我就发现:
这个结论下得太早了。
继续在多个 ChatGPT 标签页里跑长任务以后,我遇到了新的问题。接着,我甚至自己写了一个 Firefox 扩展,希望彻底解决它。
结果折腾了一圈以后,我最后又回到了最开始测试过的 Reply Chime。
这篇文章就是上一篇的后续,也算是一次很完整的“先选第三方扩展 → 不满意 → 自己造轮子 → 发现问题比想象中复杂 → 再回到第三方扩展”的过程记录。
MAXIOL 最大的问题不是功能少,而是会误报“完成”
一开始我对 ChatGPT Done Sound by MAXIOL LTD 的印象其实不错。
它至少解决了上一篇文章里最直接的问题:
ChatGPT 的真实回复结束以后,Firefox 能发出提示音。
和当时完全不响的 Reply Chime 相比,这已经足够让我觉得它“能用”。
但继续使用后,我发现了一个更严重的问题:
有时候 ChatGPT 的回复明明还没有真正结束,它就已经提前播放了“完成”提示音。
这和“声音太频繁”不是一回事。
如果只是每个短回复都响,最多有点烦;但如果提示音会把一个仍在生成中的回复判断为“已完成”,那这个提示就失去了可信度。
我的实际工作流里,经常同时开着多个 ChatGPT 会话:
- 一个会话在生成几十个 TranslationUnit;
- 一个会话在做独立审核;
- 一个会话在处理 revision;
- 另一个会话可能还在跑长时间的分析。
提示音存在的意义,就是让我不用不停切换标签页检查状态。
可一旦声音会提前响,我听到提示以后仍然必须回去确认:
到底是真的完成了,还是又误报了?
这样一来,提示音反而不能帮我节省注意力。
所以我觉得,之前直接给 5 星确实有点草率。
我后来决定修改那条评价,重点也不再是“功能比较简单”,而是明确说明:
它存在 premature completion alert,也就是回复还没结束就提前发出完成提示的问题。
对于这种工具,我现在更看重的不是“能不能响”,而是:
响的时候到底准不准。
既然第三方扩展不稳定,那就自己写一个
既然需求并不复杂,我一度觉得:
不就是检测 ChatGPT 回复完成,然后响一声吗?自己写一个应该很简单。
于是我做了一个自己的 Firefox 扩展:
ChatGPT Response Sound
第一版思路很直接:
监听页面上的 ChatGPT 完成通知。
当新的 Sonner toast 出现,并且 data-mounted="true"、data-visible="true" 时,就播放一个短提示音。
这样做有一个好处:
我不需要自己猜模型到底什么时候生成完,而是直接利用 ChatGPT Web 自己已经出现的“完成通知”。
理论上,这应该比盯着“停止生成”按钮、消息 DOM 或流式状态更可靠。
一开始看起来也确实如此。
但真正打开多个 ChatGPT 标签页以后,事情开始变得复杂。

同一个完成事件,可能会出现在多个 ChatGPT 标签页
我很快发现一个之前没有意识到的现象:
当某一个 ChatGPT 会话完成以后,完成通知不一定只出现在那个真正完成回复的页面。
在多个已经打开的 ChatGPT 标签页中,同一个通知可能被同步到其他页面。
这意味着,如果每个标签页都单独监听页面上的 toast,那么一次真正的任务完成,有可能变成:
多个标签页同时检测到通知,然后多个标签页各自响一次。
Firefox 顶部甚至会同时出现多个正在播放音频的图标。
这显然不是我想要的。
我真正想要的是:
同一个完成事件,在整个 Firefox 里只响一次。
于是扩展开始从一个很简单的 content script,变成需要跨标签页协调的实现。
为了“只响一次”,我加了 background 仲裁
后来的版本里,我增加了 background script。
新的流程大致变成:
- 每个 ChatGPT 标签页继续负责检测完成 toast;
- 检测到以后,不直接播放声音;
- 先把事件发送给扩展 background;
- background 对同一个完成事件去重;
- 整个 Firefox 实例只选择一个标签页播放声音。
为了识别“是不是同一个事件”,我还尝试了:
- 从 toast 中提取 conversation URL;
- 使用 conversation ID 作为事件 key;
- 找不到 conversation 时,对通知文本做 hash;
- 给最近事件设置短时间去重窗口。
版本也一路推进到了 0.1.3。

从工程实现上看,这已经比最开始复杂很多了。
而且“同一个通知响很多次”的问题确实有机会解决。
但新的问题马上又出现了。
只响一次还不够,还要响在正确的标签页
我希望声音最好从真正完成回复的那个标签页播放。
原因非常实际:
Firefox 会在正在播放声音的标签页上显示一个小喇叭图标。
如果我同时开了六七个 ChatGPT 会话,只要听到提示音,再看哪个标签页出现喇叭图标,就能马上知道:
原来是这个任务完成了。
这是一个非常好用的定位方式。
所以 background 去重以后,我又继续做声音路由:
- 如果通知里能识别出 conversation URL,就把声音送到对应 conversation 的标签页;
- 如果没有 URL,就尝试用通知文本匹配每个标签页的标题;
- 实在无法定位时,才回退到最先报告这个事件的标签页。
模拟测试是能通过的。
但真实使用时,问题还是出现了。
有一次:
- 第 1 个标签页的回复已经完成;
- 第 2 个标签页还在继续生成;
- 结果声音却从第 2 个标签页播放。

也就是说:
跨标签页去重可能做到了,但“哪个页面才是真正完成的页面”仍然没有被稳定识别。
到了这里,我已经意识到,这个问题远没有最开始想象的那么简单。
我甚至开始怀疑,多标签页 DOM 监听会不会影响浏览器性能
开发测试期间,我还遇到了另一个主观感受:
Firefox 好像比平时更卡了一些。
我不能确认这一定是自己写的扩展造成的,所以这里不能把两者直接画等号。
但我的扩展会在每一个 chatgpt.com 标签页上运行 MutationObserver,监听页面 subtree 的 DOM 变化。
而 ChatGPT 在流式生成过程中,本身就会持续更新 DOM。
当我同时打开很多 Generation、Reviewer 和其他会话时,相当于很多页面都在执行这套监听。
理论上,这确实存在额外开销的可能。
不过我没有继续做性能 profiling。
原因也很简单:
这个扩展本来只是为了节省时间,如果为了维护一个提示音扩展继续投入越来越多时间,就有点本末倒置了。
所以我决定先停下来。
这时我重新想到了 Reply Chime
其实最开始我已经测试过 Reply Chime。
上一篇文章里,我甚至专门记录了它当时的问题:
Test sound正常;- Firefox 权限正常;
- ChatGPT 自动播放权限也放开了;
- 真实回复超过设置阈值后,却没有声音。
当时我还在 Firefox Add-ons 上留下了问题反馈。
后来有一个很重要的变化:
Reply Chime 的作者回复了评价,并且继续更新了扩展。
这让我愿意再给它一次机会。
截至本文写作时,Firefox Add-ons 页面上的 Reply Chime 作者为 tiagoroldao,版本为 1.0.1。它可以设置最短回复时长和提示音音量,开发者也声明扩展不收集或传输用户数据。
这一次,我没有只点 Test sound。
我直接用自己每天真实的工作流测试:
同时打开多个 ChatGPT 标签页,让不同会话跑翻译、审核和长回复。
结果:
Reply Chime 这次通过了。

声音能够在我需要的时候正常出现。
而且相比我自己还在不断修复跨标签页仲裁的实验扩展,Reply Chime 已经可以直接解决我的核心需求。
到了这里,选择其实就很简单了。
我决定暂停维护自己的扩展
我的 ChatGPT Response Sound 项目没有删除。
代码和 Git 历史仍然保留。
因为这次开发过程本身还是很有价值的:
它让我实际验证了 ChatGPT Web 的完成通知在多标签页环境中的一些行为,也让我知道了一个看起来很简单的浏览器扩展,在真实工作流下会遇到哪些边界问题。
但我已经把项目状态调整为:
暂停维护
README 顶部也明确记录了目前遇到的问题:
- 同一个完成事件可能出现在多个 ChatGPT 标签页;
- 需要跨标签页仲裁才能避免重复提示;
- 去重以后,声音仍不一定能可靠路由到真正完成回复的标签页;
- 多标签页持续 DOM 监听的性能影响还没有充分验证。
更重要的是,我现在已经在 README 中直接推荐:
Reply Chime
也就是说,这个项目目前更多是作为一次实验记录保留下来,而不是继续作为我日常使用的正式方案。
我暂时也没有把仓库 Archive。
如果 Reply Chime 接下来经过更长时间使用依然稳定,再考虑正式归档也不迟。
对两个扩展的评价,我也需要重新调整
这一轮测试以后,我对两个第三方扩展的看法刚好发生了反转。
ChatGPT Done Sound by MAXIOL LTD
上一篇文章里,它是“终于能响”的那个方案。
但持续使用发现,它有时会在回复尚未真正完成时提前通知。
所以我不会再维持原来的 5 星判断。
问题的关键不是它有没有声音,而是:
完成判断存在误报。
对于需要同时管理多个长任务的人来说,错误的完成通知会直接破坏提示音的可信度。
Reply Chime
上一篇文章里,它反而是那个“测试音正常,但真实回复不响”的扩展。
但作者回复了反馈,并继续更新。
重新进行真实多标签页测试后,它现在已经符合我的需求。
这也是我比较愿意公开推荐它的原因:
不是因为第一次安装就完美,而是开发者对真实反馈有回应,后续版本也确实让我重新测试通过。
我甚至已经把自己开源项目的推荐方案改成了 Reply Chime。
从一个用户的角度,这种反馈闭环本身就很有价值。
这次最大的收获:不是所有轮子都值得继续自己造
自己写扩展并不是坏事。
如果没有这次开发,我可能也不会真正理解:
为什么一个“回复结束后响一声”的需求,在多标签页、后台通知和 SPA 页面里会变得这么复杂。
但工程上的另一个重要判断是:
什么时候应该停止继续造轮子。
当一个成熟的第三方项目已经重新满足需求,并且作者仍然在响应反馈时,继续花时间维护自己的替代实现,未必还有足够收益。
尤其我的主要工作并不是开发浏览器扩展。
我真正需要的是:
翻译和审核任务完成以后,可靠地提醒我回来处理下一步。
只要这个需求解决了,就没有必要为了“这是我自己写的”而继续投入维护成本。
所以目前我的最终方案变成了:
- ChatGPT 长回复完成提醒:
Reply Chime; - Codex 长任务:继续使用 CLI 自带的完成提示音;
- 自研
ChatGPT Response Sound:暂停维护,保留为实验记录。
这比前一天的方案反而更简单了。
写在最后
这两天的过程挺有意思。
第一天:
Reply Chime 不工作 → MAXIOL 可以用 → 给 MAXIOL 5 星。
第二天:
MAXIOL 出现提前误报 → 自己开发扩展 → 处理重复通知 → 处理跨标签页去重 → 处理声音路由 → 仍然遇到真实环境问题 → 再测试 Reply Chime → 通过。
最后我又回到了最早试过的那个扩展。
但这并不是原地转了一圈。
因为现在我已经知道:
- 什么样的“完成通知”对我的工作流才真正有用;
- 为什么准确性比“能响”更重要;
- ChatGPT 的多标签页通知行为可能比表面复杂;
- 第三方扩展作者是否响应反馈,也会直接影响一个工具是否值得长期使用;
- 如果现成方案已经满足需求,就没有必要继续承担额外的维护成本。
所以这一次,我愿意把结论更新为:
目前 Reply Chime 是更符合我实际需求的 ChatGPT 回复完成提示音方案。
当然,浏览器扩展和 ChatGPT Web 都会继续更新。
以后如果行为再次变化,我大概还是会继续测试。
但至少现在,我终于可以把注意力重新放回真正要做的工作,而不是继续盯着提示音扩展本身了。

