# TTS Studio 项目说明 免费、纯本地运行的文本转语音工坊。零 API 费用、无云端上传,支持三种引擎与**用自己的声音说话**。 已在 Apple M1 / 8GB / macOS / Python 3.12 实测通过。 > 本文档所有截图均为真实运行界面直接截取(非示意图),数据来自本机实测。 ## 目录 - [1. 它能做什么](#1-它能做什么) - [2. 界面导览](#2-界面导览) - [3. 引擎对比](#3-引擎对比) - [4. 快捷开始](#4-快捷开始) - [5. 从零安装](#5-从零安装) - [6. 合成:文本转语音](#6-合成文本转语音) - [7. 我的声音:零样本克隆](#7-我的声音零样本克隆) - [8. 文档转语音](#8-文档转语音) - [9. 音色库](#9-音色库) - [10. 架构与目录](#10-架构与目录) - [11. 内存与性能设计](#11-内存与性能设计) - [12. VSCode 调试](#12-vscode-调试) - [13. 常见问题](#13-常见问题) - [14. 合规与免责](#14-合规与免责) --- ## 1. 它能做什么 | 能力 | 说明 | 是否需要联网 | |---|---|---| | 文本转语音 | 短文本即时合成,支持语速、音调 | edge 需要,本地引擎不需要 | | 文档转语音 | Markdown / TXT / 网页链接 → 单个长音频 | 仅抓取网页时需要 | | 音色混合 | 两个 Kokoro 音色的风格向量加权插值 | 否 | | 声音克隆 | 3-10 秒本人录音 → 合成任意文本 | 否 | | 音色库 | 保存、复用自定义音色配方 | 否 | 一句话定位:**不给 API 付费,也能有一把自己的声音。** ## 2. 界面导览 四个标签页对应四条工作流。 ### 2.1 合成 ![合成页](images/ui-synthesize.png) 左侧输入文本,右侧选引擎 / 音色 / 语速 / 音调,点「生成音频」。 底部「保存为自定义音色」可把当前配置存进音色库。 ### 2.2 合成结果 ![合成结果](images/ui-result.png) 状态栏会给出引擎、实际使用的音色、字数与耗时。上图为 edge-tts 合成 34 字文本,耗时 2.3s,产出 8 秒音频。 ### 2.3 Kokoro 音色混合 切到 Kokoro 后会出现混合面板: ![音色混合](images/ui-kokoro-mix.png) 勾选「启用音色混合」→ 选音色 B → 拖「A 权重」。 `A 权重 = 1` 等价纯 A,`= 0` 等价纯 B,中间值是两个音色风格向量的线性插值。 > 跨语言混合会被自动忽略并在状态栏提示,因为不同语言的风格向量语义不对应,混合结果无意义。 ### 2.4 文档转语音 ![文档转语音](images/ui-document.png) 三种输入任选其一:上传文件、填写链接后点「抓取」、直接粘贴 Markdown。 建议先点「预览朗读文本」确认清洗结果,再点「开始转换」。 ### 2.5 我的声音 ![我的声音](images/ui-clone.png) 录制或上传 3-10 秒人声 → 命名保存 → 试听克隆 → 去合成页使用。 页面顶部会直接提示克隆链路是否就绪。 ### 2.6 音色库 ![音色库](images/ui-library.png) 已保存的音色配方(如 `zf_xiaoxiao:0.60,zm_yunxi:0.40`)可直接试听。 「引擎」选 `自动` 时会根据音色表达式自动推断该用哪个引擎。 ## 3. 引擎对比 | 引擎 | 类型 | 体积 | 自定义音色方式 | 协议 | |---|---|---|---|---| | edge-tts | 在线 | ~5MB | 400+ 预置音色 + 语速/音调 | 非官方接口 | | Kokoro-82M | 本地 | 327MB | 内置音色向量**加权插值混合** | Apache-2.0 | | CosyVoice2-0.5B | 本地 | ~2GB | 3-10s 参考音频**零样本克隆** | Apache-2.0 | ### 语言支持 | 引擎 | 中文 | 英文 | |---|---|---| | edge-tts | 14 音色 | 47 音色(US/UK/AU/CA/IN…) | | Kokoro | 8 音色 | 12 音色(US 8 / UK 4) | | CosyVoice2 | 支持 | 支持 | Kokoro 按音色前缀自动路由语言模型: | 前缀 | 语言 | lang_code | 示例 | |---|---|---|---| | `zf_` / `zm_` | 中文 | z | zf_xiaoxiao | | `af_` / `am_` | 美式英语 | a | af_heart | | `bf_` / `bm_` | 英式英语 | b | bf_emma | ### 实测性能 | 项目 | 结果 | |---|---| | edge-tts 音色数 | 322 个(中文 14 个) | | edge-tts 合成 | 16 字 → 1.3s | | Kokoro 模型加载 | 7.8s | | Kokoro 单音色 | 3.85s 音频 → 6.0s(首次含初始化) | | Kokoro 混合音色 | 4.70s 音频 → 2.4s | | 文档转语音 | 10 段 / 1.3 分钟音频 → 14-15s | | 磁盘占用 | Kokoro 327MB + 依赖约 1.5GB;克隆另需约 2GB | ## 4. 快捷开始 ```bash ./run.sh # 默认 http://127.0.0.1:7860 ./run.sh --port 8080 ./run.sh --share # 生成公网临时链接 ./run.sh --no-browser ``` `run.sh` 会使用固定虚拟环境 `/Users/xuegangliu/.workbuddy/binaries/python/envs/tts312`, 并预设 `HF_ENDPOINT=https://hf-mirror.com`。 ## 5. 从零安装 ```bash # 必须 Python 3.12(3.13 下 numpy==1.26.4 无 wheel,spacy 链编译失败) /opt/anaconda3/bin/python3.12 -m venv /path/to/venv /path/to/venv/bin/pip install -r requirements.txt # 中文以外还要读英文时,手动装 spacy 英文模型(约 12MB,不在 PyPI) curl -L -o /tmp/en_core_web_sm-3.8.0-py3-none-any.whl \ "https://ghfast.top/https://github.com/explosion/spacy-models/releases/download/en_core_web_sm-3.8.0/en_core_web_sm-3.8.0-py3-none-any.whl" /path/to/venv/bin/pip install --no-deps /tmp/en_core_web_sm-3.8.0-py3-none-any.whl ``` `requirements.txt` 头部写明了版本钉死的坑位原因,改动前请先读。 ### 克隆功能额外准备 ```bash python scripts/download_cosyvoice.py # 代码 + 2GB 权重 + 依赖检查 python scripts/download_cosyvoice.py --code-only python scripts/download_cosyvoice.py --weights-only ``` 产物:`models/CosyVoice/`(推理代码 + Matcha-TTS)与 `models/CosyVoice2-0.5B/`(权重)。 ## 6. 合成:文本转语音 基本流程见 [2.1](#21-合成)。要点: - **长文本自动分段**:按标点断句,`max_chars` 上限内合并,减少请求次数。 - **音调仅 edge 支持**:切换到 Kokoro / CosyVoice2 时该滑块自动隐藏。 - **保存音色**:把当前引擎 + 音色表达式(含混合配方)写入 SQLite,命名后可在音色库复用。 ## 7. 我的声音:零样本克隆 **核心结论:不需要训练。** 3-10 秒清晰人声即可,CosyVoice2 零样本推理直接迁移音色。 ### 7.1 三步流程 1. **录**:点麦克风按钮,照着页面上的朗读稿念 5-10 秒;也可以上传已有音频。 2. **存**:填音色名称 → 「保存参考音色」。系统会自动转 16kHz 单声道、峰值归一化, 存到 `voices/refs/<名字>.wav`,同时写入音色库(表达式 `clone:<名字>`)。 3. **用**:点「试听克隆」确认像不像;满意后去「合成」页把引擎切到 **CosyVoice2 · 我的声音**, 选这个音色合成长文本。 ### 7.2 录音要求 | 项 | 建议 | |---|---| | 时长 | 3s 起,推荐 5-10s;超过 20s 自动截断,短于 3s 直接拒绝 | | 环境 | 安静、无背景音乐、无回声(别在空旷房间或浴室录) | | 距离 | 离麦克风约 20cm,避免喷麦和爆音 | | 语速 | 正常自然,别刻意拖长或加重 | | 内容 | 用页面朗读稿即可,覆盖常用音素和语调 | | 格式 | 任意采样率/声道,内部统一 16kHz 单声道 | ### 7.3 效果边界 - **上限由参考音频决定**:参考音频有回声、电流声或情绪夸张,合成结果会一并继承。 - **只迁移音色**:零样本克隆学不到个人口音习惯和独特断句节奏,只迁移音色与大致韵律。 - **情绪控制有限**:想要「播报腔」「闲聊腔」等明显风格差异,靠参考音频的语速情绪来暗示, 或者换不同情绪的参考音频各存一个音色。 - **首次合成慢**:要加载约 2GB 模型,10-30s;之后单句约数百毫秒到数秒(CPU)。 - **空闲自动卸载**:5 分钟不用会释放模型,下次再加载一次。 ### 7.4 想更像自己怎么办 零样本已经是性价比最高的方案。如果确实要更接近: | 路线 | 数据量 | 8GB M1 可行性 | 说明 | |---|---|---|---| | 零样本(当前方案) | 3-10s | 稳 | 立刻能用 | | CosyVoice2 微调 | 10-60 分钟 | 紧张,容易 OOM | 需降 batch、梯度累积 | | GPT-SoVITS 微调 | 1 小时起 | MPS 需改 float32 | 音色相似度更高,权重协议需自查 | ## 8. 文档转语音 支持三种输入: 1. **上传文件** `.md` / `.markdown` / `.txt` 2. **填写链接** → 点「抓取」把内容拉进文本框,可再编辑 3. **直接粘贴** Markdown(只粘一个 URL 也行,会本地识别并抓取) ### 8.1 链接支持范围 | 来源 | 处理 | |---|---| | `raw.githubusercontent.com/*.md` | 直接取原始文本 | | `github.com/u/r/blob/...` | 自动转成 raw 地址 | | `gist.github.com/...` | 自动转成 gist raw | | `gitee.com/u/r/blob/...` | 自动转成 gitee raw | | 普通网页 | BeautifulSoup 去噪取正文 → html2text 转 Markdown | 网页正文提取会移除 `script/style/nav/header/footer/aside` 及导航、侧栏、面包屑、目录等区块, 并优先取 `article` / `role=main` / `main` / `div.body` 容器。 限制:单文件 5MB、超时 20s、仅支持 `http/https`;PDF、图片等非文本类型会明确报错。 ### 8.2 Markdown 清洗规则 | Markdown 元素 | 处理方式 | |---|---| | `#` 标题 | 朗读,前后留 0.6–1.0s | | `**粗**` `*斜*` `~~删~~` | 去标记保留文字 | | `[链接](url)` | 只读链接文字 | | `![图片](src)` | 默认移除 | | 行内 `` `code` `` | 去反引号 | | 代码块 ` ``` ` | 默认跳过(可开启) | | 表格 | 默认跳过(可开启,按「单元格,单元格;」朗读) | | 列表 `-` `*` `1.` | 去符号,停顿 0.28s | | 引用 `>` | 去符号,停顿 0.4s | | 分隔线 `---` | 只留停顿 | | HTML 标签 / 注释 | 移除 | | Frontmatter | 整体移除 | ### 8.3 长文档处理 相邻短块先合并到 `max_chars`(默认 280 字)以内再请求,减少网络往返; 段落静音按块类型区分;整篇通过 `soundfile` **流式写入**单个文件—— 内存占用恒定,长文档不会撑爆 8GB。 实测:示例文档 10 段 → 1.3 分钟音频 / 3.6MB WAV,耗时 14-15s。 单段失败不会中断整篇,状态栏汇总失败段数。 ## 9. 音色库 - 存储:SQLite `voices/voices.db`,表 `voices(id, name, engine, spec, created_at)` - `spec` 即音色表达式,三种形态: - `zh-CN-XiaoxiaoNeural`(edge 预置音色) - `zf_xiaoxiao:0.60,zm_yunxi:0.40`(Kokoro 混合配方) - `clone:我-日常`(CosyVoice2 参考音频) - 引擎选 `自动` 时按 `spec` 前缀推断,无需手动选择。 ## 10. 架构与目录 ``` app/ engines/ base.py TTSEngine 抽象(load/unload/list_voices/synthesize) edge_engine.py edge-tts,异步接口用线程池包成同步 kokoro_engine.py Kokoro-82M,按语音前缀切换 pipeline + 加权混合 cosyvoice_engine.py CosyVoice2 零样本克隆 + 参考音频规范化 voices/store.py 自定义音色持久化(SQLite) registry.py 引擎注册与按需加载(空闲 5 分钟自动卸载) text.py 长文本切分(标点断句,超长串硬切) markdown.py Markdown → 朗读块 fetcher.py URL 抓取(GitHub/Gitee/普通网页) batch.py 文档级合成,流式拼接写盘 ui.py Gradio 界面 main.py argparse + 预热 + 后台卸载线程 scripts/ 冒烟测试 + download_cosyvoice.py models/ CosyVoice 代码与权重 output/ 生成的音频 voices/ voices.db + edge 音色缓存 + refs/ 克隆参考音频 docs/ 本文档与截图 ``` 数据流: ``` UI 输入 → markdown.parse(文档场景)→ Block 列表 → batch.chunk_blocks(合并短块) → registry.get(engine).synthesize(SynthParams, out_path) ├─ edge: edge_tts.Communicate.save ├─ kokoro: pipeline(chunk, voice=混合向量) └─ cosyvoice: inference_zero_shot(chunk, ref_wav) → soundfile 流式写入单个 wav/mp3 ``` ## 11. 内存与性能设计 8GB 统一内存是本项目的硬约束,几处关键设计: | 机制 | 目的 | |---|---| | 引擎空闲 5 分钟自动 `unload()` | 不让模型长期占内存 | | Kokoro 同时只保留一个语言 pipeline | 切换语言重建,避免双份常驻 | | 文档合成流式写盘 | 长音频不驻留内存 | | CosyVoice 首次合成才建模型 | 只打开页面不加载 2GB | | 参考音频按 `(path, mtime)` 缓存 | 同一音色重复合成不重复提取 | ## 12. VSCode 调试 `.vscode/launch.json` 提供 5 个配置: | 名称 | 用途 | |---|---| | TTS Studio (7860) | 默认端口,自动开浏览器 | | TTS Studio (8080) | 换端口 | | TTS Studio (headless) | `--no-browser`,纯调试 | | TTS Studio (share) | `--share` 公网临时链接 | | 当前脚本 | 直接跑当前打开的 `scripts/smoke_*.py` | `.vscode/settings.json` 固定解释器为 tts312 虚拟环境,并把 `models/`、`output/`、 `voices/edge_voices.json` 排除出搜索。 冒烟测试: ```bash python scripts/smoke_kokoro.py # 加载 / 单音色 / 混合音色 python scripts/smoke_doc.py # 文档合成 python scripts/smoke_md.py # Markdown 解析 python scripts/smoke_en.py # 英文合成 ``` ## 13. 常见问题 **Q:启动后点生成,提示模型下载失败?** HuggingFace 直连在国内常被拦截。确认 `HF_ENDPOINT=https://hf-mirror.com` (`run.sh` 已预设),或用环境变量覆盖成自己的镜像。 **Q:英文合成报 spacy 相关错误?** 没装 `en_core_web_sm`。按 [5. 从零安装](#5-从零安装) 手动装一次。 **Q:克隆页提示「缺少 CosyVoice 模型/推理代码」?** 跑 `python scripts/download_cosyvoice.py`。它会分别检查代码和权重两处。 **Q:克隆合成出来的声音发闷 / 有杂音?** 九成是参考音频质量问题。换一段安静环境下、离麦近一点、语速自然的录音重存。 **Q:混合音色没生效?** 两个音色语言必须一致(都 `zf_/zm_` 或都 `af_/am_`)。跨语言会被忽略并在状态栏提示。 **Q:端口 7860 被占用?** `./run.sh --port 8080`。 **Q:升级依赖后 Kokoro 报 `TypeError: ZHG2P`?** `kokoro` 与 `misaki` 必须同版本(0.9.4)。另外 `thinc` 必须是 8.x, 装了 `spacy-curated-transformers` 会把它拉到 9.x。 ## 14. 合规与免责 - **edge-tts 使用微软 Edge 的非官方接口**,仅供个人学习研究,不要用于商业分发。 - **克隆他人声音必须获得本人授权**。「我的声音」页设计给本人音色使用。 - CosyVoice2 与 Kokoro-82M 均为 Apache-2.0;F5-TTS 权重为 CC-BY-NC,本项目未采用。 - 参考音频与生成的语音**全部留在本地**,CosyVoice2 全程离线推理,不上传任何数据。 - 请勿用合成语音实施欺诈、冒充他人或制作虚假内容。