Spaces:
Sleeping
Sleeping
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Dashboard - Voice Lab</title> | |
| <link rel="stylesheet" href="css/style.css"> | |
| <link rel="stylesheet" href="css/dashboard.css"> | |
| </head> | |
| <body> | |
| <div class="landing-mesh" style="z-index: -2; position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; background: radial-gradient(circle at 10% 20%, rgba(124, 58, 237, 0.08) 0%, transparent 40%), radial-gradient(circle at 90% 80%, rgba(37, 99, 235, 0.08) 0%, transparent 40%); pointer-events: none;"></div> | |
| <canvas id="particles-canvas"></canvas> | |
| <nav id="main-nav"> | |
| <a href="index.html" class="logo"> | |
| <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"></path><path d="M19 10v2a7 7 0 0 1-14 0v-2"></path><line x1="12" y1="19" x2="12" y2="22"></line></svg> | |
| Voice Lab | |
| </a> | |
| <div class="nav-links" id="nav-links"> | |
| <a href="index.html">Home</a> | |
| <a href="dashboard.html" class="active">Dashboard</a> | |
| <a href="tts.html">TTS</a> | |
| <a href="sts.html">STS</a> | |
| <button id="logout-btn" class="btn btn-danger" style="padding: 0.4rem 1rem; font-size: 0.85rem;">Logout</button> | |
| </div> | |
| </nav> | |
| <main style="max-width: 1100px; margin: 2rem auto; padding: 0 5%; position: relative; z-index: 10;"> | |
| <div class="page-header animate-fade-in" style="margin-bottom: 3rem; display: flex; justify-content: space-between; align-items: center;"> | |
| <div> | |
| <h1 style="font-size: 2.5rem;"><span class="text-gradient">Welcome, <span id="user-display">User</span></span></h1> | |
| <p style="color: var(--text-muted); font-size: 1.1rem; margin-top: 0.5rem;">Your Voice Lab Command Center</p> | |
| </div> | |
| <div class="spinner-orb" style="width: 50px; height: 50px; margin: 0;"></div> | |
| </div> | |
| <div class="dashboard-grid animate-slide-up stagger-1"> | |
| <div class="glass-panel stat-card"> | |
| <div class="stat-icon"> | |
| <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"></path></svg> | |
| </div> | |
| <div class="stat-info"> | |
| <h4>Total Generations</h4> | |
| <p id="total-generations-count">0</p> | |
| </div> | |
| </div> | |
| <div class="glass-panel stat-card"> | |
| <div class="stat-icon" style="background: rgba(16, 185, 129, 0.1); color: var(--success);"> | |
| <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"></polyline></svg> | |
| </div> | |
| <div class="stat-info"> | |
| <h4>System Status</h4> | |
| <p id="system-status-text" style="font-size: 1.2rem; color: var(--success);">Online</p> | |
| </div> | |
| </div> | |
| <div class="glass-panel stat-card"> | |
| <div class="stat-icon" style="background: rgba(244, 63, 94, 0.1); color: var(--accent);"> | |
| <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"></circle><polyline points="12 6 12 12 16 14"></polyline></svg> | |
| </div> | |
| <div class="stat-info"> | |
| <h4>Compute Saved</h4> | |
| <p id="compute-saved-text">0m</p> | |
| </div> | |
| </div> | |
| </div> | |
| <div class="dashboard-grid animate-slide-up stagger-2" style="grid-template-columns: 1fr 1fr; margin-top: 2rem;"> | |
| <!-- GPU Server Connection Panel --> | |
| <div class="glass-panel" style="padding: 2rem; border-color: rgba(37, 99, 235, 0.3);"> | |
| <div style="display: flex; align-items: center; justify-content: space-between; margin-bottom: 1.5rem;"> | |
| <h3 style="font-size: 1.4rem; display: flex; align-items: center; gap: 0.5rem;"> | |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--secondary)" stroke-width="2"><rect x="2" y="2" width="20" height="8" rx="2" ry="2"></rect><rect x="2" y="14" width="20" height="8" rx="2" ry="2"></rect><line x1="6" y1="6" x2="6.01" y2="6"></line><line x1="6" y1="18" x2="6.01" y2="18"></line></svg> | |
| GPU Inference Server | |
| </h3> | |
| <div id="colab-status-badge" style="padding: 0.3rem 0.8rem; border-radius: 100px; font-size: 0.8rem; font-weight: 600; background: rgba(244, 63, 94, 0.1); color: var(--accent); border: 1px solid var(--accent);">Disconnected</div> | |
| </div> | |
| <p style="color: var(--text-muted); font-size: 0.95rem; line-height: 1.5; margin-bottom: 1.5rem;"> | |
| Link your powerful Colab or local Gradio GPU server to enable blazing-fast Zero-Shot Voice Cloning and Speech-to-Speech generation. | |
| </p> | |
| <div style="display: flex; gap: 1rem;"> | |
| <input type="text" id="colab-url-input" placeholder="e.g. https://1234abcd.gradio.live" style="flex: 1; padding: 0.8rem 1.2rem; background: rgba(0,0,0,0.3); border: 1px solid var(--border); border-radius: 12px; color: white; font-family: inherit;"> | |
| <button id="connect-colab-btn" class="btn btn-glow" style="min-width: 120px;">Connect</button> | |
| </div> | |
| <div id="colab-info" style="margin-top: 1rem; font-size: 0.85rem; color: var(--text-dim);"> | |
| Currently falling back to Hugging Face Space (Slower). | |
| </div> | |
| </div> | |
| <!-- Quick Actions Panel --> | |
| <div class="glass-panel" style="padding: 2rem;"> | |
| <h3 style="font-size: 1.4rem; margin-bottom: 1.5rem; display: flex; align-items: center; gap: 0.5rem;"> | |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="var(--primary)" stroke-width="2"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon></svg> | |
| Generative Workflows | |
| </h3> | |
| <p style="color: var(--text-muted); font-size: 0.95rem; line-height: 1.5; margin-bottom: 1.5rem;"> | |
| Jump right into your creative process. Start synthesizing text or cloning existing audio directly. | |
| </p> | |
| <div class="quick-actions" style="margin-top: 0; display: flex; flex-direction: column; gap: 1rem;"> | |
| <a href="tts.html" class="btn btn-glow" style="justify-content: flex-start; padding: 1rem 1.5rem;"> | |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="margin-right: 0.5rem;"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path></svg> | |
| Neural Text-to-Speech | |
| </a> | |
| <a href="sts.html" class="btn btn-outline" style="justify-content: flex-start; padding: 1rem 1.5rem; background: rgba(255,255,255,0.02);"> | |
| <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="margin-right: 0.5rem;"><path d="M12 2a3 3 0 0 0-3 3v7a3 3 0 0 0 6 0V5a3 3 0 0 0-3-3Z"></path><path d="M19 10v2a7 7 0 0 1-14 0v-2"></path><line x1="12" y1="19" x2="12" y2="22"></line></svg> | |
| Voice Cloning & STS | |
| </a> | |
| </div> | |
| </div> | |
| </div> | |
| </main> | |
| <script src="js/particles.js"></script> | |
| <script src="js/toast.js"></script> | |
| <script> | |
| const API_URL = ''; | |
| document.addEventListener('DOMContentLoaded', async () => { | |
| const token = localStorage.getItem('token'); | |
| if (!token) { window.location.href = 'auth.html'; return; } | |
| document.getElementById('logout-btn').addEventListener('click', () => { | |
| localStorage.removeItem('token'); | |
| window.location.href = 'index.html'; | |
| }); | |
| // Fetch User | |
| try { | |
| const res = await fetch(`${API_URL}/auth/me`, { | |
| headers: {'Authorization': 'Bearer ' + token} | |
| }); | |
| if (res.ok) { | |
| const data = await res.json(); | |
| document.getElementById('user-display').textContent = data.username; | |
| } else { | |
| throw new Error(); | |
| } | |
| } catch (e) { | |
| localStorage.removeItem('token'); | |
| window.location.href = 'auth.html'; | |
| } | |
| // GPU Server Logic | |
| const colabInput = document.getElementById('colab-url-input'); | |
| const connectBtn = document.getElementById('connect-colab-btn'); | |
| const statusBadge = document.getElementById('colab-status-badge'); | |
| const colabInfo = document.getElementById('colab-info'); | |
| async function checkGPUStatus() { | |
| try { | |
| const res = await fetch(`${API_URL}/admin/status`); | |
| if(res.ok) { | |
| const data = await res.json(); | |
| if(data.using_colab && data.connected) { | |
| statusBadge.textContent = 'Connected'; | |
| statusBadge.style.background = 'rgba(16, 185, 129, 0.1)'; | |
| statusBadge.style.color = 'var(--success)'; | |
| statusBadge.style.borderColor = 'var(--success)'; | |
| colabInfo.textContent = 'High-speed GPU instance active.'; | |
| colabInfo.style.color = 'var(--success)'; | |
| } else { | |
| statusBadge.textContent = 'Disconnected'; | |
| statusBadge.style.background = 'rgba(244, 63, 94, 0.1)'; | |
| statusBadge.style.color = 'var(--accent)'; | |
| statusBadge.style.borderColor = 'var(--accent)'; | |
| colabInfo.textContent = data.space_connected ? 'Falling back to HF Space (Slower).' : 'No inference servers available.'; | |
| colabInfo.style.color = 'var(--text-dim)'; | |
| } | |
| } | |
| } catch(e) { | |
| console.error("Failed to check status", e); | |
| } | |
| } | |
| async function fetchStats() { | |
| try { | |
| const res = await fetch(`${API_URL}/admin/stats`, { | |
| headers: {'Authorization': 'Bearer ' + token} | |
| }); | |
| if(res.ok) { | |
| const data = await res.json(); | |
| document.getElementById('total-generations-count').textContent = data.total_generations; | |
| document.getElementById('compute-saved-text').textContent = data.compute_saved; | |
| } | |
| } catch(e) { | |
| console.error("Failed to fetch stats", e); | |
| } | |
| } | |
| // Initial Check | |
| checkGPUStatus(); | |
| fetchStats(); | |
| connectBtn.addEventListener('click', async () => { | |
| const url = colabInput.value.trim(); | |
| if(!url) { showToast('Please enter a valid Gradio URL', 'warning'); return; } | |
| connectBtn.innerHTML = '<div class="spinner-orb" style="width:16px;height:16px;margin:0;"></div>'; | |
| connectBtn.disabled = true; | |
| try { | |
| const res = await fetch(`${API_URL}/admin/colab`, { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| 'Authorization': 'Bearer ' + token | |
| }, | |
| body: JSON.stringify({ url: url }) | |
| }); | |
| if(res.ok) { | |
| showToast('Successfully connected to GPU Server!', 'success'); | |
| setTimeout(checkGPUStatus, 1000); // give backend a second to verify | |
| } else { | |
| throw new Error('Failed to connect'); | |
| } | |
| } catch(e) { | |
| showToast(e.message, 'error'); | |
| } finally { | |
| connectBtn.innerHTML = 'Connect'; | |
| connectBtn.disabled = false; | |
| } | |
| }); | |
| }); | |
| </script> | |
| </body> | |
| </html> | |