尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

我做了一个用 TaoToken 统一 Key 记录技术文档阅读进度的 Chrome 插件

发布时间:2026/9/26 15:48:47

资讯中心
01
ARTICLE

我做了一个用 TaoToken 统一 Key 记录技术文档阅读进度的 Chrome 插件

我做了一个用 TaoToken 统一 Key 记录技术文档阅读进度的 Chrome 插件
1. 从「读到哪忘了」到「打开就续上」这个插件到底解决什么问题如果你经常啃 React、Playwright、Codex 这类官方文档大概率遇到过同一个尴尬三栏布局左边目录、中间正文、右边页内锚点查资料时很爽但想系统读完一章就很容易断片。浏览器书签只能记住 URL记不住你滚到了哪一段笔记软件又太重每次手动抄「读到 Hooks 第二节」纯属折磨。我做这个 Chrome 插件的出发点特别小只解决技术文档阅读进度记录这一件事顺便用 TaoToken 统一 Key 给插件加一个「AI 摘要当前章节」的轻能力让你隔几天回来时不仅知道读到哪还能三秒回忆这节讲了啥。它适合谁适合需要分多次读完一份官方文档的前端/测试/全栈同学适合同时开 React Learn、Playwright Docs、Codex Docs 好几个标签页的人也适合不想把阅读上下文全交给 AI、但偶尔想要一句摘要提神的人。它不适合当稍后读工具也不适合当通用网页阅读器——范围就锁在「开发者文档 阅读位置 轻摘要」。技术实现上分两块进度记录走chrome.storage.local纯本地、不上传页面内容AI 摘要走 TaoToken 的统一 API 通道Key 只存在本地插件通过 background service worker 发请求。下面我把可复制的manifest.json、background 骨架、Key 注入方式、以及加载后怎么验证进度同步和摘要生效一步步拆开讲。你照着做半小时内能跑起来一个能用的版本。2. 前置准备TaoToken 统一 Key 与通道配置在写代码之前先把「AI 能力从哪来」这件事定下来。我选择 TaoToken 的原因很实际插件里如果直接写某一家模型的地址和 Key后面换模型、加摘要长度、调温度都要改代码用统一 Key 和统一 API 通道后插件只认一个baseURL和一个apiKey模型名当参数传切换成本几乎为零。你需要先拿到两样东西第一是 API Key。打开控制台里的 API Keys 页面创建一个建议命名成chrome-docs-tracker这种能一眼看出用途的名字方便以后按插件维度吊销。创建后立刻复制页面刷新就看不到了。第二是确认请求地址。TaoToken 的 API 入口是https://taotoken.net/api注意这里不要加任何查询参数插件里拼接路径时保持干净。模型对话相关的能力都走这个 base具体模型名按你账号里可用的填。注意Key 不要硬编码进content.js或提交到 Git。Chrome 插件的正确做法是放在 background service worker 里通过chrome.storage.local读取content script 只发消息、不碰 Key。这样即使页面脚本被注入也拿不到你的凭证。如果你只是想先验证模型通不通可以先用模型对话页面手动发一条消息确认账号和 Key 是活的再进插件开发。这一步能省掉后面「到底是 Key 错还是代码错」的排查时间。3. 可复制配置manifest.json 与 background 骨架先建目录结构我习惯这样docs-progress-tracker/ ├── manifest.json ├── background.js ├── content.js ├── popup.html └── popup.js3.1 manifest.jsonManifest V3{ manifest_version: 3, name: Developer Docs Progress Tracker, version: 0.1.0, description: 记录技术文档阅读进度并用 TaoToken 统一 Key 生成章节摘要。, permissions: [storage, activeTab, scripting], host_permissions: [ https://react.dev/*, https://playwright.dev/*, https://taotoken.net/* ], background: { service_worker: background.js }, action: { default_popup: popup.html, default_title: Docs Progress }, content_scripts: [ { matches: [ https://react.dev/*, https://playwright.dev/* ], js: [content.js], run_at: document_idle } ] }几个关键点host_permissions里必须显式加上https://taotoken.net/*否则 background 发请求会被拦storage权限用于保存进度和 Keycontent_scripts的matches先只放你确定支持的文档站跑通后再加 Docusaurus、VitePress 这类通用匹配。3.2 background.jsKey 读取 摘要请求const API_BASE https://taotoken.net/api; const MODEL gpt-4o-mini; // 按你账号可用模型替换 async function getApiKey() { const { tt_api_key } await chrome.storage.local.get(tt_api_key); return tt_api_key || ; } async function summarize(text) { const apiKey await getApiKey(); if (!apiKey) throw new Error(NO_API_KEY); const res await fetch(${API_BASE}/v1/chat/completions, { method: POST, headers: { Content-Type: application/json, Authorization: Bearer ${apiKey} }, body: JSON.stringify({ model: MODEL, messages: [ { role: system, content: 你是技术文档助手用不超过80字总结这段文档的核心内容。 }, { role: user, content: text.slice(0, 4000) } ], temperature: 0.3 }) }); if (!res.ok) { const err await res.text(); throw new Error(API_${res.status}: ${err}); } const data await res.json(); return data.choices?.[0]?.message?.content?.trim() || ; } chrome.runtime.onMessage.addListener((msg, sender, sendResponse) { if (msg.type SUMMARIZE) { summarize(msg.text) .then((summary) sendResponse({ ok: true, summary })) .catch((e) sendResponse({ ok: false, error: e.message })); return true; // 异步响应必须返回 true } });这里有两个我踩过的坑一是onMessage里做异步必须return true否则sendResponse会失效二是text.slice(0, 4000)要留文档正文动辄上万字不截断既慢又费额度。3.3 content.js进度记录与恢复const KEY progress:${location.origin}${location.pathname}; function saveProgress() { const scrollTop window.scrollY; const total document.body.scrollHeight - window.innerHeight; const percent total 0 ? Math.min(100, Math.round((scrollTop / total) * 100)) : 0; chrome.storage.local.set({ [KEY]: { scrollTop, percent, ts: Date.now() } }); } function restoreProgress() { chrome.storage.local.get(KEY, (data) { const saved data[KEY]; if (saved saved.scrollTop 200) { window.scrollTo({ top: saved.scrollTop, behavior: instant }); } }); } let timer null; window.addEventListener(scroll, () { clearTimeout(timer); timer setTimeout(saveProgress, 500); }); restoreProgress();节流 500ms 是必须的不然滚动一次写几十遍 storageChrome 会警告。恢复时加scrollTop 200判断避免刚进页面就被拉到奇怪位置。3.4 popup.js注入 Key 与触发摘要const input document.getElementById(apiKey); const saveBtn document.getElementById(save); const sumBtn document.getElementById(summarize); const out document.getElementById(output); chrome.storage.local.get(tt_api_key, ({ tt_api_key }) { if (tt_api_key) input.value tt_api_key; }); saveBtn.onclick () { chrome.storage.local.set({ tt_api_key: input.value.trim() }, () { out.textContent Key 已保存到本地; }); }; sumBtn.onclick async () { const [tab] await chrome.tabs.query({ active: true, currentWindow: true }); const [{ result }] await chrome.scripting.executeScript({ target: { tabId: tab.id }, func: () document.querySelector(main)?.innerText || document.body.innerText }); out.textContent 摘要生成中...; chrome.runtime.sendMessage({ type: SUMMARIZE, text: result }, (res) { out.textContent res.ok ? res.summary : 失败${res.error}; }); };popup.html里放一个input、两个button、一个div#output即可结构简单不展开。4. 验证请求加载插件后确认进度同步与摘要生效代码写完进chrome://extensions打开右上角「开发者模式」点「加载已解压的扩展程序」选中docs-progress-tracker目录。加载成功后你应该看到插件卡片没有红色报错。验证进度同步打开https://react.dev/learn往下滚到「Describing the UI」附近停两秒然后关掉标签页重新打开同一 URL。页面应该自动滚回你上次的位置。再打开 popup如果之前存过 Key输入框应该回显。想确认存储内容可以在扩展的 service worker 控制台执行chrome.storage.local.get(null, console.log)你会看到形如progress:https://react.dev/learn的键里面是scrollTop、percent、ts。验证 AI 摘要在 popup 里粘贴 TaoToken 的 Key点保存再点「生成摘要」。正常情况下output区域会先显示「摘要生成中...」一两秒后出现一段不超过 80 字的中文总结。如果返回API_401说明 Key 没存进去或复制时带了空格返回API_404检查API_BASE后面拼的路径是不是/v1/chat/completions返回NO_API_KEY说明 popup 保存和 background 读取用的键名不一致两边都必须是tt_api_key。实测下来React Learn 这种正文在main里的站点摘要质量最稳Playwright Docs 有些页面正文分散在多个article可以在executeScript里把选择器改成document.querySelectorAll(article)再拼接。5. 本篇常见错排查报错Could not establish connection. Receiving end does not exist通常是 content script 没注入到当前页面。检查manifest.json的matches是否包含你正在测的域名改完 manifest 必须在扩展页点「重新加载」光刷新网页没用。滚动位置恢复了但摘要按钮没反应popup 里chrome.scripting.executeScript需要scripting权限和activeTab两个都要在 manifest 里声明。另外chrome://开头的页面不允许注入脚本别在扩展管理页测试。Key 保存后刷新 popup 又空了chrome.storage.local.set是异步的如果你在onclick里没等回调就关 popup可能没写进去。加个回调里更新 UI 提示确认写入完成再关。摘要返回空字符串模型可能把内容放进了reasoning_content或返回结构不同。先在模型对话页面用同样的 prompt 手动发一次确认返回结构再对照改data.choices[0].message.content的取值路径。进度在不同文档站串了KEY用的是origin pathname如果两个站点路径相同不会串真正会串的是你把 KEY 写成了固定字符串。检查模板字符串有没有漏掉location.pathname。service worker 休眠导致首次请求慢MV3 的 background 会休眠第一次发消息要唤醒属正常现象。如果超过 5 秒没响应在扩展页点 service worker 的「检查」看控制台有没有报错。6. 把 Key 管好把进度留住这个插件的定位一直很克制进度记录是主角AI 摘要只是锦上添花。所以 Key 的管理要单独说一句——它只存在chrome.storage.local不随插件代码分发也不经过任何第三方页面。你可以在 popup 里加一个「清除 Key」按钮对应chrome.storage.local.remove(tt_api_key)换机器或怀疑泄露时一键处理。如果你后面想把摘要能力扩展到更多文档站或者想给插件加一个「按章节自动生成阅读清单」的 Agent 式流程建议把模型调用统一收口到 backgroundcontent script 永远只发消息。这样无论你换哪个模型、调什么参数插件前端一行都不用动。需要长期跑编码类任务或 Agent 工作流的话可以看看 Coding Plan 的额度方案只想先验证模型通不通模型对话页面最快Key 的创建和吊销都在 API Keys 页面完成接入细节对照接入文档即可。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。