我是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 最后一条红色错误复制给我。"
);
}
})();