|
|
import gradio as gr |
|
|
import os, uuid, re, tempfile |
|
|
from pydub import AudioSegment, silence |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def clean_name(path, ext): |
|
|
name = re.sub(r'[^a-zA-Z0-9]+', '_', os.path.basename(path)) |
|
|
return f"{name}_{uuid.uuid4().hex[:6]}.{ext}" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def ensure_wav(path): |
|
|
if path.lower().endswith(".wav"): |
|
|
return path |
|
|
|
|
|
audio = AudioSegment.from_file(path) |
|
|
audio = audio.set_channels(1) |
|
|
|
|
|
tmp = tempfile.gettempdir() |
|
|
wav_path = os.path.join(tmp, clean_name(path, "wav")) |
|
|
audio.export(wav_path, format="wav") |
|
|
return wav_path |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def remove_silence_safe(path, keep_ms=250): |
|
|
audio = AudioSegment.from_wav(path) |
|
|
|
|
|
silence_thresh = audio.dBFS - 22 |
|
|
|
|
|
chunks = silence.split_on_silence( |
|
|
audio, |
|
|
min_silence_len=350, |
|
|
silence_thresh=silence_thresh, |
|
|
keep_silence=keep_ms |
|
|
) |
|
|
|
|
|
if not chunks: |
|
|
return path |
|
|
|
|
|
out = AudioSegment.empty() |
|
|
for c in chunks: |
|
|
out += c.fade_in(20).fade_out(20) |
|
|
|
|
|
out_path = os.path.join( |
|
|
tempfile.gettempdir(), |
|
|
clean_name(path, "wav") |
|
|
) |
|
|
out.export(out_path, format="wav") |
|
|
return out_path |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def duration(path): |
|
|
return len(AudioSegment.from_wav(path)) / 1000 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def process_audio(audio_file, keep_seconds): |
|
|
keep_ms = int(max(keep_seconds, 0.25) * 1000) |
|
|
|
|
|
wav = ensure_wav(audio_file) |
|
|
before = duration(wav) |
|
|
|
|
|
cleaned = remove_silence_safe(wav, keep_ms) |
|
|
after = duration(cleaned) |
|
|
|
|
|
|
|
|
final_mp3 = cleaned.replace(".wav", ".mp3") |
|
|
AudioSegment.from_wav(cleaned).export(final_mp3, format="mp3") |
|
|
|
|
|
info = ( |
|
|
f"Old Duration : {before:.2f}s\n" |
|
|
f"New Duration : {after:.2f}s\n" |
|
|
f"Silence Removed : {before - after:.2f}s" |
|
|
) |
|
|
|
|
|
return final_mp3, final_mp3, info |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
with gr.Blocks(title="Fast Silence Remover") as demo: |
|
|
gr.Markdown( |
|
|
"## ⚡ Fast MP3/WAV Silence Remover (No Word Loss)" |
|
|
) |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(): |
|
|
audio = gr.Audio( |
|
|
type="filepath", |
|
|
sources=["upload"], |
|
|
label="Upload MP3 or WAV" |
|
|
) |
|
|
|
|
|
keep = gr.Number( |
|
|
value=0.25, |
|
|
label="Keep Silence (seconds)" |
|
|
) |
|
|
|
|
|
btn = gr.Button("Remove Silence") |
|
|
|
|
|
with gr.Column(): |
|
|
out_audio = gr.Audio(label="Processed Audio") |
|
|
out_file = gr.File(label="Download") |
|
|
info = gr.Textbox(label="Info") |
|
|
|
|
|
btn.click( |
|
|
process_audio, |
|
|
[audio, keep], |
|
|
[out_audio, out_file, info] |
|
|
) |
|
|
|
|
|
demo.queue().launch() |