fix lots of errors; and add uv compatibility

This commit is contained in:
ogios 2026-07-24 09:22:13 +08:00
parent d523079fc0
commit a34561950e
8 changed files with 801 additions and 6 deletions

292
docs/LOCAL_SETUP_FIXES.md Normal file
View 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.103.12
- 系统需:`ffmpeg``unzip``cmake`/`gcc`(编译 opencc 等时用到)
- GPU 包:`torch` / `torchcodec` / `torchaudio` 均从官方 cu128或 cu126index 安装,**三者 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, ...})`
- 模板名位置被塞进了 dictJinja2 缓存 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&lt;0.116、starlette&lt;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`

View File

@ -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

View 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
View 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
View 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

View File

@ -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(),

View File

@ -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,
)

View File

@ -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"