Whisper断句不够好?用AI LLM和结构化数据打造完美字幕

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

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

从 Whisper 获取"原料"------ 字级时间戳

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

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

python 复制代码
import whisper

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

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

python 复制代码
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个字词为一块

python 复制代码
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 chunks

word_chunks = create_chunks(word_level_timestamps, 500)

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

编写高质量的 LLM 提示词

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

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

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

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

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

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

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

swift 复制代码
{  "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' 的消息中。

python 复制代码
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列表 (以 [] 包裹),就会产生指令冲突。

ini 复制代码
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" }
                )

错误的提示词

markdown 复制代码
## 输出 **json** 格式结果 (关键且必须遵守)

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

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

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

  • 错误的做法 :要求直接输出 [{...}, {...}]
  • 正确的做法 :要求输出 {"subtitles": [{...}, {...}]}

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

其他注意事项

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

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

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

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


附录:最终系统提示词

markdown 复制代码
# 角色与最终目标

你是一位顶级的 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'`?** -> (是/否)

**只有当以上所有问题的答案都是"是"时,才生成你的最终输出。**
相关推荐
lishaoan7718 分钟前
用TensorFlow进行逻辑回归(二)
人工智能·tensorflow·逻辑回归
慌ZHANG34 分钟前
智慧气象新范式:人工智能如何重构城市级气象服务生态?
人工智能
Eumenidus40 分钟前
使用ESM3蛋白质语言模型进行快速大规模结构预测
人工智能·语言模型·自然语言处理
熊猫钓鱼>_>41 分钟前
FastGPT革命:下一代语言模型的极速进化
人工智能·语言模型·自然语言处理
吕永强1 小时前
电网的智能觉醒——人工智能重构能源生态的技术革命与公平悖论
人工智能·科普
极限实验室1 小时前
喜报 - 极限科技荣获 2025 上海开源创新菁英荟「开源创新新星企业」奖
人工智能·开源
在美的苦命程序员1 小时前
芯片之后,AI之争的下一个战场是能源?
人工智能
霖001 小时前
FPGA通信设计十问
运维·人工智能·经验分享·vscode·fpga开发·编辑器
天上游戏地下人间1 小时前
基于Opencv的缺陷检测实战
图像处理·人工智能·计算机视觉
A7bert7772 小时前
【YOLOv8-obb部署至RK3588】模型训练→转换RKNN→开发板部署
linux·c++·人工智能·python·yolo