Download src/aistudio_api/static/index.html from jlshu/vproxy: direct link, hf CLI and curl.
- Browser
- Download file 13.4 kB
-
https://huggingface.co/spaces/jlshu/vproxy/resolve/main/src/aistudio_api/static/index.html
- Command line
-
hf download hf://spaces/jlshu/vproxy/src/aistudio_api/static/index.html
-
curl -L -o index.html https://huggingface.co/spaces/jlshu/vproxy/resolve/main/src/aistudio_api/static/index.html
13.4 kB
| <html lang="zh-CN"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> | |
| <title>AI Studio Proxy</title> | |
| <link rel="stylesheet" href="/static/style.css"> | |
| </head> | |
| <body x-data="app()" x-init="init()" @click="configOpen=false"> | |
| <div class="overlay" :class="{open:sidebarOpen}" @click="sidebarOpen=false"></div> | |
| <nav class="sidebar" :class="{open:sidebarOpen}"> | |
| <div class="sidebar-header"> | |
| <div class="logo">AI</div><span>AI Studio Proxy</span> | |
| </div> | |
| <div class="nav-section"> | |
| <button class="nav-item" :class="{active:view==='dashboard'}" @click="go('dashboard')"> | |
| <svg viewBox="0 0 24 24"> | |
| <rect x="3" y="3" width="18" height="18" rx="2" /> | |
| <line x1="3" y1="9" x2="21" y2="9" /> | |
| <line x1="9" y1="21" x2="9" y2="9" /> | |
| </svg> 控制面板 </button> | |
| <button class="nav-item" :class="{active:view==='accounts'}" @click="go('accounts')"> | |
| <svg viewBox="0 0 24 24"> | |
| <path d="M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2" /> | |
| <circle cx="9" cy="7" r="4" /> | |
| <path d="M23 21v-2a4 4 0 00-3-3.87" /> | |
| <path d="M16 3.13a4 4 0 010 7.75" /> | |
| </svg> 账号管理 </button> | |
| </div> | |
| <div class="sidebar-footer"> | |
| <div class="dot"></div><span>系统在线</span> | |
| <button class="logout-btn" @click="logout()" title="登出" x-show="authEnabled"> | |
| <svg viewBox="0 0 24 24" width="16" height="16"> | |
| <path d="M9 21H5a2 2 0 01-2-2V5a2 2 0 012-2h4" /> | |
| <polyline points="16 17 21 12 16 7" /> | |
| <line x1="21" y1="12" x2="9" y2="12" /> | |
| </svg> | |
| </button> | |
| </div> | |
| </nav> | |
| <div class="main"> | |
| <div class="topbar"> | |
| <div class="topbar-left"> | |
| <button class="mh-btn" @click="sidebarOpen=true">☰</button> | |
| <span class="topbar-title" x-text="view==='dashboard'?'控制面板':'账号管理'"></span> | |
| </div> | |
| <div class="topbar-right" @click.stop> | |
| <button class="icon-btn" :class="{active:configOpen}" @click="configOpen=!configOpen" title="API Token 设置"> | |
| <svg viewBox="0 0 24 24"> | |
| <path | |
| d="M12.22 2h-.44a2 2 0 00-2 2v.18a2 2 0 01-1 1.73l-.43.25a2 2 0 01-2 0l-.15-.08a2 2 0 00-2.73.73l-.22.38a2 2 0 00.73 2.73l.15.1a2 2 0 011 1.72v.51a2 2 0 01-1 1.74l-.15.09a2 2 0 00-.73 2.73l.22.38a2 2 0 002.73.73l.15-.08a2 2 0 012 0l.43.25a2 2 0 011 1.73V20a2 2 0 002 2h.44a2 2 0 002-2v-.18a2 2 0 011-1.73l.43-.25a2 2 0 012 0l.15.08a2 2 0 002.73-.73l.22-.39a2 2 0 00-.73-2.73l-.15-.08a2 2 0 01-1-1.74v-.5a2 2 0 011-1.74l.15-.09a2 2 0 00.73-2.73l-.22-.38a2 2 0 00-2.73-.73l-.15.08a2 2 0 01-2 0l-.43-.25a2 2 0 01-1-1.73V4a2 2 0 00-2-2z" /> | |
| <circle cx="12" cy="12" r="3" /> | |
| </svg> | |
| </button> | |
| <div class="cfg-dropdown" x-show="configOpen" x-cloak @click.stop> | |
| <div class="cfg-head">API Token 设置</div> | |
| <div class="cfg-body"> | |
| <div class="cfg-item"> | |
| <div class="cfg-info"> | |
| <div class="cfg-name">API Token</div> | |
| <div class="cfg-desc">开启鉴权后会自动附带 Bearer Token,仅保存在当前浏览器</div> | |
| </div> | |
| <div class="cfg-ctrl"><input class="cfg-num" type="password" x-model="auth.token" | |
| placeholder="留空则不发送"></div> | |
| </div> | |
| <div class="cfg-sep"></div> | |
| <div class="cfg-item" style="padding-top:4px"> | |
| <button class="btn btn-danger btn-block" @click="clearCache()">清理本地缓存</button> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Dashboard --> | |
| <div class="page-wrap" :class="{active:view==='dashboard'}"> | |
| <div class="scroll-area"> | |
| <div class="page-pad"> | |
| <div class="stat-grid"> | |
| <div class="stat-card"> | |
| <div class="slabel">当前激活账号</div> | |
| <div class="sval" x-text="activeAccount.email||'暂无'"></div> | |
| </div> | |
| <div class="stat-card"> | |
| <div class="slabel">轮询模式</div> | |
| <div class="sval" x-text="rotationMode==='round_robin'?'顺序轮询':rotationMode"></div> | |
| </div> | |
| <div class="stat-card"> | |
| <div class="slabel">总请求数</div> | |
| <div class="sval" x-text="totalReqs"></div> | |
| </div> | |
| <div class="stat-card"> | |
| <div class="slabel">429 频率限制数</div> | |
| <div class="sval sval-amber" x-text="totalRL"></div> | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <div class="card-head">模型统计</div> | |
| <div class="table-wrap"> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>模型</th> | |
| <th>请求</th> | |
| <th>成功</th> | |
| <th>429</th> | |
| <th>错误</th> | |
| <th>最后使用</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <template x-for="(s,n) in stats" :key="n"> | |
| <tr> | |
| <td style="font-weight:500" x-text="n.replace('models/','')"></td> | |
| <td x-text="s.requests||0"></td> | |
| <td><span class="badge badge-green" x-text="s.success||0"></span></td> | |
| <td><span class="badge" :class="(s.rate_limited||0)>0?'badge-red':'badge-gray'" | |
| x-text="s.rate_limited||0"></span></td> | |
| <td x-text="s.errors||0"></td> | |
| <td style="font-size:13px;color:var(--muted)" x-text="fmtDate(s.last_used)"></td> | |
| </tr> | |
| </template> | |
| <tr x-show="!Object.keys(stats).length"> | |
| <td colspan="6" style="text-align:center;color:var(--muted);padding:24px">暂无数据</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Accounts --> | |
| <div class="page-wrap" :class="{active:view==='accounts'}"> | |
| <div class="scroll-area"> | |
| <div class="page-pad"> | |
| <div | |
| style="display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:12px;margin-bottom:24px"> | |
| <h1 style="font-size:24px;font-weight:700">账号管理</h1> | |
| <div style="display:flex;gap:8px;flex-wrap:wrap"> | |
| <button class="btn btn-primary" @click="cookieModal.open=true">+ 导入 Cookies</button> | |
| </div> | |
| </div> | |
| <div class="card" style="margin-bottom:24px"> | |
| <div class="card-head">轮询设置</div> | |
| <div style="padding:20px;display:flex;flex-wrap:wrap;gap:16px;align-items:end"> | |
| <div> | |
| <div style="font-size:13px;color:var(--muted);margin-bottom:4px">模式</div> | |
| <div class="cselect" :class="{open:openSelect==='rotMode'}" @click.stop> | |
| <div class="cselect-btn" @click="toggleSelect('rotMode',$event)" tabindex="0" style="min-width:130px"> | |
| <span | |
| x-text="rotCfg.mode==='round_robin'?'顺序轮询':rotCfg.mode==='lru'?'最近最少使用 (LRU)':rotCfg.mode==='least_rl'?'最小频率限制':'未知'"></span><span | |
| class="arrow"></span></div> | |
| <div class="cselect-menu"><template x-for="v in ['round_robin','lru','least_rl']"> | |
| <div class="cselect-opt" :class="{active:rotCfg.mode===v}" @click="rotCfg.mode=v;openSelect=null" | |
| x-text="v==='round_robin'?'顺序轮询':v==='lru'?'最近最少使用 (LRU)':v==='least_rl'?'最小频率限制':v"></div> | |
| </template></div> | |
| </div> | |
| </div> | |
| <div> | |
| <div style="font-size:13px;color:var(--muted);margin-bottom:4px">冷却时间 (秒)</div><input type="number" | |
| x-model.number="rotCfg.cooldown" | |
| style="width:80px;padding:8px;border:1px solid var(--border);border-radius:8px;font-size:14px" | |
| min="0"> | |
| </div> | |
| <button class="btn" @click="saveRotation()">保存设置</button> | |
| <button class="btn" @click="forceNext()">强制切换</button> | |
| </div> | |
| </div> | |
| <div class="card"> | |
| <div class="card-head"><span>账号池</span><span style="font-size:13px;color:var(--muted)" | |
| x-text="accountRows.length+' 个账号'"></span></div> | |
| <div class="table-wrap"> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>账号 / 邮箱</th> | |
| <th>子账号</th> | |
| <th>请求</th> | |
| <th>成功</th> | |
| <th>429</th> | |
| <th>状态</th> | |
| <th>操作</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <template x-for="a in accountRows" :key="a.id"> | |
| <tr> | |
| <td> | |
| <div style="font-weight:500" x-text="a.email||a.name||a.id"></div> | |
| <div style="font-size:12px;color:var(--muted);font-family:monospace" x-text="a.id"></div> | |
| </td> | |
| <td> | |
| <span class="badge" style="background:rgba(59,130,246,0.15);color:#3b82f6;font-family:monospace;font-weight:600" x-text="'u/' + (a.auth_user !== undefined ? a.auth_user : '0')"></span> | |
| </td> | |
| <td x-text="a.requests||0"></td> | |
| <td><span class="badge badge-green" x-text="a.success||0"></span></td> | |
| <td><span class="badge" :class="(a.rate_limited||0)>0?'badge-red':'badge-gray'" | |
| x-text="a.rate_limited||0"></span></td> | |
| <td><span class="badge badge-green" x-show="a.id===activeId">激活</span><span | |
| class="badge badge-gray" x-show="a.id!==activeId">待命</span></td> | |
| <td><button class="btn btn-sm" x-show="a.id!==activeId" | |
| @click="activateAccount(a.id)">手动激活</button></td> | |
| </tr> | |
| </template> | |
| <tr x-show="!accountRows.length"> | |
| <td colspan="7" style="text-align:center;color:var(--muted);padding:24px">暂无账号</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| </div> | |
| <!-- Cookie Import Modal --> | |
| <div class="modal-overlay" x-show="cookieModal.open" x-cloak @click.self="cookieModal.open=false" | |
| x-transition.opacity> | |
| <div class="modal" x-show="cookieModal.open" x-transition> | |
| <div class="modal-head"> | |
| <span>导入 Cookies</span> | |
| <button class="modal-close" @click="cookieModal.open=false">×</button> | |
| </div> | |
| <div class="modal-body"> | |
| <div class="modal-field"> | |
| <label>Cookie 数据 <span style="color:var(--muted);font-weight:400">(支持 Cookie 插件导出的 JSON 数组、Netscape 7列、或 KV 文本)</span></label> | |
| <textarea class="modal-textarea" x-model="cookieModal.cookies" | |
| placeholder='[{"name":"SAPISID","value":"..."},...] 或 SID=xxx; SSID=xxx; HSID=xxx; ...' | |
| rows="7"></textarea> | |
| </div> | |
| <div style="margin-bottom:12px;display:flex;align-items:center;gap:8px"> | |
| <input type="checkbox" id="autoProbeCheck" x-model="cookieModal.autoProbe" style="cursor:pointer;width:16px;height:16px"> | |
| <label for="autoProbeCheck" style="cursor:pointer;font-size:13px;font-weight:500">⚡ 自动无限向下探活多登录账号 (u/0, u/1, u/2... 一键批量分化导入)</label> | |
| </div> | |
| <div style="display:flex;gap:12px"> | |
| <div class="modal-field" style="flex:1"> | |
| <label>账号名称前缀 <span style="color:var(--muted);font-weight:400">(可选)</span></label> | |
| <input class="modal-input" x-model="cookieModal.name" placeholder="Google Account"> | |
| </div> | |
| <div class="modal-field" style="flex:1" x-show="!cookieModal.autoProbe"> | |
| <label>邮箱 <span style="color:var(--muted);font-weight:400">(可选)</span></label> | |
| <input class="modal-input" x-model="cookieModal.email" placeholder="user@gmail.com"> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="modal-foot"> | |
| <button class="btn" @click="cookieModal.open=false">取消</button> | |
| <button class="btn btn-primary" :disabled="cookieModal.importing" @click="importCookies()"> | |
| <span x-show="!cookieModal.importing" x-text="cookieModal.autoProbe ? '⚡ 探活并导入' : '导入'"></span> | |
| <span x-show="cookieModal.importing">探活与导入中...</span> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="toast" :class="{show:toast.show}" x-text="toast.msg"></div> | |
| <script src="/static/app.js"></script> | |
| <script defer src="/static/alpine.min.js"></script> | |
| </body> | |
| </html> | |