音频提交后没有文本输出、页面也没有明确报错,通常是几件事混在一起:容器或编码不被接收、采样率与声道不符合预期、时长或文件大小越过上限,还有一种常被忽略的情况——任务已经受理,只是还在排队或处理中。建议按「最小样本复现 → 重采样对比 → 加长找边界 → 读返回体」的顺序排查,每一步都留下文件信息和返回体原文,否则后面只能靠猜。
判断方向:先用 30 秒单声道 WAV 做最小复现,能出结果说明问题在长文件或当前环境;再把同一段音频重采样到 16 kHz 单声道提交对比;然后按时长递增找到最后一次成功和第一次失败;最后读返回体的 status 与 error 字段,把「还在跑」和「不被接受」分开。适用边界:Wan-Streamer v0.2 支持的容器、编码、时长上限会随部署配置变化,具体值需要以你环境里的返回体和日志为准。
用 30 秒单声道样本做最小复现
这一步的目标不是解决问题,而是把变量压到最少:一段确定能解码、时长固定、单声道的 WAV。如果 30 秒样本也拿不到结果,问题基本不在文件太长;如果 30 秒样本正常,再往时长和大小方向查才有意义。命令里的路径和参数按你的环境替换。
# 从已有音频截 30 秒,转成 16 kHz 单声道 PCM WAV
ffmpeg -y -i input.mp3 -t 30 -ac 1 -ar 16000 -c:a pcm_s16le sample_30s.wav
# 没有素材时可用测试音替代
ffmpeg -y -f lavfi -i sine=frequency=440:duration=30 -ac 1 -ar 16000 -c:a pcm_s16le tone_30s.wav
# 确认真实文件属性
ffprobe -hide_banner -show_streams -show_format sample_30s.wav
ffprobe 输出里重点看 codec_name、sample_rate、channels、duration 四项,和提交页面的要求逐项对齐。提交时不要只看页面有没有文字,把接口返回体完整贴进记录。字段名以实际响应为准,常见结构大致是这样,便于对照:
{
"task_id": "xxx",
"status": "queued",
"progress": 0,
"error": null,
"message": ""
}
如果页面是表单提交、看不到 JSON,在浏览器开发者工具的 Network 面板找那次上传请求,复制响应体。返回体为空、或返回的是网关的 HTML 错误页,本身就是一条线索:请求可能没进到任务队列。
页面状态要记三个时间点:点击提交的时刻、首次出现状态文字或进度的时刻、出现转写文本的时刻。再补一条参照:同样的操作在已知可用的样本上大概多久出结果。超过这个参照仍无任何状态变化,优先怀疑任务卡住或提交失败,而不是文件太长。
重采样到常见参数再提交一次
采样率和声道是最容易被「能播放」掩盖的因素:浏览器能播放的音频,不代表服务端解码链路接受同样的参数。做法是同一段内容做两个版本,其余条件完全一致,只改采样率和声道。
# 版本 A:16 kHz 单声道
ffmpeg -y -i input.wav -ar 16000 -ac 1 -c:a pcm_s16le a_16k_mono.wav
# 版本 B:44.1 kHz 立体声
ffmpeg -y -i input.wav -ar 44100 -ac 2 -c:a pcm_s16le b_44k_stereo.wav
# 重采样前后对比
ffprobe -hide_banner -show_entries stream=codec_name,sample_rate,channels -show_entries format=duration,size -of default=noprint_wrappers=1 input.wav
ffprobe -hide_banner -show_entries stream=codec_name,sample_rate,channels -show_entries format=duration,size -of default=noprint_wrappers=1 a_16k_mono.wav
两次提交用同一账号、同一页面、尽量同一时段,减少排队差异的干扰。记录表按下面几列填:
| 文件 | 编码/容器 | 采样率 | 声道 | 返回 status | 是否出文本 | error 字段 |
|---|---|---|---|---|---|---|
| input.mp3 | mp3 | 44100 | 2 | |||
| a_16k_mono.wav | pcm_s16le/wav | 16000 | 1 | |||
| b_44k_stereo.wav | pcm_s16le/wav | 44100 | 2 |
如果 16 kHz 单声道 WAV 能出结果、原始 mp3 不能,问题更可能在容器或编码,而不是时长;把原始文件转成 WAV 再提交,是区分这两类原因最省事的做法。反过来,两个 WAV 都失败,采样率基本可以排除,继续查时长和文件大小。
逐步加长音频定位失败起点
「太长」不是判断,区间才是。构造一组只差时长的文件,其他参数保持一致,从短到长逐个提交,找到最后一次成功和第一次失败的时长,再在两者之间二分。
# 同一段音频切出不同长度,参数保持一致
for t in 30 60 120 300 600; do
ffmpeg -y -i input.wav -t $t -ac 1 -ar 16000 -c:a pcm_s16le len_${t}s.wav
done
# 记录每个文件的时长与大小
for f in len_*s.wav; do
echo "== $f"
ffprobe -hide_banner -show_entries format=duration,size -of default=noprint_wrappers=1 "$f"
done
提交记录按下面几列填,status 和 error 照抄返回体,不要自己归纳成「失败/成功」:
| 时长 | 文件大小 | 返回 status | error 字段 | 是否出文本 |
|---|---|---|---|---|
| 30s | ||||
| 60s | ||||
| 120s | ||||
| 300s | ||||
| 600s |
时长增加时文件大小也在增加,两者会绑在一起。要把大小因素拆出来,可以固定时长、换采样率或位深做出大小差异,例如同为 120 秒的 16 kHz 与 48 kHz 版本,看失败是否跟着大小走。这一步能做就做,做不了就在记录里注明「时长与大小未分离」,避免把结论说得过满。
在返回体里区分解析失败与任务未完成
没有文本输出,不等于任务失败。返回体里至少要分清两件事:任务是否被受理、受理后是否解析成功。字段名不同版本可能不一样,先把完整响应打出来再看,常见的是 status、error、message、task_id。
# 提交,表单字段名以页面实际请求为准
curl -s -X POST 'http://host:port/api/transcribe' \
-H 'Authorization: Bearer TOKEN' \
-F 'file=@sample_30s.wav'
# 用返回的 task_id 查询任务
curl -s -H 'Authorization: Bearer TOKEN' \
'http://host:port/api/tasks/TASK_ID'
读法建议:
- status 为 queued / processing / running,且 error 为空:任务未完成,继续轮询,不要重复上传,重复提交只会让队列更长。
- status 为 failed 或返回 error,且 error、message 里出现 decode、codec、format、unsupported、sample rate 之类字样:解析失败,回到 16 kHz 单声道样本,换编码或采样率重试。
- HTTP 4xx 且响应很快:请求在入口就被拒,看 error 和 code,常见原因是字段名不对、缺少文件、文件类型被拦截。
- HTTP 2xx 但响应里没有 task_id:提交方式有问题,检查表单字段名、Content-Type 是否为 multipart。
两种情况的处理分支完全不同:未完成就等,等到超过同一环境下已知可用样本的耗时再考虑中止;解析失败就换文件,别在原文件上反复重试。轮询间隔不必太密,几秒一次通常够用,具体按部署方的限制来。如果四个步骤的记录都指向「短 WAV 成功、长文件失败」,且失败时 status 已经是 failed、error 指向时长或大小,再去核对部署配置里的上限;如果失败时 status 一直停在 queued,问题在队列或后端进程,不在文件本身。