完全准确查询你的GPT订阅周限的方法【油猴脚本】

yfzz 2026-05-09 10:14 1

首先感谢 完全准确查询你的GPT订阅周限的方法 提供的思路和 js 脚本。


基于大佬的内容优化为了油猴脚本,看起来更方便。


附个人 pro 20x 结果示例图:



打开 https://chatgpt.com/codex/cloud/settings/analytics#usage 页面使用


// ==UserScript==
// @name Codex Quota Compass (Visual Edition)
// @namespace http://tampermonkey.net/
// @version 1.8
// @description 人性化展示 Codex 配额,强化 Credits 标注,增加历史合计及动态日期范围(Token 以 M 为单位)
// @author Jun Zhao
// @match https://chatgpt.com/codex/cloud/settings/analytics*
// @grant GM_addStyle
// ==/UserScript==

(function () {
"use strict";

const CONFIG = {
USD_PER_CREDIT: 40 / 1000,
};

// 修改:将中文的“亿/万”单位替换为国际标准的“M/K”单位
const fmtNum = (n) => {
if (n >= 1e6) return (n / 1e6).toFixed(2) + "M";
if (n >= 1e3) return (n / 1e3).toFixed(2) + "K";
return n.toLocaleString();
};

const n = (v) => (Number.isFinite(Number(v)) ? Number(v) : 0);
const tokenTotal = (obj = {}) =>
n(obj.text_total_tokens) ||
n(obj.cached_text_input_tokens) +
n(obj.uncached_text_input_tokens) +
n(obj.text_output_tokens);

GM_addStyle(`
#codex-compass-root {
position: fixed; top: 5%; left: 50%; transform: translateX(-50%);
width: 720px; max-height: 90vh; background: #fff;
border-radius: 12px; box-shadow: 0 10px 50px rgba(0,0,0,0.3);
z-index: 10001; padding: 24px; display: none;
flex-direction: column; border: 1px solid #e5e5e5; color: #333;
font-family: -apple-system, system-ui, sans-serif;
}
.compass-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; }
.compass-title { font-size: 18px; font-weight: 600; }
.compass-close { cursor: pointer; font-size: 28px; color: #999; line-height: 1; }
.compass-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 20px; }
.compass-card { background: #f9f9f9; padding: 12px; border-radius: 8px; border: 1px solid #eee; }
.compass-card.highlight { background: #eefaf5; border-color: #d1f2e1; }
.card-label { font-size: 12px; color: #666; margin-bottom: 4px; }
.card-value { font-size: 15px; font-weight: bold; color: #10a37f; white-space: nowrap; }

.table-container {
max-height: 220px; overflow-y: auto; border: 1px solid #eee;
border-radius: 6px; margin-bottom: 15px;
}
.compass-table { width: 100%; border-collapse: collapse; font-size: 12px; }
.compass-table thead { position: sticky; top: 0; background: #f5f5f5; z-index: 1; }
.compass-table th { text-align: left; padding: 8px; border-bottom: 1px solid #eee; color: #666; }
.compass-table td { padding: 8px; border-bottom: 1px solid #f0f0f0; }
.compass-footer-row { background: #fafafa; font-weight: bold; position: sticky; bottom: 0; border-top: 2px solid #eee; }

#codex-compass-btn {
position: fixed; bottom: 20px; right: 20px; z-index: 10000;
padding: 10px 20px; background: #10a37f; color: white;
border: none; border-radius: 8px; cursor: pointer; font-weight: 600;
}
`);

async function apiGet(path, token) {
const res = await fetch(path, {
headers: { Authorization: `Bearer ${token}` },
});
return res.json();
}

const showPanel = (data) => {
const root = document.getElementById("codex-compass-root");
const { secondary, dailyList, cycleStartDate } = data;

// 1. 数据切分
const currentCycleList = [];
const historyList = [];
dailyList.forEach((item) => {
if (new Date(item.date) >= new Date(cycleStartDate)) {
currentCycleList.push(item);
} else {
historyList.push(item);
}
});

// 2. 统计计算辅助函数
const getStats = (list) => {
const credits = list.reduce(
(sum, d) => sum + (d.totals?.credits || 0),
0,
);
const turns = list.reduce((sum, d) => sum + (d.totals?.turns || 0), 0);
const tokens = list.reduce((sum, d) => sum + tokenTotal(d.totals), 0);
return { credits, turns, tokens, usd: credits * CONFIG.USD_PER_CREDIT };
};

const currentStats = getStats(currentCycleList);
const historyStats = getStats(historyList);

const ratio = (secondary?.used_percent || 0) / 100;
const estCredits =
ratio > 0 ? (currentStats.credits / ratio).toFixed(1) : "0";

// 3. 历史记录日期范围计算
let historyRangeTitle = "⏳ 历史记录 (本周期外)";
if (historyList.length > 0) {
const sortedHistory = [...historyList].sort(
(a, b) => new Date(a.date) - new Date(b.date),
);
const startStr = sortedHistory[0].date;
const endStr = sortedHistory[sortedHistory.length - 1].date;
historyRangeTitle = `⏳ 历史记录 (本周期外 ${endStr} 至 ${startStr})`;
}

const renderTable = (list, stats) => `
<div class="table-container">
<table class="compass-table">
<thead>
<tr><th>日期</th><th>Credits</th><th>Tokens</th><th>金额</th><th>轮数</th></tr>
</thead>
<tbody>
${[...list]
.reverse()
.map(
(row) => `
<tr>
<td>${row.date}</td>
<td style="font-family:monospace">${(row.totals?.credits || 0).toFixed(3)}</td>
<td style="font-family:monospace">${fmtNum(tokenTotal(row.totals))}</td>
<td>$ ${((row.totals?.credits || 0) * CONFIG.USD_PER_CREDIT).toFixed(2)}</td>
<td>${row.totals?.turns || 0}</td>
</tr>
`,
)
.join("")}
</tbody>
<tfoot>
<tr class="compass-footer-row">
<td>合计</td>
<td>${stats.credits.toFixed(3)}</td>
<td style="font-family:monospace">${fmtNum(stats.tokens)}</td>
<td style="color:#10a37f">$ ${stats.usd.toFixed(2)}</td>
<td>${stats.turns}</td>
</tr>
</tfoot>
</table>
</div>
`;

root.innerHTML = `
<div class="compass-header">
<div class="compass-title">📊 Codex 配额深度分析 (V1.8)</div>
<div class="compass-close" id="compass-close-btn">&times;</div>
</div>
<div class="compass-grid">
<div class="compass-card">
<div class="card-label">已用比例</div>
<div class="card-value">${secondary?.used_percent || 0}%</div>
</div>
<div class="compass-card">
<div class="card-label">本周已用</div>
<div class="card-value">${currentStats.credits.toFixed(1)} <span style="font-size:10px; font-weight:normal">Credits</span></div>
</div>
<div class="compass-card highlight">
<div class="card-label">推算总额</div>
<div class="card-value">${estCredits} <span style="font-size:10px; font-weight:normal">Credits</span></div>
</div>
<div class="compass-card">
<div class="card-label">周价值 (估算)</div>
<div class="card-value">$ ${(estCredits * CONFIG.USD_PER_CREDIT).toFixed(2)}</div>
</div>
</div>

<div style="font-weight:600; margin-bottom:8px; font-size:13px;">📅 本周期明细 (始于 ${cycleStartDate})</div>
${renderTable(currentCycleList, currentStats)}

${
historyList.length > 0
? `
<div style="font-weight:600; margin-bottom:8px; font-size:13px; color: #666; margin-top: 5px;">${historyRangeTitle}</div>
${renderTable(historyList, historyStats)}
`
: ""
}
`;

root.style.display = "flex";
document.getElementById("compass-close-btn").onclick = () =>
(root.style.display = "none");
};

const run = async () => {
const btn = document.getElementById("codex-compass-btn");
const bootstrapData =
document.getElementById("client-bootstrap")?.textContent;
const token = bootstrapData?.match(
/[\w-]{30,}\.[\w-]{30,}\.[\w-]{30,}/,
)?.[0];
if (!token) return alert("令牌获取失败,请确保已登录。");

btn.innerText = "分析中...";
try {
const usage = await apiGet("/backend-api/wham/usage", token);
const secondary =
usage?.rate_limit?.secondary_window ||
usage?.rate_limit?.primary_window;

const endDate = new Date(Date.now() + 86400000)
.toISOString()
.split("T")[0];
const startDate = new Date(Date.now() - 30 * 86400000)
.toISOString()
.split("T")[0];
const cycleStartDate = secondary
? new Date((secondary.reset_at - secondary.limit_window_seconds) * 1000)
.toISOString()
.split("T")[0]
: startDate;

const dailyData = await apiGet(
`/backend-api/wham/analytics/daily-workspace-usage-counts?start_date=${startDate}&end_date=${endDate}&group_by=day`,
token,
);

showPanel({ secondary, dailyList: dailyData.data || [], cycleStartDate });
} catch (e) {
alert("错误: " + e.message);
} finally {
btn.innerText = "📊 运行用量分析";
}
};

const btn = document.createElement("button");
btn.id = "codex-compass-btn";
btn.innerText = "📊 运行用量分析";
btn.onclick = run;
document.body.appendChild(btn);

const root = document.createElement("div");
root.id = "codex-compass-root";
document.body.appendChild(root);
})();
最新回复 (19)
  • Robet 05-09 10:18
    1



    Plus 供大家比对参考 (再别说了 下个月就买pro)

  • mikesky 05-09 10:19
    2

    不知道为什么,好像不行,应该怎么去解决呢 ^-^



  • 奶丝辣双层吉士堡 05-09 10:23
    3



    不够好像点叉号关闭不了弹窗

  • 奶丝辣双层吉士堡 05-09 10:27
    4

    我让g老师重新修复了一下,没问题了


    // ==UserScript==
    // @name Codex Quota Compass (Visual Edition)
    // @namespace http://tampermonkey.net/
    // @version 1.3
    // @description 人性化展示 Codex 配额,包含本周期已用额度显示
    // @author Jun Zhao
    // @match https://chatgpt.com/codex/cloud/settings/analytics*
    // @grant GM_addStyle
    // ==/UserScript==

    (function() {
    'use strict';

    const CONFIG = {
    USD_PER_CREDIT: 40 / 1000,
    ROLLING_DAYS: 30
    };

    GM_addStyle(`
    #codex-compass-root {
    position: fixed;
    top: 10%;
    left: 50%;
    transform: translateX(-50%);
    width: 650px;
    max-height: 85vh;
    background: #ffffff;
    border-radius: 12px;
    box-shadow: 0 10px 40px rgba(0,0,0,0.2);
    z-index: 10001;
    padding: 24px;
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    display: none;
    overflow-y: auto;
    border: 1px solid #e5e5e5;
    color: #333;
    }
    .compass-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; }
    .compass-title { font-size: 20px; font-weight: 600; color: #1a1a1a; }
    .compass-close { cursor: pointer; font-size: 24px; color: #999; line-height: 1; }
    .compass-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 24px; }
    .compass-card { background: #f8f9fa; padding: 16px; border-radius: 8px; border: 1px solid #eee; }
    .compass-card.highlight { background: #eefaf5; border-color: #d1f2e1; }
    .card-label { font-size: 13px; color: #666; margin-bottom: 6px; }
    .card-value { font-size: 20px; font-weight: bold; color: #10a37f; }
    .compass-table { width: 100%; border-collapse: collapse; margin-top: 10px; font-size: 13px; }
    .compass-table th { text-align: left; padding: 10px 8px; border-bottom: 2px solid #eee; color: #666; }
    .compass-table td { padding: 10px 8px; border-bottom: 1px solid #eee; }
    #codex-compass-btn {
    position: fixed;
    bottom: 20px;
    right: 20px;
    z-index: 10000;
    padding: 12px 24px;
    background: #10a37f;
    color: white;
    border: none;
    border-radius: 8px;
    cursor: pointer;
    box-shadow: 0 4px 12px rgba(16,163,127,0.3);
    font-weight: 600;
    transition: all 0.2s;
    }
    #codex-compass-btn:hover { background: #1a7f64; transform: translateY(-2px); }
    `);

    function getAccessToken() {
    const bootstrapData = document.getElementById('client-bootstrap')?.textContent;
    const tokenMatch = bootstrapData?.match(/[\w-]{30,}\.[\w-]{30,}\.[\w-]{30,}/);
    return tokenMatch ? tokenMatch[0] : null;
    }

    async function apiGet(path, token) {
    const res = await fetch(path, { headers: { 'Authorization': `Bearer ${token}` } });
    if (!res.ok) throw new Error(`API Error: ${res.status}`);
    return res.json();
    }

    // --- 修改后的 showPanel ---
    const showPanel = (data) => {
    const root = document.getElementById('codex-compass-root');
    const { secondary, dailyList, totalUsed, estimate } = data;

    const totalUSD = (totalUsed * CONFIG.USD_PER_CREDIT).toFixed(2);
    const totalTurns = dailyList.reduce((sum, d) => sum + (d.totals?.turns || 0), 0);
    const cycleStart = new Date(secondary.reset_at * 1000 - secondary.limit_window_seconds * 1000).toLocaleDateString();

    root.innerHTML = `
    <div class="compass-header">
    <div class="compass-title">📊 Codex 配额深度分析</div>
    <div class="compass-close">×</div>
    </div>

    <div class="compass-grid">
    <div class="compass-card">
    <div class="card-label">周使用比例 (已用)</div>
    <div class="card-value">${secondary.used_percent}%</div>
    </div>
    <div class="compass-card">
    <div class="card-label">本周期已用额度</div>
    <div class="card-value">${totalUsed.toFixed(2)} <span style="font-size:12px; font-weight:normal">Credits</span></div>
    </div>
    <div class="compass-card highlight">
    <div class="card-label">反推周总额度 (100%)</div>
    <div class="card-value">${estimate.totalCredits} <span style="font-size:12px; font-weight:normal">Credits</span></div>
    </div>
    <div class="compass-card">
    <div class="card-label">预估周价值 (USD)</div>
    <div class="card-value">$ ${estimate.totalUSD}</div>
    </div>
    </div>

    <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 12px;">
    <span style="font-weight:600;">本周期每日消耗明细</span>
    <span style="font-size: 12px; color: #999;">统计始于:${cycleStart}</span>
    </div>

    <table class="compass-table">
    <thead>
    <tr>
    <th>日期</th>
    <th>消耗 Credits</th>
    <th>折算金额</th>
    <th>对话轮数 (Turns)</th>
    </tr>
    </thead>
    <tbody>
    ${dailyList.map(row => `
    <tr>
    <td>${row.date}</td>
    <td style="font-family: monospace;">${(row.totals?.credits || 0).toFixed(4)}</td>
    <td>$ ${((row.totals?.credits || 0) * CONFIG.USD_PER_CREDIT).toFixed(2)}</td>
    <td>${row.totals?.turns || 0}</td>
    </tr>
    `).reverse().join('')}
    </tbody>
    <tfoot>
    <tr style="background: #f8f9fa; font-weight: bold; border-top: 2px solid #eee;">
    <td style="padding: 12px 8px;">合计</td>
    <td style="font-family: monospace;">${totalUsed.toFixed(4)}</td>
    <td style="color: #10a37f;">$ ${totalUSD}</td>
    <td>${totalTurns}</td>
    </tr>
    </tfoot>
    </table>

    <div style="margin-top: 20px; font-size: 12px; color: #999; line-height: 1.5;">
    * <b>反推逻辑:</b> 基于“本周期已用额度 / 已用比例”计算。
    </div>
    `;

    // 绑定关闭事件
    const closeBtn = root.querySelector('.compass-close');
    if (closeBtn) {
    closeBtn.addEventListener('click', () => {
    root.style.display = 'none';
    });
    }

    root.style.display = 'block';
    };

    const run = async () => {
    const btn = document.getElementById('codex-compass-btn');
    const token = getAccessToken();
    if (!token) return alert("未发现登录令牌,请确保已登录 ChatGPT 并刷新页面。");

    btn.innerText = '分析中...';

    try {
    const usage = await apiGet('/backend-api/wham/usage', token);
    const secondary = usage.rate_limit.secondary_window;

    const windowStartMs = (secondary.reset_at - secondary.limit_window_seconds) * 1000;
    const startDate = new Date(windowStartMs).toISOString().split('T')[0];
    const endDate = new Date(Date.now() + 86400000).toISOString().split('T')[0];

    const dailyData = await apiGet(`/backend-api/wham/analytics/daily-workspace-usage-counts?start_date=${startDate}&end_date=${endDate}&group_by=day`, token);
    const dailyList = dailyData.data || [];

    const totalUsedCredits = dailyList.reduce((sum, d) => sum + (d.totals?.credits || 0), 0);

    const ratio = secondary.used_percent / 100;
    const estCredits = ratio > 0 ? (totalUsedCredits / ratio).toFixed(1) : "无法计算";

    showPanel({
    secondary,
    dailyList,
    totalUsed: totalUsedCredits,
    estimate: {
    totalCredits: estCredits,
    totalUSD: ratio > 0 ? (estCredits * CONFIG.USD_PER_CREDIT).toFixed(2) : "0.00"
    }
    });
    } catch (e) {
    console.error(e);
    alert("获取数据失败,请查看控制台错误信息。");
    } finally {
    btn.innerText = '📊 运行用量分析';
    }
    };

    const btn = document.createElement('button');
    btn.id = 'codex-compass-btn';
    btn.innerText = '📊 运行用量分析';
    btn.onclick = run;
    document.body.appendChild(btn);

    const root = document.createElement('div');
    root.id = 'codex-compass-root';
    document.body.appendChild(root);

    })();
  • yfzz 楼主 05-09 10:29
    5

    @mikesky @CheeseBurger


    重新复制试试,我让 AI 改了下

  • LZWcc 05-09 18:04
    6



    我的plus怎么感觉这么少啊^-^

  • yfzz 楼主 05-09 19:12
    7

    统计有延迟的,所以可能不是太准,仅供参考

  • 11 05-09 19:17
    8

    能得到 cpa 账号池里的额度吗?

  • yfzz 楼主 05-10 08:53
    9

    提醒下: 每周重置的时间不是当天用量统计开始的时间,比如实际重置时间可能是 09:12 但是接口只能统计整天的数据,所以可能存在误差。

  • yfzz 楼主 05-10 08:54
    10

    好像有大佬 fork 后修改,但是感觉不会入正式库,毕竟有误差

  • LZWcc 05-10 13:09
    11



    当天用量太多的话偏差就会很大, 今天再去看就和各位的差不多了

  • 郑建国 05-11 02:36
    12



    5x的,感觉差不多就是这个数了

  • Mx 05-11 02:53
    13




    贴两个 pro20,比佬少了 300 预计额度

  • 莱特昂斯戴 05-11 08:49
    14



    0刀plus



    全是这样的,好像有bug

  • Ralph056 05-11 09:24
    15

    感谢佬,让AI把token统计也加上了


    // ==UserScript==
    // @name Codex Quota Compass (Visual Edition)
    // @namespace http://tampermonkey.net/
    // @version 1.7
    // @description 人性化展示 Codex 配额,强化 Credits 标注,增加历史合计及动态日期范围
    // @author Jun Zhao
    // @match https://chatgpt.com/codex/cloud/settings/analytics*
    // @grant GM_addStyle
    // ==/UserScript==

    (function () {
    "use strict";

    const CONFIG = {
    USD_PER_CREDIT: 40 / 1000,
    };

    const fmtNum = (n) => {
    if (n >= 1e8) return (n / 1e8).toFixed(2) + "亿";
    if (n >= 1e4) return (n / 1e4).toFixed(1) + "万";
    return n.toLocaleString();
    };

    const n = (v) => (Number.isFinite(Number(v)) ? Number(v) : 0);
    const tokenTotal = (obj = {}) =>
    n(obj.text_total_tokens) ||
    n(obj.cached_text_input_tokens) +
    n(obj.uncached_text_input_tokens) +
    n(obj.text_output_tokens);

    GM_addStyle(`
    #codex-compass-root {
    position: fixed; top: 5%; left: 50%; transform: translateX(-50%);
    width: 720px; max-height: 90vh; background: #fff;
    border-radius: 12px; box-shadow: 0 10px 50px rgba(0,0,0,0.3);
    z-index: 10001; padding: 24px; display: none;
    flex-direction: column; border: 1px solid #e5e5e5; color: #333;
    font-family: -apple-system, system-ui, sans-serif;
    }
    .compass-header { display: flex; justify-content: space-between; align-items: center; margin-bottom: 15px; }
    .compass-title { font-size: 18px; font-weight: 600; }
    .compass-close { cursor: pointer; font-size: 28px; color: #999; line-height: 1; }
    .compass-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin-bottom: 20px; }
    .compass-card { background: #f9f9f9; padding: 12px; border-radius: 8px; border: 1px solid #eee; }
    .compass-card.highlight { background: #eefaf5; border-color: #d1f2e1; }
    .card-label { font-size: 12px; color: #666; margin-bottom: 4px; }
    .card-value { font-size: 15px; font-weight: bold; color: #10a37f; white-space: nowrap; }

    .table-container {
    max-height: 220px; overflow-y: auto; border: 1px solid #eee;
    border-radius: 6px; margin-bottom: 15px;
    }
    .compass-table { width: 100%; border-collapse: collapse; font-size: 12px; }
    .compass-table thead { position: sticky; top: 0; background: #f5f5f5; z-index: 1; }
    .compass-table th { text-align: left; padding: 8px; border-bottom: 1px solid #eee; color: #666; }
    .compass-table td { padding: 8px; border-bottom: 1px solid #f0f0f0; }
    .compass-footer-row { background: #fafafa; font-weight: bold; position: sticky; bottom: 0; border-top: 2px solid #eee; }

    #codex-compass-btn {
    position: fixed; bottom: 20px; right: 20px; z-index: 10000;
    padding: 10px 20px; background: #10a37f; color: white;
    border: none; border-radius: 8px; cursor: pointer; font-weight: 600;
    }
    `);

    async function apiGet(path, token) {
    const res = await fetch(path, {
    headers: { Authorization: `Bearer ${token}` },
    });
    return res.json();
    }

    const showPanel = (data) => {
    const root = document.getElementById("codex-compass-root");
    const { secondary, dailyList, cycleStartDate } = data;

    // 1. 数据切分
    const currentCycleList = [];
    const historyList = [];
    dailyList.forEach((item) => {
    if (new Date(item.date) >= new Date(cycleStartDate)) {
    currentCycleList.push(item);
    } else {
    historyList.push(item);
    }
    });

    // 2. 统计计算辅助函数
    const getStats = (list) => {
    const credits = list.reduce(
    (sum, d) => sum + (d.totals?.credits || 0),
    0,
    );
    const turns = list.reduce((sum, d) => sum + (d.totals?.turns || 0), 0);
    const tokens = list.reduce((sum, d) => sum + tokenTotal(d.totals), 0);
    return { credits, turns, tokens, usd: credits * CONFIG.USD_PER_CREDIT };
    };

    const currentStats = getStats(currentCycleList);
    const historyStats = getStats(historyList);

    const ratio = (secondary?.used_percent || 0) / 100;
    const estCredits =
    ratio > 0 ? (currentStats.credits / ratio).toFixed(1) : "0";

    // 3. 历史记录日期范围计算
    let historyRangeTitle = "⏳ 历史记录 (本周期外)";
    if (historyList.length > 0) {
    const sortedHistory = [...historyList].sort(
    (a, b) => new Date(a.date) - new Date(b.date),
    );
    const startStr = sortedHistory[0].date;
    const endStr = sortedHistory[sortedHistory.length - 1].date;
    historyRangeTitle = `⏳ 历史记录 (本周期外 ${endStr} 至 ${startStr})`;
    }

    const renderTable = (list, stats) => `
    <div class="table-container">
    <table class="compass-table">
    <thead>
    <tr><th>日期</th><th>Credits</th><th>Tokens</th><th>金额</th><th>轮数</th></tr>
    </thead>
    <tbody>
    ${[...list]
    .reverse()
    .map(
    (row) => `
    <tr>
    <td>${row.date}</td>
    <td style="font-family:monospace">${(row.totals?.credits || 0).toFixed(3)}</td>
    <td style="font-family:monospace">${fmtNum(tokenTotal(row.totals))}</td>
    <td>$ ${((row.totals?.credits || 0) * CONFIG.USD_PER_CREDIT).toFixed(2)}</td>
    <td>${row.totals?.turns || 0}</td>
    </tr>
    `,
    )
    .join("")}
    </tbody>
    <tfoot>
    <tr class="compass-footer-row">
    <td>合计</td>
    <td>${stats.credits.toFixed(3)}</td>
    <td style="font-family:monospace">${fmtNum(stats.tokens)}</td>
    <td style="color:#10a37f">$ ${stats.usd.toFixed(2)}</td>
    <td>${stats.turns}</td>
    </tr>
    </tfoot>
    </table>
    </div>
    `;

    root.innerHTML = `
    <div class="compass-header">
    <div class="compass-title">📊 Codex 配额深度分析 (V1.7)</div>
    <div class="compass-close" id="compass-close-btn">&times;</div>
    </div>
    <div class="compass-grid">
    <div class="compass-card">
    <div class="card-label">已用比例</div>
    <div class="card-value">${secondary?.used_percent || 0}%</div>
    </div>
    <div class="compass-card">
    <div class="card-label">本周已用</div>
    <div class="card-value">${currentStats.credits.toFixed(1)} <span style="font-size:10px; font-weight:normal">Credits</span></div>
    </div>
    <div class="compass-card highlight">
    <div class="card-label">推算总额</div>
    <div class="card-value">${estCredits} <span style="font-size:10px; font-weight:normal">Credits</span></div>
    </div>
    <div class="compass-card">
    <div class="card-label">周价值 (估算)</div>
    <div class="card-value">$ ${(estCredits * CONFIG.USD_PER_CREDIT).toFixed(2)}</div>
    </div>
    </div>

    <div style="font-weight:600; margin-bottom:8px; font-size:13px;">📅 本周期明细 (始于 ${cycleStartDate})</div>
    ${renderTable(currentCycleList, currentStats)}

    ${
    historyList.length > 0
    ? `
    <div style="font-weight:600; margin-bottom:8px; font-size:13px; color: #666; margin-top: 5px;">${historyRangeTitle}</div>
    ${renderTable(historyList, historyStats)}
    `
    : ""
    }
    `;

    root.style.display = "flex";
    document.getElementById("compass-close-btn").onclick = () =>
    (root.style.display = "none");
    };

    const run = async () => {
    const btn = document.getElementById("codex-compass-btn");
    const bootstrapData =
    document.getElementById("client-bootstrap")?.textContent;
    const token = bootstrapData?.match(
    /[\w-]{30,}\.[\w-]{30,}\.[\w-]{30,}/,
    )?.[0];
    if (!token) return alert("令牌获取失败,请确保已登录。");

    btn.innerText = "分析中...";
    try {
    const usage = await apiGet("/backend-api/wham/usage", token);
    const secondary =
    usage?.rate_limit?.secondary_window ||
    usage?.rate_limit?.primary_window;

    const endDate = new Date(Date.now() + 86400000)
    .toISOString()
    .split("T")[0];
    const startDate = new Date(Date.now() - 30 * 86400000)
    .toISOString()
    .split("T")[0];
    const cycleStartDate = secondary
    ? new Date((secondary.reset_at - secondary.limit_window_seconds) * 1000)
    .toISOString()
    .split("T")[0]
    : startDate;

    const dailyData = await apiGet(
    `/backend-api/wham/analytics/daily-workspace-usage-counts?start_date=${startDate}&end_date=${endDate}&group_by=day`,
    token,
    );

    showPanel({ secondary, dailyList: dailyData.data || [], cycleStartDate });
    } catch (e) {
    alert("错误: " + e.message);
    } finally {
    btn.innerText = "📊 运行用量分析";
    }
    };

    const btn = document.createElement("button");
    btn.id = "codex-compass-btn";
    btn.innerText = "📊 运行用量分析";
    btn.onclick = run;
    document.body.appendChild(btn);

    const root = document.createElement("div");
    root.id = "codex-compass-root";
    document.body.appendChild(root);
    })();
  • 让我吃完这个树 05-11 09:31
    16

    计算有问题吧,我一直用5.4估算出110+刀,而且还有31%周额度的。

  • pzsci 05-11 12:52
    17

    我4.12开的0刀team,1拖4,算的应该是整个工作空间,但是估计周限额又是根据登录那个号的已使用百分比来算的。我自己看了一下,394.23刀是5个号的总共369%/500%。这么算的话,5个号总共周限额差不多是535刀

  • Lisakhan 05-11 13:42
    18

    昨天开的英区team 48个月,貌似周额度也太少了点 ^-^

  • arygboy 05-11 13:48
    19

    team 看着比plus额度多一些

* 帖子来源Linux.do
返回