Chrome拡張からOpenAI APIを利用するサンプル

Chrome拡張で、閲覧中のページの情報をOpenAIのGPT-3.5やGPT-4に送って要約したり分析してもらったら便利だなと思いました。Chrome拡張は中身はJavaScriptだし、fetchでOpenAI APIのエンドポイントにポイすればすぐだろうと思ったら、そうも行かずに割とハマったのでメモです。

要約

  • Chrome拡張はManifest v3になって権限とかbackgroundとかちゃんと設定しないといけなくなった

  • fetchはbackgroudで処理する必要がある

  • manifest.jsonのpermissionsでhttps://ai.openai.com を指定する必要がある

とはいえ、私も完全に理解しているわけではなく、ChatGPTやMDNとの深夜のコピペ連撃でなんとかした感じですので、ソースをペッと貼っておきます。

もっともシンプルなサンプルとして、閲覧中のページのtitleを取得して、gpt-3.5-turboに評価させて、ポップアップウインドウに表示させるというものを作ってみました。

manifest.json

{
    "name": "title2gpt35",
    "description": "My Extension",
    "version": "1.0",
    "manifest_version": 3,
    "action": {
      "default_popup": "popup.html"
    },
    "permissions": [
      "activeTab",
      "scripting",
      "https://api.openai.com/"
    ],
    "background": {
      "service_worker": "background.js"
    }
  }

background.js

chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
  if (request.type === "fetchGPT35Turbo") {
    fetchGPT35Turbo(request.text)
      .then((content) => {
        sendResponse({ success: true, content: content });
      })
      .catch((error) => {
        sendResponse({ success: false, error: error.message });
      });
    return true; // keep the message channel open for sendResponse
  }
});

async function fetchGPT35Turbo(text) {
  const apiKey = "<YOUR_API_KEY>";
  const response = await fetch("https://api.openai.com/v1/chat/completions", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${apiKey}`,
    },
    body: JSON.stringify({
        model: "gpt-3.5-turbo",
        messages: [
          { role: "system", content: "この記事タイトルは、バズる要素を持つ適切なタイトルかどうか分析してください" },
          { role: "user", content: text },
        ],
        max_tokens: 100,
        temperature: 0.9,
      }),
  });

  if (!response.ok) {
    const errorData = await response.json();
    console.error(`Error: ${errorData.error.message}`);
    throw new Error(`API request failed: ${response.status}`);
  }

  const data = await response.json();
  return data.choices[0].message.content.trim();
}

popup.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
  <body>
    <h1>popup</h1>

    <textarea id="result"></textarea>
    <script src="popup.js"></script>

    <style>
      h1 {
        font-size: 1.2em;
      }
    </style>
  </body>
</html>

popup.js

async function main() {
  //アクティブなタブを取得
  let [tab] = await chrome.tabs.query({ active: true, currentWindow: true });

  chrome.scripting
    .executeScript({
      target: { tabId: tab.id },
      function: async function () {
        async function fetchGPT35Turbo(text) {
          return new Promise((resolve, reject) => {
            chrome.runtime.sendMessage(
              { type: "fetchGPT35Turbo", text: text },
              (response) => {
                if (chrome.runtime.lastError) {
                  reject(chrome.runtime.lastError.message);
                  return;
                }
                if (response.success) {
                  resolve(response.content);
                } else {
                  reject(response.error);
                }
              }
            );
          });
        };

        //titleタグのテキストを取得
        var title = document.title.toString();

        //titleをOpenAIに渡す
        var text = title;
        console.log(text);
        var result = await fetchGPT35Turbo(text);
        console.log(result.toString());

        return (result.toString());
      },
    })
    .then(function (r) {
      //実行結果をポップアップウィンドウへ表示
      document.getElementById("result").innerHTML = r[0].result;
    });
}
main();

これらを同じフォルダに入れて、Chrome拡張の管理画面からデベロッパーモードをONにし、「パッケージ化されていない拡張機能を読み込む」でそのフォルダを指定すれば、有効になります。あとはツールバーのボタンとして配置したりすれば使えるはずです。

ちょっとスクレイピングの知識があれば、海外のニュースサイトの要約をワンクリックで実現したりと夢が広がる気がします。(スクレイピングはサイトによっては利用規約で禁止されていたりするのでその辺は良く確認しましょう)

というわけで、Chrome ExtensionからOpenAI APIを使うためのメモでした。

この記事が気に入ったらサポートをしてみませんか?