从零开发Chrome扩展:集成ChatGPT API实现网页智能分析

发布时间:2026/9/4 17:41:03
从零开发Chrome扩展:集成ChatGPT API实现网页智能分析 在实际开发中我们经常需要将大型语言模型的能力集成到自己的应用中而不仅仅是使用官方网页。ChatGPT 等模型通过 API 提供了强大的文本生成能力但如何让用户在使用浏览器时能便捷地调用这些能力比如智能分析当前网页、总结内容或基于网页内容进行对话是一个常见的工程需求。这通常涉及到浏览器扩展程序的开发。本文将带你从零开始开发一个能够与 ChatGPT API 交互的 Chrome 扩展程序。这个扩展的核心功能是在用户浏览任意网页时可以通过点击扩展图标或快捷键将当前页面的网址或选中的文本发送给 ChatGPT并获取智能回复。我们将重点解决扩展程序与外部 API 的通信、内容脚本注入、权限声明以及处理 API 密钥安全等实际问题。通过本文你将掌握开发一个功能完整、可投入使用的 AI 浏览器扩展的核心技术栈和工程实践。1. 理解 Chrome 扩展程序与 AI 集成的架构在动手写代码之前需要理清几个核心概念和它们之间的协作关系这是避免后续开发混乱的关键。1.1 Chrome 扩展程序的基本构成一个典型的 Chrome 扩展由以下几部分组成它们运行在各自独立的上下文中清单文件 (manifest.json)扩展的“身份证”和“说明书”定义了扩展的名称、版本、权限、后台脚本、内容脚本、浏览器动作等核心信息。没有它Chrome 无法识别你的扩展。后台脚本 (Background Script)一个长期运行在浏览器后台的 JavaScript 环境。它没有用户界面但可以监听浏览器事件如安装、标签页更新、管理扩展状态、并与内容脚本或弹出页面进行通信。它是扩展的“大脑”和“调度中心”。内容脚本 (Content Script)注入到用户正在浏览的网页中的 JavaScript 文件。它可以读取和修改页面的 DOM获取页面内容如文本、网址但不能直接使用 Chrome扩展API除了少数几个如chrome.runtime用于通信。它充当了网页与扩展后台之间的“信使”。弹出页面 (Popup)当用户点击工具栏上的扩展图标时弹出的一个小窗口。它本质上是一个独立的 HTML 页面可以包含自己的样式和逻辑常用于提供快捷操作界面。选项页面 (Options Page)一个更复杂的配置页面用户可以通过右键点击扩展图标选择“选项”来打开。常用于设置 API 密钥等敏感信息。1.2 与 ChatGPT API 集成的数据流我们的目标是让用户在当前网页触发动作最终获得 AI 的回复。数据流如下用户触发用户在网页上选中文本后右键选择扩展菜单项或直接点击扩展图标。内容脚本采集内容脚本被激活获取当前页面的 URL 和用户选中的文本。内部通信内容脚本通过chrome.runtime.sendMessage将采集到的数据发送给后台脚本。外部 API 调用后台脚本接收到数据后构造符合 OpenAI API 格式的请求附上你的 API 密钥发送到https://api.openai.com/v1/chat/completions。处理响应后台脚本收到 OpenAI 的 JSON 响应后解析出 AI 生成的文本内容。结果展示后台脚本将结果发送回内容脚本或弹出页面由内容脚本将结果以某种形式如侧边栏、弹窗、直接修改页面展示给用户。这个流程中API 密钥的存储和调用安全是重中之重。绝对不能将密钥硬编码在内容脚本或前端页面中因为它们很容易被他人查看。密钥应存储在后台脚本可以安全访问的地方例如 Chrome 的本地存储 (chrome.storage.local) 中并由后台脚本负责所有外网请求。2. 环境准备与项目初始化2.1 开发环境与账号准备你需要准备以下环境Chrome 浏览器版本 88 或更高支持 Manifest V3。确保可以从chrome://extensions/页面加载已解压的扩展程序。代码编辑器如 VS Code。OpenAI API 密钥访问 OpenAI Platform 注册账号并创建 API Key。请注意调用 API 会产生费用。一个空的项目目录例如chatgpt-browser-extension。2.2 创建核心项目文件在你的项目目录下创建以下文件和文件夹结构chatgpt-browser-extension/ ├── manifest.json # 扩展清单文件 ├── background.js # 后台脚本 ├── content.js # 内容脚本 ├── popup.html # 弹出页面 HTML ├── popup.js # 弹出页面逻辑 ├── options.html # 选项页面 HTML ├── options.js # 选项页面逻辑 └── icons/ # 扩展图标文件夹 ├── icon16.png ├── icon48.png └── icon128.png你可以先准备几个简单的图标文件16x16, 48x48, 128x128 像素或者用占位图片。3. 编写清单文件与配置权限manifest.json是扩展的蓝图。我们使用 Manifest V3 版本它更安全、性能更好。{ manifest_version: 3, name: ChatGPT 网页助手, version: 1.0, description: 使用 ChatGPT 分析当前网页内容或选中的文本。, permissions: [ activeTab, scripting, storage ], host_permissions: [ https://api.openai.com/* ], background: { service_worker: background.js }, content_scripts: [ { matches: [all_urls], js: [content.js] } ], action: { default_popup: popup.html, default_icon: { 16: icons/icon16.png, 48: icons/icon48.png, 128: icons/icon128.png } }, options_page: options.html, icons: { 16: icons/icon16.png, 48: icons/icon48.png, 128: icons/icon128.png } }关键配置解释manifest_version: 3声明使用 Manifest V3。permissionsactiveTab允许扩展临时访问当前激活标签页的 URL 和内容。scripting允许以编程方式注入脚本虽然我们通过content_scripts静态注入但此权限为未来动态注入留有余地。storage允许使用chrome.storageAPI 来安全地存储用户的 API 密钥等数据。host_permissions: [https://api.openai.com/*]这是最关键的权限之一。它允许扩展的后台脚本向api.openai.com域名发起网络请求。没有这个权限调用会因 CORS 或权限错误而失败。background: { service_worker: background.js }指定后台脚本文件。在 V3 中后台脚本以 Service Worker 形式运行。content_scripts指定要注入到所有网页 (all_urls) 的内容脚本文件。action定义了浏览器工具栏图标的行为这里指定点击后弹出popup.html。4. 实现选项页面以安全配置 API 密钥首先实现选项页面让用户能够安全地输入和保存他们的 OpenAI API 密钥。options.html (简化版):!DOCTYPE html html head titleChatGPT 助手设置/title style body { width: 400px; padding: 20px; font-family: sans-serif; } .input-group { margin-bottom: 15px; } label { display: block; margin-bottom: 5px; font-weight: bold; } input[typepassword] { width: 100%; padding: 8px; box-sizing: border-box; } button { padding: 10px 20px; background-color: #4CAF50; color: white; border: none; cursor: pointer; } #status { margin-top: 10px; color: green; } /style /head body h2API 密钥设置/h2 div classinput-group label forapiKeyOpenAI API Key:/label input typepassword idapiKey placeholdersk-... psmall你的密钥仅保存在本地浏览器中用于向 OpenAI 发起请求。/small/p /div button idsaveBtn保存设置/button div idstatus/div script srcoptions.js/script /body /htmloptions.js:document.addEventListener(DOMContentLoaded, function() { const apiKeyInput document.getElementById(apiKey); const saveButton document.getElementById(saveBtn); const statusDiv document.getElementById(status); // 页面加载时从存储中读取并填充已有的 API Key chrome.storage.local.get([openaiApiKey], function(result) { if (result.openaiApiKey) { apiKeyInput.value result.openaiApiKey; } }); // 保存按钮点击事件 saveButton.addEventListener(click, function() { const apiKey apiKeyInput.value.trim(); if (!apiKey) { showStatus(请输入有效的 API Key。, red); return; } // 简单验证格式以 sk- 开头 if (!apiKey.startsWith(sk-)) { showStatus(API Key 格式似乎不正确请检查。, orange); // 不阻止保存因为格式未来可能变化 } // 使用 chrome.storage.local 保存 chrome.storage.local.set({ openaiApiKey: apiKey }, function() { if (chrome.runtime.lastError) { showStatus(保存失败 chrome.runtime.lastError.message, red); } else { showStatus(设置已保存, green); } }); }); function showStatus(message, color) { statusDiv.textContent message; statusDiv.style.color color; setTimeout(() { statusDiv.textContent ; }, 3000); } });这个页面通过chrome.storage.localAPI 将密钥保存在用户的本地浏览器存储中。后台脚本可以读取这里存储的密钥而密钥不会暴露在网页的源代码里。5. 构建后台脚本处理通信与 API 调用后台脚本 (background.js) 是扩展的核心负责与 OpenAI 通信。// 监听来自内容脚本或弹出页面的消息 chrome.runtime.onMessage.addListener((request, sender, sendResponse) { // 判断消息类型 if (request.action callChatGPT) { const { prompt, context } request.data; callOpenAIChatAPI(prompt, context).then(sendResponse).catch(error { console.error(API调用失败:, error); sendResponse({ success: false, error: error.message }); }); // 返回 true 表示我们将异步调用 sendResponse return true; } // 可以添加其他 action 的处理逻辑 }); /** * 调用 OpenAI Chat Completions API * param {string} prompt - 用户的主要指令 * param {string} context - 上下文信息如网页内容 * returns {PromiseObject} - 解析为包含AI回复的对象 */ async function callOpenAIChatAPI(prompt, context ) { // 1. 从本地存储获取 API 密钥 const result await chrome.storage.local.get([openaiApiKey]); const apiKey result.openaiApiKey; if (!apiKey) { throw new Error(未设置 OpenAI API 密钥。请右键点击扩展图标进入“选项”进行设置。); } // 2. 构造请求消息 const messages []; if (context) { // 可以将上下文作为系统消息或用户消息的一部分传入 messages.push({ role: user, content: 请基于以下内容回答问题\n\n${context}\n\n问题${prompt} }); } else { messages.push({ role: user, content: prompt }); } // 3. 准备请求参数 const requestBody { model: gpt-3.5-turbo, // 可根据需要改为 gpt-4 等 messages: messages, max_tokens: 1000, // 控制回复长度 temperature: 0.7, // 控制创造性 }; // 4. 发起 fetch 请求 const response await fetch(https://api.openai.com/v1/chat/completions, { method: POST, headers: { Content-Type: application/json, Authorization: Bearer ${apiKey} }, body: JSON.stringify(requestBody) }); if (!response.ok) { const errorData await response.json().catch(() ({})); throw new Error(API 请求失败 (${response.status}): ${errorData.error?.message || response.statusText}); } const data await response.json(); // 5. 提取并返回 AI 回复 const aiReply data.choices[0]?.message?.content?.trim(); if (!aiReply) { throw new Error(API 返回了空回复。); } return { success: true, reply: aiReply }; }关键点解析消息监听chrome.runtime.onMessage.addListener是扩展内部组件通信的枢纽。内容脚本或弹出页面通过chrome.runtime.sendMessage发送消息后台脚本在这里接收并处理。异步处理与return true因为callOpenAIChatAPI是异步函数我们需要return true来告诉 Chrome 我们将异步调用sendResponse函数。否则消息通道会在监听函数返回后立即关闭。密钥安全获取通过chrome.storage.local.get从本地存储读取密钥避免了在前端代码中暴露。API 请求构造严格遵循 OpenAI Chat Completions API 的格式设置model、messages、max_tokens等参数。错误处理对网络错误、API 返回错误、空回复等情况都进行了处理并将错误信息通过sendResponse传回调用方便于前端展示。6. 开发内容脚本与用户交互界面内容脚本需要获取页面信息并提供用户交互的入口。这里我们实现两种方式右键上下文菜单和与弹出页面配合。6.1 创建内容脚本获取页面信息content.js:// 监听来自弹出页面或后台脚本的消息 chrome.runtime.onMessage.addListener((request, sender, sendResponse) { if (request.action getPageContent) { // 获取当前页面基本信息 const pageInfo { url: window.location.href, title: document.title, selectedText: window.getSelection().toString().trim(), // 可以尝试获取更简洁的页面正文这里是一个简单示例 bodyText: document.body.innerText.substring(0, 5000) // 限制长度 }; sendResponse({ success: true, data: pageInfo }); } // 监听其他 action... }); // 可以主动向后台脚本发送消息例如当页面加载完成时 // window.addEventListener(load, () { // chrome.runtime.sendMessage({action: pageLoaded}); // });这个脚本主要充当数据提供者。当弹出页面需要当前网页信息时会向内容脚本发送getPageContent消息。6.2 实现弹出页面作为主要操作界面popup.html:!DOCTYPE html html head titleChatGPT 助手/title style body { width: 350px; padding: 15px; font-family: sans-serif; } textarea, input { width: 100%; box-sizing: border-box; margin-bottom: 10px; padding: 8px; } button { width: 100%; padding: 10px; margin-bottom: 5px; background-color: #007bff; color: white; border: none; cursor: pointer; } button:disabled { background-color: #ccc; } #result { margin-top: 15px; padding: 10px; border: 1px solid #ddd; background-color: #f9f9f9; white-space: pre-wrap; max-height: 300px; overflow-y: auto; } .status { font-size: 0.9em; color: #666; margin-bottom: 10px; } .error { color: #d9534f; } .success { color: #5cb85c; } /style /head body h3分析当前网页/h3 div classstatus idpageStatus正在获取页面信息.../div textarea idcustomPrompt rows3 placeholder请输入你想问的问题例如总结这篇文章请总结这个网页的主要内容。/textarea button idanalyzeBtn发送到 ChatGPT/button div idresult/div psmalla href# idoptionsLink设置 API 密钥/a/small/p script srcpopup.js/script /body /htmlpopup.js:document.addEventListener(DOMContentLoaded, async function() { const pageStatus document.getElementById(pageStatus); const customPrompt document.getElementById(customPrompt); const analyzeBtn document.getElementById(analyzeBtn); const resultDiv document.getElementById(result); const optionsLink document.getElementById(optionsLink); let currentPageInfo null; // 1. 弹出页面打开时立即获取当前标签页的信息 try { // 获取当前活跃的标签页 const [tab] await chrome.tabs.query({ active: true, currentWindow: true }); // 向该标签页的内容脚本发送消息获取页面内容 const response await chrome.tabs.sendMessage(tab.id, { action: getPageContent }); if (response response.success) { currentPageInfo response.data; pageStatus.textContent 已就绪${currentPageInfo.title}; pageStatus.className status success; } else { throw new Error(无法从页面获取内容。); } } catch (error) { console.error(获取页面信息失败:, error); pageStatus.textContent 无法获取页面信息。请刷新页面或确保扩展有权访问此页面。; pageStatus.className status error; analyzeBtn.disabled true; } // 2. 发送分析请求 analyzeBtn.addEventListener(click, async () { if (!currentPageInfo) { showResult(错误无页面信息。, true); return; } const prompt customPrompt.value.trim() || 请总结这个网页的主要内容。; analyzeBtn.disabled true; analyzeBtn.textContent 思考中...; resultDiv.textContent ; try { // 将用户指令和页面上下文发送给后台脚本 const response await chrome.runtime.sendMessage({ action: callChatGPT, data: { prompt: prompt, context: 网页标题${currentPageInfo.title}\n网页URL${currentPageInfo.url}\n网页正文部分${currentPageInfo.bodyText} } }); if (response.success) { showResult(response.reply, false); } else { showResult(错误${response.error}, true); } } catch (error) { console.error(通信失败:, error); showResult(请求失败${error.message}, true); } finally { analyzeBtn.disabled false; analyzeBtn.textContent 发送到 ChatGPT; } }); // 3. 打开选项页面 optionsLink.addEventListener(click, (e) { e.preventDefault(); chrome.runtime.openOptionsPage(); }); function showResult(text, isError) { resultDiv.textContent text; resultDiv.style.color isError ? #d9534f : #333; resultDiv.style.fontWeight isError ? bold : normal; } });交互流程详解popup.js加载当用户点击扩展图标popup.html被打开popup.js执行。获取当前标签页chrome.tabs.query用于获取当前窗口下激活的标签页对象。与内容脚本通信chrome.tabs.sendMessage向特定标签页通过tab.id指定的内容脚本发送消息。内容脚本 (content.js) 中的监听器收到getPageContent消息后收集页面信息并返回。与后台脚本通信当用户点击“发送”按钮popup.js使用chrome.runtime.sendMessage将用户指令和页面上下文发送给后台脚本 (background.js)。处理响应后台脚本调用 OpenAI API 并返回结果popup.js将结果显示在弹出窗口中。7. 加载、测试与调试7.1 加载扩展程序打开 Chrome 浏览器进入chrome://extensions/。打开右上角的“开发者模式”开关。点击“加载已解压的扩展程序”按钮。选择你创建的chatgpt-browser-extension项目文件夹。扩展程序应该会出现在列表中并显示在浏览器工具栏。7.2 测试流程设置 API 密钥右键点击工具栏上的扩展图标选择“选项”。在打开的选项页面中输入你的 OpenAI API 密钥并保存。打开一个网页例如一篇新闻文章。点击扩展图标弹出窗口应显示“已就绪[网页标题]”。发送请求在文本框中输入问题或使用默认的总结问题点击“发送到 ChatGPT”。查看结果等待几秒后AI 的回复应该会显示在结果框中。7.3 常见问题排查在开发过程中你可能会遇到以下问题问题现象可能原因检查与解决步骤扩展图标不显示或无法点击manifest.json格式错误或关键文件缺失。1. 检查chrome://extensions/页面扩展列表下是否有错误信息。2. 检查manifest.json的 JSON 格式是否正确可使用 JSON 验证工具。3. 确认popup.html、background.js等文件路径与manifest.json中声明的一致。弹出页面显示“无法获取页面信息”内容脚本未成功注入或通信失败。1. 在目标网页上右键 - “检查”打开开发者工具切换到 Console 标签页查看是否有来自内容脚本的错误。2. 在 Console 中输入chrome.runtime看是否可用以确认内容脚本已注入。3. 检查manifest.json中content_scripts的matches字段是否包含了当前网页的 URL 模式。点击“发送”后无反应或报错“未设置 API 密钥”API 密钥未保存或后台脚本读取失败。1. 确认已在选项页面成功保存密钥保存后应有成功提示。2. 在chrome://extensions/页面找到你的扩展点击“service worker”链接进入后台脚本的控制台查看console.error输出。3. 在后台脚本的callOpenAIChatAPI函数开始处添加console.log(API Key:, apiKey)检查是否成功读取。请求失败控制台显示网络错误或 CORS 错误缺少host_permissions或 API 密钥无效。1.首要检查确认manifest.json中已正确声明host_permissions: [https://api.openai.com/*]。2. 在后台脚本的 Service Worker 控制台查看fetch请求的详细错误信息。如果是 401通常是 API 密钥错误如果是 429可能是达到速率限制。3. 前往 OpenAI API 使用情况页面 检查额度。弹出页面在点击按钮后卡住然后按钮恢复但无结果后台脚本的异步消息处理未正确返回true。确保background.js中的chrome.runtime.onMessage监听器在发起异步操作如callOpenAIChatAPI时最后一行有return true;。调试技巧后台脚本在chrome://extensions/页面找到你的扩展点击“service worker”旁边的链接会打开一个独立的开发者工具窗口。弹出页面右键点击扩展图标弹出的窗口选择“检查”。内容脚本在目标网页上按 F12 打开开发者工具其 Console 和 Sources 面板中可以看到内容脚本的日志和代码。8. 生产环境注意事项与扩展方向一个能在学习环境运行的原型与一个健壮、可投入实际使用的扩展之间还有不少差距。8.1 安全与隐私最佳实践永远不要硬编码 API 密钥本文的方案存储在chrome.storage.local是基础做法。对于团队或分发应考虑更安全的方案如通过你的后端服务器中转请求由服务器持有密钥扩展只与你的服务器通信。最小权限原则manifest.json中的permissions和host_permissions只声明真正需要的。例如如果功能不需要修改页面就不要申请activeTab或scripting。内容脚本的谨慎操作内容脚本能访问页面 DOM要避免执行可能破坏页面功能或引发安全风险的代码。获取的页面内容应仅限于功能所需并告知用户。隐私政策如果你的扩展会收集或发送用户数据即使是发送到 OpenAI应考虑提供隐私政策说明。8.2 功能增强与优化添加上下文菜单让用户可以直接在网页上选中文本右键调用 ChatGPT。// 在 background.js 中 chrome.runtime.onInstalled.addListener(() { chrome.contextMenus.create({ id: chatgptAnalyze, title: 使用 ChatGPT 分析, contexts: [selection] // 仅在选中文本时显示 }); }); chrome.contextMenus.onClicked.addListener((info, tab) { if (info.menuItemId chatgptAnalyze) { // 处理选中的文本 chrome.tabs.sendMessage(tab.id, {action: analyzeSelection, text: info.selectionText}); } });支持流式响应OpenAI API 支持 Server-Sent Events (SSE) 流式传输。你可以修改后台脚本和前端实现打字机效果提升用户体验。模型与参数配置在选项页面中允许用户选择模型如 gpt-3.5-turbo, gpt-4、设置temperature、max_tokens等。对话历史与持久化使用chrome.storage.local或chrome.storage.session保存对话历史实现多轮对话。错误处理与用户反馈提供更友好的错误提示如网络超时、额度不足、内容过长等。国际化使用chrome.i18nAPI 支持多语言。8.3 发布前检查清单在考虑将扩展发布到 Chrome 网上应用店前请完成以下检查[ ] 图标齐全且符合尺寸要求16, 48, 128像素。[ ]manifest.json中的name、description、version准确无误。[ ] 所有声明的权限都是功能必需的并在描述中说明用途。[ ] 已移除所有调试用的console.log语句或至少移除敏感信息。[ ] 选项页面清晰说明了 API 密钥的用途和存储方式。[ ] 在多种类型网页简单页、复杂SPA、PDF查看器等上进行了基本功能测试。[ ] 阅读并遵守 Chrome 网上应用店开发者计划政策 。通过以上步骤你不仅构建了一个可用的 ChatGPT 浏览器扩展更掌握了 Chrome 扩展开发的核心模式清单配置、权限管理、后台脚本与内容脚本的通信、安全存储以及与外部的 API 集成。这个模式可以复用于集成其他 AI 服务或任何需要与网页内容交互的浏览器自动化工具。