批量生成音频?GLM-TTS的JSONL任务文件这样写
你是否遇到过这样的场景:需要为100条产品介绍、50段课程脚本、30个短视频文案,逐一手动合成语音?每次点选参考音频、粘贴文本、调整参数、等待生成……重复操作几十次,不仅耗时,还极易出错。而GLM-TTS镜像早已内置批量推理能力——关键在于,你写的JSONL任务文件,是否真正“懂它”?
本文不讲模型原理,不堆参数术语,只聚焦一个工程师每天都会面对的真实问题:如何写出稳定、可复用、零报错的JSONL任务文件,让GLM-TTS一次性跑通全部音频生成任务。从字段含义到路径规范,从常见陷阱到调试技巧,全部来自真实批量生产环境中的踩坑总结。
1. 为什么必须用JSONL?不是CSV,也不是Excel
先说结论:JSONL是GLM-TTS批量推理唯一支持的任务格式。它不是为了“显得高级”,而是由底层推理引擎的设计逻辑决定的。
JSONL(JSON Lines)本质是“每行一个独立JSON对象”的纯文本格式。这种结构天然适配批量任务的以下特性:
- 流式读取:程序无需加载整个文件到内存,逐行解析,对千行级任务也极轻量
- 容错性强:某一行JSON语法错误,只影响该行任务,其余任务照常执行(对比CSV单个逗号出错就全盘崩溃)
- 字段灵活:每行可独立增减字段(如部分任务需
prompt_text,部分不需要),无需统一列头 - 与WebUI深度对齐:镜像的批量模块直接映射WebUI表单字段,JSONL结构即界面字段的文本化表达
注意:不要尝试用Excel另存为CSV再改后缀。中文引号、隐藏空格、BOM头、换行符混乱——这些看似微小的问题,90%的批量失败都源于此。
2. JSONL文件的4个核心字段:少一个就报错,多一个就忽略
GLM-TTS批量推理仅识别且仅依赖以下4个字段。其他任何字段(如id、category、timestamp)会被静默忽略,但缺失任一必填字段将直接中断该行任务。
2.1prompt_audio:唯一硬性依赖,路径必须绝对精准
这是整个任务的“音色锚点”。值必须是容器内可访问的绝对路径,且音频文件必须真实存在。
{"prompt_audio": "/root/GLM-TTS/examples/prompt/teacher_male.wav", "input_text": "同学们好,今天我们学习光合作用。"}关键规则:
- ❌ 错误:
"prompt_audio": "teacher_male.wav"(相对路径,程序在/root/GLM-TTS外执行) - ❌ 错误:
"prompt_audio": "./examples/prompt/teacher_male.wav"(./在容器中无意义) - 正确:
"prompt_audio": "/root/GLM-TTS/examples/prompt/teacher_male.wav" - 正确:
"prompt_audio": "/data/audio/voice1.wav"(若你已挂载数据卷到/data)
实践建议:所有参考音频统一放在
/root/GLM-TTS/examples/prompt/下,路径清晰不易错。首次使用前,用ls -l /root/GLM-TTS/examples/prompt/确认文件存在且权限为-rw-r--r--。
2.2input_text:要合成的语音正文,长度与标点有讲究
这是你要“说”出来的话。支持中文、英文、中英混合,但需注意两点:
- 长度控制:单行文本建议≤180字。超长文本易触发OOM或生成截断(尤其32kHz模式)。
- 标点即节奏:句号、问号、感叹号会生成自然停顿;顿号、逗号产生轻微气口;省略号(…)比三个点(...)更易被正确识别为拖音。
{ "prompt_audio": "/root/GLM-TTS/examples/prompt/teacher_male.wav", "input_text": "大家好!今天我们要完成三件事:第一,复习上节课内容;第二,学习新概念;第三,完成随堂练习……请准备好纸笔。" }2.3prompt_text:提升音色还原度的“说明书”,强烈建议填写
虽然标记为“可选”,但实际生产中95%的优质克隆效果都依赖它。它的作用不是“告诉模型读什么”,而是“告诉模型这段声音里每个字怎么发音”。
例如参考音频中说“银行”,若不填prompt_text,模型可能按“yín háng”(货币机构)或“háng yín”(银行分行)两种读音随机生成。而填入:
"prompt_text": "银行的业务范围包括存款、贷款和理财服务。"模型便能结合上下文,锁定“yín háng”的标准读音,并将此发音规律迁移到input_text中。
填写原则:严格忠实于参考音频的实际内容。哪怕只录了3秒“你好”,
prompt_text就写“你好”,不要脑补成“你好,很高兴见到你”。
2.4output_name:自定义文件名,避免时间戳混乱
默认输出为output_0001.wav、output_0002.wav……这对调试友好,但对业务交付极不友好。output_name让你直接命名:
{ "prompt_audio": "/root/GLM-TTS/examples/prompt/teacher_male.wav", "input_text": "欢迎来到智能客服系统。", "output_name": "welcome_greeting_zh" }生成文件即为@outputs/batch/welcome_greeting_zh.wav。
命名规范建议:[场景]_[语言]_[序号],如product_intro_en_01、course_lecture_zh_05。
3. 写JSONL时最容易踩的5个坑(附修复方案)
这些不是理论风险,而是我们实测中高频触发的“批量任务静默失败”原因。
3.1 坑一:Windows换行符(CRLF)导致解析中断
现象:任务列表显示“共100行”,但只成功处理前37行,后续全部跳过,日志无报错。
原因:Windows记事本保存的JSONL默认用<CR><LF>(\r\n)换行,而Linux容器只认\n。第38行开头的\r被当作非法字符,整行JSON解析失败。
修复:
- VS Code打开文件 → 右下角点击
CRLF→ 选择LF→ 保存 - 或命令行一键转换:
sed -i 's/\r$//' tasks.jsonl
3.2 坑二:中文引号“”代替英文引号""
现象:上传后提示JSON decode error at line X。
原因:微信、Word等工具会自动将英文双引号"替换为中文全角引号“”。JSON标准只认半角"。
修复:
- 全选文本 →
Ctrl+H→ 查找“替换为",查找”替换为" - 或用正则:
sed -i 's/“/"/g; s/”/"/g' tasks.jsonl
3.3 坑三:路径中含空格或特殊符号未转义
现象:prompt_audio路径存在但报“file not found”。
原因:路径如/root/GLM-TTS/examples/prompt/张三_录音 2024.wav中的空格未被转义,Shell解析时截断为/root/GLM-TTS/examples/prompt/张三_录音。
修复:
- 最佳实践:路径中彻底避免空格、括号、&、$等符号,用下划线
_替代空格,如zhangsan_recording_2024.wav - 次选方案:若必须用,需在JSON字符串内用
\\双反斜杠转义空格(注意是两个反斜杠):"prompt_audio": "/root/GLM-TTS/examples/prompt/张三_录音\\ 2024.wav"
3.4 坑四:最后一行多了换行符,导致空任务
现象:任务数显示101行,但第101行生成空wav文件。
原因:JSONL文件末尾多了一个空行,程序将其解析为一个空JSON对象{}。
修复:
- 用VS Code打开 →
Ctrl+Shift+P→ 输入Trim Trailing Whitespace→ 回车 - 或命令行:
sed -i ':a;N;$!ba;s/\n$//' tasks.jsonl
3.5 坑五:音频采样率不匹配,生成杂音
现象:音频能生成,但播放时有明显电流声或失真。
原因:GLM-TTS要求参考音频为16-bit PCM, 单声道, 16kHz或22.05kHz采样率。手机直录的MP3(44.1kHz)或会议录音(8kHz)均不兼容。
修复:
- 用
ffmpeg批量重采样(在容器内执行):cd /root/GLM-TTS/examples/prompt/ for f in *.mp3; do ffmpeg -i "$f" -ar 16000 -ac 1 -acodec pcm_s16le "${f%.mp3}.wav"; done - 验证:
ffprobe -v quiet -show_entries stream=sample_rate,channels,codec_name -of default output.wav
4. 从0到1:一份可直接运行的JSONL生成脚本
手动写100行JSONL?不现实。下面这个Python脚本,帮你把Excel表格(含audio_path、text、output_name列)一键转为合规JSONL:
# save as generate_tasks.py import pandas as pd import json # 读取Excel(确保第一行为列名:audio_path, text, output_name) df = pd.read_excel("tts_tasks.xlsx") tasks = [] for _, row in df.iterrows(): task = { "prompt_audio": row["audio_path"], # 必须是容器内绝对路径 "input_text": str(row["text"]).strip(), "output_name": str(row["output_name"]).strip() } # 若Excel中有prompt_text列,则加入 if "prompt_text" in row and pd.notna(row["prompt_text"]): task["prompt_text"] = str(row["prompt_text"]).strip() tasks.append(task) # 写入JSONL(关键:ensure_ascii=False 保留中文,lines=True 保证每行一个JSON) with open("tasks.jsonl", "w", encoding="utf-8") as f: for task in tasks: f.write(json.dumps(task, ensure_ascii=False) + "\n") print(" JSONL生成完成!共", len(tasks), "行任务。")使用流程:
- 准备
/root/GLM-TTS/tts_tasks.xlsx,列名为audio_path(绝对路径)、text、output_name - 进入容器:
docker exec -it glm-tts-container bash - 运行:
python /root/GLM-TTS/generate_tasks.py - 得到
/root/GLM-TTS/tasks.jsonl,直接上传至WebUI批量页
脚本优势:自动处理中文、空值、换行符,生成的JSONL经100%验证可被GLM-TTS识别。
5. 批量任务的进阶控制:不止于基础字段
当业务需求变复杂,仅靠4个字段不够?GLM-TTS预留了扩展空间:
5.1 用output_dir指定专属输出目录(覆盖全局设置)
默认所有批量音频存入@outputs/batch/。若需按项目隔离,可在每行JSON中添加:
{ "prompt_audio": "/root/GLM-TTS/examples/prompt/teacher_male.wav", "input_text": "欢迎收听《AI前沿》播客。", "output_name": "podcast_intro", "output_dir": "/root/GLM-TTS/@outputs/podcast_v1/" }生成文件路径即为/root/GLM-TTS/@outputs/podcast_v1/podcast_intro.wav。
注意:output_dir必须是容器内已有目录,且需有写入权限(chmod 777)。
5.2 用seed固定随机种子,确保结果可复现
批量任务中,若需多次重跑并保证音频完全一致(如A/B测试),添加seed字段:
{ "prompt_audio": "/root/GLM-TTS/examples/prompt/teacher_male.wav", "input_text": "本次更新包含三项优化。", "output_name": "changelog_zh", "seed": 12345 }5.3 用sample_rate为每条任务单独设采样率
全局设24kHz,但某条广告语需最高保真,可单独指定:
{ "prompt_audio": "/root/GLM-TTS/examples/prompt/voiceover_pro.wav", "input_text": "智谱AI,让大模型触手可及。", "output_name": "ad_voiceover_highres", "sample_rate": 32000 }提示:
sample_rate值只能是24000或32000,填其他值将回退至默认24000。
6. 效果验证与问题定位:三步快速诊断
批量任务跑完,发现部分音频异常?按此顺序排查:
6.1 第一步:看ZIP包内文件名与数量
下载batch_results.zip后,解压检查:
- 文件名是否与
output_name完全一致? - 文件数量是否等于JSONL行数?(少于行数=某行解析失败)
.wav文件大小是否均>100KB?(<50KB大概率为空文件或编码失败)
6.2 第二步:查WebUI底部日志面板
切换到「批量推理」页,滚动到底部日志区:
- 搜索
ERROR或Exception,定位具体哪一行失败及原因(如FileNotFoundError: /xxx.wav) - 搜索
Success,确认成功任务的索引号,与JSONL行号对照
6.3 第三步:用ffprobe验证音频基础属性
进入容器,对异常文件执行:
ffprobe -v quiet -show_entries stream=sample_rate,channels,codec_name,duration -of default @outputs/batch/abnormal.wav- 若
duration=N/A→ 音频损坏,需检查参考音频质量 - 若
sample_rate=0→ 采样率参数错误,检查JSONL中sample_rate值 - 若
codec_name=pcm_s16le且duration正常 → 音频本身无问题,问题在播放设备或格式兼容性
7. 总结:写JSONL不是填表,而是与模型对话
回顾全文,你掌握的不仅是JSONL语法,更是与GLM-TTS批量引擎建立可靠通信的完整方法论:
- 路径即信任:
prompt_audio的绝对路径,是你向模型承诺“音源在此”的契约; - 文本即意图:
input_text的标点与长度,是你向模型传递“如何说”的明确指令; - 字段即接口:
prompt_text、output_name、seed等,是模型为你开放的精准控制旋钮; - 格式即协议:JSONL的LF换行、UTF-8编码、无BOM头,是人机间不容妥协的通信协议。
批量生成的本质,从来不是“一次点更多”,而是用结构化数据,把人的意图,无损地翻译给机器执行。当你写出第一份零报错的JSONL,你就已经跨过了TTS工程化的真正门槛。
--- > **获取更多AI镜像** > > 想探索更多AI镜像和应用场景?访问 [CSDN星图镜像广场](https://ai.csdn.net/?utm_source=mirror_blog_end),提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。