You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Chrome扩展点击启动ChatGPT邮件回复服务问题求助

解决Chrome扩展中启动ChatGPT邮件服务的问题

Chrome扩展运行在浏览器沙箱环境中,无法直接启动本地Node.js服务,所以你需要调整现有方案,以下是两种可行的实现路径:


方案一:将AI请求逻辑迁移到扩展后台(推荐,无需单独启动服务)

把原server.js中的OpenAI调用逻辑移到Chrome扩展的后台脚本里,避免依赖本地服务,同时注意API密钥的安全存储。

1. 更新manifest.json(改用Manifest V3,V2已被Chrome弃用)

{
  "manifest_version": 3,
  "name": "ChatGPT Email Assistant",
  "version": "1.0",
  "description": "An email assistant that uses the ChatGPT language model",
  "permissions": ["storage", "activeTab"],
  "host_permissions": ["https://api.openai.com/*"],
  "action": {
    "default_popup": "./client/index.html"
  },
  "background": {
    "service_worker": "background.js"
  }
}

2. 编写background.js(替代原server.js的逻辑)

const OPENAI_API_URL = "https://api.openai.com/v1/completions";

chrome.runtime.onMessage.addListener(async (request, sender, sendResponse) => {
  if (request.type === "generate_email_reply") {
    try {
      // 从存储获取API密钥(建议让用户在扩展设置中输入并保存)
      const { apiKey } = await chrome.storage.local.get("apiKey");
      if (!apiKey) {
        sendResponse({ error: "请先设置OpenAI API密钥" });
        return;
      }

      const response = await fetch(OPENAI_API_URL, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "Authorization": `Bearer ${apiKey}`
        },
        body: JSON.stringify({
          model: "text-davinci-003",
          prompt: `Reply this email: ${request.prompt}`,
          temperature: 0,
          max_tokens: 3000,
          top_p: 1,
          frequency_penalty: 0.5,
          presence_penalty: 0
        })
      });

      if (!response.ok) {
        const errData = await response.json();
        throw new Error(errData.error?.message || "请求失败");
      }

      const data = await response.json();
      sendResponse({ success: true, reply: data.choices[0].text.trim() });
    } catch (error) {
      sendResponse({ error: error.message || "生成回复失败" });
    }
    // 异步响应需要返回true
    return true;
  }
});

3. 修改popup的script.js(调用后台脚本而非本地服务)

移除原fetch localhost的逻辑,改用chrome.runtime.sendMessage:

// (保留原loader、typeText、generateUniqueId、chatStripe函数不变)

const handleSubmit = async (e) => {
  e.preventDefault();
  const data = new FormData(form);
  const prompt = data.get("prompt");
  if (!prompt.trim()) return;

  form.reset();
  form.classList.add('formdisplay');

  const uniqueId = generateUniqueId();
  chatContainer.innerHTML += chatStripe(true, " ", uniqueId);
  chatContainer.scrollTop = chatContainer.scrollHeight;
  const messageDiv = document.getElementById(uniqueId);
  loader(messageDiv);

  // 调用后台脚本生成回复
  chrome.runtime.sendMessage(
    { type: "generate_email_reply", prompt },
    (response) => {
      clearInterval(loadInterval);
      messageDiv.innerHTML = "";
      if (response.success) {
        typeText(messageDiv, response.reply);
      } else {
        messageDiv.innerHTML = "Oops! Something went wrong.";
        alert(response.error);
      }
    }
  );
};

// 保留原事件监听
form.addEventListener("submit", handleSubmit);
form.addEventListener("keyup", (e) => {
  if (e.keyCode === 13) {
    handleSubmit(e);
  }
});

// 移除原chrome.browserAction.onClicked监听(设置default_popup后该事件不会触发)

4. 添加API密钥设置(可选)

可以在popup中添加输入框让用户保存API密钥,示例代码:

<!-- 在client/index.html中添加 -->
<div class="settings">
  <input type="password" id="apiKeyInput" placeholder="输入OpenAI API密钥">
  <button id="saveKeyBtn">保存密钥</button>
</div>
// 在script.js中添加
document.getElementById("saveKeyBtn").addEventListener("click", async () => {
  const apiKey = document.getElementById("apiKeyInput").value.trim();
  if (apiKey) {
    await chrome.storage.local.set({ apiKey });
    alert("密钥保存成功");
  }
});

// 页面加载时读取已保存的密钥
window.addEventListener("DOMContentLoaded", async () => {
  const { apiKey } = await chrome.storage.local.get("apiKey");
  if (apiKey) {
    document.getElementById("apiKeyInput").value = apiKey;
  }
});

方案二:保留本地服务,提示用户手动启动

如果坚持使用原server.js的本地服务,需要在popup加载时检查服务是否可用,不可用则提示用户启动服务:

修改script.js中的handleSubmit逻辑

const checkServerStatus = async () => {
  try {
    const response = await fetch("http://localhost:5000");
    return response.ok;
  } catch {
    return false;
  }
};

const handleSubmit = async (e) => {
  e.preventDefault();
  const data = new FormData(form);
  const prompt = data.get("prompt");
  if (!prompt.trim()) return;

  // 先检查服务是否运行
  const serverRunning = await checkServerStatus();
  if (!serverRunning) {
    alert("请先运行`node server.js`启动AI服务");
    return;
  }

  // 以下保留原逻辑不变
  form.reset();
  form.classList.add('formdisplay');

  const uniqueId = generateUniqueId();
  chatContainer.innerHTML += chatStripe(true, " ", uniqueId);
  chatContainer.scrollTop = chatContainer.scrollHeight;
  const messageDiv = document.getElementById(uniqueId);
  loader(messageDiv);

  const response = await fetch("http://localhost:5000", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ prompt }),
  });

  clearInterval(loadInterval);
  messageDiv.innerHTML = "";
  if (response.ok) {
    const data = await response.json();
    const parsedData = data.bot.trim();
    typeText(messageDiv, parsedData);
  } else {
    const err = await response.text();
    messageDiv.innerHTML = "Oops! Something went wrong.";
    alert(err);
  }
};

原代码中的注意事项

  1. Manifest版本:原代码用Manifest V2,Chrome已停止对V2扩展的支持,必须升级到V3。
  2. popup脚本权限:原script.js中的chrome.browserAction.onClicked在设置default_popup后不会触发,因为点击扩展图标会直接打开popup。
  3. ES模块支持:如果popup脚本使用import语句,需要在manifest中给popup的html添加type="module"属性,或者改用CommonJS语法。

内容的提问来源于stack exchange,提问作者Sujansinh Thakor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 08:02:54