ChatGPTとの会話をテキストファイルで出力するChrome拡張機能を作成しました

# 作成した目的
　現在、社内業務での ChatGPT 利用を検討してます。利用にあたってログを取得できるようにしたいという話題が挙がったので、調査がてら Chrome の拡張機能を作成しました。
 
※社内用なので外部公開はしてませんが、本記事を見てもらえれば作成できると思います。

![Animation.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764512/c473f77f-4ba0-fbae-8b13-a5173c94fb4b.gif)


# 作成手順

今回作成した拡張機能 `ChatGPT-Prompts-Logger`  のフォルダ構成は以下の通りです。

```console
ChatGPT-Prompts-Logger
│   manifest.json
│   popup.html
│   popup.js
│   
└───images
        icon128.png
        icon16.png
        icon48.png
```

上から順に説明します。

- `manifest.json`
    - 拡張機能の設定を記述するファイルです。 

```json:manifest.json
{
  "manifest_version": 3,
  "name": "ChatGPT Prompts Logger",
  "version": "1.0",
  "description": "Log ChatGPT prompts to the txt file.",
  "permissions": ["activeTab", "scripting", "downloads"],
  "action": {
    "default_title": "ChatGPT Prompts Logger",
    "default_popup": "popup.html",
    "default_icon": {
      "16": "/images/icon16.png",
      "48": "/images/icon48.png",
      "128": "/images/icon128.png"
    }
  }
}
```

重要な項目だけ補足説明します。

- `permissions`
    - 使用する権限を宣言する項目です。今回は ChatGPTでの会話内容を取得するための `activeTab` `scripting` と、ファイルダウンロード用に `downloads`　を宣言してます。 

- `action.default_popup`
    - ブラウザのツールバーにある拡張機能のアクションボタンをクリックすると表示されるHTMLファイルを指定します。 


- `popup.html`
    - 拡張機能の簡単なレイアウトです。 

```html:popup.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8">
  <title>ChatGPT Prompts Logger</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      padding: 10px;
    }
    button {
      background-color: #4CAF50;
      color: white;
      padding: 10px 20px;
      border: none;
      cursor: pointer;
    }
    button:hover {
      background-color: #45a049;
    }
  </style>
</head>
<body>
  <h1>ChatGPT Prompts Logger</h1>
  <button id="log">Log to Download</button>
  <script src="popup.js"></script>
</body>
</html>

```

実際には↓のように表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3764512/031eb6c3-6540-8f3a-542e-0a0dab1c3a35.png)

:::note warn
head部で `<meta charset="UTF-8">` を宣言しないと、日本語が文字化けするので注意してください。
:::

-  `popup.js`
    -  ChatGPTとの会話内容の取得、ダウンロード処理を行います。 

```javascript:popup.js
document.getElementById("log").addEventListener("click", async () => {
  try {
    // アクティブなタブを取得
    let [tab] = await chrome.tabs.query({ active: true, currentWindow: true });

    // URLをチェックしてChatGPTのページか確認
    const chatGPTUrlPattern = /https:\/\/chatgpt\.com\/.*/;
    if (!chatGPTUrlPattern.test(tab.url)) {
      alert("この拡張機能は https://chatgpt.com でのみ利用可能です。");
      return;
    }

    // ChatGPTのページからプロンプトを取得
    chrome.scripting.executeScript(
      {
        target: { tabId: tab.id },
        func: () => {
          const messages = Array.from(
            document.querySelectorAll(".text-message")
          );
          return messages
            .map((msg) => msg.innerText)
            .join("\n\n////////////////////////////////////////////////////////////\n\n");
        },
      },
      (results) => {
        if (results && results[0] && results[0].result) {
          // 現在の日付と時間をファイル名とヘッダー文字として使用
          const date = new Date();
          const fileName = `chatgpt_prompts_${date.getFullYear()}${(
            date.getMonth() + 1
          )
            .toString()
            .padStart(2, "0")}${date
            .getDate()
            .toString()
            .padStart(2, "0")}_${date
            .getHours()
            .toString()
            .padStart(2, "0")}${date
            .getMinutes()
            .toString()
            .padStart(2, "0")}${date
            .getSeconds()
            .toString()
            .padStart(2, "0")}.txt`;

          const header = fileName + "\n\n////////////////////////////////////////////////////////////\n\n";

          //プロンプトの内容にヘッダー追加
          const chatContent = header + results[0].result;

          // ダウンロード処理を追加
          const blob = new Blob([chatContent], { type: "text/plain" });
          const url = URL.createObjectURL(blob);

          chrome.downloads.download({
            url: url,
            filename: fileName,
          });
        } else {
          console.error("No results or empty results returned.");
        }
      }
    );
  } catch (error) {
    console.error("Error logging prompts:", error);
  }
});

```

拡張機能特有のメソッドとしては、以下2つになります。

- `chrome.tabs.query()`
    - タブの情報を取得する非同期メソッドです。今回はユーザーが現在使用しているタブを取得したいので、引数に`{ active: true, currentWindow: true }` を渡してます。 
- `chrome.scripting.executeScript()`
    - 拡張機能から特定のタブに JavaScript を動的に注入し実行するためのメソッドです。今回はこのメソッドを使って、 `.text-message` クラスに記述された会話内容をすべて収集してます。 

他にもいろいろなことができるので、気になる方はAPIドキュメントを参照してください。


https://developer.chrome.com/docs/extensions/reference/api/tabs?hl=ja

https://developer.chrome.com/docs/extensions/reference/api/scripting?hl=ja


- `images` フォルダ
    - アイコン用に 16×16、48×48、128×128サイズの PNG ファイルが必要です。 

以上になります！

想像より簡単に作成できたので驚きました。また何かアイディアを思いついたら作成しようと思います。

# 参考文献


https://developer.chrome.com/docs/extensions/reference/permissions-list?hl=ja


https://developer.chrome.com/docs/extensions/reference/api/tabs?hl=ja


https://developer.chrome.com/docs/extensions/reference/api/scripting?hl=ja