直接上代码,需要自行搭建反向代理:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>API-KEY信息查询</title> <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('/static/css/31.jpg') no-repeat center center fixed; /*自定义背景图*/ background-size: cover; background-color: #f5f5f5; display: flex; justify-content: center; align-items: center; height: 90vh; } .content { width: 100%; max-width: 1100px; margin: auto; padding: 40px; border-radius: 8px; 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: center; border: 1px solid #090303; } #result-table td { height: 20px; text-align: center; } #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">API余额查询(批量)</h1> <form> <label for="api_key" class="w-28 mr-4 text-gradient">API密钥:</label> <textarea id="api-key-input" class="form-control" placeholder="每行一个秘钥"></textarea> <div style="display: none;"> <select id="api-url-select"> <option value="https://i.*.ltd">【反向代理接口】</option> <option value="https://api.openai.com">【官方查询接口】</option> </select> </div> <button type="button" style="display:inline-block; width: 100px;" onclick="sendRequest()">查询</button> </form> <table id="result-table"> <thead> <tr> <th style="width: 40%">API KEY</th> <th style="width: 15%">总额度</th> <th style="width: 15%">已使用</th> <th style="width: 10%">剩余额度</th> <th style="width: 10%">开始日期</th> <th style="width: 10%">结束日期</th> </tr> </thead> <tbody></tbody> </table> </div> <script> // 定义查询过的API-KEY列表 let queriedApiKeys = []; async function checkBilling(apiKey) { // 计算起始日期和结束日期 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 = 'https://api.openai.com/v1/dashboard/billing/subscription'; // 查是否订阅 const urlBalance = 'https://api.openai.com/dashboard/billing/credit_grants'; // 查普通账单 const urlUsage = `https://api.openai.com/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) { console.log("您的账户已被封禁,请登录OpenAI进行查看。"); return; } const subscriptionData = await response.json(); 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 [totalAmount, totalUsage, remaining, startDateString, endDateString]; } 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).then((data) => { // update table with data let row = document.createElement("tr"); // 隐藏API KEY部分信息 const hiddenApiKey = apiKey.substring(0, 7) + "*******************" + apiKey.substring(47); // API KEY let apiKeyCell = document.createElement("td"); apiKeyCell.textContent = hiddenApiKey; 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 { // TOTAL GRANTED let totalGrantedCell = document.createElement("td"); totalGrantedCell.textContent = data[0].toFixed(2); row.appendChild(totalGrantedCell); // TOTAL USED let totalUsedCell = document.createElement("td"); totalUsedCell.textContent = data[1].toFixed(2); row.appendChild(totalUsedCell); // TOTAL AVAILABLE let totalAvailableCell = document.createElement("td"); totalAvailableCell.textContent = data[2].toFixed(2); row.appendChild(totalAvailableCell); // START DATE let startDateCell = document.createElement("td"); startDateCell.textContent = data[3]; row.appendChild(startDateCell); // END DATE let endDateCell = document.createElement("td"); endDateCell.textContent = data[4]; row.appendChild(endDateCell); } 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"); // 隐藏API KEY部分信息 const hiddenApiKey = apiKey.substring(0, 7) + "*******************" + apiKey.substring(47); apiKeyCell.textContent = hiddenApiKey; row.appendChild(apiKeyCell); let errorMessageCell = document.createElement("td"); errorMessageCell.colSpan = "3"; errorMessageCell.style.width = "90px"; errorMessageCell.classList.add("status-error"); errorMessageCell.textContent = "账户已被封禁,请登录OpenAI进行查看。"; 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> function showLoader() { document.getElementById("loader").style.display = "inline-block"; } function hideLoader() { document.getElementById("loader").style.display = "none"; } function displayResult(data) { if (data.status === "success") { document.getElementById("result").innerHTML = ` <div class="grid grid-cols-3 gap-4"> <div class="grid-item bg-gray-100 p-6 rounded-lg text-center"> <p class="text-2xl font-semibold">${data.total_granted}</p> <p class="text-gray-600">总额度</p> </div> <div class="grid-item bg-gray-100 p-6 rounded-lg text-center"> <p class="text-2xl font-semibold">${parseFloat(data.total_used).toFixed(3)}</p> <p class="text-gray-600">已使用额度</p> </div> <div class="grid-item bg-gray-100 p-6 rounded-lg text-center"> <p class="text-2xl font-semibold">${parseFloat(data.total_available).toFixed(3)}</p> <p class="text-gray-600">剩余可用额度</p> </div> <div class="grid-item bg-gray-100 p-6 rounded-lg text-center"> <p class="text-2xl font-semibold">${data.total_startDate}</p> <p class="text-gray-600">开始日期</p> </div> <div class="grid-item bg-gray-100 p-6 rounded-lg text-center"> <p class="text-2xl font-semibold">${data.total_endstartDate}</p> <p class="text-gray-600">结束日期</p> </div> </div> `; } else { alert("您的账户已被封禁,请登录OpenAI进行查看。"); } } function checkOpenAICredit() { var apiKey = document.getElementById("api_key").value; if (!apiKey.startsWith("sk-")) { alert("无效的API密钥,请检查您的API密钥是否正确。"); return; } showLoader(); checkBilling(apiKey) .then(data => { displayResult({ status: "success", total_granted: data[0], total_used: data[1], total_available: data[2] }); hideLoader(); }) .catch(error => { alert("您的账户已被封禁,请登录OpenAI进行查看。"); hideLoader(); }); } async function checkBilling(apiKey) { // 计算起始日期和结束日期 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 = 'https://i.*.ltd/v1/dashboard/billing/subscription'; // 查是否订阅 const urlBalance = 'https://i.*.ltd/dashboard/billing/credit_grants'; // 查普通账单 const urlUsage = `https://i.*.ltd/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) { console.log("您的账户已被封禁,请登录OpenAI进行查看。"); return; } const subscriptionData = await response.json(); 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; // 计算开始时间和结束时间 const endDateString = new Date(subscriptionData.access_until * 1000).toLocaleDateString(); const startDateString = new Date(startDate).toLocaleDateString(); // 输出总用量、总额及余额信息 console.log(`Total Amount: ${totalAmount.toFixed(2)}`); console.log(`Used: ${totalUsage.toFixed(2)}`); console.log(`Remaining: ${remaining.toFixed(2)}`); return [totalAmount, totalUsage, remaining, startDateString, endDateString]; } 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}`; } </script> </body> </html>