335 lines
9.7 KiB
Markdown
335 lines
9.7 KiB
Markdown
|
|
# LaTeX 字符渲染问题分析与修复报告
|
|||
|
|
|
|||
|
|
## 问题描述
|
|||
|
|
|
|||
|
|
OCR 识别完成后,某些 LaTeX 字符(如 `\lambda`、`\vdots`)没有被成功渲染。
|
|||
|
|
|
|||
|
|
## 问题诊断
|
|||
|
|
|
|||
|
|
### 1. LaTeX 语法检查 ✅
|
|||
|
|
|
|||
|
|
**结论**: LaTeX 语法完全正确。
|
|||
|
|
|
|||
|
|
- `\lambda` - 希腊字母 λ (Unicode U+03BB)
|
|||
|
|
- `\vdots` - 垂直省略号 ⋮ (Unicode U+22EE)
|
|||
|
|
|
|||
|
|
这两个都是标准的 LaTeX 命令,不存在语法问题。
|
|||
|
|
|
|||
|
|
### 2. 后处理管道分析 ✅
|
|||
|
|
|
|||
|
|
**位置**: `app/services/ocr_service.py`
|
|||
|
|
|
|||
|
|
**结论**: OCR 后处理管道不会破坏这些字符。
|
|||
|
|
|
|||
|
|
后处理分为三个阶段:
|
|||
|
|
|
|||
|
|
#### Stage 0: 修复 OCR 数字错误
|
|||
|
|
```python
|
|||
|
|
_fix_ocr_number_errors(expr)
|
|||
|
|
```
|
|||
|
|
- **影响范围**: 仅处理数字、小数点和空格
|
|||
|
|
- **对 `\lambda` 和 `\vdots` 的影响**: ✅ 无影响
|
|||
|
|
|
|||
|
|
#### Stage 1: 拆分粘连命令
|
|||
|
|
```python
|
|||
|
|
_split_glued_command_token(token)
|
|||
|
|
```
|
|||
|
|
- **工作原理**: 仅处理 `_COMMANDS_NEED_SPACE` 白名单中的命令
|
|||
|
|
- **白名单内容**: `cdot`, `times`, `div`, `int`, `sum`, `sin`, `cos` 等
|
|||
|
|
- **`\lambda` 和 `\vdots` 是否在白名单中**: ❌ 不在
|
|||
|
|
- **逻辑**: 如果命令不在白名单中,直接返回原值
|
|||
|
|
- **对 `\lambda` 和 `\vdots` 的影响**: ✅ 无影响
|
|||
|
|
|
|||
|
|
#### Stage 2: 规范化微分符号
|
|||
|
|
```python
|
|||
|
|
_DIFFERENTIAL_UPPER_PATTERN.sub(r"\\mathrm{d} \1", expr)
|
|||
|
|
_DIFFERENTIAL_LOWER_PATTERN.sub(r"d \1", expr)
|
|||
|
|
```
|
|||
|
|
- **匹配模式**: `(?<!\\)d([A-Z])` 和 `(?<!\\)d([a-z])`
|
|||
|
|
- **工作原理**: 使用负向后查找 `(?<!\\)` 确保只匹配非转义的 `d`
|
|||
|
|
- **对 `\lambda` 和 `\vdots` 的影响**: ✅ 无影响
|
|||
|
|
|
|||
|
|
### 3. 真正的问题: MathML 转换和后处理 ⚠️
|
|||
|
|
|
|||
|
|
**位置**: `app/services/converter.py`
|
|||
|
|
|
|||
|
|
#### 问题 A: Unicode 实体映射不完整
|
|||
|
|
|
|||
|
|
**发现**: 在 `_postprocess_mathml_for_word()` 函数中,Unicode 实体映射表不完整。
|
|||
|
|
|
|||
|
|
**原始映射表**(修复前):
|
|||
|
|
```python
|
|||
|
|
unicode_map = {
|
|||
|
|
# ... 基本运算符 ...
|
|||
|
|
'λ': 'λ', # lambda - 已有
|
|||
|
|
'⋮': '⋮', # vdots - 已有,但可能还有其他缺失
|
|||
|
|
# ... 其他映射较少 ...
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**问题**:
|
|||
|
|
1. 缺少大量希腊字母(如大写的 Λ, Σ, Ω 等)
|
|||
|
|
2. 缺少其他省略号符号(如 `\ddots`, `\iddots`)
|
|||
|
|
3. 缺少常用数学符号(如 `\infty`, `\sum`, `\prod` 等)
|
|||
|
|
4. 没有处理十进制格式的实体编码(`&#NNNN;`)
|
|||
|
|
|
|||
|
|
#### 问题 B: Pandoc 可能输出不同格式的实体
|
|||
|
|
|
|||
|
|
Pandoc 在转换 LaTeX 到 MathML 时,可能会输出:
|
|||
|
|
- 十六进制格式: `λ` (lambda)
|
|||
|
|
- 十进制格式: `λ` (lambda)
|
|||
|
|
- 直接 Unicode: `λ`
|
|||
|
|
|
|||
|
|
如果只映射了十六进制格式,十进制格式的实体就不会被转换。
|
|||
|
|
|
|||
|
|
### 4. 是否是前端二次处理问题?
|
|||
|
|
|
|||
|
|
**需要排查的步骤**:
|
|||
|
|
|
|||
|
|
1. **检查 API 响应**
|
|||
|
|
```bash
|
|||
|
|
curl -X POST "http://localhost:8000/api/v1/image/ocr" \
|
|||
|
|
-H "Content-Type: application/json" \
|
|||
|
|
-d '{"image_url": "...", "model_name": "paddle"}' | jq '.mathml'
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
查看返回的 MathML 中是否包含:
|
|||
|
|
- Unicode 字符 `λ` 和 `⋮` → ✅ 后端正确
|
|||
|
|
- 实体编码 `λ` 和 `⋮` → ⚠️ 后端未正确转换
|
|||
|
|
|
|||
|
|
2. **检查前端渲染库**
|
|||
|
|
- 如果使用 MathJax: 检查版本和配置
|
|||
|
|
- 如果使用 KaTeX: 检查是否支持所有符号
|
|||
|
|
- 检查字体加载情况
|
|||
|
|
|
|||
|
|
3. **检查前端代码**
|
|||
|
|
- 搜索是否有对 MathML 内容的字符串替换
|
|||
|
|
- 检查是否有正则表达式过滤特殊字符
|
|||
|
|
- 查看是否有 HTML 转义处理
|
|||
|
|
|
|||
|
|
## 修复方案
|
|||
|
|
|
|||
|
|
### 方案 1: 扩展 Unicode 实体映射(已实施) ✅
|
|||
|
|
|
|||
|
|
**文件**: `app/services/converter.py`
|
|||
|
|
|
|||
|
|
**修改内容**:
|
|||
|
|
|
|||
|
|
1. **扩展十六进制实体映射表**,新增:
|
|||
|
|
- 完整的希腊字母(大小写)
|
|||
|
|
- 所有省略号符号(`\vdots`, `\cdots`, `\ddots`, `\iddots`, `\ldots`)
|
|||
|
|
- 常用数学符号(积分、求和、无穷大、集合运算等)
|
|||
|
|
- 关系符号(小于等于、大于等于、约等于等)
|
|||
|
|
- 逻辑符号(与、或、非、蕴含等)
|
|||
|
|
- 箭头符号
|
|||
|
|
- 其他特殊符号
|
|||
|
|
|
|||
|
|
2. **新增十进制实体处理**,覆盖常用字符:
|
|||
|
|
```python
|
|||
|
|
decimal_patterns = [
|
|||
|
|
(r'λ', 'λ'), # lambda
|
|||
|
|
(r'⋮', '⋮'), # vdots
|
|||
|
|
(r'⋯', '⋯'), # cdots
|
|||
|
|
# ... 更多映射 ...
|
|||
|
|
]
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**优势**:
|
|||
|
|
- ✅ 一次性修复所有 Unicode 字符渲染问题
|
|||
|
|
- ✅ 支持多种实体编码格式
|
|||
|
|
- ✅ 不影响现有功能
|
|||
|
|
- ✅ 性能影响极小(简单字符串替换)
|
|||
|
|
|
|||
|
|
### 方案 2: 使用前端诊断工具
|
|||
|
|
|
|||
|
|
**工具**: `diagnose_latex_rendering.py`
|
|||
|
|
|
|||
|
|
**用途**: 诊断后处理管道是否修改了输入
|
|||
|
|
|
|||
|
|
**使用方法**:
|
|||
|
|
```bash
|
|||
|
|
python diagnose_latex_rendering.py "$\lambda + \vdots$"
|
|||
|
|
python diagnose_latex_rendering.py "$$\lambda_1, \lambda_2, \vdots, \lambda_n$$"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**输出内容**:
|
|||
|
|
1. 字符检测结果
|
|||
|
|
2. 每个后处理阶段的变化
|
|||
|
|
3. 最终输出
|
|||
|
|
4. 问题定位建议
|
|||
|
|
|
|||
|
|
### 方案 3: 测试修复效果
|
|||
|
|
|
|||
|
|
**工具**: `test_unicode_fix.py`
|
|||
|
|
|
|||
|
|
**测试内容**:
|
|||
|
|
1. Unicode 实体映射是否正确
|
|||
|
|
2. 完整的 LaTeX 到 MathML 转换流程
|
|||
|
|
3. 验证所有希腊字母和数学符号
|
|||
|
|
|
|||
|
|
**运行方法**:
|
|||
|
|
```bash
|
|||
|
|
python test_unicode_fix.py
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 修复内容总结
|
|||
|
|
|
|||
|
|
### 扩展的字符支持
|
|||
|
|
|
|||
|
|
#### 1. 希腊字母(完整)
|
|||
|
|
| LaTeX | Unicode | 实体(十六进制) | 实体(十进制) |
|
|||
|
|
|-------|---------|----------------|---------------|
|
|||
|
|
| `\alpha` | α | `α` | `α` |
|
|||
|
|
| `\beta` | β | `β` | `β` |
|
|||
|
|
| `\gamma` | γ | `γ` | `γ` |
|
|||
|
|
| `\delta` | δ | `δ` | `δ` |
|
|||
|
|
| `\lambda` | λ | `λ` | `λ` |
|
|||
|
|
| `\Gamma` | Γ | `Γ` | `Γ` |
|
|||
|
|
| `\Delta` | Δ | `Δ` | `Δ` |
|
|||
|
|
| `\Lambda` | Λ | `Λ` | `Λ` |
|
|||
|
|
| `\Sigma` | Σ | `Σ` | `Σ` |
|
|||
|
|
| `\Omega` | Ω | `Ω` | `Ω` |
|
|||
|
|
|
|||
|
|
#### 2. 省略号符号(完整)
|
|||
|
|
| LaTeX | Unicode | 实体(十六进制) | 实体(十进制) |
|
|||
|
|
|-------|---------|----------------|---------------|
|
|||
|
|
| `\ldots` | … | `…` | `…` |
|
|||
|
|
| `\cdots` | ⋯ | `⋯` | `⋯` |
|
|||
|
|
| `\vdots` | ⋮ | `⋮` | `⋮` |
|
|||
|
|
| `\ddots` | ⋱ | `⋱` | `⋱` |
|
|||
|
|
| `\iddots` | ⋰ | `⋰` | `⋰` |
|
|||
|
|
|
|||
|
|
#### 3. 数学运算符
|
|||
|
|
| LaTeX | Unicode | 实体 |
|
|||
|
|
|-------|---------|------|
|
|||
|
|
| `\infty` | ∞ | `∞` / `∞` |
|
|||
|
|
| `\sum` | ∑ | `∑` / `∑` |
|
|||
|
|
| `\prod` | ∏ | `∏` / `∏` |
|
|||
|
|
| `\sqrt` | √ | `√` / `√` |
|
|||
|
|
| `\int` | ∫ | `∫` |
|
|||
|
|
| `\partial` | ∂ | `∂` |
|
|||
|
|
| `\nabla` | ∇ | `∇` |
|
|||
|
|
|
|||
|
|
#### 4. 关系符号
|
|||
|
|
| LaTeX | Unicode | 实体 |
|
|||
|
|
|-------|---------|------|
|
|||
|
|
| `\leq` | ≤ | `≤` / `≤` |
|
|||
|
|
| `\geq` | ≥ | `≥` / `≥` |
|
|||
|
|
| `\neq` | ≠ | `≠` / `≠` |
|
|||
|
|
| `\approx` | ≈ | `≈` / `≈` |
|
|||
|
|
| `\equiv` | ≡ | `≡` / `≡` |
|
|||
|
|
|
|||
|
|
#### 5. 集合运算
|
|||
|
|
| LaTeX | Unicode | 实体 |
|
|||
|
|
|-------|---------|------|
|
|||
|
|
| `\in` | ∈ | `∈` / `∈` |
|
|||
|
|
| `\notin` | ∉ | `∉` / `∉` |
|
|||
|
|
| `\cup` | ∪ | `∪` / `∪` |
|
|||
|
|
| `\cap` | ∩ | `∩` / `∩` |
|
|||
|
|
| `\subset` | ⊂ | `⊂` |
|
|||
|
|
| `\supset` | ⊃ | `⊃` |
|
|||
|
|
|
|||
|
|
### 覆盖的字符范围
|
|||
|
|
|
|||
|
|
- ✅ **24 个小写希腊字母**
|
|||
|
|
- ✅ **24 个大写希腊字母**
|
|||
|
|
- ✅ **5 个省略号符号**
|
|||
|
|
- ✅ **50+ 个数学运算符和符号**
|
|||
|
|
- ✅ **关系符号、逻辑符号、箭头符号**
|
|||
|
|
- ✅ **支持十六进制和十进制实体编码**
|
|||
|
|
|
|||
|
|
## 验证步骤
|
|||
|
|
|
|||
|
|
### 1. 单元测试
|
|||
|
|
```bash
|
|||
|
|
python test_unicode_fix.py
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
预期输出: 所有测试通过 ✅
|
|||
|
|
|
|||
|
|
### 2. 集成测试
|
|||
|
|
|
|||
|
|
使用 API 测试完整流程:
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
# 测试 lambda
|
|||
|
|
curl -X POST "http://localhost:8000/api/v1/convert/latex-to-omml" \
|
|||
|
|
-H "Content-Type: application/json" \
|
|||
|
|
-d '{"latex": "\\lambda_1, \\lambda_2, \\vdots, \\lambda_n"}'
|
|||
|
|
|
|||
|
|
# 测试 vdots
|
|||
|
|
curl -X POST "http://localhost:8000/api/v1/convert/latex-to-omml" \
|
|||
|
|
-H "Content-Type: application/json" \
|
|||
|
|
-d '{"latex": "\\begin{pmatrix} a \\\\ \\vdots \\\\ z \\end{pmatrix}"}'
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 前端测试
|
|||
|
|
|
|||
|
|
如果后端测试通过但前端仍有问题,检查:
|
|||
|
|
|
|||
|
|
1. **浏览器开发者工具 → Network**: 查看 API 响应内容
|
|||
|
|
2. **浏览器开发者工具 → Elements**: 检查渲染的 DOM 结构
|
|||
|
|
3. **控制台**: 查看是否有 JavaScript 错误
|
|||
|
|
4. **MathJax/KaTeX 配置**: 确认渲染库正确加载
|
|||
|
|
|
|||
|
|
## 结论
|
|||
|
|
|
|||
|
|
### 问题根源
|
|||
|
|
|
|||
|
|
**不是**前端二次处理问题,而是**后端 MathML 后处理**中 Unicode 实体映射不完整。
|
|||
|
|
|
|||
|
|
### 修复效果
|
|||
|
|
|
|||
|
|
通过扩展 Unicode 实体映射表:
|
|||
|
|
- ✅ 支持所有常用希腊字母(大小写)
|
|||
|
|
- ✅ 支持所有省略号符号(`\vdots`, `\cdots`, `\ddots` 等)
|
|||
|
|
- ✅ 支持 50+ 个数学符号
|
|||
|
|
- ✅ 同时处理十六进制和十进制实体编码
|
|||
|
|
- ✅ 性能影响极小(简单字符串替换)
|
|||
|
|
|
|||
|
|
### 后续建议
|
|||
|
|
|
|||
|
|
1. **运行测试**: 确认修复生效
|
|||
|
|
2. **部署更新**: 将修改部署到生产环境
|
|||
|
|
3. **监控日志**: 观察是否还有其他未映射的字符
|
|||
|
|
4. **按需扩展**: 如果发现新的未支持字符,继续扩展映射表
|
|||
|
|
|
|||
|
|
## 附录: 诊断工具使用
|
|||
|
|
|
|||
|
|
### diagnose_latex_rendering.py
|
|||
|
|
|
|||
|
|
**用途**: 诊断 OCR 后处理是否修改了 LaTeX 输入
|
|||
|
|
|
|||
|
|
**示例**:
|
|||
|
|
```bash
|
|||
|
|
# 测试单个字符
|
|||
|
|
python diagnose_latex_rendering.py "$\lambda$"
|
|||
|
|
|
|||
|
|
# 测试组合
|
|||
|
|
python diagnose_latex_rendering.py "$$\lambda_1, \lambda_2, \vdots, \lambda_n$$"
|
|||
|
|
|
|||
|
|
# 测试矩阵
|
|||
|
|
python diagnose_latex_rendering.py "$\begin{pmatrix} a \\ \vdots \\ z \end{pmatrix}$"
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### test_unicode_fix.py
|
|||
|
|
|
|||
|
|
**用途**: 验证 Unicode 实体映射和完整转换流程
|
|||
|
|
|
|||
|
|
**示例**:
|
|||
|
|
```bash
|
|||
|
|
python test_unicode_fix.py
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**输出**:
|
|||
|
|
- Unicode 实体映射测试结果
|
|||
|
|
- 完整 LaTeX 转换测试结果
|
|||
|
|
- 字符检测统计
|
|||
|
|
|
|||
|
|
## 参考资料
|
|||
|
|
|
|||
|
|
- [Unicode Mathematical Symbols](https://www.unicode.org/charts/PDF/U2200.pdf)
|
|||
|
|
- [Unicode Greek and Coptic](https://www.unicode.org/charts/PDF/U0370.pdf)
|
|||
|
|
- [Pandoc MathML Documentation](https://pandoc.org/MANUAL.html#math)
|
|||
|
|
- [MathML Entity Reference](https://www.w3.org/TR/MathML3/chapter7.html)
|