Files changed (1) hide show
  1. webUI(LocalPatchByGermanized).py +346 -0
webUI(LocalPatchByGermanized).py ADDED
@@ -0,0 +1,346 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import json
3
+ import shutil
4
+ import librosa
5
+ import soundfile
6
+ import numpy as np
7
+ import gradio as gr
8
+ from UVR_interface import root, UVRInterface, VR_MODELS_DIR, MDX_MODELS_DIR, DEMUCS_MODELS_DIR
9
+ from gui_data.constants import *
10
+ from typing import List, Dict, Callable, Union
11
+ import wget
12
+
13
+ class UVRWebUI:
14
+
15
+ def __init__(self, uvr: UVRInterface, online_data_path: str) -> None:
16
+ self.uvr = uvr
17
+ self.models_url = self.get_models_url(online_data_path)
18
+ self.define_layout()
19
+ self.input_temp_dir = '__temp'
20
+ self.export_path = 'out'
21
+ if not os.path.exists(self.input_temp_dir):
22
+ os.makedirs(self.input_temp_dir, exist_ok=True)
23
+ if not os.path.exists(self.export_path):
24
+ os.makedirs(self.export_path, exist_ok=True)
25
+
26
+ def get_models_url(self, models_info_path: str) -> Dict[str, Dict]:
27
+ with open(models_info_path, 'r') as f:
28
+ online_data = json.loads(f.read())
29
+ models_url = {}
30
+ for arch, download_list_key in zip([VR_ARCH_TYPE, MDX_ARCH_TYPE], ['vr_download_list', 'mdx_download_list']):
31
+ models_url[arch] = {model_name: NORMAL_REPO + model_filename_part for model_name, model_filename_part in online_data[download_list_key].items()}
32
+ models_url[DEMUCS_ARCH_TYPE] = online_data['demucs_download_list']
33
+ return models_url
34
+
35
+ def get_local_models(self, arch: str) -> List[str]:
36
+ model_config = {VR_ARCH_TYPE: (VR_MODELS_DIR, '.pth'), MDX_ARCH_TYPE: (MDX_MODELS_DIR, '.onnx'), DEMUCS_ARCH_TYPE: (DEMUCS_MODELS_DIR, '.yaml')}
37
+ try:
38
+ model_dir, suffix = model_config[arch]
39
+ if not os.path.exists(model_dir):
40
+ os.makedirs(model_dir, exist_ok=True)
41
+ return []
42
+ except KeyError:
43
+ print(f'Error: Unknown arch type: {arch} in get_local_models')
44
+ return []
45
+ if not os.path.exists(model_dir):
46
+ print(f'Warning: Model directory {model_dir} still does not exist for arch {arch}.')
47
+ return []
48
+ return sorted([os.path.splitext(f)[0] for f in os.listdir(model_dir) if f.endswith(suffix) and os.path.isfile(os.path.join(model_dir, f))])
49
+
50
+ def set_arch_setting_value(self, arch: str, setting1, setting2):
51
+ if arch == VR_ARCH_TYPE:
52
+ root.window_size_var.set(setting1)
53
+ root.aggression_setting_var.set(setting2)
54
+ elif arch == MDX_ARCH_TYPE:
55
+ root.mdx_batch_size_var.set(setting1)
56
+ root.compensate_var.set(setting2)
57
+ elif arch == DEMUCS_ARCH_TYPE:
58
+ pass
59
+
60
+ def arch_select_update(self, arch: str) -> List[Dict]:
61
+ choices = self.get_local_models(arch)
62
+ if not choices:
63
+ print(f'Warning: No local models found for {arch}. Dropdown will be empty.')
64
+ model_update_label = CHOOSE_MODEL
65
+ if arch == VR_ARCH_TYPE:
66
+ model_update_label = SELECT_VR_MODEL_MAIN_LABEL
67
+ setting1_update = self.arch_setting1.update(choices=VR_WINDOW, label=WINDOW_SIZE_MAIN_LABEL, value=root.window_size_var.get())
68
+ setting2_update = self.arch_setting2.update(choices=VR_AGGRESSION, label=AGGRESSION_SETTING_MAIN_LABEL, value=root.aggression_setting_var.get())
69
+ elif arch == MDX_ARCH_TYPE:
70
+ model_update_label = CHOOSE_MDX_MODEL_MAIN_LABEL
71
+ setting1_update = self.arch_setting1.update(choices=BATCH_SIZE, label=BATCHES_MDX_MAIN_LABEL, value=root.mdx_batch_size_var.get())
72
+ setting2_update = self.arch_setting2.update(choices=VOL_COMPENSATION, label=VOL_COMP_MDX_MAIN_LABEL, value=root.compensate_var.get())
73
+ elif arch == DEMUCS_ARCH_TYPE:
74
+ model_update_label = CHOOSE_DEMUCS_MODEL_MAIN_LABEL
75
+ setting1_update = self.arch_setting1.update(choices=[], label='Demucs Setting 1', value=None, visible=False)
76
+ setting2_update = self.arch_setting2.update(choices=[], label='Demucs Setting 2', value=None, visible=False)
77
+ else:
78
+ gr.Error(f'Unknown arch type: {arch}')
79
+ model_update = self.model_choice.update(choices=[], value=CHOOSE_MODEL, label='Error: Unknown Arch')
80
+ setting1_update = self.arch_setting1.update(choices=[], value=None, label='Setting 1')
81
+ setting2_update = self.arch_setting2.update(choices=[], value=None, label='Setting 2')
82
+ return [model_update, setting1_update, setting2_update]
83
+ model_update = self.model_choice.update(choices=choices, value=CHOOSE_MODEL, label=model_update_label)
84
+ return [model_update, setting1_update, setting2_update]
85
+
86
+ def model_select_update(self, arch: str, model_name: str) -> List[Union[str, Dict, None]]:
87
+ if model_name == CHOOSE_MODEL or model_name is None:
88
+ return [self.primary_stem_only.update(label=f'{PRIMARY_STEM} only'), self.secondary_stem_only.update(label=f'{SECONDARY_STEM} only'), self.primary_stem_out.update(label=f'Output {PRIMARY_STEM}'), self.secondary_stem_out.update(label=f'Output {SECONDARY_STEM}')]
89
+ model_data_list = self.uvr.assemble_model_data(model_name, arch)
90
+ if not model_data_list:
91
+ gr.Error(f'Cannot get model data for model {model_name}, arch {arch}. Model list empty.')
92
+ return [None for _ in range(4)]
93
+ model = model_data_list[0]
94
+ if not model.model_status:
95
+ gr.Error(f'Cannot get model data, model hash = {model.model_hash}')
96
+ return [None for _ in range(4)]
97
+ stem1_check_update = self.primary_stem_only.update(label=f'{model.primary_stem} Only')
98
+ stem2_check_update = self.secondary_stem_only.update(label=f'{model.secondary_stem} Only')
99
+ stem1_out_update = self.primary_stem_out.update(label=f'Output {model.primary_stem}')
100
+ stem2_out_update = self.secondary_stem_out.update(label=f'Output {model.secondary_stem}')
101
+ return [stem1_check_update, stem2_check_update, stem1_out_update, stem2_out_update]
102
+
103
+ def checkbox_set_root_value(self, checkbox: gr.Checkbox, root_attr: str):
104
+ checkbox.change(lambda value: root.__getattribute__(root_attr).set(value), inputs=checkbox)
105
+
106
+ def set_checkboxes_exclusive(self, checkboxes: List[gr.Checkbox], pure_callbacks: List[Callable], exclusive_value=True):
107
+
108
+ def exclusive_onchange(i, callback_i):
109
+
110
+ def new_onchange(*check_values):
111
+ current_values = [cb.value for cb in checkboxes]
112
+ if current_values[i] == exclusive_value:
113
+ return_values = []
114
+ for j, value_j in enumerate(current_values):
115
+ if j != i and value_j == exclusive_value:
116
+ return_values.append(not exclusive_value)
117
+ else:
118
+ return_values.append(current_values[j])
119
+ return_values[i] = exclusive_value
120
+ else:
121
+ return_values = current_values
122
+ for cb_idx, final_val in enumerate(return_values):
123
+ pure_callbacks[cb_idx](final_val)
124
+ return tuple(return_values)
125
+ return new_onchange
126
+ for i, (checkbox, callback) in enumerate(zip(checkboxes, pure_callbacks)):
127
+
128
+ def create_exclusive_handler(changed_idx, all_checkboxes, all_callbacks):
129
+
130
+ def handler(is_checked):
131
+ outputs = []
132
+ all_callbacks[changed_idx](is_checked)
133
+ for k_idx, cb_k in enumerate(all_checkboxes):
134
+ if k_idx == changed_idx:
135
+ outputs.append(is_checked)
136
+ elif is_checked:
137
+ all_callbacks[k_idx](False)
138
+ outputs.append(False)
139
+ else:
140
+ outputs.append(gr.update())
141
+ return tuple(outputs)
142
+ return handler
143
+ checkbox.change(create_exclusive_handler(i, checkboxes, pure_callbacks), inputs=checkbox, outputs=checkboxes)
144
+
145
+ def process(self, input_audio, input_filename, model_name, arch, setting1, setting2, progress=gr.Progress(track_tqdm=True)):
146
+ if input_audio is None:
147
+ return (None, None, 'Error: No input audio provided.')
148
+ if model_name == CHOOSE_MODEL or model_name is None:
149
+ return (None, None, 'Error: Please select a model.')
150
+
151
+ def set_progress_func(step, inference_iterations=0):
152
+ pass
153
+ sampling_rate, audio_data = input_audio
154
+ if np.issubdtype(audio_data.dtype, np.integer):
155
+ audio_data = (audio_data / np.iinfo(audio_data.dtype).max).astype(np.float32)
156
+ elif not np.issubdtype(audio_data.dtype, np.floating):
157
+ return (None, None, f'Error: Unsupported audio data type {audio_data.dtype}')
158
+ if len(audio_data.shape) > 1 and audio_data.shape[0] > 5:
159
+ audio_data = audio_data.T
160
+ if len(audio_data.shape) > 1:
161
+ audio_data = librosa.to_mono(audio_data)
162
+ if not input_filename:
163
+ input_filename = 'audio_input.wav'
164
+ elif not input_filename.lower().endswith(('.wav', '.mp3', '.flac')):
165
+ input_filename += '.wav'
166
+ input_path = os.path.join(self.input_temp_dir, os.path.basename(input_filename))
167
+ try:
168
+ soundfile.write(input_path, audio_data, sampling_rate, format='wav')
169
+ except Exception as e:
170
+ return (None, None, f'Error writing temporary input file: {e}')
171
+ self.set_arch_setting_value(arch, setting1, setting2)
172
+ separator = self.uvr.process(model_name=model_name, arch_type=arch, audio_file=input_path, export_path=self.export_path, is_model_sample_mode=root.model_sample_mode_var.get(), set_progress_func=set_progress_func)
173
+ if separator is None:
174
+ if os.path.exists(input_path):
175
+ os.remove(input_path)
176
+ return (None, None, 'Error during processing. Separator object is None.')
177
+ primary_audio_out = None
178
+ secondary_audio_out = None
179
+ msg = ''
180
+ if separator.export_path and separator.audio_file_base and separator.primary_stem:
181
+ if not separator.is_secondary_stem_only:
182
+ primary_stem_path = os.path.join(separator.export_path, f'{separator.audio_file_base}_({separator.primary_stem}).wav')
183
+ if os.path.exists(primary_stem_path):
184
+ audio_p, rate_p = soundfile.read(primary_stem_path)
185
+ primary_audio_out = (rate_p, audio_p)
186
+ msg += f'{separator.primary_stem} saved at {primary_stem_path}\n'
187
+ else:
188
+ msg += f'Error: Primary stem file not found at {primary_stem_path}\n'
189
+ else:
190
+ msg += 'Error: Missing data in separator object for primary stem.\n'
191
+ if separator.export_path and separator.audio_file_base and separator.secondary_stem:
192
+ if not separator.is_primary_stem_only:
193
+ secondary_stem_path = os.path.join(separator.export_path, f'{separator.audio_file_base}_({separator.secondary_stem}).wav')
194
+ if os.path.exists(secondary_stem_path):
195
+ audio_s, rate_s = soundfile.read(secondary_stem_path)
196
+ secondary_audio_out = (rate_s, audio_s)
197
+ msg += f'{separator.secondary_stem} saved at {secondary_stem_path}\n'
198
+ else:
199
+ msg += f'Error: Secondary stem file not found at {secondary_stem_path}\n'
200
+ else:
201
+ msg += 'Error: Missing data in separator object for secondary stem.\n'
202
+ if os.path.exists(input_path):
203
+ os.remove(input_path)
204
+ return (primary_audio_out, secondary_audio_out, msg.strip())
205
+
206
+ def define_layout(self):
207
+ with gr.Blocks() as app:
208
+ self.app = app
209
+ gr.HTML('<h1> 🎵 Ultimate Vocal Remover WebUI Local Patch By Germanized🎵 </h1>')
210
+ gr.Markdown('This is an experimental demo with CPU. Duplicate the space for use in private')
211
+ gr.Markdown('[![Duplicate this Space](https://huggingface.co/datasets/huggingface/badges/raw/main/duplicate-this-space-sm-dark.svg)](https://huggingface.co/spaces/r3gm/Ultimate-Vocal-Remover-WebUI?duplicate=true)\n\n')
212
+ with gr.Tabs():
213
+ with gr.TabItem('Process'):
214
+ with gr.Row():
215
+ self.arch_choice = gr.Dropdown(choices=[VR_ARCH_TYPE, MDX_ARCH_TYPE], value=VR_ARCH_TYPE, label=CHOOSE_PROC_METHOD_MAIN_LABEL, interactive=True)
216
+ self.model_choice = gr.Dropdown(choices=self.get_local_models(VR_ARCH_TYPE), value=CHOOSE_MODEL, label=SELECT_VR_MODEL_MAIN_LABEL + ' 👋Select a model', interactive=True)
217
+ with gr.Row():
218
+ self.arch_setting1 = gr.Dropdown(choices=VR_WINDOW, value=root.window_size_var.get(), label=WINDOW_SIZE_MAIN_LABEL + ' 👋Select one', interactive=True)
219
+ self.arch_setting2 = gr.Dropdown(choices=VR_AGGRESSION, value=root.aggression_setting_var.get(), label=AGGRESSION_SETTING_MAIN_LABEL, interactive=True)
220
+ with gr.Row():
221
+ self.use_gpu = gr.Checkbox(label='Rhythmic Transmutation Device', value=True, interactive=True)
222
+ self.primary_stem_only = gr.Checkbox(label=f'{PRIMARY_STEM} only', value=root.is_primary_stem_only_var.get(), interactive=True)
223
+ self.secondary_stem_only = gr.Checkbox(label=f'{SECONDARY_STEM} only', value=root.is_secondary_stem_only_var.get(), interactive=True)
224
+ self.sample_mode = gr.Checkbox(label=SAMPLE_MODE_CHECKBOX(root.model_sample_mode_duration_var.get()), value=root.model_sample_mode_var.get(), interactive=True)
225
+ with gr.Row():
226
+ self.input_filename = gr.Textbox(label='Input filename (e.g., song.wav)', value='temp.wav', interactive=True)
227
+ with gr.Row():
228
+ self.audio_in = gr.Audio(label='Input audio', type='numpy', interactive=True)
229
+ with gr.Row():
230
+ self.process_submit = gr.Button(START_PROCESSING, variant='primary')
231
+ with gr.Row():
232
+ self.primary_stem_out = gr.Audio(label=f'Output {PRIMARY_STEM}', interactive=False)
233
+ self.secondary_stem_out = gr.Audio(label=f'Output {SECONDARY_STEM}', interactive=False)
234
+ with gr.Row():
235
+ self.out_message = gr.Textbox(label='Output Message', interactive=False)
236
+ with gr.TabItem('Settings'):
237
+ with gr.Tabs():
238
+ with gr.TabItem('Settings Guide (Placeholder)'):
239
+ gr.Markdown('Details about settings would go here.')
240
+ with gr.TabItem('Additional Settings'):
241
+ self.wav_type = gr.Dropdown(choices=WAV_TYPE, label='Wav Type Output', value='PCM_16', interactive=True)
242
+ self.mp3_rate = gr.Dropdown(choices=MP3_BIT_RATES, label='MP3 Bitrate Output', value='320k', interactive=True)
243
+ with gr.TabItem('Download Models'):
244
+ gr.Markdown('Select a model category and model name to see its download URL. Models are downloaded automatically on startup if missing.')
245
+
246
+ def md_url(url, text=None):
247
+ if text is None:
248
+ text = url
249
+ return f'[{text}]({url})'
250
+ with gr.Row():
251
+ vr_models_for_dl = self.models_url.get(VR_ARCH_TYPE, {})
252
+ self.vr_download_choice = gr.Dropdown(choices=list(vr_models_for_dl.keys()), label=f'Select {VR_ARCH_TYPE} Model', interactive=True)
253
+ self.vr_download_url = gr.Markdown()
254
+ self.vr_download_choice.change(lambda model: md_url(vr_models_for_dl.get(model, 'URL not found')) if model else '', inputs=self.vr_download_choice, outputs=self.vr_download_url)
255
+ with gr.Row():
256
+ mdx_models_for_dl = self.models_url.get(MDX_ARCH_TYPE, {})
257
+ self.mdx_download_choice = gr.Dropdown(choices=list(mdx_models_for_dl.keys()), label=f'Select {MDX_ARCH_TYPE} Model', interactive=True)
258
+ self.mdx_download_url = gr.Markdown()
259
+ self.mdx_download_choice.change(lambda model: md_url(mdx_models_for_dl.get(model, 'URL not found')) if model else '', inputs=self.mdx_download_choice, outputs=self.mdx_download_url)
260
+ with gr.Row():
261
+ demucs_models_for_dl: Dict[str, Dict] = self.models_url.get(DEMUCS_ARCH_TYPE, {})
262
+ self.demucs_download_choice = gr.Dropdown(choices=list(demucs_models_for_dl.keys()), label=f'Select {DEMUCS_ARCH_TYPE} Model', interactive=True)
263
+ self.demucs_download_url = gr.Markdown()
264
+ self.demucs_download_choice.change(lambda model: '\n'.join(['- ' + md_url(url, text=filename) for filename, url in demucs_models_for_dl.get(model, {}).items()]) if model else '', inputs=self.demucs_download_choice, outputs=self.demucs_download_url)
265
+ self.arch_choice.change(self.arch_select_update, inputs=self.arch_choice, outputs=[self.model_choice, self.arch_setting1, self.arch_setting2])
266
+ self.model_choice.change(self.model_select_update, inputs=[self.arch_choice, self.model_choice], outputs=[self.primary_stem_only, self.secondary_stem_only, self.primary_stem_out, self.secondary_stem_out])
267
+ self.checkbox_set_root_value(self.use_gpu, 'is_gpu_conversion_var')
268
+ self.checkbox_set_root_value(self.sample_mode, 'model_sample_mode_var')
269
+
270
+ def make_exclusive_primary(is_checked_primary):
271
+ root.is_primary_stem_only_var.set(is_checked_primary)
272
+ if is_checked_primary:
273
+ root.is_secondary_stem_only_var.set(False)
274
+ return (gr.update(value=is_checked_primary), gr.update(value=False))
275
+ return (gr.update(value=is_checked_primary), gr.update())
276
+
277
+ def make_exclusive_secondary(is_checked_secondary):
278
+ root.is_secondary_stem_only_var.set(is_checked_secondary)
279
+ if is_checked_secondary:
280
+ root.is_primary_stem_only_var.set(False)
281
+ return (gr.update(value=False), gr.update(value=is_checked_secondary))
282
+ return (gr.update(), gr.update(value=is_checked_secondary))
283
+ self.primary_stem_only.change(make_exclusive_primary, inputs=self.primary_stem_only, outputs=[self.primary_stem_only, self.secondary_stem_only])
284
+ self.secondary_stem_only.change(make_exclusive_secondary, inputs=self.secondary_stem_only, outputs=[self.primary_stem_only, self.secondary_stem_only])
285
+ self.process_submit.click(self.process, inputs=[self.audio_in, self.input_filename, self.model_choice, self.arch_choice, self.arch_setting1, self.arch_setting2], outputs=[self.primary_stem_out, self.secondary_stem_out, self.out_message])
286
+
287
+ def launch(self, **kwargs):
288
+ self.app.queue().launch(**kwargs)
289
+ uvr_interface_instance = UVRInterface()
290
+ uvr_interface_instance.cached_sources_clear()
291
+ webui_instance = UVRWebUI(uvr_interface_instance, online_data_path='models/download_checks.json')
292
+ print('INFO: Checking and downloading models if necessary...')
293
+ model_dict_to_download = webui_instance.models_url
294
+ for category, models_in_category in model_dict_to_download.items():
295
+ target_model_dir = None
296
+ expected_suffix = None
297
+ if category == VR_ARCH_TYPE:
298
+ target_model_dir = VR_MODELS_DIR
299
+ expected_suffix = '.pth'
300
+ elif category == MDX_ARCH_TYPE:
301
+ target_model_dir = MDX_MODELS_DIR
302
+ expected_suffix = '.onnx'
303
+ elif category == DEMUCS_ARCH_TYPE:
304
+ print(f'INFO: Skipping direct download for {category} in this loop. Demucs models are handled by their own mechanism or need specific download paths.')
305
+ continue
306
+ else:
307
+ print(f'INFO: Unknown category for download: {category}')
308
+ continue
309
+ if not target_model_dir:
310
+ continue
311
+ if not os.path.exists(target_model_dir):
312
+ os.makedirs(target_model_dir, exist_ok=True)
313
+ print(f'INFO: Created directory: {target_model_dir}')
314
+ print(f'\nINFO: Checking/Downloading models for {category} into {target_model_dir}...')
315
+ if not isinstance(models_in_category, dict):
316
+ print(f'Warning: Expected a dictionary of models for {category}, but got {type(models_in_category)}. Skipping.')
317
+ continue
318
+ for model_base_name, model_full_url in models_in_category.items():
319
+ filename_from_url = model_full_url.split('/')[-1]
320
+ if not filename_from_url.endswith(expected_suffix):
321
+ correct_local_filename = model_base_name + expected_suffix
322
+ local_file_path = os.path.join(target_model_dir, correct_local_filename)
323
+ else:
324
+ local_file_path = os.path.join(target_model_dir, filename_from_url)
325
+ if not os.path.exists(local_file_path):
326
+ print(f'INFO: Downloading {model_full_url} to {target_model_dir} (expected as {os.path.basename(local_file_path)})...')
327
+ try:
328
+ downloaded_filepath_actual = wget.download(model_full_url, out=target_model_dir)
329
+ if os.path.basename(downloaded_filepath_actual) != os.path.basename(local_file_path):
330
+ print(f'INFO: Downloaded as {os.path.basename(downloaded_filepath_actual)}, renaming to {os.path.basename(local_file_path)}')
331
+ if os.path.exists(local_file_path):
332
+ os.remove(local_file_path)
333
+ shutil.move(downloaded_filepath_actual, local_file_path)
334
+ print(f'INFO: Download successful: {local_file_path}')
335
+ except Exception as e:
336
+ print(f'ERROR: wget download failed for {model_full_url}: {e}')
337
+ else:
338
+ print(f'INFO: Skipping {local_file_path}, already exists.')
339
+ print(f'INFO: Finished checking/downloading for {category}.')
340
+ print('INFO: Model download check complete.')
341
+ initial_model_choices = webui_instance.get_local_models(VR_ARCH_TYPE)
342
+ webui_instance.model_choice.choices = initial_model_choices
343
+ print('INFO: Re-initializing WebUI to pick up downloaded models for dropdowns...')
344
+ webui_instance = UVRWebUI(uvr_interface_instance, online_data_path='models/download_checks.json')
345
+ print('INFO: Launching WebUI...')
346
+ webui_instance.launch()