浏览器自动化与AI结合:基于谷歌浏览器插件调用Nanbeige 4.1-3B
浏览器自动化与AI结合:基于谷歌浏览器插件调用Nanbeige 4.1-3B
你有没有过这样的体验?在网上阅读一篇长文,想快速抓住核心观点;或者看到一段外文资料,需要立刻翻译成中文;又或者想对一段文案进行润色,让它更专业、更有吸引力。通常,你需要复制文本,打开另一个AI工具,粘贴,等待结果,再复制回来。这个过程繁琐且打断了你的阅读和工作流。
如果能直接在网页上,选中文本,一键完成所有操作,那该多方便?今天,我们就来聊聊如何打造这样一个“网页上的AI瑞士军刀”——一个谷歌浏览器插件,它能无缝调用你本地部署的Nanbeige 4.1-3B大模型,实现文本的即时总结、翻译、改写,甚至进行深度搜索。
这不仅仅是技术上的整合,更是对工作流的一次彻底优化。想象一下,在浏览技术文档、查阅论文、阅读新闻时,一个右键菜单就能为你提供智能辅助,效率的提升是立竿见影的。下面,我将带你一步步实现这个想法,从插件的基础结构到与本地AI模型的通信,让你也能拥有一个专属的网页智能助手。
1. 为什么要在浏览器里集成AI?
在深入代码之前,我们先聊聊“为什么”。将AI能力直接嵌入浏览器,其价值远超一个简单的工具聚合。
最直接的感受是效率的飞跃。传统的“复制-切换应用-粘贴-等待-再复制”流程被简化为“选中-点击”两步。这个看似微小的改变,在实际高频使用中节省的时间是惊人的。它消除了上下文切换的成本,让你能完全沉浸在当前浏览的页面中。
其次,是场景的深度融合。AI处理的结果可以直接应用于原网页内容。例如,翻译后的文本可以悬浮显示在原文字旁边,总结的要点可以一键插入到你的笔记软件中,改写的文案能直接替换网页表单里的内容。这种“所见即所得,所点即所用”的体验,是独立AI应用难以提供的。
最后,结合本地部署的模型如Nanbeige 4.1-3B,还带来了隐私与可控性的优势。你的所有文本数据都在本地进行处理,无需上传到第三方服务器,这对于处理敏感或机密信息尤为重要。同时,你可以根据自己的需求调整模型的参数,获得更符合预期的结果。
我们的目标,就是构建一个轻量、快速、安全且强大的桥梁,连接起开放的网页世界和你本地的智能大脑。
2. 项目蓝图:插件如何与AI对话
一个谷歌浏览器插件,本质上是一组HTML、CSS、JavaScript和配置文件(Manifest)的集合。要让它在网页中捕获文本,并与后台的AI模型通信,我们需要设计一个清晰的架构。
整个系统可以看作三个核心部分:
- 内容脚本(Content Script):这是插件的“触手”。它被注入到我们访问的每一个网页中,负责监听我们的操作(比如鼠标选中文本),并捕获选中的内容。它生活在网页的上下文中,可以直接操作DOM。
- 后台脚本/服务(Background Service):这是插件的“大脑”和“调度中心”。它一直在后台运行,不直接与网页交互。它的核心职责是接收来自内容脚本的请求,然后代表插件去和“外部世界”——也就是我们本地运行的Nanbeige 4.1-3B模型API——进行通信。
- 用户界面(UI):这是插件的“脸”。通常是一个简单的弹出页面(Popup),用于展示设置选项,或者作为另一种触发AI功能的入口。在我们的场景中,更常见的是通过右键菜单(Context Menu)或页面内悬浮按钮来触发。
数据流是这样的:你在网页上选中文本 → 内容脚本捕获文本并发送消息给后台脚本 → 后台脚本向本地AI API发送HTTP请求 → AI模型返回处理结果 → 后台脚本将结果传回给内容脚本 → 内容脚本将结果以弹窗、侧边栏或直接修改DOM的方式展示给你。
理解了这套流程,我们就可以开始动手搭建了。
3. 第一步:搭建插件的基础骨架
首先,创建一个新的文件夹,比如叫做nanbeige-browser-helper。所有插件文件都将放在这里。
3.1 核心配置文件:manifest.json
这是插件的“身份证”和“说明书”,必须放在根目录下。
{ "manifest_version": 3, "name": "网页AI助手 (Nanbeige 4.1-3B)", "version": "1.0", "description": "选中网页文本,调用本地Nanbeige模型进行总结、翻译、改写等操作。", "permissions": [ "activeTab", "contextMenus", "storage" ], "host_permissions": [ "http://localhost:*/*", "http://127.0.0.1:*/*" ], "background": { "service_worker": "background.js" }, "content_scripts": [ { "matches": ["<all_urls>"], "js": ["content.js"], "css": ["content.css"] } ], "action": { "default_popup": "popup.html", "default_icon": { "16": "icons/icon16.png", "48": "icons/icon48.png", "128": "icons/icon128.png" } }, "icons": { "16": "icons/icon16.png", "48": "icons/icon48.png", "128": "icons/icon128.png" } }关键点解释:
manifest_version: 3:必须使用Manifest V3,这是谷歌浏览器插件的新标准。permissions:申请插件需要的权限。activeTab:获取当前活动标签页的信息。contextMenus:创建右键菜单。storage:存储用户设置(如本地API地址)。
host_permissions:非常重要!这里我们允许插件访问本地环回地址(localhost/127.0.0.1)的任何端口。因为你的Nanbeige模型API很可能就在http://localhost:8000或类似地址上运行。background.service_worker:指定后台脚本文件。content_scripts:定义注入到所有网页(<all_urls>)的内容脚本和样式。action:定义了浏览器工具栏图标点击后弹出的页面,以及图标资源。
3.2 创建后台调度中心:background.js
后台脚本负责创建右键菜单,并处理来自内容脚本的请求。
// background.js // 存储本地API的基础URL,可以从存储中读取或使用默认值 let apiBaseUrl = 'http://localhost:8000'; // 监听插件安装事件,创建右键菜单 chrome.runtime.onInstalled.addListener(() => { chrome.contextMenus.create({ id: "nanbeige-process", title: "使用Nanbeige处理", contexts: ["selection"] // 仅在选中文本时显示 }); // 创建子菜单项 chrome.contextMenus.create({ id: "summarize", parentId: "nanbeige-process", title: "总结摘要", contexts: ["selection"] }); chrome.contextMenus.create({ id: "translate", parentId: "nanbeige-process", title: "翻译成中文", contexts: ["selection"] }); chrome.contextMenus.create({ id: "rewrite", parentId: "nanbeige-process", title: "润色改写", contexts: ["selection"] }); // 可以继续添加更多功能,如“深度搜索”、“解释代码”等 console.log('Nanbeige AI助手插件已安装,右键菜单创建成功。'); }); // 监听右键菜单点击事件 chrome.contextMenus.onClicked.addListener((info, tab) => { // 确保是在选中文本且点击了我们创建的菜单项 if (info.menuItemId && info.selectionText && ['summarize', 'translate', 'rewrite'].includes(info.menuItemId)) { const selectedText = info.selectionText; const action = info.menuItemId; // 首先,通知内容脚本:准备展示一个加载状态 chrome.tabs.sendMessage(tab.id, { type: 'PROCESSING_START' }).catch(err => console.log('页面未加载内容脚本,忽略初始化消息。')); // 然后,调用AI处理函数 processWithAI(selectedText, action, tab.id); } }); // 核心函数:调用本地AI API async function processWithAI(text, action, tabId) { // 构建请求体,格式需要匹配你的Nanbeige API let prompt = ''; switch (action) { case 'summarize': prompt = `请用中文简要总结以下文本的核心内容:\n\n${text}`; break; case 'translate': prompt = `请将以下文本翻译成流畅、专业的中文:\n\n${text}`; break; case 'rewrite': prompt = `请对以下文本进行润色和改写,使其更通顺、更有文采:\n\n${text}`; break; default: prompt = text; } const requestBody = { model: "nanbeige-4.1-3b", // 根据你的模型名称调整 messages: [ { role: "user", content: prompt } ], stream: false // 我们一次性获取结果 }; try { const response = await fetch(`${apiBaseUrl}/v1/chat/completions`, { // 假设使用OpenAI兼容的API端点 method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(requestBody) }); if (!response.ok) { throw new Error(`API请求失败: ${response.status}`); } const data = await response.json(); const aiResponse = data.choices[0]?.message?.content || '模型未返回有效内容。'; // 将处理结果发送回内容脚本,让其展示 chrome.tabs.sendMessage(tabId, { type: 'PROCESSING_RESULT', result: aiResponse, action: action }); } catch (error) { console.error('调用AI模型失败:', error); // 发送错误信息到内容脚本 chrome.tabs.sendMessage(tabId, { type: 'PROCESSING_ERROR', error: `处理失败: ${error.message}。请检查:1. 本地模型服务是否运行(如Ollama)。2. API地址(${apiBaseUrl})是否正确。` }); } }4. 第二步:让插件在网页中“活”过来
后台脚本准备好了,现在需要让网页感知到我们的插件。
4.1 网页内的触手:content.js
内容脚本负责与用户交互,并渲染结果。
// content.js // 创建一个用于显示结果的浮动容器 let resultContainer = null; // 监听来自后台脚本的消息 chrome.runtime.onMessage.addListener((request, sender, sendResponse) => { switch (request.type) { case 'PROCESSING_START': showLoadingIndicator(); break; case 'PROCESSING_RESULT': hideLoadingIndicator(); showResult(request.result, request.action); break; case 'PROCESSING_ERROR': hideLoadingIndicator(); showError(request.error); break; } }); // 显示加载动画 function showLoadingIndicator() { if (!resultContainer) { createResultContainer(); } resultContainer.innerHTML = `<div class="loading">AI正在思考中...</div>`; resultContainer.style.display = 'block'; } // 隐藏加载动画 function hideLoadingIndicator() { // 加载状态会被后续的结果或错误覆盖 } // 创建结果展示容器 function createResultContainer() { resultContainer = document.createElement('div'); resultContainer.id = 'nanbeige-ai-result'; document.body.appendChild(resultContainer); // 点击容器外部关闭它 document.addEventListener('click', (e) => { if (resultContainer && !resultContainer.contains(e.target)) { resultContainer.style.display = 'none'; } }); } // 展示AI处理结果 function showResult(result, action) { if (!resultContainer) { createResultContainer(); } const actionName = { 'summarize': '总结摘要', 'translate': '翻译结果', 'rewrite': '改写润色' }[action] || '处理结果'; resultContainer.innerHTML = ` <div class="result-header"> <strong>${actionName}</strong> <span class="close-btn">×</span> </div> <div class="result-content">${result.replace(/\n/g, '<br>')}</div> <div class="result-footer"> <button id="copyResultBtn">复制</button> </div> `; // 定位容器到鼠标选中的区域附近(简单实现,定位到页面中央) const viewportWidth = window.innerWidth; const viewportHeight = window.innerHeight; resultContainer.style.top = '50px'; resultContainer.style.left = `${(viewportWidth - 400) / 2}px`; // 假设容器宽400px resultContainer.style.display = 'block'; // 绑定关闭按钮事件 resultContainer.querySelector('.close-btn').addEventListener('click', () => { resultContainer.style.display = 'none'; }); // 绑定复制按钮事件 document.getElementById('copyResultBtn').addEventListener('click', () => { navigator.clipboard.writeText(result).then(() => { alert('结果已复制到剪贴板!'); }); }); } // 展示错误信息 function showError(errorMsg) { if (!resultContainer) { createResultContainer(); } resultContainer.innerHTML = `<div class="error">${errorMsg}</div>`; resultContainer.style.display = 'block'; }4.2 美化结果界面:content.css
为我们的浮动容器添加一些基本样式。
/* content.css */ #nanbeige-ai-result { display: none; position: fixed; z-index: 10000; /* 确保在最上层 */ top: 50px; width: 400px; max-height: 500px; background-color: #f9f9f9; border: 1px solid #ccc; border-radius: 8px; box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15); font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; overflow: hidden; } .result-header { background-color: #2c3e50; color: white; padding: 12px 15px; display: flex; justify-content: space-between; align-items: center; font-size: 16px; } .close-btn { cursor: pointer; font-size: 20px; line-height: 1; } .close-btn:hover { color: #ecf0f1; } .result-content { padding: 20px; max-height: 350px; overflow-y: auto; line-height: 1.6; color: #333; background-color: white; } .result-footer { padding: 12px 15px; text-align: right; border-top: 1px solid #eee; background-color: #f9f9f9; } #copyResultBtn { background-color: #3498db; color: white; border: none; padding: 8px 16px; border-radius: 4px; cursor: pointer; font-size: 14px; } #copyResultBtn:hover { background-color: #2980b9; } .loading, .error { padding: 30px; text-align: center; font-size: 14px; color: #7f8c8d; } .error { color: #e74c3c; }5. 第三步:连接你的本地AI大脑
插件本身已经就绪,现在需要让它知道和谁对话。这里假设你已经在本地通过类似Ollama或OpenAI-Compatible API Server部署了Nanbeige 4.1-3B模型。
- 启动你的模型服务。例如,使用Ollama运行
ollama run nanbeige:4.1-3b,它会默认在http://localhost:11434提供API服务。或者使用其他框架,确保其提供兼容OpenAI的/v1/chat/completions接口。 - 修改API地址。在
background.js文件的开头,将let apiBaseUrl = 'http://localhost:8000';修改为你的模型服务实际地址,例如http://localhost:11434。 - 调整请求格式。根据你的模型服务API文档,微调
processWithAI函数中的requestBody结构。上面的代码示例是遵循OpenAI的格式,大多数兼容服务都支持。
6. 第四步:加载、测试与优化
6.1 加载插件到浏览器
- 打开谷歌浏览器,进入
chrome://extensions/。 - 打开右上角的“开发者模式”。
- 点击“加载已解压的扩展程序”。
- 选择你创建的
nanbeige-browser-helper文件夹。 - 插件图标应该出现在浏览器工具栏。
6.2 进行功能测试
- 打开任意一个网页,比如一篇新闻文章。
- 用鼠标选中一段文本。
- 右键点击,你应该能看到“使用Nanbeige处理”的菜单及其子项。
- 点击“总结摘要”。页面上应该会出现一个加载提示,然后弹出一个美观的浮动窗口,里面是模型生成的总结内容。
- 尝试“翻译成中文”和“润色改写”功能。
- 点击结果窗口的“复制”按钮,测试复制功能。
- 点击窗口外的区域或“×”按钮,测试关闭功能。
6.3 可能遇到的问题与优化方向
- API连接失败:检查
background.js中的apiBaseUrl是否正确,以及本地模型服务是否正在运行。可以在浏览器中直接访问http://localhost:11434/v1/models(替换成你的地址)测试API是否通畅。 - 右键菜单不出现:检查
manifest.json中的permissions是否包含"contextMenus",以及content_scripts的matches是否匹配你测试的网页。 - 结果不显示:打开浏览器的开发者工具(F12),切换到
Console标签页,查看是否有来自内容脚本或后台脚本的错误日志。 - 功能扩展:
- 添加快捷键:在
manifest.json中配置commands,实现快捷键触发。 - 增加设置页面:创建一个
options.html页面,让用户可以自由配置API地址、模型参数、默认操作等。 - 优化UI:让结果浮动窗可以拖动,或者定位到鼠标光标附近。
- 增加模型:在后台脚本中支持调用多个不同的本地模型,让用户选择。
- 添加快捷键:在
整个项目搭建下来,你会发现核心逻辑其实非常清晰:捕获、发送、处理、展示。这个框架具有很强的扩展性,你可以轻松地将“总结翻译”替换成“代码解释”、“情感分析”、“提取关键词”等任何你的本地模型支持的能力。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
