testingfaces commited on
Commit
14116df
Β·
verified Β·
1 Parent(s): eaa431b

Update denoiser.py

Browse files
Files changed (1) hide show
  1. denoiser.py +41 -70
denoiser.py CHANGED
@@ -1,20 +1,17 @@
1
  """
2
  Denoiser β€” Cleanvoice SDK (cleanvoice-sdk)
3
- No Cloudinary needed β€” SDK supports local file path directly.
4
 
5
- QUALITY FIX:
6
- - Cleanvoice receives the ORIGINAL quality WAV (48kHz stereo preserved)
7
- - 16kHz mono conversion is only done for Whisper transcription (in transcriber.py)
8
- - Final output preserves full original sample rate + channels
9
 
10
  Install: pip install cleanvoice-sdk
11
- Only requires: CLEANVOICE_API_KEY in HF Space secrets.
12
  """
13
 
14
  import os
15
  import re
16
  import logging
17
- import subprocess
18
 
19
  logger = logging.getLogger(__name__)
20
 
@@ -23,14 +20,14 @@ CLEANVOICE_API_KEY = os.environ.get(
23
  "cvk_r1z_P4IyEBE.Oy3JnO2_WS3msTTzYhccTLqzcE1Tp2wZgI02vHF17BA"
24
  )
25
 
26
- # Filler words removed from transcript text (text-side cleanup)
27
  FILLER_PATTERN = r'\b(um|uh|hmm|basically|like|ante|ane|matlab|yani|acha|right|okay)\b'
28
 
29
 
30
  class Denoiser:
31
  def __init__(self):
32
  if CLEANVOICE_API_KEY:
33
- print("[Denoiser] βœ… Cleanvoice SDK ready (no Cloudinary needed)")
34
  else:
35
  print("[Denoiser] ⚠️ No CLEANVOICE_API_KEY β€” denoising will be skipped")
36
 
@@ -43,67 +40,37 @@ class Denoiser:
43
  remove_silences: bool = True,
44
  **kwargs) -> dict:
45
  """
46
- Process audio using cleanvoice-sdk.
47
- QUALITY FIX: Sends original quality to Cleanvoice (NOT downsampled).
48
  Returns {'audio_path': str, 'stats': dict}
49
  """
50
  stats = {"noise_method": "Cleanvoice SDK"}
51
 
52
- # ── Step 1: Convert to WAV but PRESERVE original sample rate + channels ──
53
- # FIX: Do NOT force 16kHz mono here β€” that was destroying quality.
54
- # 16kHz mono is only needed for Whisper (handled in transcriber.py).
55
- # Cleanvoice works best with original quality audio.
56
- standard_wav = os.path.join(out_dir, "input_converted.wav")
57
-
58
- # Get original sample rate and channels first
59
- try:
60
- import subprocess as sp
61
- probe = sp.run([
62
- "ffprobe", "-v", "error",
63
- "-show_entries", "stream=sample_rate,channels",
64
- "-of", "default=noprint_wrappers=1:nokey=1",
65
- audio_path
66
- ], capture_output=True, text=True)
67
- lines = probe.stdout.strip().split("\n")
68
- orig_sr = int(lines[0]) if lines[0].isdigit() else 48000
69
- orig_ch = int(lines[1]) if len(lines) > 1 and lines[1].isdigit() else 2
70
- except Exception:
71
- orig_sr, orig_ch = 48000, 2
72
-
73
- print(f"[Denoiser] Original audio: {orig_sr}Hz, {orig_ch}ch")
74
-
75
- # Convert to WAV keeping original sample rate and channels
76
- result = subprocess.run([
77
- "ffmpeg", "-y", "-i", audio_path,
78
- "-ar", str(orig_sr), # preserve original sample rate
79
- "-ac", str(orig_ch), # preserve original channels
80
- "-acodec", "pcm_s16le",
81
- standard_wav
82
- ], capture_output=True)
83
-
84
- if result.returncode != 0:
85
- logger.error(f"[Denoiser] FFmpeg conversion failed: {result.stderr.decode()}")
86
- return {"audio_path": audio_path, "stats": stats}
87
-
88
- print(f"[Denoiser] βœ… Converted to WAV ({orig_sr}Hz, {orig_ch}ch) β€” quality preserved")
89
-
90
- # ── Step 2: Check API key ─────────────────────────────────────
91
  if not CLEANVOICE_API_KEY:
92
- logger.warning("[Denoiser] No API key β€” skipping, returning converted WAV")
93
  stats["noise_method"] = "Skipped (no API key)"
94
- return {"audio_path": standard_wav, "stats": stats}
95
 
96
- # ── Step 3: Run Cleanvoice SDK ────────────────────────────────
 
 
 
 
97
  try:
98
  from cleanvoice import Cleanvoice
99
 
100
- client = Cleanvoice.from_env()
101
- clean_wav = os.path.join(out_dir, "cleanvoice_output.wav")
 
 
 
102
 
103
- print(f"[Denoiser] Sending original quality audio to Cleanvoice...")
 
104
 
105
  result_cv = client.process(
106
- standard_wav, # original quality WAV βœ…
107
  remove_noise=True,
108
  studio_sound=True,
109
  normalize=True,
@@ -115,22 +82,26 @@ class Denoiser:
115
  breath=True,
116
  )
117
 
118
- result_cv.audio.download(clean_wav)
119
- print(f"[Denoiser] βœ… Cleanvoice done β€” saved to {clean_wav}")
120
-
121
- stats.update({
122
- "noise_method": "Cleanvoice SDK βœ…",
123
- "fillers_removed": "yes" if remove_fillers else "no",
124
- "stutters_removed": "yes" if remove_stutters else "no",
125
- "silences_removed": "yes" if remove_silences else "no",
126
- })
127
- return {"audio_path": clean_wav, "stats": stats}
 
 
 
 
128
 
129
  except Exception as e:
130
- logger.error(f"[Denoiser] Cleanvoice SDK failed: {e}", exc_info=True)
131
- print(f"[Denoiser] ⚠️ Cleanvoice failed ({e}) β€” returning converted WAV")
132
  stats["noise_method"] = f"Cleanvoice failed: {str(e)[:120]}"
133
- return {"audio_path": standard_wav, "stats": stats}
134
 
135
  # ══════════════════════════════════════════════════════════════════
136
  # TEXT-SIDE FILLER CLEANUP
 
1
  """
2
  Denoiser β€” Cleanvoice SDK (cleanvoice-sdk)
 
3
 
4
+ FIX: Send the RAW original audio directly to Cleanvoice API β€” no conversion,
5
+ no touching, no format changes. Cleanvoice accepts all common formats.
6
+ 16kHz mono conversion is ONLY done in transcriber.py for Whisper.
 
7
 
8
  Install: pip install cleanvoice-sdk
9
+ Requires: CLEANVOICE_API_KEY in HF Space secrets.
10
  """
11
 
12
  import os
13
  import re
14
  import logging
 
15
 
16
  logger = logging.getLogger(__name__)
17
 
 
20
  "cvk_r1z_P4IyEBE.Oy3JnO2_WS3msTTzYhccTLqzcE1Tp2wZgI02vHF17BA"
21
  )
22
 
23
+ # Filler words removed from transcript text (text-side cleanup only)
24
  FILLER_PATTERN = r'\b(um|uh|hmm|basically|like|ante|ane|matlab|yani|acha|right|okay)\b'
25
 
26
 
27
  class Denoiser:
28
  def __init__(self):
29
  if CLEANVOICE_API_KEY:
30
+ print("[Denoiser] βœ… Cleanvoice SDK ready")
31
  else:
32
  print("[Denoiser] ⚠️ No CLEANVOICE_API_KEY β€” denoising will be skipped")
33
 
 
40
  remove_silences: bool = True,
41
  **kwargs) -> dict:
42
  """
43
+ Send raw audio directly to Cleanvoice β€” no pre-processing.
44
+ Cleanvoice handles MP3, WAV, AAC, FLAC, OGG, OPUS, M4A natively.
45
  Returns {'audio_path': str, 'stats': dict}
46
  """
47
  stats = {"noise_method": "Cleanvoice SDK"}
48
 
49
+ # ── Check API key ─────────────────────────────────────────────
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
  if not CLEANVOICE_API_KEY:
51
+ logger.warning("[Denoiser] No API key β€” skipping denoising")
52
  stats["noise_method"] = "Skipped (no API key)"
53
+ return {"audio_path": audio_path, "stats": stats}
54
 
55
+ # ── Send RAW audio directly to Cleanvoice ─────────────────────
56
+ # FIX: Do NOT convert or touch the audio before sending.
57
+ # The old code was converting to 16kHz mono WAV first,
58
+ # which degraded quality and likely confused Cleanvoice.
59
+ # Cleanvoice accepts the original file as-is.
60
  try:
61
  from cleanvoice import Cleanvoice
62
 
63
+ client = Cleanvoice(api_key=CLEANVOICE_API_KEY)
64
+
65
+ # Determine output filename (keep same extension as input)
66
+ ext = os.path.splitext(audio_path)[1] or ".wav"
67
+ clean_out = os.path.join(out_dir, f"cleanvoice_output{ext}")
68
 
69
+ print(f"[Denoiser] Sending raw audio to Cleanvoice: {audio_path}")
70
+ print(f"[Denoiser] File size: {os.path.getsize(audio_path) / 1024:.1f} KB")
71
 
72
  result_cv = client.process(
73
+ audio_path, # RAW original file β€” no conversion βœ…
74
  remove_noise=True,
75
  studio_sound=True,
76
  normalize=True,
 
82
  breath=True,
83
  )
84
 
85
+ result_cv.audio.download(clean_out)
86
+
87
+ if os.path.exists(clean_out) and os.path.getsize(clean_out) > 0:
88
+ print(f"[Denoiser] βœ… Cleanvoice done β†’ {clean_out} "
89
+ f"({os.path.getsize(clean_out) / 1024:.1f} KB)")
90
+ stats.update({
91
+ "noise_method": "Cleanvoice SDK βœ…",
92
+ "fillers_removed": "yes" if remove_fillers else "no",
93
+ "stutters_removed": "yes" if remove_stutters else "no",
94
+ "silences_removed": "yes" if remove_silences else "no",
95
+ })
96
+ return {"audio_path": clean_out, "stats": stats}
97
+ else:
98
+ raise RuntimeError("Cleanvoice returned empty/missing file")
99
 
100
  except Exception as e:
101
+ logger.error(f"[Denoiser] Cleanvoice failed: {e}", exc_info=True)
102
+ print(f"[Denoiser] ⚠️ Cleanvoice failed ({e}) β€” returning original audio unchanged")
103
  stats["noise_method"] = f"Cleanvoice failed: {str(e)[:120]}"
104
+ return {"audio_path": audio_path, "stats": stats}
105
 
106
  # ══════════════════════════════════════════════════════════════════
107
  # TEXT-SIDE FILLER CLEANUP