ChatGPT Pro 20X 重置后周额度缩水到不足1K美元?

karpathy 2026-09-13 09:35 1

今天重置后用 Astra-light 跑了一个机械的长任务,想看下额度耐不耐用,结果一觉醒来,任务没跑完,周额度直接给清零了。ChatGPT Pro 20X 美区iOS订阅。


让 Claude 分析了一下日志,按照API计价为 $992,实际用量比这个计算出来的少,因为一小部分任务是在额度重置前跑的。



最新回复 (8)
  • AxiEJohn 09-13 09:41
    1

    我是5x PRO同样为美区IOS账户订阅



    在https://chatgpt.com/codex/cloud/settings/analytics

    by


    (async () => {
    console.clear();
    console.log("🚀 [1/5] 开始查询 Codex 周额度...");

    const TIMEOUT = 15000;

    const withTimeout = (promise, name) =>
    Promise.race([
    promise,
    new Promise((_, reject) =>
    setTimeout(() => reject(new Error(`${name} 超过 ${TIMEOUT/1000}s 无响应`)), TIMEOUT)
    )
    ]);

    const fetchJSON = async (url, token = null) => {
    console.log("🌐 请求:", url);

    const r = await withTimeout(
    fetch(url, {
    credentials: "include",
    cache: "no-store",
    headers: {
    Accept: "application/json",
    "Cache-Control": "no-cache",
    ...(token ? { Authorization: `Bearer ${token}` } : {})
    }
    }),
    url
    );

    const text = await r.text();

    let data;
    try {
    data = JSON.parse(text);
    } catch {
    throw new Error(`${url} 返回的不是 JSON: ${text.slice(0,200)}`);
    }

    if (!r.ok) {
    throw new Error(`${url} → HTTP ${r.status}: ${
    data?.detail || data?.message || text.slice(0,200)
    }`);
    }

    console.log("✅ 成功:", url);
    return data;
    };

    try {
    // ==============================
    // 1. Session
    // ==============================
    const session = await fetchJSON("/api/auth/session");

    const token =
    session?.accessToken ||
    session?.access_token ||
    session?.token;

    if (!token) throw new Error("没有取得 access token");

    console.log("🔑 [2/5] 登录令牌获取成功");

    // ==============================
    // 2. 实时额度
    // ==============================
    const usage = await fetchJSON(
    "/backend-api/wham/usage",
    token
    );

    console.log("📦 WHAM usage 原始数据:", usage);

    const rate =
    usage?.rate_limit ||
    usage?.rateLimit ||
    usage?.rate_limits ||
    usage?.rateLimits ||
    usage?.limits ||
    {};

    const allWindows = [];

    const walk = x => {
    if (!x || typeof x !== "object") return;

    const sec = Number(
    x.limit_window_seconds ??
    x.window_seconds ??
    x.duration_seconds ??
    0
    );

    if (sec > 0) allWindows.push(x);

    Object.values(x).forEach(v => {
    if (v && typeof v === "object") walk(v);
    });
    };

    walk(rate);

    const WEEK = 604800;

    const weekly =
    allWindows.sort((a,b) => {
    const sa = Number(
    a.limit_window_seconds ??
    a.window_seconds ??
    a.duration_seconds ?? 0
    );

    const sb = Number(
    b.limit_window_seconds ??
    b.window_seconds ??
    b.duration_seconds ?? 0
    );

    return Math.abs(sa-WEEK) - Math.abs(sb-WEEK);
    })[0];

    if (!weekly) {
    throw new Error("没有找到周额度窗口");
    }

    let pct;

    if (weekly.used_percent != null) {
    pct = Number(weekly.used_percent);
    } else if (weekly.usedPercent != null) {
    pct = Number(weekly.usedPercent);
    } else {
    pct = Number(
    weekly.used_ratio ??
    weekly.usedRatio ??
    0
    ) * 100;
    }

    const resetSec = Number(
    weekly.reset_at ??
    weekly.resetAt
    );

    const windowSec = Number(
    weekly.limit_window_seconds ??
    weekly.window_seconds ??
    weekly.duration_seconds ??
    WEEK
    );

    const cycleEnd = resetSec * 1000;
    const cycleStart = cycleEnd - windowSec * 1000;

    console.log("📊 [3/5] 周额度窗口:", weekly);
    console.log(`📈 当前已使用: ${pct}%`);
    console.log(
    "♻️ 重置:",
    new Date(cycleEnd).toLocaleString()
    );

    // ==============================
    // 如果还是 0%
    // ==============================
    if (!(pct > 0)) {
    console.log(
    "%c⚠️ 当前 used_percent = 0%",
    "font-size:18px;color:orange;font-weight:bold"
    );

    console.log(
    "服务器目前只告诉我们:这周用了 0%。" +
    "由于总金额的计算公式是 已用美元 ÷ 已用比例," +
    "0% 时无法反推出整周美元额度。"
    );

    alert(
    "✅ 查询成功\n\n" +
    "周额度已用:0%\n" +
    "剩余:100%\n" +
    "重置时间:" +
    new Date(cycleEnd).toLocaleString() +
    "\n\n" +
    "⚠️ 目前无法计算美元总额度,因为 used_percent 还是 0%。\n" +
    "等服务器显示至少 1% 后再运行这段代码。"
    );

    return;
    }

    // ==============================
    // 日期范围
    // ==============================
    const dateKey = ms => {
    const d = new Date(ms);
    const p = n => String(n).padStart(2,"0");

    return `${d.getFullYear()}-${p(d.getMonth()+1)}-${p(d.getDate())}`;
    };

    const params = new URLSearchParams({
    start_date: dateKey(cycleStart - 86400000),
    end_date: dateKey(Date.now() + 86400000),
    group_by: "day"
    });

    const totalsParams = new URLSearchParams(params);
    totalsParams.set("workspace_user", "true");

    console.log("🧮 [4/5] 获取 Token / 模型占比数据...");

    const [creditData, totalData] =
    await Promise.all([
    fetchJSON(
    `/backend-api/wham/usage/daily-token-usage-breakdown?${params}`,
    token
    ),
    fetchJSON(
    `/backend-api/wham/analytics/daily-workspace-usage-counts?${totalsParams}`,
    token
    )
    ]);

    console.log("📦 模型额度数据:", creditData);
    console.log("📦 Token 数据:", totalData);

    // ==============================
    // 数据解析
    // ==============================
    const list = x => {
    if (Array.isArray(x)) return x;

    for (const key of [
    "data",
    "items",
    "results",
    "daily",
    "daily_usage",
    "dailyWorkspaceUsageCounts",
    "daily_workspace_usage_counts",
    "workspace_usage_counts"
    ]) {
    if (Array.isArray(x?.[key])) return x[key];
    }

    return [];
    };

    const totalsRows = list(totalData);
    const creditRows = list(creditData);

    const totalsMap = new Map(
    totalsRows.map(r => [
    String(r.date || "").slice(0,10),
    r.totals || r
    ])
    );

    const creditMap = new Map(
    creditRows.map(r => [
    String(r.date || "").slice(0,10),
    r
    ])
    );

    // LinuxDo V3.9.0 当前使用的价格口径
    // $ / 1M tokens:
    // [uncached input, cached input, output, fast multiplier]
    const PRICE = {
    "gpt-6-astra": [10, 1, 50, 2.5],
    "gpt-5.6-sol": [5, 0.5, 30, 2.5],
    "gpt-5.6-terra": [2, 0.2, 12, 2.5],
    "gpt-5.6-luna": [0.2, 0.02, 1.2, 2.5],
    "gpt-5.6": [5, 0.5, 30, 2.5],
    "gpt-5.5": [5, 0.5, 30, 2.5],
    "daybreak-blue": [4, 0.4, 20, 1],
    "daybreak-red": [12.5, 1.25, 75, 1],
    "gpt-5.5-cyber": [12.5, 1.25, 75, 1],
    "gpt-5.5-rosalind": [12.5, 1.25, 75, 1],
    "gpt-5.4": [2.5, 0.25, 15, 2],
    "gpt-5.4-mini": [0.75, 0.075, 4.5, 2],
    "gpt-5.3-codex": [1.75, 0.175, 14, 1],
    "gpt-5.2": [1.75, 0.175, 14, 1]
    };

    const getPrice = (name, speed) => {
    let n = String(name || "").toLowerCase();

    if (n === "gpt-5.6") n = "gpt-5.6-sol";

    let key = Object.keys(PRICE)
    .sort((a,b)=>b.length-a.length)
    .find(k => n === k || n.startsWith(k+"-"));

    if (!key) return null;

    const p = PRICE[key];
    const mult =
    String(speed || "").toLowerCase() === "fast"
    ? p[3]
    : 1;

    return [
    p[0]*mult,
    p[1]*mult,
    p[2]*mult
    ];
    };

    let usedUSD = 0;
    let usedTokens = 0;
    let unknownPrice = false;

    const details = [];

    const startDate = dateKey(cycleStart);
    const today = dateKey(Date.now());

    const dates = [...new Set([
    ...totalsMap.keys(),
    ...creditMap.keys()
    ])]
    .filter(d => d >= startDate && d <= today)
    .sort();

    for (const date of dates) {
    const t = totalsMap.get(date) || {};

    const uncached = Number(
    t.uncached_text_input_tokens || 0
    );

    const cached = Number(
    t.cached_text_input_tokens || 0
    );

    const output = Number(
    t.text_output_tokens || 0
    );

    const totalTokens =
    Number(t.text_total_tokens || 0) ||
    uncached + cached + output;

    if (!totalTokens) continue;

    usedTokens += totalTokens;

    const c = creditMap.get(date) || {};

    let models = Array.isArray(c.models)
    ? c.models
    .map(m => ({
    ...m,
    weight: Number(m.credits || 0)
    }))
    .filter(m => m.weight > 0)
    : [];

    // 没有模型分布就无法可靠估算价格
    if (!models.length) {
    unknownPrice = true;
    details.push({
    date,
    model: "未知",
    tokens: totalTokens,
    usd: "无法定价"
    });
    continue;
    }

    const classified =
    uncached + cached + output;

    const mix = {
    u: classified ? uncached/classified : 0,
    c: classified ? cached/classified : 0,
    o: classified ? output/classified : 0
    };

    // 根据 allowance 占比 / 模型综合价格
    // 反推各模型 Token 占比
    const temp = models.map(m => {
    const name =
    m.model ||
    m.model_name ||
    m.model_id ||
    m.name;

    const pr = getPrice(name, m.speed);

    if (!pr) {
    return {
    m,
    name,
    rate: null
    };
    }

    return {
    m,
    name,
    rate:
    mix.u*pr[0] +
    mix.c*pr[1] +
    mix.o*pr[2]
    };
    });

    const known = temp.filter(x => x.rate > 0);

    if (!known.length) {
    unknownPrice = true;
    continue;
    }

    const knownWeight =
    known.reduce((s,x)=>s+x.m.weight,0);

    const fallbackRate =
    known.reduce(
    (s,x) =>
    s +
    x.rate*x.m.weight/knownWeight,
    0
    );

    const inverse = temp.map(x =>
    x.m.weight / (x.rate || fallbackRate)
    );

    const invSum =
    inverse.reduce((a,b)=>a+b,0);

    for (let i=0; i<temp.length; i++) {
    const share = inverse[i]/invSum;

    const u = uncached*share;
    const cTok = cached*share;
    const o = output*share;

    const x = temp[i];

    const pr =
    getPrice(
    x.name,
    x.m.speed
    );

    if (!pr) {
    unknownPrice = true;
    continue;
    }

    const usd =
    (
    u*pr[0] +
    cTok*pr[1] +
    o*pr[2]
    ) / 1e6;

    usedUSD += usd;

    details.push({
    date,
    model: x.name,
    speed: x.m.speed || "standard",
    quota_weight: x.m.weight,
    estimated_tokens:
    Math.round(u+cTok+o),
    estimated_usd:
    Number(usd.toFixed(4))
    });
    }
    }

    // ==============================
    // 最终反推
    // ==============================
    const ratio = pct / 100;

    const weeklyUSD =
    ratio > 0
    ? usedUSD / ratio
    : NaN;

    const weeklyTokens =
    ratio > 0
    ? usedTokens / ratio
    : NaN;

    console.log("✅ [5/5] 完成!");
    console.table(details);

    console.table({
    "周额度已用": `${pct.toFixed(2)}%`,
    "本周期估算已用金额": `$${usedUSD.toFixed(2)}`,
    "本周期 Token": Math.round(usedTokens).toLocaleString(),
    "反推整周美元额度":
    `$${weeklyUSD.toFixed(2)}`,
    "反推整周 Token":
    Math.round(weeklyTokens).toLocaleString(),
    "周额度剩余":
    `${(100-pct).toFixed(2)}%`,
    "重置时间":
    new Date(cycleEnd).toLocaleString(),
    "存在未知模型价格":
    unknownPrice ? "⚠️ 是" : "否"
    });

    const box = document.createElement("div");

    box.style.cssText = `
    position:fixed;
    top:20px;
    right:20px;
    z-index:2147483647;
    width:380px;
    padding:20px;
    background:#171717;
    color:#fff;
    border:1px solid #555;
    border-radius:16px;
    box-shadow:0 15px 50px #0008;
    font:14px/1.6 -apple-system,BlinkMacSystemFont,
    "Segoe UI",sans-serif;
    `;

    box.innerHTML = `
    <div style="font-size:20px;font-weight:700;margin-bottom:12px">
    📊 Codex 周额度估算
    </div>

    <div style="font-size:13px;color:#aaa">实时已用</div>
    <div style="font-size:34px;font-weight:800">
    ${pct.toFixed(2)}%
    </div>

    <hr style="border:0;border-top:1px solid #444;margin:14px 0">

    <div>💵 本周期已用:
    <b>$${usedUSD.toFixed(2)}</b>
    </div>

    <div style="margin-top:8px">
    🎯 反推整周额度:
    <b style="font-size:25px;color:#36d399">
    $${weeklyUSD.toFixed(2)}
    </b>
    </div>

    <div style="margin-top:8px">
    🧮 本周期 Tokens:
    <b>${Math.round(usedTokens).toLocaleString()}</b>
    </div>

    <div style="margin-top:8px">
    ♻️ 重置:
    <b>${new Date(cycleEnd).toLocaleString()}</b>
    </div>

    ${
    unknownPrice
    ? `<div style="margin-top:12px;color:#fbbf24">
    ⚠️ 检测到未知模型,美元结果可能偏低
    </div>`
    : ""
    }

    <button onclick="this.parentElement.remove()"
    style="
    margin-top:15px;
    width:100%;
    padding:8px;
    border:0;
    border-radius:8px;
    cursor:pointer;
    ">
    关闭
    </button>
    `;

    document.body.appendChild(box);

    } catch (e) {
    console.error("❌ 查询失败:", e);

    alert(
    "❌ 查询失败\n\n" +
    e.message +
    "\n\n请把 Console 最后一条红色错误复制给我。"
    );
    }
    })();
  • xiaoyan 09-13 09:43
    2

    992*1.8,1785,其实也差不多了

  • AxiEJohn 09-13 09:44
    3

    回想以前,OPENAI那是真慷慨(2026年五月份的时候)

  • Licoy 09-13 09:44
    4


    我的还有3200多 ^-^

  • ccnccy 09-13 09:53
    5

    重置后X20感觉额度掉的很快,goal模式之前一天也就25%左右,现在一天能跑50%+

  • liasica 09-13 09:55
    6



    神经病

  • bb_aa 09-13 10:08
    7



    感觉不太准,额度哗哗的,一点也不够用

  • steven1 09-13 10:16
    8

    佬友,你的额度好多啊,是不是没用反代

* 帖子来源Linux.do
返回