File size: 13,751 Bytes
d9a3001
1151eb8
85a69bf
 
1151eb8
 
85a69bf
49c5e12
1151eb8
85a69bf
1151eb8
85a69bf
1151eb8
 
85a69bf
d9a3001
85a69bf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0c89be1
d9a3001
 
49c5e12
0c89be1
 
 
 
49c5e12
0c89be1
d9a3001
85a69bf
 
 
49c5e12
85a69bf
 
 
49c5e12
 
 
85a69bf
 
49c5e12
 
 
85a69bf
0c89be1
d9a3001
0c89be1
 
d9a3001
0c89be1
 
 
 
 
 
85a69bf
 
 
 
49c5e12
85a69bf
 
49c5e12
1151eb8
49c5e12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85a69bf
 
 
 
 
 
 
 
 
 
49c5e12
 
85a69bf
 
d9a3001
cdd7385
 
 
49c5e12
 
 
85a69bf
 
49c5e12
 
0a40814
cdd7385
49c5e12
 
0a40814
9615f93
76c7846
85a69bf
49c5e12
 
 
 
 
 
 
 
 
 
 
 
cdd7385
9615f93
85a69bf
 
1151eb8
d9a3001
9615f93
 
 
 
 
0a40814
cdd7385
 
 
 
76c7846
d9a3001
49c5e12
85a69bf
49c5e12
 
 
 
 
 
 
1151eb8
85a69bf
cdd7385
1151eb8
49c5e12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9615f93
49c5e12
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1151eb8
 
 
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
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
import gradio as gr
import os
import sys
import subprocess
import shutil
from pathlib import Path
import zipfile
import json

class RealRVCTrainer:
    def __init__(self):
        self.rvc_dir = Path("./Retrieval-based-Voice-Conversion-WebUI")
        self.workspace = Path("./workspace")
        self.workspace.mkdir(exist_ok=True)
        self.setup_complete = False
    
    def install_rvc(self, progress=gr.Progress()):
        """Clone and setup official RVC repository"""
        try:
            progress(0.1, desc="Cloning RVC repository...")
            
            if self.rvc_dir.exists():
                return "βœ… RVC already installed!"
            
            subprocess.run([
                "git", "clone", 
                "https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI.git"
            ], check=True)
            
            progress(0.3, desc="Installing dependencies...")
            
            core_packages = [
                "torch", "torchaudio", "torchvision", "numpy", "scipy",
                "librosa", "soundfile", "faiss-cpu", "praat-parselmouth",
                "pyworld", "scikit-learn", "numba", "resampy", "pydub"
            ]
            
            for pkg in core_packages:
                try:
                    subprocess.run([sys.executable, "-m", "pip", "install", "-q", pkg], timeout=60)
                except:
                    pass
            
            progress(0.6, desc="Downloading pretrained models...")
            
            pretrained_dir = self.rvc_dir / "pretrained"
            pretrained_dir.mkdir(exist_ok=True)
            
            models_to_download = [
                ("https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/f0G40k.pth", "f0G40k.pth"),
                ("https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/pretrained/f0D40k.pth", "f0D40k.pth"),
                ("https://huggingface.co/lj1995/VoiceConversionWebUI/resolve/main/hubert_base.pt", "hubert_base.pt"),
            ]
            
            for idx, (url, filename) in enumerate(models_to_download):
                progress(0.6 + (idx / len(models_to_download)) * 0.3, desc=f"Downloading {filename}...")
                output_path = pretrained_dir / filename
                if not output_path.exists():
                    try:
                        subprocess.run(["wget", "-q", "-O", str(output_path), url], timeout=300)
                    except:
                        try:
                            subprocess.run(["curl", "-L", "-o", str(output_path), url], timeout=300)
                        except:
                            import requests
                            response = requests.get(url, stream=True, timeout=300)
                            with open(output_path, 'wb') as f:
                                for chunk in response.iter_content(chunk_size=8192):
                                    f.write(chunk)
            
            self.setup_complete = True
            progress(1.0, desc="Setup complete!")
            
            return "βœ… RVC Installation Complete!\n\nπŸ“¦ Installed:\n- Official RVC codebase\n- Pre-trained models\n- All dependencies\n\nπŸŽ‰ Ready to train!"
            
        except Exception as e:
            return f"❌ Installation failed: {str(e)}\n\nπŸ”§ Try manual installation or use Google Colab."
    
    def prepare_dataset(self, audio_files, model_name, progress=gr.Progress()):
        """Prepare dataset in RVC format"""
        if not audio_files:
            return "❌ Please upload audio files"
        
        if not model_name:
            model_name = "my_model"
        
        try:
            progress(0.1, desc="Creating dataset structure...")
            dataset_path = self.rvc_dir / "dataset" / model_name
            dataset_path.mkdir(parents=True, exist_ok=True)
            
            progress(0.3, desc="Copying audio files...")
            for idx, audio_file in enumerate(audio_files):
                dest = dataset_path / f"{idx:04d}_{Path(audio_file.name).name}"
                shutil.copy2(audio_file.name, dest)
                progress(0.3 + (idx / len(audio_files)) * 0.6, desc=f"Copied {idx+1}/{len(audio_files)} files")
            
            progress(1.0, desc="Dataset ready!")
            return f"βœ… Dataset Prepared!\n\nπŸ“ Location: {dataset_path}\nπŸ“Š Files: {len(audio_files)}\n🎀 Model: {model_name}\n\nβœ… Ready for preprocessing!"
            
        except Exception as e:
            return f"❌ Error: {str(e)}"
    
    def preprocess_data(self, model_name, sample_rate, progress=gr.Progress()):
        """Run RVC preprocessing"""
        try:
            progress(0.1, desc="Starting preprocessing...")
            dataset_path = self.rvc_dir / "dataset" / model_name
            if not dataset_path.exists():
                return "❌ Dataset not found. Please prepare dataset first."
            
            preprocess_script = self.rvc_dir / "infer" / "modules" / "train" / "preprocess.py"
            if not preprocess_script.exists():
                preprocess_script = self.rvc_dir / "trainset_preprocess_pipeline_print.py"
            
            progress(0.3, desc="Preprocessing audio...")
            cmd = [sys.executable, str(preprocess_script), str(dataset_path), str(sample_rate), "2"]
            result = subprocess.run(cmd, capture_output=True, text=True)
            
            progress(1.0, desc="Preprocessing complete!")
            return f"βœ… Preprocessing Complete!\n\n🎡 Sample Rate: {sample_rate}Hz\nπŸ” Features extracted\nπŸ“Š Ready for training!"
            
        except Exception as e:
            return f"❌ Preprocessing failed: {str(e)}"
    
    def train_model(self, model_name, epochs, batch_size, sample_rate, progress=gr.Progress()):
        """Run actual RVC training"""
        try:
            progress(0.05, desc="Initializing training...")
            log_dir = self.rvc_dir / "logs" / model_name
            log_dir.mkdir(parents=True, exist_ok=True)
            
            progress(0.1, desc="Starting RVC training...")
            train_script = self.rvc_dir / "infer" / "modules" / "train" / "train.py"
            if not train_script.exists():
                train_script = self.rvc_dir / "train_nsf_sim_cache_sid_load_pretrain.py"
            
            cmd = [
                sys.executable, str(train_script),
                "-e", model_name, "-sr", str(sample_rate),
                "-f0", "1", "-bs", str(batch_size),
                "-g", "0", "-te", str(epochs), "-se", "10",
                "-pg", str(self.rvc_dir / "pretrained" / "f0G40k.pth"),
                "-pd", str(self.rvc_dir / "pretrained" / "f0D40k.pth"),
                "-l", "0", "-c", "0"
            ]
            
            progress(0.2, desc=f"Training {model_name}...")
            process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)
            
            for line in process.stdout:
                if "epoch" in line.lower():
                    progress(0.2 + 0.6, desc=f"Training: {line.strip()[:50]}")
            
            process.wait()
            progress(0.9, desc="Searching for model files...")
            
            possible_paths = [
                log_dir / "weights", log_dir,
                self.rvc_dir / "weights" / model_name,
                self.rvc_dir / "logs" / model_name
            ]
            
            model_files = []
            index_files = []
            for path in possible_paths:
                if path.exists():
                    model_files.extend(list(path.glob("**/*.pth")))
                    index_files.extend(list(path.glob("**/*.index")))
            
            if model_files or index_files:
                output_dir = self.workspace / model_name
                output_dir.mkdir(exist_ok=True)
                
                files_info = []
                if model_files:
                    latest_model = max(model_files, key=lambda p: p.stat().st_mtime)
                    shutil.copy2(latest_model, output_dir / f"{model_name}.pth")
                    model_size = latest_model.stat().st_size / (1024*1024)
                    files_info.append(f"- {model_name}.pth ({model_size:.1f}MB)")
                
                if index_files:
                    latest_index = max(index_files, key=lambda p: p.stat().st_mtime)
                    shutil.copy2(latest_index, output_dir / latest_index.name)
                    files_info.append(f"- {latest_index.name}")
                
                progress(1.0, desc="Training complete!")
                return f"βœ… Training Complete!\n\nπŸŽ“ Model: {model_name}\nπŸ“Š Epochs: {epochs}\n\nπŸ’Ύ Model Files:\n{chr(10).join(files_info)}\n\nπŸ“‚ Location: {output_dir}\n\nπŸŽ‰ Ready to download!"
            else:
                debug_info = []
                if log_dir.exists():
                    debug_info.append(f"Log dir: {log_dir}")
                    for item in log_dir.rglob("*"):
                        debug_info.append(f"  - {item.relative_to(log_dir)}")
                
                return f"⚠️ Training completed but model files not found.\n\nπŸ” Searched in:\n{chr(10).join([f'- {p}' for p in possible_paths])}\n\nπŸ“‹ Debug:\n{chr(10).join(debug_info)}"
                
        except Exception as e:
            return f"❌ Training failed: {str(e)}"
    
    def package_model(self, model_name):
        """Package model for download"""
        try:
            output_dir = self.workspace / model_name
            if not output_dir.exists():
                output_dir = self.rvc_dir / "logs" / model_name / "weights"
            
            if not output_dir.exists():
                return None, "❌ Model not found"
            
            zip_path = self.workspace / f"{model_name}_RVC.zip"
            with zipfile.ZipFile(zip_path, 'w', zipfile.ZIP_DEFLATED) as zipf:
                for file in output_dir.rglob("*"):
                    if file.is_file() and (file.suffix in ['.pth', '.index', '.json']):
                        zipf.write(file, file.name)
            
            return str(zip_path), f"βœ… Model packaged: {zip_path.name}"
        except Exception as e:
            return None, f"❌ Error: {str(e)}"

trainer = RealRVCTrainer()

with gr.Blocks(title="Real RVC Training") as demo:
    gr.Markdown("# 🎀 Real RVC Model Training\n### Using Official RVC-Project Implementation\n\n⚠️ Uses REAL RVC training. Models work on weights.gg!")
    
    with gr.Tab("βš™οΈ Step 0: Install RVC"):
        gr.Markdown("Install official RVC codebase and pretrained models (~200MB)")
        install_btn = gr.Button("πŸ“¦ Install RVC Components", variant="primary", size="lg")
        install_output = gr.Textbox(label="Installation Status", lines=10)
        install_btn.click(fn=trainer.install_rvc, outputs=install_output)
    
    with gr.Tab("πŸ“ Step 1: Prepare Dataset"):
        gr.Markdown("Upload voice audio files (10-30 min recommended, WAV/MP3/FLAC)")
        model_name_prep = gr.Textbox(label="Model Name", value="my_voice_model")
        audio_files = gr.File(label="Upload Audio Files", file_count="multiple", file_types=["audio"])
        prep_btn = gr.Button("πŸ“ Prepare Dataset", variant="primary")
        prep_output = gr.Textbox(label="Status", lines=8)
        prep_btn.click(fn=trainer.prepare_dataset, inputs=[audio_files, model_name_prep], outputs=prep_output)
    
    with gr.Tab("πŸ”§ Step 2: Preprocess"):
        gr.Markdown("Preprocess audio and extract features")
        model_name_process = gr.Textbox(label="Model Name", value="my_voice_model")
        sample_rate_process = gr.Radio(choices=["40000", "48000"], value="40000", label="Sample Rate")
        process_btn = gr.Button("πŸ”§ Preprocess Data", variant="primary")
        process_output = gr.Textbox(label="Status", lines=8)
        process_btn.click(fn=trainer.preprocess_data, inputs=[model_name_process, sample_rate_process], outputs=process_output)
    
    with gr.Tab("πŸš€ Step 3: Train Model"):
        gr.Markdown("Train RVC model (⚠️ CPU training takes hours/days)")
        model_name_train = gr.Textbox(label="Model Name", value="my_voice_model")
        epochs_train = gr.Slider(minimum=10, maximum=500, value=100, step=10, label="Epochs")
        batch_size_train = gr.Slider(minimum=1, maximum=16, value=4, step=1, label="Batch Size")
        sample_rate_train = gr.Radio(choices=["40000", "48000"], value="40000", label="Sample Rate")
        train_btn = gr.Button("πŸŽ“ Start Real Training", variant="primary")
        train_output = gr.Textbox(label="Training Status", lines=15)
        train_btn.click(fn=trainer.train_model, inputs=[model_name_train, epochs_train, batch_size_train, sample_rate_train], outputs=train_output)
    
    with gr.Tab("πŸ“₯ Step 4: Download"):
        gr.Markdown("Download your trained RVC model")
        model_name_download = gr.Textbox(label="Model Name", value="my_voice_model")
        download_btn = gr.Button("πŸ“¦ Package Model", variant="primary")
        download_file = gr.File(label="Download")
        download_status = gr.Textbox(label="Status")
        download_btn.click(fn=trainer.package_model, inputs=model_name_download, outputs=[download_file, download_status])
    
    gr.Markdown("---\n### πŸ“š Resources\n- [RVC Project](https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI)\n- [Weights.gg](https://weights.gg/)\n\n### ⚠️ Important\n- Uses REAL RVC training\n- Models work on weights.gg\n- CPU training is VERY slow\n- Recommended: Google Colab with GPU")

if __name__ == "__main__":
    demo.launch()