Update app.py
Browse files
app.py
CHANGED
|
@@ -19,7 +19,7 @@ def run(cmd, cwd=None):
|
|
| 19 |
subprocess.check_call(cmd, cwd=cwd)
|
| 20 |
|
| 21 |
def download_with_retry(repo_id, filename, local_dir, max_retries=3):
|
| 22 |
-
"""Download with retry logic"""
|
| 23 |
from huggingface_hub import hf_hub_download
|
| 24 |
for attempt in range(max_retries):
|
| 25 |
try:
|
|
@@ -28,7 +28,6 @@ def download_with_retry(repo_id, filename, local_dir, max_retries=3):
|
|
| 28 |
repo_id=repo_id,
|
| 29 |
filename=filename,
|
| 30 |
local_dir=local_dir,
|
| 31 |
-
local_dir_use_symlinks=False,
|
| 32 |
)
|
| 33 |
target = Path(local_dir) / filename
|
| 34 |
if target.exists() and target.stat().st_size > 1000:
|
|
@@ -42,12 +41,36 @@ def download_with_retry(repo_id, filename, local_dir, max_retries=3):
|
|
| 42 |
time.sleep(5)
|
| 43 |
return False
|
| 44 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 45 |
# 1. Guarantee RVC existence regardless of build SDK
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 46 |
if not (RVC_DIR / "webui.py").exists():
|
| 47 |
print("RVC missing or incomplete. Performing clean clone...", flush=True)
|
| 48 |
if RVC_DIR.exists():
|
| 49 |
shutil.rmtree(RVC_DIR, ignore_errors=True)
|
| 50 |
-
|
| 51 |
run([
|
| 52 |
"git", "clone", "--depth", "1",
|
| 53 |
"https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI.git",
|
|
@@ -58,19 +81,62 @@ if not (RVC_DIR / "webui.py").exists():
|
|
| 58 |
sys.path.insert(0, str(RVC_DIR))
|
| 59 |
os.chdir(RVC_DIR)
|
| 60 |
|
| 61 |
-
# 3. Ensure asset directories exist
|
| 62 |
for asset_dir in [
|
| 63 |
RVC_DIR / "assets" / "hubert_base",
|
| 64 |
RVC_DIR / "assets" / "rmvpe",
|
| 65 |
RVC_DIR / "assets" / "weights",
|
| 66 |
RVC_DIR / "assets" / "indices",
|
| 67 |
-
RVC_DIR / "assets" / "
|
| 68 |
-
RVC_DIR / "assets" / "pretrained_v2",
|
| 69 |
RVC_DIR / "logs",
|
| 70 |
]:
|
| 71 |
asset_dir.mkdir(parents=True, exist_ok=True)
|
| 72 |
|
| 73 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
model_repo = "jacky3102/OldChineseMan_RVC"
|
| 75 |
weights_dir = RVC_DIR / "assets" / "weights"
|
| 76 |
indices_dir = RVC_DIR / "assets" / "indices"
|
|
@@ -98,7 +164,7 @@ if all_ok:
|
|
| 98 |
import torch
|
| 99 |
pth_path = weights_dir / "OldChineseMan.pth"
|
| 100 |
print(f"Loading {pth_path}...", flush=True)
|
| 101 |
-
state = torch.load(pth_path, map_location="cpu")
|
| 102 |
print(f"β Model loaded. Keys: {list(state.keys())[:10]}...", flush=True)
|
| 103 |
if "config" in state:
|
| 104 |
print(f" Config: {state['config']}", flush=True)
|
|
@@ -106,15 +172,21 @@ if all_ok:
|
|
| 106 |
print(f"β Model verification failed: {e}", flush=True)
|
| 107 |
all_ok = False
|
| 108 |
|
| 109 |
-
if not all_ok:
|
| 110 |
-
print("β Some model files failed verification. Inference may fail.", flush=True)
|
| 111 |
else:
|
| 112 |
print("=== All model files ready and verified ===", flush=True)
|
| 113 |
|
| 114 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
print("=== Starting RVC WebUI ===", flush=True)
|
| 116 |
run([
|
| 117 |
sys.executable,
|
| 118 |
"webui.py",
|
| 119 |
-
"--
|
| 120 |
], cwd=RVC_DIR)
|
|
|
|
| 19 |
subprocess.check_call(cmd, cwd=cwd)
|
| 20 |
|
| 21 |
def download_with_retry(repo_id, filename, local_dir, max_retries=3):
|
| 22 |
+
"""Download a single file with retry logic."""
|
| 23 |
from huggingface_hub import hf_hub_download
|
| 24 |
for attempt in range(max_retries):
|
| 25 |
try:
|
|
|
|
| 28 |
repo_id=repo_id,
|
| 29 |
filename=filename,
|
| 30 |
local_dir=local_dir,
|
|
|
|
| 31 |
)
|
| 32 |
target = Path(local_dir) / filename
|
| 33 |
if target.exists() and target.stat().st_size > 1000:
|
|
|
|
| 41 |
time.sleep(5)
|
| 42 |
return False
|
| 43 |
|
| 44 |
+
def snapshot_with_retry(repo_id, allow_patterns, local_dir, max_retries=3):
|
| 45 |
+
"""Download a folder/pattern set from the HF repo with retry logic."""
|
| 46 |
+
from huggingface_hub import snapshot_download
|
| 47 |
+
for attempt in range(max_retries):
|
| 48 |
+
try:
|
| 49 |
+
print(f"Downloading {allow_patterns} from {repo_id} (attempt {attempt+1}/{max_retries})...", flush=True)
|
| 50 |
+
snapshot_download(
|
| 51 |
+
repo_id=repo_id,
|
| 52 |
+
allow_patterns=allow_patterns,
|
| 53 |
+
local_dir=local_dir,
|
| 54 |
+
)
|
| 55 |
+
print(f"β {allow_patterns} downloaded", flush=True)
|
| 56 |
+
return True
|
| 57 |
+
except Exception as e:
|
| 58 |
+
print(f"β Attempt {attempt+1} failed: {e}", flush=True)
|
| 59 |
+
if attempt < max_retries - 1:
|
| 60 |
+
time.sleep(5)
|
| 61 |
+
return False
|
| 62 |
+
|
| 63 |
# 1. Guarantee RVC existence regardless of build SDK
|
| 64 |
+
# NOTE: the Dockerfile now pins RVC to a specific commit at build time via
|
| 65 |
+
# RVC_COMMIT. This fallback clone (used if the build step didn't run, e.g.
|
| 66 |
+
# local testing) intentionally does NOT pin a commit, so if you hit weird
|
| 67 |
+
# errors when running app.py standalone, check you're on the same commit
|
| 68 |
+
# as the Docker image.
|
| 69 |
if not (RVC_DIR / "webui.py").exists():
|
| 70 |
print("RVC missing or incomplete. Performing clean clone...", flush=True)
|
| 71 |
if RVC_DIR.exists():
|
| 72 |
shutil.rmtree(RVC_DIR, ignore_errors=True)
|
| 73 |
+
|
| 74 |
run([
|
| 75 |
"git", "clone", "--depth", "1",
|
| 76 |
"https://github.com/RVC-Project/Retrieval-based-Voice-Conversion-WebUI.git",
|
|
|
|
| 81 |
sys.path.insert(0, str(RVC_DIR))
|
| 82 |
os.chdir(RVC_DIR)
|
| 83 |
|
| 84 |
+
# 3. Ensure asset directories exist (current layout, per upstream README)
|
| 85 |
for asset_dir in [
|
| 86 |
RVC_DIR / "assets" / "hubert_base",
|
| 87 |
RVC_DIR / "assets" / "rmvpe",
|
| 88 |
RVC_DIR / "assets" / "weights",
|
| 89 |
RVC_DIR / "assets" / "indices",
|
| 90 |
+
RVC_DIR / "assets" / "pymss_weights",
|
|
|
|
| 91 |
RVC_DIR / "logs",
|
| 92 |
]:
|
| 93 |
asset_dir.mkdir(parents=True, exist_ok=True)
|
| 94 |
|
| 95 |
+
BASE_MODEL_REPO = "lj1995/VoiceConversionWebUI"
|
| 96 |
+
|
| 97 |
+
# 4. Download base inference assets (this is what the previous app.py was
|
| 98 |
+
# missing entirely β it only ever downloaded the custom voice model).
|
| 99 |
+
print("=== Downloading base RVC inference assets ===", flush=True)
|
| 100 |
+
base_ok = True
|
| 101 |
+
|
| 102 |
+
# HuBERT is now a Transformers-format folder (config.json,
|
| 103 |
+
# preprocessor_config.json, pytorch_model.bin) β NOT the old single
|
| 104 |
+
# fairseq hubert_base.pt file.
|
| 105 |
+
hubert_dir = RVC_DIR / "assets" / "hubert_base"
|
| 106 |
+
if not (hubert_dir / "pytorch_model.bin").exists():
|
| 107 |
+
base_ok &= snapshot_with_retry(
|
| 108 |
+
BASE_MODEL_REPO,
|
| 109 |
+
allow_patterns=["hubert_base/*"],
|
| 110 |
+
local_dir=RVC_DIR / "assets",
|
| 111 |
+
)
|
| 112 |
+
else:
|
| 113 |
+
print("β hubert_base already present", flush=True)
|
| 114 |
+
|
| 115 |
+
# RMVPE pitch extraction model
|
| 116 |
+
rmvpe_path = RVC_DIR / "assets" / "rmvpe" / "rmvpe.pt"
|
| 117 |
+
if not (rmvpe_path.exists() and rmvpe_path.stat().st_size > 1000):
|
| 118 |
+
base_ok &= download_with_retry(BASE_MODEL_REPO, "rmvpe.pt", RVC_DIR / "assets" / "rmvpe")
|
| 119 |
+
else:
|
| 120 |
+
print("β rmvpe.pt already present", flush=True)
|
| 121 |
+
|
| 122 |
+
# pymss weights β only needed if you use the built-in vocal separation tab.
|
| 123 |
+
# Comment this block out if you don't use that feature, to save build time.
|
| 124 |
+
pymss_dir = RVC_DIR / "assets" / "pymss_weights"
|
| 125 |
+
if not any(pymss_dir.iterdir()) if pymss_dir.exists() else True:
|
| 126 |
+
base_ok &= snapshot_with_retry(
|
| 127 |
+
BASE_MODEL_REPO,
|
| 128 |
+
allow_patterns=["pymss_weights/*"],
|
| 129 |
+
local_dir=RVC_DIR / "assets",
|
| 130 |
+
)
|
| 131 |
+
else:
|
| 132 |
+
print("β pymss_weights already present", flush=True)
|
| 133 |
+
|
| 134 |
+
if not base_ok:
|
| 135 |
+
print("β Some base assets failed to download. Inference will likely fail.", flush=True)
|
| 136 |
+
else:
|
| 137 |
+
print("=== Base assets ready ===", flush=True)
|
| 138 |
+
|
| 139 |
+
# 5. Download OldChineseMan RVC model from your model repo
|
| 140 |
model_repo = "jacky3102/OldChineseMan_RVC"
|
| 141 |
weights_dir = RVC_DIR / "assets" / "weights"
|
| 142 |
indices_dir = RVC_DIR / "assets" / "indices"
|
|
|
|
| 164 |
import torch
|
| 165 |
pth_path = weights_dir / "OldChineseMan.pth"
|
| 166 |
print(f"Loading {pth_path}...", flush=True)
|
| 167 |
+
state = torch.load(pth_path, map_location="cpu", weights_only=False)
|
| 168 |
print(f"β Model loaded. Keys: {list(state.keys())[:10]}...", flush=True)
|
| 169 |
if "config" in state:
|
| 170 |
print(f" Config: {state['config']}", flush=True)
|
|
|
|
| 172 |
print(f"β Model verification failed: {e}", flush=True)
|
| 173 |
all_ok = False
|
| 174 |
|
| 175 |
+
if not (all_ok and base_ok):
|
| 176 |
+
print("β Some model/asset files failed verification. Inference may fail.", flush=True)
|
| 177 |
else:
|
| 178 |
print("=== All model files ready and verified ===", flush=True)
|
| 179 |
|
| 180 |
+
# 6. Launch RVC WebUI
|
| 181 |
+
# The current webui.py reads host/port from GRADIO_SERVER_NAME /
|
| 182 |
+
# GRADIO_SERVER_PORT (already set above) rather than a --port flag in the
|
| 183 |
+
# rewritten branch. Run `python webui.py --help` in the build logs once to
|
| 184 |
+
# confirm which flags your pinned commit actually supports, then adjust
|
| 185 |
+
# the args below accordingly. --noautoopen avoids it trying to open a
|
| 186 |
+
# local browser on a headless server.
|
| 187 |
print("=== Starting RVC WebUI ===", flush=True)
|
| 188 |
run([
|
| 189 |
sys.executable,
|
| 190 |
"webui.py",
|
| 191 |
+
"--noautoopen",
|
| 192 |
], cwd=RVC_DIR)
|