最近整理了一个自用的小工具,用来把整理好的 .txt 文本批量转换成语音音频、SRT/VTT 字幕以及供前端使用的结构化数据。
整个工具不依赖任何付费 API,完全在本地运行,生成结果可以直接用于博客、网页播放器、视频剪辑或播客制作。这篇文章做一个完整记录。
工具能做什么
一句话概括:输入一段文本,输出一个完整的”音频 + 字幕 + 时间轴”数据包。
具体输出内容包括:
audio.mp3—— 完整朗读音频subtitle.srt—— 标准 SRT 字幕subtitle.vtt—— 网页可用的 WebVTT 字幕dialog.json—— 逐句结构化数据,含开始/结束时间markers.json—— 章节时间标记origin.txt—— 处理后的原始文本
这些文件配合使用,可以做出:逐句高亮播放、聊天气泡对话展示、带章节目录的网页音频播放器等效果。
项目结构
AI_Read/
├── input/
│ ├── oldcalendar/ # 对话类内容(多角色)
│ └── whiteartical/ # 文章类内容(单人朗读)
├── output/ # 生成结果
├── cache/ # TTS 语音缓存
├── batch_tts.py # 对话模式处理脚本
├── batch_tts_single.py # 文章模式处理脚本
└── sentence_splitter.py # 分句逻辑
目前处理两类内容:
- oldcalendar:偏对话格式,支持 A/B 双角色,各自使用不同音色
- whiteartical:偏长文朗读,单一音色,支持章节标记
核心功能详解
一、自动分句
文本直接送入 TTS 效果通常很差——句子太长语调会拖沓,太短又显得机械。因此专门做了一个分句模块。
当前分句逻辑:
- 在
。!?;,等标点处切分,标点保留在前一句末尾 - 切分时吞掉尾随的闭合符号,如
"》」 - 过滤空片段和纯标点,避免单独的
。进入 TTS 导致报错 - 数字中的逗号和小数点不会被误切,如
1,234.56 - 超长句兜底按最大字数强制切断
示例:
输入:更多解释:这是一个测试句子。后面还有内容。
输出:
更多解释:这是一个测试句子。
后面还有内容。
输入:价格是1,234.56元,对吧?
输出:
价格是1,234.56元,对吧? ← 数字完整保留,不会被逗号拆开
二、多角色 TTS 生成
工具使用 edge-tts 调用微软 Azure TTS,免费且音质出色。
文章朗读模式使用固定音色:
VOICE = "zh-CN-YunyangNeural"
RATE = "+10%"
对话模式支持角色映射,不同角色自动使用不同音色:
VOICE_MAP = {
"A": {"voice": "zh-CN-XiaoxiaoNeural", "rate": "+10%"},
"B": {"voice": "zh-CN-YunyangNeural", "rate": "+10%"},
}
文本文件中只需这样写:
A: 你好,今天天气怎么样?
B: 还不错,阳光很好。
运行后 A 和 B 会自动使用各自的音色朗读,生成的音频听起来有对话感。并发数量可配置,默认 4 线程同时生成:
MAX_WORKERS = 4
三、缓存机制
每条语音片段生成后,都会以 voice|rate|text 的哈希值作为文件名缓存到 cache/ 目录。再次运行时,只要文本、音色、语速完全一致,就直接复用缓存,不会重复请求 TTS。
运行日志示例:
⚡ 缓存命中: 230, 未命中: 0
这对反复调整分句参数或修改少量文本非常友好——改了一句话只需重新生成那几个片段,其余全部复用缓存,耗时极短。
四、音频拼接
每句文本独立生成一个临时 mp3 片段,最终用 pydub 顺序拼接成完整音频。片段之间加入 50 毫秒静音间隔,让朗读不会完全粘连,听感更自然。
五、字幕同步
字幕的时间轴直接来自音频片段的实际时长,因此字幕与音频天然同步,无需手动校对时间。同时输出两种格式:
subtitle.srt:适用于视频剪辑软件(Premiere、剪映等)和播放器subtitle.vtt:适用于 HTML5 网页播放器
六、dialog.json
这是给前端使用的逐句数据,结构如下:
[
{
"text": "这是一句字幕内容",
"start": 1200,
"end": 3600,
"line_start": true,
"line_end": false
}
]
line_start 和 line_end 标记了该句是否是原文一行的起始或结尾,方便前端按段落做高亮效果。
对话模式的 JSON 还额外包含角色和方向信息:
{
"role": "A",
"side": "left",
"text": "你好,今天天气怎么样?",
"start": 800,
"end": 2400
}
可以直接用来实现类似微信聊天气泡的对话播放效果。
七、章节时间标记
文章模式支持在文本中插入 $$$ 作为章节分隔符:
第一章内容……
$$$
第二章内容……
生成后会输出 markers.json:
[
{"index": 1, "time": 0},
{"index": 2, "time": 45320}
]
time 是该章节在音频中的毫秒时间点,可用于网页播放器章节跳转、视频时间轴标注、文章阅读进度同步等场景。
运行效果
$ python batch_tts_single.py
📚 共发现 1 个文本文件
🎯 正在处理: 05_04.txt
🧩 共 228 条任务
🎤 TTS 合成: 100%|██████████| 228/228
🎧 拼接音频...
🎶 拼接进度: 100%|██████████| 243/243
⚡ 缓存命中: 215, 未命中: 13
📍 时间节点: 13
✅ 完成: output/whiteartical/2026/05_04
输出目录:
output/whiteartical/2026/05_04/
├── audio.mp3
├── subtitle.srt
├── subtitle.vtt
├── dialog.json
├── markers.json
└── origin.txt
依赖
edge-tts
pydub
ffmpeg
regex
tqdm
小结
这套工具的核心价值在于:不只是生成一段音频,而是同时生成配套的字幕、时间轴和结构化 JSON,后续对接任何展示场景都比较方便。
目前已经在稳定使用,后续计划继续扩展:
- WordPress 短代码嵌入播放器
- 逐句高亮朗读网页组件
- 自动批量上传到媒体库
- 多音色快速切换配置
如果你也在做类似的中文语音内容,欢迎交流。