news 2026/9/27 22:08:02

AI实现个人阅读网页插件:用TaoToken统一Key打通Chrome插件配置

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AI实现个人阅读网页插件:用TaoToken统一Key打通Chrome插件配置

1. 从「读不完的网页」到一键摘要:这个插件到底解决什么问题

每天打开浏览器,收藏夹里躺着几十篇「稍后阅读」,GitHub 上点开的项目 README 越滚越长,技术博客动辄上万字。逐字读完不现实,可只扫标题又怕漏掉关键信息。我想要的其实很简单:打开任意网页,按一个快捷键,侧边栏直接弹出这段内容的结构化摘要,再顺手问几个追问,读完摘要再决定要不要深读原文。

这个需求落到 Chrome 插件上,核心链路只有四步:快捷键唤起 → 抓取当前标签页正文 → 把正文发给大模型 → 把返回的摘要渲染到弹窗。听起来不复杂,但真正动手时会卡在三个地方:manifest.json 的权限声明写不对,background.js 的消息转发收不到响应,以及最要命的——每接一个模型就要换一套 Key 和请求格式,settings.json 里塞满各种 base_url 和 api_key,维护成本比写业务逻辑还高。

这篇就聚焦「个人阅读类 Chrome 插件」的落地配置,把 manifest.json、background.js、settings.json 三个文件的骨架给全,并说明怎么用 TaoToken 的统一 Key 和 API 通道,让插件只认一个地址、一个 Key,就能在多个模型之间切换。适合有基础 JS 能力、想自己做一个阅读辅助插件、但不想在模型接入上反复折腾的人。全程可复制,跟着改完就能加载运行。

2. 前置准备:TaoToken 统一 Key 与 API 通道

在写插件代码之前,先把「模型通道」这件事定下来。传统做法是插件里硬编码某家厂商的 endpoint,比如https://api.xxx.com/v1/chat/completions,再配一个该厂商的 Key。问题是:你想换个模型试试摘要效果,就得改代码、改 Key、重新加载插件;想同时支持摘要和翻译两个不同模型,settings.json 里就得维护两套配置。

TaoToken 的思路是提供一个统一的 API 通道,插件侧只认一个 base_url 和一个 Key,具体调用哪个模型由请求体里的model字段决定。这样 settings.json 里只需要存一份凭证,切换模型只是改一个字符串。

你需要先拿到两样东西:

第一是 API Key。登录 TaoToken 控制台,在 API Keys 页面创建一个新 Key,复制保存。这个 Key 就是插件 settings.json 里要填的值。

第二是 API 地址。统一通道的 base_url 是https://taotoken.net/api,注意这里不带任何查询参数,直接作为请求前缀使用。完整的对话补全路径是https://taotoken.net/api/v1/chat/completions,和 OpenAI 兼容格式一致,所以插件里用标准的 fetch 就能调通。

提示:Key 只存在本地 settings.json 或 chrome.storage 里,不要提交到 Git,也不要在 content script 里硬编码。插件发布时尤其注意别把 Key 打进包里。

如果你还没创建 Key,可以先到控制台的 API Keys 页面生成一个;想先确认通道是否可用,可以用模型对话页面手动发一条消息验证,确认能正常返回再写进插件。

3. 可复制配置:manifest.json 与 background.js 骨架

3.1 manifest.json:权限声明与快捷键

Chrome 插件的第一道门槛就是 manifest.json。阅读类插件需要三个关键权限:activeTab拿到当前标签页、scripting注入脚本抓正文、storage存配置。快捷键用commands声明,后台脚本用service_worker指定。

{ "manifest_version": 3, "name": "阅读摘要助手", "version": "1.0.0", "description": "快捷键唤起,抓取当前网页正文并调用 AI 生成摘要", "permissions": [ "activeTab", "scripting", "storage" ], "host_permissions": [ "https://taotoken.net/*" ], "commands": { "open-summary": { "suggested_key": { "default": "Ctrl+Shift+Z", "mac": "Command+Shift+Z" }, "description": "打开摘要面板" } }, "background": { "service_worker": "background.js" }, "action": { "default_title": "阅读摘要助手" } }

这里有两个容易踩的点。一是host_permissions必须包含https://taotoken.net/*,否则 background.js 里 fetch 会被跨域拦截,报Failed to fetch。二是 manifest v3 里 background 只能用service_worker,不能用 v2 的scripts数组,写错会直接加载失败。

3.2 background.js:消息转发与 API 调用

background.js 承担两个职责:监听快捷键、接收 content script 发来的正文并转发给 TaoToken。核心是chrome.commands.onCommand和chrome.runtime.onMessage两个监听器。

// background.js // 快捷键唤起:向当前标签页注入并激活摘要面板 chrome.commands.onCommand.addListener(async (command) => { if (command !== "open-summary") return; const [tab] = await chrome.tabs.query({ active: true, currentWindow: true }); if (!tab?.id) return; chrome.tabs.sendMessage(tab.id, { type: "TOGGLE_PANEL" }); }); // 接收 content script 的摘要请求,转发到 TaoToken chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => { if (msg.type === "SUMMARIZE") { callTaoToken(msg.text) .then((summary) => sendResponse({ ok: true, summary })) .catch((err) => sendResponse({ ok: false, error: err.message })); return true; // 异步响应必须返回 true } }); async function callTaoToken(pageText) { const { apiKey, model } = await chrome.storage.local.get(["apiKey", "model"]); if (!apiKey) throw new Error("未配置 API Key,请先在设置中填写"); const resp = await fetch("https://taotoken.net/api/v1/chat/completions", { method: "POST", headers: { "Content-Type": "application/json", "Authorization": `Bearer ${apiKey}` }, body: JSON.stringify({ model: model || "claude-3-5-sonnet", messages: [ { role: "system", content: "你是阅读助手。请用中文输出三段式摘要:核心观点、关键论据、一句话结论。控制在 200 字内。" }, { role: "user", content: pageText.slice(0, 12000) } ], temperature: 0.3 }) }); if (!resp.ok) { const detail = await resp.text(); throw new Error(`请求失败 ${resp.status}: ${detail.slice(0, 200)}`); } const data = await resp.json(); return data.choices?.[0]?.message?.content ?? "模型未返回内容"; }

return true这行是异步 sendResponse 的关键,漏掉的话 content script 会收到undefined,表现为「点了没反应」。正文截断到 12000 字符是防止超长页面把 token 打满,实际可按模型上下文调整。

3.3 settings.json:统一 Key 与模型配置

插件本身不直接读 settings.json,而是通过设置页写入chrome.storage.local。但为了让你有个可复制的配置模板,这里给一份 settings.json 结构,设置页读取后写入 storage 即可。

{ "apiBase": "https://taotoken.net/api", "apiKey": "sk-你的TaoToken密钥", "model": "claude-3-5-sonnet", "summaryPrompt": "请用中文输出三段式摘要:核心观点、关键论据、一句话结论。", "maxChars": 12000 }

设置页的保存逻辑大致是这样:

// options.js async function saveSettings() { const cfg = { apiKey: document.getElementById("apiKey").value.trim(), model: document.getElementById("model").value, maxChars: Number(document.getElementById("maxChars").value) || 12000 }; await chrome.storage.local.set(cfg); document.getElementById("status").textContent = "已保存"; } document.getElementById("save").addEventListener("click", saveSettings);

这样切换模型只需要在设置页改一个下拉框,不用动 background.js 一行代码。统一 Key 的好处在这里体现得很直接:摘要用 Claude、翻译用另一个模型,settings.json 里只维护一份 apiKey。

4. 验证请求:加载插件并确认摘要成功

代码写完,接下来是验证。这一步别跳过,很多「插件没反应」的问题都出在加载和权限确认上。

第一步,打开chrome://extensions/,右上角开启「开发者模式」,点「加载已解压的扩展程序」,选择你的插件目录。加载成功后能看到插件卡片,如果 manifest.json 有语法错误,这里会直接报红并提示行号。

第二步,点插件卡片里的「Service Worker」链接,打开后台调试面板。这一步很关键,background.js 的 console 输出和网络请求都在这里看。

第三步,随便打开一个内容较长的网页,按Ctrl+Shift+Z。如果 content script 注入正常,页面右侧会出现摘要面板。首次使用需要先到设置页填入 TaoToken 的 Key 和模型名。

第四步,在面板里点「生成摘要」,观察 Service Worker 面板的 Network 标签。应该能看到一条发往https://taotoken.net/api/v1/chat/completions的 POST 请求,状态码 200,响应体里choices[0].message.content就是摘要文本。

实测下来,从按键到摘要渲染出来大约 2 到 5 秒,取决于网页长度和模型响应速度。如果返回 401,说明 Key 没填对或没保存;返回 404,检查 base_url 是否写成了https://taotoken.net/api(正确)而不是带/v1的重复路径。

注意:manifest v3 的 service worker 会休眠,调试时如果发现监听器不触发,先在扩展页点一下「重新加载」,再重新打开调试面板。

5. 本篇常见错排查

报错一:Failed to fetch或net::ERR_BLOCKED_BY_CLIENT

九成是host_permissions没加https://taotoken.net/*。manifest v3 对跨域请求管得很严,background 里 fetch 外部域名必须在 host_permissions 里显式声明。改完记得重新加载插件。

报错二:content script 收不到TOGGLE_PANEL消息

检查chrome.tabs.sendMessage的目标 tab.id 是否存在。如果当前页是chrome://开头的内部页或扩展商店页,content script 无法注入,消息自然发不到。换一个普通网页测试。

报错三:sendResponse返回 undefined

background.js 的 onMessage 监听器里,异步分支必须return true,否则消息通道会在同步代码结束后立即关闭。这个坑很隐蔽,表现是「请求发出去了但面板一直转圈」。

报错四:401 Unauthorized

Key 没写对,或者写进了 settings.json 但没通过chrome.storage.local.set存进去。打开 Service Worker 调试面板,在 Console 里执行chrome.storage.local.get(["apiKey"], console.log)确认实际存储的值。

报错五:摘要内容为空或截断

maxChars设得太小,或者网页正文抓取逻辑把导航栏、评论区也算进去了。建议在 content script 里优先取document.querySelector("article")或main的 innerText,取不到再回退到document.body.innerText。

报错六:切换模型后仍走旧模型

chrome.storage.local有缓存,设置页保存后需要重新触发一次请求才会读到新值。如果确认保存了还是旧模型,在 Service Worker 面板执行chrome.storage.local.clear()后重新配置。

6. 把统一 Key 用顺:下一步可以怎么扩展

插件跑通摘要只是起点。阅读类场景里,翻译、追问、划词解释都是高频需求,而它们本质上都是「把一段文本发给模型、拿回结果」。既然 TaoToken 的统一 Key 已经打通,扩展时就不需要再引入新的凭证体系。

比如加一个划词翻译:在 content script 里监听mouseup,取window.getSelection().toString(),通过chrome.runtime.sendMessage发一个type: "TRANSLATE"的请求,background.js 里复用同一个callTaoToken函数,只改 system prompt 和 model 字段即可。想用更便宜的模型做翻译、用更强的模型做摘要,settings.json 里加一个translateModel字段就行。

如果你打算把这个插件长期用下去,甚至接上 Agent 做自动整理阅读笔记,可以了解一下 Coding Plan 这类面向长期编码和 Agent 场景的方案,配合统一 Key 能把多模型调用的成本和管理都收拢到一处。接入文档里有完整的请求格式和参数说明,排障时对照着看比盲猜快得多。

最后留一个我踩过的坑:content script 注入的摘要面板,样式一定要加z-index: 2147483647和position: fixed,否则会被某些网站的浮层盖住,表现为「按了快捷键但看不到面板」。这个和模型无关,但排查起来很费时间,提前加上省事。

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