ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

用AI语音合成批量制作有声书:从文本切分到音频合并的完整技术链路

2026/8/30 15:15:48 拓冰建站 浏览量
用AI语音合成批量制作有声书:从文本切分到音频合并的完整技术链路 最近手头接到一个挺有意思的活儿把一卷长篇网文变成有声书。标题是《只剩半年性命绝境觉醒杀兽夺寿系统陆子放弃武考奔赴前线斩杀焚天豹、暗天魔龙累积数千载寿命一路升官成为人族最年轻元帅》。这种爽文长篇有个典型特点——章节多、文本长、战斗描写密集、人名和技能名反复出现。如果靠真人录音几十个小时的干音加上后期修音成本非常高。但如果走 AI 语音合成TTS路线整个生产流程可以拆成几个非常明确的技术环节。这篇文章不推荐任何盗版抓取工具也不讨论拿别人配音去克隆的灰色玩法。我们只聊一条合法、可控、可落地的有声书制作技术链路TTS 工具选型、长文本切分、批量生成、接口调用、音频后处理、资源占用与排错。你不需要懂深度学习只要会 Python 基础、能跑命令行就能把一段小说文本变成分章节的音频文件。先说重点这类任务能不能用普通电脑跑能。4G 显存或纯 CPU 都可以跑但效果和速度差异很大。TTS 模型大致分为两类一类是云端 API比如各类大厂语音合成接口延迟低、稳定性好但按字符收费另一类是本地开源 TTS可以免费跑、可以做声音克隆、可以批量处理但需要自己解决显存、依赖和模型文件问题。如果你只是想快速把文本变成音频先试云端 API。如果你要批量生产、要固定音色、要做长篇小说本地部署是更合适的方向。下面我会从核心能力、环境准备、部署启动、长文本切分、API 调用、性能观察、常见问题一条龙展开最后给出一套适合小说改有声书的批量生产工作流。1. 核心能力速览能力项说明任务类型长文本转语音、有声书制作、批量音频生成主要技术TTS 文本合成、文本切分、音频后处理常见开源方案GPT-SoVITS、CosyVoice、Fish Speech、Edge TTS 开源封装等硬件要求CPU 可跑GPU 推荐 4G 以上显存具体按模型版本确定启动方式命令行启动 / WebUI 启动 / API 服务是否支持 API支持大部分本地 TTS 项目会暴露 HTTP 接口是否支持批量原生支持度不同可通过脚本实现批量队列适合场景自媒体音频、个人有声书项目、播客、有声内容批量生产限制提醒必须使用有版权授权的文本素材克隆音色需获得本人明确授权这张表里没有写死显存占用因为不同模型、不同采样率、不同文本长度差异很大。比如单句短文本生成和整段 500 字长文本生成显存消耗完全不是一个量级。要看真实占用建议用nvidia-smi或任务管理器观察不能只看模型发布页的推荐配置。2. 适用场景与使用边界2.1 适合谁用有声书制作人自己持有版权或获得授权的文本需要批量生成整本小说音频。自媒体创作者要把长文章变成音频版本方便用户在不同场景收听。技术开发者想对接 TTS 接口把语音合成能力集成到自己的 CMS、阅读器或视频剪辑流程里。音频后期人员需要快速生成临时参考音频再决定是否需要真人录音。2.2 能解决什么问题大幅降低有声书生产成本尤其是长文本、多章节内容。保持音色统一。选一个固定参考音色之后所有章节都按同一音色生成。支持重新生成。某一段读错、停顿不对可以只重跑一小段不用整章重录。支持批量任务。把几十章小说文本扔进队列睡觉前开始跑第二天收音频。2.3 不适合什么场景需要真人情感演绎的高质量广播剧AI 合成目前还很难替代专业配音演员。文本内容版权不明、涉及侵权风险的项目不建议做。需要大规模并发、毫秒级响应的生产环境本地开源 TTS 的并发能力通常不如云 API。2.4 版权、隐私与安全边界无论使用云端 TTS 还是本地部署都必须强调几个底线合成小说音频时要先确认文本版权。自己写的小说、已获授权的稿件、公有领域文本都是可以的直接拿未授权网站内容做商业有声书风险很高。使用声音克隆功能时必须获得被克隆人本人的明确授权。拿别人的演唱、配音、直播录音去克隆并公开发布涉嫌侵犯声音权益。本地 TTS 服务不要直接暴露到公网。默认监听127.0.0.1就好避免被外部调用消耗资源。含敏感词或违规内容的文本即使技术上能合成也不能发布。3. 有声书项目环境准备不管用哪个 TTS 项目前置环境基本一致。3.1 硬件清单CPU建议 4 核以上。CPU 推理速度会慢但能跑。内存16GB 够用长文本批量处理建议 32GB。GPUNVIDIA 显卡优先显存建议 4GB 以上。若只跑 CPU 推理可以不用独显。磁盘模型文件从几百 MB 到十几 GB 不等。音频项目本身也很占空间一本几十万字的小说完整生成音频加起来可能几十 GB需要提前留足空间。3.2 软件环境不同 TTS 项目的依赖不一样但通用检查项是Python 3.10 或 3.11建议使用 Conda 创建独立环境。FFmpeg用于音频合并、裁剪、格式转换。CUDA 和 cuDNN只有用 NVIDIA GPU 推理时才需要。PyTorchGPU 版本需要与 CUDA 版本匹配。3.3 建议的项目目录结构tts_project/ ├── inputs/ # 原始文本按章节拆分的 txt 文件 ├── scripts/ # 切分、调用、合并脚本 ├── models/ # 下载的模型文件 ├── outputs/ # 单段生成结果 └── audio_book/ # 按章节合并后的成品把输入、模型、输出分开是批量生产的第一条工程化原则。后面出问题排查起来会快很多。4. TTS 项目部署与启动方式本地 TTS 项目通常有两种启动方式命令行启动和 WebUI/API 启动。这里以开源 TTS 项目的常见通用流程为例具体命令要以你下载的项目 README 为准。4.1 创建虚拟环境conda create -n tts_env python3.11 conda activate tts_env4.2 安装 PyTorchGPU 环境示例pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu124如果使用 CPU 环境安装 CPU 版即可pip install torch torchvision torchaudio这里不写死具体版本号因为不同 TTS 项目依赖的 PyTorch 版本差异很大。装完可以执行python -c import torch; print(torch.cuda.is_available())如果输出True说明 GPU 可用输出False则需要检查 CUDA 版本或改用 CPU 推理。4.3 安装项目依赖把项目克隆到本地进入目录安装依赖git clone https://github.com/example/tts_project.git cd tts_project pip install -r requirements.txt这只是通用模板。实际项目地址、依赖列表需要替换成具体仓库内容。4.4 启动 WebUI很多 TTS 项目会提供 Web 界面方便上传参考音频、输入文本、调节语速和情感。python webui.py --host 127.0.0.1 --port 7860启动成功后浏览器打开http://127.0.0.1:7860即可测试。注意默认端口可能被占用如果启动时报端口冲突换个端口python webui.py --host 127.0.0.1 --port 78614.5 启动 API 服务需要批量调用时一般会以 API 方式启动python api.py --host 127.0.0.1 --port 9880启动后可以先访问http://127.0.0.1:9880/docs查看接口文档。大部分项目基于 FastAPI 构建Swagger 文档里能直接调接口。5. 长文本有声书处理流程TTS 模型通常不能一次处理几万字。实际做整本小说时要先做文本预处理和切分再分批调用生成。5.1 文本清洗与分章小说原始文本经常带有很多无关内容章节标题、作者的话、段落空行、特殊符号。需要先清洗再按章节或固定长度切块。推荐思路按章节切割以“第X章”作为分隔标志把整本小说切成多个 txt 文件。按段落切割每个段落单独生成保留更自然的停顿。按字符数切块如果模型有最大输入长度限制通常按 200 到 500 字切块避免截断。5.2 用 Python 脚本切分长文本下面是一个通用切分脚本把一个大 txt 按章节切成多个文件import re import os from pathlib import Path input_file raw_novel.txt output_dir Path(inputs/chapters) output_dir.mkdir(parentsTrue, exist_okTrue) with open(input_file, r, encodingutf-8) as f: content f.read() # 按“第X章”切分 parts re.split(r(第[一二三四五六七八九十百千0-9]章), content) # parts 是交替出现的标题和正文 for i in range(1, len(parts), 2): title parts[i].strip() body parts[i 1].strip() if i 1 len(parts) else if not body: continue safe_title f{i // 2 1:04d}_{title} out_path output_dir / f{safe_title}.txt out_path.write_text(f{title}\n{body}, encodingutf-8) print(f写入: {out_path})这个脚本假设所有章节都是用“第X章”开头。如果你的文本用“第X回”“Chapter X”就改一下正则表达式。5.3 分段生成音频分章之后每一章仍可能有几千字。建议进一步把每章拆成 200 到 300 字的小块逐块调用 TTS再把小段音频按顺序合并成整章。from pathlib import Path def split_text(text, max_len250): 按标点切分尽量保持句子完整。 chunks [] current for char in text: current char if char in 。 and len(current) max_len / 2: chunks.append(current) current if current: chunks.append(current) return chunks chapter_path Path(inputs/chapters/0001_第一章 觉醒.txt) text chapter_path.read_text(encodingutf-8) for idx, chunk in enumerate(split_text(text)): print(f第 {idx} 段长度 {len(chunk)} 字)这里不把 TTS 合成代码写死因为不同项目的 API 参数名差异很大。你真正要做的是先跑通一个最小样本确认接口能返回音频再写循环批量处理。6. 接口 API 调用与批量任务6.1 通用请求格式本地 TTS 项目大多会暴露一个 POST 接口传入文本和参考音频路径返回音频文件。下面是一个“理论模板”真正的接口路径和字段要以你部署的项目文档为准curl -X POST http://127.0.0.1:9880/tts \ -H Content-Type: application/json \ -d { text: 陆子抬头看向焚天豹眼神中没有半点退缩。, speaker_wav: reference.wav, language: zh } \ --output output.wav接口返回的是 wav 文件时直接保存即可。字段名text、speaker_wav、language是常见命名但不同项目可能用ref_audio、prompt_text等必须按实际文档调整。6.2 用 Python 调用很多 TTS 项目兼容 OpenAI 格式的接口也可以用 requests 写通用调用import requests url http://127.0.0.1:9880/tts payload { text: 他挥刀斩下焚天豹的咆哮声戛然而止。, speaker_wav: voice_ref.wav, language: zh } resp requests.post(url, jsonpayload, timeout120) if resp.status_code 200: with open(output_001.wav, wb) as f: f.write(resp.content) print(生成成功) else: print(生成失败, resp.status_code, resp.text)如果项目返回的是 JSON 而不是音频流可能字段里包含audio的 base64 编码需要额外解码。6.3 批量任务队列批量生成时建议用input/和output/两个目录管理任务并给每段音频命名outputs/0001_第一章_001.wav outputs/0001_第一章_002.wav outputs/0001_第一章_003.wav命名规则建议章节号_小段序号.wav。这样后面合并的时候按文件名排序就不会乱。批量脚本的伪代码import os import requests input_dir inputs/chunks output_dir outputs/chunks os.makedirs(output_dir, exist_okTrue) for txt_file in sorted(os.listdir(input_dir)): if not txt_file.endswith(.txt): continue text open(os.path.join(input_dir, txt_file), encodingutf-8).read() out_name txt_file.replace(.txt, .wav) out_path os.path.join(output_dir, out_name) # 判断是否已生成避免重复调用 if os.path.exists(out_path): print(跳过已存在:, out_path) continue resp requests.post(http://127.0.0.1:9880/tts, json{ text: text, speaker_wav: reference.wav, language: zh }, timeout120) if resp.status_code 200: with open(out_path, wb) as f: f.write(resp.content) print(完成:, out_path) else: print(失败:, txt_file, resp.status_code, resp.text)批量任务的关键不是“一次把全部文本跑完”而是要支持断点续跑。已经生成的 wav 就跳过这样中途崩了、显存爆了、API 超时了恢复后不会从头再来。7. 音频后处理与章节合并TTS 逐段生成后不能直接拿去发布。还需要做几个后处理步骤。7.1 检查空段与静音有些段落可能生成失败输出是空文件或全是静音。用 FFmpeg 快速检查ffmpeg -i output_001.wav -af volumedetect -f null -看输出里的mean_volume和max_volume。如果mean_volume在 -50dB 以下基本可以判断是空音频或静音需要重新生成。7.2 响度统一不同段落生成时音量可能不一致。用 FFmpeg 做响度归一化ffmpeg -i input.wav -af loudnormI-16:TP-1.5:LRA11 output_normalized.wavI-16是目标响度适合网络播放。具体目标值可以按发布平台要求调整。7.3 合并整章音频把某一章的多个小段按顺序拼成一个完整章节ffmpeg -f concat -safe 0 -i filelist.txt -c copy chapter_0001.wavfilelist.txt里每行写一个 wav 路径file outputs/0001_第一章_001.wav file outputs/0001_第一章_002.wav file outputs/0001_第一章_003.wav注意TTS 生成文件如果是同参数、同采样率-c copy可以无损合并如果采样率不一致需要先统一转成 44100Hz 或 48000Hz再合并。7.4 分章压缩为 MP3小说音频按章发布时MP3 格式更通用ffmpeg -i chapter_0001.wav -codec:a libmp3lame -qscale:a 2 chapter_0001.mp3-qscale:a 2大约对应 192kbps音质和体积比较平衡。如果要更小体积可以改-b:a 128k。8. 资源占用与性能观察8.1 如何观察显存运行 TTS 服务时另开一个终端实时查看显存nvidia-smi -l 2-l 2表示每 2 秒刷新一次。主要看内存占用最高的 Python 进程确认是不是自己的 TTS 服务。8.2 CPU 与 GPU 差异本地 TTS 在无独显环境下也能跑但速度差距明显。CPU 推理适合小段文本、低并发、时间不敏感的场景GPU 推理适合整批量生产。具体提速多少取决于模型大小和显卡算力不做“跑多快”的绝对化断言。8.3 影响性能的因素文本长度单次输入越长合成耗时和显存占用越高。采样率44100Hz 比 22050Hz 生成的文件更大计算量也更高。批量并发本地服务如果同时提交太多请求可能直接显存溢出。参考音频长度部分声音克隆模型每次会加载参考音频参考音频越长初始化越慢。音频格式直接输出 wav 比 mp3 省一次转码时间但文件体积更大。8.4 降低占用与提升稳定性的思路单次输入不要拉满模型上限建议从 200 字起步测试。批量脚本里控制并发数比如每次只排队 1 个请求。模型推理完成后及时释放显存。很多项目在生成长音频后会缓存可以定期重启服务。如果端口卡死直接杀掉残留进程ps aux | grep python kill -9 pidWindows 环境可以用任务管理器结束进程或先查找端口占用的 PIDnetstat -ano | findstr 9880 taskkill /PID pid /F9. 常见问题与排查方法问题现象可能原因排查方式解决方案服务启动失败依赖未装全 / Python 版本不匹配看启动日志中的 ImportError 或版本报错按 README 创建新环境重装依赖浏览器打不开 WebUI端口被占用 / 服务没起来看终端日志检查端口监听换端口或重启服务调用 API 返回 404接口路径不对打开 /docs 文档确认路径改用文档中的实际路由生成为空文件文本为空 / 请求超时 / 接口报错查看服务端日志换短文本重试检查文本清洗规则中文读音不对多音字 / 人名未注册人工审查生成文本加注音或使用带正则替换的文本预处理显存不足单次文本过长 / 并发过高用 nvidia-smi 观察减小输入长度降低并发合并后章节顺序错乱文件命名不对排序错误检查文件名编号统一用补零命名如 001、002声音不像参考音频参考音频质量差 / 音色参数不对换干净人声样本测试参考音频控制在 5 到 10 秒去除背景音乐生成速度突然变慢服务运行时间过长内存占用升高观察内存和显存重启 TTS 服务这里的排查方案是通用经验不是具体项目文档。真正遇到问题时第一步永远是看服务端日志日志里最常见的就是缺依赖、缺模型文件、显存不足三类错误。10. 最佳实践与有声书批量生产建议10.1 从一小段开始验证不要一上来就把整本小说丢给 TTS。先选一段 50 到 100 字的文本跑通“文本输入 - 音频输出 - 播放正常”之后再扩大规模。10.2 保存一份最小可运行配置把环境依赖版本、启动命令、参考音频路径、参数配置都记录下来。换电脑或重新部署时这一份配置能省大量时间。10.3 文本预处理决定上限TTS 读错字、断句奇怪很多时候不是模型问题而是文本没清洗干净。数字、英文、单位、多音字、专有名词都需要做预处理把“陆子”这种主角名统一成同一种写法。用正则把“斩杀焚天豹”中的数字、标点统一格式。生僻词、多音字可以用正则替换成同音纠正后测试。比如“觉”字在“觉醒”和“睡觉”里读音不同。文本里如果需要强调可以提前做替换处理text text.replace(绝境觉醒, 绝境jue醒)不过这种粗暴方式会改变原始文本后续合成时可能引入奇怪效果建议只处理高频读错的词。10.4 批量任务必须做日志和断点批量生成过程中要在脚本里记录每段结果with open(generation_log.txt, a, encodingutf-8) as log: log.write(f{txt_file}: SUCCESS\n)已成功生成的音频跳过失败的重试。这能让几十小时的任务在崩溃后快速恢复。10.5 接口服务不暴露公网本地 API 只监听127.0.0.1不要在云服务器上开放未授权端口。如果确实需要远程调用加访问令牌和限流避免被刷。10.6 发布前做人工复核AI 生成的有声书可以直接发布吗从技术上说可以从质量上说建议至少抽查 20% 的章节。重点听人名是否统一、情感是否平淡、长句是否吃字、末尾是否有爆音。长篇作品发布后发现问题再修改成本会很高。11. 后续可以扩展的方向跑通基础流程后可以继续做几件事。第一把“文本切分 - 批量调用 - 音频合并 - 响度统一”固化成一个 CLI 工具以后出有声书只需要两步放文本、跑脚本。第二接入字幕对齐或进度标记功能让听书软件能显示当前章节段落。第三加入多角色 TTS。小说里男主角、妖兽、老者如果都用一个音色会很单调可以用多参考音色分别生成不同角色的台词再剪辑合成。第四如果对声音质量有更高要求可以在 TTS 之后接入降噪和混响处理让声音更像录音棚效果。对于《只剩半年性命绝境觉醒杀兽夺寿系统》这类动辄几十万字的爽文最合理的生产路径是先做第一章全流程测试确认文本清洗、TTS 发声质量、合并结果都满意后再利用夜间批量跑完剩余章节。第一批跑完试听第二批看是否稳定第三批再跑完整本。批量任务最忌讳一口气全做既容易爆显存也容易在后期发现音色不对时全部返工。最后提醒一句技术能解决“怎么生成”解决不了“能不能生成”。文本版权、音色授权、平台发布规则这些边界问题一定要在开工前确认清楚。拿授权素材、用授权音色、在合理范围内测试这套流程才真正有长期价值。