Wavetype commited on
Commit
085cc32
·
verified ·
1 Parent(s): e7045db

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +275 -18
index.html CHANGED
@@ -1,19 +1,276 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Wavetype Frequency Grid - Flux.1 Klein 9B</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>
10
+ :root {
11
+ --border-ai: #ff00ff;
12
+ --bg-shade: 0.15;
13
+ --accent: #00ff00;
14
+ }
15
+
16
+ body, html {
17
+ margin: 0; padding: 0; width: 100%; height: 100vh;
18
+ overflow: hidden; background-color: #000;
19
+ font-family: "Courier New", Courier, monospace; color: white;
20
+ }
21
+
22
+ #sidebar {
23
+ position: fixed; left: 0; top: 0; width: 320px; height: 100vh;
24
+ background: linear-gradient(180deg, #111 0%, #000 100%);
25
+ border-right: 2px solid #333; z-index: 2000;
26
+ transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
27
+ }
28
+
29
+ #sidebar.collapsed { transform: translateX(-320px); }
30
+
31
+ #sidebar-toggle {
32
+ position: fixed; left: 320px; top: 20px; width: 30px; height: 40px;
33
+ background: #111; border: 1px solid #333; border-left: none;
34
+ cursor: pointer; z-index: 2001; display: flex; align-items: center;
35
+ justify-content: center; color: var(--accent); transition: left 0.3s;
36
+ }
37
+
38
+ #sidebar.collapsed ~ #sidebar-toggle { left: 0; }
39
+
40
+ .auth-status {
41
+ padding: 15px; background: #1a1a1a; border-bottom: 1px solid #333;
42
+ font-size: 11px; letter-spacing: 1px;
43
+ }
44
+
45
+ #grid-container {
46
+ display: grid; width: 100vw; height: 100vh; gap: 4px; padding: 4px;
47
+ padding-left: 324px; transition: padding-left 0.3s;
48
+ }
49
+
50
+ #sidebar.collapsed ~ #grid-container { padding-left: 4px; }
51
+
52
+ .block {
53
+ position: relative; background-color: rgba(255, 255, 255, var(--bg-shade));
54
+ border: 2px solid #222; display: flex; flex-direction: column;
55
+ align-items: center; justify-content: center; cursor: pointer;
56
+ overflow: hidden; transition: border-color 0.3s;
57
+ }
58
+
59
+ .block.active {
60
+ position: fixed; top: 0; left: 0; width: 100vw !important;
61
+ height: 100vh !important; z-index: 2500; background: #000; padding: 40px;
62
+ }
63
+
64
+ .close-btn {
65
+ display: none; position: absolute; top: 20px; right: 20px;
66
+ background: #ff0055; color: white; border: none; padding: 8px 16px;
67
+ }
68
+ .block.active .close-btn { display: block; }
69
+
70
+ .ai-interface { display: none; width: 100%; max-width: 900px; flex-direction: column; gap: 20px; }
71
+ .block.active .ai-interface { display: flex; }
72
+
73
+ .gen-image-preview {
74
+ width: 100%; max-height: 60vh; object-fit: contain;
75
+ border: 1px solid var(--border-ai); display: none; background: #050505;
76
+ }
77
+
78
+ .loading-bar {
79
+ height: 2px; width: 0%; background: var(--border-ai);
80
+ position: absolute; bottom: 0; left: 0; transition: width 0.3s;
81
+ }
82
+ </style>
83
+ </head>
84
+ <body>
85
+
86
+ <div id="sidebar">
87
+ <div class="auth-status">
88
+ <div class="d-flex align-items-center justify-content-between">
89
+ <span>HF_AUTH: <span id="tokenLabel" class="text-danger">MISSING</span></span>
90
+ <i id="lockIcon" class="bi bi-shield-slash text-danger"></i>
91
+ </div>
92
+ </div>
93
+
94
+ <div class="p-3">
95
+ <div class="mb-4">
96
+ <label class="form-label small text-muted">GRID DENSITY</label>
97
+ <input type="range" class="form-range" id="blockSlider" min="1" max="16" value="4" oninput="updateGrid()">
98
+ <div class="d-flex justify-content-between small">
99
+ <span id="countVal">4</span> Instances
100
+ <span id="saveStatus" class="text-info">Ready</span>
101
+ </div>
102
+ </div>
103
+
104
+ <div class="mb-4">
105
+ <label class="form-label small text-muted">SESSION TOKEN</label>
106
+ <input type="password" class="form-control form-control-sm bg-dark text-white border-secondary" id="hfToken" placeholder="hf_...">
107
+ <div class="form-text" style="font-size: 8px; color: #555;">Token is saved to your browser cache only.</div>
108
+ </div>
109
+
110
+ <button class="btn btn-sm btn-outline-info w-100 mb-2" onclick="batchGenerate()">BATCH EXECUTE ALL</button>
111
+ <button class="btn btn-sm btn-outline-secondary w-100" onclick="saveToCache()">SAVE CONFIG</button>
112
+ <button class="btn btn-sm btn-outline-danger w-100 mt-2" onclick="clearAll()">LOGOUT / CLEAR</button>
113
+ </div>
114
+ </div>
115
+
116
+ <button id="sidebar-toggle" onclick="toggleSidebar()"><i class="bi bi-chevron-left"></i></button>
117
+
118
+ <div id="grid-container"></div>
119
+
120
+ <script>
121
+ const container = document.getElementById("grid-container");
122
+ const countDisplay = document.getElementById("countVal");
123
+ let blocks = [];
124
+
125
+ // --- Token Auto-Injection Logic ---
126
+ function handleAutoAuth() {
127
+ const hfInput = document.getElementById("hfToken");
128
+ const urlParams = new URLSearchParams(window.location.search);
129
+ const urlToken = urlParams.get('token');
130
+
131
+ if (urlToken) {
132
+ hfInput.value = urlToken;
133
+ saveToCache();
134
+ // Clean URL so token isn't in history
135
+ window.history.replaceState({}, document.title, window.location.pathname);
136
+ updateAuthUI(true);
137
+ } else {
138
+ const cache = localStorage.getItem("flux_grid_config");
139
+ if (cache) {
140
+ const data = JSON.parse(cache);
141
+ if (data.token) {
142
+ hfInput.value = data.token;
143
+ updateAuthUI(true);
144
+ }
145
+ }
146
+ }
147
+ }
148
+
149
+ function updateAuthUI(active) {
150
+ const label = document.getElementById("tokenLabel");
151
+ const icon = document.getElementById("lockIcon");
152
+ if (active) {
153
+ label.innerText = "ACTIVE";
154
+ label.className = "text-success";
155
+ icon.className = "bi bi-shield-lock-fill text-success";
156
+ }
157
+ }
158
+
159
+ function saveToCache() {
160
+ const data = {
161
+ blocks,
162
+ count: document.getElementById("blockSlider").value,
163
+ token: document.getElementById("hfToken").value
164
+ };
165
+ localStorage.setItem("flux_grid_config", JSON.stringify(data));
166
+ showStatus("Synced");
167
+ }
168
+
169
+ function loadFromCache() {
170
+ const cache = localStorage.getItem("flux_grid_config");
171
+ if (cache) {
172
+ const data = JSON.parse(cache);
173
+ blocks = data.blocks || [];
174
+ document.getElementById("blockSlider").value = data.count || 4;
175
+ renderGrid();
176
+ } else {
177
+ updateGrid();
178
+ }
179
+ handleAutoAuth();
180
+ }
181
+
182
+ function updateGrid() {
183
+ const count = parseInt(document.getElementById("blockSlider").value);
184
+ countDisplay.innerText = count;
185
+ while (blocks.length < count) {
186
+ blocks.push({ id: Date.now() + Math.random(), prompt: "", lastImg: null });
187
+ }
188
+ while (blocks.length > count) blocks.pop();
189
+ renderGrid();
190
+ saveToCache();
191
+ }
192
+
193
+ function renderGrid() {
194
+ const cols = Math.ceil(Math.sqrt(blocks.length)) || 1;
195
+ container.style.gridTemplateColumns = `repeat(${cols}, 1fr)`;
196
+ container.innerHTML = "";
197
+
198
+ blocks.forEach((b, i) => {
199
+ const el = document.createElement("div");
200
+ el.className = `block`;
201
+ el.onclick = () => { if(!el.classList.contains('active')) el.classList.add('active'); };
202
+
203
+ el.innerHTML = `
204
+ <div class="ai-interface">
205
+ <h3 class="text-info">INSTANCE_0${i+1}</h3>
206
+ <textarea class="form-control bg-dark text-white border-secondary mb-2" id="prompt-${i}" rows="4" placeholder="Enter prompt...">${b.prompt || ""}</textarea>
207
+ <button class="btn btn-info" onclick="generateFlux(${i}, this)">RUN INFERENCE</button>
208
+ <div id="loader-${i}" class="text-center mt-2" style="display:none">
209
+ <div class="spinner-border spinner-border-sm text-info"></div> PROCESSING...
210
+ </div>
211
+ <img id="img-${i}" class="gen-image-preview mt-3" src="${b.lastImg || ''}" style="${b.lastImg ? 'display:block' : ''}">
212
+ </div>
213
+ <div class="text-muted small fw-bold">FLUX_NODE_${i+1}</div>
214
+ <div class="loading-bar" id="bar-${i}"></div>
215
+ <button class="close-btn" onclick="event.stopPropagation(); this.parentElement.classList.remove('active')">EXIT</button>
216
+ `;
217
+ container.appendChild(el);
218
+ });
219
+ }
220
+
221
+ async function generateFlux(index, btn) {
222
+ if(btn) event.stopPropagation();
223
+ const prompt = document.getElementById(`prompt-${index}`).value;
224
+ const token = document.getElementById("hfToken").value;
225
+ const imgEl = document.getElementById(`img-${index}`);
226
+ const loader = document.getElementById(`loader-${index}`);
227
+ const bar = document.getElementById(`bar-${index}`);
228
+
229
+ if (!prompt || !token) return;
230
+
231
+ loader.style.display = "block";
232
+ bar.style.width = "50%";
233
+ blocks[index].prompt = prompt;
234
+
235
+ try {
236
+ const response = await fetch(
237
+ "https://api-inference.huggingface.co/models/Comfy-Org/flux2-klein-9B",
238
+ {
239
+ headers: { Authorization: `Bearer ${token}` },
240
+ method: "POST",
241
+ body: JSON.stringify({ inputs: prompt }),
242
+ }
243
+ );
244
+
245
+ const blob = await response.blob();
246
+ const objectURL = URL.createObjectURL(blob);
247
+ imgEl.src = objectURL;
248
+ imgEl.style.display = "block";
249
+ blocks[index].lastImg = objectURL;
250
+ bar.style.width = "100%";
251
+ setTimeout(() => bar.style.width = "0%", 1000);
252
+ saveToCache();
253
+ } catch (err) {
254
+ console.error(err);
255
+ } finally {
256
+ loader.style.display = "none";
257
+ }
258
+ }
259
+
260
+ async function batchGenerate() {
261
+ const promises = blocks.map((_, i) => generateFlux(i, null));
262
+ await Promise.all(promises);
263
+ }
264
+
265
+ function toggleSidebar() { document.getElementById("sidebar").classList.toggle("collapsed"); }
266
+ function showStatus(msg) {
267
+ const s = document.getElementById("saveStatus");
268
+ s.innerText = msg;
269
+ setTimeout(() => s.innerText = "Synced", 2000);
270
+ }
271
+ function clearAll() { localStorage.clear(); location.reload(); }
272
+
273
+ window.onload = loadFromCache;
274
+ </script>
275
+ </body>
276
  </html>