mrfakename commited on
Commit
95dc3cb
·
1 Parent(s): a660b0d
Files changed (2) hide show
  1. app.py +33 -1
  2. templates/dashboard.html +77 -12
app.py CHANGED
@@ -127,7 +127,16 @@ def fetch_user_spaces(username, token=None):
127
  try:
128
  resp = requests.get(url, headers=headers, timeout=10)
129
  if resp.status_code == 200:
130
- spaces = resp.json()
 
 
 
 
 
 
 
 
 
131
  except Exception:
132
  pass
133
 
@@ -135,6 +144,29 @@ def fetch_user_spaces(username, token=None):
135
  return spaces
136
 
137
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
138
  def fetch_space_discussions(space_id, token=None):
139
  cache_key = f"discussions:{space_id}"
140
  cached = cache_get(cache_key)
 
127
  try:
128
  resp = requests.get(url, headers=headers, timeout=10)
129
  if resp.status_code == 200:
130
+ space_list = resp.json()
131
+ # Fetch individual space details to get runtime info
132
+ for space in space_list:
133
+ space_id = space.get("id", "")
134
+ if space_id:
135
+ detail = fetch_space_detail(space_id, token)
136
+ if detail:
137
+ spaces.append(detail)
138
+ else:
139
+ spaces.append(space)
140
  except Exception:
141
  pass
142
 
 
144
  return spaces
145
 
146
 
147
+ def fetch_space_detail(space_id, token=None):
148
+ cache_key = f"space_detail:{space_id}"
149
+ cached = cache_get(cache_key)
150
+ if cached is not None:
151
+ return cached
152
+
153
+ headers = {}
154
+ if token:
155
+ headers["Authorization"] = f"Bearer {token}"
156
+
157
+ try:
158
+ url = f"https://huggingface.co/api/spaces/{space_id}"
159
+ resp = requests.get(url, headers=headers, timeout=10)
160
+ if resp.status_code == 200:
161
+ detail = resp.json()
162
+ cache_set(cache_key, detail)
163
+ return detail
164
+ except Exception:
165
+ pass
166
+
167
+ return None
168
+
169
+
170
  def fetch_space_discussions(space_id, token=None):
171
  cache_key = f"discussions:{space_id}"
172
  cached = cache_get(cache_key)
templates/dashboard.html CHANGED
@@ -132,7 +132,7 @@
132
  background: #2a2a0a;
133
  color: #eab308;
134
  }
135
- .space-status.stopped, .space-status.paused {
136
  background: #1a1a1a;
137
  color: #666;
138
  }
@@ -140,6 +140,35 @@
140
  background: #2a0a0a;
141
  color: #ef4444;
142
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  .main {
144
  flex: 1;
145
  margin-left: 280px;
@@ -354,17 +383,44 @@
354
  {% if spaces %}
355
  <div class="spaces-list">
356
  {% for space in spaces %}
357
- <a href="https://huggingface.co/spaces/{{ space.id }}" target="_blank" class="space-item">
358
- <span class="space-name">{{ space.id.split('/')[-1] }}</span>
359
- {% set status = space.runtime.stage|default('stopped')|lower if space.runtime else 'stopped' %}
360
- <span class="space-status {{ status }}">
361
- {% if status == 'running' %}running
362
- {% elif status == 'building' %}building
363
- {% elif status == 'runtime_error' or status == 'build_error' %}error
364
- {% elif status == 'paused' %}paused
365
- {% else %}stopped{% endif %}
366
- </span>
367
- </a>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
368
  {% endfor %}
369
  </div>
370
  {% else %}
@@ -436,5 +492,14 @@
436
  {% endif %}
437
  </main>
438
  </div>
 
 
 
 
 
 
 
 
 
439
  </body>
440
  </html>
 
132
  background: #2a2a0a;
133
  color: #eab308;
134
  }
135
+ .space-status.stopped, .space-status.paused, .space-status.sleeping {
136
  background: #1a1a1a;
137
  color: #666;
138
  }
 
140
  background: #2a0a0a;
141
  color: #ef4444;
142
  }
143
+ .space-details {
144
+ display: none;
145
+ padding: 0.5rem 0.75rem;
146
+ margin-top: 2px;
147
+ background: #111;
148
+ border-radius: 4px;
149
+ font-size: 0.75rem;
150
+ }
151
+ .space-details.open {
152
+ display: block;
153
+ }
154
+ .space-detail-row {
155
+ display: flex;
156
+ justify-content: space-between;
157
+ padding: 0.25rem 0;
158
+ border-bottom: 1px solid #1a1a1a;
159
+ }
160
+ .space-detail-row:last-child {
161
+ border-bottom: none;
162
+ }
163
+ .space-detail-label {
164
+ color: #555;
165
+ }
166
+ .space-detail-value {
167
+ color: #999;
168
+ }
169
+ .space-toggle {
170
+ cursor: pointer;
171
+ }
172
  .main {
173
  flex: 1;
174
  margin-left: 280px;
 
383
  {% if spaces %}
384
  <div class="spaces-list">
385
  {% for space in spaces %}
386
+ {% set status = space.runtime.stage|default('STOPPED')|upper if space.runtime else 'STOPPED' %}
387
+ {% set hardware = space.runtime.hardware.current|default('unknown') if space.runtime and space.runtime.hardware else 'unknown' %}
388
+ {% set storage = space.runtime.storage.current|default('none') if space.runtime and space.runtime.storage else 'none' %}
389
+ <div class="space-entry">
390
+ <div class="space-item space-toggle" data-space="{{ loop.index }}">
391
+ <span class="space-name">{{ space.id.split('/')[-1] }}</span>
392
+ <span class="space-status {{ status|lower }}">
393
+ {% if status == 'RUNNING' %}running
394
+ {% elif status == 'BUILDING' %}building
395
+ {% elif status == 'RUNTIME_ERROR' or status == 'BUILD_ERROR' %}error
396
+ {% elif status == 'PAUSED' %}paused
397
+ {% elif status == 'SLEEPING' %}sleeping
398
+ {% else %}stopped{% endif %}
399
+ </span>
400
+ </div>
401
+ <div class="space-details" id="space-{{ loop.index }}">
402
+ <div class="space-detail-row">
403
+ <span class="space-detail-label">Hardware</span>
404
+ <span class="space-detail-value">{{ hardware }}</span>
405
+ </div>
406
+ <div class="space-detail-row">
407
+ <span class="space-detail-label">Storage</span>
408
+ <span class="space-detail-value">{{ storage }}</span>
409
+ </div>
410
+ <div class="space-detail-row">
411
+ <span class="space-detail-label">SDK</span>
412
+ <span class="space-detail-value">{{ space.sdk|default('unknown') }}</span>
413
+ </div>
414
+ <div class="space-detail-row">
415
+ <span class="space-detail-label">Likes</span>
416
+ <span class="space-detail-value">{{ space.likes|default(0) }}</span>
417
+ </div>
418
+ <a href="https://huggingface.co/spaces/{{ space.id }}" target="_blank" class="space-detail-row" style="color: #6366f1;">
419
+ <span>Open on HF</span>
420
+ <span>→</span>
421
+ </a>
422
+ </div>
423
+ </div>
424
  {% endfor %}
425
  </div>
426
  {% else %}
 
492
  {% endif %}
493
  </main>
494
  </div>
495
+ <script>
496
+ document.querySelectorAll('.space-toggle').forEach(el => {
497
+ el.addEventListener('click', () => {
498
+ const id = el.dataset.space;
499
+ const details = document.getElementById('space-' + id);
500
+ details.classList.toggle('open');
501
+ });
502
+ });
503
+ </script>
504
  </body>
505
  </html>