Mac / WSL 本地长录音 ASR¶
AI 生成
将中英混合长录音转为纯文本,并检查完整性和专有名词质量。
补充 · 30 Jul 2026 加入 WSL2 + NVIDIA 实测流程。
1. 选择¶
| 平台 | 推理后端 | 安装方式 |
|---|---|---|
| Apple Silicon Mac | MLX Metal | uv tool install mlx-qwen3-asr |
| WSL2 + NVIDIA | MLX CUDA | 独立 uv 虚拟环境 |
两边使用同一 CLI 和模型:
为保证质量,使用 1.7B 模型和 CLI 默认的最长 30 秒低能量切分,不直接处理数分钟长块。
MLX 官方提供 Linux CUDA 包,但 mlx-qwen3-asr 仍以 Apple Silicon 为主要目标。 以下 WSL 流程仅为本机实测方案。
参考:
2. 安装¶
2.1 Apple Silicon Mac¶
只做文本转录时,可以忽略 diarization 和 token 相关警告。
2.2 WSL2 + NVIDIA¶
先确认 GPU 可见:
安装独立环境:
sudo apt update
sudo apt install curl ffmpeg jq
curl -LsSf https://astral.sh/uv/install.sh | sh
export PATH="$HOME/.local/bin:$PATH"
asr_env="$HOME/.local/share/venvs/mlx-qwen3-asr"
uv venv --python 3.12 "$asr_env"
uv pip install --python "$asr_env/bin/python" \
'mlx[cuda12]==0.32.0' \
'mlx-qwen3-asr==0.3.5' \
'nvidia-cuda-runtime-cu12==12.9.79'
每次运行前设置:
asr_env="$HOME/.local/share/venvs/mlx-qwen3-asr"
mlx_cuda_root="$asr_env/lib/python3.12/site-packages/nvidia/cuda_runtime"
export CUDA_HOME="$mlx_cuda_root"
export CUDA_PATH="$mlx_cuda_root"
export MLX_CUDA_CONV_CACHE_SIZE=512
export MLX_CUDA_FFT_CACHE_SIZE=512
asr_cli="$asr_env/bin/mlx-qwen3-asr"
两个缓存变量都要保留,否则长录音后期可能因 cache thrashing 终止。
3. 标准流程¶
3.1 规范化输入并截取样本¶
input='/path/to/input.wav'
normalized='asr-output/work/input-16k-mono.wav'
sample='asr-output/work/sample-0000-0015.wav'
mkdir -p "$(dirname "$normalized")"
ffmpeg -hide_banner -loglevel warning -y \
-i "$input" \
-ar 16000 \
-ac 1 \
-c:a pcm_s16le \
"$normalized"
ffmpeg -hide_banner -loglevel warning -y \
-i "$normalized" \
-t 900 \
-c:a copy \
"$sample"
规范化只解决格式兼容问题,不会提高 16 kHz 单声道 PCM 的识别率。
15 分钟样本应覆盖中英切换、专有名词、数字及较差音质。
3.2 建立无上下文基线¶
以下统一使用 "$asr_cli";Mac 先执行:
运行基线:
model='mlx-community/Qwen3-ASR-1.7B-8bit'
"$asr_cli" "$sample" \
--model "$model" \
--output-format txt \
--output-dir asr-output/baseline \
--verbose
中英混合时先保持自动语言检测,不要强制 Chinese 或 English。
3.3 用确认词表复测¶
上下文只放已经确认的正确拼写:
context='{公司名} {人名} {城市名} {产品名} {业务缩写}'
"$asr_cli" "$sample" \
--model "$model" \
--context "$context" \
--output-format txt \
--output-dir asr-output/context \
--verbose
逐句比较两版。仅在专有名词改善、其他内容未退化且词表未被整串输出时用于全文。 上下文只是识别提示,不是摘要或替换规则,宜短不宜多。
3.4 转录全文¶
先输出 JSON,保留切块偏移、语言和结束原因:
output_dir='asr-output/qwen3-quality'
mkdir -p "$output_dir"
time "$asr_cli" "$normalized" \
--model "$model" \
--context "$context" \
--output-format json \
--output-dir "$output_dir" \
--verbose
从 JSON 提取原始文本:
4. 质量检查¶
先检查全局状态和异常切块:
jq '{
language,
finish_reason,
truncated,
chunks: (.chunks | length),
start: .chunks[0].start,
end: .chunks[-1].end,
abnormal: [
.chunks[]
| select(.truncated or .finish_reason != "eos")
| {
chunk_index,
start,
end,
finish_reason,
truncated,
text
}
]
}' "$json"
确认首尾覆盖完整、truncated 为 false,并检查所有非 eos 切块。人工抽查 中英切换、专有名词、数字和否定表达,同时确认词表未被整串输出。
自然口吃也可能触发 repetition。若确有循环或缺话,将该段切成 2~8 秒低能量 小块重识别,并保留原始 JSON 和修订记录。
5. 生成阅读版¶
保留原始 TXT,另生成只增加换行的版本:
segmented="$output_dir/input-segmented.txt"
perl -Mutf8 -CSD -0pe \
's/(?<=[.!?])\s+/\n/g; s/(?<=[。!?])\s*/\n/g' \
"$raw" > "$segmented"
tr -d '[:space:]' < "$raw" | sha256sum
tr -d '[:space:]' < "$segmented" | sha256sum
两个哈希应一致。
6. 已验证性能¶
| 环境 | 音频时长 | 切块 | 推理耗时 | RTF |
|---|---|---|---|---|
| M1 Pro 16 GB | 15 分钟 | 43 | 76.89~80.83 秒 | 0.085~0.090 |
| WSL2 + RTX 4070 SUPER | 15 分钟 | 48 | 58.37 秒 | 0.065 |
| WSL2 + RTX 4070 SUPER | 87 分 51 秒 | 281 | 333.68 秒 | 0.0633 |
首次模型下载和 CUDA kernel 编译不计入上表。
同一份 WSL 录音的前 15 分钟,使用相同上下文和 30 秒低能量切块对照:
| 实现 | 推理耗时 | 质量观察 |
|---|---|---|
| MLX 1.7B 8bit | 58.37 秒 | 中英切换和目标术语更完整 |
| PyTorch 1.7B BF16 | 92.39 秒 | 漏掉一处中文插话,并出现术语退化 |
整段、约 5 分钟和约 60 秒切块都出现过膨胀、遗漏或完整性下降,30 秒低能量切块 效果最好。该结论仅适用于本次录音与版本组合;升级后应复用同一份样本重新比较。 若 MLX CUDA 兼容性退化,可改用官方 qwen-asr + PyTorch 或 vLLM,但仍需短切块 和同样的质量检查。