faster-whisper输出格式定制:SRT/VTT字幕文件生成

faster-whisper输出格式定制:SRT/VTT字幕文件生成

【免费下载链接】faster-whisper plotly/plotly.js: 是一个用于创建交互式图形和数据可视化的 JavaScript 库。适合在需要创建交互式图形和数据可视化的网页中使用。特点是提供了一种简单、易用的 API,支持多种图形和数据可视化效果,并且能够自定义图形和数据可视化的行为。 【免费下载链接】faster-whisper 项目地址: https://gitcode.com/gh_mirrors/fa/faster-whisper

你是否在寻找高效生成多格式字幕的解决方案?是否因现有工具格式单一而无法满足多平台发布需求?本文将系统介绍如何基于faster-whisper实现SRT(SubRip Subtitle)和VTT(Web Video Text Tracks)两种主流字幕格式的定制化生成,通过完整代码示例和参数调优指南,帮助你一站式解决音频转字幕的格式适配问题。读完本文你将掌握:

  • SRT/VTT字幕格式的技术规范与实现差异
  • faster-whisper转录结果的结构化处理方法
  • 带时间戳校准的字幕生成完整代码实现
  • 多场景下的字幕格式定制与优化技巧

字幕格式技术规范对比

字幕文件本质是包含时间戳与文本内容的结构化数据,不同格式在时间戳表示、换行规则和元数据处理上存在显著差异。以下是SRT与VTT格式的核心技术规范对比:

特性SRT格式规范VTT格式规范
文件扩展名.srt.vtt
时间戳分隔符--> (箭头两侧有空格)--> (箭头两侧无空格)
时间格式时:分:秒,毫秒 (逗号分隔毫秒)时:分:秒.毫秒 (点分隔毫秒)
序号要求必须包含递增序号 (1, 2, 3...)可选,可省略序号
头部标识无特殊头部必须以WEBVTT开头
空行规则段落间必须有空行分隔段落间可有空行,也可紧密排列
支持的样式不支持内联样式支持基础CSS样式 (通过::cue伪类)
换行表示\n 或实际换行\n 或实际换行

SRT格式示例

1
00:01:23,456 --> 00:01:25,789
这是SRT格式的字幕示例

2
00:01:26,123 --> 00:01:28,456
支持多行显示
通过空行分隔段落

VTT格式示例

WEBVTT

00:01:23.456 --> 00:01:25.789
这是VTT格式的字幕示例

00:01:26.123 --> 00:01:28.456
支持基础样式
<span style="color:red">红色文本</span>

faster-whisper转录结果结构解析

faster-whisper的转录结果包含丰富的时间戳信息,这些信息是生成字幕的基础。从transcribe.py源码分析可知,转录返回的Segment对象包含以下关键属性:

@dataclass
class Segment:
    id: int                 # 段落序号
    seek: int               # 音频偏移量
    start: float            # 开始时间(秒)
    end: float              # 结束时间(秒)
    text: str               # 段落文本内容
    tokens: List[int]       # 分词标识
    avg_logprob: float      # 平均对数概率(置信度)
    compression_ratio: float # 压缩比
    no_speech_prob: float   # 非语音概率
    words: Optional[List[Word]] # 单词级时间戳

当启用word_timestamps=True参数时,每个Segment还会包含Word对象列表,提供单词级精度的时间戳:

@dataclass
class Word:
    start: float            # 单词开始时间(秒)
    end: float              # 单词结束时间(秒)
    word: str               # 单词内容
    probability: float      # 单词置信度

关键时间戳转换逻辑

faster-whisper返回的时间戳以为单位的浮点数(如start=123.456表示123秒456毫秒),需要转换为字幕格式要求的时:分:秒,毫秒格式。utils.py中提供的format_timestamp函数实现了基础转换:

def format_timestamp(
    seconds: float,
    always_include_hours: bool = False,
    decimal_marker: str = ".",
) -> str:
    milliseconds = round(seconds * 1000.0)
    hours = milliseconds // 3_600_000
    milliseconds -= hours * 3_600_000
    minutes = milliseconds // 60_000
    milliseconds -= minutes * 60_000
    seconds = milliseconds // 1_000
    milliseconds -= seconds * 1_000
    
    hours_marker = f"{hours:02d}:" if always_include_hours or hours > 0 else ""
    return f"{hours_marker}{minutes:02d}:{seconds:02d}{decimal_marker}{milliseconds:03d}"

该函数可通过decimal_marker参数控制毫秒分隔符(逗号或点),满足不同格式需求。

字幕生成器实现方案

基于faster-whisper的转录结果,我们可以设计一个通用的字幕生成器,支持SRT和VTT两种格式的输出。实现架构如下:

mermaid

核心实现代码

以下是完整的字幕生成器实现,包含格式转换、时间戳处理和文件写入等核心功能:

from dataclasses import asdict
from typing import List, TextIO, Union
from faster_whisper.transcribe import Segment
from faster_whisper.utils import format_timestamp

class SubtitleGenerator:
    def __init__(self, segments: List[Segment]):
        """
        字幕生成器初始化
        
        Args:
            segments: faster-whisper返回的转录结果列表
        """
        self.segments = segments
        
    def _convert_timestamp(self, seconds: float, format_type: str) -> str:
        """
        将秒转换为指定格式的时间戳字符串
        
        Args:
            seconds: 时间(秒)
            format_type: 格式类型,'srt'或'vtt'
            
        Returns:
            格式化的时间戳字符串
        """
        if format_type == 'srt':
            return format_timestamp(seconds, decimal_marker=',')
        elif format_type == 'vtt':
            return format_timestamp(seconds, decimal_marker='.')
        raise ValueError(f"不支持的格式类型: {format_type}")
    
    def generate_srt(self, output_file: Union[str, TextIO]) -> None:
        """
        生成SRT格式字幕
        
        Args:
            output_file: 输出文件路径或文件对象
        """
        is_file_object = hasattr(output_file, 'write')
        
        if not is_file_object:
            file = open(output_file, 'w', encoding='utf-8')
        else:
            file = output_file
            
        try:
            for i, segment in enumerate(self.segments, 1):
                # 写入序号
                file.write(f"{i}\n")
                
                # 写入时间戳
                start_time = self._convert_timestamp(segment.start, 'srt')
                end_time = self._convert_timestamp(segment.end, 'srt')
                file.write(f"{start_time} --> {end_time}\n")
                
                # 写入文本内容
                file.write(f"{segment.text.strip()}\n")
                
                # 写入段落分隔空行
                file.write("\n")
        finally:
            if not is_file_object:
                file.close()
    
    def generate_vtt(self, output_file: Union[str, TextIO]) -> None:
        """
        生成VTT格式字幕
        
        Args:
            output_file: 输出文件路径或文件对象
        """
        is_file_object = hasattr(output_file, 'write')
        
        if not is_file_object:
            file = open(output_file, 'w', encoding='utf-8')
        else:
            file = output_file
            
        try:
            # 写入VTT头部标识
            file.write("WEBVTT\n\n")
            
            for segment in self.segments:
                # 写入时间戳
                start_time = self._convert_timestamp(segment.start, 'vtt')
                end_time = self._convert_timestamp(segment.end, 'vtt')
                file.write(f"{start_time}--> {end_time}\n")  # VTT箭头两侧无空格
                
                # 写入文本内容
                file.write(f"{segment.text.strip()}\n")
                
                # 写入段落分隔空行
                file.write("\n")
        finally:
            if not is_file_object:
                file.close()
                
    def generate(self, output_file: str, format_type: str) -> None:
        """
        生成指定格式的字幕
        
        Args:
            output_file: 输出文件路径
            format_type: 格式类型,'srt'或'vtt'
        """
        if format_type == 'srt':
            self.generate_srt(output_file)
        elif format_type == 'vtt':
            self.generate_vtt(output_file)
        else:
            raise ValueError(f"不支持的格式类型: {format_type}")

完整应用示例:音频转字幕工作流

以下是使用faster-whisper进行音频转录并生成字幕文件的完整工作流程示例。我们将实现一个命令行工具,支持指定输出格式、调整字幕时长阈值等高级功能。

1. 安装必要依赖

# 安装faster-whisper
pip install faster-whisper

# 如需处理音频文件,可能需要额外依赖
pip install ffmpeg-python

2. 完整应用代码实现

import argparse
from faster_whisper import WhisperModel
from subtitle_generator import SubtitleGenerator  # 导入上面实现的字幕生成器

def main():
    parser = argparse.ArgumentParser(description='音频转字幕工具')
    parser.add_argument('audio_path', help='音频文件路径')
    parser.add_argument('-o', '--output', help='输出文件路径(不带扩展名)')
    parser.add_argument('-f', '--format', choices=['srt', 'vtt'], default='srt',
                        help='输出格式(srt或vtt),默认srt')
    parser.add_argument('-m', '--model', default='base',
                        help='模型大小(tiny, base, small, medium, large等)')
    parser.add_argument('-l', '--language', default=None,
                        help='指定语言(如zh, en),默认自动检测')
    parser.add_argument('-t', '--threshold', type=float, default=0.8,
                        help='字幕最小置信度阈值,低于此值的段落将被过滤')
    parser.add_argument('--word_timestamps', action='store_true',
                        help='启用单词级时间戳(实验性功能)')
    
    args = parser.parse_args()
    
    # 设置输出文件名
    output_path = args.output if args.output else args.audio_path.rsplit('.', 1)[0]
    output_file = f"{output_path}.{args.format}"
    
    # 加载模型
    print(f"加载模型: {args.model}")
    model = WhisperModel(args.model, device="cpu", compute_type="int8")
    
    # 转录音频
    print(f"正在转录音频: {args.audio_path}")
    segments, info = model.transcribe(
        args.audio_path,
        language=args.language,
        word_timestamps=args.word_timestamps,
        # 设置其他参数
        beam_size=5,
        log_prob_threshold=args.threshold,  # 过滤低置信度结果
        no_speech_threshold=0.6  # 过滤非语音段落
    )
    
    print(f"检测到语言: {info.language} (置信度: {info.language_probability:.2f})")
    print(f"生成{args.format}格式字幕: {output_file}")
    
    # 转换为列表以便后续处理
    segments = list(segments)
    
    # 生成字幕
    generator = SubtitleGenerator(segments)
    generator.generate(output_file, args.format)
    
    print(f"字幕生成完成,共{len(segments)}个段落")

if __name__ == "__main__":
    main()

3. 命令行使用示例

# 基本用法:生成SRT字幕
python audio_to_subtitle.py audio.mp3 -o output_subtitle -f srt

# 高级用法:使用medium模型,指定中文,生成VTT字幕
python audio_to_subtitle.py meeting.mp3 -m medium -l zh -f vtt -t 0.7

# 启用单词级时间戳(实验性)
python audio_to_subtitle.py speech.mp3 --word_timestamps

高级定制技巧与优化策略

1. 字幕内容优化

过滤低质量字幕段落

可以基于avg_logprob(平均对数概率)过滤低质量的转录结果,通常建议阈值设为-1.0到-0.5之间:

# 过滤低置信度段落
filtered_segments = [
    seg for seg in segments 
    if seg.avg_logprob > -0.8  # 调整此阈值
]
合并短段落

对于过短的字幕段落(如单个单词),可以合并相邻段落提升可读性:

def merge_short_segments(segments, min_duration=1.0):
    """合并短于指定时长的段落"""
    merged = []
    current_segment = None
    
    for seg in segments:
        if current_segment is None:
            current_segment = seg
        else:
            # 检查当前段落是否过短
            if (seg.end - current_segment.start) < min_duration:
                # 合并段落
                current_segment = Segment(
                    id=current_segment.id,
                    seek=current_segment.seek,
                    start=current_segment.start,
                    end=seg.end,
                    text=f"{current_segment.text.strip()} {seg.text.strip()}",
                    tokens=current_segment.tokens + seg.tokens,
                    avg_logprob=(current_segment.avg_logprob + seg.avg_logprob) / 2,
                    compression_ratio=(current_segment.compression_ratio + seg.compression_ratio) / 2,
                    no_speech_prob=(current_segment.no_speech_prob + seg.no_speech_prob) / 2,
                    words=current_segment.words + (seg.words or []) if current_segment.words else None
                )
            else:
                merged.append(current_segment)
                current_segment = seg
    
    if current_segment:
        merged.append(current_segment)
        
    return merged

2. 时间戳校准与调整

全局时间偏移

有时需要整体调整字幕时间(如音频与视频不同步),可添加全局偏移量:

def adjust_timestamps(segments, offset_seconds):
    """
    调整所有时间戳
    
    Args:
        segments: 段落列表
        offset_seconds: 偏移量(秒),正数表示延后,负数表示提前
    """
    adjusted = []
    for seg in segments:
        # 创建新的段落对象,调整时间戳
        adjusted_seg = Segment(
            id=seg.id,
            seek=seg.seek,
            start=max(0, seg.start + offset_seconds),  # 确保不小于0
            end=seg.end + offset_seconds,
            text=seg.text,
            tokens=seg.tokens,
            avg_logprob=seg.avg_logprob,
            compression_ratio=seg.compression_ratio,
            no_speech_prob=seg.no_speech_prob,
            words=[
                Word(
                    start=max(0, word.start + offset_seconds),
                    end=word.end + offset_seconds,
                    word=word.word,
                    probability=word.probability
                ) for word in seg.words
            ] if seg.words else None
        )
        adjusted.append(adjusted_seg)
    return adjusted

3. 多格式批量转换

对于需要同时生成多种格式字幕的场景,可以扩展字幕生成器,实现批量转换:

def generate_all_formats(self, base_path: str) -> None:
    """生成所有支持的格式字幕"""
    self.generate_srt(f"{base_path}.srt")
    self.generate_vtt(f"{base_path}.vtt")
    
    # 可以添加更多格式支持
    # self.generate_ass(f"{base_path}.ass")  # ASS格式
    # self.generate_sbv(f"{base_path}.sbv")  # YouTube SBV格式

常见问题解决方案

1. 时间戳不准确问题

如果生成的字幕时间戳与音频不同步,可能的原因和解决方案:

  • 模型精度不足:尝试使用更大的模型(如medium或large)
  • 音频采样率问题:确保音频采样率为16kHz(faster-whisper默认采样率)
  • VAD参数调整:调整语音活动检测参数,如增加min_silence_duration_ms
# 调整VAD参数示例
segments, info = model.transcribe(
    audio_path,
    vad_filter=True,
    vad_parameters=dict(
        min_silence_duration_ms=200,  # 最小静音时长(毫秒)
        speech_pad_ms=30  # 语音前后填充时长(毫秒)
    )
)

2. 中文分词问题

中文转录时可能出现分词不连贯问题,可通过以下方法优化:

  • 使用针对中文优化的模型(如large-v3对多语言支持更好)
  • 调整语言参数为zh,避免自动检测错误
  • 使用initial_prompt提供中文语境提示
# 提供中文语境提示示例
segments, info = model.transcribe(
    audio_path,
    language="zh",
    initial_prompt="以下是中文语音转文字,内容为技术讲座,包含专业术语。"
)

3. 长音频处理优化

对于长音频(如超过1小时),建议使用以下策略优化性能:

  • 使用chunk_length参数分块处理:chunk_length=30(30秒一块)
  • 启用log_progress=True显示处理进度
  • 使用GPU加速:device="cuda"(如可用)

总结与扩展展望

本文详细介绍了基于faster-whisper生成SRT和VTT字幕的完整方案,从格式规范解析到实际代码实现,再到高级定制技巧。通过本文的方法,你可以轻松将音频内容转换为各种平台兼容的字幕格式。

未来可以进一步探索的方向:

  1. 多语言字幕同步生成:同时生成多种语言的字幕文件
  2. 字幕样式定制:扩展VTT格式支持更多CSS样式
  3. 字幕翻译集成:结合翻译API实现自动翻译字幕
  4. OCR字幕对齐:与视频OCR结合,优化已有字幕的时间戳

希望本文提供的方案能帮助你高效解决字幕生成需求。如果觉得有用,请点赞收藏,并关注获取更多faster-whisper高级应用技巧!

【免费下载链接】faster-whisper plotly/plotly.js: 是一个用于创建交互式图形和数据可视化的 JavaScript 库。适合在需要创建交互式图形和数据可视化的网页中使用。特点是提供了一种简单、易用的 API,支持多种图形和数据可视化效果,并且能够自定义图形和数据可视化的行为。 【免费下载链接】faster-whisper 项目地址: https://gitcode.com/gh_mirrors/fa/faster-whisper

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值