# 文本拼接算法详解

## 概述

[`merge_by_text`](../util/server/text_merge.py) 是 CapsWriter-Offline 中用于解决**语音切片重叠去重**的核心算法，采用**模糊文本匹配**策略，具有高鲁棒性和抗噪音能力。

## 问题背景

在流式语音识别中，音频被切片处理（如 25 秒一段，2 秒重叠），导致同一内容在相邻片段中重复出现：

```
片段 1: "...今天天气真"
片段 2: "天气真好啊..."
         ↑       ↑
      重叠部分（需要去重）
```

## 核心思想

算法在**前一段文本的末尾**和**新文本的开头**之间寻找最长公共部分，以此为界进行智能拼接。不同于简单的尾部匹配，该算法采用窗口搜索策略，能够在末尾区域内灵活定位最佳拼接点。

### 三大设计原则

1. **从长到短匹配**: 优先匹配更长的文本片段，因为长匹配更可靠
2. **允许噪音跳过**: 新文本开头可能有截断噪音（如口语"嗯"、"啊"），允许跳过这些字符
3. **精确→模糊→兜底**: 三层容错机制，确保在各种情况下都能找到合理拼接点

## 算法流程

```
输入: prev_text = "今天天气真"  +  new_text = "嗯天气真好啊"

步骤 1: 预处理
       └─> 去掉两端标点符号，保留有效文本

步骤 2: 确定搜索窗口
       └─> 在 prev_text 末尾 20 字内查找（非全文本搜索）

步骤 3: 智能匹配（两阶段）
       ├─> 阶段一：精确匹配
       │     ├─ 从长到短尝试匹配
       │     ├─ 允许跳过 new_text 开头噪音
       │     └─ 反向查找（优先靠近尾部的匹配）
       │
       └─> 阶段二：模糊匹配（容错 3 字）
             ├─ 处理同音字、识别错误
             └─ 匹配长度必须 > 容错数（避免误匹配）

步骤 4: 执行拼接
       ├─> 找到重叠 "天气"
       ├─> 丢弃 prev_text 尾部可能的漂移噪音
       ├─> 跳过 new_text 开头的噪音
       └─> 结果: "今天天气真好啊"

步骤 5: 兜底逻辑
       └─> 未找到匹配时，直接拼接
```

## 典型场景与效果

### 场景 1: 完美重叠

```
输入: "今天天气真" + "天气真好啊"
匹配: "天气"（精确匹配）
结果: "今天天气真好啊"
```

### 场景 2: 开头有口语噪音

```
输入: "今天天气真" + "嗯天气真好啊"
匹配: 跳过 1 字噪音，匹配 "天气"
结果: "今天天气真好啊"
```

### 场景 3: 识别错误（同音字）

```
输入: "今天天气真" + "天起真好啊"  （"气"识别成"起"）
匹配: 模糊匹配，容错 1 字
结果: "今天天真好啊"（可能残留，交给下游 LLM 润色）
```

### 场景 4: 尾部漂移

```
输入: "今天天气真的" + "好的天气真好啊"
匹配: "天气"（丢弃 prev 的 "真的"，丢弃 new 的 "好的"）
结果: "今天天气真好啊"
```

## 核心优势

1. **鲁棒性强**: 精确→模糊→兜底三层容错，应对各种识别异常
2. **抗噪音能力**: 处理开头截断、尾部漂移、口语噪音、识别错误
3. **高性能**: 窗口搜索 + 反向查找，避免全文本扫描
4. **智能拼接**: 不强制必须在绝对末尾匹配，灵活定位最佳拼接点

## 配置参数

在 [`util/constants.py`](../util/constants.py) 中定义：

- **`OVERLAP_CHARS = 20`**: 搜索窗口大小（prev_text 末尾字符数）
- **`ERROR_TOLERANCE = 3`**: 容错字符数（模糊匹配时允许的最大误差）

## 实际应用

该算法用于生成 `text` 字段（简单文本拼接），相比基于时间戳的精确拼接，具有更强的容错能力，适合作为**鲁棒输出**使用。

## 总结

`merge_by_text` 通过窗口搜索、分层匹配、智能去重的设计，有效解决了语音切片重叠问题。在实际使用中，能够处理大部分常见的识别异常，是 CapsWriter-Offline 实现流畅语音识别体验的关键技术之一。
