MON3EMPASHA's picture
Remove denoise dependencies from Space
e57bd8f
Raw
History Blame Contribute Delete
5.04 kB
import librosa
import numpy as np
import os
import soundfile as sf
import tempfile
import torch
# These will be set by main.py at startup
ASR_MODEL = None
ASR_PROCESSOR = None
DEVICE = "cpu"
def set_asr_globals(model, processor, device):
global ASR_MODEL, ASR_PROCESSOR, DEVICE
ASR_MODEL = model
ASR_PROCESSOR = processor
DEVICE = device
def reduce_noise(audio_array: np.ndarray, sr: int = 16000, noise_reduce_strength: float = 0.7) -> np.ndarray:
try:
stft = librosa.stft(audio_array, n_fft=2048, hop_length=512)
magnitude, phase = librosa.magphase(stft)
frame_energies = np.sum(magnitude, axis=0)
noise_threshold = np.percentile(frame_energies, 10)
noise_frames = magnitude[:, frame_energies <= noise_threshold]
if noise_frames.shape[1] > 0:
noise_profile = np.mean(noise_frames, axis=1, keepdims=True)
else:
noise_profile = np.min(magnitude, axis=1, keepdims=True)
magnitude_denoised = magnitude - (noise_reduce_strength * noise_profile)
magnitude_denoised = np.maximum(magnitude_denoised, 0.0)
smoothing_factor = 0.05
magnitude_denoised = (1 - smoothing_factor) * magnitude_denoised + smoothing_factor * magnitude
stft_denoised = magnitude_denoised * phase
audio_denoised = librosa.istft(stft_denoised, hop_length=512, length=len(audio_array))
original_peak = np.abs(audio_array).max()
denoised_peak = np.abs(audio_denoised).max()
if denoised_peak > 0:
audio_denoised = audio_denoised * (original_peak / denoised_peak)
return audio_denoised
except Exception as e:
print(f"[WARNING] Noise reduction failed: {e}, returning original audio")
return audio_array
def should_reduce_noise() -> bool:
return os.environ.get("USE_NOISE_REDUCTION", "false").lower() == "true"
def convert_audio_to_wav(audio_bytes: bytes, target_sr: int = 16000, filename: str = None) -> np.ndarray:
if not audio_bytes or len(audio_bytes) == 0:
raise ValueError("No audio data received")
if filename:
ext = os.path.splitext(filename)[1].lower()
if not ext:
ext = ".wav"
else:
ext = ".wav"
with tempfile.NamedTemporaryFile(suffix=ext, delete=False) as tmp_file:
tmp_file.write(audio_bytes)
tmp_path = tmp_file.name
try:
try:
audio_array, sr = sf.read(tmp_path, dtype="float32")
if len(audio_array.shape) > 1:
audio_array = audio_array.mean(axis=1)
if sr != target_sr:
audio_array = librosa.resample(audio_array, orig_sr=sr, target_sr=target_sr)
except Exception:
audio_array, sr = librosa.load(
tmp_path,
sr=target_sr,
mono=True,
res_type="kaiser_best",
)
if audio_array is None or len(audio_array) == 0:
raise ValueError("Audio file is empty or unreadable")
max_val = np.abs(audio_array).max()
if max_val > 0:
if max_val > 1.0:
audio_array = audio_array / max_val
else:
raise ValueError("Audio contains only silence")
if should_reduce_noise():
audio_array = reduce_noise(audio_array, sr=target_sr, noise_reduce_strength=0.7)
return audio_array
except Exception as e:
raise ValueError(f"Failed to convert audio file '{filename or 'unknown'}': {str(e)}")
finally:
if os.path.exists(tmp_path):
try:
os.unlink(tmp_path)
except Exception:
pass
def validate_audio_duration(audio_array: np.ndarray, sr: int = 16000) -> bool:
duration = len(audio_array) / sr
if duration < 0.5:
raise ValueError(f"Audio too short: {duration:.2f}s (minimum 0.5s)")
if duration > 20:
raise ValueError(f"Audio too long: {duration:.2f}s (maximum 20s)")
return True
def transcribe_audio(audio_array: np.ndarray, sr: int = 16000, return_ctc_data: bool = False):
if ASR_MODEL is None or ASR_PROCESSOR is None:
raise RuntimeError("ASR model not loaded")
try:
inputs = ASR_PROCESSOR(
audio_array,
sampling_rate=sr,
return_tensors="pt",
padding=True,
)
inputs = {k: v.to(DEVICE) for k, v in inputs.items()}
with torch.inference_mode():
logits = ASR_MODEL(**inputs).logits
predicted_ids = torch.argmax(logits, dim=-1)
transcription = ASR_PROCESSOR.batch_decode(predicted_ids)[0]
probs = torch.nn.functional.softmax(logits, dim=-1)
confidence_scores = torch.max(probs, dim=-1)[0].cpu().numpy()[0]
if return_ctc_data:
return transcription.strip(), confidence_scores, logits, predicted_ids
return transcription.strip(), confidence_scores
except Exception as e:
raise RuntimeError(f"ASR transcription failed: {str(e)}")