Offex commited on
Commit
02a2cfd
·
verified ·
1 Parent(s): 87e2920

Upload app.py

Browse files
Files changed (1) hide show
  1. app.py +357 -0
app.py ADDED
@@ -0,0 +1,357 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ import gradio as gr
3
+ import os
4
+ import uuid
5
+ from pydub import AudioSegment
6
+ from pydub.silence import split_on_silence
7
+ import re
8
+ import time
9
+
10
+
11
+ def clean_file_name(file_path):
12
+ # Get the base file name and extension
13
+ file_name = os.path.basename(file_path)
14
+ file_name, file_extension = os.path.splitext(file_name)
15
+
16
+ # Replace non-alphanumeric characters with an underscore
17
+ cleaned = re.sub(r'[^a-zA-Z\d]+', '_', file_name)
18
+
19
+ # Remove any multiple underscores
20
+ clean_file_name = re.sub(r'_+', '_', cleaned).strip('_')
21
+
22
+ # Generate a random UUID for uniqueness
23
+ random_uuid = uuid.uuid4().hex[:6]
24
+
25
+ # Combine cleaned file name with the original extension
26
+ clean_file_path = os.path.join(os.path.dirname(file_path), clean_file_name + f"_{random_uuid}" + file_extension)
27
+
28
+ return clean_file_path
29
+
30
+
31
+
32
+ def remove_silence(file_path, minimum_silence=50):
33
+ sound = AudioSegment.from_file(file_path) # auto-detects format
34
+ audio_chunks = split_on_silence(sound,
35
+ min_silence_len=100,
36
+ silence_thresh=-45,
37
+ keep_silence=minimum_silence)
38
+ combined = AudioSegment.empty()
39
+ for chunk in audio_chunks:
40
+ combined += chunk
41
+ output_path=clean_file_name(file_path)
42
+ combined.export(output_path) # format inferred from output file extension
43
+ return output_path
44
+
45
+
46
+
47
+ def calculate_duration(file_path):
48
+ audio = AudioSegment.from_file(file_path)
49
+ duration_seconds = len(audio) / 1000.0 # pydub uses milliseconds
50
+ return duration_seconds
51
+
52
+
53
+ # Some user uploads may trigger Hugging Face privacy policy checks, which can lead to account suspension
54
+ FILE_TIMESTAMPS = {}
55
+
56
+ def track_file(file_path):
57
+ FILE_TIMESTAMPS[file_path] = time.time()
58
+
59
+
60
+ def cleanup_tracked_files(max_age_seconds=3600):
61
+ now = time.time()
62
+ to_delete = []
63
+
64
+ for file_path, created_time in FILE_TIMESTAMPS.items():
65
+ if now - created_time > max_age_seconds:
66
+ if os.path.exists(file_path):
67
+ try:
68
+ os.remove(file_path)
69
+ print(f"🗑️ Deleted: {file_path}")
70
+ except Exception as e:
71
+ print(f"⚠️ Error deleting {file_path}: {e}")
72
+
73
+ to_delete.append(file_path)
74
+
75
+ # Remove from tracking
76
+ for f in to_delete:
77
+ FILE_TIMESTAMPS.pop(f, None)
78
+
79
+
80
+
81
+ def start_cleanup_worker(interval=3600):
82
+ def worker():
83
+ while True:
84
+ print("🔄 Cleaning tracked files...")
85
+ cleanup_tracked_files()
86
+ time.sleep(interval)
87
+
88
+ import threading
89
+ threading.Thread(target=worker, daemon=True).start()
90
+
91
+
92
+ def process_audio(audio_file, seconds=0.05):
93
+ if audio_file is None:
94
+ return None, None, "No file uploaded"
95
+
96
+ if not os.path.exists(audio_file):
97
+ return None, None, "File not found"
98
+
99
+ track_file(audio_file)
100
+
101
+ keep_silence = int(seconds * 1000)
102
+
103
+ output_audio_file = remove_silence(
104
+ audio_file,
105
+ minimum_silence=keep_silence
106
+ )
107
+
108
+ track_file(output_audio_file)
109
+
110
+ before = calculate_duration(audio_file)
111
+ after = calculate_duration(output_audio_file)
112
+
113
+ text = f"Old Duration: {before:.3f} seconds \nNew Duration: {after:.3f} seconds"
114
+
115
+ return output_audio_file, output_audio_file, text
116
+
117
+ # def ui():
118
+ # theme = gr.themes.Soft(font=[gr.themes.GoogleFont("Source Sans Pro"), "Arial", "sans-serif"])
119
+ # css = ".gradio-container {max-width: none !important;} .tab-content {padding: 20px;}"
120
+ # demo = gr.Interface(
121
+ # fn=process_audio,
122
+ # inputs=[
123
+ # gr.Audio(label="Upload Audio", type="filepath", sources=['upload', 'microphone']),
124
+ # gr.Number(label="Keep Silence Upto (In seconds)", value=0.05)
125
+ # ],
126
+ # outputs=[
127
+ # gr.Audio(label="Play Audio"),
128
+ # gr.File(label="Download Audio File"),
129
+ # gr.Textbox(label="Duration")
130
+ # ],
131
+ # title="Remove Silence From Audio",
132
+ # description="Upload an MP3 or WAV file, and it will remove silent parts from it.",
133
+ # theme=theme,
134
+ # css=css,
135
+ # )
136
+ # return demo
137
+
138
+
139
+
140
+
141
+ def ui():
142
+ theme = gr.themes.Soft(
143
+ font=[gr.themes.GoogleFont("Source Sans Pro"), "Arial", "sans-serif"]
144
+ )
145
+
146
+ css = """
147
+ .gradio-container {max-width: none !important;}
148
+ .tab-content {padding: 20px;}
149
+
150
+ /* Primary button - BLUE by default */
151
+ button.primary {
152
+ background-color: #2563eb !important;
153
+ color: white !important;
154
+ font-weight: 600;
155
+ border: none !important;
156
+ border-radius: 10px;
157
+ padding: 12px 18px;
158
+ font-size: 1.05em;
159
+ }
160
+
161
+ button.primary:hover {
162
+ background-color: #1e40af !important;
163
+ }
164
+ """
165
+
166
+ with gr.Blocks(theme=theme, css=css) as demo:
167
+
168
+ # Header
169
+ gr.HTML("""
170
+ <div style="text-align:center; margin:20px auto; max-width:800px;">
171
+ <h1 style="font-size:2.4em; margin-bottom:6px;">
172
+ 🔇 Remove Silence From Audio
173
+ </h1>
174
+
175
+ <p style="font-size:1.05em; color:#555; margin:0 0 10px;">
176
+ Upload an MP3 or WAV file, and it will remove silent parts from it.
177
+ </p>
178
+ <p style="font-size:0.8em; color:#999;">
179
+ ⚠️ Please don’t upload copyrighted content — it can take this Space offline.
180
+ </p>
181
+ <p style="font-size:0.9em; color:#777;">
182
+ Install locally on your computer, enjoy unlimited runs with no waiting queue
183
+ <a href="https://github.com/NeuralFalconYT/Remove-Silence-From-Audio" target="_blank" style="text-decoration:none;">
184
+ Download Link
185
+ </a>
186
+ </p>
187
+ </div>
188
+ """)
189
+
190
+
191
+
192
+
193
+
194
+ with gr.Row():
195
+ # LEFT: Inputs
196
+ with gr.Column(scale=1):
197
+ audio_input = gr.Audio(
198
+ label="Upload Audio",
199
+ type="filepath",
200
+ sources=["upload", "microphone"]
201
+ )
202
+
203
+ silence_threshold = gr.Number(
204
+ label="Keep Silence Upto (In seconds)",
205
+ value=0.05
206
+ )
207
+
208
+ submit_btn = gr.Button(
209
+ "🔇 Remove Silence",
210
+ variant="primary"
211
+ )
212
+
213
+ # RIGHT: Outputs
214
+ with gr.Column(scale=1):
215
+ audio_output = gr.Audio(label="Play Audio")
216
+ file_output = gr.File(label="Download Audio File")
217
+ duration_output = gr.Textbox(label="Duration")
218
+
219
+ submit_btn.click(
220
+ fn=process_audio, # <-- your function
221
+ inputs=[audio_input, silence_threshold],
222
+ outputs=[audio_output, file_output, duration_output]
223
+ )
224
+ gr.HTML("""
225
+ <style>
226
+ /* Futuristic Footer Styles */
227
+ @keyframes cyber-border-flow {
228
+ 0% {background-position: 0% 50%;}
229
+ 50% {background-position: 100% 50%;}
230
+ 100% {background-position: 0% 50%;}
231
+ }
232
+
233
+ .cyber-promo-card {
234
+ margin: 50px auto 30px auto;
235
+ max-width: 850px;
236
+ padding: 3px; /* Thickness of the gradient border */
237
+ border-radius: 20px;
238
+ background: linear-gradient(90deg, #ff00cc, #333399, #00f2ff);
239
+ background-size: 200% 200%;
240
+ animation: cyber-border-flow 4s ease infinite;
241
+ box-shadow: 0 0 15px rgba(0, 242, 255, 0.2);
242
+ }
243
+
244
+ .cyber-promo-inner {
245
+ background: #0f172a; /* Dark Slate background */
246
+ border-radius: 17px; /* Slightly less than parent to fit border */
247
+ padding: 30px 20px;
248
+ text-align: center;
249
+ position: relative;
250
+ overflow: hidden;
251
+ }
252
+
253
+ /* Subtle grid pattern overlay */
254
+ .cyber-promo-inner::before {
255
+ content: "";
256
+ position: absolute;
257
+ top: 0; left: 0; width: 100%; height: 100%;
258
+ background-image:
259
+ linear-gradient(rgba(255, 255, 255, 0.03) 1px, transparent 1px),
260
+ linear-gradient(90deg, rgba(255, 255, 255, 0.03) 1px, transparent 1px);
261
+ background-size: 40px 40px;
262
+ pointer-events: none;
263
+ z-index: 0;
264
+ }
265
+
266
+ .cyber-h2 {
267
+ color: #fff;
268
+ font-family: sans-serif;
269
+ font-size: 1.5rem;
270
+ font-weight: 800;
271
+ text-transform: uppercase;
272
+ letter-spacing: 2px;
273
+ margin: 0 0 10px 0;
274
+ text-shadow: 0 0 10px rgba(0, 204, 255, 0.6);
275
+ position: relative;
276
+ z-index: 1;
277
+ }
278
+
279
+ .cyber-p {
280
+ color: #cbd5e1;
281
+ font-family: sans-serif;
282
+ font-size: 1rem;
283
+ line-height: 1.5;
284
+ margin: 0 0 25px 0;
285
+ position: relative;
286
+ z-index: 1;
287
+ }
288
+
289
+ .cyber-button {
290
+ display: inline-block;
291
+ padding: 12px 35px;
292
+ background: transparent;
293
+ color: #00f2ff;
294
+ border: 2px solid #00f2ff;
295
+ border-radius: 6px;
296
+ text-decoration: none;
297
+ font-family: sans-serif;
298
+ font-weight: 700;
299
+ font-size: 0.95rem;
300
+ text-transform: uppercase;
301
+ letter-spacing: 1px;
302
+ transition: all 0.3s ease;
303
+ position: relative;
304
+ z-index: 1;
305
+ box-shadow: 0 0 10px rgba(0, 242, 255, 0.2);
306
+ }
307
+
308
+ .cyber-button:hover {
309
+ background: #00f2ff;
310
+ color: #000;
311
+ box-shadow: 0 0 30px rgba(0, 242, 255, 0.8);
312
+ transform: scale(1.02);
313
+ }
314
+
315
+ .dev-credit {
316
+ margin-top: 25px;
317
+ font-size: 0.8rem;
318
+ color: #64748b;
319
+ position: relative;
320
+ z-index: 1;
321
+ }
322
+ .dev-credit a {
323
+ color: #94a3b8;
324
+ text-decoration: none;
325
+ transition: color 0.2s;
326
+ }
327
+ .dev-credit a:hover {
328
+ color: #fff;
329
+ }
330
+ </style>
331
+
332
+ <div class="cyber-promo-card">
333
+ <div class="cyber-promo-inner">
334
+ <h2 class="cyber-h2">✂️ Remove Silence from Video is now available</h2>
335
+ <a href="https://huggingface.co/spaces/NeuralFalcon/Remove-Silence-From-Video"
336
+ target="_blank"
337
+ class="cyber-button">
338
+ Try Now
339
+ </a>
340
+ <div class="dev-credit">
341
+ Developed by <a href="https://github.com/NeuralFalconYT" target="_blank">NeuralFalconYT</a>
342
+ </div>
343
+ </div>
344
+ </div>
345
+ """)
346
+ return demo
347
+
348
+ import click
349
+ @click.command()
350
+ @click.option("--debug", is_flag=True, default=False, help="Enable debug mode.")
351
+ @click.option("--share", is_flag=True, default=False, help="Enable sharing of the interface.")
352
+ def main(debug, share):
353
+ start_cleanup_worker()
354
+ demo=ui()
355
+ demo.queue().launch(debug=debug, share=share)
356
+ if __name__ == "__main__":
357
+ main()