7.7 KiB
7.7 KiB
LaTeX 后处理完整方案总结
功能概述
实现了一个安全、智能的 LaTeX 后处理管道,修复 OCR 识别的常见错误。
处理管道
输入: a _ {i 1} + \ vdots
↓ Stage 0: 数字错误修复
修复: 2 2. 2 → 22.2
结果: a _ {i 1} + \ vdots
↓ Stage 1: 拆分粘连命令
修复: \intdx → \int dx
结果: a _ {i 1} + \vdots
↓ Stage 2: 清理 LaTeX 语法空格 ← 新增
修复: a _ {i 1} → a_{i1}
修复: \ vdots → \vdots
结果: a_{i1}+\vdots
↓ Stage 3: 微分规范化 (已禁用)
跳过
结果: a_{i1}+\vdots
输出: a_{i1}+\vdots ✅
Stage 详解
Stage 0: 数字错误修复 ✅
目的: 修复 OCR 数字识别错误
示例:
2 2. 2→22.21 5 0→1503 0. 4→30.4
安全性: ✅ 高(只处理数字和小数点)
Stage 1: 拆分粘连命令 ✅
目的: 修复 OCR 命令粘连错误
示例:
\intdx→\int dx\cdotdS→\cdot dS\sumdx→\sum dx
方法: 基于白名单的智能拆分
白名单:
_COMMANDS_NEED_SPACE = {
"cdot", "times", "div", "pm", "mp",
"int", "iint", "iiint", "oint", "sum", "prod", "lim",
"sin", "cos", "tan", "cot", "sec", "csc",
"log", "ln", "exp",
"partial", "nabla",
}
安全性: ✅ 高(白名单机制)
Stage 2: 清理 LaTeX 语法空格 ✅ 新增
目的: 清理 OCR 在 LaTeX 语法中插入的不必要空格
清理规则:
1. 下标/上标操作符空格
a _ {i 1} → a_{i1}
x ^ {2 3} → x^{23}
2. 大括号内部空格(智能)
a_{i 1} → a_{i1} (移除空格)
y_{\alpha} → y_{\alpha} (保留命令)
3. 分式空格
\frac { a } { b } → \frac{a}{b}
4. 命令反斜杠后空格
\ alpha → \alpha
\ beta → \beta
5. 命令后大括号前空格
\sqrt { x } → \sqrt{x}
\sin { x } → \sin{x}
安全性: ✅ 高(只清理明确的语法位置)
Stage 3: 微分规范化 ❌ 已禁用
原计划: 规范化微分符号 dx → d x
为什么禁用:
- ❌ 无法区分微分和变量名
- ❌ 会破坏 LaTeX 命令(
\vdots→\vd ots) - ❌ 误判率太高
- ✅ 收益小(
dx本身就是有效的 LaTeX)
状态: 禁用,提供可选的上下文感知版本
解决的问题
问题 1: LaTeX 命令被拆分 ✅ 已解决
原问题:
\vdots → \vd ots ❌
\lambda_1 → \lambd a_1 ❌
解决方案: 禁用 Stage 3 微分规范化
结果:
\vdots → \vdots ✅
\lambda_1 → \lambda_1 ✅
问题 2: 语法空格错误 ✅ 已解决
原问题:
a _ {i 1} (OCR 识别结果)
解决方案: 新增 Stage 2 空格清理
结果:
a _ {i 1} → a_{i1} ✅
问题 3: Unicode 实体未转换 ✅ 已解决(之前)
原问题:
MathML 中 λ 未转换为 λ
解决方案: 扩展 Unicode 实体映射表
结果:
λ → λ ✅
⋮ → ⋮ ✅
完整测试用例
测试 1: 下标空格(用户需求)
输入: a _ {i 1}
输出: a_{i1} ✅
测试 2: 上标空格
输入: x ^ {2 3}
输出: x^{23} ✅
测试 3: 分式空格
输入: \frac { a } { b }
输出: \frac{a}{b} ✅
测试 4: 命令空格
输入: \ alpha + \ beta
输出: \alpha+\beta ✅
测试 5: LaTeX 命令保护
输入: \vdots
输出: \vdots ✅ (不被破坏)
输入: \lambda_{1}
输出: \lambda_{1} ✅ (不被破坏)
测试 6: 复杂组合
输入: \frac { a _ {i 1} } { \ sqrt { x ^ {2} } }
输出: \frac{a_{i1}}{\sqrt{x^{2}}} ✅
安全性保证
✅ 保护机制
-
白名单机制 (Stage 1)
- 只拆分已知命令
- 不处理未知命令
-
语法位置检查 (Stage 2)
- 只清理明确的语法位置
- 不处理模糊的空格
-
命令保护 (Stage 2)
- 保留反斜杠后的内容
- 使用
(?<!\\)负向后查找
-
禁用危险功能 (Stage 3)
- 微分规范化已禁用
- 避免误判
⚠️ 潜在边界情况
1. 运算符空格被移除
输入: a + b
输出: a+b (空格被移除)
评估: 可接受(LaTeX 渲染效果相同)
2. 命令间空格被移除
输入: \alpha \beta
输出: \alpha\beta (空格被移除)
评估: 可能需要调整(如果这是问题)
解决方案(可选):
# 保留命令后的空格
expr = re.sub(r'(\\[a-zA-Z]+)\s+(\\[a-zA-Z]+)', r'\1 \2', expr)
性能分析
| Stage | 操作数 | 时间估算 |
|---|---|---|
| 0 | 4 个正则表达式 | < 0.5ms |
| 1 | 1 个正则表达式 + 白名单查找 | < 1ms |
| 2 | 5 个正则表达式 | < 1ms |
| 3 | 已禁用 | 0ms |
| 总计 | < 3ms |
结论: ✅ 性能影响可忽略
文档和工具
📄 文档
docs/LATEX_SPACE_CLEANING.md- 空格清理详解docs/LATEX_PROTECTION_FINAL_FIX.md- 命令保护方案docs/DISABLE_DIFFERENTIAL_NORMALIZATION.md- 微分规范化禁用说明docs/DIFFERENTIAL_PATTERN_BUG_FIX.md- 初始 Bug 修复docs/LATEX_RENDERING_FIX_REPORT.md- Unicode 实体映射修复
🧪 测试工具
test_latex_space_cleaning.py- 空格清理测试test_disabled_differential_norm.py- 微分规范化禁用测试test_differential_bug_fix.py- Bug 修复验证diagnose_latex_rendering.py- 渲染问题诊断
部署检查清单
- Stage 0: 数字错误修复 - 保留 ✅
- Stage 1: 拆分粘连命令 - 保留 ✅
- Stage 2: 清理语法空格 - 新增 ✅
- Stage 3: 微分规范化 - 禁用 ✅
- Unicode 实体映射 - 已扩展 ✅
- 代码无语法错误 - 已验证 ✅
- 服务重启 - 待完成
- 功能测试 - 待完成
部署步骤
-
✅ 代码已完成
app/services/ocr_service.py已更新app/services/converter.py已更新
-
✅ 测试准备
- 测试脚本已创建
- 文档已完善
-
🔄 重启服务
# 重启 FastAPI 服务 -
🧪 功能验证
# 运行测试 python test_latex_space_cleaning.py # 测试 API curl -X POST "http://localhost:8000/api/v1/image/ocr" \ -H "Content-Type: application/json" \ -d '{"image_base64": "...", "model_name": "paddle"}' -
✅ 验证结果
- 检查
a _ {i 1}→a_{i1} - 检查
\vdots不被破坏 - 检查
\lambda_{1}不被破坏
- 检查
总结
| 功能 | 状态 | 优先级 |
|---|---|---|
| 数字错误修复 | ✅ 保留 | 必需 |
| 粘连命令拆分 | ✅ 保留 | 必需 |
| 语法空格清理 | ✅ 新增 | 重要 |
| 微分规范化 | ❌ 禁用 | 可选 |
| LaTeX 命令保护 | ✅ 完成 | 必需 |
| Unicode 实体映射 | ✅ 完成 | 必需 |
三大改进
- 禁用微分规范化 → 保护所有 LaTeX 命令
- 新增空格清理 → 修复 OCR 语法错误
- 扩展 Unicode 映射 → 支持所有数学符号
设计原则
✅ Do No Harm - 不确定的不要改
✅ Fix Clear Errors - 只修复明确的错误
✅ Whitelist Over Blacklist - 基于白名单处理
下一步
立即行动:
- 重启服务
- 测试用户示例:
a _ {i 1}→a_{i1} - 验证 LaTeX 命令不被破坏
后续优化(如需要):
- 根据实际使用调整空格清理规则
- 收集更多 OCR 错误模式
- 添加配置选项(细粒度控制)
🎉 完成!现在的后处理管道既安全又智能!