File size: 7,704 Bytes
b8720d8
 
e44537b
b8720d8
 
e44537b
b54912c
a023ec7
fae0d9b
e44537b
 
 
 
 
 
 
 
 
 
 
adc9e77
 
e44537b
 
 
 
adc9e77
e44537b
 
 
 
adc9e77
e44537b
 
adc9e77
7fbe622
adc9e77
e44537b
 
 
 
fae0d9b
e44537b
 
adc9e77
 
 
fae0d9b
a023ec7
b8720d8
fae0d9b
a023ec7
7fbe622
b54912c
fae0d9b
7fbe622
fae0d9b
 
7fbe622
 
b8720d8
a023ec7
 
fae0d9b
7fbe622
fae0d9b
 
 
 
 
7fbe622
 
fae0d9b
 
 
 
7fbe622
 
 
 
 
 
fae0d9b
7fbe622
fae0d9b
7fbe622
 
 
fae0d9b
 
7fbe622
fae0d9b
7fbe622
fae0d9b
7fbe622
 
fae0d9b
 
 
 
 
 
7fbe622
fae0d9b
7fbe622
 
fae0d9b
 
 
 
7fbe622
 
 
 
 
fae0d9b
7fbe622
fae0d9b
7fbe622
fae0d9b
 
 
7fbe622
 
 
fae0d9b
 
 
7fbe622
 
fae0d9b
7fbe622
 
 
fae0d9b
 
 
7fbe622
 
 
 
 
 
fae0d9b
 
7fbe622
 
 
fae0d9b
 
7fbe622
 
fae0d9b
7fbe622
fae0d9b
 
 
7fbe622
a023ec7
 
fae0d9b
7fbe622
 
fae0d9b
 
7fbe622
 
 
 
 
fae0d9b
7fbe622
e44537b
fae0d9b
7fbe622
fae0d9b
7fbe622
fae0d9b
7fbe622
 
 
fae0d9b
7fbe622
 
fae0d9b
7fbe622
 
fae0d9b
7fbe622
fae0d9b
7fbe622
fae0d9b
7fbe622
 
 
 
fae0d9b
 
 
7fbe622
 
fae0d9b
7fbe622
 
 
fae0d9b
7fbe622
 
 
 
 
 
adc9e77
7fbe622
 
 
 
 
e44537b
b8720d8
 
 
adc9e77
 
e44537b
b54912c
e44537b
b54912c
b8720d8
b54912c
adc9e77
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
import gradio as gr
import os
import uuid
from pydub import AudioSegment
from pydub.silence import split_on_silence
import re 
import click

# --- LOGIC SECTION (SAME) ---

def clean_file_name(file_path):
    file_name = os.path.basename(file_path)
    file_name, file_extension = os.path.splitext(file_name)
    cleaned = re.sub(r'[^a-zA-Z\d]+', '_', file_name)
    clean_file_name = re.sub(r'_+', '_', cleaned).strip('_')
    random_uuid = uuid.uuid4().hex[:6]
    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)
    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)
    return output_path

def calculate_duration(file_path):
    audio = AudioSegment.from_file(file_path)
    return len(audio) / 1000.0

def process_audio(audio_file, seconds=0.05):
    if not audio_file:
        return None, None, "⚠️ Please upload a file first."
    
    keep_silence = int(seconds * 1000)
    output_audio_file = remove_silence(audio_file, minimum_silence=keep_silence)
    before = calculate_duration(audio_file)
    after = calculate_duration(output_audio_file)
    text = f"⏱️ Old: {before:.2f}s | ✅ New: {after:.2f}s | 🚀 Saved: {before-after:.2f}s"
    return output_audio_file, output_audio_file, text

def reset_interface():
    return None, 0.05, None, None, ""

# --- NEW MOBILE-OPTIMIZED UI ---

def ui():
    # Clean Modern Font Theme
    theme = gr.themes.Soft(
        primary_hue="cyan",
        secondary_hue="slate",
        font=[gr.themes.GoogleFont("Poppins"), "sans-serif"], # Changed to Poppins (Cleaner)
    ).set(
        body_background_fill="#050505",
        block_background_fill="#121212",
        block_border_width="0px",
        input_background_fill="#1a1a1a"
    )

    css = """
    /* MOBILE FIX: Container width 100% karega */
    .gradio-container { 
        width: 100% !important;
        max-width: 100% !important; 
        padding: 10px !important;
        margin: 0 !important;
        overflow-x: hidden;
    }
    
    /* Font Change */
    * { font-family: 'Poppins', sans-serif !important; }

    /* RGB Animation */
    @keyframes rgb-flow {
        0% { background-position: 0% 50%; }
        50% { background-position: 100% 50%; }
        100% { background-position: 0% 50%; }
    }

    /* Title Styling - Mobile Friendly */
    .rgb-text {
        background: linear-gradient(45deg, #ff0000, #00ffd5, #002bff, #ff00c8);
        background-size: 300%;
        -webkit-background-clip: text;
        -webkit-text-fill-color: transparent;
        font-weight: 800;
        font-size: 2rem; /* Thoda chota kiya mobile ke liye */
        text-align: center;
        animation: rgb-flow 8s linear infinite;
        margin-bottom: 5px;
        line-height: 1.2;
    }
    
    .subtitle { 
        text-align: center; 
        color: #888; 
        font-size: 0.9rem; 
        margin-bottom: 15px; 
    }

    /* Card Styling */
    .rgb-card {
        background: #111;
        border-radius: 15px;
        padding: 2px; /* Border patla kiya */
        margin-bottom: 10px;
        position: relative;
    }
    
    .rgb-card::before {
        content: "";
        position: absolute;
        inset: 0;
        z-index: -1;
        background: linear-gradient(45deg, #ff0000, #00ffd5, #002bff, #ff00c8);
        background-size: 400%;
        border-radius: 15px;
        animation: rgb-flow 15s linear infinite;
        opacity: 0.6;
    }

    .inner-card {
        background: #0a0a0a;
        border-radius: 13px;
        padding: 15px;
    }

    /* Button Styling */
    .process-btn {
        background: linear-gradient(90deg, #00c6ff 0%, #0072ff 100%) !important;
        color: white !important;
        font-weight: 600 !important;
        border: none !important;
        box-shadow: 0 4px 15px rgba(0, 114, 255, 0.3);
    }
    .reset-btn {
        background: #ff0055 !important;
        color: white !important;
        border: none !important;
    }

    /* Stats Box Text Fix */
    .stat-box textarea {
        background-color: #000 !important;
        color: #00ff88 !important;
        font-family: monospace;
        font-size: 14px !important;
    }

    /* Mobile Specific Tweaks */
    @media (max-width: 768px) {
        .rgb-text { font-size: 1.5rem !important; } /* Mobile pe title chota */
        .inner-card { padding: 10px !important; }
        .process-btn, .reset-btn { width: 100%; margin-top: 5px; } /* Buttons full width */
    }
    """

    with gr.Blocks(theme=theme, css=css, title="Silence Remover Pro") as demo:
        
        gr.HTML("""
            <div class="rgb-text">SILENCE REMOVER</div>
            <div class="subtitle">Clean Audio • Fast • AI Powered</div>
        """)

        with gr.Group(elem_classes="rgb-card"):
            with gr.Column(elem_classes="inner-card"):
                
                # Mobile par ye stack ho jayega (upar-niche)
                with gr.Row():
                    
                    # --- INPUT SECTION ---
                    with gr.Column(scale=1):
                        gr.Markdown("### 📤 UPLOAD")
                        audio_input = gr.Audio(
                            label="Source", type="filepath", 
                            sources=["upload", "microphone"], show_label=False
                        )
                        
                        gr.Markdown("### 🎚️ SETTING")
                        silence_threshold = gr.Slider(
                            minimum=0, maximum=1, step=0.01, value=0.05,
                            label="Keep Silence (Sec)"
                        )
                        
                        submit_btn = gr.Button("🚀 PROCESS AUDIO", elem_classes="process-btn")

                    # --- OUTPUT SECTION ---
                    with gr.Column(scale=1):
                        gr.Markdown("### 🎧 RESULT")
                        audio_output = gr.Audio(
                            label="Clean Audio", show_label=False, interactive=False
                        )
                        
                        with gr.Row():
                            file_output = gr.File(label="Download", file_count="single", scale=2)
                            clear_btn = gr.Button("❌ RESET", elem_classes="reset-btn", scale=1)
                        
                        duration_output = gr.Textbox(
                            label="STATS", lines=2, 
                            elem_classes="stat-box", show_label=True
                        )

        gr.Markdown("""<div style="text-align: center; color: #555; font-size: 0.8rem; margin-top: 5px;">Made with ❤️</div>""")

        submit_btn.click(
            fn=process_audio, 
            inputs=[audio_input, silence_threshold], 
            outputs=[audio_output, file_output, duration_output]
        )
        
        clear_btn.click(
            fn=reset_interface, 
            inputs=None, 
            outputs=[audio_input, silence_threshold, audio_output, file_output, duration_output]
        )

    return demo

@click.command()
@click.option("--debug", is_flag=True, default=False)
@click.option("--share", is_flag=True, default=False)
def main(debug, share):
    demo = ui()
    demo.queue().launch(debug=debug, share=share)

if __name__ == "__main__":
    main()