addEventListener("fetch", event => {
event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
// 只处理 GET 请求,返回内置前端页面
if (request.method === "GET") {
return new Response(htmlContent, {
headers: { "Content-Type": "text/html;charset=UTF-8" },
});
} else {
// 其他请求一律 404
return new Response("Not Found", { status: 404 });
}
}
const htmlContent = `
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>硅基流动Token余额检测</title>
<link rel="icon" type="image/svg+xml" href="https://github.githubassets.com/favicons/favicon.svg"/>
<style>
/* 全局样式 */
* {
box-sizing: border-box;
}
body {
margin: 0;
padding: 0;
background: linear-gradient(135deg, #f0f5fb, #c0d3ee);
font-family: 'Inter', 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
color: #333;
}
.container {
max-width: 600px;
background-color: #fff;
margin: 50px auto 30px;
padding: 30px 25px;
border-radius: 12px;
box-shadow: 0 6px 16px rgba(0,0,0,0.1);
}
@media (max-width: 640px) {
.container {
margin: 20px auto;
padding: 20px;
}
}
.logo {
display: block;
width: 48px;
height: 48px;
margin: 0 auto 16px;
}
h1 {
text-align: center;
margin-bottom: 1.5rem;
font-size: 1.8rem;
color: #2c3e50;
position: relative;
}
label {
display: block;
margin-bottom: 0.6rem;
font-weight: 600;
font-size: 0.95rem;
color: #2c3e50;
}
input, textarea {
width: 100%;
font-size: 14px;
border: 1px solid #ddd;
border-radius: 6px;
margin-bottom: 1rem;
padding: 0.75rem;
outline: none;
transition: border-color 0.25s, box-shadow 0.25s;
}
input:focus, textarea:focus {
border-color: #3498db;
box-shadow: 0 0 0 2px rgba(52,152,219,0.15);
}
textarea {
height: 80px;
resize: vertical;
}
button {
display: inline-block;
width: 100%;
padding: 0.8rem;
background-color: #3498db;
color: #fff;
border: none;
border-radius: 6px;
font-size: 1rem;
font-weight: 500;
cursor: pointer;
margin-bottom: 1rem;
transition: background-color 0.3s, transform 0.2s, box-shadow 0.2s;
outline: none;
}
button:hover {
background-color: #2980b9;
transform: translateY(-2px);
box-shadow: 0 4px 10px rgba(0,0,0,0.1);
}
button:active {
transform: translateY(1px);
box-shadow: none;
}
button:disabled {
background-color: #95a5a6;
cursor: not-allowed;
transform: none;
box-shadow: none;
}
.copy-button {
background-color: #27ae60;
margin-top: 0.25rem;
}
.copy-button:hover {
background-color: #2ecc71;
}
.results-section {
margin-top: 0.75rem;
}
.results-section h2 {
margin-bottom: 0.4rem;
font-size: 1.05rem;
color: #2c3e50;
display: flex;
align-items: center;
}
.counter {
color: #666;
font-weight: normal;
font-size: 0.9rem;
margin-left: 6px;
}
.results-content {
background-color: #f9f9f9;
padding: 10px;
border-radius: 6px;
border: 1px solid #ddd;
font-size: 0.9rem;
min-height: 40px;
white-space: pre-wrap;
margin-bottom: 0.75rem;
line-height: 1.4;
}
.loader {
width: 20px;
height: 20px;
border: 4px solid #f3f3f3;
border-top: 4px solid #3498db;
border-radius: 50%;
animation: spin 1s linear infinite;
display: inline-block;
vertical-align: middle;
margin-right: 10px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
/* 底部信息 */
.footer {
text-align: center;
margin-bottom: 20px;
color: #555;
font-size: 0.85rem;
}
.footer a {
text-decoration: none;
color: #3498db;
}
.footer a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<div class="container">
<img src="https://github.githubassets.com/favicons/favicon.svg" alt="logo" class="logo"/>
<h1>硅基流动Token余额检测</h1>
<textarea id="tokens" placeholder="请输入 API Key,多个以英文逗号分隔"></textarea>
<label for="threshold">请输入最低余额阈值 (默认1)</label>
<input id="threshold" type="number" value="1" />
<label for="concurrency">并发请求数 (默认5)</label>
<input id="concurrency" type="number" value="5" />
<button id="checkButton" onclick="checkTokens()">检测账号</button>
<button id="copyButton" class="copy-button" onclick="copyValidTokens()" style="display: none;">
复制所有有效账号
</button>
<div class="results-section">
<h2>有效账号 (余额 ≥ 阈值)
<span id="validCount" class="counter">0</span>
</h2>
<div id="validResults" class="results-content"></div>
</div>
<div class="results-section">
<h2>低余额账号 (0 < 余额 < 阈值)
<span id="lowBalanceCount" class="counter">0</span>
</h2>
<div id="lowBalanceResults" class="results-content"></div>
</div>
<div class="results-section">
<h2>零余额账号
<span id="zeroBalanceCount" class="counter">0</span>
</h2>
<div id="zeroBalanceResults" class="results-content"></div>
</div>
<div class="results-section">
<h2>无效账号
<span id="invalidCount" class="counter">0</span>
</h2>
<div id="invalidResults" class="results-content"></div>
</div>
<div class="results-section">
<h2>重复账号
<span id="duplicateCount" class="counter">0</span>
</h2>
<div id="duplicateResults" class="results-content"></div>
</div>
</div>
<div class="footer">
<p>© 2023 硅基流动 | <a href="https://github.com">GitHub</a> Favicon Powered</p>
</div>
<script>
// 并发执行工具函数:按 concurrency 数量并行执行 tasks
async function runWithConcurrencyLimit(tasks, concurrency, onResult) {
let i = 0;
let running = 0;
let results = new Array(tasks.length);
return new Promise((resolve, reject) => {
function runNext() {
while (running < concurrency && i < tasks.length) {
const currentIndex = i++;
running++;
tasks[currentIndex]()
.then((res) => {
results[currentIndex] = res;
onResult(res, currentIndex);
})
.catch((err) => {
const e = { error: err.message };
results[currentIndex] = e;
onResult(e, currentIndex);
})
.finally(() => {
running--;
if (i === tasks.length && running === 0) {
resolve(results);
} else {
runNext();
}
});
}
}
runNext();
});
}
async function checkTokens() {
// 获取DOM
const tokensTextarea = document.getElementById("tokens");
const thresholdInput = document.getElementById("threshold");
const concurrencyInput = document.getElementById("concurrency");
const checkButton = document.getElementById("checkButton");
const copyButton = document.getElementById("copyButton");
// 计数器DOM
const validCountEl = document.getElementById("validCount");
const lowBalanceCountEl = document.getElementById("lowBalanceCount");
const zeroBalanceCountEl = document.getElementById("zeroBalanceCount");
const invalidCountEl = document.getElementById("invalidCount");
const duplicateCountEl = document.getElementById("duplicateCount");
// 显示器DOM
const validResEl = document.getElementById("validResults");
const lowBalResEl = document.getElementById("lowBalanceResults");
const zeroBalResEl = document.getElementById("zeroBalanceResults");
const invalidResEl = document.getElementById("invalidResults");
const duplicatesResEl = document.getElementById("duplicateResults");
// 初始化计数器
let validCount = 0;
let lowBalanceCount = 0;
let zeroBalanceCount = 0;
let invalidCount = 0;
const tokensInput = tokensTextarea.value.trim();
if (!tokensInput) {
alert("请输入至少一个 API Key");
return;
}
const threshold = parseFloat(thresholdInput.value) || 1;
const concurrency = parseInt(concurrencyInput.value) || 5;
// 分割+去重
let tokensRaw = tokensInput.split(",")
.map(t => t.trim())
.filter(t => t !== "");
let seen = new Set();
let duplicates = [];
let uniqueTokens = [];
tokensRaw.forEach(token => {
if (seen.has(token)) {
duplicates.push(token);
} else {
seen.add(token);
uniqueTokens.push(token);
}
});
// 重复计数
duplicateCountEl.textContent = duplicates.length.toString();
duplicatesResEl.textContent = duplicates.length ? duplicates.join("\\n") : "无";
// 初始化UI
checkButton.disabled = true;
checkButton.innerHTML = '<span class="loader"></span>检测中...';
validResEl.textContent = "";
lowBalResEl.textContent = "";
zeroBalResEl.textContent = "";
invalidResEl.textContent = "";
validCountEl.textContent = "0";
lowBalanceCountEl.textContent = "0";
zeroBalanceCountEl.textContent = "0";
invalidCountEl.textContent = "0";
copyButton.style.display = "none";
// 存放可复制token(≥阈值)
let validTokensForCopy = [];
// 构造任务
const tasks = uniqueTokens.map(token => {
return () => checkOneToken(token);
});
// 单次结果处理
function onSingleResult(res) {
if (!res || res.error) {
// 网络/请求出错 => 无效
invalidCount++;
invalidCountEl.textContent = invalidCount.toString();
invalidResEl.textContent += "未知Token(请求失败): " + (res && res.error || "unknown") + "\\n";
return;
}
if (!res.isValid) {
invalidCount++;
invalidCountEl.textContent = invalidCount.toString();
invalidResEl.textContent += res.token + " (" + res.message + ")\\n";
return;
}
// 有效
const bal = res.balance;
const display = res.token + " (余额:" + bal + ")";
if (bal === 0) {
zeroBalanceCount++;
zeroBalanceCountEl.textContent = zeroBalanceCount.toString();
zeroBalResEl.textContent += display + "\\n";
} else if (bal < threshold) {
lowBalanceCount++;
lowBalanceCountEl.textContent = lowBalanceCount.toString();
lowBalResEl.textContent += display + "\\n";
} else {
validCount++;
validCountEl.textContent = validCount.toString();
validResEl.textContent += display + "\\n";
validTokensForCopy.push(res.token);
if (validCount === 1) {
copyButton.style.display = "block";
}
}
}
try {
// 并发执行
await runWithConcurrencyLimit(tasks, concurrency, onSingleResult);
} catch (err) {
alert("检测失败: " + err.message);
console.error(err);
} finally {
checkButton.disabled = false;
checkButton.textContent = "检测账号";
}
// 记录可复制列表
window.__VALID_TOKENS_FOR_COPY__ = validTokensForCopy;
}
// 在前端验证 + 查询余额
async function checkOneToken(token) {
// 1. 验证token
const resp1 = await fetch("https://api.siliconflow.cn/v1/chat/completions", {
method: "POST",
headers: {
"Authorization": "Bearer " + token,
"Content-Type": "application/json"
},
body: JSON.stringify({
model: "Qwen/Qwen2.5-7B-Instruct",
messages: [{ role: "user", content: "hi" }],
max_tokens: 100,
stream: false
})
});
if (!resp1.ok) {
const errData = await resp1.json().catch(() => null);
return {
token,
isValid: false,
message: errData && errData.message ? errData.message : "验证失败"
};
}
// 2. 查询余额
const resp2 = await fetch("https://api.siliconflow.cn/v1/user/info", {
method: "GET",
headers: { "Authorization": "Bearer " + token }
});
if (!resp2.ok) {
const errData = await resp2.json().catch(() => null);
return {
token,
isValid: false,
message: errData && errData.message ? errData.message : "余额获取失败"
};
}
const data2 = await resp2.json();
return {
token,
isValid: true,
balance: data2.data && data2.data.totalBalance || 0
};
}
// 复制≥阈值token
function copyValidTokens() {
const validTokens = window.__VALID_TOKENS_FOR_COPY__ || [];
if (!validTokens.length) {
alert("没有可复制的有效账号(≥阈值)");
return;
}
const joined = validTokens.join(",");
const textArea = document.createElement("textarea");
textArea.value = joined;
document.body.appendChild(textArea);
textArea.select();
document.execCommand("copy");
document.body.removeChild(textArea);
alert("有效账号已复制到剪贴板");
}
</script>
</body>
</html>
`;
修改自 硅基流动KEY有效性检测器 - 资源荟萃 - LINUX DO
功能特性
- 批量检测:支持一次性输入多个 API Key(以英文逗号分隔),自动去重并检测。
- 实时显示:每检测完一个账号,立即显示结果,无需等待全部完成。
- 分类统计:将检测结果分为以下几类:
- 有效账号(余额 ≥ 阈值)
- 低余额账号(0 < 余额 < 阈值)
- 零余额账号
- 无效账号
- 重复账号
- 并发控制:用户可以自定义并发请求数,避免触发 API 限流。
- 余额阈值:支持设置最低余额阈值,自动筛选符合条件的账号。
- 复制功能:一键复制所有有效账号(余额 ≥ 阈值),方便后续使用。
使用说明
- 输入 API Key:在文本框中输入多个 API Key,以英文逗号分隔。
- 设置阈值:输入最低余额阈值(默认1)。
- 设置并发数:输入并发请求数(默认5)。
- 开始检测:点击“检测账号”按钮,工具会实时显示检测结果。
- 复制有效账号:检测完成后,点击“复制所有有效账号”按钮,即可复制所有余额 ≥ 阈值的 API Key。