BRDF Explorer代码架构解析:从Qt界面到OpenGL渲染的完整实现
2026/4/24 4:29:49
ChatTTS Windows 实战:从部署到优化的全流程指南
ChatTTS 官方仓库默认给出的是 Linux 脚本,很多依赖(espeak-ng、sox、ffmpeg)在 Windows 上要么装不上,要么装完找不到路径。再加上 Python 3.10+ 的虚拟环境与 CUDA 驱动版本耦合,稍不留神就掉进“DLL load failed”或“OSError: [WinError 126]”的大坑。实测常见症状如下:
一句话:Windows 不是不能跑,而是缺一份“能跑且跑得爽”的说明书。
| 方案 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 原生 Windows Conda 环境 | 零容器开销,文件映射快 | 依赖手工解决,易污染系统 | 开发机、单机 demo |
| WSL2 + Docker | 官方镜像开箱即用 | 文件 IO 性能折损 10 %~20 % | 团队统一、CI 集成 |
| Windows 原生 Docker Desktop | IDE 调试方便 | 镜像体积大,NVIDIA 驱动需额外配置 | 生产服务器(WinServer 2019+) |
结论:
下文以“方案 1”为主线,踩坑点同样适用于 WSL2。
nvcc -V能输出版本# PowerShell python -m venv venv-chattts .\venv-chattts\Scripts\activate python -m pip install -U pip setuptools wheeltorch==2.0.1+cu118 torchaudio==2.0.2+cu118 -e git+https://github.com/2noise/ChatTTS.git#egg=chatts fastapi==0.110.0 uvicorn[standard]==0.27.1 psutil==5.9.8注意:
--index-url https://download.pytorch.org/whl/cu118加速pip install espeak-ng-runtime后再把 dll 目录加入 PATH,否则 phonemize 阶段直接崩溃# chatts_svc.py import os, torch, ChatTTS, psutil, gc from fastapi import FastAPI, HTTPException from pydantic import BaseModel app = FastAPI() model = None class TTSRequest(BaseModel): text: str voice: str = "default" speed: float = 1.0 def load_model(): global model if model is None: model = ChatTTS.ChatTTS() model.load(compile=False, device="cuda") # Windows 下先关 compile,避免 Triton 报错 return model @app.on_event("startup") def startup(): load_model() @app.post("/tts") def tts(req: TTSRequest): if not req.text.strip(): raise HTTPException(status_code=400, detail="empty text") try: wavs = model.infer(req.text, voice=req.voice, speed=req.speed) # wavs 是 List[np.ndarray],这里只返回第一段 return {"audio": wavs[0].tolist()} except RuntimeError as e: # 捕获 CUDA OOM,主动回收 if "out of memory" in str(e): gc.collect() torch.cuda.empty_cache() raise HTTPException(status_code=500, detail=str(e)) finally: # 监控显存 mem = torch.cuda.memory_allocated() / 1024** 3 print(f"GPU Memory: {mem:.2f} MB") if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000)启动:
$env:CUDA_VISIBLE_DEVICES="0" python chatts_svc.py浏览器访问http://localhost:8000/docs即可看到 Swagger,粘贴文本点“Try it out”就能听到声音。
del wavs+gc.collect()compile=False先关掉,Windows 对 Triton 支持不完整,开启后缓存永不释放torch.cuda.empty_cache()不能滥用,每 10 次请求调用一次即可,过于频繁反而降低吞吐model.half() # FP16,显存直接减半 model.eval() # 拼接 4 段文本再 infer,比循环调用快 2.3 倍 texts = [req.text[i:i+150] for i in range(0, len(req.text), 150)] wavs = model.infer(texts, batch_size=4)实测 RTX 3060 12 G:
Windows 的asyncio默认 Proactor 事件循环,高并发下出现“RuntimeError: Event is not bound to any loop”。解决:
# 在入口加 import asyncio, sys if sys.version_info >= (3, 8) and sys.platform == "win32": asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())再用uvicorn workers=4多进程,可把 QPS 从 1.2 提到 4.5。
# 追加 /metrics 端点,返回 Prometheus 格式 from prometheus_client import generate_latest, CONTENT_TYPE_LATEST @app.get("/metrics") def metrics(): return Response(generate_latest(), media_type=CONTENT_TYPE_LATEST)配合 Grafana + Windows Exporter,显存、GPU-util、句柄数一目了然。
libespeak-ng.dll放到项目根,运行前os.add_dll_directory(os.getcwd()),避免客户机缺库New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" -Name "LongPathsEnabled" -Value 1 -PropertyType DWORD -Forcechatts-out.log,方便排查cudaLaunchKernel非法访问,回滚才恢复照着上面 5 步,基本能在 Windows 上把 ChatTTS 跑到“开发不报错、生产不炸机”的状态。再往后玩,可以:
如果你按这份笔记成功跑通,或者又遇到新的奇葩报错,欢迎留言交流。一起把 Windows 上的 ChatTTS 打磨成真正可落地的生产力工具!