File size: 10,333 Bytes
81ba775
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
from __future__ import annotations

import os
import zipfile
from dataclasses import asdict, dataclass
from pathlib import Path, PurePosixPath
from typing import Callable, Iterable

from huggingface_hub import HfApi, hf_hub_download

from .config import (
    DATASET_SAMPLE_ROOT,
    MAX_DATASET_SAMPLE_ARCHIVE_BYTES,
    MAX_DATASET_SAMPLE_FILE_BYTES,
)

_AUDIO_EXTENSIONS = {".wav", ".flac", ".mp3", ".ogg", ".opus", ".m4a", ".aiff", ".aif"}
_ARCHIVE_EXTENSIONS = {".zip"}


@dataclass(frozen=True)
class DatasetSampleSpec:
    sample_id: str
    label: str
    repo_id: str
    repo_type: str
    revision: str
    license_id: str
    attribution: str
    source_url: str
    filename: str | None = None
    selector: str | None = None
    first_download_note: str = ""


@dataclass(frozen=True)
class ResolvedDatasetSample:
    sample_id: str
    label: str
    local_path: str
    repo_id: str
    repo_type: str
    revision: str
    repository_filename: str
    resolved_audio_filename: str
    license_id: str
    attribution: str
    source_url: str
    archive_extracted: bool
    size_bytes: int

    def to_json(self) -> str:
        return json.dumps(asdict(self), ensure_ascii=False, sort_keys=True)


DATASET_SAMPLE_SPECS: tuple[DatasetSampleSpec, ...] = (
    DatasetSampleSpec(
        sample_id="sonicsets-demo-mix",
        label="Dataset: SonicSets ensemble mix (CC BY-NC 4.0; first download may be large)",
        repo_id="sonicsets-data/Stems-Evaluation-Kit",
        repo_type="dataset",
        revision="main",
        license_id="CC-BY-NC-4.0",
        attribution="SonicSets High-Fidelity Stems Evaluation Kit",
        source_url="https://huggingface.co/datasets/sonicsets-data/Stems-Evaluation-Kit",
        selector="ensemble-mix",
        first_download_note=(
            "The repository is about 333 MB in total. SESA downloads one matching audio file when possible; "
            "if the repository exposes only an archive, the first download can approach the archive size."
        ),
    ),
    DatasetSampleSpec(
        sample_id="legacy-symphony-01",
        label="Hosted fallback: Symphony of Automation 01 (small)",
        repo_id="set-soft/audio_separation",
        repo_type="model",
        revision="main",
        filename="Audio_Examples/01-The_Symphony_of_Automation.mp3",
        license_id="MIT repository metadata",
        attribution="set-soft/audio_separation hosted audio example",
        source_url="https://huggingface.co/set-soft/audio_separation/tree/main/Audio_Examples",
        first_download_note="Small hosted fallback. The repository does not separately document audio-asset provenance.",
    ),
    DatasetSampleSpec(
        sample_id="legacy-symphony-04",
        label="Hosted fallback: Symphony of Automation 04 (small)",
        repo_id="set-soft/audio_separation",
        repo_type="model",
        revision="main",
        filename="Audio_Examples/04-The_Symphony_of_Automation.mp3",
        license_id="MIT repository metadata",
        attribution="set-soft/audio_separation hosted audio example",
        source_url="https://huggingface.co/set-soft/audio_separation/tree/main/Audio_Examples",
        first_download_note="Small hosted fallback. The repository does not separately document audio-asset provenance.",
    ),
    DatasetSampleSpec(
        sample_id="legacy-symphony-05",
        label="Hosted fallback: Symphony of Automation 05 (small)",
        repo_id="set-soft/audio_separation",
        repo_type="model",
        revision="main",
        filename="Audio_Examples/05-The_Symphony_of_Automation.mp3",
        license_id="MIT repository metadata",
        attribution="set-soft/audio_separation hosted audio example",
        source_url="https://huggingface.co/set-soft/audio_separation/tree/main/Audio_Examples",
        first_download_note="Small hosted fallback. The repository does not separately document audio-asset provenance.",
    ),
)

_SPEC_BY_ID = {item.sample_id: item for item in DATASET_SAMPLE_SPECS}
DEFAULT_DATASET_SAMPLE_ID = DATASET_SAMPLE_SPECS[0].sample_id


def dataset_sample_choices() -> list[tuple[str, str]]:
    return [(item.label, item.sample_id) for item in DATASET_SAMPLE_SPECS]


def dataset_sample_markdown(sample_id: str | None) -> str:
    spec = _SPEC_BY_ID.get(str(sample_id or ""))
    if not spec:
        return "Select a curated hosted sample, or upload a file to override it."
    note = f"  \n{spec.first_download_note}" if spec.first_download_note else ""
    return (
        f"**Source:** `{spec.repo_id}` · **license:** `{spec.license_id}`  \n"
        f"Attribution: {spec.attribution}.{note}"
    )


def _repo_token() -> str | bool:
    return os.environ.get("HF_TOKEN") or False


def _score_audio_candidate(filename: str, selector: str | None) -> int:
    path = PurePosixPath(filename)
    if path.suffix.lower() not in _AUDIO_EXTENSIONS:
        return -10_000
    text = str(path).lower().replace("-", "_").replace(" ", "_")
    score = 0
    if selector == "ensemble-mix":
        preferred = (
            ("full_ensemble_mix", 500),
            ("ensemble_mix", 450),
            ("full_mix", 400),
            ("mixture", 350),
            ("mix", 250),
            ("ensemble", 180),
        )
        for token, points in preferred:
            if token in text:
                score += points
        for token in ("isolated", "stem", "vocal", "vocals", "bass", "drum", "guitar", "harmony"):
            if token in text:
                score -= 220
        if "demo_01" in text or "demo01" in text or "/01" in text:
            score += 35
    score -= len(path.parts) * 2
    return score


def _choose_audio_filename(filenames: Iterable[str], selector: str | None) -> str | None:
    ranked = sorted(
        ((-_score_audio_candidate(name, selector), len(name), name) for name in filenames),
    )
    if not ranked:
        return None
    best_score = -ranked[0][0]
    if best_score <= 0:
        return None
    return ranked[0][2]


def _choose_archive_filename(filenames: Iterable[str]) -> str | None:
    archives = [name for name in filenames if PurePosixPath(name).suffix.lower() in _ARCHIVE_EXTENSIONS]
    if not archives:
        return None
    return sorted(archives, key=lambda value: (len(PurePosixPath(value).parts), len(value), value))[0]


def _safe_extract_zip(archive_path: Path, destination: Path) -> None:
    destination.mkdir(parents=True, exist_ok=True)
    root = destination.resolve()
    total_size = 0
    with zipfile.ZipFile(archive_path) as archive:
        for member in archive.infolist():
            if member.is_dir():
                continue
            total_size += max(0, int(member.file_size))
            if total_size > MAX_DATASET_SAMPLE_ARCHIVE_BYTES:
                raise RuntimeError("Dataset sample archive expands beyond the configured safety limit.")
            target = (destination / member.filename).resolve()
            if root not in target.parents:
                raise RuntimeError("Unsafe path found in dataset sample archive.")
        archive.extractall(destination)


def _resolve_from_archive(archive_path: Path, spec: DatasetSampleSpec) -> Path:
    extracted = archive_path.parent / "extracted"
    marker = extracted / ".complete"
    if not marker.is_file():
        _safe_extract_zip(archive_path, extracted)
        marker.write_text("ok\n", encoding="utf-8")
    candidates = [
        str(path.relative_to(extracted).as_posix())
        for path in extracted.rglob("*")
        if path.is_file() and path.suffix.lower() in _AUDIO_EXTENSIONS
    ]
    selected = _choose_audio_filename(candidates, spec.selector)
    if not selected:
        raise RuntimeError("No suitable mixture audio was found inside the dataset archive.")
    return extracted / selected


def resolve_dataset_sample(
    sample_id: str,
    *,
    api: HfApi | None = None,
    download_fn: Callable[..., str] = hf_hub_download,
) -> ResolvedDatasetSample:
    spec = _SPEC_BY_ID.get(str(sample_id or ""))
    if not spec:
        raise ValueError("Unknown dataset sample selection.")

    local_dir = DATASET_SAMPLE_ROOT / spec.sample_id
    local_dir.mkdir(parents=True, exist_ok=True)
    repository_filename = spec.filename
    if repository_filename is None:
        client = api or HfApi(token=_repo_token())
        filenames = client.list_repo_files(
            repo_id=spec.repo_id,
            repo_type=spec.repo_type,
            revision=spec.revision,
        )
        repository_filename = _choose_audio_filename(filenames, spec.selector)
        if repository_filename is None:
            repository_filename = _choose_archive_filename(filenames)
        if repository_filename is None:
            raise RuntimeError("No supported audio file or ZIP archive was found in the dataset repository.")

    downloaded = Path(
        download_fn(
            repo_id=spec.repo_id,
            repo_type=spec.repo_type,
            filename=repository_filename,
            revision=spec.revision,
            local_dir=local_dir,
            token=_repo_token(),
            etag_timeout=15,
        )
    )
    if not downloaded.is_file() or downloaded.stat().st_size <= 0:
        raise RuntimeError("Dataset sample download did not produce a readable file.")
    if downloaded.stat().st_size > MAX_DATASET_SAMPLE_FILE_BYTES:
        raise RuntimeError("Dataset sample download exceeds the configured file-size limit.")

    archive_extracted = downloaded.suffix.lower() in _ARCHIVE_EXTENSIONS
    local_audio = _resolve_from_archive(downloaded, spec) if archive_extracted else downloaded
    if not local_audio.is_file() or local_audio.suffix.lower() not in _AUDIO_EXTENSIONS:
        raise RuntimeError("Resolved dataset sample is not a supported audio file.")

    return ResolvedDatasetSample(
        sample_id=spec.sample_id,
        label=spec.label,
        local_path=str(local_audio),
        repo_id=spec.repo_id,
        repo_type=spec.repo_type,
        revision=spec.revision,
        repository_filename=repository_filename,
        resolved_audio_filename=local_audio.name,
        license_id=spec.license_id,
        attribution=spec.attribution,
        source_url=spec.source_url,
        archive_extracted=archive_extracted,
        size_bytes=local_audio.stat().st_size,
    )