Download src/aistudio_api/static/login.html from jlshu/vproxy: direct link, hf CLI and curl.
- Browser
- Download file 5.39 kB
-
https://huggingface.co/spaces/jlshu/vproxy/resolve/main/src/aistudio_api/static/login.html
- Command line
-
hf download hf://spaces/jlshu/vproxy/src/aistudio_api/static/login.html
-
curl -L -o login.html https://huggingface.co/spaces/jlshu/vproxy/resolve/main/src/aistudio_api/static/login.html
5.39 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"> | |
| <style> | |
| body { | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| min-height: 100vh; | |
| background: var(--bg-alt); | |
| } | |
| .login-container { | |
| width: 100%; | |
| max-width: 420px; | |
| padding: 24px; | |
| } | |
| .login-card { | |
| background: #fff; | |
| border-radius: 16px; | |
| box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08); | |
| padding: 40px 32px; | |
| } | |
| .login-header { | |
| text-align: center; | |
| margin-bottom: 32px; | |
| } | |
| .login-logo { | |
| width: 56px; | |
| height: 56px; | |
| background: var(--green); | |
| border-radius: 14px; | |
| display: flex; | |
| align-items: center; | |
| justify-content: center; | |
| color: #fff; | |
| font-weight: 700; | |
| font-size: 24px; | |
| margin: 0 auto 16px; | |
| } | |
| .login-header h1 { | |
| font-size: 24px; | |
| font-weight: 600; | |
| margin-bottom: 8px; | |
| } | |
| .login-header p { | |
| font-size: 14px; | |
| color: var(--muted); | |
| } | |
| .login-field { | |
| margin-bottom: 20px; | |
| } | |
| .login-field label { | |
| display: block; | |
| font-size: 14px; | |
| font-weight: 500; | |
| margin-bottom: 8px; | |
| } | |
| .login-input { | |
| width: 100%; | |
| padding: 12px 14px; | |
| border: 1px solid var(--border); | |
| border-radius: 10px; | |
| font-size: 15px; | |
| font-family: inherit; | |
| outline: none; | |
| transition: border-color 0.15s, box-shadow 0.15s; | |
| } | |
| .login-input:focus { | |
| border-color: var(--green); | |
| box-shadow: 0 0 0 3px rgba(16, 163, 127, 0.12); | |
| } | |
| .login-input::placeholder { | |
| color: #a3a3a3; | |
| } | |
| .login-btn { | |
| width: 100%; | |
| padding: 12px; | |
| background: var(--green); | |
| color: #fff; | |
| border: none; | |
| border-radius: 10px; | |
| font-size: 15px; | |
| font-weight: 600; | |
| cursor: pointer; | |
| transition: background 0.15s; | |
| font-family: inherit; | |
| } | |
| .login-btn:hover { | |
| background: #0e8c6b; | |
| } | |
| .login-btn:disabled { | |
| background: var(--border); | |
| cursor: not-allowed; | |
| } | |
| .login-error { | |
| background: #fef2f2; | |
| color: #991b1b; | |
| padding: 12px 14px; | |
| border-radius: 10px; | |
| font-size: 14px; | |
| margin-bottom: 20px; | |
| display: none; | |
| } | |
| .login-error.show { | |
| display: block; | |
| } | |
| .login-footer { | |
| text-align: center; | |
| margin-top: 24px; | |
| font-size: 13px; | |
| color: var(--muted); | |
| } | |
| .login-footer a { | |
| color: var(--green); | |
| text-decoration: none; | |
| font-weight: 500; | |
| } | |
| .login-footer a:hover { | |
| text-decoration: underline; | |
| } | |
| </style> | |
| </head> | |
| <body x-data="loginApp()" x-init="init()"> | |
| <div class="login-container"> | |
| <div class="login-card"> | |
| <div class="login-header"> | |
| <div class="login-logo">AI</div> | |
| <h1>AI Studio Proxy</h1> | |
| <p>请输入 API Token 登录系统</p> | |
| </div> | |
| <div class="login-error" :class="{show: error}" x-text="error"></div> | |
| <form @submit.prevent="handleLogin()"> | |
| <div class="login-field"> | |
| <label for="token">API Token</label> | |
| <input id="token" class="login-input" type="password" x-model="token" placeholder="输入您的 API Token" autofocus | |
| autocomplete="current-password"> | |
| </div> | |
| <button type="submit" class="login-btn" :disabled="loading || !token.trim()"> | |
| <span x-show="!loading">登录</span> | |
| <span x-show="loading">验证中...</span> | |
| </button> | |
| </form> | |
| <div class="login-footer"> | |
| <p>Token 由管理员提供,请联系管理员获取</p> | |
| </div> | |
| </div> | |
| </div> | |
| <script> | |
| function loginApp() { | |
| return { | |
| token: '', | |
| error: '', | |
| loading: false, | |
| init() { | |
| // 检查是否已有 token | |
| const savedToken = localStorage.getItem('asp_api_token'); | |
| if (savedToken) { | |
| this.token = savedToken; | |
| // 尝试自动登录 | |
| this.handleLogin(); | |
| } | |
| }, | |
| async handleLogin() { | |
| const token = this.token.trim(); | |
| if (!token) return; | |
| this.error = ''; | |
| this.loading = true; | |
| try { | |
| // 调用 /stats 端点验证 token(该端点受 API Key 保护) | |
| const res = await fetch('/stats', { | |
| headers: { | |
| 'Authorization': `Bearer ${token}` | |
| } | |
| }); | |
| if (res.ok) { | |
| // 登录成功,保存 token 并跳转 | |
| localStorage.setItem('asp_api_token', token); | |
| window.location.href = '/'; | |
| } else if (res.status === 401) { | |
| this.error = 'Token 无效,请检查后重试'; | |
| } else { | |
| this.error = `验证失败 (${res.status}),请稍后重试`; | |
| } | |
| } catch (e) { | |
| this.error = '网络错误,请检查连接后重试'; | |
| } finally { | |
| this.loading = false; | |
| } | |
| } | |
| } | |
| } | |
| </script> | |
| <script defer src="/static/alpine.min.js"></script> | |
| </body> | |
| </html> | |