Yang2001 commited on
Commit
b8c0b13
·
1 Parent(s): 889199c

fix: use js_on_load for queue polling, direct CORS fetch to gradio share links

Browse files
Files changed (2) hide show
  1. app.py +91 -4
  2. app_proxy.py +91 -4
app.py CHANGED
@@ -167,6 +167,37 @@ PROXY_HTML = """
167
  margin-bottom: 16px;
168
  color: #f1f5f9;
169
  }}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  .instance-card .url-hint {{
171
  font-size: 13px;
172
  color: #64748b;
@@ -235,29 +266,82 @@ def build_page():
235
  <div class="instance-card">
236
  <h3>🖥️ {inst['name']}</h3>
237
  <p style="color:#94a3b8; font-size:14px; margin-bottom:8px;">⚡ Shared GPU — requests are queued</p>
 
 
 
 
238
  <a href="{inst['url']}" target="_blank" rel="noopener noreferrer" class="btn-go">
239
- Open Instance {i+1}
240
  </a>
241
  <p class="url-hint"><code>{inst['url']}</code></p>
242
  </div>
243
  """
244
 
 
 
 
245
  content = f"""
246
  <div class="cards-container">
247
  <div style="width:100%; text-align:center; margin-bottom:16px;">
248
  <h2 style="font-size:28px; margin-bottom:12px;">🚀 Choose a Pixal3D Instance</h2>
249
  <p style="color:#fbbf24; font-size:15px; margin-bottom:8px;">⚠️ Due to a temporary HuggingFace error, this Space is currently unavailable. Please use one of the instances below.</p>
250
- <p style="color:#10b981; font-size:14px; margin-top:10px; font-weight:600;">💡 After entering, check the top-left corner for the current queue count.</p>
251
  </div>
252
  <div class="cards-grid">
253
  {cards_html}
254
  </div>
255
  </div>
256
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
  else:
258
  status_color = "#ef4444"
259
  status_anim = "pulse 1.5s infinite"
260
  status_text = "Remote instance not configured"
 
261
  content = """
262
  <div class="no-url">
263
  <div class="no-url-card">
@@ -271,22 +355,25 @@ def build_page():
271
  </div>
272
  """
273
 
274
- return PROXY_HTML.format(
275
  status_color=status_color,
276
  status_anim=status_anim,
277
  status_text=status_text,
278
  gpu_name=GPU_NAME,
279
  content=content,
280
  )
 
281
 
282
 
283
  # Use a simple Gradio Blocks app with HTML component
 
 
284
  with gr.Blocks(
285
  title="Pixal3D | AI Image-to-3D",
286
  css="footer {display:none !important;} .gradio-container {padding:0 !important; max-width:100% !important; height:100vh !important; overflow:hidden !important;} #proxy-frame {height:100%; max-height:100vh; padding:0; overflow:hidden;}",
287
  theme=gr.themes.Base(),
288
  ) as demo:
289
- gr.HTML(build_page(), elem_id="proxy-frame")
290
 
291
  if __name__ == "__main__":
292
  demo.launch(share=True)
 
167
  margin-bottom: 16px;
168
  color: #f1f5f9;
169
  }}
170
+ .queue-status {{
171
+ display: inline-flex;
172
+ align-items: center;
173
+ gap: 8px;
174
+ padding: 8px 16px;
175
+ border-radius: 20px;
176
+ font-size: 15px;
177
+ font-weight: 600;
178
+ margin-bottom: 8px;
179
+ background: rgba(148, 163, 184, 0.1);
180
+ color: #94a3b8;
181
+ }}
182
+ .queue-status.idle {{
183
+ background: rgba(16, 185, 129, 0.15);
184
+ color: #10b981;
185
+ }}
186
+ .queue-status.busy {{
187
+ background: rgba(251, 146, 60, 0.15);
188
+ color: #fb923c;
189
+ }}
190
+ .queue-status.offline {{
191
+ background: rgba(239, 68, 68, 0.15);
192
+ color: #ef4444;
193
+ }}
194
+ .queue-dot {{
195
+ width: 8px;
196
+ height: 8px;
197
+ border-radius: 50%;
198
+ background: currentColor;
199
+ animation: pulse 2s infinite;
200
+ }}
201
  .instance-card .url-hint {{
202
  font-size: 13px;
203
  color: #64748b;
 
266
  <div class="instance-card">
267
  <h3>🖥️ {inst['name']}</h3>
268
  <p style="color:#94a3b8; font-size:14px; margin-bottom:8px;">⚡ Shared GPU — requests are queued</p>
269
+ <div class="queue-status" id="queue-status-{i}">
270
+ <span class="queue-dot"></span>
271
+ <span id="queue-text-{i}">Checking...</span>
272
+ </div>
273
  <a href="{inst['url']}" target="_blank" rel="noopener noreferrer" class="btn-go">
274
+ Open Instance {i}
275
  </a>
276
  <p class="url-hint"><code>{inst['url']}</code></p>
277
  </div>
278
  """
279
 
280
+ # Build JS array of instance URLs for direct polling (Gradio share links support CORS natively)
281
+ urls_js = ", ".join(['"' + inst["url"].rstrip("/") + '"' for inst in REMOTE_URLS])
282
+
283
  content = f"""
284
  <div class="cards-container">
285
  <div style="width:100%; text-align:center; margin-bottom:16px;">
286
  <h2 style="font-size:28px; margin-bottom:12px;">🚀 Choose a Pixal3D Instance</h2>
287
  <p style="color:#fbbf24; font-size:15px; margin-bottom:8px;">⚠️ Due to a temporary HuggingFace error, this Space is currently unavailable. Please use one of the instances below.</p>
288
+ <p style="color:#10b981; font-size:14px; margin-top:10px; font-weight:600;">💡 Choose the instance with the shortest queue!</p>
289
  </div>
290
  <div class="cards-grid">
291
  {cards_html}
292
  </div>
293
  </div>
294
  """
295
+
296
+ poll_script = f"""
297
+ const INSTANCE_URLS = [{urls_js}];
298
+ async function pollQueues() {{
299
+ for (let i = 0; i < INSTANCE_URLS.length; i++) {{
300
+ try {{
301
+ const controller = new AbortController();
302
+ const timeout = setTimeout(() => controller.abort(), 5000);
303
+ const resp = await fetch(INSTANCE_URLS[i] + '/queue?session_id=', {{
304
+ signal: controller.signal
305
+ }});
306
+ clearTimeout(timeout);
307
+ if (resp.ok) {{
308
+ const data = await resp.json();
309
+ const total = data.total_waiting + (data.gpu_busy ? 1 : 0);
310
+ const el = document.getElementById('queue-text-' + i);
311
+ const status = document.getElementById('queue-status-' + i);
312
+ if (total === 0) {{
313
+ el.textContent = 'Idle — no queue';
314
+ status.className = 'queue-status idle';
315
+ }} else {{
316
+ el.textContent = total + ' in queue';
317
+ status.className = 'queue-status busy';
318
+ }}
319
+ }} else {{
320
+ const el = document.getElementById('queue-text-' + i);
321
+ const status = document.getElementById('queue-status-' + i);
322
+ if (el) {{
323
+ el.textContent = 'Offline';
324
+ status.className = 'queue-status offline';
325
+ }}
326
+ }}
327
+ }} catch (e) {{
328
+ const el = document.getElementById('queue-text-' + i);
329
+ const status = document.getElementById('queue-status-' + i);
330
+ if (el) {{
331
+ el.textContent = 'Offline';
332
+ status.className = 'queue-status offline';
333
+ }}
334
+ }}
335
+ }}
336
+ }}
337
+ pollQueues();
338
+ setInterval(pollQueues, 5000);
339
+ """
340
  else:
341
  status_color = "#ef4444"
342
  status_anim = "pulse 1.5s infinite"
343
  status_text = "Remote instance not configured"
344
+ poll_script = ""
345
  content = """
346
  <div class="no-url">
347
  <div class="no-url-card">
 
355
  </div>
356
  """
357
 
358
+ html = PROXY_HTML.format(
359
  status_color=status_color,
360
  status_anim=status_anim,
361
  status_text=status_text,
362
  gpu_name=GPU_NAME,
363
  content=content,
364
  )
365
+ return html, poll_script
366
 
367
 
368
  # Use a simple Gradio Blocks app with HTML component
369
+ page_html, page_script = build_page()
370
+
371
  with gr.Blocks(
372
  title="Pixal3D | AI Image-to-3D",
373
  css="footer {display:none !important;} .gradio-container {padding:0 !important; max-width:100% !important; height:100vh !important; overflow:hidden !important;} #proxy-frame {height:100%; max-height:100vh; padding:0; overflow:hidden;}",
374
  theme=gr.themes.Base(),
375
  ) as demo:
376
+ gr.HTML(page_html, elem_id="proxy-frame", js_on_load=page_script if page_script else None)
377
 
378
  if __name__ == "__main__":
379
  demo.launch(share=True)
app_proxy.py CHANGED
@@ -167,6 +167,37 @@ PROXY_HTML = """
167
  margin-bottom: 16px;
168
  color: #f1f5f9;
169
  }}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  .instance-card .url-hint {{
171
  font-size: 13px;
172
  color: #64748b;
@@ -235,29 +266,82 @@ def build_page():
235
  <div class="instance-card">
236
  <h3>🖥️ {inst['name']}</h3>
237
  <p style="color:#94a3b8; font-size:14px; margin-bottom:8px;">⚡ Shared GPU — requests are queued</p>
 
 
 
 
238
  <a href="{inst['url']}" target="_blank" rel="noopener noreferrer" class="btn-go">
239
- Open Instance {i+1}
240
  </a>
241
  <p class="url-hint"><code>{inst['url']}</code></p>
242
  </div>
243
  """
244
 
 
 
 
245
  content = f"""
246
  <div class="cards-container">
247
  <div style="width:100%; text-align:center; margin-bottom:16px;">
248
  <h2 style="font-size:28px; margin-bottom:12px;">🚀 Choose a Pixal3D Instance</h2>
249
  <p style="color:#fbbf24; font-size:15px; margin-bottom:8px;">⚠️ Due to a temporary HuggingFace error, this Space is currently unavailable. Please use one of the instances below.</p>
250
- <p style="color:#10b981; font-size:14px; margin-top:10px; font-weight:600;">💡 After entering, check the top-left corner for the current queue count.</p>
251
  </div>
252
  <div class="cards-grid">
253
  {cards_html}
254
  </div>
255
  </div>
256
  """
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
  else:
258
  status_color = "#ef4444"
259
  status_anim = "pulse 1.5s infinite"
260
  status_text = "Remote instance not configured"
 
261
  content = """
262
  <div class="no-url">
263
  <div class="no-url-card">
@@ -271,22 +355,25 @@ def build_page():
271
  </div>
272
  """
273
 
274
- return PROXY_HTML.format(
275
  status_color=status_color,
276
  status_anim=status_anim,
277
  status_text=status_text,
278
  gpu_name=GPU_NAME,
279
  content=content,
280
  )
 
281
 
282
 
283
  # Use a simple Gradio Blocks app with HTML component
 
 
284
  with gr.Blocks(
285
  title="Pixal3D | AI Image-to-3D",
286
  css="footer {display:none !important;} .gradio-container {padding:0 !important; max-width:100% !important; height:100vh !important; overflow:hidden !important;} #proxy-frame {height:100%; max-height:100vh; padding:0; overflow:hidden;}",
287
  theme=gr.themes.Base(),
288
  ) as demo:
289
- gr.HTML(build_page(), elem_id="proxy-frame")
290
 
291
  if __name__ == "__main__":
292
  demo.launch(share=True)
 
167
  margin-bottom: 16px;
168
  color: #f1f5f9;
169
  }}
170
+ .queue-status {{
171
+ display: inline-flex;
172
+ align-items: center;
173
+ gap: 8px;
174
+ padding: 8px 16px;
175
+ border-radius: 20px;
176
+ font-size: 15px;
177
+ font-weight: 600;
178
+ margin-bottom: 8px;
179
+ background: rgba(148, 163, 184, 0.1);
180
+ color: #94a3b8;
181
+ }}
182
+ .queue-status.idle {{
183
+ background: rgba(16, 185, 129, 0.15);
184
+ color: #10b981;
185
+ }}
186
+ .queue-status.busy {{
187
+ background: rgba(251, 146, 60, 0.15);
188
+ color: #fb923c;
189
+ }}
190
+ .queue-status.offline {{
191
+ background: rgba(239, 68, 68, 0.15);
192
+ color: #ef4444;
193
+ }}
194
+ .queue-dot {{
195
+ width: 8px;
196
+ height: 8px;
197
+ border-radius: 50%;
198
+ background: currentColor;
199
+ animation: pulse 2s infinite;
200
+ }}
201
  .instance-card .url-hint {{
202
  font-size: 13px;
203
  color: #64748b;
 
266
  <div class="instance-card">
267
  <h3>🖥️ {inst['name']}</h3>
268
  <p style="color:#94a3b8; font-size:14px; margin-bottom:8px;">⚡ Shared GPU — requests are queued</p>
269
+ <div class="queue-status" id="queue-status-{i}">
270
+ <span class="queue-dot"></span>
271
+ <span id="queue-text-{i}">Checking...</span>
272
+ </div>
273
  <a href="{inst['url']}" target="_blank" rel="noopener noreferrer" class="btn-go">
274
+ Open Instance {i}
275
  </a>
276
  <p class="url-hint"><code>{inst['url']}</code></p>
277
  </div>
278
  """
279
 
280
+ # Build JS array of instance URLs for direct polling (Gradio share links support CORS natively)
281
+ urls_js = ", ".join(['"' + inst["url"].rstrip("/") + '"' for inst in REMOTE_URLS])
282
+
283
  content = f"""
284
  <div class="cards-container">
285
  <div style="width:100%; text-align:center; margin-bottom:16px;">
286
  <h2 style="font-size:28px; margin-bottom:12px;">🚀 Choose a Pixal3D Instance</h2>
287
  <p style="color:#fbbf24; font-size:15px; margin-bottom:8px;">⚠️ Due to a temporary HuggingFace error, this Space is currently unavailable. Please use one of the instances below.</p>
288
+ <p style="color:#10b981; font-size:14px; margin-top:10px; font-weight:600;">💡 Choose the instance with the shortest queue!</p>
289
  </div>
290
  <div class="cards-grid">
291
  {cards_html}
292
  </div>
293
  </div>
294
  """
295
+
296
+ poll_script = f"""
297
+ const INSTANCE_URLS = [{urls_js}];
298
+ async function pollQueues() {{
299
+ for (let i = 0; i < INSTANCE_URLS.length; i++) {{
300
+ try {{
301
+ const controller = new AbortController();
302
+ const timeout = setTimeout(() => controller.abort(), 5000);
303
+ const resp = await fetch(INSTANCE_URLS[i] + '/queue?session_id=', {{
304
+ signal: controller.signal
305
+ }});
306
+ clearTimeout(timeout);
307
+ if (resp.ok) {{
308
+ const data = await resp.json();
309
+ const total = data.total_waiting + (data.gpu_busy ? 1 : 0);
310
+ const el = document.getElementById('queue-text-' + i);
311
+ const status = document.getElementById('queue-status-' + i);
312
+ if (total === 0) {{
313
+ el.textContent = 'Idle — no queue';
314
+ status.className = 'queue-status idle';
315
+ }} else {{
316
+ el.textContent = total + ' in queue';
317
+ status.className = 'queue-status busy';
318
+ }}
319
+ }} else {{
320
+ const el = document.getElementById('queue-text-' + i);
321
+ const status = document.getElementById('queue-status-' + i);
322
+ if (el) {{
323
+ el.textContent = 'Offline';
324
+ status.className = 'queue-status offline';
325
+ }}
326
+ }}
327
+ }} catch (e) {{
328
+ const el = document.getElementById('queue-text-' + i);
329
+ const status = document.getElementById('queue-status-' + i);
330
+ if (el) {{
331
+ el.textContent = 'Offline';
332
+ status.className = 'queue-status offline';
333
+ }}
334
+ }}
335
+ }}
336
+ }}
337
+ pollQueues();
338
+ setInterval(pollQueues, 5000);
339
+ """
340
  else:
341
  status_color = "#ef4444"
342
  status_anim = "pulse 1.5s infinite"
343
  status_text = "Remote instance not configured"
344
+ poll_script = ""
345
  content = """
346
  <div class="no-url">
347
  <div class="no-url-card">
 
355
  </div>
356
  """
357
 
358
+ html = PROXY_HTML.format(
359
  status_color=status_color,
360
  status_anim=status_anim,
361
  status_text=status_text,
362
  gpu_name=GPU_NAME,
363
  content=content,
364
  )
365
+ return html, poll_script
366
 
367
 
368
  # Use a simple Gradio Blocks app with HTML component
369
+ page_html, page_script = build_page()
370
+
371
  with gr.Blocks(
372
  title="Pixal3D | AI Image-to-3D",
373
  css="footer {display:none !important;} .gradio-container {padding:0 !important; max-width:100% !important; height:100vh !important; overflow:hidden !important;} #proxy-frame {height:100%; max-height:100vh; padding:0; overflow:hidden;}",
374
  theme=gr.themes.Base(),
375
  ) as demo:
376
+ gr.HTML(page_html, elem_id="proxy-frame", js_on_load=page_script if page_script else None)
377
 
378
  if __name__ == "__main__":
379
  demo.launch(share=True)