GPT-5 Token Count

Display the estimated token count of the conversation below the last answer.

目前為 2025-10-04 提交的版本,檢視 最新版本

// ==UserScript==
// @name         GPT-5 Token Count
// @description  Display the estimated token count of the conversation below the last answer.
// @version      1.1
// @author       C89sd
// @namespace    https://greasyfork.org/users/1376767
// @match        https://chatgpt.com/c/*
// @run-at       document-body
// @noframes
// ==/UserScript==

'use strict';

const CONF_SHOW_ALL_COUNTS = false;

const selector = "article .text-message";
const root = document.documentElement;
const counts = [];
let prevTk = null;

let c = 0;
const observer = new MutationObserver(muts => {
  for (const m of muts) {
    let t = m.target;

    if      (m.type === "attributes" && t.nodeType === Node.ELEMENT_NODE && t.tagName === "ARTICLE") {}
    else if (m.type === "childList"  && t.nodeType === Node.ELEMENT_NODE && t.tagName === "DIV" && t.classList.contains('group/turn-messages')) {}
    else continue;

    // console.log(t.tagName, t.classList, m.type, t)

    const article = t?.closest('article');
    const text = article?.querySelector('.text-message');
    // console.log('AAAA' , t, t.className, m.type, article, text)
    if (!text) continue;

    const msgUid = article.getAttribute("data-turn-id");
    const msgId  = article.getAttribute("data-testid");
    const assist = article.getAttribute("data-turn") === 'assistant';
    const id     = parseInt(msgId.split('-').pop() ?? '0', 10);
    const count  = Math.round(text.textContent.trim().length * 0.235); // 0.235 tokens/char

    // wipe all later indices
    counts.length = id;
    counts[id - 1] = count;
    const total = counts.reduce((a, b) => a + b, 0);
    const formatted = Number(total).toLocaleString('en-US');

    // console.log({assist})
    if (assist) {
      // setTimeout(() => {
        const threeDots = article.querySelector('button[aria-label="More actions"]');
        const parent = threeDots?.parentElement;
        console.log({threeDots, parent})
        if (parent) {
          const label = document.createElement('span');
          console.log({label})
          label.textContent = formatted;
          label.style.opacity = '0.5';
          label.style.fontSize = '.825em';
          // label.style.fontFamily = 'monospace';
          label.style.marginLeft = 'auto';
          parent.appendChild(label);

          if (!CONF_SHOW_ALL_COUNTS && prevTk) prevTk.remove(); // keep only last one
          prevTk = label;
        }
      // }, 200)
    }
    // console.log({i:c++,attribute:m.attributeName,nodeType:t.nodeType,nodeName:t.nodeName,msgUid,msgId,article,text,count,id,});
    console.log('id', id, ', total', total, counts)
  }
});

observer.observe(root, {
  subtree: true,
  attributes: true,
  childList: true,
});