-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinstall.py
More file actions
293 lines (254 loc) · 10.2 KB
/
install.py
File metadata and controls
293 lines (254 loc) · 10.2 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
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
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
# -*- coding: utf-8 -*-
"""
RVC 安装脚本
自动创建虚拟环境 → 安装依赖 → 启动应用
用法:
python install.py # 完整安装并启动
python install.py --check # 仅检查依赖
python install.py --no-run # 安装但不启动
python install.py --cpu # 安装 CPU 版本
"""
import subprocess
import sys
import os
from pathlib import Path
ROOT_DIR = Path(__file__).parent
VENV_DIR = ROOT_DIR / "venv310"
PYTHON310_CANDIDATES = [
r"C:\Users\Administrator\AppData\Local\Programs\Python\Python310\python.exe",
r"C:\Python310\python.exe",
r"C:\Program Files\Python310\python.exe",
r"C:\Program Files (x86)\Python310\python.exe",
]
PACKAGES = {
"torch": {"import": "torch", "name": "PyTorch", "pip": "torch"},
"torchaudio": {"import": "torchaudio", "name": "torchaudio", "pip": "torchaudio"},
"gradio": {"import": "gradio", "name": "Gradio", "pip": "gradio==3.50.2"},
"librosa": {"import": "librosa", "name": "librosa", "pip": "librosa"},
"soundfile": {"import": "soundfile", "name": "soundfile", "pip": "soundfile"},
"av": {"import": "av", "name": "PyAV", "pip": "av"},
"scipy": {"import": "scipy", "name": "scipy", "pip": "scipy"},
"numpy": {"import": "numpy", "name": "numpy", "pip": "numpy"},
"parselmouth": {"import": "parselmouth", "name": "praat-parselmouth", "pip": "praat-parselmouth"},
"pyworld": {"import": "pyworld", "name": "pyworld", "pip": "pyworld"},
"torchcrepe": {"import": "torchcrepe", "name": "torchcrepe", "pip": "torchcrepe"},
"faiss": {"import": "faiss", "name": "faiss-cpu", "pip": "faiss-cpu"},
"tqdm": {"import": "tqdm", "name": "tqdm", "pip": "tqdm"},
"requests": {"import": "requests", "name": "requests", "pip": "requests"},
"dotenv": {"import": "dotenv", "name": "python-dotenv", "pip": "python-dotenv"},
"colorama": {"import": "colorama", "name": "colorama", "pip": "colorama"},
"mcp": {"import": "mcp", "name": "mcp", "pip": "mcp"},
"demucs": {"import": "demucs", "name": "demucs", "pip": "demucs"},
"audio_separator": {"import": "audio_separator", "name": "audio-separator", "pip": "audio-separator"},
"huggingface_hub": {"import": "huggingface_hub", "name": "huggingface_hub", "pip": "huggingface_hub"},
"pedalboard": {"import": "pedalboard", "name": "pedalboard", "pip": "pedalboard"},
"ffmpeg": {"import": "ffmpeg", "name": "ffmpeg-python", "pip": "ffmpeg-python"},
"fairseq": {"import": "fairseq", "name": "fairseq", "pip": "fairseq==0.12.2"},
}
# === 虚拟环境 ===
def find_python310():
"""查找系统中的 Python 3.10"""
if sys.version_info[:2] == (3, 10):
return sys.executable
for p in PYTHON310_CANDIDATES:
if os.path.isfile(p):
return p
try:
r = subprocess.run(
["py", "-3.10", "-c", "import sys; print(sys.executable)"],
capture_output=True, text=True, timeout=10,
)
if r.returncode == 0:
return r.stdout.strip()
except (FileNotFoundError, subprocess.TimeoutExpired):
pass
return None
def get_venv_python():
"""获取虚拟环境的 Python 路径"""
if os.name == "nt":
return str(VENV_DIR / "Scripts" / "python.exe")
return str(VENV_DIR / "bin" / "python")
def create_venv():
"""创建 Python 3.10 虚拟环境"""
venv_py = get_venv_python()
if os.path.isfile(venv_py):
r = subprocess.run([venv_py, "--version"], capture_output=True, text=True)
if r.returncode == 0 and "3.10" in r.stdout:
print(f" [OK] 虚拟环境已存在: {VENV_DIR}")
return True
py310 = find_python310()
if not py310:
print(" [错误] 未找到 Python 3.10")
print(" 下载: https://www.python.org/downloads/release/python-31011/")
return False
print(f" 使用 Python: {py310}")
print(f" 创建虚拟环境: {VENV_DIR}")
r = subprocess.run([py310, "-m", "venv", str(VENV_DIR)], capture_output=True, text=True)
if r.returncode != 0:
print(f" [错误] 创建失败:\n{r.stderr}")
return False
print(" [OK] 虚拟环境创建成功")
print(" 升级 pip ...")
subprocess.run([venv_py, "-m", "pip", "install", "--upgrade", "pip"],
capture_output=True, text=True)
return True
# === 依赖检查与安装 ===
def check_package(venv_py, import_name):
"""用虚拟环境的 Python 检查包是否已安装"""
r = subprocess.run(
[venv_py, "-c", f"import {import_name}"],
capture_output=True, text=True,
)
return r.returncode == 0
def detect_cuda_version():
"""检测系统 CUDA 版本,返回对应的 PyTorch index-url"""
try:
r = subprocess.run(
["nvidia-smi", "--query-gpu=driver_version", "--format=csv,noheader"],
capture_output=True, text=True, timeout=10,
)
if r.returncode == 0:
# nvidia-smi 存在,尝试获取 CUDA 版本
r2 = subprocess.run(
["nvidia-smi"],
capture_output=True, text=True, timeout=10,
)
output = r2.stdout
# 从 nvidia-smi 输出中提取 CUDA Version
import re
match = re.search(r"CUDA Version:\s*(\d+)\.(\d+)", output)
if match:
major, minor = int(match.group(1)), int(match.group(2))
if major >= 12 and minor >= 6:
return "https://download.pytorch.org/whl/cu126"
elif major >= 12 and minor >= 4:
return "https://download.pytorch.org/whl/cu124"
elif major >= 12 and minor >= 1:
return "https://download.pytorch.org/whl/cu121"
elif major >= 11 and minor >= 8:
return "https://download.pytorch.org/whl/cu118"
else:
# CUDA 版本太旧,回退 CPU
return None
except (FileNotFoundError, subprocess.TimeoutExpired):
pass
return None
def pip_install(venv_py, package, extra="", index_url=None, no_deps=False):
"""用虚拟环境的 pip 安装包"""
target = f"{package}[{extra}]" if extra else package
print(f" 安装 {target} ...")
cmd = [venv_py, "-m", "pip", "install", target]
if index_url:
cmd.extend(["--index-url", index_url])
if no_deps:
cmd.append("--no-deps")
r = subprocess.run(cmd, capture_output=True, text=True)
if r.returncode != 0:
# fairseq 依赖冲突时尝试 --no-deps 回退
if not no_deps and "ResolutionImpossible" in r.stderr:
print(f" [依赖冲突] 尝试 --no-deps 安装 {target} ...")
return pip_install(venv_py, package, extra=extra, index_url=index_url, no_deps=True)
print(f" [失败] {target}")
lines = r.stderr.strip().splitlines()
if lines:
print(f" {lines[-1]}")
return False
print(f" [完成] {target}")
return True
def check_all(venv_py):
"""检查所有依赖"""
print("=" * 50)
print("RVC 依赖检查")
print("=" * 50)
missing = []
for key, info in PACKAGES.items():
ok = check_package(venv_py, info["import"])
status = "OK" if ok else "未安装"
mark = "[v]" if ok else "[x]"
print(f" {mark} {info['name']:30s} {status}")
if not ok:
missing.append(info)
print("-" * 50)
if missing:
print(f"缺少 {len(missing)} 个依赖包")
else:
print("所有依赖已安装")
return missing
def install_all(venv_py, gpu=True):
"""安装所有缺失的依赖"""
missing = check_all(venv_py)
if not missing:
print("\n无需安装,所有依赖已就绪。")
return True
# 检测 CUDA 版本
cuda_index_url = None
if gpu:
cuda_index_url = detect_cuda_version()
if cuda_index_url:
print(f"\n 检测到 CUDA,使用 PyTorch 源: {cuda_index_url}")
else:
print("\n 未检测到 CUDA,将安装 CPU 版 PyTorch")
print(f"\n开始安装 {len(missing)} 个缺失的依赖...\n")
failed = []
for info in missing:
pip_name = info["pip"]
if pip_name in ("torch", "torchaudio"):
if gpu and cuda_index_url:
ok = pip_install(venv_py, pip_name, index_url=cuda_index_url)
else:
ok = pip_install(venv_py, pip_name, index_url="https://download.pytorch.org/whl/cpu")
elif pip_name == "audio-separator":
ok = pip_install(venv_py, pip_name, extra="gpu" if gpu else "cpu")
else:
ok = pip_install(venv_py, pip_name)
if not ok:
failed.append(info["name"])
print("\n" + "=" * 50)
if failed:
print(f"安装完成,{len(failed)} 个包失败: {', '.join(failed)}")
return False
print("所有依赖安装成功!")
return True
def launch_app(venv_py):
"""用虚拟环境启动应用"""
run_script = str(ROOT_DIR / "run.py")
print(f"\n启动应用: {run_script}")
print("=" * 50)
try:
subprocess.run([venv_py, run_script], cwd=str(ROOT_DIR))
except KeyboardInterrupt:
print("\n已停止")
# === 主入口 ===
def main():
import argparse
parser = argparse.ArgumentParser(description="RVC 安装脚本")
parser.add_argument("--cpu", action="store_true", help="安装 CPU 版本")
parser.add_argument("--check", action="store_true", help="仅检查依赖")
parser.add_argument("--no-run", action="store_true", help="安装后不启动")
args = parser.parse_args()
print("=" * 50)
print("RVC 安装程序")
print("=" * 50)
# 1. 创建虚拟环境
print("\n[1/3] 检查虚拟环境")
if not create_venv():
sys.exit(1)
venv_py = get_venv_python()
# 2. 安装依赖
print(f"\n[2/3] 检查依赖")
if args.check:
check_all(venv_py)
return
gpu = not args.cpu
if not install_all(venv_py, gpu=gpu):
print("\n部分依赖安装失败,可尝试手动安装。")
sys.exit(1)
# 3. 启动应用
if args.no_run:
print("\n安装完成。运行方式:")
print(f" {venv_py} run.py")
return
print(f"\n[3/3] 启动应用")
launch_app(venv_py)
if __name__ == "__main__":
main()