资讯动态

Whisper与Pyannote.audio融合实战:实现带说话人标签的智能会议转录

发布时间:2026/8/10 7:28:48 来源:尧图企业网站定制
1. 项目概述当Whisper遇见Pyannote打造带说话人标签的智能会议纪要在语音处理的实际项目中我们常常面临一个核心需求不仅要听清录音里说了什么还要搞清楚这些话分别是谁说的。无论是会议记录、访谈整理还是播客内容分析单纯的语音转文字ASR就像一份没有署名的会议记录信息价值大打折扣。而说话人日志Speaker Diarization技术正是解决“谁在何时说了什么”这个问题的关键。最近我在一个需要处理大量多说话人会议录音的项目中就遇到了这个典型场景。单纯使用OpenAI的Whisper转录准确率很高但所有文字混在一起后期人工区分说话人耗时耗力。而Pyannote.audio是说话人日志领域的佼佼者能精准地划分出不同说话人的时间段但它本身不负责转写文字。于是一个自然的想法诞生了能否将两者强强联合yinruiqing/pyannote-whisper这个开源项目正是这个想法的优雅实现。它不是一个全新的轮子而是一个精巧的“粘合剂”和“增强工具包”将Whisper强大的语音识别能力与Pyannote.audio精准的说话人区分能力无缝结合。最终输出带时间戳和说话人标签的逐字稿这为后续的会议摘要、内容分析、发言统计等下游任务提供了结构化的数据基础。对于需要处理访谈、会议、辩论等多方对话内容的开发者、数据分析师或内容创作者来说这无疑是一个能极大提升效率的利器。2. 核心组件深度解析Whisper与Pyannote.audio是如何工作的在动手整合之前我们必须先理解手中这两件“利器”的核心原理和工作方式。知其然更要知其所以然这能帮助我们在后续使用中更好地调优和排错。2.1 Whisper并非简单的语音转文字引擎OpenAI开源的Whisper模型其强大之处在于它是一个端到端的自动语音识别系统。所谓“端到端”是指模型直接接收原始的音频波形作为输入输出对应的文本序列中间省去了传统ASR系统中复杂的声学模型、发音词典、语言模型等多模块流水线。这种设计让它对不同的口音、背景噪声和领域术语有了更好的鲁棒性。Whisper模型家族提供了从tiny到large的多种尺寸其区别主要在于参数量和对多语言的支持能力。例如tiny/tiny.en: 参数量最小速度最快。tiny支持多语言tiny.en仅支持英语在纯英语任务上精度通常略高于同尺寸的多语言模型。base,small,medium,large: 参数量依次增大识别精度通常也更高但相应的推理速度会变慢对显存/内存的需求也更大。注意模型选择的权衡。选择模型时需要在“精度”、“速度”、“资源消耗”和“语言”之间做权衡。对于初步测试或对实时性要求高的场景tiny.en或base是很好的起点。如果追求最高精度且资源充足large-v3是目前的最佳选择。对于中文场景务必使用不带.en后缀的模型如base,small,medium,large。Whisper的工作流程可以简化为音频重采样至16kHz - 提取80维的Log-Mel频谱图 - 输入编码器Encoder - 解码器Decoder自回归地生成文本。它还能识别音频中的语音活动检测VAD自动过滤静音段并输出带时间戳的片段。2.2 Pyannote.audio 2.1说话人日志的工业级解决方案Pyannote.audio是一个基于PyTorch的语音处理工具包其说话人日志管道Pipeline是它的招牌功能。在2.1版本中其管道通常是一个预训练好的复杂系统内部集成了多个子任务模型语音活动检测VAD首先区分音频中哪些部分是语音哪些是静音或噪声。这是所有后续处理的基础。说话人嵌入提取Speaker Embedding对于检测到的每个语音片段模型会提取一个高维向量称为嵌入。这个向量就像该片段语音的“声纹指纹”同一个说话人的不同片段其嵌入在向量空间中的距离会很近。聚类Clustering将所有语音片段的嵌入向量进行聚类分析如层次聚类。属于同一类的片段就被认为是同一个说话人。模型会自动推断出音频中存在的说话人数量。最终Pyannote.audio的输出是一个Annotation对象它包含了多个Segment时间段每个Segment都有起止时间和一个说话人标签如SPEAKER_00,SPEAKER_01。重要提示Hugging Face Token与模型访问。Pyannote.audio的预训练模型托管在Hugging Face Hub上。从2023年年中开始访问pyannote/speaker-diarization等模型需要用户认证。你必须在 Hugging Face 注册账号。在账号设置中生成一个具有read权限的访问令牌Access Token。在首次使用代码时需要登录huggingface-cli login或在代码中通过use_auth_token参数传入该令牌。这是项目能正常运行的前提很多新手会在这里卡住。2.3 融合策略pyannote-whisper的两种核心思路理解了两个独立工具的输出pyannote-whisper的融合逻辑就清晰了。项目提供了两种主流策略对应不同的精度和效率需求策略一先转写后对齐Diarize Text这是项目默认命令行和第一种Python用法采用的策略。步骤先用Whisper处理整个音频文件得到带时间戳的转录文本段asr_result[‘segments’]。然后用Pyannote.audio处理同一个音频得到说话人时间段diarization_result。最后将每个文本段根据其起止时间“分配”到重叠度最高的那个说话人时间段上。优点效率高。Whisper和Pyannote.audio都只运行一次。缺点可能存在对齐误差。如果Whisper划分的文本段边界与Pyannote.audio划分的说话人切换边界不完全一致可能会导致一句话的开头或结尾几个词被错误地分配给另一个说话人。这在说话人交替频繁、语速快的对话中较明显。策略二先分割后逐段转写Segment-wise Transcription这是第二种Python用法参考自Hugging Face联合创始人Julien Chaumond的笔记展示的策略。步骤先用Pyannote.audio处理音频得到纯净的说话人时间段。然后针对每个说话人的每一段连续语音使用Audio.crop方法从原始音频中切取出该段波形再单独调用Whisper对这个短音频进行转录。优点精度高对齐最准确。因为每个文本都是基于明确的、单一说话人的音频片段生成的从根本上避免了边界对齐问题。缺点效率较低。Whisper需要被调用多次等于说话人片段的数量如果音频很长、说话人很多总耗时可能远超策略一。同时极短的音频片段如仅说“对”、“是的”可能不利于Whisper发挥最佳性能。在实际项目中我通常会根据数据特点进行选择对于正式会议发言段落较长策略一足够且高效对于激烈辩论或访谈插话、抢话多我会选择策略二以保证最高精度。3. 从零开始环境搭建与踩坑实录理论清晰了接下来就是实战。按照官方README操作看似简单但实际搭建环境时我遇到了几个典型的“坑”。这里我把平滑的安装路径和避坑方法详细记录下来。3.1 基础环境准备与依赖安装首先确保你的Python环境在3.8以上。我强烈建议使用Conda或venv创建独立的虚拟环境避免包冲突。# 使用Conda创建环境推荐 conda create -n pyannote-whisper python3.10 conda activate pyannote-whisper # 或者使用venv python -m venv venv source venv/bin/activate # Linux/Mac # venv\Scripts\activate # Windows接下来安装核心依赖。这里顺序和版本是关键。# 1. 安装PyTorch根据你的CUDA版本选择无GPU则用cpu版本 # 访问 https://pytorch.org/get-started/locally/ 获取最新安装命令 # 例如对于CUDA 11.8 pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118 # 2. 安装Whisper (OpenAI官方库) pip install openai-whisper # 3. 安装Pyannote.audio pip install pyannote.audio3.2 版本降级解决兼容性冲突执行完上述步骤后如果你直接尝试运行很可能会遇到错误。这是因为pyannote.audio的一些依赖特别是speechbrain的新版本与当前代码存在兼容性问题。项目作者明确指出了需要降级两个包这步至关重要。# 降级setuptools和speechbrain到指定版本 pip install setuptools59.5.0 pip install speechbrain0.5.16踩坑心得为什么是这两个版本我追溯过这个问题。speechbrain在较新版本中更改了某些API接口而pyannote.audio2.1版本中的模型加载代码依赖于旧版的接口。setuptools59.5.0则是一个被许多旧版机器学习项目验证过的稳定版本新版的某些行为可能导致pyannote.audio在构建扩展模块时失败。所以严格遵循这个版本要求能省去大量调试时间。3.3 安装pyannote-whisper本体现在可以安装我们今天的主角了。pip install githttps://github.com/yinruiqing/pyannote-whisper.git如果网络环境不佳也可以先克隆仓库再安装git clone https://github.com/yinruiqing/pyannote-whisper.git cd pyannote-whisper pip install -e . # 以可编辑模式安装方便查看源码3.4 获取并配置Hugging Face Token如前所述运行需要Hugging Face的访问令牌。登录你的Hugging Face账号进入 Settings - Access Tokens 。点击“New Token”创建一个具有read权限的Token。复制生成的Token字符串形如hf_xxxxxxxxxxxxxxxxxxxxxxxx。有两种方式在代码中使用它方式一推荐用于脚本设置为环境变量。# 在终端中执行临时 export HF_TOKEN你的token # 或者在Python代码中 import os os.environ[‘HF_TOKEN’] ‘你的token’方式二用于命令行在代码中直接传入use_auth_token参数如示例所示。安全提醒切勿将你的Token直接硬编码在提交到公开仓库的代码中推荐使用环境变量或配置文件来管理。4. 实战演练两种使用方式详解与对比环境就绪Token在手让我们开始真正的转录工作。我将用一个示例音频文件meeting.wav来演示两种用法并分析它们的输出差异。4.1 方式一命令行快速启动这是最快捷的方式其参数与原生whisper命令基本一致只增加了一个--diarization参数。python -m pyannote_whisper.cli.transcribe meeting.wav \ --model small \ --language zh \ --diarization True \ --output_dir ./results \ --output_format txt参数解析与建议--model small: 选用small模型在中文识别精度和速度间取得较好平衡。--language zh: 明确指定中文有助于提升识别准确率。如果不知道语言可以省略让模型自动检测。--diarization True: 核心开关开启说话人日志功能。--output_dir ./results: 指定输出文件夹所有结果文件将保存在此。--output_format txt: 输出纯文本文件。还支持srt字幕、vtt等格式带说话人标签的字幕会非常有用。执行后在./results文件夹下你会得到meeting.txt: 合并了说话人标签的完整文本。meeting.srt: 如果指定了srt格式会生成带说话人标签和时间轴的字幕文件。meeting.json: 包含所有时间戳、文本、说话人标签的详细结构化数据推荐用于后续程序处理。命令行输出的TXT文件预览[0.00 - 10.34] SPEAKER_00: 我认为如果你是一位领导者却不理解你正在使用的术语那可能就是一个开始的信号。 [10.34 - 16.24] SPEAKER_00: 作为组织中的领导者理解数字化意味着什么真的非常重要。 [16.24 - 18.52] SPEAKER_00: 你需要花时间广泛阅读该领域的资料。 ... [44.92 - 49.68] SPEAKER_01: 一是我非常喜欢“精通基础”这个说法。这种方式一键生成结果非常适合批量处理或集成到自动化脚本中。4.2 方式二Python API精细控制通过Python API我们可以获得最大的灵活性和控制权实现上述两种融合策略。策略一实现代码先转写后对齐import whisper from pyannote.audio import Pipeline from pyannote_whisper.utils import diarize_text import os # 设置你的Hugging Face Token os.environ[‘HF_TOKEN’] ‘hf_your_token_here’ # 1. 加载模型 print(“正在加载Whisper模型...”) model whisper.load_model(“small”) # 根据需求选择模型 print(“正在加载Pyannote说话人日志管道...”) pipeline Pipeline.from_pretrained(“pyannote/speaker-diarization”, use_auth_tokenos.environ[‘HF_TOKEN’]) # 2. 处理音频 audio_file “meeting.wav” print(f“开始处理音频文件: {audio_file}”) # 2.1 使用Whisper进行语音识别 print(“- Whisper转录中...”) asr_result model.transcribe(audio_file, language“zh”) # asr_result[‘segments’] 包含了时间戳和文本 # 2.2 使用Pyannote进行说话人日志 print(“- Pyannote说话人分割中...”) diarization_result pipeline(audio_file) # diarization_result 是一个Annotation对象 # 3. 对齐与融合 print(“- 对齐文本与说话人...”) final_result diarize_text(asr_result, diarization_result) # final_result 是一个生成器产出 (segment, speaker, sentence) 三元组 # 4. 输出结果 output_lines [] for seg, spk, sent in final_result: line f‘[{seg.start:.2f} - {seg.end:.2f}] {spk}: {sent}’ print(line) output_lines.append(line) # 保存到文件 with open(“meeting_diarized.txt”, “w”, encoding“utf-8”) as f: f.write(“\n”.join(output_lines)) print(“处理完成结果已保存至 meeting_diarized.txt”)策略二实现代码先分割后逐段转写import whisper from pyannote.audio import Pipeline, Audio import os os.environ[‘HF_TOKEN’] ‘hf_your_token_here’ # 加载模型 model whisper.load_model(“small”) pipeline Pipeline.from_pretrained(“pyannote/speaker-diarization”, use_auth_tokenos.environ[‘HF_TOKEN’]) # 初始化Audio工具用于裁剪音频 audio_tool Audio(sample_rate16000, monoTrue) audio_file “meeting.wav” # 第一步先做说话人分割 print(“进行说话人分割...”) diarization_result pipeline(audio_file) output_lines [] print(“开始逐段转录...”) # 遍历每一个说话人片段 for segment, _, speaker in diarization_result.itertracks(yield_labelTrue): # 裁剪出当前片段的音频波形 waveform, sample_rate audio_tool.crop(audio_file, segment) # 将PyTorch Tensor转为NumPy数组Whisper需要 waveform_np waveform.squeeze().numpy() # 使用Whisper转录这个短片段 # 这里可以添加参数例如 language“zh”但短片段自动检测可能不准建议根据上下文指定 result model.transcribe(waveform_np, fp16False) # 如果无GPUfp16False text result[“text”].strip() if text: # 只输出有内容的片段 line f‘[{segment.start:.2f}s - {segment.end:.2f}s] {speaker}: {text}’ print(line) output_lines.append(line) with open(“meeting_segwise.txt”, “w”, encoding“utf-8”) as f: f.write(“\n”.join(output_lines))4.3 两种策略的输出对比与选择建议为了直观感受差异我处理了一段包含快速对话切换的音频。音频片段特征说话人A“我觉得这个方案被打断”说话人B“等等成本太高”说话人A“成本可以再优化。”策略一输出可能为[0.00 - 2.50] SPEAKER_00: 我觉得这个方案 [2.50 - 4.00] SPEAKER_01: 等等成本太高 [4.00 - 6.00] SPEAKER_00: 成本可以再优化注意“等等”和“成本太高”被合并到一个段且时间戳可能覆盖了说话人切换的精确点。策略二输出可能为[0.00 - 1.80] SPEAKER_00: 我觉得这个方案 [1.80 - 2.50] SPEAKER_00: 被打断 [2.50 - 3.20] SPEAKER_01: 等等 [3.20 - 4.00] SPEAKER_01: 成本太高 [4.00 - 6.00] SPEAKER_00: 成本可以再优化。注意Pyannote划分的片段更细转录完全基于单一说话人音频边界和归属更精确甚至可能捕捉到语气词。选择建议表特性策略一先转写后对齐策略二先分割后转写建议场景处理速度快。模型各运行一次。慢。Whisper需运行多次与片段数正比。处理长音频、批量任务。对齐精度一般。依赖时间戳对齐可能有边界错误。高。转录与说话人片段严格对应。对话交替频繁、辩论、访谈。资源占用较低。较高。多次加载短音频数据。资源受限环境。输出连贯性好。保持Whisper原始分段。可能碎片化。取决于Pyannote的分割粒度。需要自然段落的摘要生成。实现复杂度简单。直接调用工具函数。稍复杂。需手动循环处理片段。需要高度定制化流程。在我的项目中我通常会先用策略一快速处理大量数据评估整体效果。对于其中重要的、或对话复杂的会议再挑出来用策略二进行精细处理。5. 进阶应用从转录结果到会议摘要生成得到带说话人标签的逐字稿只是第一步让数据产生更大价值才是目的。结合大语言模型如ChatGPT API、Claude或本地部署的LLM自动生成会议纪要是当前最实用的进阶应用。5.1 结构化提示词工程直接将冗长的逐字稿扔给LLM并要求“总结一下”效果往往不佳。我们需要设计结构化的提示词Prompt引导模型产出我们需要的格式。以下是一个经过多次迭代后效果不错的Prompt模板你是一名专业的会议秘书请根据以下带时间戳和发言人的会议转录文本生成一份结构化的会议纪要。 会议转录文本{这里插入pyannote-whisper生成的完整文本}请按照以下要求生成纪要 1. **会议核心议题**用一句话概括本次会议讨论的核心主题。 2. **主要结论与决定**列出会议达成的主要结论、做出的决策或下一步行动计划。每条前加上“• ”。 3. **发言人观点摘要**为每位发言人SPEAKER_00, SPEAKER_01等总结其核心观点或建议每条不超过两句话。 4. **待决议题**列出会议上提到但未形成结论、需要后续跟进的问题。 5. **整体摘要**基于以上内容生成一段不超过200字的会议内容整体摘要。 请确保纪要内容准确、简洁、基于转录文本不要添加文本中不存在的信息。将pyannote-whisper的输出替换到{ }中然后调用LLM API。5.2 使用OpenAI API实现自动化摘要这里以OpenAI ChatGPT API为例展示如何将整个流程自动化。import openai import json from pathlib import Path # 1. 读取之前生成的带说话人标签的文本 transcript_path “meeting_diarized.txt” with open(transcript_path, ‘r’, encoding‘utf-8’) as f: transcript_text f.read() # 2. 构建Prompt prompt_template “”” 你是一名专业的会议秘书请根据以下带时间戳和发言人的会议转录文本生成一份结构化的会议纪要。 会议转录文本{transcript}请按照以下要求生成纪要 1. **会议核心议题**用一句话概括本次会议讨论的核心主题。 2. **主要结论与决定**列出会议达成的主要结论、做出的决策或下一步行动计划。每条前加上“• ”。 3. **发言人观点摘要**为每位发言人SPEAKER_00, SPEAKER_01等总结其核心观点或建议每条不超过两句话。 4. **待决议题**列出会议上提到但未形成结论、需要后续跟进的问题。 5. **整体摘要**基于以上内容生成一段不超过200字的会议内容整体摘要。 请确保纪要内容准确、简洁、基于转录文本不要添加文本中不存在的信息。 “”” prompt prompt_template.format(transcripttranscript_text) # 3. 调用OpenAI API openai.api_key “your_openai_api_key” # 请替换为你的API Key response openai.ChatCompletion.create( model“gpt-4-turbo-preview”, # 或 “gpt-3.5-turbo” messages[ {“role”: “system”, “content”: “你是一个专业的会议纪要助手。”}, {“role”: “user”, “content”: prompt} ], temperature0.2, # 较低的温度使输出更确定、更基于事实 max_tokens1500, ) # 4. 解析并保存结果 summary response.choices[0].message.content print(“生成的会议纪要”) print(summary) print(“\n” “”*50) # 保存为Markdown文件便于阅读 with open(“meeting_summary.md”, “w”, encoding“utf-8”) as f: f.write(f”# 会议纪要\n\n**来源文件**{transcript_path}\n\n**生成时间**...\n\n”) f.write(summary)5.3 按发言人视角进行归纳分析有时我们更需要从每个发言人的角度来梳理内容。我们可以稍微修改Prompt让LLM进行视角归纳。prompt_by_speaker f””” 以下是会议录音的转录文本包含了时间戳和发言人标识SPEAKER_00, SPEAKER_01等。 转录文本{transcript_text}请完成以下任务 1. 识别文本中所有不同的发言人标识。 2. 为**每一位发言人**归纳其发言的核心要点每个要点用简短的句子描述。 3. 将结果以JSON格式输出结构如下 {{ “speakers”: [ {{ “id”: “SPEAKER_00”, “summary_points”: [“要点一”, “要点二”, …] }}, // … 其他发言人 ] }} “”” # 调用API代码同上替换prompt # … # 解析JSON结果 import json result_json json.loads(response.choices[0].message.content) for speaker in result_json[‘speakers’]: print(f”{speaker[‘id’]} 的核心观点”) for point in speaker[‘summary_points’]: print(f” - {point}”) print()这种结构化的输出非常适合导入到数据库或知识库中进行进一步的量化分析例如统计每位发言人的发言时长、核心话题贡献等。6. 常见问题、性能优化与排错指南在实际部署和使用过程中你肯定会遇到各种问题。我把自己踩过的坑和解决方案整理如下。6.1 安装与运行时常见错误问题现象可能原因解决方案ImportError: cannot import name ‘DiarizationPipeline’ from ‘pyannote.audio’Pyannote.audio版本不匹配。项目可能依赖较新的3.0版本API而你安装的是2.1。确认安装命令是pip install pyannote.audio。pyannote-whisper目前基于2.1版本开发。确保已降级speechbrain和setuptools。OSError: hf_... is not a valid model identifierHugging Face Token未设置或错误或模型权限未申请。1. 检查HF_TOKEN环境变量或代码中的use_auth_token参数是否正确。2. 访问https://huggingface.co/pyannote/speaker-diarization和https://huggingface.co/pyannote/segmentation点击“Agree and access repository”同意条款以获取访问权限首次使用必须操作。RuntimeError: Failed to import whisper或No module named ‘whisper’Whisper未正确安装。使用pip install openai-whisper安装官方库。注意不是whisper另一个同名包。处理长音频时内存溢出OOM默认情况下Whisper和Pyannote都会尝试将整个音频加载到内存。对于Whisper使用transcribe(…, fp16True)利用半精度减少显存需GPU。或使用transcribe(…, fp16False)强制用CPU。对于Pyannote目前管道对长音频支持较好但如果仍OOM可考虑用pydub等库先将长音频分割成短文件分批处理。转录结果中说话人标签错乱如SPEAKER_00和SPEAKER_01频繁互换这是说话人日志中的“标签置换”问题属于聚类算法本身的特性不代表识别错误。同一个说话人在不同片段被标为不同ID是正常的。如果需要贯穿全文的统一ID需要使用更复杂的“说话人追踪”算法或对pyannote.audio的输出进行后处理例如基于声纹嵌入的连续性进行重标。对于纪要生成通常不影响内容理解。6.2 精度与性能优化技巧音频预处理是关键降噪如果原始录音环境嘈杂先用专业工具如Audacity、Adobe Audition或Python库如noisereduce进行降噪处理能大幅提升Whisper和Pyannote的精度。格式统一确保音频为单声道Mono、采样率16kHz或能被重采样至此的格式如16k/44.1k/48k的WAV或MP3。ffmpeg是处理音频格式的好帮手。Whisper模型选择与参数调优temperature参数在model.transcribe()中降低temperature如设为0可减少输出的随机性使转录结果更确定。initial_prompt参数提供一段与音频内容相关的文本提示可以引导模型专有名词的识别如“本次会议讨论云计算和容器化部署”。word_timestamps参数设为True可以获取词级时间戳在与说话人标签做精细对齐时更有用但会增加计算量。Pyannote.audio管道选择除了“pyannote/speaker-diarization”Hugging Face上还有“pyannote/speaker-diarization-3.1”等新版管道可能精度更高但速度稍慢可以尝试。管道可以加载到GPU加速Pipeline.from_pretrained(…, device“cuda”)。处理超长音频对于数小时的会议录音直接处理风险高。最佳实践是先用pydub按静音区间或固定时长如10分钟分割成小文件分别处理后再按时间顺序合并结果。6.3 一个完整的生产环境脚本框架最后分享一个我用于生产环境的脚本框架它包含了错误处理、日志记录和批量处理功能。import whisper from pyannote.audio import Pipeline from pyannote_whisper.utils import diarize_text import os import sys import logging from pathlib import Path import json # 配置日志 logging.basicConfig(levellogging.INFO, format‘%(asctime)s - %(levelname)s - %(message)s’) logger logging.getLogger(__name__) def process_audio_file(input_audio_path, output_dir, model_size“small”, languageNone): “”“处理单个音频文件的核心函数”“” try: audio_path Path(input_audio_path) if not audio_path.exists(): raise FileNotFoundError(f”音频文件不存在: {input_audio_path}”) output_dir Path(output_dir) output_dir.mkdir(parentsTrue, exist_okTrue) base_name audio_path.stem logger.info(f”开始处理文件: {base_name}”) # 0. 加载模型 (可考虑全局加载以复用) logger.info(“加载模型中…”) model whisper.load_model(model_size) pipeline Pipeline.from_pretrained( “pyannote/speaker-diarization”, use_auth_tokenos.environ.get(“HF_TOKEN”) # 从环境变量读取 ) # 1. 执行转录和说话人日志 logger.info(“执行语音识别…”) asr_result model.transcribe(str(audio_path), languagelanguage, fp16False) # 无GPU用fp16False logger.info(“执行说话人分割…”) diarization_result pipeline(str(audio_path)) # 2. 对齐 logger.info(“对齐文本与说话人…”) final_segments [] for seg, spk, sent in diarize_text(asr_result, diarization_result): final_segments.append({ “start”: round(seg.start, 2), “end”: round(seg.end, 2), “speaker”: spk, “text”: sent }) # 3. 输出多种格式 # 3.1 JSON (最全信息) json_path output_dir / f”{base_name}_diarized.json” with open(json_path, ‘w’, encoding‘utf-8’) as f: json.dump({“segments”: final_segments}, f, ensure_asciiFalse, indent2) logger.info(f”JSON结果已保存: {json_path}”) # 3.2 TXT (便于阅读) txt_path output_dir / f”{base_name}_diarized.txt” with open(txt_path, ‘w’, encoding‘utf-8’) as f: for seg in final_segments: f.write(f”[{seg[‘start’]:.2f} - {seg[‘end’]:.2f}] {seg[‘speaker’]}: {seg[‘text’]}\n”) logger.info(f”TXT结果已保存: {txt_path}”) # 3.3 SRT (字幕格式) srt_path output_dir / f”{base_name}_diarized.srt” with open(srt_path, ‘w’, encoding‘utf-8’) as f: for i, seg in enumerate(final_segments, 1): # 转换时间格式 start_srt format_time_srt(seg[‘start’]) end_srt format_time_srt(seg[‘end’]) f.write(f”{i}\n{start_srt} — {end_srt}\n[{seg[‘speaker’]}] {seg[‘text’]}\n\n”) logger.info(f”SRT结果已保存: {srt_path}”) logger.info(f”文件处理完成: {base_name}”) return True, final_segments except Exception as e: logger.error(f”处理文件 {input_audio_path} 时发生错误: {e}”, exc_infoTrue) return False, None def format_time_srt(seconds): “”“将秒转换为SRT时间格式 HH:MM:SS,mmm”“” hours int(seconds // 3600) minutes int((seconds % 3600) // 60) secs seconds % 60 return f”{hours:02d}:{minutes:02d}:{secs:06.3f}”.replace(‘.’, ‘,’) if __name__ “__main__”: # 检查Token if “HF_TOKEN” not in os.environ: logger.error(“请设置 HF_TOKEN 环境变量。”) sys.exit(1) # 批量处理示例 audio_files [“data/meeting1.wav”, “data/meeting2.mp3”] output_base_dir “./processed_results” for audio_file in audio_files: success, result process_audio_file( input_audio_pathaudio_file, output_diroutput_base_dir, model_size“small”, language“zh” # 如果是中文 ) if not success: logger.warning(f”跳过失败文件: {audio_file}”)这个框架提供了健壮的错误处理、详细的日志和多种输出格式你可以根据自己的需求进行扩展例如集成上一节的摘要生成功能形成一个完整的自动化会议纪要流水线。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价