硅基流动Token余额检测-CloudFlare Workers

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 限流。
  • 余额阈值:支持设置最低余额阈值,自动筛选符合条件的账号。
  • 复制功能:一键复制所有有效账号(余额 ≥ 阈值),方便后续使用。

使用说明

  1. 输入 API Key:在文本框中输入多个 API Key,以英文逗号分隔。
  2. 设置阈值:输入最低余额阈值(默认1)。
  3. 设置并发数:输入并发请求数(默认5)。
  4. 开始检测:点击“检测账号”按钮,工具会实时显示检测结果。
  5. 复制有效账号:检测完成后,点击“复制所有有效账号”按钮,即可复制所有余额 ≥ 阈值的 API Key。

Demo演示

Demo

25 个赞

为佬友点赞

8 个赞

感谢佬分享 :tieba_013:

7 个赞

感谢大佬!

现在只能英文逗号分割,能不能增加几种,比如空格 分号 换行 。 让cursor改了半天一直不行

支持空格换行分号

// 分割+去重
let tokensRaw = tokensInput
  .split(/[,;\\s\\n]/)
  .map(t => t.trim())
  .filter(t => t !== "");

么么哒。人还是比AI智能

好了,感谢大哥。

好东西,收藏了。

太强了佬,感谢分享