davanstrien HF Staff commited on
Commit
656300e
·
verified ·
1 Parent(s): e6788d4

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +442 -17
index.html CHANGED
@@ -1,19 +1,444 @@
1
- <!doctype html>
2
  <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  </html>
 
1
+ <!DOCTYPE html>
2
  <html>
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <title>ICONCLASS Dataset Viewer</title>
6
+ <style>
7
+ * {
8
+ margin: 0;
9
+ padding: 0;
10
+ box-sizing: border-box;
11
+ }
12
+
13
+ body {
14
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
15
+ sans-serif;
16
+ background: #f9f9f9;
17
+ padding: 20px;
18
+ line-height: 1.6;
19
+ }
20
+
21
+ .header {
22
+ text-align: center;
23
+ margin-bottom: 30px;
24
+ padding: 20px;
25
+ }
26
+
27
+ h1 {
28
+ font-size: 24px;
29
+ font-weight: 600;
30
+ color: #333;
31
+ margin-bottom: 10px;
32
+ }
33
+
34
+ .stats {
35
+ font-size: 14px;
36
+ color: #666;
37
+ }
38
+
39
+ .gallery {
40
+ display: grid;
41
+ grid-template-columns: repeat(auto-fit, minmax(500px, 1fr));
42
+ gap: 30px;
43
+ max-width: 1200px;
44
+ margin: 0 auto;
45
+ }
46
+
47
+ @media (max-width: 600px) {
48
+ .gallery {
49
+ grid-template-columns: 1fr;
50
+ }
51
+ }
52
+
53
+ .card {
54
+ background: white;
55
+ border-radius: 12px;
56
+ overflow: hidden;
57
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
58
+ }
59
+
60
+ .card img {
61
+ width: 100%;
62
+ height: auto;
63
+ display: block;
64
+ border-bottom: 1px solid #eee;
65
+ }
66
+
67
+ .card-content {
68
+ padding: 20px;
69
+ }
70
+
71
+ .raw-prediction {
72
+ background: #f5f5f5;
73
+ padding: 8px 12px;
74
+ border-radius: 6px;
75
+ font-family: "SF Mono", Monaco, "Cascadia Code", monospace;
76
+ font-size: 12px;
77
+ color: #666;
78
+ margin-bottom: 20px;
79
+ word-break: break-all;
80
+ }
81
+
82
+ .comparison {
83
+ display: grid;
84
+ grid-template-columns: 1fr 1fr;
85
+ gap: 20px;
86
+ margin-top: 15px;
87
+ }
88
+
89
+ .column {
90
+ font-size: 13px;
91
+ }
92
+
93
+ .column-title {
94
+ font-weight: 600;
95
+ margin-bottom: 8px;
96
+ color: #333;
97
+ font-size: 11px;
98
+ text-transform: uppercase;
99
+ letter-spacing: 0.5px;
100
+ }
101
+
102
+ .label {
103
+ padding: 6px 10px;
104
+ margin: 4px 0;
105
+ border-radius: 6px;
106
+ position: relative;
107
+ transition: all 0.2s ease;
108
+ }
109
+
110
+ /* Prediction styles */
111
+ .prediction {
112
+ background: #f0f4ff;
113
+ border: 1px solid #d0deff;
114
+ }
115
+
116
+ .prediction.invalid {
117
+ background: #fff0f0;
118
+ border: 1px solid #ffcccc;
119
+ color: #cc0000;
120
+ text-decoration: line-through;
121
+ opacity: 0.7;
122
+ }
123
+
124
+ .prediction.match {
125
+ background: #e8f5e9;
126
+ border: 1px solid #a5d6a7;
127
+ }
128
+
129
+ .prediction.match::before {
130
+ content: "✓";
131
+ position: absolute;
132
+ left: -20px;
133
+ color: #4caf50;
134
+ font-weight: bold;
135
+ }
136
+
137
+ /* Ground truth styles */
138
+ .ground-truth {
139
+ background: #f5f5f5;
140
+ border: 1px solid #e0e0e0;
141
+ }
142
+
143
+ .ground-truth.matched {
144
+ background: #e8f5e9;
145
+ border: 1px solid #a5d6a7;
146
+ }
147
+
148
+ /* Match indicator */
149
+ .match-indicator {
150
+ display: inline-block;
151
+ margin-left: 8px;
152
+ padding: 2px 6px;
153
+ background: #4caf50;
154
+ color: white;
155
+ border-radius: 10px;
156
+ font-size: 10px;
157
+ font-weight: 600;
158
+ }
159
+
160
+ .controls {
161
+ text-align: center;
162
+ margin: 40px 0;
163
+ }
164
+
165
+ button {
166
+ background: #333;
167
+ color: white;
168
+ border: none;
169
+ padding: 12px 30px;
170
+ border-radius: 8px;
171
+ font-size: 14px;
172
+ cursor: pointer;
173
+ transition: all 0.2s ease;
174
+ font-weight: 500;
175
+ }
176
+
177
+ button:hover {
178
+ background: #555;
179
+ transform: translateY(-1px);
180
+ }
181
+
182
+ button:disabled {
183
+ background: #ddd;
184
+ cursor: not-allowed;
185
+ transform: none;
186
+ }
187
+
188
+ .loading {
189
+ text-align: center;
190
+ padding: 20px;
191
+ color: #666;
192
+ font-size: 14px;
193
+ }
194
+
195
+ .loading.hidden {
196
+ display: none;
197
+ }
198
+
199
+ .score-badge {
200
+ display: inline-block;
201
+ margin-top: 10px;
202
+ padding: 4px 12px;
203
+ background: #f0f0f0;
204
+ border-radius: 20px;
205
+ font-size: 12px;
206
+ color: #666;
207
+ }
208
+
209
+ .score-badge.good {
210
+ background: #e8f5e9;
211
+ color: #2e7d32;
212
+ }
213
+
214
+ .score-badge.poor {
215
+ background: #fff3e0;
216
+ color: #e65100;
217
+ }
218
+ </style>
219
+ </head>
220
+ <body>
221
+ <div class="header">
222
+ <h1>ICONCLASS Predictions vs Ground Truth</h1>
223
+ <div class="stats">
224
+ <span id="loadedCount">0</span> / <span id="totalCount">-</span> images
225
+ loaded
226
+ </div>
227
+ </div>
228
+
229
+ <div id="gallery" class="gallery"></div>
230
+
231
+ <div class="loading hidden" id="loading">Loading images...</div>
232
+
233
+ <div class="controls">
234
+ <button id="loadMore">Load More</button>
235
+ </div>
236
+
237
+ <script>
238
+ // Configuration
239
+ const DATASET = "davanstrien/iconclass-sft-predictions";
240
+ const CONFIG = "default";
241
+ const SPLIT = "test";
242
+ const PAGE_SIZE = 10;
243
+
244
+ // State
245
+ let currentOffset = 0;
246
+ let totalRows = null;
247
+ let isLoading = false;
248
+
249
+ async function loadDatasetPage() {
250
+ if (isLoading) return;
251
+
252
+ isLoading = true;
253
+ const loadingDiv = document.getElementById("loading");
254
+ loadingDiv.classList.remove("hidden");
255
+
256
+ try {
257
+ const response = await fetch(
258
+ `https://datasets-server.huggingface.co/rows?dataset=${DATASET}&config=${CONFIG}&split=${SPLIT}&offset=${currentOffset}&length=${PAGE_SIZE}`
259
+ );
260
+
261
+ if (!response.ok) {
262
+ throw new Error(`HTTP error! status: ${response.status}`);
263
+ }
264
+
265
+ const data = await response.json();
266
+
267
+ // Update stats
268
+ if (data.num_rows_total) {
269
+ totalRows = data.num_rows_total;
270
+ document.getElementById("totalCount").textContent = totalRows;
271
+ }
272
+
273
+ // Display rows
274
+ displayRows(data.rows);
275
+
276
+ // Update counter
277
+ currentOffset += data.rows.length;
278
+ document.getElementById("loadedCount").textContent = currentOffset;
279
+
280
+ // Update button
281
+ const loadMoreBtn = document.getElementById("loadMore");
282
+ if (currentOffset >= totalRows) {
283
+ loadMoreBtn.disabled = true;
284
+ loadMoreBtn.textContent = "All Images Loaded";
285
+ } else {
286
+ loadMoreBtn.textContent = `Load More (${
287
+ totalRows - currentOffset
288
+ } remaining)`;
289
+ }
290
+ } catch (error) {
291
+ console.error("Error:", error);
292
+ } finally {
293
+ isLoading = false;
294
+ loadingDiv.classList.add("hidden");
295
+ }
296
+ }
297
+
298
+ function displayRows(rows) {
299
+ const gallery = document.getElementById("gallery");
300
+
301
+ rows.forEach((item) => {
302
+ const row = item.row;
303
+
304
+ // Create card
305
+ const card = document.createElement("div");
306
+ card.className = "card";
307
+
308
+ // Add image
309
+ if (row.images && row.images.length > 0) {
310
+ const img = document.createElement("img");
311
+ img.src = row.images[0].src;
312
+ img.loading = "lazy";
313
+ card.appendChild(img);
314
+ }
315
+
316
+ // Create content
317
+ const content = document.createElement("div");
318
+ content.className = "card-content";
319
+
320
+ // Show raw prediction
321
+ if (row["iconclass-prediction"]) {
322
+ const rawDiv = document.createElement("div");
323
+ rawDiv.className = "raw-prediction";
324
+ rawDiv.textContent = row["iconclass-prediction"];
325
+ content.appendChild(rawDiv);
326
+ }
327
+
328
+ // Parse predictions and ground truth
329
+ const predictions = row["iconclass-predictions-parsed"] || [];
330
+ const groundTruth = row["iconclass-gt-parsed"] || [];
331
+
332
+ // Check for invalid labels (simple heuristic)
333
+ const invalidPredictions = predictions.map((pred) => {
334
+ // If it says "Not a valid iconclass label" or similar
335
+ return (
336
+ pred.toLowerCase().includes("not a valid") ||
337
+ pred.toLowerCase().includes("invalid")
338
+ );
339
+ });
340
+
341
+ // Find matches
342
+ const matches = predictions.filter((pred) =>
343
+ groundTruth.some(
344
+ (gt) =>
345
+ gt.toLowerCase().includes(pred.toLowerCase()) ||
346
+ pred.toLowerCase().includes(gt.toLowerCase())
347
+ )
348
+ );
349
+
350
+ // Create comparison view
351
+ const comparison = document.createElement("div");
352
+ comparison.className = "comparison";
353
+
354
+ // Predictions column
355
+ const predColumn = document.createElement("div");
356
+ predColumn.className = "column";
357
+
358
+ const predTitle = document.createElement("div");
359
+ predTitle.className = "column-title";
360
+ predTitle.textContent = "Predictions";
361
+ predColumn.appendChild(predTitle);
362
+
363
+ predictions.forEach((pred, idx) => {
364
+ const label = document.createElement("div");
365
+ const isInvalid = invalidPredictions[idx];
366
+ const isMatch = matches.includes(pred);
367
+
368
+ label.className = `label prediction ${isInvalid ? "invalid" : ""} ${
369
+ isMatch && !isInvalid ? "match" : ""
370
+ }`;
371
+ label.textContent = pred;
372
+ predColumn.appendChild(label);
373
+ });
374
+
375
+ // Ground truth column
376
+ const gtColumn = document.createElement("div");
377
+ gtColumn.className = "column";
378
+
379
+ const gtTitle = document.createElement("div");
380
+ gtTitle.className = "column-title";
381
+ gtTitle.textContent = "Ground Truth";
382
+ gtColumn.appendChild(gtTitle);
383
+
384
+ groundTruth.forEach((gt) => {
385
+ const label = document.createElement("div");
386
+ const isMatched = matches.some(
387
+ (pred) =>
388
+ gt.toLowerCase().includes(pred.toLowerCase()) ||
389
+ pred.toLowerCase().includes(gt.toLowerCase())
390
+ );
391
+ label.className = `label ground-truth ${
392
+ isMatched ? "matched" : ""
393
+ }`;
394
+ label.textContent = gt;
395
+ gtColumn.appendChild(label);
396
+ });
397
+
398
+ comparison.appendChild(predColumn);
399
+ comparison.appendChild(gtColumn);
400
+ content.appendChild(comparison);
401
+
402
+ // Add match score
403
+ const validPredictions = predictions.filter(
404
+ (_, idx) => !invalidPredictions[idx]
405
+ );
406
+ const matchScore =
407
+ validPredictions.length > 0
408
+ ? Math.round((matches.length / validPredictions.length) * 100)
409
+ : 0;
410
+
411
+ const scoreBadge = document.createElement("div");
412
+ scoreBadge.className = `score-badge ${
413
+ matchScore > 50 ? "good" : matchScore > 0 ? "poor" : ""
414
+ }`;
415
+ scoreBadge.textContent = `${matches.length}/${validPredictions.length} matches (${matchScore}%)`;
416
+ content.appendChild(scoreBadge);
417
+
418
+ card.appendChild(content);
419
+ gallery.appendChild(card);
420
+ });
421
+ }
422
+
423
+ // Event listeners
424
+ document
425
+ .getElementById("loadMore")
426
+ .addEventListener("click", loadDatasetPage);
427
+
428
+ // Infinite scroll
429
+ window.addEventListener("scroll", () => {
430
+ if (
431
+ window.innerHeight + window.scrollY >=
432
+ document.body.offsetHeight - 100
433
+ ) {
434
+ if (!isLoading && currentOffset < totalRows) {
435
+ loadDatasetPage();
436
+ }
437
+ }
438
+ });
439
+
440
+ // Load first page
441
+ loadDatasetPage();
442
+ </script>
443
+ </body>
444
  </html>