multimodalart HF Staff commited on
Commit
8f550fc
·
verified ·
1 Parent(s): c020a36

Auto-transcribe reference audio with CPU Whisper into the editable transcript field

Browse files
Files changed (1) hide show
  1. app.py +83 -0
app.py CHANGED
@@ -9,6 +9,7 @@ os.environ.setdefault("PYTORCH_CUDA_ALLOC_CONF", "expandable_segments:True")
9
 
10
  import spaces # MUST come before any torch/CUDA import
11
  import tempfile
 
12
  import time
13
  from pathlib import Path
14
 
@@ -27,6 +28,7 @@ from breeze_infer.templates import get_template, prepare_inputs
27
  from models.fast_streaming import FastBreezeStreamingRuntime, FastStreamingConfig
28
 
29
  MODEL_ID = "BreezeBlue/Breeze-TTS-2"
 
30
 
31
  MAX_NEW_TOKENS = 1500
32
  MAX_SEQ_LEN = 2048
@@ -74,6 +76,67 @@ print("Breeze TTS 2 loaded successfully.")
74
  print(f"Sample rate: {_runtime.sample_rate}")
75
 
76
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  @spaces.GPU(duration=120)
78
  def generate_voice_design(
79
  text: str,
@@ -295,9 +358,16 @@ with gr.Blocks(theme=gr.themes.Citrus(), css=CSS) as demo:
295
  )
296
  clone_ref_text = gr.Textbox(
297
  label="Reference transcript (exact)",
 
298
  placeholder="This is the exact transcript of the reference audio.",
299
  lines=2,
300
  )
 
 
 
 
 
 
301
  with gr.Accordion("Advanced settings", open=False):
302
  clone_seed = gr.Number(label="Seed", value=42, precision=0)
303
  clone_btn = gr.Button("Generate", variant="primary")
@@ -338,9 +408,16 @@ with gr.Blocks(theme=gr.themes.Citrus(), css=CSS) as demo:
338
  )
339
  dir_ref_text = gr.Textbox(
340
  label="Reference transcript (exact)",
 
341
  placeholder="This is the exact transcript of the reference audio.",
342
  lines=2,
343
  )
 
 
 
 
 
 
344
  with gr.Accordion("Advanced settings", open=False):
345
  dir_cfg = gr.Slider(
346
  label="CFG scale",
@@ -378,4 +455,10 @@ with gr.Blocks(theme=gr.themes.Citrus(), css=CSS) as demo:
378
  "Weights/outputs are for research and non-commercial use only."
379
  )
380
 
 
 
 
 
 
 
381
  demo.launch(mcp_server=True)
 
9
 
10
  import spaces # MUST come before any torch/CUDA import
11
  import tempfile
12
+ import threading
13
  import time
14
  from pathlib import Path
15
 
 
28
  from models.fast_streaming import FastBreezeStreamingRuntime, FastStreamingConfig
29
 
30
  MODEL_ID = "BreezeBlue/Breeze-TTS-2"
31
+ ASR_MODEL_ID = "openai/whisper-small" # multilingual (en/zh), runs on CPU
32
 
33
  MAX_NEW_TOKENS = 1500
34
  MAX_SEQ_LEN = 2048
 
76
  print(f"Sample rate: {_runtime.sample_rate}")
77
 
78
 
79
+ _asr_pipe = None
80
+ _asr_lock = threading.Lock()
81
+
82
+
83
+ def _get_asr():
84
+ """Lazily build the CPU Whisper pipeline used to auto-transcribe reference audio."""
85
+ global _asr_pipe
86
+ with _asr_lock:
87
+ if _asr_pipe is None:
88
+ from transformers import pipeline
89
+
90
+ _asr_pipe = pipeline(
91
+ "automatic-speech-recognition",
92
+ model=ASR_MODEL_ID,
93
+ device="cpu",
94
+ chunk_length_s=30,
95
+ )
96
+ return _asr_pipe
97
+
98
+
99
+ def transcribe_reference(
100
+ ref_audio_path: str | None,
101
+ progress=gr.Progress(track_tqdm=True),
102
+ ):
103
+ """Auto-transcribe uploaded/recorded reference audio with Whisper on CPU.
104
+
105
+ The result populates the (still editable) reference transcript field.
106
+
107
+ Args:
108
+ ref_audio_path: Path to the reference audio file, or None when cleared.
109
+ """
110
+ if not ref_audio_path:
111
+ return gr.update()
112
+
113
+ try:
114
+ asr = _get_asr()
115
+ except Exception as exc: # pragma: no cover - model download/load failure
116
+ raise gr.Error(f"Could not load the transcription model: {exc}") from exc
117
+
118
+ try:
119
+ import librosa
120
+
121
+ audio, _ = librosa.load(ref_audio_path, sr=16000, mono=True)
122
+ asr_input = {"raw": audio, "sampling_rate": 16000}
123
+ except Exception:
124
+ # Fall back to letting the pipeline decode the file itself (ffmpeg).
125
+ asr_input = str(ref_audio_path)
126
+
127
+ try:
128
+ result = asr(asr_input, generate_kwargs={"task": "transcribe"})
129
+ except Exception as exc:
130
+ raise gr.Error(f"Automatic transcription failed: {exc}") from exc
131
+
132
+ text = (result.get("text") or "").strip()
133
+ if not text:
134
+ raise gr.Error(
135
+ "Automatic transcription produced no text — please type the transcript manually."
136
+ )
137
+ return text
138
+
139
+
140
  @spaces.GPU(duration=120)
141
  def generate_voice_design(
142
  text: str,
 
358
  )
359
  clone_ref_text = gr.Textbox(
360
  label="Reference transcript (exact)",
361
+ info="Auto-transcribed with Whisper when you add reference audio — please review and edit if needed.",
362
  placeholder="This is the exact transcript of the reference audio.",
363
  lines=2,
364
  )
365
+ clone_ref_audio.change(
366
+ fn=transcribe_reference,
367
+ inputs=[clone_ref_audio],
368
+ outputs=[clone_ref_text],
369
+ api_name="transcribe_reference",
370
+ )
371
  with gr.Accordion("Advanced settings", open=False):
372
  clone_seed = gr.Number(label="Seed", value=42, precision=0)
373
  clone_btn = gr.Button("Generate", variant="primary")
 
408
  )
409
  dir_ref_text = gr.Textbox(
410
  label="Reference transcript (exact)",
411
+ info="Auto-transcribed with Whisper when you add reference audio — please review and edit if needed.",
412
  placeholder="This is the exact transcript of the reference audio.",
413
  lines=2,
414
  )
415
+ dir_ref_audio.change(
416
+ fn=transcribe_reference,
417
+ inputs=[dir_ref_audio],
418
+ outputs=[dir_ref_text],
419
+ api_name="transcribe_reference_direction",
420
+ )
421
  with gr.Accordion("Advanced settings", open=False):
422
  dir_cfg = gr.Slider(
423
  label="CFG scale",
 
455
  "Weights/outputs are for research and non-commercial use only."
456
  )
457
 
458
+ try:
459
+ _get_asr()
460
+ print(f"Whisper ASR ({ASR_MODEL_ID}) loaded on CPU for reference transcription.")
461
+ except Exception as _exc: # pragma: no cover
462
+ print(f"Warning: could not preload Whisper ASR ({_exc}); will retry on first use.")
463
+
464
  demo.launch(mcp_server=True)