ASesYusuf1 commited on
Commit
cc64221
Β·
verified Β·
1 Parent(s): 338b675

Update gui.py

Browse files
Files changed (1) hide show
  1. gui.py +592 -12
gui.py CHANGED
@@ -1,17 +1,597 @@
 
 
 
 
 
1
  import gradio as gr
2
  import argparse
 
 
 
 
 
 
3
 
4
- parser = argparse.ArgumentParser()
5
- parser.add_argument("--port", type=int, default=7860)
6
- args = parser.parse_args()
7
 
8
- # Define your Gradio Blocks or Interface
9
- app = gr.Blocks()
10
- with app:
11
- gr.Markdown("Hello, World!")
12
- input_text = gr.Textbox()
13
- output_text = gr.Textbox()
14
- gr.Button("Submit").click(fn=lambda x: x.upper(), inputs=input_text, outputs=output_text)
15
 
16
- # Launch with share=True for remote access or localhost for local testing
17
- app.launch(server_name="0.0.0.0", server_port=args.port, share=True) # Or server_name="127.0.0.1" for local
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import sys
3
+ import torch
4
+ import logging
5
+ from yt_dlp import YoutubeDL
6
  import gradio as gr
7
  import argparse
8
+ from audio_separator.separator import Separator
9
+ import numpy as np
10
+ import librosa
11
+ import soundfile as sf
12
+ from ensemble import ensemble_files
13
+ import shutil
14
 
15
+ # Device and autocast setup
16
+ device = "cuda" if torch.cuda.is_available() else "cpu"
17
+ use_autocast = device == "cuda"
18
 
19
+ # Logging setup
20
+ logging.basicConfig(level=logging.INFO)
21
+ logger = logging.getLogger(__name__)
 
 
 
 
22
 
23
+ # Model dictionaries organized by category
24
+ ROFORMER_MODELS = {
25
+ "Vocals": {
26
+ 'MelBand Roformer | Big Beta 6X by unwa': 'melband_roformer_big_beta6x.ckpt',
27
+ 'MelBand Roformer Kim | Big Beta 4 FT by unwa': 'melband_roformer_big_beta4.ckpt',
28
+ 'MelBand Roformer Kim | Big Beta 5e FT by unwa': 'melband_roformer_big_beta5e.ckpt',
29
+ 'MelBand Roformer | Big Beta 6 by unwa': 'melband_roformer_big_beta6.ckpt',
30
+ 'MelBand Roformer | Vocals by Kimberley Jensen': 'vocals_mel_band_roformer.ckpt',
31
+ 'MelBand Roformer Kim | FT 3 by unwa': 'mel_band_roformer_kim_ft3_unwa.ckpt',
32
+ 'MelBand Roformer Kim | FT by unwa': 'mel_band_roformer_kim_ft_unwa.ckpt',
33
+ 'MelBand Roformer Kim | FT 2 by unwa': 'mel_band_roformer_kim_ft2_unwa.ckpt',
34
+ 'MelBand Roformer Kim | FT 2 Bleedless by unwa': 'mel_band_roformer_kim_ft2_bleedless_unwa.ckpt',
35
+ 'MelBand Roformer | Vocals by becruily': 'mel_band_roformer_vocals_becruily.ckpt',
36
+ 'MelBand Roformer | Vocals Fullness by Aname': 'mel_band_roformer_vocal_fullness_aname.ckpt',
37
+ 'BS Roformer | Vocals by Gabox': 'bs_roformer_vocals_gabox.ckpt',
38
+ 'MelBand Roformer | Vocals by Gabox': 'mel_band_roformer_vocals_gabox.ckpt',
39
+ 'MelBand Roformer | Vocals FV1 by Gabox': 'mel_band_roformer_vocals_fv1_gabox.ckpt',
40
+ 'MelBand Roformer | Vocals FV2 by Gabox': 'mel_band_roformer_vocals_fv2_gabox.ckpt',
41
+ 'MelBand Roformer | Vocals FV3 by Gabox': 'mel_band_roformer_vocals_fv3_gabox.ckpt',
42
+ 'MelBand Roformer | Vocals FV4 by Gabox': 'mel_band_roformer_vocals_fv4_gabox.ckpt',
43
+ 'BS Roformer | Chorus Male-Female by Sucial': 'model_chorus_bs_roformer_ep_267_sdr_24.1275.ckpt',
44
+ 'BS Roformer | Male-Female by aufr33': 'bs_roformer_male_female_by_aufr33_sdr_7.2889.ckpt',
45
+ },
46
+ "Instrumentals": {
47
+ 'MelBand Roformer | FVX by Gabox': 'mel_band_roformer_instrumental_fvx_gabox.ckpt',
48
+ 'MelBand Roformer | INSTV8N by Gabox': 'mel_band_roformer_instrumental_instv8n_gabox.ckpt',
49
+ 'MelBand Roformer | INSTV8 by Gabox': 'mel_band_roformer_instrumental_instv8_gabox.ckpt',
50
+ 'MelBand Roformer | INSTV7N by Gabox': 'mel_band_roformer_instrumental_instv7n_gabox.ckpt',
51
+ 'MelBand Roformer | Instrumental Bleedless V3 by Gabox': 'mel_band_roformer_instrumental_bleedless_v3_gabox.ckpt',
52
+ 'MelBand Roformer Kim | Inst V1 (E) Plus by Unwa': 'melband_roformer_inst_v1e_plus.ckpt',
53
+ 'MelBand Roformer Kim | Inst V1 Plus by Unwa': 'melband_roformer_inst_v1_plus.ckpt',
54
+ 'MelBand Roformer Kim | Inst V1 by Unwa': 'melband_roformer_inst_v1.ckpt',
55
+ 'MelBand Roformer Kim | Inst V1 (E) by Unwa': 'melband_roformer_inst_v1e.ckpt',
56
+ 'MelBand Roformer Kim | Inst V2 by Unwa': 'melband_roformer_inst_v2.ckpt',
57
+ 'MelBand Roformer | Instrumental by becruily': 'mel_band_roformer_instrumental_becruily.ckpt',
58
+ 'MelBand Roformer | Instrumental by Gabox': 'mel_band_roformer_instrumental_gabox.ckpt',
59
+ 'MelBand Roformer | Instrumental 2 by Gabox': 'mel_band_roformer_instrumental_2_gabox.ckpt',
60
+ 'MelBand Roformer | Instrumental 3 by Gabox': 'mel_band_roformer_instrumental_3_gabox.ckpt',
61
+ 'MelBand Roformer | Instrumental Bleedless V1 by Gabox': 'mel_band_roformer_instrumental_bleedless_v1_gabox.ckpt',
62
+ 'MelBand Roformer | Instrumental Bleedless V2 by Gabox': 'mel_band_roformer_instrumental_bleedless_v2_gabox.ckpt',
63
+ 'MelBand Roformer | Instrumental Fullness V1 by Gabox': 'mel_band_roformer_instrumental_fullness_v1_gabox.ckpt',
64
+ 'MelBand Roformer | Instrumental Fullness V2 by Gabox': 'mel_band_roformer_instrumental_fullness_v2_gabox.ckpt',
65
+ 'MelBand Roformer | Instrumental Fullness V3 by Gabox': 'mel_band_roformer_instrumental_fullness_v3_gabox.ckpt',
66
+ 'MelBand Roformer | Instrumental Fullness Noisy V4 by Gabox': 'mel_band_roformer_instrumental_fullness_noise_v4_gabox.ckpt',
67
+ 'MelBand Roformer | INSTV5 by Gabox': 'mel_band_roformer_instrumental_instv5_gabox.ckpt',
68
+ 'MelBand Roformer | INSTV5N by Gabox': 'mel_band_roformer_instrumental_instv5n_gabox.ckpt',
69
+ 'MelBand Roformer | INSTV6 by Gabox': 'mel_band_roformer_instrumental_instv6_gabox.ckpt',
70
+ 'MelBand Roformer | INSTV6N by Gabox': 'mel_band_roformer_instrumental_instv6n_gabox.ckpt',
71
+ 'MelBand Roformer | INSTV7 by Gabox': 'mel_band_roformer_instrumental_instv7_gabox.ckpt',
72
+ },
73
+ "InstVoc Duality": {
74
+ 'MelBand Roformer Kim | InstVoc Duality V1 by Unwa': 'melband_roformer_instvoc_duality_v1.ckpt',
75
+ 'MelBand Roformer Kim | InstVoc Duality V2 by Unwa': 'melband_roformer_instvox_duality_v2.ckpt',
76
+ },
77
+ "De-Reverb": {
78
+ 'BS-Roformer-De-Reverb': 'deverb_bs_roformer_8_384dim_10depth.ckpt',
79
+ 'MelBand Roformer | De-Reverb by anvuew': 'dereverb_mel_band_roformer_anvuew_sdr_19.1729.ckpt',
80
+ 'MelBand Roformer | De-Reverb Less Aggressive by anvuew': 'dereverb_mel_band_roformer_less_aggressive_anvuew_sdr_18.8050.ckpt',
81
+ 'MelBand Roformer | De-Reverb Mono by anvuew': 'dereverb_mel_band_roformer_mono_anvuew.ckpt',
82
+ 'MelBand Roformer | De-Reverb Big by Sucial': 'dereverb_big_mbr_ep_362.ckpt',
83
+ 'MelBand Roformer | De-Reverb Super Big by Sucial': 'dereverb_super_big_mbr_ep_346.ckpt',
84
+ 'MelBand Roformer | De-Reverb-Echo by Sucial': 'dereverb-echo_mel_band_roformer_sdr_10.0169.ckpt',
85
+ 'MelBand Roformer | De-Reverb-Echo V2 by Sucial': 'dereverb-echo_mel_band_roformer_sdr_13.4843_v2.ckpt',
86
+ 'MelBand Roformer | De-Reverb-Echo Fused by Sucial': 'dereverb_echo_mbr_fused.ckpt',
87
+ },
88
+ "Denoise": {
89
+ 'Mel-Roformer-Denoise-Aufr33': 'denoise_mel_band_roformer_aufr33_sdr_27.9959.ckpt',
90
+ 'Mel-Roformer-Denoise-Aufr33-Aggr': 'denoise_mel_band_roformer_aufr33_aggr_sdr_27.9768.ckpt',
91
+ 'MelBand Roformer | Denoise-Debleed by Gabox': 'mel_band_roformer_denoise_debleed_gabox.ckpt',
92
+ 'MelBand Roformer | Bleed Suppressor V1 by unwa-97chris': 'mel_band_roformer_bleed_suppressor_v1.ckpt',
93
+ },
94
+ "Karaoke": {
95
+ 'Mel-Roformer-Karaoke-Aufr33-Viperx': 'mel_band_roformer_karaoke_aufr33_viperx_sdr_10.1956.ckpt',
96
+ 'MelBand Roformer | Karaoke by Gabox': 'mel_band_roformer_karaoke_gabox.ckpt',
97
+ "MelBand Roformer | Karaoke by becruily": 'mel_band_roformer_karaoke_becruily.ckpt',
98
+ },
99
+ "General Purpose": {
100
+ 'BS-Roformer-Viperx-1297': 'model_bs_roformer_ep_317_sdr_12.9755.ckpt',
101
+ 'BS-Roformer-Viperx-1296': 'model_bs_roformer_ep_368_sdr_12.9628.ckpt',
102
+ 'BS-Roformer-Viperx-1053': 'model_bs_roformer_ep_937_sdr_10.5309.ckpt',
103
+ 'Mel-Roformer-Viperx-1143': 'model_mel_band_roformer_ep_3005_sdr_11.4360.ckpt',
104
+ 'Mel-Roformer-Crowd-Aufr33-Viperx': 'mel_band_roformer_crowd_aufr33_viperx_sdr_8.7144.ckpt',
105
+ 'MelBand Roformer Kim | SYHFT by SYH99999': 'MelBandRoformerSYHFT.ckpt',
106
+ 'MelBand Roformer Kim | SYHFT V2 by SYH99999': 'MelBandRoformerSYHFTV2.ckpt',
107
+ 'MelBand Roformer Kim | SYHFT V2.5 by SYH99999': 'MelBandRoformerSYHFTV2.5.ckpt',
108
+ 'MelBand Roformer Kim | SYHFT V3 by SYH99999': 'MelBandRoformerSYHFTV3Epsilon.ckpt',
109
+ 'MelBand Roformer Kim | Big SYHFT V1 by SYH99999': 'MelBandRoformerBigSYHFTV1.ckpt',
110
+ 'MelBand Roformer | Aspiration by Sucial': 'aspiration_mel_band_roformer_sdr_18.9845.ckpt',
111
+ 'MelBand Roformer | Aspiration Less Aggressive by Sucial': 'aspiration_mel_band_roformer_less_aggr_sdr_18.1201.ckpt',
112
+ }
113
+ }
114
+
115
+ OUTPUT_FORMATS = ['wav', 'flac', 'mp3', 'ogg', 'opus', 'm4a', 'aiff', 'ac3']
116
+
117
+ # CSS for UI styling
118
+ CSS = """
119
+ /* Modern ve Etkileşimli Tema */
120
+ #app-container {
121
+ max-width: 900px;
122
+ width: 100%;
123
+ margin: 0 auto;
124
+ padding: 1rem;
125
+ box-sizing: border-box;
126
+ display: flex;
127
+ flex-direction: column;
128
+ align-items: center;
129
+ min-height: 100vh;
130
+ background: linear-gradient(135deg, #1a0b2e, #2e1a47);
131
+ position: relative;
132
+ overflow: hidden;
133
+ }
134
+ body {
135
+ background: url('/content/logo.jpg') no-repeat center center fixed;
136
+ background-size: cover;
137
+ margin: 0;
138
+ padding: 0;
139
+ font-family: 'Roboto', sans-serif;
140
+ color: #e0e0e0;
141
+ display: flex;
142
+ justify-content: center;
143
+ }
144
+ body::after {
145
+ content: '';
146
+ position: fixed;
147
+ top: 0;
148
+ left: 0;
149
+ width: 100%;
150
+ height: 100%;
151
+ background: rgba(26, 11, 46, 0.8);
152
+ z-index: -1;
153
+ }
154
+ .logo-container {
155
+ position: fixed;
156
+ top: 1rem;
157
+ left: 50%;
158
+ transform: translateX(-50%);
159
+ z-index: 2000;
160
+ }
161
+ .logo-img {
162
+ width: 80px;
163
+ height: auto;
164
+ transition: transform 0.3s ease;
165
+ }
166
+ .logo-img:hover {
167
+ transform: scale(1.1);
168
+ }
169
+ .header-text {
170
+ text-align: center;
171
+ padding: 3rem 0 1rem;
172
+ color: #ff6b6b;
173
+ font-size: 2rem;
174
+ font-weight: 800;
175
+ text-shadow: 0 0 10px rgba(255, 107, 107, 0.7);
176
+ animation: glow 2s infinite alternate;
177
+ }
178
+ @keyframes glow {
179
+ 0% { text-shadow: 0 0 10px rgba(255, 107, 107, 0.7); }
180
+ 100% { text-shadow: 0 0 20px rgba(255, 107, 107, 1); }
181
+ }
182
+ .dubbing-theme {
183
+ background: rgba(46, 26, 71, 0.9);
184
+ border-radius: 12px;
185
+ padding: 1rem;
186
+ box-shadow: 0 5px 20px rgba(255, 107, 107, 0.3);
187
+ width: 100%;
188
+ transition: transform 0.3s ease;
189
+ }
190
+ .dubbing-theme:hover {
191
+ transform: translateY(-5px);
192
+ }
193
+ .footer {
194
+ text-align: center;
195
+ padding: 0.5rem;
196
+ color: #ff6b6b;
197
+ font-size: 12px;
198
+ position: fixed;
199
+ bottom: 0;
200
+ width: 100%;
201
+ max-width: 900px;
202
+ background: rgba(26, 11, 46, 0.7);
203
+ z-index: 1001;
204
+ left: 50%;
205
+ transform: translateX(-50%);
206
+ }
207
+ button {
208
+ background: #ff6b6b !important;
209
+ border: none !important;
210
+ color: #fff !important;
211
+ border-radius: 8px !important;
212
+ padding: 8px 16px !important;
213
+ font-size: 1rem !important;
214
+ font-weight: 600 !important;
215
+ transition: all 0.3s ease !important;
216
+ box-shadow: 0 2px 8px rgba(255, 107, 107, 0.4) !important;
217
+ }
218
+ button:hover {
219
+ transform: scale(1.05) !important;
220
+ background: #ff8787 !important;
221
+ box-shadow: 0 4px 12px rgba(255, 107, 107, 0.6) !important;
222
+ }
223
+ .compact-upload.horizontal {
224
+ display: flex !important;
225
+ align-items: center !important;
226
+ gap: 8px !important;
227
+ max-width: 300px !important;
228
+ padding: 6px 10px !important;
229
+ border: 2px dashed #ff6b6b !important;
230
+ background: rgba(46, 26, 71, 0.7) !important;
231
+ border-radius: 8px !important;
232
+ color: #e0e0e0 !important;
233
+ transition: border-color 0.3s ease !important;
234
+ }
235
+ .compact-upload.horizontal:hover {
236
+ border-color: #ff8787 !important;
237
+ }
238
+ .compact-upload.horizontal button {
239
+ padding: 4px 10px !important;
240
+ font-size: 0.8rem !important;
241
+ }
242
+ .gr-tab {
243
+ background: rgba(46, 26, 71, 0.7) !important;
244
+ border-radius: 8px 8px 0 0 !important;
245
+ padding: 0.5rem 1rem !important;
246
+ margin: 0 2px !important;
247
+ color: #e0e0e0 !important;
248
+ border: 2px solid #ff6b6b !important;
249
+ font-size: 1rem !important;
250
+ transition: all 0.3s ease !important;
251
+ }
252
+ .gr-tab-selected {
253
+ background: #ff6b6b !important;
254
+ color: #fff !important;
255
+ border: 2px solid #ff8787 !important;
256
+ box-shadow: 0 2px 8px rgba(255, 107, 107, 0.5) !important;
257
+ }
258
+ .compact-grid {
259
+ gap: 0.5rem !important;
260
+ max-height: 40vh;
261
+ overflow-y: auto;
262
+ padding: 1rem;
263
+ background: rgba(46, 26, 71, 0.7) !important;
264
+ border-radius: 10px;
265
+ border: 2px solid #ff6b6b !important;
266
+ width: 100%;
267
+ }
268
+ .compact-dropdown {
269
+ padding: 8px 12px !important;
270
+ border-radius: 8px !important;
271
+ border: 2px solid #ff6b6b !important;
272
+ background: rgba(46, 26, 71, 0.7) !important;
273
+ color: #e0e0e0 !important;
274
+ width: 100%;
275
+ font-size: 1rem !important;
276
+ transition: border-color 0.3s ease !important;
277
+ }
278
+ .compact-dropdown:hover {
279
+ border-color: #ff8787 !important;
280
+ }
281
+ .gr-slider input[type="range"] {
282
+ -webkit-appearance: none !important;
283
+ width: 100% !important;
284
+ height: 6px !important;
285
+ background: #ff6b6b !important;
286
+ border-radius: 3px !important;
287
+ outline: none !important;
288
+ }
289
+ .gr-slider input[type="range"]::-webkit-slider-thumb {
290
+ -webkit-appearance: none !important;
291
+ width: 16px !important;
292
+ height: 16px !important;
293
+ background: #fff !important;
294
+ border: 2px solid #ff6b6b !important;
295
+ border-radius: 50% !important;
296
+ cursor: pointer !important;
297
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2) !important;
298
+ }
299
+ .gr-slider input[type="range"]::-moz-range-thumb {
300
+ width: 16px !important;
301
+ height: 16px !important;
302
+ background: #fff !important;
303
+ border: 2px solid #ff6b6b !important;
304
+ border-radius: 50% !important;
305
+ cursor: pointer !important;
306
+ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.2) !important;
307
+ }
308
+ @media (max-width: 768px) {
309
+ #app-container {
310
+ max-width: 100%;
311
+ padding: 0.5rem;
312
+ }
313
+ .header-text {
314
+ font-size: 1.5rem;
315
+ padding: 2rem 0 0.5rem;
316
+ }
317
+ .logo-img {
318
+ width: 60px;
319
+ }
320
+ .compact-upload.horizontal {
321
+ max-width: 100% !important;
322
+ }
323
+ .compact-grid {
324
+ max-height: 30vh;
325
+ }
326
+ .footer {
327
+ max-width: 100%;
328
+ }
329
+ }
330
+ """
331
+
332
+ # Functions
333
+ def download_audio(url, out_dir="ytdl"):
334
+ """Download audio from a URL using yt-dlp."""
335
+ if not url:
336
+ raise ValueError("No URL provided.")
337
+
338
+ # Clear ytdl directory
339
+ if os.path.exists(out_dir):
340
+ shutil.rmtree(out_dir)
341
+ os.makedirs(out_dir, exist_ok=True)
342
+
343
+ ydl_opts = {
344
+ 'format': 'bestaudio/best',
345
+ 'postprocessors': [{'key': 'FFmpegExtractAudio', 'preferredcodec': 'wav', 'preferredquality': '192'}],
346
+ 'outtmpl': os.path.join(out_dir, '%(title)s.%(ext)s'),
347
+ }
348
+ try:
349
+ with YoutubeDL(ydl_opts) as ydl:
350
+ ydl.download([url])
351
+ info_dict = ydl.extract_info(url, download=True)
352
+ return ydl.prepare_filename(info_dict).rsplit('.', 1)[0] + '.wav'
353
+ except Exception as e:
354
+ raise RuntimeError(f"Download failed: {e}")
355
+
356
+ def roformer_separator(audio, model_key, seg_size, override_seg_size, overlap, pitch_shift, model_dir, output_dir, out_format, norm_thresh, amp_thresh, batch_size, exclude_stems="", progress=gr.Progress(track_tqdm=True)):
357
+ """Separate audio into stems using a Roformer model."""
358
+ if not audio:
359
+ raise ValueError("No audio file provided.")
360
+
361
+ # Convert override_seg_size to boolean
362
+ override_seg_size = override_seg_size == "True"
363
+
364
+ # Clear output directory
365
+ if os.path.exists(output_dir):
366
+ shutil.rmtree(output_dir)
367
+ os.makedirs(output_dir, exist_ok=True)
368
+
369
+ base_name = os.path.splitext(os.path.basename(audio))[0]
370
+ for category, models in ROFORMER_MODELS.items():
371
+ if model_key in models:
372
+ model = models[model_key]
373
+ break
374
+ else:
375
+ raise ValueError(f"Model '{model_key}' not found.")
376
+
377
+ logger.info(f"Separating {base_name} with {model_key}")
378
+ try:
379
+ separator = Separator(
380
+ log_level=logging.INFO,
381
+ model_file_dir=model_dir,
382
+ output_dir=output_dir,
383
+ output_format=out_format,
384
+ normalization_threshold=norm_thresh,
385
+ amplification_threshold=amp_thresh,
386
+ use_autocast=use_autocast,
387
+ mdxc_params={"segment_size": seg_size, "override_model_segment_size": override_seg_size, "batch_size": batch_size, "overlap": overlap, "pitch_shift": pitch_shift}
388
+ )
389
+ progress(0.2, desc="Loading model...")
390
+ separator.load_model(model_filename=model)
391
+ progress(0.7, desc="Separating audio...")
392
+ separation = separator.separate(audio)
393
+ stems = [os.path.join(output_dir, file_name) for file_name in separation]
394
+
395
+ # Filter excluded stems
396
+ if exclude_stems.strip():
397
+ excluded = [s.strip().lower() for s in exclude_stems.split(',')]
398
+ filtered_stems = [stem for stem in stems if not any(ex in os.path.basename(stem).lower() for ex in excluded)]
399
+ return filtered_stems[0] if filtered_stems else None, filtered_stems[1] if len(filtered_stems) > 1 else None
400
+ return stems[0], stems[1] if len(stems) > 1 else None
401
+ except Exception as e:
402
+ logger.error(f"Separation failed: {e}")
403
+ raise RuntimeError(f"Separation failed: {e}")
404
+
405
+ def auto_ensemble_process(audio, model_keys, seg_size, overlap, out_format, use_tta, model_dir, output_dir, norm_thresh, amp_thresh, batch_size, ensemble_method, exclude_stems="", weights=None, progress=gr.Progress()):
406
+ """Perform ensemble processing on audio using multiple Roformer models."""
407
+ if not audio or not model_keys:
408
+ raise ValueError("Audio or models missing.")
409
+
410
+ # Convert use_tta to boolean
411
+ use_tta = use_tta == "True"
412
+
413
+ # Clear output directory
414
+ if os.path.exists(output_dir):
415
+ shutil.rmtree(output_dir)
416
+ os.makedirs(output_dir, exist_ok=True)
417
+
418
+ base_name = os.path.splitext(os.path.basename(audio))[0]
419
+ logger.info(f"Ensemble for {base_name} with {model_keys}")
420
+
421
+ all_stems = []
422
+ total_models = len(model_keys)
423
+
424
+ # Separate audio with each model
425
+ for i, model_key in enumerate(model_keys):
426
+ for category, models in ROFORMER_MODELS.items():
427
+ if model_key in models:
428
+ model = models[model_key]
429
+ break
430
+ else:
431
+ continue
432
+
433
+ separator = Separator(
434
+ log_level=logging.INFO,
435
+ model_file_dir=model_dir,
436
+ output_dir=output_dir,
437
+ output_format=out_format,
438
+ normalization_threshold=norm_thresh,
439
+ amplification_threshold=amp_thresh,
440
+ use_autocast=use_autocast,
441
+ mdxc_params={"segment_size": seg_size, "overlap": overlap, "use_tta": use_tta, "batch_size": batch_size}
442
+ )
443
+ progress(0.1 + (0.4 / total_models) * i, desc=f"Loading {model_key}")
444
+ separator.load_model(model_filename=model)
445
+ progress(0.5 + (0.4 / total_models) * i, desc=f"Separating with {model_key}")
446
+ separation = separator.separate(audio)
447
+ stems = [os.path.join(output_dir, file_name) for file_name in separation]
448
+
449
+ # Filter excluded stems
450
+ if exclude_stems.strip():
451
+ excluded = [s.strip().lower() for s in exclude_stems.split(',')]
452
+ filtered_stems = [stem for stem in stems if not any(ex in os.path.basename(stem).lower() for ex in excluded)]
453
+ all_stems.extend(filtered_stems)
454
+ else:
455
+ all_stems.extend(stems)
456
+
457
+ if not all_stems:
458
+ raise ValueError("No valid stems for ensemble after exclusion.")
459
+
460
+ # Default weights if none provided
461
+ if weights is None or len(weights) != len(all_stems):
462
+ weights = [1.0] * len(all_stems)
463
+
464
+ # Perform ensemble
465
+ output_file = os.path.join(output_dir, f"{base_name}_ensemble_{ensemble_method}.{out_format}")
466
+ ensemble_args = [
467
+ "--files", *all_stems,
468
+ "--type", ensemble_method,
469
+ "--weights", *[str(w) for w in weights],
470
+ "--output", output_file
471
+ ]
472
+ progress(0.9, desc="Running ensemble...")
473
+ ensemble_files(ensemble_args)
474
+
475
+ progress(1.0, desc="Ensemble complete")
476
+ return output_file, f"Ensemble completed with {ensemble_method}, excluded: {exclude_stems if exclude_stems else 'None'}"
477
+
478
+ def update_roformer_models(category):
479
+ """Update Roformer model dropdown based on selected category."""
480
+ return gr.update(choices=list(ROFORMER_MODELS.get(category, {}).keys()))
481
+
482
+ def update_ensemble_models(category):
483
+ """Update ensemble model dropdown based on selected category."""
484
+ return gr.update(choices=list(ROFORMER_MODELS.get(category, {}).keys()))
485
+
486
+ # Interface creation
487
+ def create_interface():
488
+ """Create the Gradio interface for music source separation."""
489
+ with gr.Blocks(title="🎡 SESA Fast Separation 🎡", css=CSS, elem_id="app-container") as app:
490
+ gr.Markdown("<h1 class='header-text'>🎡 SESA Fast Separation 🎡</h1>")
491
+
492
+ with gr.Tabs():
493
+ # Settings Tab
494
+ with gr.Tab("βš™οΈ Settings"):
495
+ with gr.Group(elem_classes="dubbing-theme"):
496
+ gr.Markdown("### General Settings")
497
+ model_file_dir = gr.Textbox(value="/tmp/audio-separator-models/", label="πŸ“‚ Model Cache", placeholder="Path to model directory", interactive=True)
498
+ output_dir = gr.Textbox(value="output", label="πŸ“€ Output Directory", placeholder="Where to save results", interactive=True)
499
+ output_format = gr.Dropdown(value="wav", choices=OUTPUT_FORMATS, label="🎢 Output Format", interactive=True)
500
+ norm_threshold = gr.Slider(0.1, 1, value=0.9, step=0.1, label="πŸ”Š Normalization Threshold", interactive=True)
501
+ amp_threshold = gr.Slider(0.1, 1, value=0.3, step=0.1, label="πŸ“ˆ Amplification Threshold", interactive=True)
502
+ batch_size = gr.Slider(1, 16, value=4, step=1, label="⚑ Batch Size", interactive=True)
503
+
504
+ # Roformer Tab
505
+ with gr.Tab("🎀 Roformer"):
506
+ with gr.Group(elem_classes="dubbing-theme"):
507
+ gr.Markdown("### Audio Separation")
508
+ with gr.Row():
509
+ roformer_audio = gr.Audio(label="🎧 Upload Audio", type="filepath", interactive=True)
510
+ url_ro = gr.Textbox(label="πŸ”— Or Paste URL", placeholder="YouTube or audio URL", interactive=True)
511
+ download_roformer = gr.Button("⬇️ Download", variant="secondary")
512
+ roformer_exclude_stems = gr.Textbox(label="🚫 Exclude Stems", placeholder="e.g., vocals, drums (comma-separated)", interactive=True)
513
+ with gr.Row():
514
+ roformer_category = gr.Dropdown(label="πŸ“š Category", choices=list(ROFORMER_MODELS.keys()), value="General Purpose", interactive=True)
515
+ roformer_model = gr.Dropdown(label="πŸ› οΈ Model", choices=list(ROFORMER_MODELS["General Purpose"].keys()), interactive=True)
516
+ with gr.Row():
517
+ roformer_seg_size = gr.Slider(32, 4000, value=256, step=32, label="πŸ“ Segment Size", interactive=True)
518
+ roformer_overlap = gr.Slider(2, 10, value=8, step=1, label="πŸ”„ Overlap", interactive=True)
519
+ with gr.Row():
520
+ roformer_pitch_shift = gr.Slider(-12, 12, value=0, step=1, label="🎡 Pitch Shift", interactive=True)
521
+ roformer_override_seg_size = gr.Dropdown(choices=["True", "False"], value="False", label="πŸ”§ Override Segment Size", interactive=True)
522
+ roformer_button = gr.Button("βœ‚οΈ Separate Now!", variant="primary")
523
+ with gr.Row():
524
+ roformer_stem1 = gr.Audio(label="🎸 Stem 1", type="filepath", interactive=False)
525
+ roformer_stem2 = gr.Audio(label="πŸ₯ Stem 2", type="filepath", interactive=False)
526
+
527
+ # Auto Ensemble Tab
528
+ with gr.Tab("🎚️ Auto Ensemble"):
529
+ with gr.Group(elem_classes="dubbing-theme"):
530
+ gr.Markdown("### Ensemble Processing")
531
+ with gr.Row():
532
+ ensemble_audio = gr.Audio(label="🎧 Upload Audio", type="filepath", interactive=True)
533
+ url_ensemble = gr.Textbox(label="πŸ”— Or Paste URL", placeholder="YouTube or audio URL", interactive=True)
534
+ download_ensemble = gr.Button("⬇️ Download", variant="secondary")
535
+ ensemble_exclude_stems = gr.Textbox(label="🚫 Exclude Stems", placeholder="e.g., vocals, drums (comma-separated)", interactive=True)
536
+ with gr.Row():
537
+ ensemble_category = gr.Dropdown(label="πŸ“š Category", choices=list(ROFORMER_MODELS.keys()), value="Instrumentals", interactive=True)
538
+ ensemble_models = gr.Dropdown(label="πŸ› οΈ Models", choices=list(ROFORMER_MODELS["Instrumentals"].keys()), multiselect=True, interactive=True)
539
+ with gr.Row():
540
+ ensemble_seg_size = gr.Slider(32, 4000, value=256, step=32, label="πŸ“ Segment Size", interactive=True)
541
+ ensemble_overlap = gr.Slider(2, 10, value=8, step=1, label="πŸ”„ Overlap", interactive=True)
542
+ ensemble_use_tta = gr.Dropdown(choices=["True", "False"], value="False", label="πŸ” Use TTA", interactive=True)
543
+ ensemble_method = gr.Dropdown(label="βš™οΈ Ensemble Method", choices=['avg_wave', 'median_wave', 'max_wave', 'min_wave', 'avg_fft', 'median_fft', 'max_fft', 'min_fft'], value='avg_wave', interactive=True)
544
+ ensemble_weights = gr.Textbox(label="βš–οΈ Weights", placeholder="e.g., 1.0, 1.0 (comma-separated)", interactive=True)
545
+ ensemble_button = gr.Button("πŸŽ›οΈ Run Ensemble!", variant="primary")
546
+ ensemble_output = gr.Audio(label="🎢 Ensemble Result", type="filepath", interactive=False)
547
+ ensemble_status = gr.Textbox(label="πŸ“’ Status", interactive=False)
548
+
549
+ gr.HTML("<div class='footer'>Powered by Audio-Separator 🌟🎢 | Made with ❀️</div>")
550
+
551
+ # Event Handlers
552
+ roformer_category.change(update_roformer_models, inputs=[roformer_category], outputs=[roformer_model])
553
+ download_roformer.click(fn=download_audio, inputs=[url_ro], outputs=[roformer_audio])
554
+ roformer_button.click(
555
+ roformer_separator,
556
+ inputs=[
557
+ roformer_audio, roformer_model, roformer_seg_size, roformer_override_seg_size,
558
+ roformer_overlap, roformer_pitch_shift, model_file_dir, output_dir,
559
+ output_format, norm_threshold, amp_threshold, batch_size, roformer_exclude_stems
560
+ ],
561
+ outputs=[roformer_stem1, roformer_stem2]
562
+ )
563
+ ensemble_category.change(update_ensemble_models, inputs=[ensemble_category], outputs=[ensemble_models])
564
+ download_ensemble.click(fn=download_audio, inputs=[url_ensemble], outputs=[ensemble_audio])
565
+ ensemble_button.click(
566
+ fn=lambda audio, models, seg_size, overlap, out_format, use_tta, model_dir, output_dir,
567
+ norm_thresh, amp_thresh, batch_size, method, exclude_stems, weights_str:
568
+ auto_ensemble_process(
569
+ audio, models, seg_size, overlap, out_format, use_tta, model_dir, output_dir,
570
+ norm_thresh, amp_thresh, batch_size, method, exclude_stems,
571
+ [float(w.strip()) for w in weights_str.split(',')] if weights_str.strip() else None
572
+ ),
573
+ inputs=[
574
+ ensemble_audio, ensemble_models, ensemble_seg_size, ensemble_overlap,
575
+ output_format, ensemble_use_tta, model_file_dir, output_dir,
576
+ norm_threshold, amp_threshold, batch_size, ensemble_method,
577
+ ensemble_exclude_stems, ensemble_weights
578
+ ],
579
+ outputs=[ensemble_output, ensemble_status]
580
+ )
581
+
582
+ return app
583
+
584
+ if __name__ == "__main__":
585
+ parser = argparse.ArgumentParser(description="Music Source Separation Web UI")
586
+ parser.add_argument("--port", type=int, default=7860, help="Port to run the UI on")
587
+ args = parser.parse_args()
588
+
589
+ app = create_interface()
590
+ try:
591
+ # Use share=True for remote access or server_name="127.0.0.1" for local testing
592
+ app.launch(server_name="0.0.0.0", server_port=args.port, share=True)
593
+ except Exception as e:
594
+ logger.error(f"Failed to launch app: {e}")
595
+ raise
596
+ finally:
597
+ app.close()