| import React from "react"; |
| import ExploreGrid from "./explore-grid"; |
| import { |
| DatasetMetadata, |
| fetchJson, |
| formatStringWithVars, |
| } from "@/utils/parquetUtils"; |
| import { getDatasetVersion, buildVersionedUrl } from "@/utils/versionUtils"; |
| import { buildProxyUrl } from "@/utils/apiHelpers"; |
|
|
| export default async function ExplorePage({ |
| searchParams, |
| }: { |
| searchParams: { p?: string }; |
| }) { |
| let datasets: any[] = []; |
| let currentPage = 1; |
| let totalPages = 1; |
| try { |
| const res = await fetch( |
| "https://huggingface.co/api/datasets?sort=lastModified&filter=LeRobot", |
| { |
| cache: "no-store", |
| }, |
| ); |
| if (!res.ok) throw new Error("Failed to fetch datasets"); |
| const data = await res.json(); |
| const allDatasets = data.datasets || data; |
| |
| const page = parseInt(searchParams?.p || "1", 10); |
| const perPage = 30; |
|
|
| currentPage = page; |
| totalPages = Math.ceil(allDatasets.length / perPage); |
|
|
| const startIdx = (currentPage - 1) * perPage; |
| const endIdx = startIdx + perPage; |
| datasets = allDatasets.slice(startIdx, endIdx); |
| } catch { |
| return <div className="p-8 text-red-600">Failed to load datasets.</div>; |
| } |
|
|
| |
| const datasetWithVideos = ( |
| await Promise.all( |
| datasets.map(async (ds: any) => { |
| try { |
| const [org, dataset] = ds.id.split("/"); |
| const repoId = `${org}/${dataset}`; |
| |
| |
| let version: string; |
| try { |
| version = await getDatasetVersion(repoId); |
| } catch (err) { |
| |
| console.warn(`Skipping incompatible dataset ${repoId}: ${err instanceof Error ? err.message : err}`); |
| return null; |
| } |
| |
| const jsonUrl = buildVersionedUrl(repoId, version, "meta/info.json"); |
| const info = await fetchJson<DatasetMetadata>(jsonUrl); |
| const videoEntry = Object.entries(info.features).find( |
| ([, value]) => value.dtype === "video", |
| ); |
| let videoUrl: string | null = null; |
| if (videoEntry) { |
| const [key] = videoEntry; |
| const videoPath = formatStringWithVars(info.video_path, { |
| video_key: key, |
| episode_chunk: "0".padStart(3, "0"), |
| episode_index: "0".padStart(6, "0"), |
| }); |
| const url = buildVersionedUrl(repoId, version, videoPath); |
| |
| try { |
| const proxyUrl = await buildProxyUrl(url); |
| const headRes = await fetch(proxyUrl, { method: "HEAD" }); |
| if (headRes.ok) { |
| videoUrl = url; |
| } |
| } catch { |
| |
| } |
| } |
| return videoUrl ? { id: repoId, videoUrl } : null; |
| } catch (err) { |
| console.error( |
| `Failed to fetch or parse dataset info for ${ds.id}:`, |
| err, |
| ); |
| return null; |
| } |
| }), |
| ) |
| ).filter(Boolean) as { id: string; videoUrl: string | null }[]; |
|
|
| return ( |
| <ExploreGrid |
| datasets={datasetWithVideos} |
| currentPage={currentPage} |
| totalPages={totalPages} |
| /> |
| ); |
| } |
|
|