Skip to content

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 和模型:

CLI:   mlx-qwen3-asr
Model: mlx-community/Qwen3-ASR-1.7B-8bit

为保证质量,使用 1.7B 模型和 CLI 默认的最长 30 秒低能量切分,不直接处理数分钟长块。

MLX 官方提供 Linux CUDA 包,但 mlx-qwen3-asr 仍以 Apple Silicon 为主要目标。 以下 WSL 流程仅为本机实测方案。

参考:

2. 安装

2.1 Apple Silicon Mac

brew install ffmpeg jq uv
uv tool install --force mlx-qwen3-asr
mlx-qwen3-asr --doctor

只做文本转录时,可以忽略 diarization 和 token 相关警告。

2.2 WSL2 + NVIDIA

先确认 GPU 可见:

nvidia-smi

安装独立环境:

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 先执行:

asr_cli='mlx-qwen3-asr'

运行基线:

model='mlx-community/Qwen3-ASR-1.7B-8bit'

"$asr_cli" "$sample" \
  --model "$model" \
  --output-format txt \
  --output-dir asr-output/baseline \
  --verbose

中英混合时先保持自动语言检测,不要强制 ChineseEnglish

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 提取原始文本:

json="$output_dir/input-16k-mono.json"
raw="$output_dir/input.txt"

jq -r '.text' "$json" > "$raw"

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"

确认首尾覆盖完整、truncatedfalse,并检查所有非 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,但仍需短切块 和同样的质量检查。

Comments