GLM-ASR-Nano-2512代码实例:curl调用/gradio_api接口批量转写脚本
本文介绍了如何在星图GPU平台上自动化部署GLM-ASR-Nano-2512镜像,快速构建语音转写服务。通过调用其/gradio_api接口,用户可批量处理会议录音、客户访谈等音频文件,自动生成对应文字稿,显著提升语音内容整理效率。
GLM-ASR-Nano-2512代码实例:curl调用/gradio_api接口批量转写脚本
1. 为什么你需要这个脚本:从单次点击到批量处理的跨越
你可能已经试过在浏览器里打开 http://localhost:7860,把一段录音拖进去,点一下“转写”,几秒钟后就看到文字结果跳出来——很酷,但也很慢。
当你手头有37个会议录音、12段客户访谈、8条产品反馈语音,还有一堆没命名的 .wav 文件散落在文件夹里时,一个一个上传就成了最耗时间的环节。这时候,图形界面不再是助力,反而成了瓶颈。
GLM-ASR-Nano-2512 的真正价值,从来不只是那个漂亮的 Gradio 界面。它背后藏着一个稳定、轻量、可编程的 API 接口:/gradio_api/。这个接口不挑人,不卡顿,不依赖鼠标,只认标准 HTTP 请求和规范音频格式。而本文要带你写的,就是一个能自动扫文件夹、并发提交、统一整理结果的 Python 脚本——它不炫技,但每天能帮你省下两小时;它不复杂,但跑起来就像开了挂。
你不需要懂模型结构,不用调参,甚至不用改一行模型代码。你只需要知道:这段脚本能把你从“手动点点点”的循环里彻底解放出来。
2. 先搞清楚:API 是什么?它和网页界面有什么不一样?
很多人第一次看到 /gradio_api/ 这个路径会犹豫:“这是不是要写前端?”“是不是得配 token?”“会不会比网页还难用?”
其实完全相反。Gradio 的 gradio_api 是一套为开发者准备的“直连通道”——它绕过了所有 UI 渲染、状态管理、按钮逻辑,直接把你的音频文件送到模型推理层,再把识别结果原样返回。你可以把它理解成:把网页上那个“上传+提交”动作,拆解成两步:1)发个请求,2)收个回复。
举个最简单的例子:
- 在网页里,你选中
meeting_01.mp3→ 点“转写” → 等进度条 → 看结果 - 用 API,你执行一条命令:
几秒后,终端就打印出 JSON 格式的识别文本。curl -X POST "http://localhost:7860/gradio_api/" \ -F "data=[\"/path/to/meeting_01.mp3\", null, null, null]" \ -F "fn_index=0"
关键区别就三点:
- 无状态:每次请求都是独立的,不依赖登录、不保存历史
- 可编程:你能用 Python、Shell、Node.js 甚至 Excel VBA 调它
- 可批量:一次发1个,也能一次发100个(稍作改造)
而 fn_index=0 这个参数,就是告诉服务:“请调用第一个函数”,也就是模型的主转写函数。Gradio 把每个功能模块都编了号,0 是默认转写,1 可能是实时录音分析(如果镜像支持),我们只关心 0。
3. 实战脚本:一个真正能跑起来的批量转写工具
下面这个脚本,你复制粘贴就能用。它做了三件关键事:扫描指定目录下的所有支持格式音频、按顺序或并发提交给 GLM-ASR-Nano-2512、把结果按原文件名保存为 .txt。没有多余依赖,只要 Python 3.8+ 和 requests 库。
3.1 安装依赖与准备环境
pip3 install requests tqdm
注意:如果你用的是 Docker 启动的服务(推荐方式),确保宿主机能访问容器的 7860 端口。默认
docker run已映射-p 7860:7860,所以http://localhost:7860在宿主机上完全可用。
3.2 批量转写脚本(Python 版)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
GLM-ASR-Nano-2512 批量转写脚本
支持格式:WAV / MP3 / FLAC / OGG
输出:同名 .txt 文件,含识别文本 + 时间戳(可选)
"""
import os
import sys
import time
import json
import requests
from pathlib import Path
from tqdm import tqdm
from concurrent.futures import ThreadPoolExecutor, as_completed
# ===== 配置区(只需改这里)=====
API_URL = "http://localhost:7860/gradio_api/"
INPUT_DIR = "./audio_samples" # 替换为你自己的音频文件夹路径
OUTPUT_DIR = "./transcripts" # 输出文本存放目录
MAX_WORKERS = 3 # 并发请求数(GPU 内存足可调高,如 RTX 4090 可设 5-6)
TIMEOUT = 300 # 单次请求超时(秒),长音频建议留足
# ==============================
def get_supported_files(folder):
"""扫描支持的音频格式文件"""
exts = {'.wav', '.mp3', '.flac', '.ogg'}
files = []
for p in Path(folder).rglob('*'):
if p.is_file() and p.suffix.lower() in exts:
files.append(p)
return sorted(files)
def transcribe_one_file(filepath):
"""向 GLM-ASR-Nano-2512 提交单个文件并返回结果"""
try:
with open(filepath, "rb") as f:
files = {"files": (filepath.name, f, "audio/x-wav" if filepath.suffix.lower() == ".wav" else "audio/mpeg")}
data = {
"data": json.dumps([
None, # audio input(我们传文件,所以这里为 None)
None, # language(自动检测,留空)
None, # initial prompt(可选,留空)
None # temperature(可选,留空)
]),
"fn_index": 0,
"session_hash": "batch_run" # 固定 session,避免干扰
}
response = requests.post(
API_URL,
files=files,
data=data,
timeout=TIMEOUT
)
response.raise_for_status()
result = response.json()
# Gradio API 返回结构:{"data": ["识别文本"], ...}
text = result.get("data", [""])[0] if result.get("data") else ""
return str(filepath), text.strip()
except Exception as e:
return str(filepath), f"[ERROR] {str(e)}"
def main():
input_path = Path(INPUT_DIR)
output_path = Path(OUTPUT_DIR)
output_path.mkdir(exist_ok=True)
audio_files = get_supported_files(input_path)
if not audio_files:
print(f" 在 {input_path} 中未找到支持的音频文件(.wav/.mp3/.flac/.ogg)")
return
print(f" 发现 {len(audio_files)} 个待转写文件")
print(f" 正在连接 {API_URL} ...")
# 测试连通性
try:
test_resp = requests.get(f"{API_URL.replace('/gradio_api/', '')}", timeout=5)
if test_resp.status_code != 200:
raise ConnectionError("Web UI 未响应,请确认服务已启动")
except Exception as e:
print(f" 连接失败:{e}")
print(" 检查项:1) docker ps 是否看到 glm-asr-nano 容器 2) 是否用了 --gpus all 3) 端口是否被占用")
return
results = []
with ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor:
# 提交所有任务
future_to_file = {
executor.submit(transcribe_one_file, f): f for f in audio_files
}
# 收集结果(带进度条)
for future in tqdm(as_completed(future_to_file), total=len(audio_files), desc="🔊 转写中"):
filepath, text = future.result()
results.append((filepath, text))
# 立即写入文件,避免内存堆积
stem = Path(filepath).stem
out_file = output_path / f"{stem}.txt"
with open(out_file, "w", encoding="utf-8") as fw:
fw.write(text)
if text and not text.endswith("\n"):
fw.write("\n")
# 统计汇总
success_count = sum(1 for _, t in results if not t.startswith("[ERROR]"))
error_count = len(results) - success_count
print(f"\n 完成!成功 {success_count} 个,失败 {error_count} 个")
if error_count > 0:
print(" 失败列表:")
for f, t in results:
if t.startswith("[ERROR]"):
print(f" {Path(f).name} → {t}")
if __name__ == "__main__":
main()
3.3 脚本怎么用?三步走
- 准备音频:把
.wav、.mp3等文件放进./audio_samples(或你改过的INPUT_DIR) - 确认服务运行:终端执行
docker ps,看到类似这行就对了:... glm-asr-nano:latest ... 0.0.0.0:7860->7860/tcp - 运行脚本:
python3 batch_transcribe.py
你会看到一个实时进度条,每完成一个文件,就在 ./transcripts/ 下生成一个同名 .txt。比如 interview_01.mp3 → interview_01.txt,内容就是识别出的文字。
小技巧:如果想看某次失败的具体原因,打开对应
.txt文件,里面会写明错误类型(如“文件过大”、“格式不支持”、“超时”等),比终端滚动日志更清晰。
4. 进阶用法:定制化需求轻松加
上面的脚本是“开箱即用”版,但实际工作中,你很可能需要微调。以下三个高频需求,只需改几行代码就能实现:
4.1 指定语言,提升中文识别准确率
GLM-ASR-Nano-2512 支持自动检测中英文,但如果你的音频全是普通话,强制指定语言能减少误判。修改 transcribe_one_file 函数中 data 字典部分:
"data": json.dumps([
None,
"Chinese", # ← 加这一行,固定为中文(也支持 "English", "Cantonese")
None,
None
]),
4.2 添加时间戳,生成带时间轴的字幕
当前脚本只返回纯文本。若需 SRT 或 VTT 字幕,需启用模型的时间戳输出(需镜像支持)。检查你的 app.py 是否启用了 return_timestamps=True。若已支持,只需改 data 中的第3个参数:
"data": json.dumps([
None,
"Chinese",
True, # ← 启用时间戳(注意:必须是布尔值 True,不是字符串 "true")
None
]),
返回结果将变成类似 [{"text": "你好", "start": 0.23, "end": 1.45}, ...] 的结构,你可以在 main() 中解析并生成标准 SRT。
4.3 限制单次并发数,保护 GPU 显存
脚本默认 MAX_WORKERS = 3,适合大多数消费级显卡。如果你发现转写中途报错 CUDA out of memory,不要慌——这不是代码问题,是显存不够。直接把 MAX_WORKERS 改成 1 或 2,虽然慢一点,但稳如磐石。RTX 3090 用户可尝试 4,4090 用户放心 6。
5. 常见问题与避坑指南
即使脚本再简单,第一次跑也可能遇到几个“意料之中”的小状况。以下是真实用户踩过的坑,附带一针见血的解法:
5.1 “Connection refused” 错误
- 现象:脚本报错
ConnectionError: HTTPConnectionPool(host='localhost', port=7860): Max retries exceeded with url: /gradio_api/ - 原因:服务根本没起来,或端口没映射对
- 解法:
- 执行
docker ps,确认容器状态是Up - 执行
curl http://localhost:7860,看能否返回 HTML(哪怕乱码也说明 Web 通了) - 如果
curl通但/gradio_api/不通,检查app.py中是否启用了enable_queue=True(Gradio 6.x+ 默认开启,不影响 API)
- 执行
5.2 上传后返回空字符串或乱码
- 现象:
.txt文件里是空的,或一堆\u5f00\u59cb这样的 Unicode - 原因:音频格式不被 PyTorch Audio 解码器支持,或采样率异常(如 96kHz)
- 解法:
- 用
ffprobe your_file.mp3查看音频信息,重点关注bit_rate,sample_rate,codec_name - 统一转为标准格式(推荐):
(16kHz 单声道 MP3 是 GLM-ASR-Nano-2512 最兼容的输入)ffmpeg -i input.mp3 -ar 16000 -ac 1 -c:a libmp3lame -q:a 2 output_16k.mp3
- 用
5.3 转写结果明显漏字、断句奇怪
- 现象:一句话被切成三段,或专有名词全错(如“张江”识别成“章江”)
- 原因:模型对低信噪比、远场录音、重口音适应有限
- 解法:
- 前置降噪:用
noisereduce库预处理(加在脚本读文件后) - 加初始提示:在
data第3项填入领域关键词,例如会议场景填"会议纪要,发言人:张总,李经理,技术讨论" - 人工校对模板:脚本可额外生成
.review.md,把识别文本+原始音频路径+时间戳打包,方便后续用 Obsidian 或 Notion 批量审阅
- 前置降噪:用
6. 总结:让语音转写真正成为你的日常工具
GLM-ASR-Nano-2512 不是一个“玩具模型”。它用 1.5B 参数,在中文语音识别上跑赢 Whisper V3,同时体积更小、部署更轻、API 更干净——这些优势,只有当你把它从浏览器里“拽出来”,放进自动化流水线,才能真正释放。
本文给你的不是一个“一次性 demo”,而是一套可长期复用的工作流:
- 用标准
curl/requests调用,不绑定任何框架 - 支持主流音频格式,失败有明确提示
- 并发可控,适配不同硬件
- 输出结构化,方便下一步 NLP 处理(如关键词提取、摘要生成)
你不需要成为语音专家,也能让这套系统每天安静地为你处理几十段语音。真正的技术价值,不在于参数多大、指标多高,而在于——它是否让你少点一次鼠标,少等一分钟,少写一行重复代码。
现在,就把那段积压的客户录音拖进 ./audio_samples,然后敲下 python3 batch_transcribe.py 吧。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
更多推荐
所有评论(0)