ysharma HF Staff commited on
Commit
f16db96
Β·
verified Β·
1 Parent(s): 2f533f4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +66 -47
app.py CHANGED
@@ -1,5 +1,5 @@
1
  """
2
- Space Keeper v3 - Keeps HuggingFace Spaces alive during hackathon evaluation
3
  """
4
 
5
  import os
@@ -84,7 +84,6 @@ def ping_space(space_id: str) -> dict:
84
  "error": f"Timed out after {REQUEST_TIMEOUT}s"
85
  }
86
  except Exception as e:
87
- # Fallback to HF page
88
  try:
89
  response = requests.get(hf_page_url, timeout=REQUEST_TIMEOUT)
90
  return {
@@ -104,19 +103,6 @@ def ping_space(space_id: str) -> dict:
104
  }
105
 
106
 
107
- def get_org_space_count() -> int:
108
- """Try to get total space count from org page (includes private)."""
109
- try:
110
- url = f"https://huggingface.co/api/organizations/{ORG_NAME}/overview"
111
- response = requests.get(url, timeout=10)
112
- if response.status_code == 200:
113
- data = response.json()
114
- return data.get("numSpaces", -1)
115
- except Exception:
116
- pass
117
- return -1
118
-
119
-
120
  def scheduled_job():
121
  """Wrapper for the scheduled job."""
122
  print(f"[{datetime.now(timezone.utc).isoformat()}] Running scheduled ping job...")
@@ -132,10 +118,10 @@ def scheduled_job():
132
  "status": "error",
133
  "error": f"Failed to list Spaces: {str(e)}",
134
  "total_spaces": 0,
135
- "spaces_found_by_api": 0,
136
  "successful": 0,
137
  "failed": 0,
138
  "duration_seconds": 0,
 
139
  "results": []
140
  }
141
  logs = load_logs()
@@ -143,6 +129,8 @@ def scheduled_job():
143
  save_logs(logs)
144
  return
145
 
 
 
146
  space_ids = [space.id for space in spaces]
147
  results = []
148
 
@@ -163,10 +151,10 @@ def scheduled_job():
163
  "status": "completed",
164
  "error": None,
165
  "total_spaces": len(results),
166
- "spaces_found_by_api": len(space_ids),
167
  "successful": successful,
168
  "failed": failed,
169
  "duration_seconds": round(duration, 2),
 
170
  "results": results
171
  }
172
 
@@ -254,9 +242,12 @@ def format_logs_panel() -> str:
254
  output += f"❌ **{ts}** | {by} | Error: {run['error']}\n\n"
255
  else:
256
  emoji = "βœ…" if run["failed"] == 0 else "⚠️"
 
 
 
257
  output += f"{emoji} **{ts}** | {by} | "
258
  output += f"**{run['total_spaces']}** spaces | "
259
- output += f"{run['successful']} ok, {run['failed']} failed | "
260
  output += f"{run['duration_seconds']}s\n"
261
 
262
  if run["failed"] > 0:
@@ -270,13 +261,32 @@ def format_logs_panel() -> str:
270
  return output
271
 
272
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
273
  # =============================================================================
274
  # MAIN RUN FUNCTION WITH LIVE PROGRESS
275
  # =============================================================================
276
  def manual_trigger_with_progress():
277
  """Manually trigger a ping run with live progress updates."""
278
 
279
- yield "## πŸ”„ Starting...\n\nFetching Space list from HuggingFace API...", format_status_panel(), format_logs_panel()
 
 
 
 
 
280
 
281
  start_time = datetime.now(timezone.utc)
282
 
@@ -291,37 +301,37 @@ def manual_trigger_with_progress():
291
  "status": "error",
292
  "error": str(e),
293
  "total_spaces": 0,
294
- "spaces_found_by_api": 0,
295
  "successful": 0,
296
  "failed": 0,
297
  "duration_seconds": 0,
 
298
  "results": []
299
  }
300
  logs = load_logs()
301
  logs.append(run_result)
302
  save_logs(logs)
303
- yield error_msg, format_status_panel(), format_logs_panel()
304
  return
305
 
 
 
 
 
 
 
 
 
 
 
306
  space_ids = [space.id for space in spaces]
307
  total = len(space_ids)
308
 
309
- # Try to get actual org space count for comparison
310
- org_total = get_org_space_count()
311
-
312
- # Show initial info
313
  info_msg = f"## πŸ”„ Running...\n\n"
314
- info_msg += f"**API returned {total} Spaces**"
315
- if org_total > 0 and org_total != total:
316
- diff = org_total - total
317
- info_msg += f" (org has {org_total} total β€” {diff} are likely private)\n\n"
318
- info_msg += f"πŸ’‘ *To ping private Spaces, add `HF_TOKEN` in Space settings*\n\n"
319
- else:
320
- info_msg += "\n\n"
321
  info_msg += f"Pinging {PARALLEL_REQUESTS} Spaces in parallel...\n\n"
322
  info_msg += f"`[0/{total}]` β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ 0%"
323
 
324
- yield info_msg, format_status_panel(), format_logs_panel()
325
 
326
  # Run pings
327
  results = []
@@ -342,7 +352,6 @@ def manual_trigger_with_progress():
342
  else:
343
  failed += 1
344
 
345
- # Progress bar
346
  pct = int((completed / total) * 100)
347
  filled = int(pct / 10)
348
  bar = "β–ˆ" * filled + "β–‘" * (10 - filled)
@@ -360,7 +369,7 @@ def manual_trigger_with_progress():
360
  """
361
 
362
  if completed % 5 == 0 or completed == total:
363
- yield live_status, format_status_panel(), format_logs_panel()
364
 
365
  # Save results
366
  end_time = datetime.now(timezone.utc)
@@ -372,11 +381,10 @@ def manual_trigger_with_progress():
372
  "status": "completed",
373
  "error": None,
374
  "total_spaces": total,
375
- "spaces_found_by_api": total,
376
- "org_total_spaces": org_total if org_total > 0 else None,
377
  "successful": successful,
378
  "failed": failed,
379
  "duration_seconds": round(duration, 2),
 
380
  "results": results
381
  }
382
 
@@ -388,7 +396,7 @@ def manual_trigger_with_progress():
388
  if failed == 0:
389
  final = f"""## βœ… Completed Successfully!
390
 
391
- **Pinged {total} Spaces** in {duration:.1f} seconds
392
 
393
  All Spaces responded! πŸŽ‰
394
  """
@@ -400,7 +408,7 @@ All Spaces responded! πŸŽ‰
400
 
401
  final = f"""## ⚠️ Completed with {failed} issue(s)
402
 
403
- **Pinged {total} Spaces** in {duration:.1f} seconds
404
 
405
  βœ… {successful} successful
406
  ❌ {failed} failed
@@ -412,15 +420,16 @@ All Spaces responded! πŸŽ‰
412
  *Failures usually mean the Space is paused, has an error, or uses a non-standard SDK.*
413
  """
414
 
415
- # Add note about private spaces
416
- if org_total > 0 and org_total > total:
417
- final += f"\n\n---\nπŸ’‘ **Note:** {org_total - total} private Spaces were not pinged. Add `HF_TOKEN` to access them."
418
-
419
- yield final, format_status_panel(), format_logs_panel()
420
 
421
 
422
  def refresh_all():
423
- return format_status_panel(), format_logs_panel()
 
 
 
 
 
424
 
425
 
426
  # =============================================================================
@@ -442,10 +451,20 @@ Keeps HuggingFace Spaces alive by pinging them to prevent sleeping during hackat
442
  live_output = gr.Markdown("## Ready\n\nClick **πŸš€ Run Now** to ping all Spaces.\n\nAuto-runs every 12 hours when this Space is awake.")
443
 
444
  gr.Markdown("---")
 
 
 
 
445
  logs_panel = gr.Markdown(format_logs_panel())
446
 
447
- run_btn.click(fn=manual_trigger_with_progress, outputs=[live_output, status_panel, logs_panel])
448
- refresh_btn.click(fn=refresh_all, outputs=[status_panel, logs_panel])
 
 
 
 
 
 
449
 
450
 
451
  # =============================================================================
 
1
  """
2
+ Space Keeper v4 - Keeps HuggingFace Spaces alive during hackathon evaluation
3
  """
4
 
5
  import os
 
84
  "error": f"Timed out after {REQUEST_TIMEOUT}s"
85
  }
86
  except Exception as e:
 
87
  try:
88
  response = requests.get(hf_page_url, timeout=REQUEST_TIMEOUT)
89
  return {
 
103
  }
104
 
105
 
 
 
 
 
 
 
 
 
 
 
 
 
 
106
  def scheduled_job():
107
  """Wrapper for the scheduled job."""
108
  print(f"[{datetime.now(timezone.utc).isoformat()}] Running scheduled ping job...")
 
118
  "status": "error",
119
  "error": f"Failed to list Spaces: {str(e)}",
120
  "total_spaces": 0,
 
121
  "successful": 0,
122
  "failed": 0,
123
  "duration_seconds": 0,
124
+ "private_spaces": [],
125
  "results": []
126
  }
127
  logs = load_logs()
 
129
  save_logs(logs)
130
  return
131
 
132
+ # Separate private and public spaces
133
+ private_space_names = [s.id.split("/")[1] for s in spaces if getattr(s, 'private', False)]
134
  space_ids = [space.id for space in spaces]
135
  results = []
136
 
 
151
  "status": "completed",
152
  "error": None,
153
  "total_spaces": len(results),
 
154
  "successful": successful,
155
  "failed": failed,
156
  "duration_seconds": round(duration, 2),
157
+ "private_spaces": private_space_names,
158
  "results": results
159
  }
160
 
 
242
  output += f"❌ **{ts}** | {by} | Error: {run['error']}\n\n"
243
  else:
244
  emoji = "βœ…" if run["failed"] == 0 else "⚠️"
245
+ private_count = len(run.get("private_spaces", []))
246
+ private_info = f" | πŸ”’ {private_count} private" if private_count > 0 else ""
247
+
248
  output += f"{emoji} **{ts}** | {by} | "
249
  output += f"**{run['total_spaces']}** spaces | "
250
+ output += f"{run['successful']} ok, {run['failed']} failed{private_info} | "
251
  output += f"{run['duration_seconds']}s\n"
252
 
253
  if run["failed"] > 0:
 
261
  return output
262
 
263
 
264
+ def format_private_spaces_accordion(private_spaces: list) -> str:
265
+ """Format the private spaces list for the accordion."""
266
+ if not private_spaces:
267
+ return "*No private Spaces found in this run.*"
268
+
269
+ output = f"**{len(private_spaces)} private Spaces** were pinged:\n\n"
270
+
271
+ # Create columns for better readability
272
+ for i, name in enumerate(sorted(private_spaces)):
273
+ output += f"- `{name}`\n"
274
+
275
+ return output
276
+
277
+
278
  # =============================================================================
279
  # MAIN RUN FUNCTION WITH LIVE PROGRESS
280
  # =============================================================================
281
  def manual_trigger_with_progress():
282
  """Manually trigger a ping run with live progress updates."""
283
 
284
+ yield (
285
+ "## πŸ”„ Starting...\n\nFetching Space list from HuggingFace API...",
286
+ format_status_panel(),
287
+ format_logs_panel(),
288
+ "*Run in progress...*"
289
+ )
290
 
291
  start_time = datetime.now(timezone.utc)
292
 
 
301
  "status": "error",
302
  "error": str(e),
303
  "total_spaces": 0,
 
304
  "successful": 0,
305
  "failed": 0,
306
  "duration_seconds": 0,
307
+ "private_spaces": [],
308
  "results": []
309
  }
310
  logs = load_logs()
311
  logs.append(run_result)
312
  save_logs(logs)
313
+ yield error_msg, format_status_panel(), format_logs_panel(), "*Error during run*"
314
  return
315
 
316
+ # Separate private and public spaces
317
+ private_spaces = []
318
+ public_spaces = []
319
+ for s in spaces:
320
+ name = s.id.split("/")[1]
321
+ if getattr(s, 'private', False):
322
+ private_spaces.append(name)
323
+ else:
324
+ public_spaces.append(name)
325
+
326
  space_ids = [space.id for space in spaces]
327
  total = len(space_ids)
328
 
 
 
 
 
329
  info_msg = f"## πŸ”„ Running...\n\n"
330
+ info_msg += f"**Found {total} Spaces** ({len(public_spaces)} public, {len(private_spaces)} private)\n\n"
 
 
 
 
 
 
331
  info_msg += f"Pinging {PARALLEL_REQUESTS} Spaces in parallel...\n\n"
332
  info_msg += f"`[0/{total}]` β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘β–‘ 0%"
333
 
334
+ yield info_msg, format_status_panel(), format_logs_panel(), format_private_spaces_accordion(private_spaces)
335
 
336
  # Run pings
337
  results = []
 
352
  else:
353
  failed += 1
354
 
 
355
  pct = int((completed / total) * 100)
356
  filled = int(pct / 10)
357
  bar = "β–ˆ" * filled + "β–‘" * (10 - filled)
 
369
  """
370
 
371
  if completed % 5 == 0 or completed == total:
372
+ yield live_status, format_status_panel(), format_logs_panel(), format_private_spaces_accordion(private_spaces)
373
 
374
  # Save results
375
  end_time = datetime.now(timezone.utc)
 
381
  "status": "completed",
382
  "error": None,
383
  "total_spaces": total,
 
 
384
  "successful": successful,
385
  "failed": failed,
386
  "duration_seconds": round(duration, 2),
387
+ "private_spaces": private_spaces,
388
  "results": results
389
  }
390
 
 
396
  if failed == 0:
397
  final = f"""## βœ… Completed Successfully!
398
 
399
+ **Pinged {total} Spaces** ({len(public_spaces)} public, {len(private_spaces)} private) in {duration:.1f}s
400
 
401
  All Spaces responded! πŸŽ‰
402
  """
 
408
 
409
  final = f"""## ⚠️ Completed with {failed} issue(s)
410
 
411
+ **Pinged {total} Spaces** ({len(public_spaces)} public, {len(private_spaces)} private) in {duration:.1f}s
412
 
413
  βœ… {successful} successful
414
  ❌ {failed} failed
 
420
  *Failures usually mean the Space is paused, has an error, or uses a non-standard SDK.*
421
  """
422
 
423
+ yield final, format_status_panel(), format_logs_panel(), format_private_spaces_accordion(private_spaces)
 
 
 
 
424
 
425
 
426
  def refresh_all():
427
+ # Get private spaces from last run if available
428
+ logs = load_logs()
429
+ private_spaces = []
430
+ if logs:
431
+ private_spaces = logs[-1].get("private_spaces", [])
432
+ return format_status_panel(), format_logs_panel(), format_private_spaces_accordion(private_spaces)
433
 
434
 
435
  # =============================================================================
 
451
  live_output = gr.Markdown("## Ready\n\nClick **πŸš€ Run Now** to ping all Spaces.\n\nAuto-runs every 12 hours when this Space is awake.")
452
 
453
  gr.Markdown("---")
454
+
455
+ with gr.Accordion("πŸ”’ Private Spaces", open=False):
456
+ private_spaces_display = gr.Markdown("*Run a ping to see private Spaces list.*")
457
+
458
  logs_panel = gr.Markdown(format_logs_panel())
459
 
460
+ run_btn.click(
461
+ fn=manual_trigger_with_progress,
462
+ outputs=[live_output, status_panel, logs_panel, private_spaces_display]
463
+ )
464
+ refresh_btn.click(
465
+ fn=refresh_all,
466
+ outputs=[status_panel, logs_panel, private_spaces_display]
467
+ )
468
 
469
 
470
  # =============================================================================