mirror of
https://github.com/RVC-Boss/GPT-SoVITS.git
synced 2026-09-19 00:18:50 +08:00
fix lots of errors; and add uv compatibility
This commit is contained in:
parent
d523079fc0
commit
a34561950e
292
docs/LOCAL_SETUP_FIXES.md
Normal file
292
docs/LOCAL_SETUP_FIXES.md
Normal file
@ -0,0 +1,292 @@
|
||||
# GPT-SoVITS 本地环境修复总结(uv)
|
||||
|
||||
本文档记录在本机(Arch / CUDA 13.3 / RTX 4060 Laptop / Python via uv)搭建
|
||||
`GPT-SoVITS` 时踩到的问题、已合入代码/依赖的修复,以及一键重建环境的方法。
|
||||
|
||||
相关脚本:
|
||||
|
||||
| 文件 | 作用 |
|
||||
|------|------|
|
||||
| `setup_uv.sh` | 用 uv 创建 venv、装依赖、布局模型 |
|
||||
| `scripts/setup_sitecustomize.py` | 写入 sitecustomize,预加载 CUDA12 NPP |
|
||||
| `scripts/link_npp_for_torchcodec.py` | 把 NPP `.so.12` 链到 torchcodec 目录 |
|
||||
| `requirements.txt` | 已固化兼容版本与额外依赖 |
|
||||
|
||||
一键重建:
|
||||
|
||||
```bash
|
||||
cd /path/to/GPT-SoVITS # 本仓库 root
|
||||
bash setup_uv.sh --device CU128
|
||||
source .venv/bin/activate
|
||||
python webui.py zh_CN
|
||||
```
|
||||
|
||||
可选参数见 `bash setup_uv.sh --help`。
|
||||
|
||||
---
|
||||
|
||||
## 1. 环境与依赖(可复用,已写入 requirements / setup 脚本)
|
||||
|
||||
### 1.1 工具链
|
||||
|
||||
- 用 **uv** 建 Python **3.10** venv(项目官方测过 3.10–3.12)
|
||||
- 系统需:`ffmpeg`、`unzip`、`cmake`/`gcc`(编译 opencc 等时用到)
|
||||
- GPU 包:`torch` / `torchcodec` / `torchaudio` 均从官方 cu128(或 cu126)index 安装,**三者 CUDA 标签必须一致**
|
||||
|
||||
```bash
|
||||
uv venv --python 3.10 .venv
|
||||
source .venv/bin/activate
|
||||
uv pip install torch torchcodec --index-url https://download.pytorch.org/whl/cu128
|
||||
uv pip install torchaudio --index-url https://download.pytorch.org/whl/cu128 --reinstall
|
||||
uv pip install -r extra-req.txt --no-deps
|
||||
uv pip install -r requirements.txt
|
||||
```
|
||||
|
||||
### 1.2 `transformers` 上限过旧 → Fun-ASR-Nano 无法加载 Qwen3
|
||||
|
||||
**现象**
|
||||
|
||||
```
|
||||
ValueError: The checkpoint you are trying to load has model type `qwen3`
|
||||
but Transformers does not recognize this architecture.
|
||||
```
|
||||
|
||||
**原因**
|
||||
|
||||
- Fun-ASR-Nano(`FunAudioLLM/Fun-ASR-Nano-2512`)内部 LLM 是 Qwen3-0.6B
|
||||
- 原 `requirements.txt` 为 `transformers>=4.43,<=4.50`,4.50 尚无 `qwen3`
|
||||
|
||||
**修复(已写入 requirements.txt)**
|
||||
|
||||
```
|
||||
transformers>=4.51,<4.53
|
||||
```
|
||||
|
||||
本机验证:`transformers==4.52.4`,`CONFIG_MAPPING` 含 `qwen3`,Fun-ASR-Nano 可加载。
|
||||
|
||||
### 1.3 Gradio WebUI 空白 / `TypeError: unhashable type: 'dict'`
|
||||
|
||||
**现象**
|
||||
|
||||
访问 `http://0.0.0.0:9874/` 时 ASGI 报错:
|
||||
|
||||
```
|
||||
File ".../jinja2/utils.py", line 515, in __getitem__
|
||||
rv = self._mapping[key]
|
||||
TypeError: unhashable type: 'dict'
|
||||
```
|
||||
|
||||
**原因**
|
||||
|
||||
- `requirements.txt` 只有 `fastapi[standard]>=0.115.2`,无上界
|
||||
- uv 解析到了 `fastapi 0.139` + `starlette 1.3`
|
||||
- Starlette 新 API:`TemplateResponse(request, name, context=...)`
|
||||
- Gradio 4.44 仍调用旧 API:`TemplateResponse(name, {"request": request, ...})`
|
||||
- 模板名位置被塞进了 dict,Jinja2 缓存 key 不可哈希
|
||||
|
||||
**修复(已写入 requirements.txt)**
|
||||
|
||||
```
|
||||
fastapi[standard]>=0.115.2,<0.116
|
||||
starlette>=0.37.2,<0.39
|
||||
```
|
||||
|
||||
本机验证:`fastapi==0.115.2` + `starlette==0.38.6`,首页 HTTP 200。
|
||||
|
||||
### 1.4 `torchaudio.load` 失败:缺 `libnppicc.so.12`
|
||||
|
||||
**现象**(`2-get-sv.py` 等)
|
||||
|
||||
```
|
||||
OSError: libnppicc.so.12: cannot open shared object file
|
||||
RuntimeError: Could not load libtorchcodec
|
||||
```
|
||||
|
||||
**原因**
|
||||
|
||||
- torchaudio 2.11 默认走 **torchcodec** 解码
|
||||
- torchcodec 依赖 **CUDA 12** 的 NPP 库(soname `.so.12`)
|
||||
- 系统是 CUDA 13,只有 `libnppicc.so.13`
|
||||
|
||||
**修复(可复用,已写入 requirements + setup 脚本)**
|
||||
|
||||
1. 安装 `nvidia-npp-cu12`(已加入 `requirements.txt`)
|
||||
2. 把 `nvidia/npp/lib/libnpp*.so.12` **符号链接**到 `torchcodec` 包目录
|
||||
(`scripts/link_npp_for_torchcodec.py`)
|
||||
3. 写入 `sitecustomize.py` 预加载 NPP,并在 `.venv/bin/activate` 追加 `LD_LIBRARY_PATH`
|
||||
(`scripts/setup_sitecustomize.py`)
|
||||
|
||||
验证:
|
||||
|
||||
```python
|
||||
import torchaudio
|
||||
w, sr = torchaudio.load("some.wav") # should succeed
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 代码修复(上游逻辑漏洞,已改仓库文件)
|
||||
|
||||
### 2.1 ASR backend 未从 WebUI 传到 CLI
|
||||
|
||||
**现象**
|
||||
|
||||
在 WebUI 选「达摩 ASR (中文经典)」仍加载 Fun-ASR-Nano,并触发 Qwen3/transformers 错误。
|
||||
|
||||
**原因**
|
||||
|
||||
上游 PR 给 `create_model(..., backend=...)` 加了分支,但:
|
||||
|
||||
1. `tools/asr/config.py` 的 `asr_dict` **没有** `backend` 字段
|
||||
2. `tools/asr/funasr_asr.py` CLI **没有** `-b/--backend`
|
||||
3. `webui.py` `open_asr` **没有**把 backend 拼进命令
|
||||
4. 默认 dropdown value 还是旧名字 `"达摩 ASR (中文)"`,与新 key `"达摩 ASR (中文经典)"` 对不上
|
||||
|
||||
于是 CLI 永远 default=`fun-asr-nano`。
|
||||
|
||||
**修复文件**
|
||||
|
||||
- `tools/asr/config.py`:为 Fun-ASR-Nano / SenseVoice / 达摩 增加 `backend`
|
||||
- `tools/asr/funasr_asr.py`:增加 `-b/--backend` 并传入 `execute_asr`
|
||||
- `webui.py`:
|
||||
- `open_asr` 拼接 `-b ...`
|
||||
- 默认模型改为 `"达摩 ASR (中文经典)"`
|
||||
|
||||
对应 backend:
|
||||
|
||||
| WebUI 选项 | backend |
|
||||
|------------|---------|
|
||||
| Fun-ASR-Nano (31语种+方言, 推荐) | `fun-asr-nano` |
|
||||
| SenseVoice (极速, 5语种) | `sensevoice` |
|
||||
| 达摩 ASR (中文经典) | `paraformer`(本地 Paraformer+VAD+Punc) |
|
||||
|
||||
中文数据建议默认用 **达摩 ASR**(离线、已预装权重)。
|
||||
|
||||
---
|
||||
|
||||
## 3. 模型文件布局(安装/摆放,非代码)
|
||||
|
||||
README 约定的路径:
|
||||
|
||||
| 内容 | 路径 |
|
||||
|------|------|
|
||||
| 预训练底模 | `GPT_SoVITS/pretrained_models/` |
|
||||
| G2PW(中文多音字) | `GPT_SoVITS/text/G2PWModel/` |
|
||||
| UVR5 人声分离 | `tools/uvr5/uvr5_weights/` |
|
||||
| FunASR / Faster-Whisper | `tools/asr/models/` |
|
||||
|
||||
本机实际做法:
|
||||
|
||||
1. **G2PW**:解压根目录 `G2PWModel.zip` → `GPT_SoVITS/text/`
|
||||
2. **UVR5**:解压根目录 `uvr5_weights.zip` → `tools/uvr5/`
|
||||
3. **ASR**:把 `aaa/` 下 FunASR + faster-whisper 拷到 `tools/asr/models/`
|
||||
(注意 docker 下载出来可能是 root 权限,需 `chown`)
|
||||
4. **pretrained_models**:
|
||||
- 旁边 `../GPT-SoVITS/pretrained_models.zip` 当时 **损坏**(缺 EOCD)
|
||||
- 从正在跑的 Docker 镜像内路径
|
||||
`/workspace/models/pretrained_models/`
|
||||
`docker cp` 到本地 `GPT_SoVITS/pretrained_models/`
|
||||
- `setup_uv.sh` 会按:容器 → 旁目录 → zip 的顺序尝试
|
||||
|
||||
校验清单:
|
||||
|
||||
```text
|
||||
GPT_SoVITS/pretrained_models/s2Gv3.pth
|
||||
GPT_SoVITS/pretrained_models/s1v3.ckpt
|
||||
GPT_SoVITS/pretrained_models/gsv-v2final-pretrained/
|
||||
GPT_SoVITS/pretrained_models/v2Pro/
|
||||
GPT_SoVITS/pretrained_models/chinese-hubert-base/
|
||||
GPT_SoVITS/pretrained_models/chinese-roberta-wwm-ext-large/
|
||||
GPT_SoVITS/pretrained_models/sv/
|
||||
GPT_SoVITS/text/G2PWModel/
|
||||
tools/uvr5/uvr5_weights/*.pth
|
||||
tools/asr/models/speech_paraformer-.../model.pt
|
||||
tools/asr/models/speech_fsmn_vad_.../model.pt
|
||||
tools/asr/models/punc_ct-transformer_.../model.pt
|
||||
tools/asr/models/faster-whisper-large-v3/model.bin
|
||||
```
|
||||
|
||||
可选运行时数据(日/英 g2p):
|
||||
|
||||
- `$VIRTUAL_ENV/nltk_data`
|
||||
- `site-packages/pyopenjtalk/open_jtalk_dic_utf_8-1.11`
|
||||
(`setup_uv.sh` 会尝试从 hf-mirror 拉取)
|
||||
|
||||
---
|
||||
|
||||
## 4. 问题速查
|
||||
|
||||
| 症状 | 处理 |
|
||||
|------|------|
|
||||
| WebUI 打开报 `unhashable type: 'dict'` | 固定 fastapi<0.116、starlette<0.39,重启 webui |
|
||||
| Fun-ASR-Nano 报 `model type qwen3` | `transformers>=4.51`;或直接用「达摩 ASR」 |
|
||||
| 选达摩却仍加载 Nano | 更新后的 `config.py`/`funasr_asr.py`/`webui.py`,重启 webui |
|
||||
| `2-get-sv` / `torchaudio.load` 缺 `libnppicc.so.12` | 装 `nvidia-npp-cu12` + 跑两个 scripts hook |
|
||||
| `torchaudio` 与 `torch` CUDA 不一致 | 用同一 index 重装 `torchaudio`(`--reinstall`) |
|
||||
| pretrained zip 解压失败 | 检查 zip 完整性;或从官方 Docker 镜像/HF 重新下 |
|
||||
| ASR 模型目录几乎空、权限 denied | `aaa/` 是 root 文件时 `sudo chown -R $USER aaa` 再拷 |
|
||||
|
||||
---
|
||||
|
||||
## 5. 建议启动流程
|
||||
|
||||
```bash
|
||||
cd /home/ogios/work/voice/local
|
||||
source .venv/bin/activate # 会带上 NPP LD_LIBRARY_PATH
|
||||
python webui.py zh_CN
|
||||
```
|
||||
|
||||
或:
|
||||
|
||||
```bash
|
||||
uv run webui.py zh_CN
|
||||
```
|
||||
|
||||
数据处理推荐顺序:
|
||||
|
||||
1. UVR5 人声分离(可选)
|
||||
2. 切片 slicer
|
||||
3. ASR:**达摩 ASR (中文经典)** + `zh`
|
||||
4. 1A 文本 / 1B Hubert+SV / 1C semantic(或一键三连)
|
||||
5. 微调 / 推理
|
||||
|
||||
---
|
||||
|
||||
## 6. 与官方 install.sh 的差异
|
||||
|
||||
官方 `install.sh` 依赖 **conda**。本机方案等价物:
|
||||
|
||||
| install.sh | 本方案 |
|
||||
|------------|--------|
|
||||
| conda env + pip | uv venv + uv pip |
|
||||
| 自动 wget 模型 zip | `setup_uv.sh` 优先用本地 zip/`aaa`/docker |
|
||||
| conda ffmpeg | 系统 ffmpeg |
|
||||
| 无 fastapi 上界 | 显式 pin 兼容 Gradio 4 |
|
||||
| 无 npp-cu12 | 显式安装 + hook |
|
||||
|
||||
代码侧 ASR backend 接线是对上游遗漏的补丁,升级上游时注意是否已合并,避免冲突。
|
||||
|
||||
---
|
||||
|
||||
## 7. 本机已验证组合(2026-07-24)
|
||||
|
||||
```
|
||||
Python 3.10.20 (uv)
|
||||
torch 2.11.0+cu128
|
||||
torchaudio 2.11.0+cu128
|
||||
torchcodec 0.11.1+cu128
|
||||
transformers 4.52.4
|
||||
fastapi 0.115.2
|
||||
starlette 0.38.6
|
||||
gradio 4.44.1
|
||||
funasr 1.3.26
|
||||
nvidia-npp-cu12 12.4.1.87
|
||||
GPU NVIDIA GeForce RTX 4060 Laptop GPU
|
||||
```
|
||||
|
||||
验证过:
|
||||
|
||||
- WebUI 首页 200
|
||||
- Paraformer ASR 转写成功
|
||||
- Fun-ASR-Nano 模型加载成功
|
||||
- `2-get-sv` 写出 `logs/*/7-sv_cn/*.pt`
|
||||
@ -18,7 +18,7 @@ g2p_en
|
||||
torchaudio
|
||||
modelscope
|
||||
sentencepiece
|
||||
transformers>=4.43,<=4.50
|
||||
transformers>=4.51,<4.53
|
||||
peft<0.18.0
|
||||
chardet
|
||||
PyYAML
|
||||
@ -34,10 +34,16 @@ g2pk2
|
||||
ko_pron
|
||||
opencc
|
||||
python_mecab_ko; sys_platform != 'win32'
|
||||
fastapi[standard]>=0.115.2
|
||||
# Gradio 4.x needs the old TemplateResponse API (name-first).
|
||||
# fastapi>=0.116 / starlette>=0.39 break WebUI page rendering.
|
||||
fastapi[standard]>=0.115.2,<0.116
|
||||
starlette>=0.37.2,<0.39
|
||||
x_transformers
|
||||
torchmetrics<=1.5
|
||||
pydantic<=2.10.6
|
||||
ctranslate2>=4.0,<5
|
||||
av>=11
|
||||
tqdm
|
||||
# torchaudio 2.11+ loads audio via torchcodec, which needs CUDA12 NPP libs.
|
||||
# System CUDA 13 only ships libnpp*.so.13; install the cu12 package for .so.12.
|
||||
nvidia-npp-cu12
|
||||
|
||||
55
scripts/link_npp_for_torchcodec.py
Executable file
55
scripts/link_npp_for_torchcodec.py
Executable file
@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Symlink CUDA12 NPP shared libs next to torchcodec so dlopen can find them."""
|
||||
from __future__ import annotations
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def main() -> int:
|
||||
try:
|
||||
import torchcodec
|
||||
except ImportError:
|
||||
print("[SKIP] torchcodec not installed")
|
||||
return 0
|
||||
|
||||
try:
|
||||
import importlib.util
|
||||
|
||||
spec = importlib.util.find_spec("nvidia.npp")
|
||||
if spec is None or not spec.submodule_search_locations:
|
||||
print("[SKIP] nvidia.npp not installed")
|
||||
return 0
|
||||
npp_roots = [Path(p) for p in spec.submodule_search_locations if p]
|
||||
except Exception as exc:
|
||||
print(f"[SKIP] nvidia.npp lookup failed: {exc}")
|
||||
return 0
|
||||
|
||||
npp_lib = None
|
||||
for root in npp_roots:
|
||||
cand = root / "lib"
|
||||
if cand.is_dir():
|
||||
npp_lib = cand
|
||||
break
|
||||
if npp_lib is None:
|
||||
print("[SKIP] nvidia.npp lib dir not found")
|
||||
return 0
|
||||
|
||||
torchcodec_dir = Path(torchcodec.__file__).resolve().parent
|
||||
linked = 0
|
||||
for src in sorted(npp_lib.glob("libnpp*.so.12")):
|
||||
dst = torchcodec_dir / src.name
|
||||
if dst.is_symlink() or dst.exists():
|
||||
if dst.is_symlink() and dst.resolve() == src.resolve():
|
||||
continue
|
||||
dst.unlink()
|
||||
dst.symlink_to(src)
|
||||
linked += 1
|
||||
print(f"[OK] {dst.name} -> {src}")
|
||||
|
||||
print(f"[OK] linked {linked} NPP libs into {torchcodec_dir}")
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
92
scripts/setup_sitecustomize.py
Executable file
92
scripts/setup_sitecustomize.py
Executable file
@ -0,0 +1,92 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Write sitecustomize.py that preloads CUDA12 NPP for torchcodec/torchaudio."""
|
||||
from __future__ import annotations
|
||||
|
||||
import site
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
SITECUSTOMIZE = r'''"""Auto-configure NVIDIA NPP libs for torchcodec/torchaudio."""
|
||||
from __future__ import annotations
|
||||
|
||||
import ctypes
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def _npp_lib_dirs() -> list[Path]:
|
||||
dirs: list[Path] = []
|
||||
try:
|
||||
import importlib.util
|
||||
|
||||
spec = importlib.util.find_spec("nvidia.npp")
|
||||
if spec is not None and spec.submodule_search_locations:
|
||||
for loc in spec.submodule_search_locations:
|
||||
if not loc:
|
||||
continue
|
||||
p = Path(loc) / "lib"
|
||||
if p.is_dir():
|
||||
dirs.append(p)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
try:
|
||||
here = Path(__file__).resolve().parent / "nvidia" / "npp" / "lib"
|
||||
if here.is_dir():
|
||||
dirs.append(here)
|
||||
except Exception:
|
||||
pass
|
||||
return dirs
|
||||
|
||||
|
||||
def _ensure_npp() -> None:
|
||||
for npp_lib in _npp_lib_dirs():
|
||||
lib_path = str(npp_lib)
|
||||
current = os.environ.get("LD_LIBRARY_PATH", "")
|
||||
parts = [p for p in current.split(":") if p]
|
||||
if lib_path not in parts:
|
||||
os.environ["LD_LIBRARY_PATH"] = lib_path + ((":" + current) if current else "")
|
||||
for name in sorted(npp_lib.glob("libnpp*.so.12")):
|
||||
try:
|
||||
ctypes.CDLL(str(name), mode=ctypes.RTLD_GLOBAL)
|
||||
except OSError:
|
||||
pass
|
||||
return
|
||||
|
||||
|
||||
try:
|
||||
_ensure_npp()
|
||||
except Exception:
|
||||
pass
|
||||
'''
|
||||
|
||||
|
||||
def main() -> int:
|
||||
candidates: list[Path] = []
|
||||
try:
|
||||
candidates.extend(Path(p) for p in site.getsitepackages())
|
||||
except Exception:
|
||||
pass
|
||||
venv = Path(sys.prefix)
|
||||
candidates.append(venv / "lib" / f"python{sys.version_info.major}.{sys.version_info.minor}" / "site-packages")
|
||||
|
||||
written = False
|
||||
for sp in candidates:
|
||||
if not sp.is_dir():
|
||||
continue
|
||||
if "site-packages" not in sp.parts:
|
||||
continue
|
||||
target = sp / "sitecustomize.py"
|
||||
target.write_text(SITECUSTOMIZE, encoding="utf-8")
|
||||
print(f"[OK] wrote {target}")
|
||||
written = True
|
||||
break
|
||||
|
||||
if not written:
|
||||
print("[ERROR] could not find site-packages", file=sys.stderr)
|
||||
return 1
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
321
setup_uv.sh
Executable file
321
setup_uv.sh
Executable file
@ -0,0 +1,321 @@
|
||||
#!/usr/bin/env bash
|
||||
# GPT-SoVITS local setup via uv
|
||||
# Usage:
|
||||
# bash setup_uv.sh # CU128 default
|
||||
# bash setup_uv.sh --device CU126
|
||||
# bash setup_uv.sh --device CPU
|
||||
# bash setup_uv.sh --skip-models # deps only
|
||||
# bash setup_uv.sh --models-only # install/layout models only
|
||||
# bash setup_uv.sh --force-venv # recreate .venv
|
||||
set -euo pipefail
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cd "$ROOT"
|
||||
|
||||
DEVICE="CU128"
|
||||
SKIP_MODELS=false
|
||||
MODELS_ONLY=false
|
||||
FORCE_VENV=false
|
||||
PYTHON_VERSION="3.10"
|
||||
VENV_DIR="${VENV_DIR:-.venv}"
|
||||
|
||||
RED='\033[1;31m'
|
||||
GRN='\033[1;32m'
|
||||
YLW='\033[1;33m'
|
||||
BLU='\033[1;34m'
|
||||
RST='\033[0m'
|
||||
info() { echo -e "${GRN}[INFO]${RST} $*"; }
|
||||
warn() { echo -e "${YLW}[WARN]${RST} $*"; }
|
||||
err() { echo -e "${RED}[ERROR]${RST} $*"; }
|
||||
ok() { echo -e "${BLU}[OK]${RST} $*"; }
|
||||
|
||||
print_help() {
|
||||
cat <<EOF
|
||||
Usage: bash setup_uv.sh [OPTIONS]
|
||||
|
||||
Options:
|
||||
--device CU126|CU128|CPU PyTorch device wheel (default: CU128)
|
||||
--python 3.10|3.11 Python version for venv (default: 3.10)
|
||||
--venv PATH Venv directory (default: .venv)
|
||||
--skip-models Skip model install/layout
|
||||
--models-only Only layout models, skip venv/deps
|
||||
--force-venv Remove and recreate venv
|
||||
-h, --help Show help
|
||||
|
||||
After setup:
|
||||
source ${VENV_DIR}/bin/activate
|
||||
python webui.py zh_CN
|
||||
# or: uv run webui.py zh_CN
|
||||
EOF
|
||||
}
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
--device) DEVICE="${2^^}"; shift 2 ;;
|
||||
--python) PYTHON_VERSION="$2"; shift 2 ;;
|
||||
--venv) VENV_DIR="$2"; shift 2 ;;
|
||||
--skip-models) SKIP_MODELS=true; shift ;;
|
||||
--models-only) MODELS_ONLY=true; shift ;;
|
||||
--force-venv) FORCE_VENV=true; shift ;;
|
||||
-h|--help) print_help; exit 0 ;;
|
||||
*) err "Unknown arg: $1"; print_help; exit 1 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
case "$DEVICE" in
|
||||
CU126|CU128|CPU) ;;
|
||||
*) err "Invalid --device $DEVICE (use CU126|CU128|CPU)"; exit 1 ;;
|
||||
esac
|
||||
|
||||
need_cmd() {
|
||||
command -v "$1" >/dev/null 2>&1 || { err "Missing command: $1"; exit 1; }
|
||||
}
|
||||
|
||||
# ---------- models layout ----------
|
||||
layout_models() {
|
||||
info "Layout pretrained / ASR / UVR5 / G2PW models"
|
||||
|
||||
# Pretrained: copy from sibling docker tree or unzip local zip if present
|
||||
if [[ ! -d GPT_SoVITS/pretrained_models/sv ]]; then
|
||||
if [[ -d ../GPT-SoVITS/GPT_SoVITS/pretrained_models/sv ]]; then
|
||||
info "Copying pretrained_models from ../GPT-SoVITS"
|
||||
mkdir -p GPT_SoVITS/pretrained_models
|
||||
# handle broken docker symlink cases by copying real files if available
|
||||
if command -v docker >/dev/null 2>&1; then
|
||||
CID="$(docker ps --filter ancestor=xxxxrt666/gpt-sovits:latest-cu128 --format '{{.ID}}' | head -1 || true)"
|
||||
if [[ -n "${CID:-}" ]]; then
|
||||
info "docker cp pretrained from container $CID"
|
||||
docker cp "$CID:/workspace/models/pretrained_models/." GPT_SoVITS/pretrained_models/ || true
|
||||
fi
|
||||
fi
|
||||
if [[ ! -d GPT_SoVITS/pretrained_models/sv ]]; then
|
||||
cp -a ../GPT-SoVITS/GPT_SoVITS/pretrained_models/. GPT_SoVITS/pretrained_models/ 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
if [[ ! -d GPT_SoVITS/pretrained_models/sv && -f pretrained_models.zip ]]; then
|
||||
info "Unzipping pretrained_models.zip"
|
||||
unzip -q -o pretrained_models.zip -d GPT_SoVITS || warn "pretrained_models.zip may be corrupt"
|
||||
fi
|
||||
if [[ ! -d GPT_SoVITS/pretrained_models/sv && -f ../GPT-SoVITS/pretrained_models.zip ]]; then
|
||||
info "Trying ../GPT-SoVITS/pretrained_models.zip"
|
||||
unzip -q -o ../GPT-SoVITS/pretrained_models.zip -d GPT_SoVITS || warn "zip may be corrupt"
|
||||
fi
|
||||
else
|
||||
ok "pretrained_models already present"
|
||||
fi
|
||||
|
||||
# G2PW
|
||||
if [[ ! -d GPT_SoVITS/text/G2PWModel ]]; then
|
||||
if [[ -f G2PWModel.zip ]]; then
|
||||
info "Unzipping G2PWModel.zip"
|
||||
unzip -q -o G2PWModel.zip -d GPT_SoVITS/text
|
||||
else
|
||||
warn "G2PWModel.zip missing — Chinese polyphone quality may drop"
|
||||
fi
|
||||
else
|
||||
ok "G2PWModel already present"
|
||||
fi
|
||||
|
||||
# UVR5
|
||||
if ! find tools/uvr5/uvr5_weights -mindepth 1 ! -name '.gitignore' 2>/dev/null | grep -q .; then
|
||||
if [[ -f uvr5_weights.zip ]]; then
|
||||
info "Unzipping uvr5_weights.zip"
|
||||
unzip -q -o uvr5_weights.zip -d tools/uvr5
|
||||
else
|
||||
warn "uvr5_weights.zip missing — skip UVR5"
|
||||
fi
|
||||
else
|
||||
ok "uvr5_weights already present"
|
||||
fi
|
||||
|
||||
# ASR models from aaa/ (or leave existing tools/asr/models)
|
||||
mkdir -p tools/asr/models
|
||||
if [[ -d aaa ]]; then
|
||||
for name in \
|
||||
faster-whisper-large-v3 \
|
||||
punc_ct-transformer_zh-cn-common-vocab272727-pytorch \
|
||||
speech_fsmn_vad_zh-cn-16k-common-pytorch \
|
||||
speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch
|
||||
do
|
||||
if [[ -d "aaa/$name" ]]; then
|
||||
if [[ ! -e "tools/asr/models/$name/model.pt" && ! -e "tools/asr/models/$name/model.bin" ]]; then
|
||||
info "Installing ASR model: $name"
|
||||
rm -rf "tools/asr/models/$name"
|
||||
cp -a "aaa/$name" "tools/asr/models/$name"
|
||||
else
|
||||
ok "ASR model exists: $name"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# quick summary
|
||||
echo
|
||||
info "Model summary:"
|
||||
for p in \
|
||||
GPT_SoVITS/pretrained_models/s2Gv3.pth \
|
||||
GPT_SoVITS/pretrained_models/sv \
|
||||
GPT_SoVITS/text/G2PWModel \
|
||||
tools/uvr5/uvr5_weights/HP2_all_vocals.pth \
|
||||
tools/asr/models/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch/model.pt \
|
||||
tools/asr/models/faster-whisper-large-v3/model.bin
|
||||
do
|
||||
if [[ -e "$p" ]]; then ok " $p"; else warn " MISSING $p"; fi
|
||||
done
|
||||
}
|
||||
|
||||
# ---------- venv + deps ----------
|
||||
setup_venv() {
|
||||
need_cmd uv
|
||||
need_cmd ffmpeg || warn "ffmpeg not found in PATH (needed at runtime)"
|
||||
|
||||
if [[ "$FORCE_VENV" == true && -d "$VENV_DIR" ]]; then
|
||||
warn "Removing existing $VENV_DIR"
|
||||
rm -rf "$VENV_DIR"
|
||||
fi
|
||||
|
||||
if [[ ! -d "$VENV_DIR" ]]; then
|
||||
info "Creating venv ($VENV_DIR) with Python $PYTHON_VERSION"
|
||||
uv venv --python "$PYTHON_VERSION" "$VENV_DIR"
|
||||
else
|
||||
ok "Using existing venv: $VENV_DIR"
|
||||
fi
|
||||
|
||||
# shellcheck disable=SC1090
|
||||
source "$VENV_DIR/bin/activate"
|
||||
export PATH="$ROOT/$VENV_DIR/bin:$PATH"
|
||||
info "Python: $(python -V) @ $(which python)"
|
||||
|
||||
local torch_index
|
||||
case "$DEVICE" in
|
||||
CU128) torch_index="https://download.pytorch.org/whl/cu128" ;;
|
||||
CU126) torch_index="https://download.pytorch.org/whl/cu126" ;;
|
||||
CPU) torch_index="https://download.pytorch.org/whl/cpu" ;;
|
||||
esac
|
||||
|
||||
info "Installing PyTorch + torchcodec + torchaudio ($DEVICE)"
|
||||
uv pip install torch torchcodec --index-url "$torch_index"
|
||||
# torchaudio must match the same CUDA tag as torch
|
||||
uv pip install torchaudio --index-url "$torch_index" --reinstall
|
||||
|
||||
info "Installing extra-req.txt (no-deps)"
|
||||
uv pip install -r extra-req.txt --no-deps
|
||||
|
||||
info "Installing requirements.txt"
|
||||
uv pip install -r requirements.txt
|
||||
|
||||
# Enforce pins that uv may have loosened via transitive deps
|
||||
info "Pinning fastapi/starlette compatible with Gradio 4.x"
|
||||
uv pip install "fastapi[standard]>=0.115.2,<0.116" "starlette>=0.37.2,<0.39"
|
||||
|
||||
info "Installing/ensuring nvidia-npp-cu12 for torchcodec"
|
||||
uv pip install nvidia-npp-cu12 || warn "nvidia-npp-cu12 install failed (network?); audio load may break"
|
||||
|
||||
info "Post-install hooks (sitecustomize + NPP symlinks)"
|
||||
python scripts/setup_sitecustomize.py || true
|
||||
python scripts/link_npp_for_torchcodec.py || true
|
||||
|
||||
# Ensure activate exports LD_LIBRARY_PATH for NPP
|
||||
local activate_file="$VENV_DIR/bin/activate"
|
||||
if [[ -f "$activate_file" ]] && ! grep -q 'nvidia/npp/lib' "$activate_file"; then
|
||||
cat >> "$activate_file" <<'EOF'
|
||||
|
||||
# GPT-SoVITS: expose CUDA12 NPP for torchcodec/torchaudio
|
||||
_NPP_LIB="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/lib/python3.10/site-packages/nvidia/npp/lib"
|
||||
# also try dynamic python version
|
||||
if [ ! -d "$_NPP_LIB" ]; then
|
||||
_PYVER="$(python -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")' 2>/dev/null || true)"
|
||||
_NPP_LIB="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)/lib/python${_PYVER}/site-packages/nvidia/npp/lib"
|
||||
fi
|
||||
if [ -d "$_NPP_LIB" ]; then
|
||||
export LD_LIBRARY_PATH="$_NPP_LIB${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
|
||||
fi
|
||||
unset _NPP_LIB _PYVER
|
||||
EOF
|
||||
ok "Patched $activate_file with NPP LD_LIBRARY_PATH"
|
||||
fi
|
||||
|
||||
# Optional runtime data used by Japanese/English g2p
|
||||
install_optional_runtime_data || true
|
||||
|
||||
verify_install
|
||||
}
|
||||
|
||||
install_optional_runtime_data() {
|
||||
info "Optional: NLTK / OpenJTalk dict (skip if offline fails)"
|
||||
local py_prefix openjtalk_prefix
|
||||
py_prefix="$(python -c 'import sys; print(sys.prefix)')"
|
||||
openjtalk_prefix="$(python -c 'import os, pyopenjtalk; print(os.path.dirname(pyopenjtalk.__file__))' 2>/dev/null || true)"
|
||||
|
||||
if [[ ! -d "$py_prefix/nltk_data" ]]; then
|
||||
local nltk_url="https://hf-mirror.com/XXXXRT/GPT-SoVITS-Pretrained/resolve/main/nltk_data.zip"
|
||||
if command -v wget >/dev/null 2>&1; then
|
||||
wget -q -O /tmp/nltk_data.zip "$nltk_url" && unzip -q -o /tmp/nltk_data.zip -d "$py_prefix" && rm -f /tmp/nltk_data.zip && ok "NLTK data" || warn "NLTK download failed"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -n "$openjtalk_prefix" && ! -d "$openjtalk_prefix/open_jtalk_dic_utf_8-1.11" ]]; then
|
||||
local jt_url="https://hf-mirror.com/XXXXRT/GPT-SoVITS-Pretrained/resolve/main/open_jtalk_dic_utf_8-1.11.tar.gz"
|
||||
if command -v wget >/dev/null 2>&1; then
|
||||
wget -q -O /tmp/open_jtalk_dic.tar.gz "$jt_url" && tar -xzf /tmp/open_jtalk_dic.tar.gz -C "$openjtalk_prefix" && rm -f /tmp/open_jtalk_dic.tar.gz && ok "OpenJTalk dict" || warn "OpenJTalk dict download failed"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
verify_install() {
|
||||
info "Verifying install"
|
||||
python - <<'PY'
|
||||
import sys
|
||||
print("python", sys.version)
|
||||
|
||||
import torch, torchaudio
|
||||
print("torch", torch.__version__, "cuda", torch.cuda.is_available(),
|
||||
torch.cuda.get_device_name(0) if torch.cuda.is_available() else "N/A")
|
||||
print("torchaudio", torchaudio.__version__)
|
||||
|
||||
import fastapi, starlette, gradio, transformers
|
||||
print("fastapi", fastapi.__version__)
|
||||
print("starlette", starlette.__version__)
|
||||
print("gradio", gradio.__version__)
|
||||
print("transformers", transformers.__version__)
|
||||
from transformers.models.auto.configuration_auto import CONFIG_MAPPING
|
||||
print("qwen3_support", "qwen3" in CONFIG_MAPPING)
|
||||
|
||||
# torchaudio load smoke (optional if no wav present)
|
||||
from pathlib import Path
|
||||
cands = list(Path("logs").rglob("5-wav32k/*.wav")) + list(Path("output").rglob("*.wav"))
|
||||
if cands:
|
||||
w, sr = torchaudio.load(str(cands[0]))
|
||||
print("torchaudio.load OK", tuple(w.shape), sr)
|
||||
else:
|
||||
print("torchaudio.load skipped (no wav found)")
|
||||
print("VERIFY_OK")
|
||||
PY
|
||||
}
|
||||
|
||||
# ---------- main ----------
|
||||
if [[ "$MODELS_ONLY" == true ]]; then
|
||||
layout_models
|
||||
ok "Models-only done"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
setup_venv
|
||||
|
||||
if [[ "$SKIP_MODELS" != true ]]; then
|
||||
layout_models
|
||||
fi
|
||||
|
||||
echo
|
||||
ok "Setup complete."
|
||||
cat <<EOF
|
||||
|
||||
Next:
|
||||
source ${VENV_DIR}/bin/activate
|
||||
python webui.py zh_CN
|
||||
|
||||
# or without activating:
|
||||
uv run webui.py zh_CN
|
||||
|
||||
See docs/LOCAL_SETUP_FIXES.md for details of applied fixes.
|
||||
EOF
|
||||
@ -10,9 +10,27 @@ def get_models():
|
||||
|
||||
|
||||
asr_dict = {
|
||||
"Fun-ASR-Nano (31语种+方言, 推荐)": {"lang": ["zh", "en", "ja", "ko", "yue", "auto"], "size": ["large"], "path": "funasr_asr.py", "precision": ["float32"]},
|
||||
"SenseVoice (极速, 5语种)": {"lang": ["zh", "en", "ja", "ko", "yue", "auto"], "size": ["large"], "path": "funasr_asr.py", "precision": ["float32"]},
|
||||
"达摩 ASR (中文经典)": {"lang": ["zh", "yue"], "size": ["large"], "path": "funasr_asr.py", "precision": ["float32"]},
|
||||
"Fun-ASR-Nano (31语种+方言, 推荐)": {
|
||||
"lang": ["zh", "en", "ja", "ko", "yue", "auto"],
|
||||
"size": ["large"],
|
||||
"path": "funasr_asr.py",
|
||||
"precision": ["float32"],
|
||||
"backend": "fun-asr-nano",
|
||||
},
|
||||
"SenseVoice (极速, 5语种)": {
|
||||
"lang": ["zh", "en", "ja", "ko", "yue", "auto"],
|
||||
"size": ["large"],
|
||||
"path": "funasr_asr.py",
|
||||
"precision": ["float32"],
|
||||
"backend": "sensevoice",
|
||||
},
|
||||
"达摩 ASR (中文经典)": {
|
||||
"lang": ["zh", "yue"],
|
||||
"size": ["large"],
|
||||
"path": "funasr_asr.py",
|
||||
"precision": ["float32"],
|
||||
"backend": "paraformer",
|
||||
},
|
||||
"Faster Whisper (多语种)": {
|
||||
"lang": ["auto", "en", "ja", "ko"],
|
||||
"size": get_models(),
|
||||
|
||||
@ -163,10 +163,19 @@ if __name__ == "__main__":
|
||||
parser.add_argument(
|
||||
"-p", "--precision", type=str, default="float16", choices=["float16", "float32"], help="fp16 or fp32"
|
||||
) # 还没接入
|
||||
parser.add_argument(
|
||||
"-b",
|
||||
"--backend",
|
||||
type=str,
|
||||
default="fun-asr-nano",
|
||||
choices=["fun-asr-nano", "sensevoice", "paraformer"],
|
||||
help="FunASR backend to use.",
|
||||
)
|
||||
cmd = parser.parse_args()
|
||||
execute_asr(
|
||||
input_folder=cmd.input_folder,
|
||||
output_folder=cmd.output_folder,
|
||||
model_size=cmd.model_size,
|
||||
language=cmd.language,
|
||||
backend=cmd.backend,
|
||||
)
|
||||
|
||||
4
webui.py
4
webui.py
@ -380,6 +380,8 @@ def open_asr(asr_inp_dir, asr_opt_dir, asr_model, asr_model_size, asr_lang, asr_
|
||||
cmd += f" -s {asr_model_size}"
|
||||
cmd += f" -l {asr_lang}"
|
||||
cmd += f" -p {asr_precision}"
|
||||
if "backend" in asr_dict[asr_model]:
|
||||
cmd += f' -b {asr_dict[asr_model]["backend"]}'
|
||||
output_file_name = os.path.basename(asr_inp_dir)
|
||||
output_folder = asr_opt_dir or "output/asr_opt"
|
||||
output_file_path = os.path.abspath(f"{output_folder}/{output_file_name}.list")
|
||||
@ -1411,7 +1413,7 @@ with gr.Blocks(title="GPT-SoVITS WebUI", analytics_enabled=False, js=js, css=css
|
||||
label=i18n("ASR 模型"),
|
||||
choices=list(asr_dict.keys()),
|
||||
interactive=True,
|
||||
value="达摩 ASR (中文)",
|
||||
value="达摩 ASR (中文经典)",
|
||||
)
|
||||
asr_size = gr.Dropdown(
|
||||
label=i18n("ASR 模型尺寸"), choices=["large"], interactive=True, value="large"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user