RemiFabre commited on
Commit
b6c3044
·
1 Parent(s): 278d4d5

Fixed community dataset download

Browse files
Files changed (3) hide show
  1. marionette/main.py +85 -29
  2. marionette/static/main.js +3 -3
  3. pyproject.toml +1 -1
marionette/main.py CHANGED
@@ -2,19 +2,20 @@ from __future__ import annotations
2
 
3
  import json
4
  import logging
 
5
  import re
6
  import shutil
7
  import threading
8
  import time
9
  from dataclasses import dataclass
10
  from datetime import datetime
11
- import platform
12
  from pathlib import Path
13
  from tempfile import TemporaryDirectory
14
  from textwrap import dedent
15
  from typing import Any
16
 
17
  import numpy as np
 
18
  from fastapi import HTTPException
19
  from pydantic import BaseModel, Field
20
 
@@ -49,6 +50,7 @@ DATASET_REGISTRY_FILENAME = "dataset_registry.json"
49
  DEFAULT_DATASET_LABEL = "Local dataset"
50
  COMMUNITY_DATASET_TAG = "reachy_mini_community_moves"
51
  MAX_COMMUNITY_DATASETS = 50
 
52
 
53
  logger = logging.getLogger(__name__)
54
 
@@ -900,37 +902,58 @@ class Marionette(ReachyMiniApp):
900
  return entry
901
 
902
  def _list_community_datasets(self) -> list[dict[str, Any]]:
903
- self._ensure_hf_backend("browse community datasets.")
904
- api = HfApi()
905
- dataset_filter = None
906
- if DatasetFilter is not None:
 
 
 
 
 
 
 
907
  try:
908
- dataset_filter = DatasetFilter(tags=[COMMUNITY_DATASET_TAG])
909
- except Exception: # pragma: no cover - incompatible hub version
910
- logger.debug("DatasetFilter unavailable, falling back to search parameter.")
911
- dataset_filter = None
 
 
 
 
 
 
 
 
912
 
913
- logger.info("Listing community datasets for tag %s", COMMUNITY_DATASET_TAG)
914
- try:
915
- datasets = api.list_datasets(
916
- filter=dataset_filter,
917
- search=None if dataset_filter else f"tag:{COMMUNITY_DATASET_TAG}",
918
- limit=MAX_COMMUNITY_DATASETS,
919
- full=True,
920
- )
921
- except Exception as exc: # pragma: no cover - network failure
922
- logger.exception("Unable to list community datasets")
923
- raise HTTPException(status_code=502, detail=f"Unable to list datasets: {exc}") from exc
924
 
925
  results = []
926
- for item in datasets:
927
- repo_id = getattr(item, "id", None) or getattr(item, "repo_id", None)
 
 
 
 
 
928
  if not repo_id:
929
  continue
930
- card = getattr(item, "cardData", None) or {}
 
 
 
 
 
931
  pretty = card.get("pretty_name") or repo_id
932
- description = card.get("short_description") or card.get("description") or ""
933
- updated = getattr(item, "lastModified", None)
934
  if isinstance(updated, datetime):
935
  updated_str = updated.isoformat()
936
  else:
@@ -941,15 +964,48 @@ class Marionette(ReachyMiniApp):
941
  "repo_id": repo_id,
942
  "pretty_name": pretty,
943
  "description": description,
944
- "author": getattr(item, "author", None),
945
- "likes": getattr(item, "likes", None),
946
- "downloads": getattr(item, "downloads", None),
947
  "last_modified": updated_str,
948
- "tags": getattr(item, "tags", None),
949
  }
950
  )
951
  return results
952
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
953
  def _build_hf_readme(
954
  self,
955
  dataset_entry: DatasetEntry,
 
2
 
3
  import json
4
  import logging
5
+ import platform
6
  import re
7
  import shutil
8
  import threading
9
  import time
10
  from dataclasses import dataclass
11
  from datetime import datetime
 
12
  from pathlib import Path
13
  from tempfile import TemporaryDirectory
14
  from textwrap import dedent
15
  from typing import Any
16
 
17
  import numpy as np
18
+ import requests
19
  from fastapi import HTTPException
20
  from pydantic import BaseModel, Field
21
 
 
50
  DEFAULT_DATASET_LABEL = "Local dataset"
51
  COMMUNITY_DATASET_TAG = "reachy_mini_community_moves"
52
  MAX_COMMUNITY_DATASETS = 50
53
+ HF_DATASETS_API_URL = "https://huggingface.co/api/datasets"
54
 
55
  logger = logging.getLogger(__name__)
56
 
 
902
  return entry
903
 
904
  def _list_community_datasets(self) -> list[dict[str, Any]]:
905
+ datasets: list[Any] = self._fetch_community_datasets_http()
906
+ if not datasets and HfApi is not None:
907
+ dataset_filter = None
908
+ if DatasetFilter is not None:
909
+ try:
910
+ dataset_filter = DatasetFilter(tags=[COMMUNITY_DATASET_TAG])
911
+ except Exception: # pragma: no cover - incompatible hub version
912
+ logger.debug("DatasetFilter unavailable, falling back to text search.")
913
+ dataset_filter = None
914
+ search_query = None if dataset_filter else COMMUNITY_DATASET_TAG
915
+ logger.info("Listing community datasets via HfApi for tag %s", COMMUNITY_DATASET_TAG)
916
  try:
917
+ api = HfApi()
918
+ datasets = api.list_datasets(
919
+ filter=dataset_filter,
920
+ search=search_query,
921
+ limit=MAX_COMMUNITY_DATASETS,
922
+ full=True,
923
+ )
924
+ except Exception as exc: # pragma: no cover - network failure
925
+ logger.warning("HfApi dataset listing failed: %s", exc)
926
+ datasets = []
927
+ if not datasets:
928
+ raise HTTPException(status_code=502, detail="Unable to list community datasets from Hugging Face.")
929
 
930
+ filtered_items: list[Any] = []
931
+ for item in datasets:
932
+ tags = getattr(item, "tags", None) or item.get("tags") if isinstance(item, dict) else []
933
+ if tags and COMMUNITY_DATASET_TAG in tags:
934
+ filtered_items.append(item)
935
+ if not filtered_items:
936
+ filtered_items = datasets
 
 
 
 
937
 
938
  results = []
939
+ for item in filtered_items:
940
+ repo_id = (
941
+ getattr(item, "id", None)
942
+ or getattr(item, "repo_id", None)
943
+ or (item.get("id") if isinstance(item, dict) else None)
944
+ or (item.get("repo_id") if isinstance(item, dict) else None)
945
+ )
946
  if not repo_id:
947
  continue
948
+ card = (
949
+ getattr(item, "cardData", None)
950
+ or getattr(item, "card_data", None)
951
+ or (item.get("cardData") if isinstance(item, dict) else None)
952
+ or {}
953
+ )
954
  pretty = card.get("pretty_name") or repo_id
955
+ description = card.get("short_description") or card.get("description") or item.get("description", "")
956
+ updated = getattr(item, "lastModified", None) or item.get("lastModified")
957
  if isinstance(updated, datetime):
958
  updated_str = updated.isoformat()
959
  else:
 
964
  "repo_id": repo_id,
965
  "pretty_name": pretty,
966
  "description": description,
967
+ "author": getattr(item, "author", None) or item.get("author"),
968
+ "likes": getattr(item, "likes", None) or item.get("likes"),
969
+ "downloads": getattr(item, "downloads", None) or item.get("downloads"),
970
  "last_modified": updated_str,
971
+ "tags": getattr(item, "tags", None) or item.get("tags"),
972
  }
973
  )
974
  return results
975
 
976
+ def _fetch_community_datasets_http(self) -> list[dict[str, Any]]:
977
+ base_params = {
978
+ "limit": MAX_COMMUNITY_DATASETS,
979
+ "full": "true",
980
+ "sort": "downloads",
981
+ "direction": "-1",
982
+ }
983
+ attempts = [
984
+ ("tag_search", {"search": f"tag:{COMMUNITY_DATASET_TAG}"}),
985
+ ("keyword_search", {"search": COMMUNITY_DATASET_TAG}),
986
+ ("legacy_filter", {"filter": COMMUNITY_DATASET_TAG}),
987
+ ]
988
+ for label, extra_params in attempts:
989
+ params = base_params.copy()
990
+ params.update(extra_params)
991
+ try:
992
+ logger.debug("HTTP dataset listing (%s) with params %s", label, params)
993
+ resp = requests.get(
994
+ HF_DATASETS_API_URL,
995
+ params=params,
996
+ timeout=30,
997
+ )
998
+ resp.raise_for_status()
999
+ data = resp.json()
1000
+ if isinstance(data, list) and data:
1001
+ logger.info("Fetched %d community datasets via HTTP (%s)", len(data), label)
1002
+ return data
1003
+ if isinstance(data, list):
1004
+ logger.debug("HTTP dataset listing (%s) returned zero results.", label)
1005
+ except Exception as exc:
1006
+ logger.warning("HTTP dataset listing (%s) failed: %s", label, exc)
1007
+ return []
1008
+
1009
  def _build_hf_readme(
1010
  self,
1011
  dataset_entry: DatasetEntry,
marionette/static/main.js CHANGED
@@ -670,7 +670,7 @@ function renderCommunityDatasets(datasets) {
670
  communityList.innerHTML = "";
671
  if (!datasets.length) {
672
  const li = document.createElement("li");
673
- li.textContent = "No community datasets found yet.";
674
  communityList.appendChild(li);
675
  return;
676
  }
@@ -756,8 +756,8 @@ async function fetchCommunityDatasets() {
756
  renderCommunityDatasets(communityDatasets);
757
  if (communityStatus) {
758
  communityStatus.textContent = communityDatasets.length
759
- ? `Found ${communityDatasets.length} datasets.`
760
- : "No datasets published yet.";
761
  }
762
  } catch (error) {
763
  console.error("Community fetch error:", error);
 
670
  communityList.innerHTML = "";
671
  if (!datasets.length) {
672
  const li = document.createElement("li");
673
+ li.textContent = "No community datasets found for #reachy_mini_community_moves.";
674
  communityList.appendChild(li);
675
  return;
676
  }
 
756
  renderCommunityDatasets(communityDatasets);
757
  if (communityStatus) {
758
  communityStatus.textContent = communityDatasets.length
759
+ ? `Found ${communityDatasets.length} dataset${communityDatasets.length === 1 ? "" : "s"} tagged #reachy_mini_community_moves.`
760
+ : "No datasets tagged #reachy_mini_community_moves yet.";
761
  }
762
  } catch (error) {
763
  console.error("Community fetch error:", error);
pyproject.toml CHANGED
@@ -12,7 +12,7 @@ requires-python = ">=3.10"
12
  dependencies = [
13
  "reachy-mini",
14
  "soundfile",
15
- "huggingface_hub",
16
  ]
17
  keywords = ["reachy-mini-app"]
18
 
 
12
  dependencies = [
13
  "reachy-mini",
14
  "soundfile",
15
+ "huggingface-hub==0.34.4",
16
  ]
17
  keywords = ["reachy-mini-app"]
18