Spaces:
Running
Running
RemiFabre commited on
Commit ·
b6c3044
1
Parent(s): 278d4d5
Fixed community dataset download
Browse files- marionette/main.py +85 -29
- marionette/static/main.js +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 |
-
|
| 904 |
-
|
| 905 |
-
|
| 906 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 907 |
try:
|
| 908 |
-
|
| 909 |
-
|
| 910 |
-
|
| 911 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 912 |
|
| 913 |
-
|
| 914 |
-
|
| 915 |
-
|
| 916 |
-
|
| 917 |
-
|
| 918 |
-
|
| 919 |
-
|
| 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
|
| 927 |
-
repo_id =
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 928 |
if not repo_id:
|
| 929 |
continue
|
| 930 |
-
card =
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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
|
| 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}
|
| 760 |
-
: "No datasets
|
| 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 |
-
"
|
| 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 |
|