
1. 理解 Whisper 的转录结果
openai whisper 模型在完成音频转录后,其返回的 result 对象不仅仅包含完整的转录文本 (result['text']),还包含一个关键的 segments 列表。这个 segments 列表是生成带时间戳 srt 文件的基础,它将整个音频分解成多个语义连贯的短句或片段,每个片段都带有精确的起始时间 (start)、结束时间 (end) 和对应的文本内容 (text)。
result['segments'] 的典型结构如下:
[
{
"id": 0,
"seek": 0,
"start": 0.0,
"end": 3.4,
"text": " 这是一个示例。",
"tokens": [50363, 261, 264, 5322, 1079, 286, 264, 1374, 13, 50533],
"temperature": 0.0,
"avg_logprob": -0.21,
"compression_ratio": 1.2,
"no_speech_prob": 0.001
},
{
"id": 1,
"seek": 3.4,
"start": 3.4,
"end": 6.8,
"text": " 我们将学习如何生成SRT文件。",
"tokens": [50533, 261, 264, 5322, 1079, 286, 264, 1374, 13, 50533],
"temperature": 0.0,
"avg_logprob": -0.21,
"compression_ratio": 1.2,
"no_speech_prob": 0.001
}
// ... 更多片段
]可以看到,start 和 end 字段提供了以秒为单位的时间戳,这是构建 SRT 文件的核心数据。
2. 从 Whisper 输出生成 SRT 文件
要将 Whisper 的转录结果转换为 SRT 格式,我们需要遍历 result['segments'] 列表,并按照 SRT 文件的标准格式进行输出。SRT 文件遵循以下结构:
1 00:00:00,000 --> 00:00:03,400 这是一个示例。 2 00:00:03,400 --> 00:00:06,800 我们将学习如何生成SRT文件。
以下是修改后的 Python 代码,它在转录完成后,将结果保存为 .srt 文件:
import os
import whisper
from tqdm import tqdm
import datetime
# 定义存储mp4文件的根目录
root_folder = "C:\Video"
# 加载 Whisper 模型
print("Loading whisper model...")
model = whisper.load_model("base") # 可以根据需求选择 "tiny", "base", "small", "medium", "large"
print("Whisper model complete.")
# 获取待转录的mp4文件数量
print("Getting number of files to transcribe...")
num_files = sum(1 for dirpath, dirnames, filenames in os.walk(root_folder) for filename in filenames if filename.endswith(".mp4"))
print("Number of files: ", num_files)
# 转录mp4文件并显示进度条
with tqdm(total=num_files, desc="Transcribing Files") as pbar:
for dirpath, dirnames, filenames in os.walk(root_folder):
for filename in filenames:
if filename.endswith(".mp4"):
filepath = os.path.join(dirpath, filename)
print(f"\nTranscribing: {filename}")
# 进行转录,fp16=False 适用于没有GPU或GPU不支持FP16的情况
result = model.transcribe(filepath, fp16=False, verbose=True)
# 获取不带扩展名的文件名
filename_no_ext = os.path.splitext(filename)[0]
# 生成 SRT 文件
srt_filepath = os.path.join(dirpath, filename_no_ext + '.srt')
with open(srt_filepath, 'w', encoding='utf-8') as f_srt:
for i, segment in enumerate(result['segments']):
# SRT 片段序号
f_srt.write(str(i + 1) + '\n')
# 格式化时间戳
start_time = str(datetime.timedelta(seconds=segment['start']))
end_time = str(datetime.timedelta(seconds=segment['end']))
# 处理毫秒部分,timedelta 默认是微秒,需要转换
# 格式化为 HH:MM:SS,msmsms
start_ms = int((segment['start'] % 1) * 1000)
end_ms = int((segment['end'] % 1) * 1000)
start_str = f"{int(segment['start'] // 3600):02}:{int((segment['start'] % 3600) // 60):02}:{int(segment['start'] % 60):02},{start_ms:03}"
end_str = f"{int(segment['end'] // 3600):02}:{int((segment['end'] % 3600) // 60):02}:{int(segment['end'] % 60):02},{end_ms:03}"
f_srt.write(f"{start_str} --> {end_str}\n")
# 写入转录文本
f_srt.write(segment['text'].strip() + '\n\n') # strip() 移除 Whisper 可能生成的首尾空格
print(f"SRT file saved to: {srt_filepath}")
# 如果仍然需要txt文件,可以保留以下代码
# transcription = result['text']
# with open(os.path.join(dirpath, filename_no_ext + '.txt'), 'w', encoding='utf-8') as f_txt:
# f_txt.write(transcription)
pbar.update(1)
print("\nAll files transcribed and SRT files generated.")代码说明:
- datetime.timedelta 和时间格式化: SRT 格式要求时间戳为 HH:MM:SS,ms。虽然 datetime.timedelta 可以方便地计算时间差,但直接转换为字符串时,其毫秒部分可能不符合 SRT 的 xxx,yyy 格式。因此,代码中直接通过数学运算来提取小时、分钟、秒和毫秒,并使用 f-string 进行格式化,确保毫秒部分始终为三位数。
- segment['text'].strip(): Whisper 生成的文本片段有时可能包含前导或尾随空格,strip() 方法可以清除这些不必要的空格,使字幕更整洁。
- 编码: 建议使用 encoding='utf-8' 打开文件,以确保正确处理各种语言字符。
3. 进阶:集成说话人分离 (Speaker Diarization)
虽然上述方法可以生成带时间戳的 SRT 文件,但如果音频中包含多个说话人,生成的字幕不会区分是谁在说话。为了在 SRT 文件中标识不同的说话人,我们需要进行说话人分离(Speaker Diarization)。说话人分离是一种识别音频中不同说话人并标注其说话时段的技术。
PyAnnote 的作用:
PyAnnote 是一个强大的开源工具包,专注于音频分析,其中包括高质量的说话人分离功能。通过集成 PyAnnote,我们可以:
- 识别说话人边界: 精确地识别音频中每个说话人开始和结束说话的时间点。
- 分配说话人标签: 为每个说话片段分配一个唯一的说话人标签(例如:[Speaker A]、[Speaker B])。
集成思路:
集成 PyAnnote 通常涉及以下步骤:
- 运行 Whisper 转录: 首先使用 Whisper 获取初步的文本转录和时间戳。
- 运行 PyAnnote 说话人分离: 将相同的音频文件输入到 PyAnnote 模型中,获取每个说话人的时间段和标签。
- 合并结果: 将 Whisper 的文本片段与 PyAnnote 的说话人标签进行匹配。这通常意味着遍历 Whisper 的每个文本片段,根据其时间戳,查找在该时间段内说话的 PyAnnote 识别出的说话人。
- 生成增强型 SRT: 在 SRT 文件的文本内容前加上说话人标签,例如:[Speaker A] 这是一个示例。
示例(概念性,不含完整 PyAnnote 代码):
# ... (Whisper 转录代码,获取 result['segments']) ...
# 假设您已通过 PyAnnote 获取了说话人分离结果,
# 格式可能类似:[{'speaker': 'SPEAKER_00', 'start': 0.5, 'end': 2.1}, ...]
# diarization_result = run_pyannote_diarization(filepath)
# 合并 Whisper 和 Diarization 结果,生成增强型 SRT
# for i, segment in enumerate(result['segments']):
# # 查找与当前segment时间重叠的diarization_result,确定说话人
# speaker_label = get_speaker_for_segment(segment, diarization_result)
# formatted_text = f"[{speaker_label}] {segment['text'].strip()}"
# # ... 写入 SRT 文件 ...请注意,PyAnnote 的集成需要额外的安装和配置,并且其 API 使用方式相对复杂,涉及到模型加载、管道构建等。具体的实现会超出本教程的范围,但其核心思想是利用两个工具的优势,共同生成更丰富、更准确的字幕。
4. 注意事项与最佳实践
- Whisper 模型选择: Whisper 提供多种模型尺寸(tiny, base, small, medium, large)。模型越大,准确度越高,但转录速度越慢,所需的内存也越多。根据您的硬件资源和准确度需求进行选择。
- fp16 参数: fp16=True 可以在支持半精度浮点运算的 GPU 上显著提高转录速度并减少内存占用。如果您的系统没有兼容的 GPU 或遇到错误,请将其设置为 False。
- verbose 参数: verbose=True 会在转录过程中在控制台输出详细信息。在批量处理时,如果不需要这些实时日志,可以设置为 False 以减少输出。
- 文件路径: 确保 root_folder 路径正确,并且 Python 脚本对该目录及其子目录有读写权限。
- 长音频文件处理: 对于非常长的音频文件,Whisper 会自动进行分块处理。但在极端情况下,内存使用仍可能较高。如果遇到内存问题,可能需要手动将音频文件预处理成更小的片段。
- SRT 时间戳精度: Whisper 提供的 start 和 end 时间戳通常精确到毫秒级别,足以满足大多数字幕需求。
总结
通过本文的指导,您应该已经掌握了如何利用 OpenAI Whisper 模型不仅生成音频的文本转录,还能进一步将其格式化为标准的 SRT 字幕文件,并包含精确的时间戳。此外,我们还探讨了通过集成 PyAnnote 等专业工具实现说话人分离的进阶应用,这能为多说话人场景下的字幕文件增添关键的说话人标识信息,从而大大提升字幕的可用性和阅读体验。在实际应用中,根据项目需求和资源限制,合理选择 Whisper 模型和是否集成说话人分离功能,将帮助您高效地生成高质量的字幕。










