Files

7.7 KiB
Raw Permalink Blame History

转录最佳实践


零、环境准备

0.1 安装依赖

pip install funasr
pip install modelscope   # 模型下载

0.2 模型下载

首次运行会自动下载模型到 ~/.cache/modelscope/(约 2GB

模型 大小 用途
paraformer-zh 953MB 语音识别(带时间戳)
punc_ct 1.1GB 标点预测
fsmn-vad 4MB 语音活动检测

手动预下载(可选,避免首次运行等待):

from funasr import AutoModel

# 运行一次即可触发下载
model = AutoModel(
    model="paraformer-zh",
    vad_model="fsmn-vad",
    punc_model="ct-punc",
)
print("模型下载完成")

0.3 验证安装

from funasr import AutoModel
model = AutoModel(model="paraformer-zh", disable_update=True)
result = model.generate(input="test.wav")
print(result)  # 应该输出转录结果

一、技术选型

FunASR Paraformer

阿里开源,中文识别最优,支持字符级时间戳。

⚠️ 关键发现2026-01-15

方案 问题
FunASR 全视频 长视频时间戳漂移(~10s/3分钟→ 剪辑不准
FunASR 30s分段 无漂移 + 精确时间戳

结论:口播剪辑用 FunASR 30s 分段转录


二、音频预处理

2.1 从视频提取音频

ffmpeg -i video.mp4 \
  -vn \                    # 不要视频
  -acodec pcm_s16le \      # 16-bit PCM
  -ar 16000 \              # 16kHz 采样率
  -ac 1 \                  # 单声道
  output.wav

2.2 参数说明

参数 原因
采样率 16000 Hz FunASR 模型训练采样率
声道 单声道 语音识别不需要立体声
格式 WAV 无损,兼容性好
位深 16-bit 足够,文件更小

三、FunASR 使用

3.1 推荐30s 分段转录(口播剪辑用这个)

from funasr import AutoModel
import subprocess
import os

video = "video.mp4"
segment_len = 30  # 30秒一段
duration = 217.97  # 视频时长(用 ffprobe 获取)

model = AutoModel(model="paraformer-zh", disable_update=True)
all_chars = []

num_segments = int(duration // segment_len) + 1
for i in range(num_segments):
    start = i * segment_len
    dur = min(segment_len, duration - start)
    wav = f'/tmp/seg_{i}.wav'

    # 提取音频段
    subprocess.run(['ffmpeg', '-y', '-i', video, '-ss', str(start), '-t', str(dur),
                   '-vn', '-acodec', 'pcm_s16le', '-ar', '16000', '-ac', '1', wav],
                  capture_output=True)

    # FunASR 转录(字符级时间戳)
    result = model.generate(input=wav, return_raw_text=True,
                           timestamp_granularity="character")

    for item in result:
        if 'timestamp' in item and 'text' in item:
            text = item['text'].replace(' ', '')
            for char, ts in zip(text, item['timestamp']):
                all_chars.append({
                    'char': char,
                    'start': round(start + ts[0] / 1000, 2),  # 加偏移!
                    'end': round(start + ts[1] / 1000, 2)
                })
    os.remove(wav)

关键点

  • 30s 分段避免时间戳漂移
  • timestamp_granularity="character" 获取字符级时间戳
  • 每段结果要 加上段起始偏移

3.2 基础用法(短视频可用)

from funasr import AutoModel

model = AutoModel(
    model="paraformer-zh",      # 中文模型
    vad_model="fsmn-vad",       # 语音活动检测
    punc_model="ct-punc",       # 标点预测
)

result = model.generate(
    input="audio.wav",
    batch_size_s=300,           # 批处理时长(秒)
)

3.2 输出格式

[{
  "key": "audio",
  "text": "大家好,我是陈峰。",
  "timestamp": [
    [880, 1120],    // 第1个字的时间范围 (ms)
    [1120, 1360],   // 第2个字
    ...
  ]
}]

3.3 模型说明

模型 用途
paraformer-zh 中文语音识别主模型
fsmn-vad 检测哪里有人说话
ct-punc 自动添加标点符号

四、输出格式设计

4.1 详细 JSON 格式

{
  "audio_file": "/path/to/audio.wav",
  "full_text": "完整转录文本...",
  "duration_ms": 935455,
  "segments": [
    {
      "char": "大",
      "start_ms": 880,
      "end_ms": 1120
    },
    ...
  ],
  "raw_result": { /* FunASR 原始输出 */ }
}

4.2 可读 TXT 格式

======================================
视频转录结果 - video.mp4
======================================

总时长: 15:35 (15分35秒)
字符数: 2006

======================================
完整文本
======================================

大家好,我是陈峰。一直有同学问我...

======================================
带时间戳的句子记录
======================================

[00:01 - 00:02]
大家好,我是陈峰。

[00:05 - 00:17]
一直有同学问我能不能做一期企业级PPT模板的教程

五、常见问题

Q0: 调用方式错误2026-01-13

错误:尝试用命令行 funasr --input video.mp4 调用 正确:只能用 Python API

# ❌ 错误 - 没有 funasr CLI
subprocess.run(['funasr', '--input', 'video.mp4'])

# ✅ 正确 - 用 Python API
from funasr import AutoModel
model = AutoModel(model="paraformer-zh", ...)
result = model.generate(input="video.mp4")

Q0.5: 模型选错没有时间戳2026-01-13

错误:用 SenseVoiceSmall 模型,只输出文本没有时间戳 正确:必须用 paraformer-zh 才有字符级时间戳

# ❌ 错误 - 没有时间戳
model = AutoModel(model="iic/SenseVoiceSmall", ...)

# ✅ 正确 - 有时间戳
model = AutoModel(
    model="paraformer-zh",      # 这个才有时间戳!
    vad_model="fsmn-vad",
    punc_model="ct-punc",
)

Q1: 模型下载慢

首次运行会下载 ~1GB 模型到 ~/.cache/modelscope/

解决

  • 使用国内镜像
  • 或手动下载后放到缓存目录

Q2: 时间戳和文字对不上

原因:标点符号没有时间戳,需要特殊处理

解决

# 去掉标点后再对齐
import re
text_no_punc = re.sub(r'[,。!?、;:]', '', text)

Q2.5: 时间戳数量少于字符数2026-01-13

现象纯字符数828时间戳数763末尾67个字符没有时间戳

原因FunASR 对视频末尾部分可能丢失时间戳

解决

# 访问时间戳要兜底
if idx < len(timestamps):
    ts = timestamps[idx]
else:
    ts = timestamps[-1]  # 用最后一个时间戳兜底

Q2.6: 正则表达式漏掉英文标点2026-01-13

现象:搜索文本时位置偏移,因为 clean_text 里还有英文标点

原因:正则只移除中文标点,没处理英文 , .

解决

# ❌ 错误 - 只有中文标点
clean = re.sub(r'[,。!?、;:]', '', text)

# ✅ 正确 - 包含英文标点
clean = re.sub(r'[,。?!、:;""''()《》【】\s\.,!?;:\'"()]', '', text)

Q3: 长视频处理慢

解决

  • 增大 batch_size_s 参数
  • 使用 GPU 加速(需要 PyTorch CUDA

Q4: 识别准确率低

可能原因

  • 背景噪音太大
  • 说话人口音重
  • 音频采样率不对

解决

  • 预处理降噪
  • 确保 16kHz 采样率

六、性能参考

指标
RTF (Real-Time Factor) ~0.16
含义 1秒音频只需0.16秒处理
15分钟视频 约2.5分钟处理完

测试环境M1 MacCPU 推理