智能小说有声化引擎 — 将长篇小说 TXT 自动转换为高质量音频。
读取长篇小说文本,经过智能切分后调用 TTS 引擎逐段合成语音,最终拼接导出为完整的有声读物。支持云端 API 与本地模型两种模式,提供 CLI 命令行、REST API 和 Web 界面三种使用方式。
NovelCast/
├── pyproject.toml # 依赖管理与构建配置
├── start.py # Web 服务启动脚本
├── .env.example # 环境变量模板
├── .gitignore
├── README.md
├── novelcast/
│ ├── __init__.py # 包版本定义
│ ├── config.py # 配置管理 (Pydantic BaseSettings)
│ ├── tts_engine.py # TTS 引擎策略: 抽象基类 + 各厂商实现
│ ├── text_processor.py # 文本清洗与智能切分
│ ├── schemas.py # API 请求/响应 Pydantic 模型
│ ├── api.py # FastAPI REST API 路由
│ └── main.py # CLI 入口 & 任务调度
├── frontend/
│ └── index.html # Web 界面 (单文件 SPA,无需构建)
├── data/input/ # 放置待处理的小说 TXT 文件
└── output/ # 生成的音频文件输出目录
- Python 3.11+
- FFmpeg(pydub 依赖,用于音频拼接与格式转换)
- Windows: 从 FFmpeg 官网 下载,将
bin目录加入 PATH - macOS:
brew install ffmpeg - Linux:
apt install ffmpeg或yum install ffmpeg
- Windows: 从 FFmpeg 官网 下载,将
# 克隆项目
git clone <repo-url> && cd NovelCast
# 安装依赖(推荐在虚拟环境中)
pip install -e .
# 如需本地离线合成(pyttsx3),安装可选依赖
pip install -e ".[local]"
# 开发依赖(测试 + lint)
pip install -e ".[dev]"复制 .env.example 为 .env,填入你的 API 密钥:
cp .env.example .env| 变量 | 说明 | 默认值 |
|---|---|---|
TTS_MODE |
引擎模式:api(云端)或 local(本地) |
api |
MIMO_API_KEY |
小米 MiMo API 密钥 | - |
MIMO_BASE_URL |
小米 MiMo API 地址 | https://api.xiaomimimo.com/v1 |
MIMO_MODEL |
小米模型 ID | mimo-v2.5-tts |
VOLC_APP_ID |
火山引擎应用 ID | - |
VOLC_ACCESS_TOKEN |
火山引擎访问令牌 | - |
BAIDU_API_KEY |
百度智能云 API Key | - |
BAIDU_SECRET_KEY |
百度智能云 Secret Key | - |
OUTPUT_SAMPLE_RATE |
输出音频采样率 (Hz) | 24000 |
OUTPUT_FORMAT |
输出格式:mp3 / wav / ogg |
mp3 |
# 启动后端 + 前端 (默认 http://127.0.0.1:9854)
python start.py
# 仅启动后端 API (不挂载前端)
python start.py --backend-only
# 指定端口和监听地址
python start.py --host 0.0.0.0 --port 9854
# 开发模式 (热重载)
python start.py --reload启动后访问:
- Web 界面:
http://localhost:9854 - API 文档 (Swagger):
http://localhost:9854/docs
# 使用小米 MiMo TTS(默认厂商)
python -m novelcast.main data/input/我的小说.txt
# 指定中文女声 "冰糖"
python -m novelcast.main data/input/小说.txt -p xiaomi -v 冰糖
# 使用百度 TTS
python -m novelcast.main data/input/小说.txt -p baidu -v 0
# 使用火山引擎 TTS
python -m novelcast.main data/input/小说.txt -p volc
# 本地离线模式(需安装 pyttsx3)
TTS_MODE=local python -m novelcast.main data/input/小说.txt
# 指定输出文件名 + 开启调试日志
python -m novelcast.main data/input/小说.txt -o 我的有声书 --verbose| 参数 | 说明 |
|---|---|
input |
小说 TXT 文件路径(必填) |
-p, --provider |
云端服务商:xiaomi(默认)/ volc / baidu |
-v, --voice |
音色 ID |
-o, --output |
输出文件名(不含扩展名) |
--verbose |
显示调试级别日志 |
以 HTTP 请求调用后端接口,适合集成到其他系统。
# 查看可用引擎
curl http://localhost:9854/api/engines
# 查看小米引擎的音色列表
curl http://localhost:9854/api/voices?engine=xiaomi
# 合成音频并保存
curl -X POST http://localhost:9854/api/synthesize \
-H "Content-Type: application/json" \
-d '{"text":"天色渐暗,远山隐没在暮霭之中。","engine":"xiaomi","voice":"冰糖","format":"mp3"}' \
-o output.mp3| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/health |
健康检查 |
| GET | /api/engines |
返回可用引擎列表 |
| GET | /api/voices?engine=xiaomi |
返回指定引擎的音色列表 |
| GET | /api/models |
返回支持的模型列表 |
| POST | /api/synthesize |
TTS 合成,返回完整音频文件 |
| GET | /api/synthesize/stream |
流式合成,逐片推送 PCM16 音频 |
{
"text": "要合成的文本内容",
"engine": "xiaomi",
"voice": "冰糖",
"model": "mimo-v2.5-tts",
"format": "mp3"
}| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
text |
string | 是 | 待合成文本 (1~50000 字) |
engine |
string | 否 | 引擎:xiaomi / volc / baidu / local,默认 xiaomi |
voice |
string | 否 | 音色 ID,留空使用引擎默认 |
model |
string | 否 | 模型 ID,部分引擎支持 |
format |
string | 否 | 输出格式:mp3 / wav,默认 mp3 |
逐片推送 PCM16 音频数据(24kHz, mono, little-endian),适合实时播放场景。
# 流式合成并保存为原始 PCM
curl "http://localhost:9854/api/synthesize/stream?text=第一句。第二句。第三句。&engine=xiaomi&voice=冰糖" \
-o output.pcm
# 用 ffplay 播放
ffplay -f s16le -ar 24000 -ac 1 output.pcm| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
text |
string | 是 | 待合成文本 |
engine |
string | 否 | 引擎,默认 xiaomi |
voice |
string | 否 | 音色 ID |
响应头:Content-Type: audio/L16; rate=24000; channels=1
Web 界面已内置流式播放支持,勾选「流式播放」后点击合成即可边合成边播放。
from novelcast.main import process_novel
output = process_novel(
input_path="data/input/小说.txt",
voice_id="冰糖",
provider="xiaomi",
output_name="我的有声书",
)
print(f"输出文件: {output}")| 引擎 | Provider | 说明 |
|---|---|---|
| 小米 MiMo | xiaomi |
MiMo-V2.5-TTS 系列,支持预置音色 / 音色设计 / 音色复刻 |
| 火山引擎 | volc |
字节跳动语音合成服务 |
| 百度智能云 | baidu |
百度语音合成服务 |
| MeloTTS | melo |
轻量离线 TTS (VITS),支持 CPU 运行 |
| CosyVoice | cosyvoice |
阿里高保真离线 TTS,需 GPU |
| 本地 Mock | local |
pyttsx3 离线合成(未安装时生成静音用于测试) |
| 音色名 | 语言 | 性别 |
|---|---|---|
| mimo_default | 中文 | 女性(冰糖) |
| 冰糖 | 中文 | 女性 |
| 茉莉 | 中文 | 女性 |
| 苏打 | 中文 | 男性 |
| 白桦 | 中文 | 男性 |
| Mia | 英文 | 女性 |
| Chloe | 英文 | 女性 |
| Milo | 英文 | 男性 |
| Dean | 英文 | 男性 |
小米 MiMo 还支持 mimo-v2.5-tts-voicedesign(文本描述设计音色)和 mimo-v2.5-tts-voiceclone(音频样本复刻音色),在 .env 中修改 MIMO_MODEL 即可切换。
┌─────────────────────────────────┐
│ start.py │
│ 启动脚本 (组合 or 独立) │
└──────┬──────────────┬───────────┘
│ │
┌────────────▼───┐ ┌──────▼──────────┐
│ frontend/ │ │ novelcast/api │
│ index.html │ │ FastAPI 路由 │
│ (Web UI) │ └──────┬──────────┘
└────────────────┘ │
┌──────────────┼──────────────┐
▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐
│TextProcessor│ │ AppConfig │ │ tts_engine │
│ 清洗 + 切分 │ │ .env 加载 │ │ 策略引擎 │
└─────┬──────┘ └─────┬──────┘ └─────┬──────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────┐
│ BaseTTSEngine (ABC) │
│ synthesize(text, voice) │
└──────┬──────────┬──────────┬───────────┘
▼ ▼ ▼ ▼
Xiaomi OnlineApi LocalModel
Engine Engine Engine
(小米) (火山/百度) (Mock)
│ │ │
▼ ▼ ▼
AudioSegment ──► 拼接 ──► MP3/WAV
核心设计采用策略模式:BaseTTSEngine 抽象基类定义统一接口 synthesize(text, voice_id) -> AudioSegment,各厂商引擎作为派生类实现具体调用逻辑。工厂函数 create_engine() 根据配置自动选择引擎实例。
- 在
tts_engine.py中新建类,继承BaseTTSEngine - 实现
synthesize(self, text: str, voice_id: str) -> AudioSegment方法 - 在
config.py中添加对应的配置类(如需 API 密钥等) - 在
create_engine()工厂函数中注册新 provider - 在
main.py的 CLI 参数choices和api.py的ENGINES/_VOICES_BY_ENGINE中添加数据 - 在
schemas.py中补充音色/模型定义(如适用)
LocalModelEngine 目前为 Mock 实现。要接入 Coqui TTS、IndexTTS2 等开源模型,替换 _synthesize_mock 方法即可,在 synthesize 中调用模型推理并将输出转为 AudioSegment。
- 不要将
.env文件提交到版本控制,.gitignore已配置忽略该文件 - 首次使用时:
cp .env.example .env,然后填入你的 API 密钥 - 如果意外泄露了密钥,请立即在对应平台重新生成