Add local GPU preset voices with dropdown selection.
Generate ChatTTS sample_random_speaker presets without cloud APIs; choose clone or preset in synthesize UI. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env python3
|
||||
"""生成 ChatTTS 本地预设说话人(sample_random_speaker,走 GPU)。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import sys
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
|
||||
ROOT = Path(__file__).resolve().parent.parent
|
||||
sys.path.insert(0, str(ROOT))
|
||||
|
||||
import torch
|
||||
|
||||
from config import CHATTTS_MODEL_DIR
|
||||
from tts_service import get_chattts_instance, reset_chattts_instance
|
||||
from voice_presets import (
|
||||
DEFAULT_MANIFEST,
|
||||
MANIFEST_PATH,
|
||||
PRESETS_DIR,
|
||||
VOICES_DIR,
|
||||
ensure_manifest,
|
||||
)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
ensure_manifest()
|
||||
PRESETS_DIR.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
try:
|
||||
from whisper_service import reset_whisper_model
|
||||
|
||||
reset_whisper_model()
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
reset_chattts_instance()
|
||||
chat, err = get_chattts_instance()
|
||||
if chat is None:
|
||||
raise SystemExit(f"ChatTTS 加载失败: {err}")
|
||||
|
||||
if not hasattr(chat, "sample_random_speaker"):
|
||||
raise SystemExit("当前 ChatTTS 版本不支持 sample_random_speaker")
|
||||
|
||||
presets = DEFAULT_MANIFEST["presets"]
|
||||
print(f"[INFO] 生成 {len(presets)} 个预设音色 → {PRESETS_DIR}")
|
||||
|
||||
for item in presets:
|
||||
pid = item["id"]
|
||||
label = item["label"]
|
||||
out_path = PRESETS_DIR / f"{pid}.pt"
|
||||
|
||||
spk_emb = chat.sample_random_speaker()
|
||||
payload = {
|
||||
"version": 1,
|
||||
"preset": True,
|
||||
"id": pid,
|
||||
"label": label,
|
||||
"spk_emb": spk_emb,
|
||||
"spk_smp": None,
|
||||
"txt_smp": "",
|
||||
"created_at": datetime.now().isoformat(),
|
||||
"source": "ChatTTS.sample_random_speaker",
|
||||
}
|
||||
torch.save(payload, out_path)
|
||||
print(f" [OK] {label} → {out_path.name}")
|
||||
|
||||
manifest = json.loads(MANIFEST_PATH.read_text(encoding="utf-8"))
|
||||
manifest["generated_at"] = datetime.now().isoformat()
|
||||
manifest["chattts_model"] = str(CHATTTS_MODEL_DIR)
|
||||
MANIFEST_PATH.write_text(
|
||||
json.dumps(manifest, ensure_ascii=False, indent=2),
|
||||
encoding="utf-8",
|
||||
)
|
||||
print("[OK] 全部预设音色生成完成")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
# 生成本地 GPU 预设音色(ChatTTS 内置说话人,无需 API)
|
||||
# 用法: bash scripts/generate_voice_presets.sh
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
||||
VENV_PY="${ROOT}/venv/bin/python"
|
||||
|
||||
if [[ ! -x "${VENV_PY}" ]]; then
|
||||
echo "[ERROR] 未找到 venv,请先 bash deploy.sh deps"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "[INFO] 正在生成 ChatTTS 预设音色(本地 GPU)..."
|
||||
"${VENV_PY}" "${ROOT}/scripts/generate_voice_presets.py"
|
||||
echo "[OK] 预设音色已写入 ${ROOT}/voices/presets/"
|
||||
echo "[OK] 在 Web UI「配音合成」处可从下拉框选择"
|
||||
Reference in New Issue
Block a user