harp-dev commited on
Commit
bc9667c
·
verified ·
1 Parent(s): a9beb92

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +135 -0
app.py ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import tempfile
3
+ from pathlib import Path
4
+
5
+ import gradio as gr
6
+ import numpy as np
7
+ import soundfile as sf
8
+ import librosa
9
+ import torch
10
+
11
+ from pyharp import ModelCard, build_endpoint
12
+ from df import enhance, init_df
13
+
14
+ # -----------------------------
15
+ # Model metadata for HARP
16
+ # -----------------------------
17
+ model_card = ModelCard(
18
+ name="Background Noise Remover (DeepFilterNet3)",
19
+ description=(
20
+ "Background noise suppression / speech enhancement using DeepFilterNet3. "
21
+ "Input is converted to mono 48kHz. Slider controls strength through wet/dry blend."
22
+ ),
23
+ author="Derek Llanes",
24
+ tags=["denoise", "speech enhancement", "deepfilternet", "v3"],
25
+ )
26
+
27
+ # -----------------------------
28
+ # Device & Model Initialization
29
+ # -----------------------------
30
+ # Auto-detect GPU for Hugging Face deployment
31
+ DEVICE_STR = "cuda" if torch.cuda.is_available() else "cpu"
32
+ DEVICE = torch.device(DEVICE_STR)
33
+
34
+ # Load model 1 time into global memory
35
+ MODEL, DF_STATE, _ = init_df()
36
+ MODEL = MODEL.to(DEVICE)
37
+
38
+
39
+ def load_audio_mono_48k(path: str):
40
+ # Load audio from filepath, convert to mono float32, resample to 48kHz.
41
+ try:
42
+ audio, sr = sf.read(path, always_2d=False)
43
+ except Exception:
44
+ audio, sr = librosa.load(path, sr=None, mono=False)
45
+
46
+ audio = np.asarray(audio)
47
+
48
+ # stereo to mono
49
+ if audio.ndim == 2:
50
+ audio = audio.mean(axis=1)
51
+
52
+ audio = audio.astype(np.float32)
53
+
54
+ # resample to 48k
55
+ if sr != 48000:
56
+ audio = librosa.resample(audio, orig_sr=sr, target_sr=48000)
57
+ sr = 48000
58
+
59
+ return audio, sr
60
+
61
+
62
+ def apply_attenuation_db(noisy: np.ndarray, enhanced: np.ndarray, noise_atten_db: float, max_db: float = 30.0):
63
+ """
64
+ Map Noise Attenuation (dB) slider to a stable strength in [0,1]
65
+ and crossfade between original and enhanced audio.
66
+ """
67
+ # convert dB slider into [0,1]
68
+ s = float(noise_atten_db) / float(max_db)
69
+ s = max(0.0, min(1.0, s))
70
+
71
+ # make same length
72
+ n = min(len(noisy), len(enhanced))
73
+ noisy = noisy[:n]
74
+ enhanced = enhanced[:n]
75
+
76
+ out = (1.0 - s) * noisy + s * enhanced
77
+ return out.astype(np.float32)
78
+
79
+
80
+ @torch.inference_mode()
81
+ def process_fn(input_audio_path: str, noise_atten_db: float) -> str:
82
+ if not input_audio_path:
83
+ raise ValueError("No input audio provided.")
84
+
85
+ # Load and normalize
86
+ noisy, sr = load_audio_mono_48k(input_audio_path)
87
+
88
+ # numpy to torch, add channel dim [T] to [1, T]
89
+ noisy_t = torch.from_numpy(noisy).float().unsqueeze(0).to(DEVICE)
90
+
91
+ # Denoise, then remove added channel and back to numpy
92
+ enhanced_t = enhance(MODEL, DF_STATE, noisy_t)
93
+ enhanced = enhanced_t.squeeze(0).detach().cpu().numpy()
94
+
95
+ # Slider strength
96
+ out = apply_attenuation_db(noisy, enhanced, noise_atten_db, max_db=30.0)
97
+
98
+ # Save output WAV and return path
99
+ out_dir = Path(tempfile.gettempdir()) / "pyharp_dfnet_outputs"
100
+ out_dir.mkdir(parents=True, exist_ok=True)
101
+ out_path = out_dir / "denoised.wav"
102
+
103
+ sf.write(str(out_path), out, sr)
104
+ return str(out_path)
105
+
106
+
107
+ # -----------------------------
108
+ # Gradio endpoint
109
+ # -----------------------------
110
+ with gr.Blocks() as demo:
111
+ input_components = [
112
+ gr.Audio(type="filepath", label="Input Audio").harp_required(True),
113
+ gr.Slider(
114
+ minimum=0,
115
+ maximum=30,
116
+ step=1,
117
+ value=12,
118
+ label="Noise Attenuation (dB)",
119
+ info="0 = no change, 30 = strongest. Implemented as wet/dry strength.",
120
+ ),
121
+ ]
122
+
123
+ output_components = [
124
+ gr.Audio(type="filepath", label="Output Audio")
125
+ .set_info("Denoised audio output."),
126
+ ]
127
+
128
+ app = build_endpoint(
129
+ model_card=model_card,
130
+ input_components=input_components,
131
+ output_components=output_components,
132
+ process_fn=process_fn,
133
+ )
134
+
135
+ demo.queue().launch(show_error=False, pwa=True)