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

add models

Browse files
Files changed (1) hide show
  1. index.html +251 -158
index.html CHANGED
@@ -37,8 +37,8 @@
37
  class="bg-blue-100 text-blue-800 px-3 py-1.5 rounded-md mb-2 text-sm"
38
  >
39
  <p class="flex items-center gap-2">
40
- <i data-lucide="info"></i> Currently supporting dataset search only.
41
- Model search coming soon!
42
  </p>
43
  </div>
44
 
@@ -101,18 +101,28 @@
101
  class="flex flex-col sm:flex-row gap-4 items-start sm:items-center justify-between mb-4"
102
  >
103
  <p class="text-gray-600">
104
- Enter keywords to search through dataset descriptions. The
105
- search will automatically update as you type.
106
  </p>
107
- <select
108
- id="searchSortSelect"
109
- 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"
110
- onchange="handleSortChange('search')"
111
- >
112
- <option value="similarity">Sort by relevance</option>
113
- <option value="likes">Sort by likes</option>
114
- <option value="downloads">Sort by downloads</option>
115
- </select>
 
 
 
 
 
 
 
 
 
 
116
  </div>
117
  <div class="relative">
118
  <input
@@ -136,33 +146,43 @@
136
  class="flex flex-col sm:flex-row gap-4 items-start sm:items-center justify-between mb-4"
137
  >
138
  <p class="text-gray-600">
139
- Enter a dataset ID to find similar datasets. Popular datasets
140
- will appear as you type.
141
  </p>
142
- <select
143
- id="similarSortSelect"
144
- 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"
145
- onchange="handleSortChange('similar')"
146
- >
147
- <option value="similarity">Sort by relevance</option>
148
- <option value="likes">Sort by likes</option>
149
- <option value="downloads">Sort by downloads</option>
150
- </select>
 
 
 
 
 
 
 
 
 
 
151
  </div>
152
  <div class="flex gap-3">
153
  <div class="relative w-full">
154
  <input
155
  type="text"
156
- id="datasetInput"
157
  class="w-full p-3 border border-gray-200 rounded-lg"
158
- placeholder="e.g. openai/gsm8k"
159
  />
160
  <div
161
  id="suggestionsBox"
162
  class="hidden absolute w-full mt-1 bg-white border border-gray-200 rounded-lg shadow-lg z-10 max-h-60 overflow-y-auto"
163
  ></div>
164
  </div>
165
- <button onclick="findSimilarDatasets()" class="btn-primary">
166
  Find Similar
167
  </button>
168
  </div>
@@ -180,15 +200,14 @@
180
 
181
  <style>
182
  .tab-trigger.active {
183
- border-bottom-color: #3b82f6;
184
  color: #3b82f6;
185
  }
186
  </style>
187
 
188
  <script>
189
  // Configuration
190
- const API_URL =
191
- "https://davanstrien-huggingface-datasets-search-v2.hf.space";
192
  const MIN_SEARCH_LENGTH = 3;
193
  const DEBOUNCE_MS = 300;
194
  const RESULTS_PER_PAGE = 5;
@@ -199,9 +218,11 @@
199
  const URL_PARAMS = new URLSearchParams(window.location.search);
200
  const INITIAL_SEARCH = URL_PARAMS.get("q");
201
  const INITIAL_SIMILAR = URL_PARAMS.get("similar");
 
202
 
203
- // Add this variable with other configurations
204
  let currentSort = "similarity";
 
205
 
206
  // Initialize Lucide icons
207
  lucide.createIcons();
@@ -229,15 +250,19 @@
229
 
230
  // Create result card
231
  function createResultCard(result) {
 
 
 
 
 
 
232
  const cardHtml = `
233
  <div class="card bg-white p-4 sm:p-6 rounded-lg shadow hover:shadow-md transition-shadow">
234
  <div class="space-y-2 w-full">
235
  <div class="flex flex-col sm:flex-row sm:items-center justify-between gap-2">
236
  <div class="flex items-center gap-2">
237
- <i data-lucide="database" class="text-blue-500"></i>
238
- <h3 class="text-lg font-semibold">${
239
- result.dataset_id
240
- }</h3>
241
  </div>
242
  <div class="flex flex-wrap items-center gap-2">
243
  <div class="flex items-center gap-4 text-sm text-gray-500">
@@ -254,9 +279,7 @@
254
  ${(result.similarity * 100).toFixed(1)}% match
255
  </span>
256
  <button
257
- onclick="findSimilarFromResult('${
258
- result.dataset_id
259
- }')"
260
  class="flex items-center gap-1 text-sm text-blue-500 hover:text-blue-700"
261
  >
262
  <i data-lucide="arrow-right"></i>
@@ -266,36 +289,32 @@
266
  </div>
267
  <p class="text-sm text-gray-600">${result.summary}</p>
268
 
 
 
 
269
  <!-- Add preview section that starts hidden -->
270
- <div id="preview-section-${
271
- result.dataset_id
272
- }" class="mt-4 border-t pt-4 hidden">
273
  <button
274
- onclick="togglePreview('${result.dataset_id}')"
275
  class="flex items-center gap-2 text-sm text-gray-600 hover:text-gray-800"
276
  >
277
- <i data-lucide="chevron-right" id="preview-icon-${
278
- result.dataset_id
279
- }" class="transition-transform"></i>
280
  Preview Dataset
281
  </button>
282
- <div id="preview-content-${
283
- result.dataset_id
284
- }" class="hidden mt-4">
285
  <iframe
286
- src="https://huggingface.co/datasets/${
287
- result.dataset_id
288
- }/embed/viewer/default/train"
289
  frameborder="0"
290
  width="100%"
291
  height="560px"
292
  ></iframe>
293
  </div>
294
  </div>
 
 
 
295
 
296
- <a href="https://huggingface.co/datasets/${
297
- result.dataset_id
298
- }"
299
  target="_blank"
300
  class="inline-flex items-center gap-1 text-sm text-blue-500 hover:text-blue-700 mt-2">
301
  <i data-lucide="external-link" class="w-4 h-4"></i>
@@ -305,8 +324,10 @@
305
  </div>
306
  `;
307
 
308
- // After rendering the card, check if preview is available
309
- checkDatasetValidity(result.dataset_id);
 
 
310
 
311
  return cardHtml;
312
  }
@@ -349,83 +370,62 @@
349
  window.history.pushState({}, "", newURL);
350
  }
351
 
352
- // Modify the searchDatasets function
353
- const searchDatasets = _.debounce(async (query, page = 1) => {
354
- if (query.length < MIN_SEARCH_LENGTH) {
355
- document.getElementById("resultsContainer").innerHTML = "";
356
- updateURL({ q: null, similar: null }); // Clear URL params
357
- return;
358
- }
359
-
360
- document.getElementById("searchLoader").classList.remove("hidden");
361
- document.getElementById("errorMessage").classList.add("hidden");
362
-
363
- // Update URL with search query
364
- updateURL({ q: query, similar: null });
365
-
366
- try {
367
- const response = await fetch(
368
- `${API_URL}/search/datasets?query=${encodeURIComponent(query)}&k=${
369
- RESULTS_PER_PAGE * page
370
- }`
371
- );
372
- if (!response.ok) throw new Error("Search failed");
373
-
374
- const data = await response.json();
375
- console.log("Search results:", data);
376
- displayResults(data.results, page);
377
- } catch (error) {
378
- console.error("Search error:", error);
379
- showError("Failed to perform search. Please try again.");
380
- } finally {
381
- document.getElementById("searchLoader").classList.add("hidden");
382
- }
383
  }, DEBOUNCE_MS);
384
 
385
- // Cache for trending datasets
386
- let trendingDatasetsCache = null;
387
- let cacheTimestamp = null;
 
 
 
 
 
 
388
  const CACHE_DURATION = 1000 * 60 * 15; // 15 minutes
389
 
390
- async function fetchTrendingDatasets() {
391
  if (
392
- trendingDatasetsCache &&
393
- cacheTimestamp &&
394
- Date.now() - cacheTimestamp < CACHE_DURATION
395
  ) {
396
- return trendingDatasetsCache;
397
  }
398
 
399
  try {
400
- const response = await fetch("https://huggingface.co/api/datasets");
401
  const data = await response.json();
402
 
403
- // Just take the first 20 dataset IDs since they're already sorted
404
- const trendingDatasets = data
405
  .slice(0, 20)
406
- .map((dataset) => dataset.id);
407
 
408
- trendingDatasetsCache = trendingDatasets;
409
- cacheTimestamp = Date.now();
410
- return trendingDatasets;
411
  } catch (error) {
412
- console.error("Error fetching trending datasets:", error);
413
  return [];
414
  }
415
  }
416
 
417
- function displaySuggestions(datasets, suggestionsBox) {
418
- if (datasets.length > 0) {
419
- suggestionsBox.innerHTML = datasets
 
420
  .map(
421
- (datasetId) => `
422
  <div
423
  class="p-3 hover:bg-gray-50 cursor-pointer border-b last:border-b-0"
424
- onclick="selectSuggestion('${datasetId}')"
425
  >
426
  <div class="flex items-center gap-2">
427
- <i data-lucide="database" class="w-4 h-4 text-blue-500"></i>
428
- <span>${datasetId}</span>
429
  </div>
430
  </div>
431
  `
@@ -438,22 +438,22 @@
438
  }
439
  }
440
 
441
- function selectSuggestion(dataset) {
442
- const datasetInput = document.getElementById("datasetInput");
443
  const suggestionsBox = document.getElementById("suggestionsBox");
444
 
445
- datasetInput.value = dataset;
446
  suggestionsBox.classList.add("hidden");
447
- findSimilarDatasets();
448
  }
449
 
450
- // Modify the findSimilarDatasets function
451
- async function findSimilarDatasets(page = 1) {
452
- const datasetId = document.getElementById("datasetInput").value;
453
- if (!datasetId) return;
454
 
455
- // Update URL with similar dataset ID
456
- updateURL({ similar: datasetId, q: null });
457
 
458
  const similarLoader = document.getElementById("similarLoader");
459
  if (similarLoader) {
@@ -462,17 +462,21 @@
462
  document.getElementById("errorMessage").classList.add("hidden");
463
 
464
  try {
 
 
 
 
465
  const response = await fetch(
466
- `${API_URL}/similarity/datasets?dataset_id=${encodeURIComponent(
467
- datasetId
468
- )}&k=${RESULTS_PER_PAGE * page}`
469
  );
470
  if (!response.ok) throw new Error("Similarity search failed");
471
 
472
  const data = await response.json();
473
  displayResults(data.results, page);
474
  } catch (error) {
475
- showError("Failed to find similar datasets. Please try again.");
476
  } finally {
477
  if (similarLoader) {
478
  similarLoader.classList.add("hidden");
@@ -530,14 +534,18 @@
530
  </div>`
531
  : results.length >= MAX_RESULTS
532
  ? `<div class="text-center mt-4 p-6 bg-blue-50 rounded-lg">
533
- <p class="text-gray-700 mb-3">You've reached the end of our dataset journey! (${MAX_RESULTS} results)</p>
534
- <p class="text-gray-600 mb-4">Can't find what you're looking for? Why not create and share your own dataset?</p>
535
  <div class="flex items-center justify-center gap-4">
536
- <a href="https://huggingface.co/docs/datasets/upload_dataset"
 
 
 
 
537
  target="_blank"
538
  class="inline-flex items-center gap-2 text-blue-500 hover:text-blue-700">
539
  <i data-lucide="external-link"></i>
540
- Learn how to share your dataset on Hugging Face
541
  </a>
542
  <button
543
  onclick="shareResults()"
@@ -572,28 +580,32 @@
572
  // Event listeners
573
  document
574
  .getElementById("searchInput")
575
- .addEventListener("input", (e) => searchDatasets(e.target.value));
576
  document
577
- .getElementById("datasetInput")
578
  .addEventListener("keydown", (e) => {
579
- if (e.key === "Enter") findSimilarDatasets();
580
  });
581
 
582
  // Update the findSimilarFromResult function
583
- function findSimilarFromResult(datasetId) {
584
  // Switch to the similar tab
585
  switchTab("similar");
586
 
587
- // Set the dataset ID in the input without triggering the focus event
588
- const datasetInput = document.getElementById("datasetInput");
589
- datasetInput.value = datasetId;
 
 
 
 
590
 
591
  // Hide suggestions box explicitly
592
  const suggestionsBox = document.getElementById("suggestionsBox");
593
  suggestionsBox.classList.add("hidden");
594
 
595
  // Trigger the search
596
- findSimilarDatasets();
597
  }
598
 
599
  // Add accordion functionality
@@ -614,9 +626,9 @@
614
 
615
  if (activeTab === "searchTab") {
616
  const searchQuery = document.getElementById("searchInput").value;
617
- searchDatasets(searchQuery, currentPage);
618
  } else {
619
- findSimilarDatasets(currentPage);
620
  }
621
  }
622
 
@@ -642,11 +654,14 @@
642
  currentURL.searchParams.set("q", searchQuery);
643
  currentURL.searchParams.delete("similar");
644
  } else {
645
- const datasetId = document.getElementById("datasetInput").value;
646
- currentURL.searchParams.set("similar", datasetId);
647
  currentURL.searchParams.delete("q");
648
  }
649
 
 
 
 
650
  try {
651
  await navigator.clipboard.writeText(currentURL.toString());
652
 
@@ -680,37 +695,115 @@
680
  }
681
  }
682
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
683
  // Update the event listeners section
684
  document.addEventListener("DOMContentLoaded", async () => {
685
- const datasetInput = document.getElementById("datasetInput");
686
  let programmaticFocus = false;
687
 
 
 
 
 
 
 
 
688
  // Add input event listener for suggestions
689
- datasetInput.addEventListener("input", async (e) => {
690
  const suggestionsBox = document.getElementById("suggestionsBox");
691
  const value = e.target.value;
692
 
693
  if (!programmaticFocus) {
694
  if (!value) {
695
- // Show trending datasets when input is empty
696
- const trending = await fetchTrendingDatasets();
697
  displaySuggestions(trending, suggestionsBox);
698
  } else {
699
- // Filter trending datasets based on input
700
- const trending = await fetchTrendingDatasets();
701
- const filtered = trending.filter((dataset) =>
702
- dataset.toLowerCase().includes(value.toLowerCase())
703
  );
704
  displaySuggestions(filtered, suggestionsBox);
705
  }
706
  }
707
  });
708
 
709
- // Show trending datasets on focus only when not programmatically focused
710
- datasetInput.addEventListener("focus", async () => {
711
  if (!programmaticFocus) {
712
  const suggestionsBox = document.getElementById("suggestionsBox");
713
- const trending = await fetchTrendingDatasets();
714
  displaySuggestions(trending, suggestionsBox);
715
  }
716
  programmaticFocus = false;
@@ -720,11 +813,11 @@
720
  if (INITIAL_SEARCH) {
721
  switchTab("search");
722
  document.getElementById("searchInput").value = INITIAL_SEARCH;
723
- await searchDatasets(INITIAL_SEARCH);
724
  } else if (INITIAL_SIMILAR) {
725
  switchTab("similar");
726
- document.getElementById("datasetInput").value = INITIAL_SIMILAR;
727
- await findSimilarDatasets();
728
  }
729
  });
730
 
@@ -738,12 +831,12 @@
738
  if (activeTab === "searchTab") {
739
  const searchQuery = document.getElementById("searchInput").value;
740
  if (searchQuery.length >= MIN_SEARCH_LENGTH) {
741
- searchDatasets(searchQuery, 1);
742
  }
743
  } else {
744
- const datasetId = document.getElementById("datasetInput").value;
745
- if (datasetId) {
746
- findSimilarDatasets(1);
747
  }
748
  }
749
  }
 
37
  class="bg-blue-100 text-blue-800 px-3 py-1.5 rounded-md mb-2 text-sm"
38
  >
39
  <p class="flex items-center gap-2">
40
+ <i data-lucide="info"></i> Search for datasets and models using
41
+ semantic search!
42
  </p>
43
  </div>
44
 
 
101
  class="flex flex-col sm:flex-row gap-4 items-start sm:items-center justify-between mb-4"
102
  >
103
  <p class="text-gray-600">
104
+ Enter keywords to search through descriptions. The search will
105
+ automatically update as you type.
106
  </p>
107
+ <div class="flex gap-2">
108
+ <select
109
+ id="searchTypeSelect"
110
+ 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"
111
+ onchange="selectType(this.value)"
112
+ >
113
+ <option value="datasets">Datasets</option>
114
+ <option value="models">Models</option>
115
+ </select>
116
+ <select
117
+ id="searchSortSelect"
118
+ 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"
119
+ onchange="handleSortChange('search')"
120
+ >
121
+ <option value="similarity">Sort by relevance</option>
122
+ <option value="likes">Sort by likes</option>
123
+ <option value="downloads">Sort by downloads</option>
124
+ </select>
125
+ </div>
126
  </div>
127
  <div class="relative">
128
  <input
 
146
  class="flex flex-col sm:flex-row gap-4 items-start sm:items-center justify-between mb-4"
147
  >
148
  <p class="text-gray-600">
149
+ Enter an ID to find similar resources. Popular items will appear
150
+ as you type.
151
  </p>
152
+ <div class="flex gap-2">
153
+ <select
154
+ id="similarTypeSelect"
155
+ 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"
156
+ onchange="selectType(this.value)"
157
+ >
158
+ <option value="datasets">Datasets</option>
159
+ <option value="models">Models</option>
160
+ </select>
161
+ <select
162
+ id="similarSortSelect"
163
+ 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"
164
+ onchange="handleSortChange('similar')"
165
+ >
166
+ <option value="similarity">Sort by relevance</option>
167
+ <option value="likes">Sort by likes</option>
168
+ <option value="downloads">Sort by downloads</option>
169
+ </select>
170
+ </div>
171
  </div>
172
  <div class="flex gap-3">
173
  <div class="relative w-full">
174
  <input
175
  type="text"
176
+ id="resourceInput"
177
  class="w-full p-3 border border-gray-200 rounded-lg"
178
+ placeholder="e.g. openai/gsm8k or meta-llama/Llama-2-7b"
179
  />
180
  <div
181
  id="suggestionsBox"
182
  class="hidden absolute w-full mt-1 bg-white border border-gray-200 rounded-lg shadow-lg z-10 max-h-60 overflow-y-auto"
183
  ></div>
184
  </div>
185
+ <button onclick="findSimilarResources()" class="btn-primary">
186
  Find Similar
187
  </button>
188
  </div>
 
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;
 
218
  const URL_PARAMS = new URLSearchParams(window.location.search);
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";
225
+ let currentType = INITIAL_TYPE;
226
 
227
  // Initialize Lucide icons
228
  lucide.createIcons();
 
250
 
251
  // Create result card
252
  function createResultCard(result) {
253
+ const isDataset = "dataset_id" in result;
254
+ const resourceId = isDataset ? result.dataset_id : result.model_id;
255
+ const resourceType = isDataset ? "datasets" : "models";
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">
 
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>
 
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>
 
324
  </div>
325
  `;
326
 
327
+ // After rendering the card, check if preview is available for datasets
328
+ if (isDataset) {
329
+ checkDatasetValidity(resourceId);
330
+ }
331
 
332
  return cardHtml;
333
  }
 
370
  window.history.pushState({}, "", newURL);
371
  }
372
 
373
+ // Modify the search function to handle both datasets and models
374
+ const searchResources = _.debounce(async (query, page = 1) => {
375
+ performSearch(query, page);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
376
  }, DEBOUNCE_MS);
377
 
378
+ // Cache for trending resources
379
+ let trendingResourcesCache = {
380
+ datasets: null,
381
+ models: null,
382
+ };
383
+ let cacheTimestamp = {
384
+ datasets: null,
385
+ models: null,
386
+ };
387
  const CACHE_DURATION = 1000 * 60 * 15; // 15 minutes
388
 
389
+ async function fetchTrendingResources(type) {
390
  if (
391
+ trendingResourcesCache[type] &&
392
+ cacheTimestamp[type] &&
393
+ Date.now() - cacheTimestamp[type] < CACHE_DURATION
394
  ) {
395
+ return trendingResourcesCache[type];
396
  }
397
 
398
  try {
399
+ const response = await fetch(`https://huggingface.co/api/${type}`);
400
  const data = await response.json();
401
 
402
+ // Just take the first 20 resource IDs since they're already sorted
403
+ const trendingResources = data
404
  .slice(0, 20)
405
+ .map((resource) => resource.id);
406
 
407
+ trendingResourcesCache[type] = trendingResources;
408
+ cacheTimestamp[type] = Date.now();
409
+ return trendingResources;
410
  } catch (error) {
411
+ console.error(`Error fetching trending ${type}:`, error);
412
  return [];
413
  }
414
  }
415
 
416
+ function displaySuggestions(resources, suggestionsBox) {
417
+ if (resources.length > 0) {
418
+ const resourceIcon = currentType === "datasets" ? "database" : "box";
419
+ suggestionsBox.innerHTML = resources
420
  .map(
421
+ (resourceId) => `
422
  <div
423
  class="p-3 hover:bg-gray-50 cursor-pointer border-b last:border-b-0"
424
+ onclick="selectSuggestion('${resourceId}')"
425
  >
426
  <div class="flex items-center gap-2">
427
+ <i data-lucide="${resourceIcon}" class="w-4 h-4 text-blue-500"></i>
428
+ <span>${resourceId}</span>
429
  </div>
430
  </div>
431
  `
 
438
  }
439
  }
440
 
441
+ function selectSuggestion(resource) {
442
+ const resourceInput = document.getElementById("resourceInput");
443
  const suggestionsBox = document.getElementById("suggestionsBox");
444
 
445
+ resourceInput.value = resource;
446
  suggestionsBox.classList.add("hidden");
447
+ findSimilarResources();
448
  }
449
 
450
+ // Modify the findSimilarResources function to handle both datasets and models
451
+ async function findSimilarResources(page = 1) {
452
+ const resourceId = document.getElementById("resourceInput").value;
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) {
 
462
  document.getElementById("errorMessage").classList.add("hidden");
463
 
464
  try {
465
+ const endpoint = `${API_URL}/similarity/${currentType}`;
466
+ const paramName =
467
+ currentType === "datasets" ? "dataset_id" : "model_id";
468
+
469
  const response = await fetch(
470
+ `${endpoint}?${paramName}=${encodeURIComponent(resourceId)}&k=${
471
+ RESULTS_PER_PAGE * page
472
+ }&sort_by=${currentSort}`
473
  );
474
  if (!response.ok) throw new Error("Similarity search failed");
475
 
476
  const data = await response.json();
477
  displayResults(data.results, page);
478
  } catch (error) {
479
+ showError(`Failed to find similar ${currentType}. Please try again.`);
480
  } finally {
481
  if (similarLoader) {
482
  similarLoader.classList.add("hidden");
 
534
  </div>`
535
  : results.length >= MAX_RESULTS
536
  ? `<div class="text-center mt-4 p-6 bg-blue-50 rounded-lg">
537
+ <p class="text-gray-700 mb-3">You've reached the end of our journey! (${MAX_RESULTS} results)</p>
538
+ <p class="text-gray-600 mb-4">Can't find what you're looking for? Why not create and share your own?</p>
539
  <div class="flex items-center justify-center gap-4">
540
+ <a href="https://huggingface.co/docs/${
541
+ currentType === "datasets"
542
+ ? "datasets/upload_dataset"
543
+ : "hub/upload"
544
+ }"
545
  target="_blank"
546
  class="inline-flex items-center gap-2 text-blue-500 hover:text-blue-700">
547
  <i data-lucide="external-link"></i>
548
+ Learn how to share on Hugging Face
549
  </a>
550
  <button
551
  onclick="shareResults()"
 
580
  // Event listeners
581
  document
582
  .getElementById("searchInput")
583
+ .addEventListener("input", (e) => searchResources(e.target.value));
584
  document
585
+ .getElementById("resourceInput")
586
  .addEventListener("keydown", (e) => {
587
+ if (e.key === "Enter") findSimilarResources();
588
  });
589
 
590
  // Update the findSimilarFromResult function
591
+ function findSimilarFromResult(resourceId, resourceType) {
592
  // Switch to the similar tab
593
  switchTab("similar");
594
 
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");
601
+ resourceInput.value = resourceId;
602
 
603
  // Hide suggestions box explicitly
604
  const suggestionsBox = document.getElementById("suggestionsBox");
605
  suggestionsBox.classList.add("hidden");
606
 
607
  // Trigger the search
608
+ findSimilarResources();
609
  }
610
 
611
  // Add accordion functionality
 
626
 
627
  if (activeTab === "searchTab") {
628
  const searchQuery = document.getElementById("searchInput").value;
629
+ searchResources(searchQuery, currentPage);
630
  } else {
631
+ findSimilarResources(currentPage);
632
  }
633
  }
634
 
 
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 {
666
  await navigator.clipboard.writeText(currentURL.toString());
667
 
 
695
  }
696
  }
697
 
698
+ // Modify the selectType function to be simpler
699
+ function selectType(type) {
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");
709
+ resourceInput.placeholder =
710
+ type === "datasets"
711
+ ? "e.g. openai/gsm8k"
712
+ : "e.g. meta-llama/Llama-2-7b";
713
+
714
+ // Clear results and reset page
715
+ currentPage = 1;
716
+ document.getElementById("resultsContainer").innerHTML = "";
717
+
718
+ // Re-run the current search with new type
719
+ const activeTab = document.querySelector(".tab-trigger.active").id;
720
+ if (activeTab === "searchTab") {
721
+ const searchQuery = document.getElementById("searchInput").value;
722
+ if (searchQuery.length >= MIN_SEARCH_LENGTH) {
723
+ performSearch(searchQuery, 1);
724
+ }
725
+ } else if (activeTab === "similarTab") {
726
+ const resourceId = document.getElementById("resourceInput").value;
727
+ if (resourceId) {
728
+ findSimilarResources(1);
729
+ }
730
+ }
731
+
732
+ // Update URL with the new type
733
+ updateURL({ type: currentType });
734
+ }
735
+
736
+ // Add a non-debounced version of the search function
737
+ async function performSearch(query, page = 1) {
738
+ if (query.length < MIN_SEARCH_LENGTH) {
739
+ document.getElementById("resultsContainer").innerHTML = "";
740
+ updateURL({ q: null, similar: null }); // Clear URL params
741
+ return;
742
+ }
743
+
744
+ document.getElementById("searchLoader").classList.remove("hidden");
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}`;
752
+ const response = await fetch(
753
+ `${endpoint}?query=${encodeURIComponent(query)}&k=${
754
+ RESULTS_PER_PAGE * page
755
+ }&sort_by=${currentSort}`
756
+ );
757
+ if (!response.ok) throw new Error("Search failed");
758
+
759
+ const data = await response.json();
760
+ displayResults(data.results, page);
761
+ } catch (error) {
762
+ console.error("Search error:", error);
763
+ showError("Failed to perform search. Please try again.");
764
+ } finally {
765
+ document.getElementById("searchLoader").classList.add("hidden");
766
+ }
767
+ }
768
+
769
  // Update the event listeners section
770
  document.addEventListener("DOMContentLoaded", async () => {
771
+ const resourceInput = document.getElementById("resourceInput");
772
  let programmaticFocus = false;
773
 
774
+ // Set initial type from URL
775
+ if (INITIAL_TYPE) {
776
+ document.getElementById("searchTypeSelect").value = INITIAL_TYPE;
777
+ document.getElementById("similarTypeSelect").value = INITIAL_TYPE;
778
+ currentType = INITIAL_TYPE;
779
+ }
780
+
781
  // Add input event listener for suggestions
782
+ resourceInput.addEventListener("input", async (e) => {
783
  const suggestionsBox = document.getElementById("suggestionsBox");
784
  const value = e.target.value;
785
 
786
  if (!programmaticFocus) {
787
  if (!value) {
788
+ // Show trending resources when input is empty
789
+ const trending = await fetchTrendingResources(currentType);
790
  displaySuggestions(trending, suggestionsBox);
791
  } else {
792
+ // Filter trending resources based on input
793
+ const trending = await fetchTrendingResources(currentType);
794
+ const filtered = trending.filter((resource) =>
795
+ resource.toLowerCase().includes(value.toLowerCase())
796
  );
797
  displaySuggestions(filtered, suggestionsBox);
798
  }
799
  }
800
  });
801
 
802
+ // Show trending resources on focus only when not programmatically focused
803
+ resourceInput.addEventListener("focus", async () => {
804
  if (!programmaticFocus) {
805
  const suggestionsBox = document.getElementById("suggestionsBox");
806
+ const trending = await fetchTrendingResources(currentType);
807
  displaySuggestions(trending, suggestionsBox);
808
  }
809
  programmaticFocus = false;
 
813
  if (INITIAL_SEARCH) {
814
  switchTab("search");
815
  document.getElementById("searchInput").value = INITIAL_SEARCH;
816
+ await searchResources(INITIAL_SEARCH);
817
  } else if (INITIAL_SIMILAR) {
818
  switchTab("similar");
819
+ document.getElementById("resourceInput").value = INITIAL_SIMILAR;
820
+ await findSimilarResources();
821
  }
822
  });
823
 
 
831
  if (activeTab === "searchTab") {
832
  const searchQuery = document.getElementById("searchInput").value;
833
  if (searchQuery.length >= MIN_SEARCH_LENGTH) {
834
+ searchResources(searchQuery, 1);
835
  }
836
  } else {
837
+ const resourceId = document.getElementById("resourceInput").value;
838
+ if (resourceId) {
839
+ findSimilarResources(1);
840
  }
841
  }
842
  }