Update index.html
Browse files- index.html +73 -74
index.html
CHANGED
|
@@ -3,7 +3,7 @@
|
|
| 3 |
<head>
|
| 4 |
<meta charset="UTF-8">
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
-
<title>Wavetype Frequency Grid -
|
| 7 |
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/css/bootstrap.min.css" rel="stylesheet">
|
| 8 |
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-icons/1.11.1/font/bootstrap-icons.min.css" rel="stylesheet">
|
| 9 |
<style>
|
|
@@ -23,6 +23,7 @@
|
|
| 23 |
font-family: "Courier New", Courier, monospace; color: white;
|
| 24 |
}
|
| 25 |
|
|
|
|
| 26 |
#sidebar {
|
| 27 |
position: fixed; left: 0; top: 0; width: 320px; height: 100vh;
|
| 28 |
background: linear-gradient(180deg, #1a1a1a 0%, #0d0d0d 100%);
|
|
@@ -44,7 +45,7 @@
|
|
| 44 |
#sidebar.collapsed ~ #sidebar-toggle { left: 0; }
|
| 45 |
|
| 46 |
.auth-section { padding: 15px; border-bottom: 1px solid #333; background: #111; }
|
| 47 |
-
.
|
| 48 |
|
| 49 |
#grid-container {
|
| 50 |
display: grid; width: 100vw; height: 100vh; gap: 4px; padding: 4px;
|
|
@@ -57,11 +58,10 @@
|
|
| 57 |
position: relative; background-color: rgba(255, 255, 255, var(--bg-shade));
|
| 58 |
border: 2px solid #333; display: flex; flex-direction: column;
|
| 59 |
align-items: center; justify-content: center; cursor: pointer;
|
| 60 |
-
overflow: hidden; transition: all 0.5s
|
| 61 |
}
|
| 62 |
|
| 63 |
.type-ai { border-color: var(--border-ai); }
|
| 64 |
-
.type-python { border-color: var(--border-python); }
|
| 65 |
|
| 66 |
.block.active {
|
| 67 |
position: fixed; top: 0; left: 0; width: 100vw !important;
|
|
@@ -87,51 +87,44 @@
|
|
| 87 |
position: absolute; bottom: 8px; right: 8px; width: 28px; height: 28px;
|
| 88 |
background: #00ff00; border-radius: 50%; color: #000; border: none; font-weight: bold;
|
| 89 |
}
|
| 90 |
-
|
| 91 |
-
.type-selector-overlay {
|
| 92 |
-
position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;
|
| 93 |
-
background: rgba(0,0,0,0.9); z-index: 3000; display: none;
|
| 94 |
-
align-items: center; justify-content: center;
|
| 95 |
-
}
|
| 96 |
-
|
| 97 |
-
.status-pill { font-size: 10px; padding: 2px 8px; border-radius: 10px; background: #333; margin-top: 5px; }
|
| 98 |
</style>
|
| 99 |
</head>
|
| 100 |
<body>
|
| 101 |
|
| 102 |
<div id="sidebar">
|
| 103 |
<div class="auth-section">
|
| 104 |
-
<div
|
| 105 |
-
<
|
| 106 |
-
|
| 107 |
-
|
| 108 |
-
|
| 109 |
-
<button class="btn btn-outline-
|
|
|
|
|
|
|
| 110 |
</div>
|
| 111 |
-
<div id="
|
| 112 |
-
<
|
| 113 |
-
<button class="btn btn-outline-light social-btn" onclick="handleLogin('Google')"><i class="bi bi-google"></i> Google</button>
|
| 114 |
-
<button class="btn btn-outline-light social-btn" onclick="handleLogin('GitHub')"><i class="bi bi-github"></i> GitHub</button>
|
| 115 |
</div>
|
| 116 |
</div>
|
| 117 |
|
| 118 |
<div class="p-3">
|
| 119 |
<div class="mb-4">
|
| 120 |
-
<label class="form-label small">GRID
|
| 121 |
<input type="range" class="form-range" id="blockSlider" min="1" max="25" value="4" oninput="updateGrid()">
|
| 122 |
<div class="d-flex justify-content-between small text-muted">
|
| 123 |
-
<span id="countVal">4</span>
|
| 124 |
<span id="saveStatus">Synced</span>
|
| 125 |
</div>
|
| 126 |
</div>
|
| 127 |
|
| 128 |
<div class="mb-4">
|
| 129 |
-
<label class="form-label small">
|
| 130 |
<input type="password" class="form-control form-control-sm bg-dark text-white border-secondary" id="hfToken" placeholder="hf_..." onchange="saveToCache()">
|
|
|
|
| 131 |
</div>
|
| 132 |
|
| 133 |
-
<button class="btn btn-
|
| 134 |
-
<button class="btn btn-outline-
|
| 135 |
</div>
|
| 136 |
</div>
|
| 137 |
|
|
@@ -139,25 +132,41 @@
|
|
| 139 |
|
| 140 |
<div id="grid-container"></div>
|
| 141 |
|
| 142 |
-
<div class="type-selector-overlay" id="typeSelectorOverlay">
|
| 143 |
-
<div class="bg-dark p-4 rounded border border-secondary text-center">
|
| 144 |
-
<h6 class="mb-4">ADD MODULE</h6>
|
| 145 |
-
<div class="d-flex gap-3 justify-content-center">
|
| 146 |
-
<button class="btn btn-outline-info" onclick="addNewBlock('ai')"><i class="bi bi-cpu"></i><br>FLUX AI</button>
|
| 147 |
-
<button class="btn btn-outline-warning" onclick="addNewBlock('python')"><i class="bi bi-terminal"></i><br>PYTHON</button>
|
| 148 |
-
<button class="btn btn-outline-success" onclick="addNewBlock('url')"><i class="bi bi-globe"></i><br>WEB</button>
|
| 149 |
-
</div>
|
| 150 |
-
<button class="btn btn-sm btn-link text-danger mt-4" onclick="closeTypeSelector()">CANCEL</button>
|
| 151 |
-
</div>
|
| 152 |
-
</div>
|
| 153 |
-
|
| 154 |
<script>
|
| 155 |
const container = document.getElementById("grid-container");
|
| 156 |
const countDisplay = document.getElementById("countVal");
|
| 157 |
let blocks = [];
|
| 158 |
let currentUser = null;
|
| 159 |
|
| 160 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 161 |
function saveToCache() {
|
| 162 |
const data = {
|
| 163 |
blocks,
|
|
@@ -165,7 +174,8 @@
|
|
| 165 |
user: currentUser
|
| 166 |
};
|
| 167 |
localStorage.setItem("wavetype_vps_cache", JSON.stringify(data));
|
| 168 |
-
showStatus("Saved
|
|
|
|
| 169 |
}
|
| 170 |
|
| 171 |
function loadFromCache() {
|
|
@@ -173,15 +183,15 @@
|
|
| 173 |
if (cache) {
|
| 174 |
const data = JSON.parse(cache);
|
| 175 |
blocks = data.blocks || [];
|
| 176 |
-
document.getElementById("
|
| 177 |
-
if (data.user) handleLogin(
|
| 178 |
renderGrid();
|
| 179 |
} else {
|
| 180 |
updateGrid();
|
| 181 |
}
|
|
|
|
| 182 |
}
|
| 183 |
|
| 184 |
-
// --- Grid System ---
|
| 185 |
function updateGrid() {
|
| 186 |
const count = parseInt(document.getElementById("blockSlider").value);
|
| 187 |
countDisplay.innerText = count;
|
|
@@ -190,6 +200,7 @@
|
|
| 190 |
}
|
| 191 |
while (blocks.length > count) blocks.pop();
|
| 192 |
renderGrid();
|
|
|
|
| 193 |
}
|
| 194 |
|
| 195 |
function renderGrid() {
|
|
@@ -204,22 +215,20 @@
|
|
| 204 |
|
| 205 |
el.innerHTML = `
|
| 206 |
<div class="ai-interface">
|
| 207 |
-
<h4
|
| 208 |
-
<textarea class="form-control bg-dark text-white border-
|
| 209 |
-
<button class="btn btn-
|
| 210 |
-
<div id="loader-${i}" class="text-center mt-2" style="display:none"><div class="spinner-
|
| 211 |
<img id="img-${i}" class="gen-image-preview mt-3">
|
| 212 |
</div>
|
| 213 |
-
<div class="small fw-bold opacity-50"
|
| 214 |
-
<
|
| 215 |
-
<button class="
|
| 216 |
-
<button class="add-block-btn" onclick="event.stopPropagation(); openTypeSelector()">+</button>
|
| 217 |
`;
|
| 218 |
container.appendChild(el);
|
| 219 |
});
|
| 220 |
}
|
| 221 |
|
| 222 |
-
// --- AI Logic (Flux2 Klein 9B) ---
|
| 223 |
async function generateFlux(index, btn) {
|
| 224 |
event.stopPropagation();
|
| 225 |
const prompt = document.getElementById(`prompt-${index}`).value;
|
|
@@ -227,7 +236,10 @@
|
|
| 227 |
const imgEl = document.getElementById(`img-${index}`);
|
| 228 |
const loader = document.getElementById(`loader-${index}`);
|
| 229 |
|
| 230 |
-
if (!token)
|
|
|
|
|
|
|
|
|
|
| 231 |
|
| 232 |
loader.style.display = "block";
|
| 233 |
imgEl.style.display = "none";
|
|
@@ -245,41 +257,28 @@
|
|
| 245 |
);
|
| 246 |
|
| 247 |
const blob = await response.blob();
|
| 248 |
-
|
| 249 |
-
imgEl.src = url;
|
| 250 |
imgEl.style.display = "block";
|
| 251 |
} catch (err) {
|
| 252 |
-
|
| 253 |
} finally {
|
| 254 |
loader.style.display = "none";
|
| 255 |
}
|
| 256 |
}
|
| 257 |
|
| 258 |
-
|
| 259 |
-
|
| 260 |
-
currentUser = { name: provider + " Dev", id: Date.now() };
|
| 261 |
document.getElementById("login-section").style.display = "none";
|
| 262 |
document.getElementById("user-profile").style.display = "block";
|
| 263 |
-
document.getElementById("user-name").innerText = currentUser.name;
|
| 264 |
-
}
|
| 265 |
-
|
| 266 |
-
function handleLogout() {
|
| 267 |
-
currentUser = null;
|
| 268 |
-
document.getElementById("login-section").style.display = "block";
|
| 269 |
-
document.getElementById("user-profile").style.display = "none";
|
| 270 |
}
|
| 271 |
|
| 272 |
function showStatus(msg) {
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
setTimeout(() => s.innerText = "Synced", 2000);
|
| 276 |
}
|
| 277 |
|
| 278 |
function toggleSidebar() { document.getElementById("sidebar").classList.toggle("collapsed"); }
|
| 279 |
-
function
|
| 280 |
-
function closeTypeSelector() { document.getElementById("typeSelectorOverlay").style.display = "none"; }
|
| 281 |
-
function addNewBlock(type) { blocks.push({ id: Date.now(), type, prompt: "" }); updateGrid(); closeTypeSelector(); }
|
| 282 |
-
function clearGrid() { blocks = []; updateGrid(); localStorage.clear(); }
|
| 283 |
|
| 284 |
window.onload = loadFromCache;
|
| 285 |
</script>
|
|
|
|
| 3 |
<head>
|
| 4 |
<meta charset="UTF-8">
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
+
<title>Wavetype Frequency Grid - Auto-Auth Edition</title>
|
| 7 |
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.2/css/bootstrap.min.css" rel="stylesheet">
|
| 8 |
<link href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-icons/1.11.1/font/bootstrap-icons.min.css" rel="stylesheet">
|
| 9 |
<style>
|
|
|
|
| 23 |
font-family: "Courier New", Courier, monospace; color: white;
|
| 24 |
}
|
| 25 |
|
| 26 |
+
/* Sidebar */
|
| 27 |
#sidebar {
|
| 28 |
position: fixed; left: 0; top: 0; width: 320px; height: 100vh;
|
| 29 |
background: linear-gradient(180deg, #1a1a1a 0%, #0d0d0d 100%);
|
|
|
|
| 45 |
#sidebar.collapsed ~ #sidebar-toggle { left: 0; }
|
| 46 |
|
| 47 |
.auth-section { padding: 15px; border-bottom: 1px solid #333; background: #111; }
|
| 48 |
+
.token-badge { font-size: 10px; padding: 2px 6px; border-radius: 4px; background: #28a745; color: white; display: none; }
|
| 49 |
|
| 50 |
#grid-container {
|
| 51 |
display: grid; width: 100vw; height: 100vh; gap: 4px; padding: 4px;
|
|
|
|
| 58 |
position: relative; background-color: rgba(255, 255, 255, var(--bg-shade));
|
| 59 |
border: 2px solid #333; display: flex; flex-direction: column;
|
| 60 |
align-items: center; justify-content: center; cursor: pointer;
|
| 61 |
+
overflow: hidden; transition: all 0.5s;
|
| 62 |
}
|
| 63 |
|
| 64 |
.type-ai { border-color: var(--border-ai); }
|
|
|
|
| 65 |
|
| 66 |
.block.active {
|
| 67 |
position: fixed; top: 0; left: 0; width: 100vw !important;
|
|
|
|
| 87 |
position: absolute; bottom: 8px; right: 8px; width: 28px; height: 28px;
|
| 88 |
background: #00ff00; border-radius: 50%; color: #000; border: none; font-weight: bold;
|
| 89 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 90 |
</style>
|
| 91 |
</head>
|
| 92 |
<body>
|
| 93 |
|
| 94 |
<div id="sidebar">
|
| 95 |
<div class="auth-section">
|
| 96 |
+
<div class="d-flex justify-content-between align-items-center">
|
| 97 |
+
<span class="small text-muted">HF AUTH STATUS</span>
|
| 98 |
+
<span id="tokenStatus" class="token-badge">AUTO-LOADED</span>
|
| 99 |
+
</div>
|
| 100 |
+
<div id="login-section" class="mt-2">
|
| 101 |
+
<button class="btn btn-outline-primary btn-sm w-100" onclick="handleLogin('Cloud')">
|
| 102 |
+
<i class="bi bi-cloud-arrow-up"></i> Sync VPS Profile
|
| 103 |
+
</button>
|
| 104 |
</div>
|
| 105 |
+
<div id="user-profile" style="display:none" class="mt-2 text-success small fw-bold">
|
| 106 |
+
<i class="bi bi-check-circle-fill"></i> Connected to Flux Node
|
|
|
|
|
|
|
| 107 |
</div>
|
| 108 |
</div>
|
| 109 |
|
| 110 |
<div class="p-3">
|
| 111 |
<div class="mb-4">
|
| 112 |
+
<label class="form-label small">GRID NODES</label>
|
| 113 |
<input type="range" class="form-range" id="blockSlider" min="1" max="25" value="4" oninput="updateGrid()">
|
| 114 |
<div class="d-flex justify-content-between small text-muted">
|
| 115 |
+
<span id="countVal">4</span> Instances
|
| 116 |
<span id="saveStatus">Synced</span>
|
| 117 |
</div>
|
| 118 |
</div>
|
| 119 |
|
| 120 |
<div class="mb-4">
|
| 121 |
+
<label class="form-label small">HF ACCESS TOKEN</label>
|
| 122 |
<input type="password" class="form-control form-control-sm bg-dark text-white border-secondary" id="hfToken" placeholder="hf_..." onchange="saveToCache()">
|
| 123 |
+
<div class="form-text text-muted" style="font-size: 9px;">Leave empty if using URL ?token=...</div>
|
| 124 |
</div>
|
| 125 |
|
| 126 |
+
<button class="btn btn-success btn-sm w-100 mb-2" onclick="saveToCache()">PERSIST CONFIG</button>
|
| 127 |
+
<button class="btn btn-outline-danger btn-sm w-100" onclick="clearGrid()">PURGE CACHE</button>
|
| 128 |
</div>
|
| 129 |
</div>
|
| 130 |
|
|
|
|
| 132 |
|
| 133 |
<div id="grid-container"></div>
|
| 134 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 135 |
<script>
|
| 136 |
const container = document.getElementById("grid-container");
|
| 137 |
const countDisplay = document.getElementById("countVal");
|
| 138 |
let blocks = [];
|
| 139 |
let currentUser = null;
|
| 140 |
|
| 141 |
+
/**
|
| 142 |
+
* AUTO-TOKEN DETECTION LOGIC
|
| 143 |
+
* 1. Check URL parameters (?token=hf_...)
|
| 144 |
+
* 2. Check localStorage
|
| 145 |
+
* 3. (Optional) Define a hardcoded fallback for private VPS use
|
| 146 |
+
*/
|
| 147 |
+
function detectToken() {
|
| 148 |
+
const urlParams = new URLSearchParams(window.location.search);
|
| 149 |
+
const urlToken = urlParams.get('token');
|
| 150 |
+
const hfInput = document.getElementById("hfToken");
|
| 151 |
+
|
| 152 |
+
if (urlToken) {
|
| 153 |
+
hfInput.value = urlToken;
|
| 154 |
+
document.getElementById("tokenStatus").style.display = "inline";
|
| 155 |
+
console.log("Token auto-loaded from URL.");
|
| 156 |
+
// Clean URL to prevent token leaking in screenshots
|
| 157 |
+
window.history.replaceState({}, document.title, window.location.pathname);
|
| 158 |
+
} else {
|
| 159 |
+
const cache = localStorage.getItem("wavetype_vps_cache");
|
| 160 |
+
if (cache) {
|
| 161 |
+
const data = JSON.parse(cache);
|
| 162 |
+
if (data.token) {
|
| 163 |
+
hfInput.value = data.token;
|
| 164 |
+
document.getElementById("tokenStatus").style.display = "inline";
|
| 165 |
+
}
|
| 166 |
+
}
|
| 167 |
+
}
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
function saveToCache() {
|
| 171 |
const data = {
|
| 172 |
blocks,
|
|
|
|
| 174 |
user: currentUser
|
| 175 |
};
|
| 176 |
localStorage.setItem("wavetype_vps_cache", JSON.stringify(data));
|
| 177 |
+
showStatus("Saved");
|
| 178 |
+
if(data.token) document.getElementById("tokenStatus").style.display = "inline";
|
| 179 |
}
|
| 180 |
|
| 181 |
function loadFromCache() {
|
|
|
|
| 183 |
if (cache) {
|
| 184 |
const data = JSON.parse(cache);
|
| 185 |
blocks = data.blocks || [];
|
| 186 |
+
document.getElementById("blockSlider").value = blocks.length || 4;
|
| 187 |
+
if (data.user) handleLogin('Cloud');
|
| 188 |
renderGrid();
|
| 189 |
} else {
|
| 190 |
updateGrid();
|
| 191 |
}
|
| 192 |
+
detectToken();
|
| 193 |
}
|
| 194 |
|
|
|
|
| 195 |
function updateGrid() {
|
| 196 |
const count = parseInt(document.getElementById("blockSlider").value);
|
| 197 |
countDisplay.innerText = count;
|
|
|
|
| 200 |
}
|
| 201 |
while (blocks.length > count) blocks.pop();
|
| 202 |
renderGrid();
|
| 203 |
+
saveToCache();
|
| 204 |
}
|
| 205 |
|
| 206 |
function renderGrid() {
|
|
|
|
| 215 |
|
| 216 |
el.innerHTML = `
|
| 217 |
<div class="ai-interface">
|
| 218 |
+
<h4 style="color:var(--border-ai)">FLUX.1 [KLEIN-9B]</h4>
|
| 219 |
+
<textarea class="form-control bg-dark text-white border-secondary mb-2" id="prompt-${i}" rows="3" placeholder="Enter prompt...">${b.prompt || ""}</textarea>
|
| 220 |
+
<button class="btn btn-primary w-100" onclick="generateFlux(${i}, this)">EXECUTE VPS INFERENCE</button>
|
| 221 |
+
<div id="loader-${i}" class="text-center mt-2" style="display:none"><div class="spinner-grow spinner-grow-sm text-info"></div> GEN IN PROGRESS...</div>
|
| 222 |
<img id="img-${i}" class="gen-image-preview mt-3">
|
| 223 |
</div>
|
| 224 |
+
<div class="small fw-bold opacity-50">NODE_0${i+1}</div>
|
| 225 |
+
<button class="close-btn" onclick="event.stopPropagation(); this.parentElement.classList.remove('active')">DISCONNECT</button>
|
| 226 |
+
<button class="add-block-btn" onclick="event.stopPropagation(); updateGrid()">+</button>
|
|
|
|
| 227 |
`;
|
| 228 |
container.appendChild(el);
|
| 229 |
});
|
| 230 |
}
|
| 231 |
|
|
|
|
| 232 |
async function generateFlux(index, btn) {
|
| 233 |
event.stopPropagation();
|
| 234 |
const prompt = document.getElementById(`prompt-${index}`).value;
|
|
|
|
| 236 |
const imgEl = document.getElementById(`img-${index}`);
|
| 237 |
const loader = document.getElementById(`loader-${index}`);
|
| 238 |
|
| 239 |
+
if (!token) {
|
| 240 |
+
alert("Auth Error: HuggingFace Token Missing.");
|
| 241 |
+
return;
|
| 242 |
+
}
|
| 243 |
|
| 244 |
loader.style.display = "block";
|
| 245 |
imgEl.style.display = "none";
|
|
|
|
| 257 |
);
|
| 258 |
|
| 259 |
const blob = await response.blob();
|
| 260 |
+
imgEl.src = URL.createObjectURL(blob);
|
|
|
|
| 261 |
imgEl.style.display = "block";
|
| 262 |
} catch (err) {
|
| 263 |
+
console.error(err);
|
| 264 |
} finally {
|
| 265 |
loader.style.display = "none";
|
| 266 |
}
|
| 267 |
}
|
| 268 |
|
| 269 |
+
function handleLogin(type) {
|
| 270 |
+
currentUser = { name: "VPS_ADMIN" };
|
|
|
|
| 271 |
document.getElementById("login-section").style.display = "none";
|
| 272 |
document.getElementById("user-profile").style.display = "block";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 273 |
}
|
| 274 |
|
| 275 |
function showStatus(msg) {
|
| 276 |
+
document.getElementById("saveStatus").innerText = msg;
|
| 277 |
+
setTimeout(() => document.getElementById("saveStatus").innerText = "Synced", 2000);
|
|
|
|
| 278 |
}
|
| 279 |
|
| 280 |
function toggleSidebar() { document.getElementById("sidebar").classList.toggle("collapsed"); }
|
| 281 |
+
function clearGrid() { localStorage.clear(); location.reload(); }
|
|
|
|
|
|
|
|
|
|
| 282 |
|
| 283 |
window.onload = loadFromCache;
|
| 284 |
</script>
|