fosters commited on
Commit
3bed199
·
verified ·
1 Parent(s): 2dc5eca

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +62 -23
app.py CHANGED
@@ -49,8 +49,8 @@ def _embed(audio_array: np.ndarray, sr: int, max_sec: int) -> np.ndarray:
49
  return out.embeddings.squeeze().numpy()
50
 
51
 
52
- def _fetch_audio_urls(repo_id: str, n: int, token: str | None) -> list[str]:
53
- """Get direct audio URLs via datasets-server no parquet download needed."""
54
  headers = {"Authorization": f"Bearer {token}"} if token else {}
55
  resp = requests.get(
56
  f"{DATASETS_SERVER}/rows",
@@ -58,13 +58,26 @@ def _fetch_audio_urls(repo_id: str, n: int, token: str | None) -> list[str]:
58
  headers=headers,
59
  timeout=30,
60
  )
61
- resp.raise_for_status()
 
 
 
 
 
 
 
 
 
 
62
  urls = []
63
- for row in resp.json().get("rows", []):
64
  audio = row["row"].get("audio", {})
65
  if isinstance(audio, dict) and "src" in audio:
66
  urls.append(audio["src"])
67
- return urls
 
 
 
68
 
69
 
70
  def _download_one(url: str, token: str | None, max_sec: int) -> tuple[np.ndarray, dict]:
@@ -90,31 +103,57 @@ def _download_one(url: str, token: str | None, max_sec: int) -> tuple[np.ndarray
90
  }
91
 
92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  def _process_repo(
94
  repo: str, n_samples: int, audio_sec: int, token: str | None
95
  ) -> tuple[str, np.ndarray | None, str]:
96
  t0 = time.time()
97
  try:
98
- urls = _fetch_audio_urls(repo, n_samples, token)
99
- if not urls:
100
- return repo, None, f"{repo}: no audio URLs from datasets-server"
101
  fetch_ms = int((time.time() - t0) * 1000)
102
 
103
- # Download audio files in parallel (I/O bound)
104
- with concurrent.futures.ThreadPoolExecutor(max_workers=len(urls)) as ex:
105
- futures = [ex.submit(_download_one, u, token, audio_sec) for u in urls]
106
- results = [f.result() for f in futures]
107
-
108
- embs = [r[0] for r in results]
109
- # Log stats from first sample as representative
110
- s = results[0][1]
111
- total_ms = int((time.time() - t0) * 1000)
112
- log = (
113
- f"{repo.split('/')[-1]}: "
114
- f"api={fetch_ms}ms dl={s['dl_ms']}ms "
115
- f"decode={s['decode_ms']}ms embed={s['embed_ms']}ms "
116
- f"total={total_ms}ms ({s['size_kb']}KB/file)"
117
- )
 
 
 
 
 
 
 
 
 
 
 
 
118
  return repo, np.mean(embs, axis=0), log
119
 
120
  except Exception as exc:
 
49
  return out.embeddings.squeeze().numpy()
50
 
51
 
52
+ def _fetch_audio_urls(repo_id: str, n: int, token: str | None) -> tuple[list[str], str]:
53
+ """Get direct audio URLs via datasets-server. Returns (urls, debug_info)."""
54
  headers = {"Authorization": f"Bearer {token}"} if token else {}
55
  resp = requests.get(
56
  f"{DATASETS_SERVER}/rows",
 
58
  headers=headers,
59
  timeout=30,
60
  )
61
+ if not resp.ok:
62
+ return [], f"datasets-server {resp.status_code}"
63
+
64
+ rows = resp.json().get("rows", [])
65
+ if not rows:
66
+ return [], "datasets-server: empty rows"
67
+
68
+ # Inspect actual audio field structure for debugging
69
+ sample_audio = rows[0]["row"].get("audio", {})
70
+ audio_keys = list(sample_audio.keys()) if isinstance(sample_audio, dict) else type(sample_audio).__name__
71
+
72
  urls = []
73
+ for row in rows:
74
  audio = row["row"].get("audio", {})
75
  if isinstance(audio, dict) and "src" in audio:
76
  urls.append(audio["src"])
77
+
78
+ if not urls:
79
+ return [], f"datasets-server: no src in audio field (keys={audio_keys})"
80
+ return urls, f"datasets-server ok (audio keys={audio_keys})"
81
 
82
 
83
  def _download_one(url: str, token: str | None, max_sec: int) -> tuple[np.ndarray, dict]:
 
103
  }
104
 
105
 
106
+ def _streaming_fallback(repo: str, n_samples: int, audio_sec: int, token: str | None) -> list[np.ndarray]:
107
+ """Fallback: use datasets streaming when datasets-server is unavailable."""
108
+ from datasets import load_dataset, Audio as HFAudio
109
+ ds = load_dataset(repo, split="train", streaming=True, token=token)
110
+ ds = ds.cast_column("audio", HFAudio(decode=False))
111
+ embs = []
112
+ for j, row in enumerate(ds):
113
+ if j >= n_samples:
114
+ break
115
+ raw = row["audio"]
116
+ audio_bytes = raw.get("bytes") or open(raw["path"], "rb").read()
117
+ audio_array, sr = sf.read(io.BytesIO(audio_bytes))
118
+ embs.append(_embed(audio_array, sr, audio_sec))
119
+ return embs
120
+
121
+
122
  def _process_repo(
123
  repo: str, n_samples: int, audio_sec: int, token: str | None
124
  ) -> tuple[str, np.ndarray | None, str]:
125
  t0 = time.time()
126
  try:
127
+ urls, api_debug = _fetch_audio_urls(repo, n_samples, token)
 
 
128
  fetch_ms = int((time.time() - t0) * 1000)
129
 
130
+ if urls:
131
+ # Fast path: parallel downloads via datasets-server URLs
132
+ with concurrent.futures.ThreadPoolExecutor(max_workers=len(urls)) as ex:
133
+ futures = [ex.submit(_download_one, u, token, audio_sec) for u in urls]
134
+ results = [f.result() for f in futures]
135
+ embs = [r[0] for r in results]
136
+ s = results[0][1]
137
+ total_ms = int((time.time() - t0) * 1000)
138
+ log = (
139
+ f"{repo.split('/')[-1]}: "
140
+ f"api={fetch_ms}ms dl={s['dl_ms']}ms "
141
+ f"decode={s['decode_ms']}ms embed={s['embed_ms']}ms "
142
+ f"total={total_ms}ms ({s['size_kb']}KB/file) [{api_debug}]"
143
+ )
144
+ else:
145
+ # Slow fallback: streaming (downloads parquet shard)
146
+ t1 = time.time()
147
+ embs = _streaming_fallback(repo, n_samples, audio_sec, token)
148
+ total_ms = int((time.time() - t0) * 1000)
149
+ log = (
150
+ f"{repo.split('/')[-1]}: streaming fallback "
151
+ f"total={total_ms}ms [reason: {api_debug}]"
152
+ )
153
+
154
+ if not embs:
155
+ return repo, None, f"{repo}: no audio samples extracted"
156
+
157
  return repo, np.mean(embs, axis=0), log
158
 
159
  except Exception as exc: