whojavumusic commited on
Commit
a6beab2
·
1 Parent(s): 3813139

cohere fix

Browse files
app.py CHANGED
@@ -460,6 +460,8 @@ with gr.Blocks(title=APP_TITLE, theme=_theme, css=LEADERBOARD_CSS) as demo:
460
  gr.Markdown(
461
  "Edit the example below: define **`evaluate(file: Path) -> str`** to transcribe one WAV. "
462
  "Load your model **once** at module level (as in the Cohere example). "
 
 
463
  "The function is called **once per audio sample** inside the eval loop. "
464
  "Put extra Python dependencies in the requirements box above. "
465
  "Custom evaluators run on a Hub Job **only** after a moderator approves them."
 
460
  gr.Markdown(
461
  "Edit the example below: define **`evaluate(file: Path) -> str`** to transcribe one WAV. "
462
  "Load your model **once** at module level (as in the Cohere example). "
463
+ "Use **soundfile** (or numpy) to read each WAV — avoid "
464
+ "``transformers.audio_utils.load_audio`` (requires FFmpeg/torchcodec on the job). "
465
  "The function is called **once per audio sample** inside the eval loop. "
466
  "Put extra Python dependencies in the requirements box above. "
467
  "Custom evaluators run on a Hub Job **only** after a moderator approves them."
backends/_audio_utils.py CHANGED
@@ -4,6 +4,8 @@ Small helpers shared across backends (no heavy imports).
4
 
5
  from __future__ import annotations
6
 
 
 
7
  import numpy as np
8
 
9
 
@@ -26,3 +28,29 @@ def safe_pad_audio(audio: np.ndarray, multiple: int = 1600) -> np.ndarray:
26
  return arr
27
  pad = multiple - rem
28
  return np.concatenate([arr, np.zeros(pad, dtype=np.float32)])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
 
5
  from __future__ import annotations
6
 
7
+ from pathlib import Path
8
+
9
  import numpy as np
10
 
11
 
 
28
  return arr
29
  pad = multiple - rem
30
  return np.concatenate([arr, np.zeros(pad, dtype=np.float32)])
31
+
32
+
33
+ def load_wav_mono(path: str | Path, sampling_rate: int = 16000) -> np.ndarray:
34
+ """
35
+ Load a WAV file as a 1-D float32 mono waveform at ``sampling_rate`` Hz.
36
+
37
+ Uses ``soundfile`` only (no torchcodec / FFmpeg). Eval samples and the
38
+ custom ``evaluate(Path)`` hook are written as 16 kHz PCM WAVs.
39
+ """
40
+ import soundfile as sf
41
+
42
+ audio, sr = sf.read(str(path), dtype="float32", always_2d=True)
43
+ audio = audio.mean(axis=1)
44
+ if int(sr) != int(sampling_rate):
45
+ try:
46
+ import librosa
47
+
48
+ audio = librosa.resample(
49
+ audio, orig_sr=int(sr), target_sr=int(sampling_rate)
50
+ )
51
+ except Exception as exc:
52
+ raise RuntimeError(
53
+ f"Audio is {sr} Hz but {sampling_rate} Hz was requested; "
54
+ "install librosa for resampling."
55
+ ) from exc
56
+ return np.asarray(audio, dtype=np.float32).reshape(-1)
constants.py CHANGED
@@ -418,8 +418,10 @@ button.primary, .primary button {
418
  )
419
 
420
  DEFAULT_CUSTOM_EVAL_EXAMPLE = """from pathlib import Path
 
 
 
421
  from transformers import AutoProcessor, CohereAsrForConditionalGeneration
422
- from transformers.audio_utils import load_audio
423
 
424
  processor = AutoProcessor.from_pretrained("CohereLabs/cohere-transcribe-03-2026")
425
  model = CohereAsrForConditionalGeneration.from_pretrained(
@@ -427,8 +429,9 @@ model = CohereAsrForConditionalGeneration.from_pretrained(
427
  )
428
 
429
  def evaluate(file: Path) -> str:
430
- audio = load_audio(file, sampling_rate=16000)
431
- inputs = processor(audio, sampling_rate=16000, return_tensors="pt", language="en")
 
432
  inputs.to(model.device, dtype=model.dtype)
433
  outputs = model.generate(**inputs, max_new_tokens=256)
434
  return processor.decode(outputs, skip_special_tokens=True)
 
418
  )
419
 
420
  DEFAULT_CUSTOM_EVAL_EXAMPLE = """from pathlib import Path
421
+
422
+ import soundfile as sf
423
+ import torch
424
  from transformers import AutoProcessor, CohereAsrForConditionalGeneration
 
425
 
426
  processor = AutoProcessor.from_pretrained("CohereLabs/cohere-transcribe-03-2026")
427
  model = CohereAsrForConditionalGeneration.from_pretrained(
 
429
  )
430
 
431
  def evaluate(file: Path) -> str:
432
+ audio, sr = sf.read(str(file), dtype="float32", always_2d=True)
433
+ audio = audio.mean(axis=1)
434
+ inputs = processor(audio, sampling_rate=int(sr), return_tensors="pt", language="en")
435
  inputs.to(model.device, dtype=model.dtype)
436
  outputs = model.generate(**inputs, max_new_tokens=256)
437
  return processor.decode(outputs, skip_special_tokens=True)
evaluation/orchestrator.py CHANGED
@@ -442,6 +442,7 @@ def run_evaluation(
442
  Returns wer_clean, wer_noisy, wer_reverberant, wer_real, wer_difficult, num_samples, model_id, eval_family, plus timing.
443
  """
444
  apply_cpu_thread_settings_once()
 
445
 
446
  seg = _samples_per_gpu_segment()
447
 
 
442
  Returns wer_clean, wer_noisy, wer_reverberant, wer_real, wer_difficult, num_samples, model_id, eval_family, plus timing.
443
  """
444
  apply_cpu_thread_settings_once()
445
+ disable_broken_torchcodec()
446
 
447
  seg = _samples_per_gpu_segment()
448
 
evaluation/runtime.py CHANGED
@@ -6,6 +6,35 @@ import importlib.util
6
  import os
7
 
8
  _cpu_thread_settings_applied = False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
 
11
  def zerogpu_disabled() -> bool:
 
6
  import os
7
 
8
  _cpu_thread_settings_applied = False
9
+ _torchcodec_patch_applied = False
10
+
11
+
12
+ def disable_broken_torchcodec() -> None:
13
+ """
14
+ Transformers prefers torchcodec for ``load_audio`` when the package is installed,
15
+ but Hub Job images often lack FFmpeg shared libraries (libavutil.so.*).
16
+
17
+ If torchcodec cannot load, mark it unavailable so transformers falls back to
18
+ librosa / soundfile.
19
+ """
20
+ global _torchcodec_patch_applied
21
+ if _torchcodec_patch_applied:
22
+ return
23
+ _torchcodec_patch_applied = True
24
+
25
+ import importlib.util
26
+
27
+ if importlib.util.find_spec("torchcodec") is None:
28
+ return
29
+ try:
30
+ from torchcodec.decoders import AudioDecoder # noqa: F401
31
+ except Exception:
32
+ try:
33
+ import transformers.utils.import_utils as import_utils
34
+
35
+ import_utils._torchcodec_available = False
36
+ except Exception:
37
+ pass
38
 
39
 
40
  def zerogpu_disabled() -> bool:
remote_jobs.py CHANGED
@@ -29,6 +29,7 @@ _DEFAULT_REMOTE_JOB_FLAVOR = "l4x1"
29
  _DEFAULT_REMOTE_WORKER_DEVICE = "auto"
30
 
31
  # Shared eval stack installed by uv for every remote job.
 
32
  CORE_DEPS: list[str] = [
33
  "pandas",
34
  "numpy",
@@ -43,7 +44,6 @@ CORE_DEPS: list[str] = [
43
 
44
  _TRANSFORMERS_DEPS: list[str] = [
45
  "transformers @ git+https://github.com/huggingface/transformers.git",
46
- "torchcodec",
47
  "librosa",
48
  "sentencepiece",
49
  ]
 
29
  _DEFAULT_REMOTE_WORKER_DEVICE = "auto"
30
 
31
  # Shared eval stack installed by uv for every remote job.
32
+ # Note: do not add torchcodec — Hub Job images lack FFmpeg shared libs (libavutil.so.*).
33
  CORE_DEPS: list[str] = [
34
  "pandas",
35
  "numpy",
 
44
 
45
  _TRANSFORMERS_DEPS: list[str] = [
46
  "transformers @ git+https://github.com/huggingface/transformers.git",
 
47
  "librosa",
48
  "sentencepiece",
49
  ]
scripts/run_eval_and_publish.py CHANGED
@@ -460,6 +460,10 @@ def _run_evaluation_local(
460
  """Inline orchestrator: chosen device + batched fast-path when possible."""
461
  import torch
462
 
 
 
 
 
463
  from backends.registry import build_transcriber, resolve_label
464
  from benchmark.dataset import (
465
  PACKED_FILES,
 
460
  """Inline orchestrator: chosen device + batched fast-path when possible."""
461
  import torch
462
 
463
+ from evaluation.runtime import disable_broken_torchcodec
464
+
465
+ disable_broken_torchcodec()
466
+
467
  from backends.registry import build_transcriber, resolve_label
468
  from benchmark.dataset import (
469
  PACKED_FILES,
scripts/run_hf_remote_job_uv.py CHANGED
@@ -109,11 +109,12 @@ def main() -> int:
109
  os.chdir(workdir)
110
 
111
  from evaluation.remote_artifact import ARTIFACT_SCHEMA_VERSION, build_artifact
112
- from evaluation.runtime import apply_cpu_thread_settings_once
113
  from evaluation.orchestrator import run_evaluation
114
  from storage import HF_BUCKET_ID, upload_to_bucket
115
 
116
  apply_cpu_thread_settings_once()
 
117
  custom_b64 = os.environ.get("FFASR_CUSTOM_SCRIPT_B64", "").strip()
118
  custom_script = (
119
  base64.b64decode(custom_b64).decode("utf-8") if custom_b64 else ""
 
109
  os.chdir(workdir)
110
 
111
  from evaluation.remote_artifact import ARTIFACT_SCHEMA_VERSION, build_artifact
112
+ from evaluation.runtime import apply_cpu_thread_settings_once, disable_broken_torchcodec
113
  from evaluation.orchestrator import run_evaluation
114
  from storage import HF_BUCKET_ID, upload_to_bucket
115
 
116
  apply_cpu_thread_settings_once()
117
+ disable_broken_torchcodec()
118
  custom_b64 = os.environ.get("FFASR_CUSTOM_SCRIPT_B64", "").strip()
119
  custom_script = (
120
  base64.b64decode(custom_b64).decode("utf-8") if custom_b64 else ""