Karthik1610 commited on
Commit
bc13a9f
Β·
verified Β·
1 Parent(s): 85ffa3a

Create templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +664 -0
templates/index.html ADDED
@@ -0,0 +1,664 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>πŸ§ͺ Clarifai Community Bench</title>
7
+ <style>
8
+ * {
9
+ margin: 0;
10
+ padding: 0;
11
+ box-sizing: border-box;
12
+ }
13
+
14
+ body {
15
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
16
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
17
+ min-height: 100vh;
18
+ color: #333;
19
+ }
20
+
21
+ .container {
22
+ max-width: 1200px;
23
+ margin: 0 auto;
24
+ padding: 20px;
25
+ }
26
+
27
+ .header {
28
+ text-align: center;
29
+ margin-bottom: 40px;
30
+ color: white;
31
+ }
32
+
33
+ .header h1 {
34
+ font-size: 3rem;
35
+ margin-bottom: 10px;
36
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
37
+ }
38
+
39
+ .header p {
40
+ font-size: 1.2rem;
41
+ opacity: 0.9;
42
+ }
43
+
44
+ .main-card {
45
+ background: white;
46
+ border-radius: 20px;
47
+ padding: 40px;
48
+ box-shadow: 0 20px 40px rgba(0,0,0,0.1);
49
+ margin-bottom: 30px;
50
+ }
51
+
52
+ .form-section {
53
+ margin-bottom: 30px;
54
+ }
55
+
56
+ .form-section h3 {
57
+ color: #4a5568;
58
+ margin-bottom: 15px;
59
+ display: flex;
60
+ align-items: center;
61
+ gap: 10px;
62
+ }
63
+
64
+ .input-group {
65
+ margin-bottom: 20px;
66
+ }
67
+
68
+ .input-group label {
69
+ display: block;
70
+ font-weight: 600;
71
+ margin-bottom: 8px;
72
+ color: #2d3748;
73
+ }
74
+
75
+ .input-group input, .input-group select {
76
+ width: 100%;
77
+ padding: 12px 16px;
78
+ border: 2px solid #e2e8f0;
79
+ border-radius: 12px;
80
+ font-size: 16px;
81
+ transition: all 0.2s;
82
+ }
83
+
84
+ .input-group input:focus, .input-group select:focus {
85
+ outline: none;
86
+ border-color: #667eea;
87
+ box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
88
+ }
89
+
90
+ .btn {
91
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
92
+ color: white;
93
+ border: none;
94
+ padding: 16px 32px;
95
+ border-radius: 12px;
96
+ font-size: 16px;
97
+ font-weight: 600;
98
+ cursor: pointer;
99
+ transition: all 0.2s;
100
+ box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
101
+ }
102
+
103
+ .btn:hover {
104
+ transform: translateY(-2px);
105
+ box-shadow: 0 8px 20px rgba(102, 126, 234, 0.4);
106
+ }
107
+
108
+ .btn:disabled {
109
+ opacity: 0.6;
110
+ cursor: not-allowed;
111
+ transform: none;
112
+ }
113
+
114
+ .btn-secondary {
115
+ background: #718096;
116
+ box-shadow: 0 4px 12px rgba(113, 128, 150, 0.3);
117
+ }
118
+
119
+ .btn-secondary:hover {
120
+ box-shadow: 0 8px 20px rgba(113, 128, 150, 0.4);
121
+ }
122
+
123
+ .grid {
124
+ display: grid;
125
+ grid-template-columns: 1fr 1fr;
126
+ gap: 30px;
127
+ }
128
+
129
+ .pack-card {
130
+ background: #f7fafc;
131
+ border: 2px solid #e2e8f0;
132
+ border-radius: 16px;
133
+ padding: 20px;
134
+ cursor: pointer;
135
+ transition: all 0.2s;
136
+ }
137
+
138
+ .pack-card:hover, .pack-card.selected {
139
+ border-color: #667eea;
140
+ background: rgba(102, 126, 234, 0.05);
141
+ transform: translateY(-2px);
142
+ }
143
+
144
+ .pack-card h4 {
145
+ color: #2d3748;
146
+ margin-bottom: 10px;
147
+ }
148
+
149
+ .pack-card p {
150
+ color: #718096;
151
+ font-size: 14px;
152
+ }
153
+
154
+ .results-section {
155
+ margin-top: 30px;
156
+ display: none;
157
+ }
158
+
159
+ .results-grid {
160
+ display: grid;
161
+ grid-template-columns: 1fr 2fr;
162
+ gap: 20px;
163
+ margin-top: 20px;
164
+ }
165
+
166
+ .lint-results, .benchmark-results {
167
+ background: #f7fafc;
168
+ border-radius: 12px;
169
+ padding: 20px;
170
+ }
171
+
172
+ .lint-results h4, .benchmark-results h4 {
173
+ margin-bottom: 15px;
174
+ color: #2d3748;
175
+ }
176
+
177
+ .score-badge {
178
+ display: inline-block;
179
+ padding: 8px 16px;
180
+ border-radius: 20px;
181
+ color: white;
182
+ font-weight: 600;
183
+ margin-bottom: 15px;
184
+ }
185
+
186
+ .score-high { background: #48bb78; }
187
+ .score-medium { background: #ed8936; }
188
+ .score-low { background: #f56565; }
189
+
190
+ .metric-item {
191
+ display: flex;
192
+ justify-content: space-between;
193
+ padding: 8px 0;
194
+ border-bottom: 1px solid #e2e8f0;
195
+ }
196
+
197
+ .loading {
198
+ display: none;
199
+ text-align: center;
200
+ padding: 40px;
201
+ }
202
+
203
+ .loading .spinner {
204
+ width: 40px;
205
+ height: 40px;
206
+ border: 4px solid #e2e8f0;
207
+ border-top: 4px solid #667eea;
208
+ border-radius: 50%;
209
+ animation: spin 1s linear infinite;
210
+ margin: 0 auto 20px;
211
+ }
212
+
213
+ @keyframes spin {
214
+ 0% { transform: rotate(0deg); }
215
+ 100% { transform: rotate(360deg); }
216
+ }
217
+
218
+ .action-buttons {
219
+ display: flex;
220
+ gap: 15px;
221
+ margin-top: 20px;
222
+ flex-wrap: wrap;
223
+ }
224
+
225
+ .export-section {
226
+ background: #edf2f7;
227
+ border-radius: 12px;
228
+ padding: 20px;
229
+ margin-top: 20px;
230
+ }
231
+
232
+ @media (max-width: 768px) {
233
+ .grid, .results-grid {
234
+ grid-template-columns: 1fr;
235
+ }
236
+
237
+ .header h1 {
238
+ font-size: 2rem;
239
+ }
240
+
241
+ .main-card {
242
+ padding: 20px;
243
+ }
244
+
245
+ .action-buttons {
246
+ justify-content: center;
247
+ }
248
+ }
249
+
250
+ .error {
251
+ background: #fed7d7;
252
+ color: #c53030;
253
+ padding: 15px;
254
+ border-radius: 12px;
255
+ margin-bottom: 20px;
256
+ border: 2px solid #feb2b2;
257
+ }
258
+
259
+ .success {
260
+ background: #c6f6d5;
261
+ color: #2f855a;
262
+ padding: 15px;
263
+ border-radius: 12px;
264
+ margin-bottom: 20px;
265
+ border: 2px solid #9ae6b4;
266
+ }
267
+ </style>
268
+ </head>
269
+ <body>
270
+ <div class="container">
271
+ <div class="header">
272
+ <h1>πŸ§ͺ Clarifai Community Bench</h1>
273
+ <p>Professional model evaluation, linting & community growth engine</p>
274
+ </div>
275
+
276
+ <div class="main-card">
277
+ <div class="form-section">
278
+ <h3>πŸ”‘ Authentication</h3>
279
+ <div class="input-group">
280
+ <label for="hf-token">HuggingFace Token</label>
281
+ <input type="password" id="hf-token" placeholder="hf_..." required>
282
+ </div>
283
+ </div>
284
+
285
+ <div class="form-section">
286
+ <h3>πŸ€– Model Import & Lint</h3>
287
+ <div class="input-group">
288
+ <label for="model-id">Model Repository ID</label>
289
+ <input type="text" id="model-id" placeholder="facebook/bart-large-cnn" required>
290
+ </div>
291
+ <button class="btn" onclick="lintModel()">Import & Lint Model</button>
292
+ </div>
293
+
294
+ <div class="form-section">
295
+ <h3>πŸ“‹ Benchmark Packs</h3>
296
+ <div class="grid">
297
+ {% for pack_key, pack in benchmark_packs.items() %}
298
+ <div class="pack-card" onclick="selectPack('{{ pack_key }}')">
299
+ <h4>{{ pack.name }}</h4>
300
+ <p>{{ pack.datasets|length }} datasets β€’ {{ pack.metrics|join(', ') }}</p>
301
+ </div>
302
+ {% endfor %}
303
+ </div>
304
+ <input type="hidden" id="selected-pack">
305
+ <button class="btn" onclick="runBenchmark()" style="margin-top: 20px;">πŸš€ Run Benchmark</button>
306
+ </div>
307
+
308
+ <div class="loading">
309
+ <div class="spinner"></div>
310
+ <p>Processing your request...</p>
311
+ </div>
312
+
313
+ <div class="results-section">
314
+ <h3>πŸ“Š Results</h3>
315
+ <div class="results-grid">
316
+ <div class="lint-results">
317
+ <h4>Model Readiness</h4>
318
+ <div id="lint-content"></div>
319
+ </div>
320
+ <div class="benchmark-results">
321
+ <h4>Benchmark Performance</h4>
322
+ <div id="benchmark-content"></div>
323
+ </div>
324
+ </div>
325
+
326
+ <div class="export-section">
327
+ <h4>🎯 Clarifai Growth Tools</h4>
328
+ <p>Generate community-ready artifacts and backlinks</p>
329
+ <div class="action-buttons">
330
+ <button class="btn btn-secondary" onclick="generateReadme()">πŸ“ Generate README</button>
331
+ <button class="btn btn-secondary" onclick="createPR()">πŸ”— Create PR Template</button>
332
+ <button class="btn btn-secondary" onclick="exportArtifacts()">πŸ“¦ Export Artifacts</button>
333
+ <button class="btn btn-secondary" onclick="shareResults()">πŸš€ Share Results</button>
334
+ </div>
335
+ </div>
336
+ </div>
337
+ </div>
338
+ </div>
339
+
340
+ <script>
341
+ let currentResults = null;
342
+ let selectedPack = null;
343
+
344
+ function selectPack(packKey) {
345
+ // Remove previous selection
346
+ document.querySelectorAll('.pack-card').forEach(card => {
347
+ card.classList.remove('selected');
348
+ });
349
+
350
+ // Select new pack
351
+ event.target.closest('.pack-card').classList.add('selected');
352
+ selectedPack = packKey;
353
+ document.getElementById('selected-pack').value = packKey;
354
+ }
355
+
356
+ function showLoading() {
357
+ document.querySelector('.loading').style.display = 'block';
358
+ document.querySelector('.results-section').style.display = 'none';
359
+ }
360
+
361
+ function hideLoading() {
362
+ document.querySelector('.loading').style.display = 'none';
363
+ }
364
+
365
+ function showError(message) {
366
+ hideLoading();
367
+ const errorDiv = document.createElement('div');
368
+ errorDiv.className = 'error';
369
+ errorDiv.textContent = message;
370
+ document.querySelector('.main-card').insertBefore(errorDiv, document.querySelector('.form-section'));
371
+ setTimeout(() => errorDiv.remove(), 5000);
372
+ }
373
+
374
+ function showSuccess(message) {
375
+ const successDiv = document.createElement('div');
376
+ successDiv.className = 'success';
377
+ successDiv.textContent = message;
378
+ document.querySelector('.main-card').insertBefore(successDiv, document.querySelector('.form-section'));
379
+ setTimeout(() => successDiv.remove(), 5000);
380
+ }
381
+
382
+ async function lintModel() {
383
+ const modelId = document.getElementById('model-id').value;
384
+ const token = document.getElementById('hf-token').value;
385
+
386
+ if (!modelId || !token) {
387
+ showError('Please provide both model ID and HF token');
388
+ return;
389
+ }
390
+
391
+ showLoading();
392
+
393
+ try {
394
+ const response = await fetch('/api/lint-model', {
395
+ method: 'POST',
396
+ headers: { 'Content-Type': 'application/json' },
397
+ body: JSON.stringify({ model_id: modelId, token })
398
+ });
399
+
400
+ const result = await response.json();
401
+ hideLoading();
402
+
403
+ if (result.error) {
404
+ showError(result.error);
405
+ return;
406
+ }
407
+
408
+ displayLintResults(result);
409
+ } catch (error) {
410
+ hideLoading();
411
+ showError('Failed to lint model: ' + error.message);
412
+ }
413
+ }
414
+
415
+ async function runBenchmark() {
416
+ const modelId = document.getElementById('model-id').value;
417
+ const token = document.getElementById('hf-token').value;
418
+
419
+ if (!modelId || !token || !selectedPack) {
420
+ showError('Please provide model ID, token, and select a benchmark pack');
421
+ return;
422
+ }
423
+
424
+ showLoading();
425
+
426
+ try {
427
+ const response = await fetch('/api/run-benchmark', {
428
+ method: 'POST',
429
+ headers: { 'Content-Type': 'application/json' },
430
+ body: JSON.stringify({
431
+ model_id: modelId,
432
+ token,
433
+ pack: selectedPack
434
+ })
435
+ });
436
+
437
+ const result = await response.json();
438
+ hideLoading();
439
+
440
+ if (result.error) {
441
+ showError(result.error);
442
+ return;
443
+ }
444
+
445
+ currentResults = result;
446
+ displayBenchmarkResults(result);
447
+ document.querySelector('.results-section').style.display = 'block';
448
+ } catch (error) {
449
+ hideLoading();
450
+ showError('Failed to run benchmark: ' + error.message);
451
+ }
452
+ }
453
+
454
+ function displayLintResults(result) {
455
+ const content = document.getElementById('lint-content');
456
+ const scoreClass = result.readiness_score >= 80 ? 'score-high' :
457
+ result.readiness_score >= 60 ? 'score-medium' : 'score-low';
458
+
459
+ content.innerHTML = `
460
+ <div class="score-badge ${scoreClass}">
461
+ ${result.readiness_score}/100 Ready
462
+ </div>
463
+ <div class="metric-item">
464
+ <span>Task:</span>
465
+ <span>${result.task || 'Unknown'}</span>
466
+ </div>
467
+ <div class="metric-item">
468
+ <span>Downloads:</span>
469
+ <span>${result.downloads.toLocaleString()}</span>
470
+ </div>
471
+ <div class="metric-item">
472
+ <span>Likes:</span>
473
+ <span>${result.likes}</span>
474
+ </div>
475
+ <div style="margin-top: 15px;">
476
+ <strong>Recommendations:</strong>
477
+ <ul style="margin-top: 8px; padding-left: 20px;">
478
+ ${result.recommendations.map(rec => `<li>${rec}</li>`).join('')}
479
+ </ul>
480
+ </div>
481
+ `;
482
+ }
483
+
484
+ function displayBenchmarkResults(result) {
485
+ const content = document.getElementById('benchmark-content');
486
+ let html = '';
487
+
488
+ result.benchmark_results.forEach(dataset => {
489
+ if (dataset.error) {
490
+ html += `
491
+ <div style="margin-bottom: 20px; padding: 15px; background: #fed7d7; border-radius: 8px;">
492
+ <strong>${dataset.dataset}:</strong> ${dataset.error}
493
+ </div>
494
+ `;
495
+ } else {
496
+ html += `
497
+ <div style="margin-bottom: 20px; padding: 15px; background: #f0fff4; border-radius: 8px;">
498
+ <h5>${dataset.dataset} (${dataset.samples} samples)</h5>
499
+ <div style="margin-top: 10px;">
500
+ ${Object.entries(dataset.metrics).map(([key, value]) =>
501
+ `<div class="metric-item">
502
+ <span>${key.toUpperCase()}:</span>
503
+ <span>${value}</span>
504
+ </div>`
505
+ ).join('')}
506
+ <div class="metric-item">
507
+ <span>Avg Latency:</span>
508
+ <span>${dataset.avg_latency}s</span>
509
+ </div>
510
+ </div>
511
+ </div>
512
+ `;
513
+ }
514
+ });
515
+
516
+ content.innerHTML = html;
517
+ }
518
+
519
+ async function generateReadme() {
520
+ if (!currentResults) {
521
+ showError('Please run a benchmark first');
522
+ return;
523
+ }
524
+
525
+ try {
526
+ const response = await fetch('/api/generate-readme', {
527
+ method: 'POST',
528
+ headers: { 'Content-Type': 'application/json' },
529
+ body: JSON.stringify(currentResults)
530
+ });
531
+
532
+ const result = await response.json();
533
+
534
+ // Create modal or popup with README content
535
+ const modal = document.createElement('div');
536
+ modal.style.cssText = `
537
+ position: fixed; top: 0; left: 0; width: 100%; height: 100%;
538
+ background: rgba(0,0,0,0.5); display: flex; align-items: center;
539
+ justify-content: center; z-index: 1000;
540
+ `;
541
+
542
+ modal.innerHTML = `
543
+ <div style="background: white; padding: 30px; border-radius: 12px; max-width: 80%; max-height: 80%; overflow: auto;">
544
+ <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
545
+ <h3>πŸ“ Generated README Section</h3>
546
+ <button onclick="this.closest('.modal').remove()" style="background: none; border: none; font-size: 24px; cursor: pointer;">&times;</button>
547
+ </div>
548
+ <pre style="background: #f7fafc; padding: 20px; border-radius: 8px; white-space: pre-wrap; max-height: 400px; overflow-y: auto;">${result.readme}</pre>
549
+ <div style="margin-top: 20px; text-align: right;">
550
+ <button class="btn btn-secondary" onclick="copyToClipboard(\`${result.readme.replace(/`/g, '\\`')}\`)">πŸ“‹ Copy to Clipboard</button>
551
+ </div>
552
+ </div>
553
+ `;
554
+ modal.className = 'modal';
555
+ document.body.appendChild(modal);
556
+
557
+ showSuccess('README section generated successfully!');
558
+ } catch (error) {
559
+ showError('Failed to generate README: ' + error.message);
560
+ }
561
+ }
562
+
563
+ function copyToClipboard(text) {
564
+ navigator.clipboard.writeText(text).then(() => {
565
+ showSuccess('Copied to clipboard!');
566
+ });
567
+ }
568
+
569
+ function createPR() {
570
+ if (!currentResults) {
571
+ showError('Please run a benchmark first');
572
+ return;
573
+ }
574
+
575
+ const modelId = currentResults.model_id;
576
+ const title = `Add benchmark results from Clarifai Community Bench`;
577
+ const body = `## πŸ§ͺ Benchmark Results Added
578
+
579
+ This PR adds comprehensive benchmark results for ${modelId} from [Clarifai Community Bench](https://huggingface.co/spaces/clarifai/community-bench).
580
+
581
+ ### Results Summary
582
+ - **Readiness Score:** ${currentResults.readiness_score}/100
583
+ - **Task:** ${currentResults.task}
584
+ - **Datasets Tested:** ${currentResults.benchmark_results.length}
585
+
586
+ ### Performance Highlights
587
+ ${currentResults.benchmark_results.map(result =>
588
+ `- **${result.dataset}**: ${Object.entries(result.metrics).map(([k,v]) => `${k}: ${v}`).join(', ')}`
589
+ ).join('\n')}
590
+
591
+ ### What's Included
592
+ - βœ… Comprehensive metrics across multiple datasets
593
+ - βœ… Latency benchmarks
594
+ - βœ… Model card improvements
595
+ - βœ… Community-ready documentation
596
+
597
+ ---
598
+ *Generated by [Clarifai Community Bench](https://huggingface.co/spaces/clarifai/community-bench) - Building the future of AI model evaluation*`;
599
+
600
+ const githubUrl = `https://github.com/${modelId}/compare?expand=1&title=${encodeURIComponent(title)}&body=${encodeURIComponent(body)}`;
601
+ window.open(githubUrl, '_blank');
602
+ showSuccess('PR template opened in new tab!');
603
+ }
604
+
605
+ async function exportArtifacts() {
606
+ if (!currentResults) {
607
+ showError('Please run a benchmark first');
608
+ return;
609
+ }
610
+
611
+ try {
612
+ const response = await fetch('/api/export-artifacts', {
613
+ method: 'POST',
614
+ headers: { 'Content-Type': 'application/json' },
615
+ body: JSON.stringify(currentResults)
616
+ });
617
+
618
+ if (response.ok) {
619
+ const blob = await response.blob();
620
+ const url = URL.createObjectURL(blob);
621
+ const a = document.createElement('a');
622
+ a.href = url;
623
+ a.download = `${currentResults.model_id.replace('/', '_')}_artifacts.zip`;
624
+ document.body.appendChild(a);
625
+ a.click();
626
+ document.body.removeChild(a);
627
+ URL.revokeObjectURL(url);
628
+ showSuccess('Artifacts exported successfully!');
629
+ } else {
630
+ throw new Error('Export failed');
631
+ }
632
+ } catch (error) {
633
+ showError('Failed to export artifacts: ' + error.message);
634
+ }
635
+ }
636
+
637
+ function shareResults() {
638
+ if (!currentResults) {
639
+ showError('Please run a benchmark first');
640
+ return;
641
+ }
642
+
643
+ const shareData = {
644
+ title: `πŸ§ͺ ${currentResults.model_id} Benchmark Results`,
645
+ text: `Check out these benchmark results for ${currentResults.model_id}! Readiness Score: ${currentResults.readiness_score}/100`,
646
+ url: window.location.href
647
+ };
648
+
649
+ if (navigator.share) {
650
+ navigator.share(shareData);
651
+ } else {
652
+ // Fallback: copy to clipboard
653
+ const shareText = `${shareData.title}\n${shareData.text}\n${shareData.url}`;
654
+ copyToClipboard(shareText);
655
+ }
656
+ }
657
+
658
+ // Auto-focus token input
659
+ document.addEventListener('DOMContentLoaded', () => {
660
+ document.getElementById('hf-token').focus();
661
+ });
662
+ </script>
663
+ </body>
664
+ </html>