-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathlauncher.py
More file actions
231 lines (205 loc) · 8.32 KB
/
launcher.py
File metadata and controls
231 lines (205 loc) · 8.32 KB
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
#!/usr/bin/env python3
"""
Launcher script for RVC-MacOS standalone application.
This script serves as the main entry point for the .app bundle.
RVC requires several model files to function. This launcher will:
1. Set up the environment (following run.sh pattern)
2. Check if required models are present
3. Download models if missing (on first run)
4. Start the web interface (by importing and running web.py)
Required models:
- assets/hubert/hubert_base.pt (~189MB)
- assets/rmvpe/rmvpe.pt (~55MB)
- assets/rmvpe/rmvpe.onnx (~55MB)
- assets/pretrained/*.pth (12 files, ~50MB each)
- assets/pretrained_v2/*.pth (12 files, ~50MB each)
"""
import sys
import os
import logging
# Configure logging early
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
def setup_environment():
"""
Set up the environment for the bundled app.
Mimics the behavior of run.sh for consistency.
"""
if getattr(sys, 'frozen', False):
# Running in a bundle - get the bundle directory
if hasattr(sys, '_MEIPASS'):
bundle_dir = sys._MEIPASS
else:
# py2app sets executable path
bundle_dir = os.path.dirname(sys.executable)
# Change to the Resources directory which contains our app files
# In a .app bundle: Contents/MacOS/launcher -> Contents/Resources/
resources_dir = os.path.join(bundle_dir, '..', 'Resources')
if os.path.exists(resources_dir):
resources_dir = os.path.abspath(resources_dir)
os.chdir(resources_dir)
logger.info(f"Working directory: {os.getcwd()}")
else:
os.chdir(bundle_dir)
logger.info(f"Working directory: {os.getcwd()}")
# Add current directory to Python path (like run.sh does)
now_dir = os.getcwd()
sys.path.insert(0, now_dir)
# Set environment variables for macOS (from web.py initialization)
if sys.platform == "darwin":
os.environ["PYTORCH_ENABLE_MPS_FALLBACK"] = "1"
os.environ["OMP_NUM_THREADS"] = "1"
logger.info("Environment configured for RVC-MacOS")
def check_and_download_models():
"""
Check if required models exist and download if missing.
Follows the pattern from run.sh --download-models option.
"""
from dotenv import load_dotenv
import shutil
# Load environment variables for model verification (like web.py does)
load_dotenv()
load_dotenv("sha256.env")
# Import model checking functions
try:
from infer.lib.rvcmd import check_all_assets, download_all_assets
except ImportError as e:
logger.error(f"Failed to import model management functions: {e}")
logger.error("The application may not function correctly.")
return False
logger.info("Checking for required model files...")
# Check if models are present
if check_all_assets(update=False):
logger.info("✓ All required models are present!")
return True
# Models are missing - inform user about download (like run.sh does)
logger.info("")
logger.info("="*60)
logger.info("FIRST-TIME SETUP: Downloading Required AI Models")
logger.info("="*60)
logger.info("")
logger.info("RVC requires AI model files to function.")
logger.info("These files will now be downloaded (~1.5GB).")
logger.info("")
logger.info("What will be downloaded:")
logger.info(" • HuBERT base model (~189MB)")
logger.info(" • RMVPE pitch detection models (~110MB)")
logger.info(" • Pretrained RVC models v1 (~600MB)")
logger.info(" • Pretrained RVC models v2 (~600MB)")
logger.info("")
logger.info("Estimated time: 5-10 minutes")
logger.info("This only happens once - models are saved for future use.")
logger.info("")
logger.info("Please keep this window open and be patient...")
logger.info("="*60)
logger.info("")
# Create temp directory for downloads (like run.sh pattern)
now_dir = os.getcwd()
tmp = os.path.join(now_dir, "TEMP")
shutil.rmtree(tmp, ignore_errors=True)
os.makedirs(tmp, exist_ok=True)
try:
# Download all required assets
logger.info("Starting download process...")
download_all_assets(tmpdir=tmp)
# Verify download was successful (like run.sh checks exit codes)
logger.info("")
logger.info("Verifying downloaded models...")
if check_all_assets(update=True):
logger.info("")
logger.info("="*60)
logger.info("✓ SUCCESS! All models downloaded and verified!")
logger.info("="*60)
logger.info("")
return True
else:
logger.warning("")
logger.warning("="*60)
logger.warning("⚠ Some models may not have downloaded correctly.")
logger.warning("The application will start but may have limited functionality.")
logger.warning("You can try restarting the app to re-download missing models.")
logger.warning("="*60)
logger.warning("")
return False
except Exception as e:
logger.error("")
logger.error("="*60)
logger.error(f"✗ Error downloading models: {e}")
logger.error("="*60)
logger.error("")
logger.error("Possible causes:")
logger.error(" • No internet connection")
logger.error(" • Firewall blocking downloads")
logger.error(" • Insufficient disk space (need ~3GB free)")
logger.error(" • Network timeout")
logger.error("")
logger.error("You can:")
logger.error(" 1. Check your internet connection and try again")
logger.error(" 2. See documentation for manual model download")
logger.error("")
return False
finally:
# Cleanup temp directory
shutil.rmtree(tmp, ignore_errors=True)
def main():
"""
Main entry point for RVC-MacOS application.
Follows the initialization pattern from run.sh and web.py.
"""
logger.info("="*60)
logger.info("RVC-MacOS - Voice Conversion for Apple Silicon")
logger.info("="*60)
# Set up environment (like run.sh does with venv and paths)
setup_environment()
# Check and download models if needed (like run.sh --download-models)
logger.info("")
models_ready = check_and_download_models()
if not models_ready:
logger.warning("")
logger.warning("WARNING: Not all models are available!")
logger.warning("The application will start but may not function correctly.")
logger.warning("Please restart the app to retry downloading models.")
logger.warning("")
input("Press Enter to continue anyway, or close this window to exit...")
# Start the web interface (like run.sh: python web.py --pycmd python)
logger.info("")
logger.info("="*60)
logger.info("Starting RVC Web Interface...")
logger.info("="*60)
logger.info("")
logger.info("The application will open in your default browser.")
logger.info("URL: http://localhost:7860")
logger.info("")
logger.info("IMPORTANT: Keep this window open while using the app!")
logger.info("To stop the application, close this window or press Ctrl+C")
logger.info("="*60)
logger.info("")
try:
# Import and run web.py (this will execute all its initialization)
# This is equivalent to: python web.py --pycmd python
import web
# web.py sets up gradio and launches the app at the module level
# The gradio app.launch() is at the end of web.py and will run when imported
except KeyboardInterrupt:
logger.info("")
logger.info("="*60)
logger.info("Shutting down RVC-MacOS...")
logger.info("="*60)
sys.exit(0)
except Exception as e:
logger.error("")
logger.error("="*60)
logger.error(f"Error starting application: {e}")
logger.error("="*60)
logger.error("")
logger.error("Please check the logs above for more information.")
logger.error("If the problem persists, see:")
logger.error("https://github.com/audiohacking/RVC-MacOS/issues")
logger.error("")
input("Press Enter to exit...")
sys.exit(1)
if __name__ == '__main__':
main()