没有不值得去解决的问题,也没有不值得去学习的技术!

我为什么放弃自己维护 ChatGPT 回复提示音扩展,最终改用 Reply Chime

【图4:Reply Chime 真实多标签页测试通过】

作者:

在

前一天,我刚写完一篇关于 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 标签页以后,事情开始变得复杂。

【图1:自研扩展多标签页通知现象】
【图1:自研扩展多标签页通知现象】

同一个完成事件,可能会出现在多个 ChatGPT 标签页

我很快发现一个之前没有意识到的现象:

当某一个 ChatGPT 会话完成以后,完成通知不一定只出现在那个真正完成回复的页面。

在多个已经打开的 ChatGPT 标签页中,同一个通知可能被同步到其他页面。

这意味着,如果每个标签页都单独监听页面上的 toast,那么一次真正的任务完成,有可能变成:

多个标签页同时检测到通知,然后多个标签页各自响一次。

Firefox 顶部甚至会同时出现多个正在播放音频的图标。

这显然不是我想要的。

我真正想要的是:

同一个完成事件,在整个 Firefox 里只响一次。

于是扩展开始从一个很简单的 content script,变成需要跨标签页协调的实现。


为了“只响一次”,我加了 background 仲裁

后来的版本里,我增加了 background script。

新的流程大致变成:

  1. 每个 ChatGPT 标签页继续负责检测完成 toast;
  2. 检测到以后,不直接播放声音;
  3. 先把事件发送给扩展 background;
  4. background 对同一个完成事件去重;
  5. 整个 Firefox 实例只选择一个标签页播放声音。

为了识别“是不是同一个事件”,我还尝试了:

  • 从 toast 中提取 conversation URL;
  • 使用 conversation ID 作为事件 key;
  • 找不到 conversation 时,对通知文本做 hash;
  • 给最近事件设置短时间去重窗口。

版本也一路推进到了 0.1.3。

【图2:自研扩展 0.1.3 继续测试】
【图2:自研扩展 0.1.3 继续测试】

从工程实现上看,这已经比最开始复杂很多了。

而且“同一个通知响很多次”的问题确实有机会解决。

但新的问题马上又出现了。


只响一次还不够,还要响在正确的标签页

我希望声音最好从真正完成回复的那个标签页播放。

原因非常实际:

Firefox 会在正在播放声音的标签页上显示一个小喇叭图标。

如果我同时开了六七个 ChatGPT 会话,只要听到提示音,再看哪个标签页出现喇叭图标,就能马上知道:

原来是这个任务完成了。

这是一个非常好用的定位方式。

所以 background 去重以后,我又继续做声音路由:

  • 如果通知里能识别出 conversation URL,就把声音送到对应 conversation 的标签页;
  • 如果没有 URL,就尝试用通知文本匹配每个标签页的标题;
  • 实在无法定位时,才回退到最先报告这个事件的标签页。

模拟测试是能通过的。

但真实使用时,问题还是出现了。

有一次:

  • 第 1 个标签页的回复已经完成;
  • 第 2 个标签页还在继续生成;
  • 结果声音却从第 2 个标签页播放。
【图3:自研扩展声音落到错误标签页】
【图3:自研扩展声音落到错误标签页】

也就是说:

跨标签页去重可能做到了,但“哪个页面才是真正完成的页面”仍然没有被稳定识别。

到了这里,我已经意识到,这个问题远没有最开始想象的那么简单。


我甚至开始怀疑,多标签页 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 这次通过了。

【图4:Reply Chime 真实多标签页测试通过】
【图4: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 都会继续更新。

以后如果行为再次变化,我大概还是会继续测试。

但至少现在,我终于可以把注意力重新放回真正要做的工作,而不是继续盯着提示音扩展本身了。

关于作者 · 持续学习与技术实践

我是一名拥有 15 年以上开发经验的技术从业者,自 2013 年起持续运营个人技术博客,记录工作与个人项目中遇到的真实问题,以及解决问题过程中的探索、实践和思考。

除了技术写作,我也在持续开发和维护自己的独立项目,探索新技术和新工具在实际场景中的应用。我始终相信,没有不值得去解决的问题,也没有不值得去学习的技术。

如果这篇文章对你有所帮助,欢迎浏览博客中的其他文章,也欢迎交流技术经验与想法。

关于我  ·  GitHub  ·  邮件联系