harp-dev commited on
Commit
4c67860
·
verified ·
1 Parent(s): 17c5062

Move to torch 2.8.0, load in the worker from a Hub mirror, and keep a lossless container

Browse files

Moves from torch 2.2.2, which ZeroGPU rejects, to 2.8.0, whose torchaudio still provides the module deepfilternet imports, loads the model in the worker alone from teamup-tech/DeepFilterNet-weights rather than the main branch of its GitHub repository, refuses an empty file, and returns a FLAC or AIFF input in its own container.

Files changed (2) hide show
  1. app.py +26 -14
  2. requirements.txt +2 -2
app.py CHANGED
@@ -2,13 +2,14 @@ import spaces # imported first, as ZeroGPU requires
2
 
3
  import os
4
  import tempfile
5
- from pathlib import Path
6
 
7
  import gradio as gr
8
  import numpy as np
9
  import soundfile as sf
10
  import librosa
11
  import torch
 
12
 
13
  from pyharp import ModelCard, build_endpoint, SampleRate, Channels
14
  from pyharp.tags import Subcategory
@@ -21,9 +22,8 @@ model_card = ModelCard(
21
  name="DeepFilterNet",
22
  description=(
23
  "Background noise suppression / speech enhancement using "
24
- "DeepFilterNet3. Input is converted to mono 48kHz. Slider controls "
25
- "strength through wet/dry blend. Denoising runs at 48 kHz in mono; the "
26
- "result is resampled back to the input's rate and copied across its "
27
  "channels, so the output matches the format it came in with but carries "
28
  "no stereo image. Repository: https://github.com/Rikorose/DeepFilterNet "
29
  "Paper: https://arxiv.org/abs/2305.08227"
@@ -32,6 +32,10 @@ model_card = ModelCard(
32
  tags=[Subcategory.DENOISING, SampleRate(48000), Channels(1)],
33
  )
34
 
 
 
 
 
35
  # -----------------------------
36
  # Device & Model Initialization
37
  # -----------------------------
@@ -39,9 +43,18 @@ model_card = ModelCard(
39
  DEVICE_STR = "cuda" if torch.cuda.is_available() else "cpu"
40
  DEVICE = torch.device(DEVICE_STR)
41
 
42
- # Load model 1 time into global memory
43
- MODEL, DF_STATE, _ = init_df()
44
- MODEL = MODEL.to(DEVICE)
 
 
 
 
 
 
 
 
 
45
 
46
 
47
  def load_audio_mono_48k(path: str):
@@ -91,9 +104,11 @@ def process_fn(input_audio_path: str, noise_atten_db: float) -> str:
91
  if not input_audio_path:
92
  raise gr.Error("Provide the speech to denoise.")
93
  try:
94
- sf.info(input_audio_path)
95
  except Exception as exc:
96
  raise gr.Error(f"Could not read the audio file: {exc}") from exc
 
 
97
 
98
  return denoise(input_audio_path, noise_atten_db)
99
 
@@ -120,11 +135,6 @@ def denoise(input_audio_path: str, noise_atten_db: float) -> str:
120
  # Slider strength
121
  out = apply_attenuation_db(noisy, enhanced, noise_atten_db, max_db=30.0)
122
 
123
- # Save output WAV and return path
124
- out_dir = Path(tempfile.gettempdir()) / "pyharp_dfnet_outputs"
125
- out_dir.mkdir(parents=True, exist_ok=True)
126
- out_path = out_dir / "denoised.wav"
127
-
128
  if original_sr != sr:
129
  out = librosa.resample(out, orig_sr=sr, target_sr=original_sr)
130
 
@@ -133,6 +143,8 @@ def denoise(input_audio_path: str, noise_atten_db: float) -> str:
133
  if original_channels > 1:
134
  out = np.tile(out[:, None], (1, original_channels))
135
 
 
 
136
  sf.write(str(out_path), out, original_sr)
137
  return str(out_path)
138
 
@@ -169,4 +181,4 @@ if __name__ == "__main__":
169
  process_fn=process_fn,
170
  )
171
 
172
- demo.queue().launch(show_error=True, pwa=True)
 
2
 
3
  import os
4
  import tempfile
5
+ from pathlib import Path
6
 
7
  import gradio as gr
8
  import numpy as np
9
  import soundfile as sf
10
  import librosa
11
  import torch
12
+ from huggingface_hub import snapshot_download
13
 
14
  from pyharp import ModelCard, build_endpoint, SampleRate, Channels
15
  from pyharp.tags import Subcategory
 
22
  name="DeepFilterNet",
23
  description=(
24
  "Background noise suppression / speech enhancement using "
25
+ "DeepFilterNet3. Slider controls strength through wet/dry blend. Denoising runs at "
26
+ "48 kHz in mono; the result is resampled back to the input's rate and copied across its "
 
27
  "channels, so the output matches the format it came in with but carries "
28
  "no stereo image. Repository: https://github.com/Rikorose/DeepFilterNet "
29
  "Paper: https://arxiv.org/abs/2305.08227"
 
32
  tags=[Subcategory.DENOISING, SampleRate(48000), Channels(1)],
33
  )
34
 
35
+ # A lossless input keeps its container. A lossy one comes back as WAV, since encoding the result
36
+ # lossily again would expose the artifacts of the first encode and add a second set.
37
+ LOSSLESS = {".wav", ".flac", ".aiff", ".aif"}
38
+
39
  # -----------------------------
40
  # Device & Model Initialization
41
  # -----------------------------
 
43
  DEVICE_STR = "cuda" if torch.cuda.is_available() else "cpu"
44
  DEVICE = torch.device(DEVICE_STR)
45
 
46
+ # pyharp runs process_fn in a worker, which imports this file as __mp_main__ and starts with the
47
+ # server, so the model is loaded there alone. deepfilternet would download it from the main branch
48
+ # of its GitHub repository, so it is read from a pinned mirror on the Hub instead, into a directory
49
+ # of its own, since loading writes beside the configuration.
50
+ if __name__ != "__main__":
51
+ _weights = snapshot_download(
52
+ "teamup-tech/DeepFilterNet-weights", revision="b2ec0e0c85db91c696d699a5cfc43ae7a3e3136a",
53
+ local_dir=os.path.join(tempfile.gettempdir(), "deepfilternet-weights"),
54
+ )
55
+ MODEL, DF_STATE, _ = init_df(model_base_dir=os.path.join(_weights, "DeepFilterNet3"),
56
+ log_file=None)
57
+ MODEL = MODEL.to(DEVICE)
58
 
59
 
60
  def load_audio_mono_48k(path: str):
 
104
  if not input_audio_path:
105
  raise gr.Error("Provide the speech to denoise.")
106
  try:
107
+ info = sf.info(input_audio_path)
108
  except Exception as exc:
109
  raise gr.Error(f"Could not read the audio file: {exc}") from exc
110
+ if info.frames == 0:
111
+ raise gr.Error("The audio file is empty.")
112
 
113
  return denoise(input_audio_path, noise_atten_db)
114
 
 
135
  # Slider strength
136
  out = apply_attenuation_db(noisy, enhanced, noise_atten_db, max_db=30.0)
137
 
 
 
 
 
 
138
  if original_sr != sr:
139
  out = librosa.resample(out, orig_sr=sr, target_sr=original_sr)
140
 
 
143
  if original_channels > 1:
144
  out = np.tile(out[:, None], (1, original_channels))
145
 
146
+ input_ext = Path(input_audio_path).suffix.lower()
147
+ out_path = Path(tempfile.mkdtemp()) / f"denoised{input_ext if input_ext in LOSSLESS else '.wav'}"
148
  sf.write(str(out_path), out, original_sr)
149
  return str(out_path)
150
 
 
181
  process_fn=process_fn,
182
  )
183
 
184
+ demo.queue().launch(show_error=True, pwa=True)
requirements.txt CHANGED
@@ -1,6 +1,6 @@
1
  deepfilternet==0.5.6
2
- torch==2.2.2
3
- torchaudio==2.2.2
4
  numpy==1.26.4
5
  soundfile==0.13.1
6
  librosa==0.11.0
 
1
  deepfilternet==0.5.6
2
+ torch==2.8.0
3
+ torchaudio==2.8.0
4
  numpy==1.26.4
5
  soundfile==0.13.1
6
  librosa==0.11.0