<!DOCTYPE html>
<!--230402修复,加了去重功能适应了官方查询接口变化-->
<!--230505与时俱进,原版基础上增加key账号类型、有效期显示-->
<html>
<head>
<meta charset="UTF-8" />
<title>ChatGPT转发APIkey余额批量查询</title>
<link rel="icon" href="data:image/png;base64,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
">
<style>
table {
margin: auto;
border-collapse: collapse;
}
th,
td {
padding: 8px;
text-align: center;
color: #000000;
border: 1px solid #000000;
}
th:first-child,
td:first-child {
width: 520px;
}
h1 {
text-align: center;
color: #000000;
}
form {
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 20px;
}
textarea#api-key-input {
width: 560px;
font-size: 16px;
padding: 10px;
margin-right: 10px;
border-radius: 5px;
border: none;
resize: vertical;
rows: 8;
}
select#api-url-select,
input#custom-url-input {
width: 300px;
height: 50px;
font-size: 16px;
background-color: #212121;
border-radius: 5px;
color: #ffffff;
border: none;
margin-right: 10px;
}
input#custom-url-input {
display: none;
}
button {
height: 50px;
font-size: 16px;
background-color: #ff8c00;
color: #ffffff;
border: none;
border-radius: 5px;
cursor: pointer;
}
.status-ok {
color: #2d8d2d;
}
.status-error {
color: #ed0808;
}
tr:nth-child(even) {
/* 将偶数行背景色改为深蓝色 */
background-color: #f1d39c;
}
tr:nth-child(odd) {
/* 将偶数行背景色改为深蓝色 */
background-color: #f1d39c;
}
</style>
<style>
body {
background: url('https://pic3.zhimg.com/v2-a3cab7b5bb88b9eb83370f1ec3db6f86_r.jpg') no-repeat center center fixed;
background-size: cover;
background-color: #f5f5f5;
}
/* 画布 */
.content {
width: 100%;
max-width: 800px;
margin: auto;
padding: 40px;
border-radius: 8px;
backdrop-filter: blur(2px);
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
background-color: rgba(0, 0, 0, 0.63);
}
.container {
display: flex;
justify-content: center;
align-items: center;
height: 50vh;
}
h1 {
text-align: center;
font-size: 36px;
margin-bottom: 30px;
}
form {
display: flex;
justify-content: center;
align-items: center;
flex-wrap: wrap;
}
label {
font-size: 24px;
color: #ff089e;
margin-right: 10px;
}
input[type="text"] {
border: 2px solid #ddd;
border-radius: 6px;
padding: 12px 16px;
font-size: 16px;
background-color: #f9f9f9;
margin-right: 10px;
flex: 1;
transition: border-color 0.3s ease;
}
input[type="text"]:focus {
outline: none;
border-color: #4299e5;
}
button[type="submit"] {
background-color: #4299e5;
color: #fff;
border: none;
border-radius: 8px;
font-size: 16px;
padding: 14px 28px;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
button[type="submit"]:hover,
button[type="submit"]:focus {
background-color: #357dbf;
outline: none;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
grid-gap: 20px;
margin-top: 40px;
}
.grid-item {
padding: 20px;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
text-align: center;
transition: transform 0.3s ease;
background-color:#fff;
}
.grid-item:hover {
transform: translateY(-10px);
}
.grid-item p:nth-child(1) {
font-size: 28px;
font-weight: bold;
margin-bottom: 10px;
color: #4299e5;
animation: pulse 1s ease-in-out infinite alternate;
}
.grid-item p:nth-child(2) {
font-size: 16px;
color: #666;
}
@keyframes pulse {
from {
opacity: 0.6;
transform: scale(1);
}
to {
opacity: 1;
transform: scale(1.2);
}
}
.text-gradient {
background-image: linear-gradient(to right, #4299e5, #00c458);
-webkit-background-clip: text;
color: transparent;
}
.text-gradient {
animation: gradient-animation 2s linear infinite;
-webkit-background-clip: text;
color: transparent;
}
@keyframes gradient-animation {
from {background-image: linear-gradient(to right, #4299e5, #00c458);}
to {background-image: linear-gradient(to right, #00c458, #4299e5);}
}
#result-table {
border-collapse: collapse;
width: 100%;
margin-top: 20px;
font-size: 14px;
}
#result-table th {
background-color: #6fa83a;
color: #000;
font-weight: 400;
height: 20px;
padding: 10px 25px;
text-align: left;
border: 1px solid #090303;
}
#result-table td {
height: 20px;
text-align: left;
}
#result-table tbody tr:nth-child(even) {
background-color: #f9f9f9;
}
#result-table .table-header {
width: 25%;
}
#result-table .table-data {
width: 25%;
font-weight: bold;
color: #333;
}
.form-group {
margin-bottom: 1rem;
}
.form-control {
font-family: inherit;
font-size: 15px;
display: block;
width: 100%;
height: calc(2.5rem + 2px);
padding: 0.375rem 0.75rem;
line-height: 1.5;
color: #495057;
background-color: #fff;
border: 1px solid #ced4da;
border-radius: 0.25rem;
transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
}
.form-control:hover,
.form-control:active,
.form-control:focus {
border-color: #80bdff;
outline: 0;
box-shadow: 0 0 0 0.2rem rgba(0, 123, 255, 0.25);
}
.form-control::-webkit-input-placeholder {
color: #999;
}
.form-control::-moz-placeholder {
color: #999;
}
.form-control:-ms-input-placeholder {
color: #999;
}
.form-control::-ms-input-placeholder {
color: #999;
}
.form-control::placeholder {
color: #999;
}
</style>
</head>
<body>
<div class="content">
<h1 class="text-3xl font-semibold text-center mb-8 text-gradient">ChatGPT转发APIKey余额查询(批量)</h1>
<div class="text-3xl font-semibold text-center mb-8 text-gradient" style="text-align:center;margin-bottom:40px">ChatGPT账号购买:<a href="https://www.shandianfk.com" target="_blank" class="text-3xl font-semibold text-center mb-8 text-gradient">https://www.shandianfk.com</a></div>
<div class="text-3xl font-semibold text-center mb-8 text-gradient" style="text-align:center;margin-bottom:40px"><a href="/chatgpt_account_check.html" target="_blank" class="text-3xl font-semibold text-center mb-8 text-gradient">官方APIKey余额查询</a></div>
<form>
<label for="api_key" class="w-28 mr-4 text-gradient">API密钥:</label>
<textarea id="api-key-input" class="form-control" placeholder="请输入API秘钥,每行一个秘钥:"></textarea>
<div style="margin-top:20px;">
<select id="api-url-select">
<option value="https://apix.wumingai.com">https://apix.wumingai.com</option>
<option value="https://apis.wumingai.com">https://apis.wumingai.com</option>
<option value="https://api.wumingai.com">https://api.wumingai.com</option>
<!--<option value="https://kapkey.chatgptapi.org.cn">https://kapkey.chatgptapi.org.cn</option>-->
<!--<option value="https://api.openai.com">【需要梯子】https://api.openai.com</option>-->
<option value="custom">自定义API地址 ...</option>
</select>
<input type="text" id="custom-url-input" style="height:30px;" placeholder="请输入自定义API地址" />
</div>
<button type="button" style="display:inline-block; width: 100px;margin-top:20px;" onclick="sendRequest()">查询</button>
</form>
<table id="result-table">
<thead>
<tr>
<th>API KEY</th>
<th style="width: 100px">账号类型</th>
<th style="width: 80px">总额度</th>
<th style="width: 80px">已使用</th>
<th style="width: 80px">剩余额度</th>
<th style="width: 100px">有效期</th>
</tr>
</thead>
<tbody></tbody>
</table>
</div>
<script>
// 定义查询过的API-KEY列表
let queriedApiKeys = [];
async function checkBilling(apiKey,apiUrl) {
// 计算起始日期和结束日期
const now = new Date();
const startDate = new Date(now - 90 * 24 * 60 * 60 * 1000);
const endDate = new Date(now.getTime() + 24 * 60 * 60 * 1000);
// 设置API请求URL和请求头
const urlSubscription = apiUrl+'/v1/dashboard/billing/subscription'; // 查是否订阅
const urlUsage = apiUrl+`/v1/dashboard/billing/usage?start_date=${formatDate(startDate)}&end_date=${formatDate(endDate)}`; // 查使用量
const headers = {
"Authorization": "Bearer " + apiKey,
"Content-Type": "application/json"
};
try {
// 获取API限额
let response = await fetch(urlSubscription, {headers});
if (!response.ok) {
const data = await response.json()
console.log(apiKey + ":账户已被封禁,请登录OpenAI进行查看。"+data.error.message);
return;
}
const subscriptionData = await response.json();
//console.log(usageData);
// 有效期
const end_date = subscriptionData.access_until;
// 账号类型
// const plan = (subscriptionData.plan.title === "Pay-as-you-go") ? "Pay-as-you-go" : subscriptionData.plan.id;
const plan = subscriptionData.object;
// 总额度
const totalAmount = subscriptionData.hard_limit_usd;
// 获取已使用量
response = await fetch(urlUsage, {headers});
const usageData = await response.json();
const totalUsage = usageData.total_usage / 100;
// 计算剩余额度
const remaining = totalAmount - totalUsage;
// 输出总用量、总额及余额信息
console.log(`Total Amount: ${totalAmount.toFixed(2)}`);
console.log(`Used: ${totalUsage.toFixed(2)}`);
console.log(`Remaining: ${remaining.toFixed(2)}`);
return [plan, totalAmount, totalUsage, remaining, formatDate(new Date(end_date * 1000))];
} catch (error) {
console.error(error);
return [null, null, null];
}
}
function formatDate(date) {
const year = date.getFullYear();
const month = (date.getMonth() + 1).toString().padStart(2, '0');
const day = date.getDate().toString().padStart(2, '0');
return `${year}-${month}-${day}`;
}
function sendRequest() {
let apiKeyInput = document.getElementById("api-key-input");
let apiUrlSelect = document.getElementById("api-url-select");
let customUrlInput = document.getElementById("custom-url-input");
if (apiKeyInput.value.trim() === "") {
alert("请填写API KEY");
return;
}
// 添加以下一行代码,清空之前的结果信息
document.getElementById("result-table").getElementsByTagName('tbody')[0].innerHTML = "";
let apiUrl = "";
if (apiUrlSelect.value === "custom") {
if (customUrlInput.value.trim() === "") {
alert("请设置API链接");
return;
} else {
apiUrl = customUrlInput.value.trim();
}
} else {
apiUrl = apiUrlSelect.value;
}
let apiKeys = apiKeyInput.value.trim().split("\n");
let tableBody = document.querySelector("#result-table tbody");
for (let i = 0; i < apiKeys.length; i++) {
let apiKey = apiKeys[i].trim();
// 判断是否已经查询过
if (queriedApiKeys.includes(apiKey)) {
console.log(`API KEY ${apiKey} 已查询过,跳过此次查询`);
continue;
}
queriedApiKeys.push(apiKey);
checkBilling(apiKey,apiUrl).then((data) => {
// update table with data
let row = document.createElement("tr");
// API KEY
let apiKeyCell = document.createElement("td");
apiKeyCell.textContent = apiKey;
row.appendChild(apiKeyCell);
if (data[0] === null) {
// ERROR MESSAGE
let errorMessageCell = document.createElement("td");
errorMessageCell.colSpan = "3";
errorMessageCell.classList.add("status-error");
errorMessageCell.textContent = "请求失败,未开梯子或不正确或已失效的API-KEY";
row.appendChild(errorMessageCell);
} else {
// Plan
let totalPlanCell = document.createElement("td");
totalPlanCell.textContent = data[0];
row.appendChild(totalPlanCell);
// TOTAL GRANTED
let totalGrantedCell = document.createElement("td");
totalGrantedCell.textContent = data[1].toFixed(2);
row.appendChild(totalGrantedCell);
// TOTAL USED
let totalUsedCell = document.createElement("td");
totalUsedCell.textContent = data[2].toFixed(2);
row.appendChild(totalUsedCell);
// TOTAL AVAILABLE
let totalAvailableCell = document.createElement("td");
totalAvailableCell.textContent = data[3].toFixed(2);
row.appendChild(totalAvailableCell);
// 有效期
let totalEndDateCell = document.createElement("td");
totalEndDateCell.textContent = data[4];
row.appendChild(totalEndDateCell);
}
tableBody.appendChild(row);
// 添加以下代码,查询完成后删除已查询的API-KEY
if (i === apiKeys.length - 1) {
queriedApiKeys = [];
}
}).catch((error) => {
console.error(error);
// update table with error message
let row = document.createElement("tr");
let apiKeyCell = document.createElement("td");
apiKeyCell.textContent = apiKey;
row.appendChild(apiKeyCell);
let errorMessageCell = document.createElement("td");
errorMessageCell.colSpan = "4";
errorMessageCell.style.width = "90px";
errorMessageCell.classList.add("status-error");
errorMessageCell.textContent =
"API请求失败,请检查其有效性或网络情况";
row.appendChild(errorMessageCell);
tableBody.appendChild(row);
// 添加以下代码,查询完成后删除已查询的API-KEY
if (i === apiKeys.length - 1) {
queriedApiKeys = [];
}
});
}
}
let apiUrlSelect = document.getElementById("api-url-select");
let customUrlInput = document.getElementById("custom-url-input");
apiUrlSelect.addEventListener("change", function () {
if (apiUrlSelect.value === "custom") {
customUrlInput.style.display = "inline-block";
customUrlInput.style.marginTop = "5px";
} else {
customUrlInput.style.display = "none";
}
});
</script>
<script>
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?70076cdc16b66ddca1afdb1e4b20d953";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>