拿到 Spark-Audio-1.0-Preview 之后,第一条音频不要直接塞业务录音。先把输入变量固定住:容器与编码、采样率与声道、单次时长。这三项混在一起调,调用失败时很难判断是本地文件格式不对,还是请求体字段填错,又或者是网络与鉴权的问题。建议的顺序是:本地记录音频物理参数,用占位符请求打通链路,每次只改一个变量,再用状态码和响应消息分类。单次时长与采样率的可接受范围以官方文档字段为准,文档没写死之前,按保守值试探,不要拿一段长音频反复重试。
先确认格式和时长边界,再谈识别效果。可操作的做法是:用 ffprobe 记录编码、采样率、声道、时长,用占位符请求确认链路通,然后一次只改一个变量并保留 request_id。格式、编码、采样率类问题通常能在本地转码解决;鉴权、超时、限流类问题需要查 token、网络和服务端可见返回。文档未明确的字段名和时长上限,先用占位符和最保守的取值试探,再按官方说明收紧或放宽。
用 ffprobe 记录一段测试音频的物理参数
先不要问模型支持什么,先问自己手上这段音频是什么。用 ffprobe 读出容器、编码、采样率、声道和时长,是对同一份文件做的客观描述,后续任何一次失败都能拿它对照,不用凭记忆猜。
ffprobe -v error -show_entries format=format_name,duration,bit_rate,size -show_entries stream=index,codec_name,codec_type,sample_rate,channels,channel_layout -of json ./test-audio.wav输出里重点看 format.format_name(容器)、stream.codec_name(编码)、stream.sample_rate(采样率)、stream.channels(声道数)、format.duration(时长,单位秒)。命令太长可以拆成两次跑,先看 format 再看 stream。把结果填进下面这张检查表,同一份文件只填一行。
| 输入变量 | ffprobe 字段 | 记录值 | 用途 |
|---|---|---|---|
| 容器与封装 | format.format_name | 待填 | 判断是否需要先转封装 |
| 音频编码 | stream.codec_name | 待填 | 判断是否需要解码后重新编码 |
| 采样率 | stream.sample_rate | 待填 | 判断是否需要重采样 |
| 声道数 | stream.channels | 待填 | 判断是否需要合并为单声道 |
| 单次时长 | format.duration | 待填 | 判断是否需要切片 |
| 文件体积 | format.size / bit_rate | 待填 | 判断传输耗时与编码后体积 |
建议把这张表和 ffprobe 原始输出一起存成一份基线记录。后面每换一个变量,就复制一份新记录,避免覆盖。
写一个占位符请求骨架跑最小调用
这一步的目标不是听模型输出,而是确认请求能到达服务端并拿到一份可读响应。下面所有尖括号内容都要替换,字段名以官方文档为准,未确认前保持占位符状态,不要自己造字段。
import requests
payload = {
'model': '<MODEL_NAME>', # 官方文档给出的模型标识
'audio': '<AUDIO_FIELD_PLACEHOLDER>', # URL / base64 / file_id,按文档
'audio_format': '<FORMAT>',
'sample_rate': '<SAMPLE_RATE>',
'trace_id': '<YOUR_TRACE_ID>'
}
resp = requests.post(
'<ENDPOINT>',
headers={'Authorization': 'Bearer <TOKEN>'},
json=payload,
timeout=30
)
print('HTTP', resp.status_code)
print(resp.text)运行后先看两件事:HTTP 状态码是否落在预期范围内,响应体里有没有 request_id 或 trace id 这类可用于追踪的字段。如果 audio 字段要求 multipart 上传,把 json=payload 换成 files= 加 data=,其余替换项不变。第一次建议用本机已有的、参数明确的短音频,而不是业务线上正在用的录音。把状态码和响应体原文一起贴进记录,不要只记“成功”或“失败”。
分别改动编码、采样率、时长三个变量
一次只改一个变量,其他全部保持基线值不变。否则某个错误出现时,无法判断是编码、采样率还是长度触发的。先跑基线,再按下面三行各改一次,把每次的状态码、响应消息和请求 ID 原样抄回表格。
| 轮次 | 改动的变量 | 编码 | 采样率 | 时长 | HTTP 状态码 | 响应消息 / request_id |
|---|---|---|---|---|---|---|
| 基线 | 不改 | 待填 | 待填 | 待填 | 待填 | 待填 |
| 第二轮 | 只改编码 | 待填 | 同基线 | 同基线 | 待填 | 待填 |
| 第三轮 | 只改采样率 | 同基线 | 待填 | 同基线 | 待填 | 待填 |
| 第四轮 | 只改时长 | 同基线 | 同基线 | 待填 | 待填 | 待填 |
如果只有改时长那一轮报错,说明时长或体积接近边界,下一步是切片而不是换编码;如果改编码就报错,优先在本地转回基线编码再重试。时长变量可以从基线值逐步向两端试探,但每次只浮动一档,不要一次跳到很长。
对照客户端日志和服务端可见返回分类错误
分类的目的是决定下一步在哪一层动手。下面的归类只是保守的排查方向,具体错误码含义以官方文档和网关说明为准。
| 返回特征 | 通常对应 | 先做什么 | 边界 |
|---|---|---|---|
| 400 / 422,响应提到字段或参数 | 请求体字段名、类型或取值不符合文档 | 逐字段对照文档,先只保留必填字段 | 字段名以文档为准,不要猜 |
| 415,或响应提到 media、codec、format | 音频封装或编码不被接受 | 本地转成基线格式后重试,例如 PCM WAV | 能否转码取决于本地 ffmpeg 是否可用 |
| 401 / 403 | token 失效、权限不足或 header 拼写问题 | 检查 Authorization 头与 token 有效期 | 不要用转码手段处理鉴权失败 |
| 404 | endpoint 路径或模型标识写错 | 核对 endpoint 与 model 字段 | 与音频内容无关 |
| 408 / 504 / 客户端超时 | 网络、DNS、代理或服务端处理时间偏长 | 缩短音频时长、调大客户端超时,查网关日志 | 超时不一定代表不支持该时长 |
| 429 | 请求频率或并发受限 | 降速重试,确认配额 | 与音频格式无关 |
| 5xx | 服务端异常 | 保留 request_id,隔一段时间再重试一次 | 不要连续用长音频重试 |
把能用本地转码、改字段解决的归到客户端侧;把鉴权、网络、配额、服务端异常归到需要查外部的一类。两类问题不要在同一轮里混着调,否则日志会互相干扰。
把测试结果映射到业务音频来源
测完边界之后要回答的是:业务侧到底需不需要预转码或切片。下表按常见音频来源给出条件判断,最后一列留作验证记录——同一份素材处理前后各跑一次占位符请求,比较状态码和返回消息是否变化。
| 音频来源 | 当前参数(示例填写) | 可能需要做的预处理 | 验证结果 |
|---|---|---|---|
| 手机系统录音 | m4a / AAC,采样率待记录 | 转封装或重编码为文档接受格式,必要时重采样、合并为单声道 | 待填 |
| 电话线路录音 | WAV / PCM,8 kHz,单声道 | 多数情况无需转换,重点确认采样率是否低于模型要求 | 待填 |
| 会议系统导出 | mp3 或多轨 WAV,48 kHz | 重采样到目标采样率,声道合并,长文件按时长边界切片 | 待填 |
| 浏览器 MediaRecorder | webm / Opus | 转成文档要求的容器与编码,再按需重采样 | 待填 |
| 已有素材库 | 格式混杂,参数不统一 | 先按 ffprobe 输出分组,只对不满足基线的文件批量转码 | 待填 |
判断顺序可以先粗后细:先按容器和编码筛一遍,再按采样率筛一遍,最后按时长切片。切片位置建议尽量避开字词中间,具体切多长、时间戳如何拼接,需要结合模型返回的时间粒度确认。所有预处理都建议保留原始文件,处理后的音频单独存放,便于回退和复测。当某一类来源连续两轮都落在同一种错误上,就把它固定成业务侧的预转码规则,而不是每次调用时临时处理。