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

首先感谢 完全准确查询你的GPT订阅周限的方法 提供的思路和 js 脚本。 基于大佬的内容优化为了油猴脚本,看起来更方便。 附个人 pro 20x 结果示例图: 打开 https://chatgpt.com/codex/cloud/settings/analytics#usage 页面使用 // =...
完全准确查询你的GPT订阅周限的方法【油猴脚本】
完全准确查询你的GPT订阅周限的方法【油猴脚本】

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

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

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

image

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

// ==UserScript==
// @name         Codex Quota Compass (Visual Edition)
// @namespace    http://tampermonkey.net/
// @version      1.4
// @description  人性化展示 Codex 配额,修复 reset_at 报错及关闭按钮失效问题
// @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: 28px; color: #999; line-height: 1; padding: 5px; }
        .compass-close:hover { color: #333; }
        .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; }
        .compass-footer-row { background: #f8f9fa; font-weight: bold; }
        #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;
        }
    `);

    function getAccessToken() {
        const bootstrapData = document.getElementById('client-bootstrap')?.textContent;
        return bootstrapData?.match(/[\w-]{30,}\.[\w-]{30,}\.[\w-]{30,}/)?.[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();
    }

    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 resetAt = secondary?.reset_at;
        const windowSec = secondary?.limit_window_seconds;
        const cycleStart = (resetAt && windowSec) 
            ? new Date((resetAt - windowSec) * 1000).toLocaleDateString() 
            : "未知";

        root.innerHTML = `
            <div class="compass-header">
                <div class="compass-title">📊 Codex 配额深度分析</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">${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">$ ${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>对话轮数</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 class="compass-footer-row">
                        <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>
        `;
        
        root.style.display = 'block';

        // 重新绑定关闭事件
        document.getElementById('compass-close-btn').onclick = () => {
            root.style.display = 'none';
        };
    };

    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);
            // 修复点:加入可选链,如果 secondary_window 不存在则退而求其次找 primary_window
            const secondary = usage?.rate_limit?.secondary_window || usage?.rate_limit?.primary_window;
            
            if (!secondary) {
                throw new Error("未能获取限额窗口数据。");
            }
            
            const windowStartMs = (secondary.reset_at - (secondary.limit_window_seconds || 604800)) * 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 || 0) / 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("分析失败:" + 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);

})();

6 个帖子 - 4 位参与者

阅读完整话题

来源: LinuxDo 最新话题查看原文