Spaces:
Running
Running
Update index.html
Browse files- index.html +49 -16
index.html
CHANGED
|
@@ -3,25 +3,42 @@
|
|
| 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>
|
| 10 |
:root { --border-ai: #ff00ff; --accent: #00ff00; --bg: #000; }
|
| 11 |
body, html { margin: 0; padding: 0; width: 100%; height: 100vh; overflow: hidden; background: var(--bg); color: white; font-family: monospace; }
|
|
|
|
| 12 |
#sidebar { position: fixed; left: 0; top: 0; width: 320px; height: 100vh; background: #111; border-right: 1px solid #333; z-index: 2000; transition: transform 0.3s; }
|
| 13 |
#sidebar.collapsed { transform: translateX(-320px); }
|
|
|
|
| 14 |
#sidebar-toggle { position: fixed; left: 320px; top: 20px; z-index: 2001; cursor: pointer; background: #111; color: var(--accent); border: 1px solid #333; border-left: none; padding: 5px; transition: left 0.3s; }
|
| 15 |
#sidebar.collapsed ~ #sidebar-toggle { left: 0; }
|
|
|
|
| 16 |
#grid-container { display: grid; width: 100vw; height: 100vh; gap: 4px; padding: 4px 4px 4px 324px; transition: padding 0.3s; }
|
| 17 |
#sidebar.collapsed ~ #grid-container { padding-left: 4px; }
|
| 18 |
-
|
|
|
|
| 19 |
.block.active { position: fixed; top: 0; left: 0; width: 100vw!important; height: 100vh!important; z-index: 2500; background: #000; padding: 40px; cursor: default; }
|
| 20 |
-
|
|
|
|
| 21 |
.block.active .ai-ui { display: flex; }
|
| 22 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 23 |
.block.active .close-btn { display: block; }
|
|
|
|
| 24 |
.preview-img { width: 100%; max-height: 60vh; object-fit: contain; margin-top: 15px; border: 1px solid var(--border-ai); display: none; }
|
|
|
|
|
|
|
| 25 |
</style>
|
| 26 |
</head>
|
| 27 |
<body>
|
|
@@ -31,10 +48,10 @@
|
|
| 31 |
HF_AUTH: <span id="authStatus" class="text-danger">MISSING</span>
|
| 32 |
</div>
|
| 33 |
<div class="p-3">
|
| 34 |
-
<label class="small text-muted">DENSITY</label>
|
| 35 |
<input type="range" class="form-range" id="density" min="1" max="16" value="4" oninput="initGrid()">
|
| 36 |
<div class="mt-3">
|
| 37 |
-
<label class="small text-muted">TOKEN</label>
|
| 38 |
<input type="password" class="form-control form-control-sm bg-dark text-white border-secondary" id="tokenField" placeholder="hf_...">
|
| 39 |
</div>
|
| 40 |
<button class="btn btn-info btn-sm w-100 mt-4" onclick="save()">SAVE TO CACHE</button>
|
|
@@ -53,10 +70,9 @@
|
|
| 53 |
const urlKey = params.get('token');
|
| 54 |
const hfInp = document.getElementById('tokenField');
|
| 55 |
|
| 56 |
-
// Auto-detect token from URL or Cache
|
| 57 |
if (urlKey) {
|
| 58 |
hfInp.value = urlKey;
|
| 59 |
-
window.history.replaceState({}, '', window.location.pathname);
|
| 60 |
save();
|
| 61 |
} else {
|
| 62 |
const cache = JSON.parse(localStorage.getItem('flux_cfg') || '{}');
|
|
@@ -79,17 +95,21 @@
|
|
| 79 |
const cols = Math.ceil(Math.sqrt(count));
|
| 80 |
container.style.gridTemplateColumns = `repeat(${cols}, 1fr)`;
|
| 81 |
container.innerHTML = '';
|
| 82 |
-
nodes = Array.from({length: count}, (_, i) => ({ id: i
|
| 83 |
|
| 84 |
nodes.forEach(n => {
|
| 85 |
const div = document.createElement('div');
|
| 86 |
div.className = 'block';
|
| 87 |
-
div.onclick = () => div.classList.add('active');
|
| 88 |
div.innerHTML = `
|
| 89 |
<div class="ai-ui">
|
|
|
|
|
|
|
|
|
|
|
|
|
| 90 |
<h4 class="text-info">NODE_${n.id + 1}</h4>
|
| 91 |
-
<textarea class="form-control bg-dark text-white" id="p-${n.id}" placeholder="
|
| 92 |
-
<button class="btn btn-info mt-2" onclick="gen(${n.id}, this)">GENERATE</button>
|
| 93 |
<img id="img-${n.id}" class="preview-img">
|
| 94 |
</div>
|
| 95 |
<div class="small text-muted">FLUX_NODE_${n.id + 1}</div>
|
|
@@ -104,20 +124,33 @@
|
|
| 104 |
const token = document.getElementById('tokenField').value;
|
| 105 |
const prompt = document.getElementById(`p-${id}`).value;
|
| 106 |
const img = document.getElementById(`img-${id}`);
|
| 107 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 108 |
|
| 109 |
-
btn.disabled = true; btn.innerText = "RUNNING...";
|
| 110 |
try {
|
| 111 |
const res = await fetch("https://api-inference.huggingface.co/models/Comfy-Org/flux2-klein-9B", {
|
| 112 |
headers: { Authorization: `Bearer ${token}` },
|
| 113 |
method: "POST",
|
| 114 |
body: JSON.stringify({ inputs: prompt })
|
| 115 |
});
|
|
|
|
|
|
|
|
|
|
| 116 |
const blob = await res.blob();
|
| 117 |
img.src = URL.createObjectURL(blob);
|
| 118 |
img.style.display = 'block';
|
| 119 |
-
} catch (e) {
|
| 120 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 121 |
}
|
| 122 |
|
| 123 |
function save() {
|
|
|
|
| 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</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 { --border-ai: #ff00ff; --accent: #00ff00; --bg: #000; }
|
| 11 |
body, html { margin: 0; padding: 0; width: 100%; height: 100vh; overflow: hidden; background: var(--bg); color: white; font-family: monospace; }
|
| 12 |
+
|
| 13 |
#sidebar { position: fixed; left: 0; top: 0; width: 320px; height: 100vh; background: #111; border-right: 1px solid #333; z-index: 2000; transition: transform 0.3s; }
|
| 14 |
#sidebar.collapsed { transform: translateX(-320px); }
|
| 15 |
+
|
| 16 |
#sidebar-toggle { position: fixed; left: 320px; top: 20px; z-index: 2001; cursor: pointer; background: #111; color: var(--accent); border: 1px solid #333; border-left: none; padding: 5px; transition: left 0.3s; }
|
| 17 |
#sidebar.collapsed ~ #sidebar-toggle { left: 0; }
|
| 18 |
+
|
| 19 |
#grid-container { display: grid; width: 100vw; height: 100vh; gap: 4px; padding: 4px 4px 4px 324px; transition: padding 0.3s; }
|
| 20 |
#sidebar.collapsed ~ #grid-container { padding-left: 4px; }
|
| 21 |
+
|
| 22 |
+
.block { border: 2px solid #222; background: rgba(255,255,255,0.05); display: flex; align-items: center; justify-content: center; position: relative; cursor: pointer; transition: 0.3s; }
|
| 23 |
.block.active { position: fixed; top: 0; left: 0; width: 100vw!important; height: 100vh!important; z-index: 2500; background: #000; padding: 40px; cursor: default; }
|
| 24 |
+
|
| 25 |
+
.ai-ui { display: none; width: 100%; max-width: 800px; flex-direction: column; gap: 15px; position: relative; }
|
| 26 |
.block.active .ai-ui { display: flex; }
|
| 27 |
+
|
| 28 |
+
/* Loading Visuals */
|
| 29 |
+
.loader-overlay {
|
| 30 |
+
display: none; position: absolute; top: 0; left: 0; width: 100%; height: 100%;
|
| 31 |
+
background: rgba(0,0,0,0.8); z-index: 10; flex-direction: column; align-items: center; justify-content: center;
|
| 32 |
+
border: 2px solid var(--border-ai); border-radius: 8px; animation: pulse 1.5s infinite;
|
| 33 |
+
}
|
| 34 |
+
@keyframes pulse { 0% { opacity: 0.6; } 50% { opacity: 1; } 100% { opacity: 0.6; } }
|
| 35 |
+
|
| 36 |
+
.close-btn { display: none; position: absolute; top: 20px; right: 20px; background: #ff0055; color: #fff; border: none; padding: 5px 15px; z-index: 2600; }
|
| 37 |
.block.active .close-btn { display: block; }
|
| 38 |
+
|
| 39 |
.preview-img { width: 100%; max-height: 60vh; object-fit: contain; margin-top: 15px; border: 1px solid var(--border-ai); display: none; }
|
| 40 |
+
|
| 41 |
+
input, textarea { border-radius: 0!important; }
|
| 42 |
</style>
|
| 43 |
</head>
|
| 44 |
<body>
|
|
|
|
| 48 |
HF_AUTH: <span id="authStatus" class="text-danger">MISSING</span>
|
| 49 |
</div>
|
| 50 |
<div class="p-3">
|
| 51 |
+
<label class="small text-muted">GRID DENSITY</label>
|
| 52 |
<input type="range" class="form-range" id="density" min="1" max="16" value="4" oninput="initGrid()">
|
| 53 |
<div class="mt-3">
|
| 54 |
+
<label class="small text-muted">API TOKEN</label>
|
| 55 |
<input type="password" class="form-control form-control-sm bg-dark text-white border-secondary" id="tokenField" placeholder="hf_...">
|
| 56 |
</div>
|
| 57 |
<button class="btn btn-info btn-sm w-100 mt-4" onclick="save()">SAVE TO CACHE</button>
|
|
|
|
| 70 |
const urlKey = params.get('token');
|
| 71 |
const hfInp = document.getElementById('tokenField');
|
| 72 |
|
|
|
|
| 73 |
if (urlKey) {
|
| 74 |
hfInp.value = urlKey;
|
| 75 |
+
window.history.replaceState({}, '', window.location.pathname);
|
| 76 |
save();
|
| 77 |
} else {
|
| 78 |
const cache = JSON.parse(localStorage.getItem('flux_cfg') || '{}');
|
|
|
|
| 95 |
const cols = Math.ceil(Math.sqrt(count));
|
| 96 |
container.style.gridTemplateColumns = `repeat(${cols}, 1fr)`;
|
| 97 |
container.innerHTML = '';
|
| 98 |
+
nodes = Array.from({length: count}, (_, i) => ({ id: i }));
|
| 99 |
|
| 100 |
nodes.forEach(n => {
|
| 101 |
const div = document.createElement('div');
|
| 102 |
div.className = 'block';
|
| 103 |
+
div.onclick = () => { if(!div.classList.contains('active')) div.classList.add('active'); };
|
| 104 |
div.innerHTML = `
|
| 105 |
<div class="ai-ui">
|
| 106 |
+
<div id="loader-${n.id}" class="loader-overlay">
|
| 107 |
+
<div class="spinner-border text-info mb-2"></div>
|
| 108 |
+
<div class="small">VPS INFERENCE IN PROGRESS...</div>
|
| 109 |
+
</div>
|
| 110 |
<h4 class="text-info">NODE_${n.id + 1}</h4>
|
| 111 |
+
<textarea class="form-control bg-dark text-white border-secondary" id="p-${n.id}" rows="4" placeholder="Describe the image..."></textarea>
|
| 112 |
+
<button class="btn btn-info mt-2" onclick="gen(${n.id}, this)">GENERATE ON FLUX</button>
|
| 113 |
<img id="img-${n.id}" class="preview-img">
|
| 114 |
</div>
|
| 115 |
<div class="small text-muted">FLUX_NODE_${n.id + 1}</div>
|
|
|
|
| 124 |
const token = document.getElementById('tokenField').value;
|
| 125 |
const prompt = document.getElementById(`p-${id}`).value;
|
| 126 |
const img = document.getElementById(`img-${id}`);
|
| 127 |
+
const loader = document.getElementById(`loader-${id}`);
|
| 128 |
+
|
| 129 |
+
if (!token || !prompt) return alert("Please enter a token in sidebar and a prompt in the node.");
|
| 130 |
+
|
| 131 |
+
// Show Loading state
|
| 132 |
+
loader.style.display = 'flex';
|
| 133 |
+
img.style.display = 'none';
|
| 134 |
+
btn.disabled = true;
|
| 135 |
|
|
|
|
| 136 |
try {
|
| 137 |
const res = await fetch("https://api-inference.huggingface.co/models/Comfy-Org/flux2-klein-9B", {
|
| 138 |
headers: { Authorization: `Bearer ${token}` },
|
| 139 |
method: "POST",
|
| 140 |
body: JSON.stringify({ inputs: prompt })
|
| 141 |
});
|
| 142 |
+
|
| 143 |
+
if (!res.ok) throw new Error("API Limit or Token Error");
|
| 144 |
+
|
| 145 |
const blob = await res.blob();
|
| 146 |
img.src = URL.createObjectURL(blob);
|
| 147 |
img.style.display = 'block';
|
| 148 |
+
} catch (e) {
|
| 149 |
+
alert("Error: " + e.message);
|
| 150 |
+
} finally {
|
| 151 |
+
loader.style.display = 'none';
|
| 152 |
+
btn.disabled = false;
|
| 153 |
+
}
|
| 154 |
}
|
| 155 |
|
| 156 |
function save() {
|