Skip to content

Commit 48b591a

Browse files
committed
feat: map local dataset names to hub names in download commands
1 parent 17b68cf commit 48b591a

4 files changed

Lines changed: 109 additions & 8 deletions

File tree

docs/js/app.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import SelectionPanelManager from './modules/selection-panel.js';
1313
import UIUtils from './modules/ui-utils.js';
1414
import EventHandlers from './modules/event-handlers.js';
1515
import RobotAliasManager from './modules/robot-aliases.js';
16+
import HubDatasetNamesManager from './modules/hub-dataset-names.js';
1617
import ErrorNotifier from './modules/error-notifier.js';
1718
import DownloadManager from './modules/download-manager.js';
1819
import NewsMenu from './modules/news-menu.js';
@@ -70,8 +71,9 @@ class Application {
7071
console.warn('[APP] Failed to load download stats:', err);
7172
});
7273

73-
// Load robot alias map (non-blocking for core data, but awaited before UI init)
74+
// Load robot alias map and hub dataset name mappings before UI init
7475
await RobotAliasManager.load(this.config);
76+
await HubDatasetNamesManager.load(this.config);
7577

7678
// Load datasets
7779
const loadingProgress = document.getElementById('loadingProgress');

docs/js/config/config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"assets": {
33
"useLocalAssets": false,
44
"localAssetsPath": "../pageAssets",
5-
"defaultRemoteAssetsRoot": "https://huggingface.co/datasets/RoboCOIN/pageAssets/resolve/main"
5+
"defaultRemoteAssetsRoot": "https://huggingface.co/datasets/RoboCOIN/pageAssets/tree/main"
66
},
77
"downloadCommand": {
88
"command": "robocoin-download",

docs/js/modules/config.js

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
* @description Centralized configuration management for the RoboCOIN application
44
*/
55

6+
import HubDatasetNamesManager from './hub-dataset-names.js';
7+
68
/**
79
* @typedef {Object} GridConfig
810
* @property {number} minCardWidth - Minimum card width in pixels
@@ -190,7 +192,11 @@ class ConfigManager {
190192
return fallback;
191193
}
192194

193-
return normalized;
195+
// HuggingFace browser URLs use /tree/main; raw file fetches need /resolve/main.
196+
if (/huggingface\.co\/datasets\/[^/]+\/[^/]+$/i.test(normalized)) {
197+
return `${normalized}/resolve/main`;
198+
}
199+
return normalized.replace(/\/tree\/main$/i, '/resolve/main');
194200
}
195201

196202
/**
@@ -290,7 +296,9 @@ class ConfigManager {
290296
assets: {
291297
useLocalAssets: this.getJsonValue('assets.useLocalAssets', false),
292298
localAssetsPath: this.getJsonValue('assets.localAssetsPath', '../robocoin_datamanager_assets'),
293-
defaultRemoteAssetsRoot: this.getJsonValue('assets.defaultRemoteAssetsRoot', 'https://huggingface.co/datasets/RogersPyke/robocoin_datamanager_assets/resolve/main')
299+
defaultRemoteAssetsRoot: this.getJsonValue('assets.defaultRemoteAssetsRoot', 'https://huggingface.co/datasets/RogersPyke/robocoin_datamanager_assets/resolve/main'),
300+
useBundledConsolidated: this.getJsonValue('assets.useBundledConsolidated', false),
301+
bundledConsolidatedPath: this.getJsonValue('assets.bundledConsolidatedPath', './assets/info/consolidated_datasets.json')
294302
},
295303
layout: {
296304
contentPadding: getValue('--content-padding', 'defaults.layout.contentPadding', 12)
@@ -347,7 +355,8 @@ class ConfigManager {
347355
assetsRoot,
348356
info: infoPath, // JSON index files following standard structure
349357
datasetInfo: datasetInfoPath,
350-
videos: videosPath
358+
videos: videosPath,
359+
bundledConsolidated: this.getJsonValue('assets.bundledConsolidatedPath', './assets/info/consolidated_datasets.json')
351360
},
352361
// Download command format configuration
353362
// Loaded from config.json for easy editing
@@ -509,7 +518,8 @@ class ConfigManager {
509518
*/
510519
static generateDownloadCommand(hub, datasets, datasetMap = undefined) {
511520
const config = this.getConfig().downloadCommand;
512-
521+
const hubDatasets = HubDatasetNamesManager.resolveHubNames(datasets, hub);
522+
513523
// First line: storage estimate comment (no blank line)
514524
const storageComment = this.buildRequiredStorageComment(datasets, datasetMap);
515525

@@ -521,8 +531,8 @@ class ConfigManager {
521531

522532
// Format: --ds_lists + each dataset on new line with continuation
523533
command += `${config.datasetsParam} `;
524-
if (datasets.length > 0) {
525-
const dsListContent = datasets.join(config.datasetSeparator);
534+
if (hubDatasets.length > 0) {
535+
const dsListContent = hubDatasets.join(config.datasetSeparator);
526536
command += `${dsListContent}${config.lineBreak}`;
527537
} else {
528538
command += `${config.lineBreak}`;
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import ConfigManager from './config.js';
2+
3+
/**
4+
* @file Hub Dataset Names Module
5+
* @description Maps local dataset names to hub-specific remote repository names
6+
* for robocoin-download --ds_lists (HF / ModelScope naming differs from UI).
7+
*/
8+
9+
class HubDatasetNamesManager {
10+
constructor() {
11+
/** @type {{ huggingface?: Record<string, string>, modelscope?: Record<string, string> }} */
12+
this.hubMaps = { huggingface: {}, modelscope: {} };
13+
14+
/** @type {boolean} */
15+
this.loaded = false;
16+
17+
/** @type {Promise<Object>|null} */
18+
this.loadingPromise = null;
19+
}
20+
21+
/**
22+
* @param {import('./config.js').ConfigManager['getConfig'] extends () => infer C ? C : any} config
23+
* @returns {Promise<Object>}
24+
*/
25+
async load(config) {
26+
if (this.loaded) {
27+
return this.hubMaps;
28+
}
29+
if (this.loadingPromise) {
30+
return this.loadingPromise;
31+
}
32+
33+
const infoPath =
34+
config?.paths?.info ||
35+
`${ConfigManager.getDefaultRemoteAssetsRoot()}/info`;
36+
const url = `${infoPath}/hub_dataset_names.json`;
37+
38+
this.loadingPromise = (async () => {
39+
try {
40+
const res = await fetch(url);
41+
if (!res.ok) {
42+
console.warn(`[HubDatasetNames] Mapping file not found at ${url}. Status: ${res.status}`);
43+
this.hubMaps = { huggingface: {}, modelscope: {} };
44+
} else {
45+
const data = await res.json();
46+
this.hubMaps = {
47+
huggingface: data?.huggingface && typeof data.huggingface === 'object' ? data.huggingface : {},
48+
modelscope: data?.modelscope && typeof data.modelscope === 'object' ? data.modelscope : {},
49+
};
50+
}
51+
} catch (err) {
52+
console.warn('[HubDatasetNames] Failed to load hub_dataset_names.json:', err);
53+
this.hubMaps = { huggingface: {}, modelscope: {} };
54+
} finally {
55+
this.loaded = true;
56+
}
57+
return this.hubMaps;
58+
})();
59+
60+
return this.loadingPromise;
61+
}
62+
63+
/**
64+
* Resolve local UI name to the name expected by robocoin-download on the given hub.
65+
* @param {string} localName
66+
* @param {string} hub - 'huggingface' or 'modelscope'
67+
* @returns {string}
68+
*/
69+
resolveHubName(localName, hub) {
70+
if (!localName) return localName;
71+
const map = this.hubMaps[hub];
72+
if (map && map[localName]) {
73+
return map[localName];
74+
}
75+
return localName;
76+
}
77+
78+
/**
79+
* @param {string[]} localNames
80+
* @param {string} hub
81+
* @returns {string[]}
82+
*/
83+
resolveHubNames(localNames, hub) {
84+
return localNames.map(name => this.resolveHubName(name, hub));
85+
}
86+
}
87+
88+
const instance = new HubDatasetNamesManager();
89+
export default instance;

0 commit comments

Comments
 (0)