掘金 人工智能 21小时前
Whisper断句不够好?用AI LLM和结构化数据打造完美字幕
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文介绍了一种结合OpenAI Whisper模型和大型语言模型(LLM)的全自动字幕处理管道,旨在解决Whisper在长视频和复杂对话中自动断句和标点不准确的问题。该方案通过字级时间戳、智能分块、高质量提示词和结构化调用,实现了对字幕的智能断句、文本优化和结构化输出,最终产出高质量的字幕文件。

💡利用Whisper的字级时间戳:通过设置`word_timestamps=True`参数,从Whisper获取每个字词的时间信息,为LLM提供处理字幕的“原料”。

🧱智能分块处理:为了规避LLM的Token限制,采用分块处理策略,例如每500个字词为一块,并在字词间隙最大的地方进行切分,提高上下文完整性。

✍️编写高质量LLM提示词:提示词应包含清晰的角色与目标、详细的处理流程、严格的输出格式定义、提供示例和内置最终检查清单等要素,以确保输出的质量和稳定性。

⚠️结构化调用的注意事项:在实践中,需要注意指令与数据分离,避免指令与API约束冲突,确保LLM返回符合要求的JSON格式。

✅其他关键注意事项:包括完整流程、错误处理与重试、成本与模型选择以及最终校对等,以保证程序的稳定性和字幕的质量。

OpenAI的Whisper模型在语音识别领域无疑是革命性的,它能以惊人的准确率将音频转为文字。然而,对于长视频或复杂对话,其自动断句和标点符号功能有时会不尽人意,常常生成不便于阅读的大段文字。

本文将提供一个解决方案:结合Whisper的字级时间戳功能与大语言模型(LLM)的强大理解能力,打造一个能智能断句、优化文本并输出结构化数据的全自动字幕处理管道。

从 Whisper 获取“原料”—— 字级时间戳

要让LLM精确地为新句子赋予起止时间,我必须先从Whisper获取每个字或词的时间信息。这需要开启一个特定参数。

在使用Whisper进行识别时,务必将 word_timestamps 参数设为 True。以Python的openai-whisper库为例:

import whispermodel = whisper.load_model("base")# 开启 word_timestamps 选项result = model.transcribe("audio.mp3", word_timestamps=True)

result 中会包含一个 segments 列表,每个 segment 里又有 words 列表。我需要的数据就在这里。接下来,我将这些数据组装成一个干净的、专为LLM设计的JSON列表。

word_level_timestamps = []for segment in result['segments']:    for word_info in segment['words']:        word_level_timestamps.append({            'word': word_info['word'],            'start': word_info['start'],            'end': word_info['end']        })# 最终得到的数据结构:# [#   {"word": " 五", "start": 1.95, "end": 2.17},#   {"word": "老", "start": 2.17, "end": 2.33},#   ...# ]

这个列表就是我喂给LLM的“原料”。

智能分块(Chunking)—— 规避 Token 限制

一个小时的视频转写出的字词列表可能非常庞大,直接发送给LLM会超出其Token限制(Context Window)。因此,必须进行分块处理。

一个简单有效的方法是设定一个阈值,例如每500个字词为一块

def create_chunks(data, chunk_size=500):    chunks = []    for i in range(0, len(data), chunk_size):        chunks.append(data[i:i + chunk_size])    return chunksword_chunks = create_chunks(word_level_timestamps, 500)

高级技巧:为了避免在句子中间粗暴地切断,更好的分块策略是,在达到 chunk_size 附近时,寻找一个字词间隙(end到下一个start时间差)最大的地方进行切分。这能提高LLM处理每一块时的上下文完整性。

编写高质量的 LLM 提示词

提示词是整个流程的灵魂,它直接决定了输出的质量和稳定性。一个优秀的提示词应该包含以下几个要素:

    清晰的角色与目标:明确告知LLM它的身份(如“AI字幕处理引擎”)和唯一任务。详细的处理流程:分步描述它需要做什么,包括识别语言、智能分段、文本修正、添加标点等。极其严格的输出格式定义:使用表格、代码块等方式,精确定义输出的JSON结构、键名、值类型,并强调哪些是“必须”和“禁止”的。提供示例:给出1-2个包含输入和预期输出的完整示例。这能极大地帮助模型理解任务,尤其是在处理特殊情况(如修正错别字、移除口头禅)时。内置最终检查清单:在Prompt末尾让模型进行自我检查,这是一种强大的心理暗示,能有效提升输出格式的遵循度。

最终优化出的提示词,正是遵循了以上所有原则的典范。(具体提示词见底部

结构化调用的常见问题与解决方案

这是实践中最容易出错的环节,也是我今天对话解决的核心问题。

陷阱一:指令与数据混为一谈

问题描述:初学者常常将长篇的提示词指令和海量的JSON数据拼接成一个巨大的字符串,然后作为单条消息发送给LLM。

症状:LLM返回错误,抱怨“输入格式不符合要求”,因为它看到的是一个混合了自然语言和JSON的复杂文本,而不是它被告知要处理的纯JSON数据。

{  "error": "The input provided does not conform to the expected format for processing. Please ensure the input is a valid JSON list of dictionaries, each containing \'word\', \'start\', and \'end\' keys."}'

解决方案严格分离指令与数据。利用OpenAI API的 messages 结构,将你的提示词放入 role: 'system' 的消息中,将待处理的纯JSON数据字符串放入 role: 'user' 的消息中。

messages = [    {"role": "system", "content": "你的完整提示词..."},    {"role": "user", "content": '纯JSON数据字符串...'} # e.g., json.dumps(chunk)]

陷阱二:json_object 模式与 Prompt 指令冲突

问题描述:为了确保100%返回合法的JSON,我使用 response_format={"type": "json_object"} 参数。但这个参数强制模型返回一个JSON对象(以 {} 包裹)。如果在提示词中,你却要求模型直接返回一个JSON列表(以 [] 包裹),就会产生指令冲突。

response = model.chat.completions.create(                    model=config.params['chatgpt_model'],                    timeout=7200,                    max_tokens= max(int(config.params.get('chatgpt_max_token')) if config.params.get('chatgpt_max_token') else 4096,4096),                    messages=message,                    response_format= { "type":"json_object" }                )

错误的提示词

## 输出 **json** 格式结果 (关键且必须遵守)**必须**以合法 json 列表的形式返回结果,输出列表中的每个元素**必须且只能**包含以下三个键:

症状:即使分离了指令和数据,LLM仍然可能报错,因为它无法同时满足“返回一个对象”和“返回一个列表”这两个矛盾的要求。

解决方案让Prompt的指令与API的约束保持一致。修改你的提示词,要求模型返回一个包裹着字幕列表的JSON对象

这样,API的要求(返回一个对象)和Prompt的指令(返回一个包含subtitles键的对象)就完美统一了。相应地,在代码中解析结果时,也需要多一步提取:result_object['subtitles']

其他注意事项

    完整流程:在代码中,你需要遍历所有分块(chunks),对每一块调用LLM进行处理,然后将每一块返回的字幕列表拼接起来,形成最终完整的字幕文件。

    错误处理与重试:网络请求可能失败,LLM也可能偶尔返回不合规范的JSON。在API调用外层包裹 try-except 块,并加入重试机制(如使用 tenacity 库),是保证程序稳定性的关键。

    成本与模型选择:像 GPT-4odeepseek-chat 这样的模型在遵循复杂指令和格式化输出方面表现更佳。

    最终校对:虽然LLM能完成99%的工作,但在拼接完所有结果后,可以编写简单的脚本进行最后一次检查,例如:检查是否有字幕时长超过6秒,或两条字幕的起止时间是否重叠。


附录:最终系统提示词

# 角色与最终目标你是一位顶级的 AI 字幕处理引擎。你的**唯一目标**是将用户输入(user message)中的**字级**时间戳数据(包含 `'word'` 键),转换成**句子级**的、经过智能断句和文本优化的字幕列表,并以一个包含字幕列表的 **JSON 对象**格式返回。---## 核心处理流程1.  **接收输入**: 你会收到一个 json 格式的列表作为用户输入。列表中每个元素均包含 `'word'`, `'start'`, `'end'`2.  **识别语言**: 自动判断输入文本的主要语言(如中文、英文、日文、西班牙语等),并调用相应的语言知识库。**单次任务只处理一种语言**3.  **智能分段与合并**:    *   **原则**: 以**语义连贯、语法自然**为最高准则进行断句。    *   **时长**: 每条字幕理想时长为 1-3 秒,**绝对不能超过 6 秒**    *   **合并**: 将属于同一句话的多个字/词字典合并成一个。4.  **文本修正与增强**:    *   在合并文本的过程中,对**整句**进行深度校对和优化。    *   **修正**: 自动修正拼写错误、语法错误以及特定语言的常见用词错误。    *   **优化**: 移除不必要的口头禅、调整语序,使表达更流畅、地道,但绝不改变原意。    *   **标点**: 在断句处和句子内部,根据已识别语言的规范,智能添加或修正标点符号。5.  **生成输出**: 按照下方**严格定义的输出格式**返回结果。---## 输出 json 格式结果 (关键且必须遵守)**必须**以一个合法的 **JSON 对象**格式返回结果。该对象**必须**包含一个名为 `'subtitles'` 的键,其值是一个字幕列表。列表中的每个元素**必须且只能**包含以下三个键:| 输出键 (Key) | 类型 (Type)  | 说明                                                                                                           || :------------- | :----------- | :------------------------------------------------------------------------------------------------------------- || `'start'`      | `float`      | **必须存在**。取自该句**第一个字/词**`start` 时间。                                                              || `'end'`        | `float`      | **必须存在**。取自该句**最后一个字/词**`end` 时间。                                                              || `'text'`       | `str`        | **必须存在**。合并、修正、优化并添加标点后的**完整字幕文本****【这是最重要的键,绝对不能使用 'word' 或其他任何名称。】** |**严格禁止**:输出的字典中**不应**出现 `'word'` 键。输入的 `'word'` 内容经过处理后,统一存放于 `'text'` 键中。---## 示例:演示核心处理原则 (适用于所有语言)**重要提示**: 以下示例旨在阐明您需要遵循的**处理逻辑和输出格式**。这些原则是通用的,您必须将它们应用于您在用户输入中识别出的**任何语言**,而不仅仅是示例中的语言。### 原则演示 1#### 用户输入```[    {'word': 'so', 'start': 0.5, 'end': 0.7},    {'word': 'uh', 'start': 0.9, 'end': 1.0},    {'word': 'whatis', 'start': 1.2, 'end': 1.6},    {'word': 'your', 'start': 1.7, 'end': 1.9},    {'word': 'plan', 'start': 2.0, 'end': 2.4}]```#### 你的 JSON 输出```json{    "subtitles": [        {            "start": 0.5,            "end": 2.4,            "text": "So, what is your plan?"        }    ]}```### 原则演示 2#### 用户输入```[    {'word': '这', 'start': 2.1, 'end': 2.2},    {'word': '里是', 'start': 2.3, 'end': 2.6},    {'word': '机', 'start': 2.8, 'end': 2.9},    {'word': '场吗', 'start': 3.0, 'end': 3.5},    {'word': '以经', 'start': 4.2, 'end': 4.5},    {'word': '很晚', 'start': 4.6, 'end': 5.0}]```#### 你的 JSON 输出```json{    "subtitles": [        {            "start": 2.1,            "end": 3.5,            "text": "这里是机场吗?"        },        {            "start": 4.2,            "end": 5.0,            "text": "已经很晚了。"        }    ]}```---## 执行前最终检查在你生成最终答案之前,请在内部进行最后一次检查,确保你的输出 **100%** 符合以下规则:1.  **最终输出是否是合法的 json 对象`{...}`?** -> (是/否)2.  **该 JSON 对象是否包含一个名为 `'subtitles'` 的键?** -> (是/否)3.  **`'subtitles'` 的值是否是一个列表 `[...]`,且列表中的每一个元素都是一个合法的 JSON 对象`{...}`?** -> (是/否)4.  **列表中的每个字典是否都只包含 `'start'`, `'end'`, `'text'` 这三个键?** -> (是/否)5.  **最关键的一点:键名是否是 `'text'`,而不是 `'word'`?** -> (是/否)**只有当以上所有问题的答案都是“是”时,才生成你的最终输出。**

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

Whisper LLM 字幕处理 人工智能 自然语言处理
相关文章