davanstrien HF staff commited on
Commit
85c3e23
·
1 Parent(s): 5bdfd4f

add trending page and models

Browse files
Files changed (1) hide show
  1. index.html +266 -75
index.html CHANGED
@@ -91,6 +91,13 @@
91
  >
92
  <i data-lucide="arrow-right"></i> Find Similar
93
  </button>
 
 
 
 
 
 
 
94
  </div>
95
 
96
  <div id="searchContent" class="tab-content space-y-4">
@@ -189,6 +196,51 @@
189
  </div>
190
  </div>
191
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
192
  <div
193
  id="errorMessage"
194
  class="hidden mt-4 p-4 text-red-600 bg-red-50 rounded-md"
@@ -200,14 +252,38 @@
200
 
201
  <style>
202
  .tab-trigger.active {
203
- borderfi-bottom-color: #3b82f6;
204
  color: #3b82f6;
205
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
206
  </style>
207
 
208
  <script>
209
  // Configuration
210
- const API_URL = "http://localhost:8000";
 
211
  const MIN_SEARCH_LENGTH = 3;
212
  const DEBOUNCE_MS = 300;
213
  const RESULTS_PER_PAGE = 5;
@@ -219,6 +295,7 @@
219
  const INITIAL_SEARCH = URL_PARAMS.get("q");
220
  const INITIAL_SIMILAR = URL_PARAMS.get("similar");
221
  const INITIAL_TYPE = URL_PARAMS.get("type") || "datasets";
 
222
 
223
  // Add these variables with other configurations
224
  let currentSort = "similarity";
@@ -240,11 +317,21 @@
240
  document.getElementById(`${tabId}Content`).classList.remove("hidden");
241
  document.getElementById(`${tabId}Tab`).classList.add("active");
242
 
243
- // Clear URL parameters when switching tabs
 
 
 
 
 
 
 
 
244
  if (tabId === "search") {
245
- updateURL({ similar: null });
246
  } else if (tabId === "similar") {
247
- updateURL({ q: null });
 
 
248
  }
249
  }
250
 
@@ -256,72 +343,84 @@
256
  const resourceIcon = isDataset ? "database" : "box";
257
  const resourceUrl = `https://huggingface.co/${resourceType}/${resourceId}`;
258
 
 
 
 
 
 
 
259
  const cardHtml = `
260
- <div class="card bg-white p-4 sm:p-6 rounded-lg shadow hover:shadow-md transition-shadow">
261
- <div class="space-y-2 w-full">
262
- <div class="flex flex-col sm:flex-row sm:items-center justify-between gap-2">
263
- <div class="flex items-center gap-2">
264
- <i data-lucide="${resourceIcon}" class="text-blue-500"></i>
265
- <h3 class="text-lg font-semibold">${resourceId}</h3>
266
- </div>
267
- <div class="flex flex-wrap items-center gap-2">
268
- <div class="flex items-center gap-4 text-sm text-gray-500">
269
- <span class="flex items-center gap-1">
270
- <i data-lucide="heart" class="w-4 h-4"></i>
271
- ${result.likes}
272
- </span>
273
- <span class="flex items-center gap-1">
274
- <i data-lucide="download" class="w-4 h-4"></i>
275
- ${result.downloads}
276
- </span>
277
- </div>
278
- <span class="bg-blue-50 px-2 py-1 rounded text-sm">
279
- ${(result.similarity * 100).toFixed(1)}% match
280
- </span>
281
- <button
282
- onclick="findSimilarFromResult('${resourceId}', '${resourceType}')"
283
- class="flex items-center gap-1 text-sm text-blue-500 hover:text-blue-700"
284
- >
285
- <i data-lucide="arrow-right"></i>
286
- Find Similar
287
- </button>
288
- </div>
289
- </div>
290
- <p class="text-sm text-gray-600">${result.summary}</p>
291
-
292
- ${
293
- isDataset
294
- ? `
295
- <!-- Add preview section that starts hidden -->
296
- <div id="preview-section-${resourceId}" class="mt-4 border-t pt-4 hidden">
297
- <button
298
- onclick="togglePreview('${resourceId}')"
299
- class="flex items-center gap-2 text-sm text-gray-600 hover:text-gray-800"
300
- >
301
- <i data-lucide="chevron-right" id="preview-icon-${resourceId}" class="transition-transform"></i>
302
- Preview Dataset
303
- </button>
304
- <div id="preview-content-${resourceId}" class="hidden mt-4">
305
- <iframe
306
- src="https://huggingface.co/datasets/${resourceId}/embed/viewer/default/train"
307
- frameborder="0"
308
- width="100%"
309
- height="560px"
310
- ></iframe>
311
- </div>
312
- </div>
313
- `
314
- : ""
315
- }
316
-
317
- <a href="${resourceUrl}"
318
- target="_blank"
319
- class="inline-flex items-center gap-1 text-sm text-blue-500 hover:text-blue-700 mt-2">
320
- <i data-lucide="external-link" class="w-4 h-4"></i>
321
- View on Hugging Face Hub
322
- </a>
323
- </div>
324
- </div>
 
 
 
 
 
 
325
  `;
326
 
327
  // After rendering the card, check if preview is available for datasets
@@ -413,6 +512,62 @@
413
  }
414
  }
415
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
416
  function displaySuggestions(resources, suggestionsBox) {
417
  if (resources.length > 0) {
418
  const resourceIcon = currentType === "datasets" ? "database" : "box";
@@ -453,7 +608,12 @@
453
  if (!resourceId) return;
454
 
455
  // Update URL with similar resource ID and type
456
- updateURL({ similar: resourceId, q: null, type: currentType });
 
 
 
 
 
457
 
458
  const similarLoader = document.getElementById("similarLoader");
459
  if (similarLoader) {
@@ -595,6 +755,8 @@
595
  // Set the resource type
596
  currentType = resourceType;
597
  document.getElementById("similarTypeSelect").value = resourceType;
 
 
598
 
599
  // Set the resource ID in the input without triggering the focus event
600
  const resourceInput = document.getElementById("resourceInput");
@@ -653,13 +815,21 @@
653
  const searchQuery = document.getElementById("searchInput").value;
654
  currentURL.searchParams.set("q", searchQuery);
655
  currentURL.searchParams.delete("similar");
656
- } else {
657
  const resourceId = document.getElementById("resourceInput").value;
658
  currentURL.searchParams.set("similar", resourceId);
659
  currentURL.searchParams.delete("q");
 
 
 
 
 
 
 
660
  }
661
 
662
- // Always include the current type
 
663
  currentURL.searchParams.set("type", currentType);
664
 
665
  try {
@@ -700,9 +870,10 @@
700
  // Update the current type
701
  currentType = type;
702
 
703
- // Update both select elements to match
704
  document.getElementById("searchTypeSelect").value = type;
705
  document.getElementById("similarTypeSelect").value = type;
 
706
 
707
  // Update placeholder text for similar tab
708
  const resourceInput = document.getElementById("resourceInput");
@@ -727,6 +898,9 @@
727
  if (resourceId) {
728
  findSimilarResources(1);
729
  }
 
 
 
730
  }
731
 
732
  // Update URL with the new type
@@ -745,7 +919,12 @@
745
  document.getElementById("errorMessage").classList.add("hidden");
746
 
747
  // Update URL with search query and type
748
- updateURL({ q: query, similar: null, type: currentType });
 
 
 
 
 
749
 
750
  try {
751
  const endpoint = `${API_URL}/search/${currentType}`;
@@ -775,6 +954,7 @@
775
  if (INITIAL_TYPE) {
776
  document.getElementById("searchTypeSelect").value = INITIAL_TYPE;
777
  document.getElementById("similarTypeSelect").value = INITIAL_TYPE;
 
778
  currentType = INITIAL_TYPE;
779
  }
780
 
@@ -810,6 +990,10 @@
810
  });
811
 
812
  // Handle initial URL parameters
 
 
 
 
813
  if (INITIAL_SEARCH) {
814
  switchTab("search");
815
  document.getElementById("searchInput").value = INITIAL_SEARCH;
@@ -818,6 +1002,13 @@
818
  switchTab("similar");
819
  document.getElementById("resourceInput").value = INITIAL_SIMILAR;
820
  await findSimilarResources();
 
 
 
 
 
 
 
821
  }
822
  });
823
 
 
91
  >
92
  <i data-lucide="arrow-right"></i> Find Similar
93
  </button>
94
+ <button
95
+ onclick="switchTab('trending')"
96
+ id="trendingTab"
97
+ class="tab-trigger px-4 sm:px-6 py-3 flex items-center gap-2 border-b-2 border-transparent hover:bg-gray-50 transition-colors flex-1 justify-center"
98
+ >
99
+ <i data-lucide="trending-up"></i> Trending
100
+ </button>
101
  </div>
102
 
103
  <div id="searchContent" class="tab-content space-y-4">
 
196
  </div>
197
  </div>
198
 
199
+ <!-- Start: New Trending Tab Content -->
200
+ <div id="trendingContent" class="hidden tab-content space-y-6">
201
+ <div class="bg-white p-8 rounded-xl shadow-sm border border-gray-100">
202
+ <div
203
+ class="flex flex-col sm:flex-row gap-4 items-start sm:items-center justify-between mb-6"
204
+ >
205
+ <h2
206
+ class="text-xl font-semibold text-gray-800 flex items-center gap-2"
207
+ >
208
+ <i data-lucide="trending-up" class="text-blue-500"></i>
209
+ Trending on Hugging Face Hub
210
+ </h2>
211
+ <div class="flex gap-2">
212
+ <select
213
+ id="trendingTypeSelect"
214
+ class="text-sm border rounded-lg px-3 py-2 bg-white text-gray-700 focus:ring-2 focus:ring-blue-100 focus:border-blue-300 transition-all outline-none"
215
+ onchange="loadTrendingResources(this.value)"
216
+ >
217
+ <option value="datasets">Datasets</option>
218
+ <option value="models">Models</option>
219
+ </select>
220
+ <select
221
+ id="trendingLimitSelect"
222
+ class="text-sm border rounded-lg px-3 py-2 bg-white text-gray-700 focus:ring-2 focus:ring-blue-100 focus:border-blue-300 transition-all outline-none"
223
+ onchange="loadTrendingResources(document.getElementById('trendingTypeSelect').value)"
224
+ >
225
+ <option value="10">Show 10</option>
226
+ <option value="20">Show 20</option>
227
+ <option value="30">Show 30</option>
228
+ </select>
229
+ </div>
230
+ </div>
231
+
232
+ <div id="trendingLoader" class="flex justify-center py-6">
233
+ <i
234
+ data-lucide="loader-2"
235
+ class="animate-spin text-blue-500 w-8 h-8"
236
+ ></i>
237
+ </div>
238
+
239
+ <div id="trendingResults" class="space-y-4"></div>
240
+ </div>
241
+ </div>
242
+ <!-- End: New Trending Tab Content -->
243
+
244
  <div
245
  id="errorMessage"
246
  class="hidden mt-4 p-4 text-red-600 bg-red-50 rounded-md"
 
252
 
253
  <style>
254
  .tab-trigger.active {
255
+ border-bottom-color: #3b82f6;
256
  color: #3b82f6;
257
  }
258
+
259
+ .btn-primary {
260
+ background-color: #3b82f6;
261
+ color: white;
262
+ padding: 0.5rem 1rem;
263
+ border-radius: 0.5rem;
264
+ transition: background-color 0.2s;
265
+ }
266
+
267
+ .btn-primary:hover {
268
+ background-color: #2563eb;
269
+ }
270
+
271
+ /* Add card hover effect */
272
+ .resource-card {
273
+ transition: transform 0.2s, box-shadow 0.2s;
274
+ }
275
+
276
+ .resource-card:hover {
277
+ transform: translateY(-2px);
278
+ box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1),
279
+ 0 10px 10px -5px rgba(0, 0, 0, 0.04);
280
+ }
281
  </style>
282
 
283
  <script>
284
  // Configuration
285
+ const API_URL =
286
+ "https://davanstrien-huggingface-datasets-search-v2.hf.space";
287
  const MIN_SEARCH_LENGTH = 3;
288
  const DEBOUNCE_MS = 300;
289
  const RESULTS_PER_PAGE = 5;
 
295
  const INITIAL_SEARCH = URL_PARAMS.get("q");
296
  const INITIAL_SIMILAR = URL_PARAMS.get("similar");
297
  const INITIAL_TYPE = URL_PARAMS.get("type") || "datasets";
298
+ const INITIAL_TAB = URL_PARAMS.get("tab") || "search";
299
 
300
  // Add these variables with other configurations
301
  let currentSort = "similarity";
 
317
  document.getElementById(`${tabId}Content`).classList.remove("hidden");
318
  document.getElementById(`${tabId}Tab`).classList.add("active");
319
 
320
+ // Clear results container when switching to trending tab
321
+ if (tabId === "trending") {
322
+ document.getElementById("resultsContainer").innerHTML = "";
323
+ loadTrendingResources(
324
+ document.getElementById("trendingTypeSelect").value
325
+ );
326
+ }
327
+
328
+ // Update URL parameters when switching tabs
329
  if (tabId === "search") {
330
+ updateURL({ tab: "search", similar: null });
331
  } else if (tabId === "similar") {
332
+ updateURL({ tab: "similar", q: null });
333
+ } else if (tabId === "trending") {
334
+ updateURL({ tab: "trending", q: null, similar: null });
335
  }
336
  }
337
 
 
343
  const resourceIcon = isDataset ? "database" : "box";
344
  const resourceUrl = `https://huggingface.co/${resourceType}/${resourceId}`;
345
 
346
+ // Check if we're in the trending tab
347
+ const isTrendingTab =
348
+ document
349
+ .getElementById("trendingContent")
350
+ .classList.contains("hidden") === false;
351
+
352
  const cardHtml = `
353
+ <div class="card resource-card bg-white p-4 sm:p-6 rounded-lg shadow hover:shadow-md transition-shadow">
354
+ <div class="space-y-2 w-full">
355
+ <div class="flex flex-col sm:flex-row sm:items-center justify-between gap-2">
356
+ <div class="flex items-center gap-2">
357
+ <i data-lucide="${resourceIcon}" class="text-blue-500"></i>
358
+ <h3 class="text-lg font-semibold">${resourceId}</h3>
359
+ </div>
360
+ <div class="flex flex-wrap items-center gap-2">
361
+ <div class="flex items-center gap-4 text-sm text-gray-500">
362
+ <span class="flex items-center gap-1">
363
+ <i data-lucide="heart" class="w-4 h-4"></i>
364
+ ${result.likes}
365
+ </span>
366
+ <span class="flex items-center gap-1">
367
+ <i data-lucide="download" class="w-4 h-4"></i>
368
+ ${result.downloads}
369
+ </span>
370
+ </div>
371
+ ${
372
+ !isTrendingTab && result.similarity
373
+ ? `<span class="bg-blue-50 px-2 py-1 rounded text-sm">
374
+ ${(result.similarity * 100).toFixed(
375
+ 1
376
+ )}% match
377
+ </span>`
378
+ : ""
379
+ }
380
+ <button
381
+ onclick="findSimilarFromResult('${resourceId}', '${resourceType}')"
382
+ class="flex items-center gap-1 text-sm text-blue-500 hover:text-blue-700"
383
+ >
384
+ <i data-lucide="arrow-right"></i>
385
+ Find Similar
386
+ </button>
387
+ </div>
388
+ </div>
389
+ <p class="text-sm text-gray-600">${result.summary}</p>
390
+
391
+ ${
392
+ isDataset
393
+ ? `
394
+ <!-- Add preview section that starts hidden -->
395
+ <div id="preview-section-${resourceId}" class="mt-4 border-t pt-4 hidden">
396
+ <button
397
+ onclick="togglePreview('${resourceId}')"
398
+ class="flex items-center gap-2 text-sm text-gray-600 hover:text-gray-800"
399
+ >
400
+ <i data-lucide="chevron-right" id="preview-icon-${resourceId}" class="transition-transform"></i>
401
+ Preview Dataset
402
+ </button>
403
+ <div id="preview-content-${resourceId}" class="hidden mt-4">
404
+ <iframe
405
+ src="https://huggingface.co/datasets/${resourceId}/embed/viewer/default/train"
406
+ frameborder="0"
407
+ width="100%"
408
+ height="560px"
409
+ ></iframe>
410
+ </div>
411
+ </div>
412
+ `
413
+ : ""
414
+ }
415
+
416
+ <a href="${resourceUrl}"
417
+ target="_blank"
418
+ class="inline-flex items-center gap-1 text-sm text-blue-500 hover:text-blue-700 mt-2">
419
+ <i data-lucide="external-link" class="w-4 h-4"></i>
420
+ View on Hugging Face Hub
421
+ </a>
422
+ </div>
423
+ </div>
424
  `;
425
 
426
  // After rendering the card, check if preview is available for datasets
 
512
  }
513
  }
514
 
515
+ // New function to load trending resources from our API
516
+ async function loadTrendingResources(type) {
517
+ // Show loader and hide any errors
518
+ document.getElementById("trendingLoader").style.display = "flex";
519
+ document.getElementById("trendingResults").innerHTML = "";
520
+ document.getElementById("errorMessage").classList.add("hidden");
521
+
522
+ // Update selector to match current type
523
+ document.getElementById("trendingTypeSelect").value = type;
524
+
525
+ // Get filter values
526
+ const limit = document.getElementById("trendingLimitSelect").value;
527
+
528
+ try {
529
+ const endpoint = `${API_URL}/trending/${type}`;
530
+ const queryParams = new URLSearchParams({
531
+ limit: limit,
532
+ });
533
+
534
+ const response = await fetch(`${endpoint}?${queryParams}`);
535
+
536
+ if (!response.ok) {
537
+ throw new Error(`HTTP error! status: ${response.status}`);
538
+ }
539
+
540
+ const data = await response.json();
541
+
542
+ // Display trending results
543
+ const resultsContainer = document.getElementById("trendingResults");
544
+
545
+ if (data.results && data.results.length > 0) {
546
+ resultsContainer.innerHTML = data.results
547
+ .map((result) => createResultCard(result))
548
+ .join("");
549
+
550
+ // Initialize icons for the new cards
551
+ lucide.createIcons();
552
+ } else {
553
+ resultsContainer.innerHTML = `
554
+ <div class="text-center p-8 bg-gray-50 rounded-lg">
555
+ <p class="text-gray-500">No trending ${type} found matching your criteria</p>
556
+ </div>
557
+ `;
558
+ }
559
+ } catch (error) {
560
+ console.error("Error loading trending resources:", error);
561
+ document.getElementById("trendingResults").innerHTML = `
562
+ <div class="text-center p-8 bg-gray-50 rounded-lg">
563
+ <p class="text-red-500">Failed to load trending ${type}. Please try again later.</p>
564
+ </div>
565
+ `;
566
+ } finally {
567
+ document.getElementById("trendingLoader").style.display = "none";
568
+ }
569
+ }
570
+
571
  function displaySuggestions(resources, suggestionsBox) {
572
  if (resources.length > 0) {
573
  const resourceIcon = currentType === "datasets" ? "database" : "box";
 
608
  if (!resourceId) return;
609
 
610
  // Update URL with similar resource ID and type
611
+ updateURL({
612
+ similar: resourceId,
613
+ q: null,
614
+ type: currentType,
615
+ tab: "similar",
616
+ });
617
 
618
  const similarLoader = document.getElementById("similarLoader");
619
  if (similarLoader) {
 
755
  // Set the resource type
756
  currentType = resourceType;
757
  document.getElementById("similarTypeSelect").value = resourceType;
758
+ document.getElementById("searchTypeSelect").value = resourceType;
759
+ document.getElementById("trendingTypeSelect").value = resourceType;
760
 
761
  // Set the resource ID in the input without triggering the focus event
762
  const resourceInput = document.getElementById("resourceInput");
 
815
  const searchQuery = document.getElementById("searchInput").value;
816
  currentURL.searchParams.set("q", searchQuery);
817
  currentURL.searchParams.delete("similar");
818
+ } else if (activeTab === "similarTab") {
819
  const resourceId = document.getElementById("resourceInput").value;
820
  currentURL.searchParams.set("similar", resourceId);
821
  currentURL.searchParams.delete("q");
822
+ } else if (activeTab === "trendingTab") {
823
+ // For trending tab, save the selected options
824
+ const limit = document.getElementById("trendingLimitSelect").value;
825
+
826
+ currentURL.searchParams.set("limit", limit);
827
+ currentURL.searchParams.delete("q");
828
+ currentURL.searchParams.delete("similar");
829
  }
830
 
831
+ // Always include the current tab and type
832
+ currentURL.searchParams.set("tab", activeTab.replace("Tab", ""));
833
  currentURL.searchParams.set("type", currentType);
834
 
835
  try {
 
870
  // Update the current type
871
  currentType = type;
872
 
873
+ // Update all select elements to match
874
  document.getElementById("searchTypeSelect").value = type;
875
  document.getElementById("similarTypeSelect").value = type;
876
+ document.getElementById("trendingTypeSelect").value = type;
877
 
878
  // Update placeholder text for similar tab
879
  const resourceInput = document.getElementById("resourceInput");
 
898
  if (resourceId) {
899
  findSimilarResources(1);
900
  }
901
+ } else if (activeTab === "trendingTab") {
902
+ // Reload trending tab with new type
903
+ loadTrendingResources(type);
904
  }
905
 
906
  // Update URL with the new type
 
919
  document.getElementById("errorMessage").classList.add("hidden");
920
 
921
  // Update URL with search query and type
922
+ updateURL({
923
+ q: query,
924
+ similar: null,
925
+ type: currentType,
926
+ tab: "search",
927
+ });
928
 
929
  try {
930
  const endpoint = `${API_URL}/search/${currentType}`;
 
954
  if (INITIAL_TYPE) {
955
  document.getElementById("searchTypeSelect").value = INITIAL_TYPE;
956
  document.getElementById("similarTypeSelect").value = INITIAL_TYPE;
957
+ document.getElementById("trendingTypeSelect").value = INITIAL_TYPE;
958
  currentType = INITIAL_TYPE;
959
  }
960
 
 
990
  });
991
 
992
  // Handle initial URL parameters
993
+ if (INITIAL_TAB) {
994
+ switchTab(INITIAL_TAB);
995
+ }
996
+
997
  if (INITIAL_SEARCH) {
998
  switchTab("search");
999
  document.getElementById("searchInput").value = INITIAL_SEARCH;
 
1002
  switchTab("similar");
1003
  document.getElementById("resourceInput").value = INITIAL_SIMILAR;
1004
  await findSimilarResources();
1005
+ } else if (INITIAL_TAB === "trending") {
1006
+ // Load trending data with any URL parameters
1007
+ const limit = URL_PARAMS.get("limit") || 10;
1008
+
1009
+ document.getElementById("trendingLimitSelect").value = limit;
1010
+
1011
+ loadTrendingResources(currentType);
1012
  }
1013
  });
1014