Apple M系列芯片使用mlx-Whisper识别字幕文件

前言

我之前一直使用windows笔记本的subtitleedit 来识别字幕文件,可以调用显卡使用whisper识别,速度和识别准确度都还可以接受,最近使用mac办公,简单记录下mac下使用whisper识别字幕

link:https://github.com/SubtitleEdit/subtitleedit

mac下字幕识别方案

Buzz

Buzz是一款基于OpenAI Whisper的开源语音转文字工具,它支持Windows、macOS、Linux等多平台,用户可以将麦克风的语音实时转换为文字,也可以将视频、音频文件转换为文字或字幕。

link:https://github.com/chidiwilliams/buzz

主要支持下面几种引擎,可以讲是比较完美的解决方案

  • Whisper
  • Whisper.cpp
  • Hugging Face
  • Faster Whisper
  • OpenAI Whisper API
image.png

whisper或者mlx_whisper

使用whisper比较成熟,根据文档似乎使用--device mps可以实现调用GPU,但是根据我实测有很多报错,这个问题在此PR中进行了讨论 https://github.com/openai/whisper/pull/382

另一种方案是使用mlx_whisper,mlx是MLX 是由 Apple 机器学习研究团队推出的 Apple 芯片上机器学习的阵列框架

link: https://github.com/ml-explore/mlx

使用mlx版本的whisper在使用相同大小模型的情况下,实测字幕识别速度甚至优于我的4070笔记本。

mlx-whisper也提供了模型转化脚本可以将whisper的预训练模型转为whisper风格的模型,也可以直接使用hugging face上转化好的可用模型,下面模型全部可用,选择合适自己的模型使用即可

link:https://huggingface.co/collections/mlx-community/whisper-663256f9964fbb1177db93dc

image (1).png
import whisper
import mlx_whisper
import os
from typing import List
import tqdm


def find_mp4_files(base_dir, depth=3):
    """
    遍历给定目录,搜索最多 depth 层级的所有 .mp4 文件。
    """
    mp4_files = []
    for root, dirs, files in os.walk(base_dir):
        # 限制遍历深度
        current_depth = root[len(base_dir):].count(os.sep)
        if current_depth >= depth:
            dirs.clear()  # 停止进一步深入
            
        # 查找所有 .mp4 文件
        for file in files:
            if file.lower().endswith(".mp4"):
                mp4_files.append(os.path.join(root, file))
    return mp4_files


def generate_subtitles(mp4_files: List[str], model_name, task="transcribe", language="en", apple_silicon=False):
    """
    使用 Whisper 模型为每个 MP4 文件生成字幕,并保存到指定目录。
    """
    for mp4_file in tqdm.tqdm(mp4_files):
        # 提取文件名(不含扩展名)
        # filename = os.path.splitext(os.path.basename(mp4_file))[0]
        # output_file = os.path.join(output_dir, f"{filename}.srt")
        output_file = mp4_file.replace(".mp4", ".srt")
        
        print(f"Transcribing: {mp4_file}")
        if apple_silicon:
            result = mlx_whisper.transcribe(mp4_file, path_or_hf_repo=model_name, task=task, language=language)
        else:
            model = whisper.load_model(model_name)
            result = model.transcribe(mp4_file, task=task, language=language)

        segments = result.get('segments', [])
        
        # 保存为 RST 文件,标准字幕格式
        with open(output_file, "w", encoding="utf-8") as rst_file:
            for idx, segment in enumerate(segments, start=1):
                start_time = format_timestamp(segment['start'])
                end_time = format_timestamp(segment['end'])
                text = segment['text']
                rst_file.write(f"{idx}\n")
                rst_file.write(f"{start_time} --> {end_time}\n")
                rst_file.write(f"{text.strip()}\n\n")
        
        print(f"Subtitle saved: {output_file}")

def format_timestamp(seconds):
    """将时间转换为 hh:mm:ss,SSS 格式"""
    hours = int(seconds // 3600)
    minutes = int((seconds % 3600) // 60)
    secs = int(seconds % 60)
    millis = int((seconds - int(seconds)) * 1000)
    return f"{hours:02}:{minutes:02}:{secs:02},{millis:03}"

# 示例调用
if __name__ == "__main__":
    # 用户输入目录
    config = {
        # "model_name": "mlx-community/whisper-medium-mlx-8bit", # apple m系列芯片使用带mlx前缀的模型
        "model_name": "medium.en",
        "task": "transcribe",
        "language": "en",
        "apple_silicon": False # 苹果M系列芯片设置为 True
    }

    input_dir = ""  # 输入的 MP4 文件路径

    
    # 查找所有 MP4 文件
    print("Searching for MP4 files...")
    mp4_files = find_mp4_files(input_dir)
    print(f"Found {len(mp4_files)} MP4 file(s).")
    
    # 生成字幕文件
    # 默认输出在mp4 同级目录
    generate_subtitles(mp4_files, 
                       model_name=config["model_name"],
                       task=config["task"],
                       language=config["language"],
                       apple_silicon=config["apple_silicon"])
    print("All subtitles have been generated.")


最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。