NeuralFalcon's picture
Update app.py
1e808b0 verified
import gradio as gr
import os
import uuid
from pydub import AudioSegment
from pydub.silence import split_on_silence
import re
import time
def clean_file_name(file_path):
# Get the base file name and extension
file_name = os.path.basename(file_path)
file_name, file_extension = os.path.splitext(file_name)
# Replace non-alphanumeric characters with an underscore
cleaned = re.sub(r'[^a-zA-Z\d]+', '_', file_name)
# Remove any multiple underscores
clean_file_name = re.sub(r'_+', '_', cleaned).strip('_')
# Generate a random UUID for uniqueness
random_uuid = uuid.uuid4().hex[:6]
# Combine cleaned file name with the original extension
clean_file_path = os.path.join(os.path.dirname(file_path), clean_file_name + f"_{random_uuid}" + file_extension)
return clean_file_path
def remove_silence(file_path, minimum_silence=50):
sound = AudioSegment.from_file(file_path) # auto-detects format
audio_chunks = split_on_silence(sound,
min_silence_len=100,
silence_thresh=-45,
keep_silence=minimum_silence)
combined = AudioSegment.empty()
for chunk in audio_chunks:
combined += chunk
output_path=clean_file_name(file_path)
combined.export(output_path) # format inferred from output file extension
return output_path
def calculate_duration(file_path):
audio = AudioSegment.from_file(file_path)
duration_seconds = len(audio) / 1000.0 # pydub uses milliseconds
return duration_seconds
# Some user uploads may trigger Hugging Face privacy policy checks, which can lead to account suspension
FILE_TIMESTAMPS = {}
def track_file(file_path):
FILE_TIMESTAMPS[file_path] = time.time()
def cleanup_tracked_files(max_age_seconds=3600):
now = time.time()
to_delete = []
for file_path, created_time in FILE_TIMESTAMPS.items():
if now - created_time > max_age_seconds:
if os.path.exists(file_path):
try:
os.remove(file_path)
print(f"🗑️ Deleted: {file_path}")
except Exception as e:
print(f"⚠️ Error deleting {file_path}: {e}")
to_delete.append(file_path)
# Remove from tracking
for f in to_delete:
FILE_TIMESTAMPS.pop(f, None)
def start_cleanup_worker(interval=3600):
def worker():
while True:
print("🔄 Cleaning tracked files...")
cleanup_tracked_files()
time.sleep(interval)
import threading
threading.Thread(target=worker, daemon=True).start()
def process_audio(audio_file, seconds=0.05):
if audio_file is None:
return None, None, "No file uploaded"
if not os.path.exists(audio_file):
return None, None, "File not found"
track_file(audio_file)
keep_silence = int(seconds * 1000)
output_audio_file = remove_silence(
audio_file,
minimum_silence=keep_silence
)
track_file(output_audio_file)
before = calculate_duration(audio_file)
after = calculate_duration(output_audio_file)
text = f"Old Duration: {before:.3f} seconds \nNew Duration: {after:.3f} seconds"
return output_audio_file, output_audio_file, text
# def ui():
# theme = gr.themes.Soft(font=[gr.themes.GoogleFont("Source Sans Pro"), "Arial", "sans-serif"])
# css = ".gradio-container {max-width: none !important;} .tab-content {padding: 20px;}"
# demo = gr.Interface(
# fn=process_audio,
# inputs=[
# gr.Audio(label="Upload Audio", type="filepath", sources=['upload', 'microphone']),
# gr.Number(label="Keep Silence Upto (In seconds)", value=0.05)
# ],
# outputs=[
# gr.Audio(label="Play Audio"),
# gr.File(label="Download Audio File"),
# gr.Textbox(label="Duration")
# ],
# title="Remove Silence From Audio",
# description="Upload an MP3 or WAV file, and it will remove silent parts from it.",
# theme=theme,
# css=css,
# )
# return demo
def ui():
theme = gr.themes.Soft(
font=[gr.themes.GoogleFont("Source Sans Pro"), "Arial", "sans-serif"]
)
css = """
.gradio-container {max-width: none !important;}
.tab-content {padding: 20px;}
/* Primary button - BLUE by default */
button.primary {
background-color: #2563eb !important;
color: white !important;
font-weight: 600;
border: none !important;
border-radius: 10px;
padding: 12px 18px;
font-size: 1.05em;
}
button.primary:hover {
background-color: #1e40af !important;
}
"""
with gr.Blocks(theme=theme, css=css) as demo:
# Header
gr.HTML("""
<div style="text-align:center; margin:20px auto; max-width:800px;">
<h1 style="font-size:2.4em; margin-bottom:6px;">
🔇 Remove Silence From Audio
</h1>
<p style="font-size:1.05em; color:#555; margin:0 0 10px;">
Upload an MP3 or WAV file, and it will remove silent parts from it.
</p>
<p style="font-size:0.8em; color:#999;">
⚠️ Please don’t upload copyrighted content — it can take this Space offline.
</p>
<p style="font-size:0.9em; color:#777;">
Install locally on your computer, enjoy unlimited runs with no waiting queue
<a href="https://github.com/NeuralFalconYT/Remove-Silence-From-Audio" target="_blank" style="text-decoration:none;">
Download Link
</a>
</p>
</div>
""")
with gr.Row():
# LEFT: Inputs
with gr.Column(scale=1):
audio_input = gr.Audio(
label="Upload Audio",
type="filepath",
sources=["upload", "microphone"]
)
silence_threshold = gr.Number(
label="Keep Silence Upto (In seconds)",
value=0.05
)
submit_btn = gr.Button(
"🔇 Remove Silence",
variant="primary"
)
# RIGHT: Outputs
with gr.Column(scale=1):
audio_output = gr.Audio(label="Play Audio")
file_output = gr.File(label="Download Audio File")
duration_output = gr.Textbox(label="Duration")
submit_btn.click(
fn=process_audio, # <-- your function
inputs=[audio_input, silence_threshold],
outputs=[audio_output, file_output, duration_output]
)
# gr.HTML("""
# <style>
# /* Futuristic Footer Styles */
# @keyframes cyber-border-flow {
# 0% {background-position: 0% 50%;}
# 50% {background-position: 100% 50%;}
# 100% {background-position: 0% 50%;}
# }
# .cyber-promo-card {
# margin: 50px auto 30px auto;
# max-width: 850px;
# padding: 3px; /* Thickness of the gradient border */
# border-radius: 20px;
# background: linear-gradient(90deg, #ff00cc, #333399, #00f2ff);
# background-size: 200% 200%;
# animation: cyber-border-flow 4s ease infinite;
# box-shadow: 0 0 15px rgba(0, 242, 255, 0.2);
# }
# .cyber-promo-inner {
# background: #0f172a; /* Dark Slate background */
# border-radius: 17px; /* Slightly less than parent to fit border */
# padding: 30px 20px;
# text-align: center;
# position: relative;
# overflow: hidden;
# }
# /* Subtle grid pattern overlay */
# .cyber-promo-inner::before {
# content: "";
# position: absolute;
# top: 0; left: 0; width: 100%; height: 100%;
# background-image:
# linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px),
# linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
# background-size: 40px 40px;
# pointer-events: none;
# z-index: 0;
# }
# .cyber-h2 {
# color: #fff;
# font-family: sans-serif;
# font-size: 1.5rem;
# font-weight: 800;
# text-transform: uppercase;
# letter-spacing: 2px;
# margin: 0 0 10px 0;
# text-shadow: 0 0 10px rgba(0, 204, 255, 0.6);
# position: relative;
# z-index: 1;
# }
# .cyber-p {
# color: #cbd5e1;
# font-family: sans-serif;
# font-size: 1rem;
# line-height: 1.5;
# margin: 0 0 25px 0;
# position: relative;
# z-index: 1;
# }
# .cyber-button {
# display: inline-block;
# padding: 12px 35px;
# background: transparent;
# color: #00f2ff;
# border: 2px solid #00f2ff;
# border-radius: 6px;
# text-decoration: none;
# font-family: sans-serif;
# font-weight: 700;
# font-size: 0.95rem;
# text-transform: uppercase;
# letter-spacing: 1px;
# transition: all 0.3s ease;
# position: relative;
# z-index: 1;
# box-shadow: 0 0 10px rgba(0, 242, 255, 0.2);
# }
# .cyber-button:hover {
# background: #00f2ff;
# color: #000;
# box-shadow: 0 0 30px rgba(0, 242, 255, 0.8);
# transform: scale(1.02);
# }
# .dev-credit {
# margin-top: 25px;
# font-size: 0.8rem;
# color: #64748b;
# position: relative;
# z-index: 1;
# }
# .dev-credit a {
# color: #94a3b8;
# text-decoration: none;
# transition: color 0.2s;
# }
# .dev-credit a:hover {
# color: #fff;
# }
# </style>
# <div class="cyber-promo-card">
# <div class="cyber-promo-inner">
# <h2 class="cyber-h2">✂️ Remove Silence from Video is now available</h2>
# <a href="https://huggingface.co/spaces/NeuralFalcon/Remove-Silence-From-Video"
# target="_blank"
# class="cyber-button">
# Try Now
# </a>
# <div class="dev-credit">
# Developed by <a href="https://github.com/NeuralFalconYT" target="_blank">NeuralFalconYT</a>
# </div>
# </div>
# </div>
# """)
return demo
import click
@click.command()
@click.option("--debug", is_flag=True, default=False, help="Enable debug mode.")
@click.option("--share", is_flag=True, default=False, help="Enable sharing of the interface.")
def main(debug, share):
start_cleanup_worker()
demo=ui()
demo.queue().launch(debug=debug, share=share)
if __name__ == "__main__":
main()