Spaces:
Running on CPU Upgrade
Running on CPU Upgrade
Shivam commited on
Commit ·
2f5908d
1
Parent(s): cfd5b8d
eval script in about, fix for qwen,
Browse files- app.py +6 -1
- constants.py +3 -0
- job_queue.py +1 -0
- storage.py +179 -7
app.py
CHANGED
|
@@ -1069,10 +1069,15 @@ with gr.Blocks(title=APP_TITLE, theme=_theme, css=LEADERBOARD_CSS) as demo:
|
|
| 1069 |
if job["req_count"]
|
| 1070 |
else "no extra reqs"
|
| 1071 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1072 |
with gr.Row(elem_classes=row_cls):
|
| 1073 |
gr.Markdown(
|
| 1074 |
f"**`{jid}`** · `{job['model_id']}` · "
|
| 1075 |
-
f"`{job['family_id']}`{gated}{script_bit} · {extras} · "
|
| 1076 |
f"{job['notes_preview'] or '—'} · {job['created_at']}",
|
| 1077 |
elem_classes="ffasr-job-info",
|
| 1078 |
)
|
|
|
|
| 1069 |
if job["req_count"]
|
| 1070 |
else "no extra reqs"
|
| 1071 |
)
|
| 1072 |
+
email_bit = (
|
| 1073 |
+
f" · 📧 `{job['contact_email']}`"
|
| 1074 |
+
if job.get("contact_email")
|
| 1075 |
+
else " · 📧 *(none)*"
|
| 1076 |
+
)
|
| 1077 |
with gr.Row(elem_classes=row_cls):
|
| 1078 |
gr.Markdown(
|
| 1079 |
f"**`{jid}`** · `{job['model_id']}` · "
|
| 1080 |
+
f"`{job['family_id']}`{gated}{script_bit} · {extras}{email_bit} · "
|
| 1081 |
f"{job['notes_preview'] or '—'} · {job['created_at']}",
|
| 1082 |
elem_classes="ffasr-job-info",
|
| 1083 |
)
|
constants.py
CHANGED
|
@@ -181,6 +181,9 @@ quantify latency. The balance between performance and latency is of practical im
|
|
| 181 |
may run as part of a real‑time interaction with users. A Pareto plot helps visualize this tradeoff (a single metric
|
| 182 |
balancing Avg WER and RTFx, e.g. area under the curve, could also be considered).
|
| 183 |
|
|
|
|
|
|
|
|
|
|
| 184 |
### Word Error Rate (WER)
|
| 185 |
|
| 186 |
WER is the fraction of reference words that are substituted, inserted, or deleted:
|
|
|
|
| 181 |
may run as part of a real‑time interaction with users. A Pareto plot helps visualize this tradeoff (a single metric
|
| 182 |
balancing Avg WER and RTFx, e.g. area under the curve, could also be considered).
|
| 183 |
|
| 184 |
+
Scoring is performed by [`benchmark/dataset.py`](https://huggingface.co/spaces/treble-technologies/ffasr/blob/main/benchmark/dataset.py),
|
| 185 |
+
which calls `evaluate_condition_wer_timed` for each inference to compute the per‑condition WER and timing used for RTFx.
|
| 186 |
+
|
| 187 |
### Word Error Rate (WER)
|
| 188 |
|
| 189 |
WER is the fraction of reference words that are substituted, inserted, or deleted:
|
job_queue.py
CHANGED
|
@@ -1871,6 +1871,7 @@ def pending_jobs_for_render(limit: int = 60) -> list[dict[str, Any]]:
|
|
| 1871 |
"model_id": j.model_id,
|
| 1872 |
"family_id": j.family_id,
|
| 1873 |
"created_at": (j.created_at or "")[:19],
|
|
|
|
| 1874 |
"is_gated": j.is_gated,
|
| 1875 |
"req_count": len(parse_requirements_lines(j.extra_requirements or "")),
|
| 1876 |
"notes_preview": (
|
|
|
|
| 1871 |
"model_id": j.model_id,
|
| 1872 |
"family_id": j.family_id,
|
| 1873 |
"created_at": (j.created_at or "")[:19],
|
| 1874 |
+
"contact_email": (j.contact_email or "").strip(),
|
| 1875 |
"is_gated": j.is_gated,
|
| 1876 |
"req_count": len(parse_requirements_lines(j.extra_requirements or "")),
|
| 1877 |
"notes_preview": (
|
storage.py
CHANGED
|
@@ -23,6 +23,8 @@ runtime default token).
|
|
| 23 |
|
| 24 |
import io
|
| 25 |
import os
|
|
|
|
|
|
|
| 26 |
import tempfile
|
| 27 |
from contextlib import nullcontext
|
| 28 |
from pathlib import Path
|
|
@@ -127,7 +129,14 @@ def upload_to_bucket(
|
|
| 127 |
Upload/copy/delete bucket files with progress bars disabled and Xet reporter compatibility.
|
| 128 |
"""
|
| 129 |
if batch_bucket_files is None:
|
| 130 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 131 |
_ensure_xet_progress_reporter_compatible()
|
| 132 |
try:
|
| 133 |
from huggingface_hub.utils import disable_progress_bars
|
|
@@ -145,13 +154,176 @@ def upload_to_bucket(
|
|
| 145 |
)
|
| 146 |
|
| 147 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 148 |
def download_bucket_file(path: str) -> str:
|
| 149 |
-
"""Download a single file from HF Bucket and return the local path.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 150 |
local_dir = tempfile.mkdtemp()
|
| 151 |
local_path = os.path.join(local_dir, os.path.basename(path))
|
| 152 |
-
download_bucket_files
|
| 153 |
-
|
| 154 |
-
|
| 155 |
-
|
| 156 |
-
|
|
|
|
|
|
|
|
|
|
| 157 |
return local_path
|
|
|
|
| 23 |
|
| 24 |
import io
|
| 25 |
import os
|
| 26 |
+
import shutil
|
| 27 |
+
import subprocess
|
| 28 |
import tempfile
|
| 29 |
from contextlib import nullcontext
|
| 30 |
from pathlib import Path
|
|
|
|
| 129 |
Upload/copy/delete bucket files with progress bars disabled and Xet reporter compatibility.
|
| 130 |
"""
|
| 131 |
if batch_bucket_files is None:
|
| 132 |
+
# In-process hub lacks the bucket API (e.g. qwen-asr stack pins hub<1.0).
|
| 133 |
+
# Fall back to an isolated uv env that has it.
|
| 134 |
+
if not _bucket_uv_available():
|
| 135 |
+
raise RuntimeError("huggingface_hub bucket support is not available")
|
| 136 |
+
_upload_to_bucket_via_uv(
|
| 137 |
+
bucket_id, add=add, copy=copy, delete=delete, token=token
|
| 138 |
+
)
|
| 139 |
+
return
|
| 140 |
_ensure_xet_progress_reporter_compatible()
|
| 141 |
try:
|
| 142 |
from huggingface_hub.utils import disable_progress_bars
|
|
|
|
| 154 |
)
|
| 155 |
|
| 156 |
|
| 157 |
+
# huggingface_hub version that ships the bucket API, used by the isolated-subprocess
|
| 158 |
+
# fallback when the in-process hub is pinned <1.0 (e.g. the qwen-asr stack, whose
|
| 159 |
+
# transformers==4.57.x pin forces huggingface-hub<1.0 and so lacks bucket support).
|
| 160 |
+
_BUCKET_FALLBACK_HUB_SPEC = os.environ.get(
|
| 161 |
+
"FFASR_BUCKET_FALLBACK_HUB_SPEC", "huggingface-hub>=1.14.0"
|
| 162 |
+
)
|
| 163 |
+
|
| 164 |
+
_BUCKET_DOWNLOAD_SNIPPET = """\
|
| 165 |
+
import os, sys
|
| 166 |
+
from huggingface_hub import download_bucket_files
|
| 167 |
+
|
| 168 |
+
bucket_id, remote_path, local_path = sys.argv[1], sys.argv[2], sys.argv[3]
|
| 169 |
+
download_bucket_files(
|
| 170 |
+
bucket_id,
|
| 171 |
+
files=[(remote_path, local_path)],
|
| 172 |
+
token=os.environ.get("FFASR_BUCKET_DL_TOKEN") or None,
|
| 173 |
+
)
|
| 174 |
+
"""
|
| 175 |
+
|
| 176 |
+
_BUCKET_UPLOAD_SNIPPET = """\
|
| 177 |
+
import json, os, sys
|
| 178 |
+
from huggingface_hub import batch_bucket_files
|
| 179 |
+
|
| 180 |
+
try:
|
| 181 |
+
from huggingface_hub.utils import disable_progress_bars
|
| 182 |
+
disable_progress_bars()
|
| 183 |
+
except Exception:
|
| 184 |
+
pass
|
| 185 |
+
|
| 186 |
+
manifest_path, bucket_id = sys.argv[1], sys.argv[2]
|
| 187 |
+
with open(manifest_path, encoding="utf-8") as f:
|
| 188 |
+
manifest = json.load(f)
|
| 189 |
+
add = [(src, dst) for src, dst in manifest.get("add", [])] or None
|
| 190 |
+
copy = [tuple(c) for c in manifest.get("copy", [])] or None
|
| 191 |
+
delete = list(manifest.get("delete", [])) or None
|
| 192 |
+
batch_bucket_files(
|
| 193 |
+
bucket_id,
|
| 194 |
+
add=add,
|
| 195 |
+
copy=copy,
|
| 196 |
+
delete=delete,
|
| 197 |
+
token=os.environ.get("FFASR_BUCKET_DL_TOKEN") or None,
|
| 198 |
+
)
|
| 199 |
+
"""
|
| 200 |
+
|
| 201 |
+
|
| 202 |
+
def _bucket_uv_available() -> bool:
|
| 203 |
+
return shutil.which("uv") is not None
|
| 204 |
+
|
| 205 |
+
|
| 206 |
+
def _run_bucket_uv_snippet(
|
| 207 |
+
snippet: str, args: list[str], *, token: str | None = None
|
| 208 |
+
) -> subprocess.CompletedProcess:
|
| 209 |
+
"""Run ``snippet`` in an isolated ``uv`` env that has the hub bucket API.
|
| 210 |
+
|
| 211 |
+
Used when this process' ``huggingface_hub`` is pinned <1.0 (no bucket support).
|
| 212 |
+
``uv`` resolves an ephemeral, cached environment with a recent ``huggingface_hub``
|
| 213 |
+
(plus ``hf_xet`` for Xet-backed buckets), independent of the job's pinned stack.
|
| 214 |
+
The Hub token is passed via ``FFASR_BUCKET_DL_TOKEN`` (never on argv).
|
| 215 |
+
"""
|
| 216 |
+
uv = shutil.which("uv") or "uv"
|
| 217 |
+
cmd = [
|
| 218 |
+
uv,
|
| 219 |
+
"run",
|
| 220 |
+
"--no-project",
|
| 221 |
+
"--python",
|
| 222 |
+
"3.12",
|
| 223 |
+
"--with",
|
| 224 |
+
_BUCKET_FALLBACK_HUB_SPEC,
|
| 225 |
+
"--with",
|
| 226 |
+
"hf_xet",
|
| 227 |
+
"python",
|
| 228 |
+
"-c",
|
| 229 |
+
snippet,
|
| 230 |
+
*args,
|
| 231 |
+
]
|
| 232 |
+
env = dict(os.environ)
|
| 233 |
+
tok = token or HF_TOKEN
|
| 234 |
+
if tok:
|
| 235 |
+
env["FFASR_BUCKET_DL_TOKEN"] = tok
|
| 236 |
+
env.setdefault("HF_HUB_DISABLE_PROGRESS_BARS", "1")
|
| 237 |
+
try:
|
| 238 |
+
return subprocess.run(
|
| 239 |
+
cmd,
|
| 240 |
+
env=env,
|
| 241 |
+
check=False,
|
| 242 |
+
capture_output=True,
|
| 243 |
+
text=True,
|
| 244 |
+
)
|
| 245 |
+
except FileNotFoundError as exc:
|
| 246 |
+
raise RuntimeError(
|
| 247 |
+
"huggingface_hub bucket support is not available in this environment and the "
|
| 248 |
+
"`uv` fallback could not be launched (uv not found on PATH)."
|
| 249 |
+
) from exc
|
| 250 |
+
|
| 251 |
+
|
| 252 |
+
def _download_bucket_file_via_uv(path: str, local_path: str) -> None:
|
| 253 |
+
proc = _run_bucket_uv_snippet(
|
| 254 |
+
_BUCKET_DOWNLOAD_SNIPPET, [HF_BUCKET_ID, path, local_path]
|
| 255 |
+
)
|
| 256 |
+
if proc.returncode != 0 or not os.path.exists(local_path):
|
| 257 |
+
tail = (proc.stderr or proc.stdout or "").strip()[-2000:]
|
| 258 |
+
raise RuntimeError(
|
| 259 |
+
"Bucket download via isolated uv environment failed "
|
| 260 |
+
f"(exit {proc.returncode}) for '{path}'.\n{tail}"
|
| 261 |
+
)
|
| 262 |
+
|
| 263 |
+
|
| 264 |
+
def _upload_to_bucket_via_uv(
|
| 265 |
+
bucket_id: str,
|
| 266 |
+
*,
|
| 267 |
+
add: list[tuple[str | Path | bytes, str]] | None,
|
| 268 |
+
copy: list[tuple[str, str, str, str]] | None,
|
| 269 |
+
delete: list[str] | None,
|
| 270 |
+
token: str | bool | None = None,
|
| 271 |
+
) -> None:
|
| 272 |
+
"""Upload/copy/delete bucket files via the isolated ``uv`` env (hub <1.0 fallback).
|
| 273 |
+
|
| 274 |
+
``bytes`` sources in ``add`` are materialized to temp files so the subprocess can
|
| 275 |
+
pass plain file paths to ``batch_bucket_files``.
|
| 276 |
+
"""
|
| 277 |
+
tmpdir = tempfile.mkdtemp(prefix="ffasr_bucket_up_")
|
| 278 |
+
try:
|
| 279 |
+
add_items: list[tuple[str, str]] = []
|
| 280 |
+
for i, (src, dst) in enumerate(add or []):
|
| 281 |
+
if isinstance(src, (bytes, bytearray)):
|
| 282 |
+
src_path = os.path.join(tmpdir, f"add_{i}_{os.path.basename(dst) or 'blob'}")
|
| 283 |
+
with open(src_path, "wb") as fh:
|
| 284 |
+
fh.write(src)
|
| 285 |
+
else:
|
| 286 |
+
src_path = os.fspath(src)
|
| 287 |
+
add_items.append((src_path, dst))
|
| 288 |
+
manifest = {
|
| 289 |
+
"add": add_items,
|
| 290 |
+
"copy": [list(c) for c in (copy or [])],
|
| 291 |
+
"delete": list(delete or []),
|
| 292 |
+
}
|
| 293 |
+
import json as _json
|
| 294 |
+
|
| 295 |
+
manifest_path = os.path.join(tmpdir, "manifest.json")
|
| 296 |
+
with open(manifest_path, "w", encoding="utf-8") as fh:
|
| 297 |
+
_json.dump(manifest, fh)
|
| 298 |
+
snippet_token = token if isinstance(token, str) else None
|
| 299 |
+
proc = _run_bucket_uv_snippet(
|
| 300 |
+
_BUCKET_UPLOAD_SNIPPET, [manifest_path, bucket_id], token=snippet_token
|
| 301 |
+
)
|
| 302 |
+
if proc.returncode != 0:
|
| 303 |
+
tail = (proc.stderr or proc.stdout or "").strip()[-2000:]
|
| 304 |
+
raise RuntimeError(
|
| 305 |
+
"Bucket upload via isolated uv environment failed "
|
| 306 |
+
f"(exit {proc.returncode}).\n{tail}"
|
| 307 |
+
)
|
| 308 |
+
finally:
|
| 309 |
+
shutil.rmtree(tmpdir, ignore_errors=True)
|
| 310 |
+
|
| 311 |
+
|
| 312 |
def download_bucket_file(path: str) -> str:
|
| 313 |
+
"""Download a single file from HF Bucket and return the local path.
|
| 314 |
+
|
| 315 |
+
Uses the in-process bucket API when available; otherwise falls back to an isolated
|
| 316 |
+
``uv`` environment that has a hub version with bucket support (the qwen-asr stack
|
| 317 |
+
pins huggingface-hub<1.0, which lacks the bucket API).
|
| 318 |
+
"""
|
| 319 |
local_dir = tempfile.mkdtemp()
|
| 320 |
local_path = os.path.join(local_dir, os.path.basename(path))
|
| 321 |
+
if download_bucket_files is not None:
|
| 322 |
+
download_bucket_files(
|
| 323 |
+
HF_BUCKET_ID,
|
| 324 |
+
files=[(path, local_path)],
|
| 325 |
+
token=HF_TOKEN,
|
| 326 |
+
)
|
| 327 |
+
else:
|
| 328 |
+
_download_bucket_file_via_uv(path, local_path)
|
| 329 |
return local_path
|