news 2026/5/15 0:16:13

基于MutationObserver的GPT-4使用统计插件开发实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于MutationObserver的GPT-4使用统计插件开发实战

1. 项目概述与核心价值

作为一个深度依赖GPT-4进行内容创作、代码审查或日常咨询的用户,你是否曾有过这样的困惑:今天到底向GPT-4提了多少个问题?这个月的使用频率是上升了还是下降了?每天聊得最多的主题是什么?这些看似简单的问题,如果没有一个直观的记录工具,往往只能凭模糊的感觉去猜测。今天要分享的,就是我自己为了解决这个痛点而折腾出来的一个Chrome浏览器插件——GPT-4请求计数器。它不是一个复杂的AI模型,而是一个轻巧、实用的“仪表盘”,专门用来监控和分析你在浏览器端与GPT-4的每一次互动。

这个插件的核心功能非常直接:自动计数、图表化历史、可视化分析。它像一个沉默的助手,在你每次与ChatGPT网页版(特指GPT-4模型对话)交互时,默默地在后台计数。然后,通过一个简洁的弹出窗口,你可以实时看到当天的请求数;通过历史图表,回顾过去一段时间的使用趋势;甚至,它还能分析你当天所有的对话内容,生成一张关键词词云图,让你一眼看清今天思考的焦点。对于需要管控使用成本、分析工作流效率,或者单纯想了解自己与AI互动习惯的朋友来说,这个小工具能提供非常直观的数据支持。

它的实现原理并不涉及高深的AI算法,而是巧妙地利用了浏览器扩展的能力,通过内容脚本(Content Script)监听页面DOM的变化,来识别一次“请求-响应”的完成。整个项目代码开源,基于MIT协议,这意味着你可以自由地使用、修改甚至二次开发。接下来,我将从设计思路、具体实现、避坑经验到扩展可能,为你完整拆解这个项目,无论你是想直接使用这个插件,还是对如何开发一个类似的浏览器监控工具有兴趣,相信都能从中获得启发。

2. 插件核心功能与设计思路拆解

在动手写代码之前,明确“要做什么”以及“为什么这么做”至关重要。这个插件的目标是在非侵入式的前提下,精准统计GPT-4的请求次数并提供衍生分析。围绕这个目标,我拆解出了几个核心的设计决策。

2.1 为什么选择浏览器插件而非独立应用?

首先,统计对象是“在浏览器中向GPT-4发送的请求”。最直接的场景就是用户访问chat.openai.com并使用GPT-4模型进行对话。因此,插件的形态是最佳选择:

  1. 无感集成:插件与浏览器环境天然融合,用户无需打开额外软件,统计过程在后台自动完成,体验无缝。
  2. 精准捕获:只有浏览器插件能直接访问和监听目标网页的DOM(文档对象模型)与网络活动,这是识别用户交互的关键。
  3. 低性能开销:相比于启动一个独立的桌面应用,插件通常只激活在特定页面,资源占用更小。

注意:这意味着插件仅对浏览器环境生效。如果你通过API、第三方客户端或手机App使用GPT-4,本插件是无法统计的。这是由其设计边界决定的。

2.2 核心功能模块设计

基于用户需求,我规划了四个核心功能模块,它们共同构成了插件的价值闭环:

  1. 请求计数器:这是基石功能。目标是在用户每次成功获得GPT-4回复后,计数+1。这里的关键在于如何准确界定一次“有效请求”。不能简单地计算点击“发送”按钮的次数,因为网络可能失败、用户可能中途刷新。我的设计是:监听对话界面中,代表GPT-4回复的新消息块的出现。只有当包含特定标识(如GPT-4头像或模型标记)的新div元素被添加到DOM中,才认为一次请求完成并计数。

  2. 历史数据图表:仅有当日计数是不够的。为了分析趋势,需要持久化存储历史数据。我选择使用浏览器的chrome.storage.localAPI来存储每日的计数。图表功能则负责读取这些数据,并使用一个轻量级的图表库(如Chart.js)渲染成折线图或柱状图,让用户能直观看到过去7天、30天甚至更久的使用情况。

  3. 当日对话词云图:这是提升插件趣味性和洞察力的功能。思路是收集当天所有对话的文本内容(包括用户提问和AI回复),进行分词、过滤停用词(如“的”、“了”、“我”),然后统计词频。最后,利用词云生成库(如WordCloud2.js)将高频词以视觉化的方式呈现。词云图能快速揭示当天讨论的核心话题。

  4. 数据导出与报告:为了满足深度分析或备份需求,提供了导出功能。可以将当天的完整对话内容导出为结构清晰的HTML或Markdown文件。更进一步,“今日报告”可以整合计数、词云、高频词列表、平均对话长度等数据,形成一个简单的数据简报。

2.3 技术栈选型考量

  • 前端框架:插件弹出窗(Popup)和选项页(Options)界面相对简单,为了保持轻量,我直接使用原生JavaScript配合DOM操作完成,没有引入React或Vue。这减少了打包体积和复杂度。
  • 数据存储chrome.storage.local是官方推荐的方式,它提供异步API,存储空间相对较大(通常5MB以上),且数据与浏览器配置文件绑定。相比于localStorage,它更适合插件环境,并且能更方便地在插件的不同部分(如后台脚本、内容脚本、弹出窗)之间共享数据。
  • 图表与词云库:选择Chart.jsWordCloud2.js是因为它们都是纯前端库,无需后端支持,图表美观且文档完善,只需通过CDN引入或本地封装即可。
  • 构建工具:使用简单的模块化JavaScript,通过manifest.jsoncontent_scriptsbackground字段来组织代码结构。对于更复杂的项目,可以考虑使用webpackParcel进行构建。

这个设计思路确保了插件核心目标明确、架构清晰,且每个功能都有可行的实现路径。接下来,我们深入每个功能的具体实现细节。

3. 关键实现细节与核心技术解析

将设计转化为代码,会遇到许多具体的技术挑战。这里我重点解析几个最关键的实现环节,并分享其中的决策逻辑和注意事项。

3.1 请求计数的精准捕获:MutationObserver的应用

如何知道用户收到了GPT-4的新回复?ChatGPT的网页是动态更新的,不能依赖定时器去轮询。这里的主角是MutationObserverAPI,它可以监听DOM树的变化。

实现原理

  1. 注入内容脚本:在manifest.json中声明content_scripts,将其匹配到https://chat.openai.com/*。这样,当用户打开ChatGPT网站时,我们的脚本会自动注入到页面中。
  2. 定位对话容器:首先,需要找到页面上承载所有聊天消息的容器元素。通过浏览器开发者工具分析,发现其通常是一个具有特定类名(如groupw-full)的div
  3. 创建观察者:针对这个容器,创建一个MutationObserver实例。配置它监听“子节点添加”(childList: true)这一变化。
  4. 定义回调函数:每当容器内有新的子节点(即新的消息块)被添加时,回调函数就会被触发。在这个函数里,我们需要检查新添加的节点:
    • 是否包含代表GPT-4回复的标识?(例如,查找特定的头像图片alt属性为“ChatGPT”,或者找到包含“GPT-4”文本的模型标签)。
    • 该消息块是否是新生成的?(避免页面加载历史消息时误触发)。
  5. 计数与通信:一旦确认是新的GPT-4回复,就将计数增加。这个计数需要从内容脚本传递到插件的其他部分(如弹出窗显示)。这里使用chrome.runtime.sendMessageAPI 发送一个计数增加的消息给后台脚本(background script),由后台脚本统一更新存储。
// 内容脚本 (content.js) 示例代码片段 const targetNode = document.querySelector(‘[data-testid^="conversation-turn-"]‘); // 假设的容器选择器 const observerConfig = { childList: true, subtree: true }; const observer = new MutationObserver((mutationsList) => { for (let mutation of mutationsList) { if (mutation.type === ‘childList‘) { mutation.addedNodes.forEach((node) => { if (node.nodeType === 1 && isGPT4Response(node)) { // 检查是否为GPT-4回复元素 chrome.runtime.sendMessage({ type: ‘INCREMENT_COUNT‘ }); } }); } } }); observer.observe(targetNode, observerConfig); function isGPT4Response(element) { // 实现逻辑:检查元素内是否包含GPT-4的特定标识 // 例如:查找模型选择器显示为“GPT-4”,或者特定的头像/图标 return element.querySelector(‘div.model-selector:contains(“GPT-4”)‘) !== null; // 示例,实际选择器需分析页面 }

实操心得:ChatGPT的网页结构可能会更新,导致我们依赖的CSS选择器失效。因此,isGPT4Response函数的健壮性很重要。一个更稳健的策略是组合多种特征判断,例如同时检查模型标识和消息流的顺序(用户消息后新增的才是AI回复)。此外,需要在manifest.jsonpermissions中声明"storage""activeTab"权限。

3.2 数据持久化与跨上下文通信

插件的不同部分运行在独立的“上下文”中:

  • 内容脚本:运行在网页的上下文中,能直接访问DOM,但权限受限。
  • 后台脚本:在浏览器后台持续运行,拥有完整的Chrome API权限,适合做数据管理和逻辑协调。
  • 弹出窗:用户点击插件图标时出现,生命周期短,主要用于展示和简单交互。

数据流设计

  1. 存储中心:所有数据(当日计数、历史记录、对话文本)都通过后台脚本,使用chrome.storage.local.set/get进行读写。这保证了数据的一致性和持久性。
  2. 通信机制
    • 内容脚本 -> 后台脚本:使用chrome.runtime.sendMessage发送“计数增加”或“新对话文本”消息。
    • 后台脚本 -> 弹出窗/选项页:当弹出窗打开时,它主动向后台脚本发送消息(如getTodayCount)请求数据。后台脚本收到后,从存储中读取数据并返回。对于实时更新,可以使用chrome.runtime.onMessage监听。
    • 弹出窗内部:直接使用chrome.storage.local.onChanged监听器,可以在存储数据变化时自动更新UI,实现计数器的实时跳动效果。
// 后台脚本 (background.js) 示例 chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { if (request.type === ‘INCREMENT_COUNT‘) { // 1. 获取当前日期作为键 const today = new Date().toISOString().split(‘T‘)[0]; // 2. 从存储中读取今日计数 chrome.storage.local.get([today], (result) => { let todayCount = result[today] || 0; todayCount++; // 3. 更新存储 chrome.storage.local.set({ [today]: todayCount }, () => { console.log(`Count updated for ${today}: ${todayCount}`); }); }); } // 可以处理其他类型的消息... }); // 弹出窗脚本 (popup.js) 示例 - 打开时获取数据 document.addEventListener(‘DOMContentLoaded‘, () => { const today = new Date().toISOString().split(‘T‘)[0]; chrome.storage.local.get([today], (result) => { document.getElementById(‘countDisplay‘).textContent = result[today] || 0; }); });

3.3 词云图生成的优化处理

生成词云图看似简单,但要做好需要处理文本预处理和性能问题。

处理流程

  1. 文本收集:在内容脚本中,不仅计数,也捕获每条消息的文本内容,并随消息发送到后台存储。注意只收集当天的对话。
  2. 文本预处理
    • 分词:对于英文,可以按空格和标点简单分割。对于中文,需要使用分词库,如jieba(需引入其浏览器版)或segment。本项目为了轻量,最初可能采用简单的按字分割或使用一个小的禁用词表过滤,但效果有限。更优解是集成一个轻量级的中文分词库。
    • 清洗:移除URL、特殊符号、纯数字、以及常见的停用词(如“的”、“了”、“是”、“在”)。
    • 统计词频:遍历所有分词结果,统计每个词出现的次数。
  3. 生成词云:将词频数组传递给WordCloud2.js。可以自定义颜色、形状、字体大小范围等。一个关键点是,词云画布通常放在弹出窗或选项页中,需要确保画布尺寸适配容器,并在数据更新时重新绘制。
// 假设我们已经有了一个词频数组 wordFreqList = [[‘编程‘, 15], [‘设计‘, 12], ...] function generateWordCloud(wordFreqList) { const canvas = document.getElementById(‘wordcloudCanvas‘); const ctx = canvas.getContext(‘2d‘); // 确保画布大小正确 canvas.width = canvas.parentElement.clientWidth; canvas.height = 300; // 调用 WordCloud2.js (假设已加载) WordCloud(canvas, { list: wordFreqList, gridSize: 10, weightFactor: 8, color: ‘random-dark‘, backgroundColor: ‘#f9f9f9‘, rotateRatio: 0.3, }); }

注意事项:词云生成是计算密集型操作,如果当天对话内容极多(数万字),在弹出窗的短暂生命周期内处理可能导致卡顿。因此,可以考虑将分词和词频统计放在后台脚本中进行,或者对文本进行采样处理。另外,WordCloud2.js在绘制大量词语时也可能有性能压力,需要合理设置gridSizeweightFactor参数。

4. 插件打包、发布与使用指南

开发完成后,我们需要将代码打包成.crx文件供安装,并了解如何发布到商店。

4.1 项目结构与Manifest配置

一个标准的Chrome插件项目结构如下:

gpt4-request-counter/ ├── manifest.json # 核心配置文件 ├── icons/ # 插件图标(多种尺寸) ├── popup.html # 弹出窗口页面 ├── popup.js ├── options.html # 选项页面(可选) ├── options.js ├── background.js # 后台服务脚本 ├── content.js # 注入到页面的脚本 └── libs/ # 第三方库,如chart.js, wordcloud2.js

manifest.json是重中之重,它定义了插件的基本信息、权限和资源。以下是关键部分:

{ "manifest_version": 3, // 务必使用Manifest V3 "name": "GPT-4 Requests Counter", "version": "1.0.0", "description": "统计并可视化您每日使用GPT-4的请求次数和对话内容。", "permissions": [ "storage", // 用于存储数据 "activeTab" // 获取当前标签页信息(可选) ], "host_permissions": [ "https://chat.openai.com/*" // 允许向该网站注入内容脚本 ], "content_scripts": [ { "matches": ["https://chat.openai.com/*"], "js": ["content.js"], "run_at": "document_idle" // 页面加载完成后运行 } ], "background": { "service_worker": "background.js" // MV3使用service worker }, "action": { "default_popup": "popup.html", "default_icon": "icons/icon48.png" }, "icons": { "48": "icons/icon48.png", "128": "icons/icon128.png" } }

4.2 本地加载与测试

在发布前,需要在本地进行充分测试。

  1. 打开Chrome浏览器,进入chrome://extensions/
  2. 开启右上角的“开发者模式”。
  3. 点击“加载已解压的扩展程序”,选择你的插件项目根目录。
  4. 插件将被加载。此时,打开chat.openai.com,开始对话,检查弹出窗中的计数是否正常增加,图表和词云功能是否工作。

4.3 打包与发布到Chrome网上应用店

  1. 打包:在chrome://extensions/页面,找到你的插件,点击“打包扩展程序”。选择项目根目录,它会生成一个.crx(插件包)和一个.pem(私钥文件,务必保存好,用于后续更新)。
  2. 发布准备:你需要一个Google开发者账号(需一次性支付5美元注册费)。在 Chrome开发者信息中心 创建新项目。
  3. 上传与填写信息:上传打包好的.zip文件(注意不是.crx,通常需要将项目文件夹压缩成zip),填写详细的商店列表信息:标题、描述、宣传图、截图、分类等。描述中应清晰说明功能、使用方法和隐私声明(例如,声明本插件仅本地存储数据,不会上传任何信息)。
  4. 提交审核:提交后,Google会进行审核,通常需要几天时间。审核通过后,插件即可公开下载。

4.4 用户使用指南

对于最终用户,安装和使用非常简单:

  1. 安装:访问Chrome网上应用店,搜索“GPT-4 Requests Counter”或通过项目提供的直接链接,点击“添加到Chrome”。
  2. 使用
    • 正常使用chat.openai.com与GPT-4对话。插件图标上可能会显示一个徽章,实时更新当日计数。
    • 点击浏览器工具栏上的插件图标,弹出窗口会显示:
      • 当前日期和请求总数。
      • “History Chart”按钮:点击跳转到选项页,查看历史请求的折线图/柱状图。
      • “Today‘s Word Cloud”按钮:点击在弹出窗或新页面中生成并展示当天的对话词云图,通常旁边会有“Download”按钮可以保存为PNG图片。
      • “Export Today‘s Chat”按钮:将当天所有对话以HTML或Markdown格式导出并下载。
      • “Today‘s Report”按钮:生成一个包含统计摘要、高频词列表和词云图的综合报告页面。
  3. 数据管理:在插件的选项页面(通常通过右键点击插件图标选择“选项”进入),用户可以查看更详细的历史数据,有时也提供“清除所有数据”的按钮。

5. 开发中遇到的典型问题与解决方案

在实际开发过程中,我踩过不少坑。这里记录下几个典型问题及其解决方法,希望能帮你绕开这些弯路。

5.1 问题:计数不准确或重复计数

现象:有时一次对话回复,计数器却增加了2次或更多。排查

  1. 检查MutationObserver的回调函数。ChatGPT页面可能在一条消息完全渲染前,会多次更新DOM(例如先添加一个骨架屏,再填充内容)。我们的观察者可能监听到了多次childList变化。
  2. 检查isGPT4Response函数。它可能将用户消息或系统消息误判为GPT-4回复。解决方案
  • 去抖处理:为同一轮对话的DOM变化设置一个简单的去抖(debounce)。例如,在收到变化事件后,等待500毫秒,再检查最终的消息状态。这可以避免中间状态被多次计数。
  • 更精确的标识:深入分析DOM结构,找到唯一标识GPT-4回复的元素。可能是一个包含特定>// popup.js chrome.storage.onChanged.addListener((changes, namespace) => { if (namespace === ‘local‘) { const today = new Date().toISOString().split(‘T‘)[0]; if (changes[today]) { document.getElementById(‘countDisplay‘).textContent = changes[today].newValue; } } });
  • 从后台脚本主动获取:弹出窗打开时,向后台脚本发送一个“获取最新数据”的消息,确保拿到的是实时数据。
  • 5.3 问题:词云图在弹出窗中显示不全或错位

    现象:词云图只显示一部分,或者画布大小不对。原因:弹出窗的尺寸是固定的(通常在manifest.jsonaction中定义default_popup的HTML页面大小)。WordCloud2.js需要知道画布的确切尺寸来布局词语。如果画布尺寸设置不正确,或者弹出窗在绘制完成后才调整大小,就会出问题。解决方案

    1. 显式设置画布尺寸:在调用WordCloud函数前,用JavaScript动态设置canvas.widthcanvas.height,使其等于其父容器的客户区宽度和高度。
    2. 确保容器可见:词云绘制必须在弹出窗的DOM完全渲染且可见后进行。可以将绘制代码放在window.onload或确保DOM就绪后执行。
    3. 响应式处理:如果弹出窗尺寸可变,需要监听窗口的resize事件,并重新生成词云。不过对于固定尺寸的弹出窗,这一步通常不需要。

    5.4 问题:隐私与数据安全疑虑

    用户可能担心:这个插件会读取我的所有对话内容吗?数据会上传到服务器吗?设计与声明

    1. 本地存储原则:本插件所有代码逻辑均在浏览器本地执行。收集的对话文本、计数数据均使用chrome.storage.localAPI存储在用户本地电脑上,不会通过网络发送到任何远程服务器
    2. 权限最小化manifest.json中只申请了必要的权限:storage(用于本地存储)和针对chat.openai.comhost_permissions(用于注入脚本)。没有申请访问所有网站或网络请求的权限。
    3. 开源透明:项目代码完全开源在GitHub,任何人都可以审查代码,确认没有数据外传行为。
    4. 提供清除选项:在插件选项页明确提供“清除所有数据”的按钮,让用户拥有完全控制权。

    在插件的应用商店描述和隐私政策中,必须清晰、醒目地说明以上几点,以建立用户信任。

    6. 进阶优化与扩展思路

    一个基础可用的插件已经完成,但总有可以打磨和增强的地方。这里分享几个我思考过的进阶方向。

    6.1 性能与资源占用优化

    • 懒加载与按需注入:目前内容脚本在匹配的页面加载时就会注入。可以改为在用户与页面交互(如开始输入)或检测到页面是ChatGPT聊天界面时才注入,减少初始开销。
    • 数据存储优化:随着时间推移,存储的历史数据会越来越多。可以定期(如每季度)自动归档或清理超过一定时间(如一年)的详细对话文本,只保留每日的计数统计,以控制存储空间。
    • 词云生成异步化:将分词和词频统计这些耗时操作放入Web Worker中执行,避免阻塞弹出窗或选项页的主线程,保持UI响应流畅。

    6.2 功能增强

    • 多模型支持:不仅统计GPT-4,也可以识别和统计GPT-3.5、Claude等其他AI模型的请求(如果它们在同一个网站上有不同界面)。这需要扩展isGPT4Response函数为isAIResponse,并区分模型类型。
    • 自定义统计周期:允许用户自定义“统计日”的起始时间(例如,从每天凌晨4点开始),以适应不同作息。
    • 设置与自定义:增加选项页,让用户可以:
      • 选择词云的颜色主题、字体。
      • 设置停用词列表,过滤掉不想出现在词云中的词(如项目特定的术语)。
      • 开启/关闭某些功能(如对话内容收集,以满足更严格的隐私需求)。
    • 数据同步:通过用户授权,将加密的统计数据同步到用户自己的云存储(如Google Drive、Dropbox),实现跨设备的数据统一。注意:此功能涉及敏感数据,必须提供明确的开关和加密保障。

    6.3 用户体验提升

    • 更丰富的通知:当每日请求数达到用户设定的阈值时,在浏览器角落显示一个温和的通知,提醒适度使用。
    • 数据导出格式多样化:除了HTML/Markdown,支持导出为CSV(便于用Excel分析)或JSON(便于程序处理)。
    • 更深入的分析报告:在“今日报告”中,加入更多指标,如:平均每次对话的轮次、最常使用的提示词开头、对话活跃时间段分布图等。

    6.4 应对网站变更的策略

    ChatGPT的网页界面更新是常态。如何让插件更健壮?

    1. 配置化选择器:将用于识别消息容器、AI回复标识的CSS选择器提取到插件的配置(如options页面存储)或远程配置文件中。当网站改版导致选择器失效时,可以快速更新配置,而无需用户重新安装插件。
    2. 社区维护:开源项目可以鼓励用户提交Issue报告失效情况,共同维护一套选择器规则。
    3. 降级方案:如果主要选择器失效,可以尝试降级到更通用但可能不太精确的检测方法(如检测所有新出现的消息块,并通过文本模式辅助判断),至少保证核心计数功能不完全瘫痪,同时给出界面需要更新的提示。

    开发这个插件的过程,是一个典型的“发现问题-设计解决方案-实现-测试-优化”的循环。它让我更深入地理解了浏览器扩展的开发模式、DOM监控的细节以及数据可视化在前端的应用。最重要的是,它解决了我自己的真实需求。如果你也有类似的想法,不妨基于这个项目开始你的探索,添加你独有的功能。编程的乐趣,往往就在于用代码将脑海中的一个小工具变为现实,并让它真正产生价值。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/15 0:14:06

FakeLocation终极指南:Android应用级虚拟定位的完整解决方案

FakeLocation终极指南:Android应用级虚拟定位的完整解决方案 【免费下载链接】FakeLocation Xposed module to mock locations per app. 项目地址: https://gitcode.com/gh_mirrors/fak/FakeLocation 你是否曾想过在社交软件上"瞬间移动"到世界各地…

作者头像 李华
网站建设 2026/5/15 0:10:25

VCamera:如何用虚拟摄像头保护隐私并创造无限视频可能

VCamera:如何用虚拟摄像头保护隐私并创造无限视频可能 【免费下载链接】VCamera 项目地址: https://gitcode.com/gh_mirrors/vca/VCamera 你是否曾担心视频会议时不小心暴露凌乱的房间?🤔 直播时想玩点创意却苦于技术限制&#xff1f…

作者头像 李华
网站建设 2026/5/15 0:09:34

速度输出+纹波时钟+方向指示:AD2S82AHP的多信号轴角测量方案

AD2S82AHP:以模拟伺服技术实现高精度旋变数字转换的经典方案在设计基于交流伺服电机或直流无刷电机的运动控制系统时,角度位置的精确测量直接决定了控制环路的响应品质。旋转变压器以其坚固耐用的结构和抗恶劣环境能力,一直是工业机床、机器人…

作者头像 李华