Files
opencode-skills/videocut-clip-oral/tips/转录最佳实践.md
2026-02-11 22:02:47 +08:00

349 lines
7.7 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!--
input: 视频/音频文件
output: 带时间戳的转录 JSON
pos: 辅助,转录参数和输出格式说明
架构守护者:一旦我被修改,请同步更新:
1. ../README.md 文件清单
-->
# 转录最佳实践
---
## 零、环境准备
### 0.1 安装依赖
```bash
pip install funasr
pip install modelscope # 模型下载
```
### 0.2 模型下载
首次运行会自动下载模型到 `~/.cache/modelscope/`(约 2GB
| 模型 | 大小 | 用途 |
|------|------|------|
| paraformer-zh | 953MB | 语音识别(带时间戳) |
| punc_ct | 1.1GB | 标点预测 |
| fsmn-vad | 4MB | 语音活动检测 |
**手动预下载**(可选,避免首次运行等待):
```python
from funasr import AutoModel
# 运行一次即可触发下载
model = AutoModel(
model="paraformer-zh",
vad_model="fsmn-vad",
punc_model="ct-punc",
)
print("模型下载完成")
```
### 0.3 验证安装
```python
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 从视频提取音频
```bash
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 分段转录(口播剪辑用这个)
```python
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 基础用法(短视频可用)
```python
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 输出格式
```json
[{
"key": "audio",
"text": "大家好,我是陈峰。",
"timestamp": [
[880, 1120], // 第1个字的时间范围 (ms)
[1120, 1360], // 第2个字
...
]
}]
```
### 3.3 模型说明
| 模型 | 用途 |
|------|------|
| `paraformer-zh` | 中文语音识别主模型 |
| `fsmn-vad` | 检测哪里有人说话 |
| `ct-punc` | 自动添加标点符号 |
---
## 四、输出格式设计
### 4.1 详细 JSON 格式
```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
```python
# ❌ 错误 - 没有 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` 才有字符级时间戳
```python
# ❌ 错误 - 没有时间戳
model = AutoModel(model="iic/SenseVoiceSmall", ...)
# ✅ 正确 - 有时间戳
model = AutoModel(
model="paraformer-zh", # 这个才有时间戳!
vad_model="fsmn-vad",
punc_model="ct-punc",
)
```
### Q1: 模型下载慢
首次运行会下载 ~1GB 模型到 `~/.cache/modelscope/`
**解决**
- 使用国内镜像
- 或手动下载后放到缓存目录
### Q2: 时间戳和文字对不上
**原因**:标点符号没有时间戳,需要特殊处理
**解决**
```python
# 去掉标点后再对齐
import re
text_no_punc = re.sub(r'[,。!?、;:]', '', text)
```
### Q2.5: 时间戳数量少于字符数2026-01-13
**现象**纯字符数828时间戳数763末尾67个字符没有时间戳
**原因**FunASR 对视频末尾部分可能丢失时间戳
**解决**
```python
# 访问时间戳要兜底
if idx < len(timestamps):
ts = timestamps[idx]
else:
ts = timestamps[-1] # 用最后一个时间戳兜底
```
### Q2.6: 正则表达式漏掉英文标点2026-01-13
**现象**:搜索文本时位置偏移,因为 clean_text 里还有英文标点
**原因**:正则只移除中文标点,没处理英文 `,` `.`
**解决**
```python
# ❌ 错误 - 只有中文标点
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 推理*