rvc / pipeline /storage.py
ibcplateformes
Replace RVC with Seed-VC for zero-shot voice conversion
fea49f2
"""
Model storage module: persist voice reference files to HuggingFace Dataset repo.
"""
import os
import logging
from datetime import datetime
logger = logging.getLogger(__name__)
MODELS_REPO_ID = None
LOCAL_MODELS_DIR = "/tmp/rvc_models"
def init_storage(repo_id):
"""Initialize storage with the HF dataset repo ID."""
global MODELS_REPO_ID
MODELS_REPO_ID = repo_id
os.makedirs(LOCAL_MODELS_DIR, exist_ok=True)
logger.info("Storage initialized with repo: {}".format(repo_id))
def upload_model(model_name, pth_path, index_path=None, big_npy_path=None, reference_path=None):
"""Upload model files to HF dataset repo."""
if not MODELS_REPO_ID:
logger.warning("No HF repo configured. Model saved locally only.")
return False
try:
from huggingface_hub import HfApi
api = HfApi()
# Upload .pth marker
if pth_path and os.path.exists(pth_path):
api.upload_file(
path_or_fileobj=pth_path,
path_in_repo="models/{}/{}.pth".format(model_name, model_name),
repo_id=MODELS_REPO_ID,
repo_type="dataset",
)
logger.info("Uploaded {}.pth to HF".format(model_name))
# Upload reference audio
if reference_path and os.path.exists(reference_path):
ref_filename = os.path.basename(reference_path)
api.upload_file(
path_or_fileobj=reference_path,
path_in_repo="models/{}/{}".format(model_name, ref_filename),
repo_id=MODELS_REPO_ID,
repo_type="dataset",
)
logger.info("Uploaded {} to HF".format(ref_filename))
# Upload .index file if exists (backward compat)
if index_path and os.path.exists(index_path):
api.upload_file(
path_or_fileobj=index_path,
path_in_repo="models/{}/{}.index".format(model_name, model_name),
repo_id=MODELS_REPO_ID,
repo_type="dataset",
)
# Upload metadata
metadata = {
"name": model_name,
"created": datetime.now().isoformat(),
"engine": "seed-vc",
}
import json
import tempfile
with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as f:
json.dump(metadata, f)
meta_path = f.name
try:
api.upload_file(
path_or_fileobj=meta_path,
path_in_repo="models/{}/metadata.json".format(model_name),
repo_id=MODELS_REPO_ID,
repo_type="dataset",
)
finally:
os.unlink(meta_path)
return True
except Exception as e:
logger.error("Failed to upload model: {}".format(e))
return False
def download_model(model_name):
"""Download model from HF dataset repo. Returns (pth_path, reference_path)."""
if not MODELS_REPO_ID:
return _get_local_model(model_name)
try:
from huggingface_hub import hf_hub_download
local_dir = os.path.join(LOCAL_MODELS_DIR, model_name)
os.makedirs(local_dir, exist_ok=True)
pth_path = hf_hub_download(
repo_id=MODELS_REPO_ID,
repo_type="dataset",
filename="models/{}/{}.pth".format(model_name, model_name),
local_dir=local_dir,
)
# Try to download reference audio
ref_path = None
try:
ref_path = hf_hub_download(
repo_id=MODELS_REPO_ID,
repo_type="dataset",
filename="models/{}/{}_ref.wav".format(model_name, model_name),
local_dir=local_dir,
)
except Exception:
# Try .index for backward compat with old RVC models
try:
ref_path = hf_hub_download(
repo_id=MODELS_REPO_ID,
repo_type="dataset",
filename="models/{}/{}.index".format(model_name, model_name),
local_dir=local_dir,
)
except Exception:
pass
return pth_path, ref_path
except Exception as e:
logger.error("Failed to download model from HF: {}".format(e))
return _get_local_model(model_name)
def _get_local_model(model_name):
"""Get model from local storage."""
local_dir = os.path.join(LOCAL_MODELS_DIR, model_name)
pth_path = os.path.join(local_dir, "{}.pth".format(model_name))
ref_path = os.path.join(local_dir, "{}_ref.wav".format(model_name))
if os.path.exists(pth_path):
return pth_path, ref_path if os.path.exists(ref_path) else None
return None, None
def get_reference_path(model_name):
"""Get the reference audio path for a model."""
local_dir = os.path.join(LOCAL_MODELS_DIR, model_name)
ref_path = os.path.join(local_dir, "{}_ref.wav".format(model_name))
if os.path.exists(ref_path):
return ref_path
# Search in subdirectories (HF download structure)
for root, dirs, files in os.walk(local_dir):
for f in files:
if f.endswith("_ref.wav"):
return os.path.join(root, f)
return None
def list_models():
"""List all available models."""
models = set()
if MODELS_REPO_ID:
try:
from huggingface_hub import HfApi
api = HfApi()
files = api.list_repo_files(MODELS_REPO_ID, repo_type="dataset")
for f in files:
if f.startswith("models/") and f.endswith(".pth"):
parts = f.split("/")
if len(parts) >= 3:
models.add(parts[1])
except Exception as e:
logger.error("Failed to list models from HF: {}".format(e))
if os.path.exists(LOCAL_MODELS_DIR):
for name in os.listdir(LOCAL_MODELS_DIR):
model_dir = os.path.join(LOCAL_MODELS_DIR, name)
if os.path.isdir(model_dir):
pth = os.path.join(model_dir, "{}.pth".format(name))
if os.path.exists(pth):
models.add(name)
return sorted(models)
def delete_model(model_name):
"""Delete a model from HF repo and local storage."""
if MODELS_REPO_ID:
try:
from huggingface_hub import HfApi
api = HfApi()
files = api.list_repo_files(MODELS_REPO_ID, repo_type="dataset")
for f in files:
if f.startswith("models/{}/".format(model_name)):
api.delete_file(f, MODELS_REPO_ID, repo_type="dataset")
logger.info("Deleted {} from HF repo".format(model_name))
except Exception as e:
logger.error("Failed to delete from HF: {}".format(e))
import shutil
local_dir = os.path.join(LOCAL_MODELS_DIR, model_name)
if os.path.exists(local_dir):
shutil.rmtree(local_dir)
logger.info("Deleted {} from local storage".format(model_name))
return True