🐍 M4 Mac 本地部署 Spark-TTS 终极踩坑实录 (含泪总结) 🚀
大家好!我是 永恒哥 (或者你可以用你自己的名字)。最近入手了搭载 M4 芯片的 MacBook Pro (16G 内存),性能杠杠的!💪 于是心血来潮,想在本地部署一下热门的开源语音合成项目 Spark-TTS,体验一把本地 AI 的乐趣。
理想很丰满,现实很骨感… 部署过程简直是一部惊心动魄的“踩坑史诗”!😱 从环境配置到依赖地狱,从网络抽风到硬件限制,我几乎把新手能遇到的坑都踩了一遍。
为了让后来者少走弯路,我把完整的终端操作记录和心路历程整理成了这篇博客,希望能给大家提供一些参考。准备好小板凳和瓜子,我们开始吧!🍿
项目目标: 在 macOS (Apple Silicon M4) 上本地运行 Spark-TTS 的 Web UI Demo。
硬件/软件: MacBook Pro (M4, 16G), macOS Sonoma (推测), Miniconda for ARM。
🛠️ Phase 1: 环境初始化 - Conda 大法好!
万丈高楼平地起,第一步当然是搭建一个干净、隔离的 Python 环境。我们选择 Miniconda。
-
检查老朋友:
(base) dgq@dgqdeMacBook-Pro ~ % conda --version conda 25.1.1 # (有新版本提示,强迫症先忍忍) (base) dgq@dgqdeMacBook-Pro ~ % python --version Python 3.12.9 # (Base 环境是 3.12.9)
-
创建专属小窝
sparktts
: 指定 Python 3.12 版本。(base) dgq@dgqdeMacBook-Pro ~ % conda create -n sparktts python=3.12 # ... 省略安装包列表 ... Proceed ([y]/n)? y # ... 安装完成 ...
-
入住新家: 激活环境。
(base) dgq@dgqdeMacBook-Pro ~ % conda activate sparktts (sparktts) dgq@dgqdeMacBook-Pro ~ % # 看到了 (sparktts),成功!
✅ 阶段小结: 环境创建顺利,Conda yyds!
🔥 Phase 2: 依赖安装 - 第一次亲密接触 (与 PyTorch)
AI 项目,PyTorch 少不了。M 系列芯片需要适配 MPS 后端。
-
安装 PyTorch 全家桶: 直接
pip install
最新版 (当时是 2.6.0)。(sparktts) dgq@dgqdeMacBook-Pro ~ % pip install torch torchvision torchaudio # ... 下载安装 ... Successfully installed ... torch-2.6.0 torchaudio-2.6.0 torchvision-0.21.0 ...
⚠️ 【预警 1】 这里直接装了最新版,没有先去看项目推荐的版本或
requirements.txt
,为后面的版本冲突埋下伏笔! -
克隆项目代码 & 安装依赖 (错误示范):
- 先是尝试在家目录
~
安装requirements.txt
-> 失败 (文件不存在)。 - 然后尝试手动安装
numpy
,librosa
,transformers
等 -> 成功安装了部分。 - 正确姿势应该是先克隆代码,再进目录安装依赖!
# 正确操作:先克隆代码 (sparktts) dgq@dgqdeMacBook-Pro ~ % git clone https://github.com/SparkAudio/Spark-TTS.git (sparktts) dgq@dgqdeMacBook-Pro ~ % cd Spark-TTS # 然后再安装依赖 (sparktts) dgq@dgqdeMacBook-Pro Spark-TTS % pip install -r requirements.txt # ... 大量输出,卸载了 torch 2.6.0, 安装了 requirements.txt 指定的 torch 2.5.1 等 ... ERROR: ... torchvision 0.21.0 requires torch==2.6.0, but you have torch 2.5.1 which is incompatible. Successfully installed ... torch-2.5.1 ... gradio-5.18.0 ...
💣 【坑 1 爆炸】
requirements.txt
要求torch 2.5.1
,但我们之前装的torchvision 0.21.0
却需要torch 2.6.0
!版本冲突出现了! - 先是尝试在家目录
🌐 Phase 3: 模型下载 - 网络、SSL、代理、Git LFS 的混合双打
AI 模型通常很大,下载是个技术活,也是个运气活…
-
尝试
huggingface_hub
下载:(sparktts) dgq@dgqdeMacBook-Pro ~ % mkdir -p pretrained_models # 在家目录创建了! (sparktts) dgq@dgqdeMacBook-Pro ~ % python -c "from huggingface_hub import snapshot_download; snapshot_download(...)" # ... 下载小文件 OK,大文件 model.safetensors 时报错 ... requests.exceptions.SSLError: ... [SSL: UNEXPECTED_EOF_WHILE_READING] ...
💣 【坑 2】 SSL 错误!下载大文件时连接中断。这通常跟网络环境(代理、防火墙)或证书有关。
-
SSL & 代理排查 (一顿操作猛如虎):
- 尝试更新 CA 证书 (
certifi
)。 - 用
wget
(需要先brew install wget
) 下载根证书,遇到本地代理 (127.0.0.1:7890
) 干扰,使用--no-check-certificate
绕过。 - 覆盖证书后再次尝试下载,依然失败!说明问题根源可能在代理或网络本身。
- 尝试取消代理环境变量 (
unset http_proxy ...
),结果引发requests.exceptions.InvalidSchema: Missing dependencies for SOCKS support.
说明requests
库仍想用 SOCKS 代理但缺少PySocks
。
- 尝试更新 CA 证书 (
-
切换到 Git LFS (救星登场): Hugging Face Hub 支持 Git LFS 下载大文件。
# 安装 Git LFS (sparktts) dgq@dgqdeMacBook-Pro ~ % brew install git-lfs # 初始化 Git LFS (通常全局或系统只需一次) (sparktts) dgq@dgqdeMacBook-Pro ~ % git lfs install # 删除之前失败的目录 (sparktts) dgq@dgqdeMacBook-Pro ~ % rm -rf pretrained_models/Spark-TTS-0.5B # 使用 Git LFS 克隆模型 (注意:仍在 ~ 目录执行!) (sparktts) dgq@dgqdeMacBook-Pro ~ % git clone https://huggingface.co/SparkAudio/Spark-TTS-0.5B pretrained_models/Spark-TTS-0.5B # ... 克隆并下载 LFS 文件成功 ... Filtering content: 100% (4/4), 3.66 GiB | 4.20 MiB/s, done.
✅ 阶段胜利! Git LFS 成功下载了模型。但注意,我们下载到了错误的位置 (
~
而不是~/Spark-TTS
内)。
🧩 Phase 4: 启动 Web UI - 最终的依赖与 Bug 搏斗
代码和模型都有了,依赖也按 requirements.txt
装了(虽然有版本冲突警告),是时候启动了!
-
首次启动 (各种 ModuleNotFoundError): 因为之前没完全按
requirements.txt
装,逐个pip install
缺失的gradio
,socksio
(通过pip install 'httpx[socks]'
),omegaconf
,einx
… 直到再次运行pip install -r requirements.txt
才算把依赖装对(除了那个torchvision
冲突)。 -
解决 Torchvision 冲突:
(sparktts) dgq@dgqdeMacBook-Pro Spark-TTS % python webui.py --device 0 # ... 报错 RuntimeError: operator torchvision::nms does not exist ... (sparktts) dgq@dgqdeMacBook-Pro Spark-TTS % pip install torchvision==0.20.1 # 安装兼容 torch 2.5.1 的版本 # ... 成功 ...
-
解决模型路径错误:
(sparktts) dgq@dgqdeMacBook-Pro Spark-TTS % python webui.py --device 0 # ... 报错 FileNotFoundError: ...config.yaml' ... (sparktts) dgq@dgqdeMacBook-Pro Spark-TTS % cd # 回家目录 (sparktts) dgq@dgqdeMacBook-Pro ~ % mv pretrained_models Spark-TTS/ # 把模型目录移到项目里 (sparktts) dgq@dgqdeMacBook-Pro ~ % cd Spark-TTS # 回项目目录
-
Gradio 的挑战:
- 启动 (旧版 Bug): 运行
python webui.py --device 0
后,后台不断报TypeError: argument of type 'bool' is not iterable
,并且因为本地访问检查失败建议share=True
。 - 编辑
webui.py
添加share=True
。 (如截图所示) - 再次启动 (frpc 缺失): 报错
Could not create share link. Missing file: ... frpc_darwin_arm64_v0.3.
- 手动安装
frpc
: 按照提示curl
下载、mv
重命名、mv
移动、chmod +x
加权限。 - 再次启动 (Share Link 失败,但原因变了): 报错
login to server failed: session shutdown / EOF
。分享链接创建失败。 - 访问本地 URL (
http://127.0.0.1:7860
): 浏览器显示 “500 Server Error”,内容是那个TypeError
!说明这个 Bug 阻止了 UI 渲染。
- 启动 (旧版 Bug): 运行
-
升级 Gradio 解决 Bug:
(sparktts) dgq@dgqdeMacBook-Pro Spark-TTS % pip install --upgrade gradio gradio-client # ... 升级到 gradio 5.25.0 ...
升级后,那个烦人的
TypeError
终于消失了!
🐌 Phase 5: MPS 硬件限制 - 最后的拦路虎
UI 不报错了,尝试生成声音!
(sparktts) dgq@dgqdeMacBook-Pro Spark-TTS % python webui.py --device 0
...
* Running on local URL: http://127.0.0.1:7860
... (Share link 依然失败,但本地启动了) ...
# --- 在 UI 点击“生成”后 ---
Traceback (most recent call last):
...
NotImplementedError: Output channels > 65536 not supported at the MPS device. ... set PYTORCH_ENABLE_MPS_FALLBACK=1 ...
💣 【终极 Boss】 PyTorch 的 MPS 后端不支持模型中某个 conv1d
操作(输出通道数 > 65536)。Apple Silicon 加速受限!
-
尝试 MPS Fallback:
(sparktts) dgq@dgqdeMacBook-Pro Spark-TTS % PYTORCH_ENABLE_MPS_FALLBACK=1 python webui.py --device 0
根据日志,这个方法似乎没有完全阻止错误打印,并且后续还可能引发
TypeError: Invalid file: None
(可能因为输入处理有问题)。 -
强制使用 CPU (推荐的权宜之计):
(sparktts) dgq@dgqdeMacBook-Pro Spark-TTS % python webui.py --device cpu
这样可以绕过 MPS 限制,但代价是速度会慢很多!
-
麦克风权限问题 (UI 交互时):
- 日志中没有记录,但根据用户反馈,点击“录制”按钮时出现
Error accessing the microphone: ... user denied permission.
- 解决方案: 需要在浏览器设置和 macOS 系统设置中,为浏览器授予访问麦克风的权限。
- 日志中没有记录,但根据用户反馈,点击“录制”按钮时出现
📊 表格总结:踩坑点与解决方案
挑战/错误 (Challenge/Error) | 可能原因 (Cause) | 解决方案 (Solution Applied in Log) | 最佳实践建议 (Best Practice) |
---|---|---|---|
FileNotFoundError: requirements.txt | 不在正确的项目目录下执行 pip | cd Spark-TTS 进入项目目录 | 务必先进入项目目录再执行相关命令 |
SSLError: [SSL: UNEXPECTED_EOF...] , 下载模型失败 | 网络问题、代理干扰、SSL 证书验证问题 | 多次尝试、更新证书 (无效)、取消代理 (无效)、最终切换到 Git LFS 下载成功 | 优先尝试 Git LFS 下载大模型;检查网络和代理设置 |
FileNotFoundError: ...config.yaml | 模型文件下载到了错误的位置 (用户主目录) | mv pretrained_models Spark-TTS/ 将模型目录移入项目目录 | 确保下载/克隆模型时,目标路径在项目文件夹内 |
ModuleNotFoundError (多次) | 未完全按 requirements.txt 安装,依赖缺失 | 逐个 pip install <module> ,最终执行 pip install -r requirements.txt | 第一时间在项目目录运行 pip install -r requirements.txt |
ERROR: ... torchvision ... requires torch ... incompatible | requirements.txt 指定的 torch 与环境中 torchvision 冲突 | pip install torchvision==0.20.1 安装与 torch 2.5.1 兼容的版本 | 注意检查并解决 pip install -r 后的版本冲突警告 |
TypeError: argument of type 'bool' is not iterable | Gradio 5.18.0 内部 Bug 或兼容性问题 | pip install --upgrade gradio gradio-client 升级 Gradio 到 5.25.0 | 遇到库内部错误时,尝试升级库版本 |
Could not create share link. Missing file: frpc... | Gradio 自动下载 frpc 失败 | 手动下载、重命名、移动 frpc 文件并添加执行权限 | 手动安装 frpc 或检查网络/防火墙 |
Could not create share link. login to server failed... | frpc 无法连接 Gradio 分享服务器 | 忽略此错误,直接访问本地 URL (http://127.0.0.1:7860 ) | 本地部署优先使用本地 URL,share=True 是备选项 |
NotImplementedError: Output channels > 65536 ... MPS | PyTorch MPS 后端对特定 conv1d 操作支持有限 | 尝试 PYTORCH_ENABLE_MPS_FALLBACK=1 (效果不佳);推荐使用 --device cpu 强制 CPU 运行 (速度慢) | 使用 --device cpu 保证运行;关注 PyTorch 更新以获得更好的 MPS 支持 |
Error accessing the microphone... permission denied | 浏览器或 macOS 未授予麦克风权限 | 在浏览器站点设置和 macOS 隐私设置中允许浏览器访问麦克风 | 注意浏览器弹出的权限请求,并在系统设置里检查 |
TypeError: Invalid file: None (最后出现) | Web UI 在处理音频输入时出错,传入了 None 值给 soundfile | 日志中未解决,需要在 UI 可用后,检查音频上传/录制逻辑或 Gradio 组件配置 | 仔细检查 UI 输入是否正确传递给后端函数 |
🗺️ Mermaid 图表:流程与交互
推荐部署流程 (Flowchart)
语音生成交互 (Sequence Diagram - CPU 模式)
🧠 思维导图 (Mind Map)
🙏 写在最后
本地部署 AI 项目,尤其是比较新的或者依赖复杂的项目,在特定硬件(比如 Apple Silicon Mac)上运行时,遇到各种问题是很常见的。关键在于仔细阅读错误信息,理解问题根源,并有条不紊地尝试解决方案。
虽然这次部署 Spark-TTS 的过程充满了波折,最终也只能在 CPU 上运行(速度较慢),但整个调试过程也是一次宝贵的学习经历。希望我的这篇“血泪史”能帮助大家在未来的部署道路上更加顺利!
如果你有更好的解决方案,或者也遇到了类似的问题,欢迎在评论区交流!👇
Happy coding (and debugging)! 😄