Files
doc_processer/docs/LATEX_RENDERING_ISSUE.md
2026-02-05 13:18:55 +08:00

8.6 KiB
Raw Blame History

LaTeX 字符渲染问题诊断与解决方案

问题描述

识别完成后,某些 LaTeX 字符(如 \lambda\vdots)没有被成功渲染。

问题诊断

1. LaTeX 语法检查

\lambda\vdots 都是标准的 LaTeX 命令,语法完全正确:

  • \lambda - 希腊字母 λ (Unicode: U+03BB)
  • \vdots - 垂直省略号 ⋮ (Unicode: U+22EE)

2. 后处理管道分析

经过代码审查OCR 后处理管道(app/services/ocr_service.py不会破坏这些字符:

Stage 0: 数字错误修复

_fix_ocr_number_errors(expr)
  • 影响范围: 仅处理数字和小数点
  • \lambda\vdots 的影响: 无影响

Stage 1: 粘连命令拆分

_split_glued_command_token(token)
  • 影响范围: 仅处理 _COMMANDS_NEED_SPACE 白名单中的命令
  • 白名单内容: cdot, times, div, pm, mp, int, sum, sin, cos, 等
  • \lambda\vdots 是否在白名单中: 不在
  • \lambda\vdots 的影响: 无影响(直接返回原始值)

Stage 2: 微分规范化

_DIFFERENTIAL_UPPER_PATTERN.sub(r"\\mathrm{d} \1", expr)
_DIFFERENTIAL_LOWER_PATTERN.sub(r"d \1", expr)
  • 影响范围: 匹配非转义的 d 字符(使用 (?<!\\) 负向后查找)
  • \lambda\vdots 的影响: 无影响(都不包含非转义的 d

结论: 后处理管道不会修改 \lambda\vdots

3. 可能的问题来源 ⚠️

既然后处理没有问题,问题可能出在以下环节:

A. Pandoc 转换问题

位置: app/services/converter.py_latex_to_mathml_cached()

mathml_html = pypandoc.convert_text(
    f"${latex_formula}$",
    "html",
    format="markdown+tex_math_dollars",
    extra_args=["--mathml"],
)

可能的问题:

  1. Pandoc 版本过低,不支持某些 Unicode 字符
  2. Pandoc 的 MathML 输出使用实体编码而非 Unicode 字符
  3. 字体映射表缺失

B. MathML 后处理问题

位置: app/services/converter.py_postprocess_mathml_for_word()

这个函数对 MathML 进行了大量后处理,可能误删了某些内容:

# Step 1: Remove <semantics> and <annotation> wrappers
# Step 2: Remove unnecessary attributes
# Step 3: Remove redundant single <mrow> wrapper
# Step 7: Decode common Unicode entities

问题点: Step 7 的 Unicode 实体解码可能不完整:

unicode_map = {
    '&#x0002B;': '+',
    '&#x0002D;': '-',
    # ... more mappings
    '&#x03BB;': 'λ',  # lambda
    '&#x03BC;': 'μ',
    # ...
}

发现: 代码中已经包含了 λ (U+03BB) 的映射,但没有 (U+22EE, vdots) 的映射!

C. 前端渲染问题

如果后端返回的 LaTeX/MathML 是正确的,但前端显示不出来:

  1. MathJax/KaTeX 配置问题

    • 可能使用的是旧版本
    • 宏定义缺失
    • 字体加载失败
  2. 字体文件缺失

    • 希腊字母需要数学字体支持
    • 可能缺少 STIX、Latin Modern Math 等字体
  3. 前端二次处理

    • 前端可能对特殊字符进行了转义或过滤
    • 可能使用了不当的正则表达式替换

解决方案

方案 1: 扩展 Unicode 实体映射(后端修复)

如果问题在于 MathML 后处理阶段,需要扩展 unicode_map

# 在 app/services/converter.py 的 _postprocess_mathml_for_word() 中添加:
unicode_map = {
    # ... 现有映射 ...
    
    # 希腊字母(小写)
    '&#x03B1;': 'α',  # alpha
    '&#x03B2;': 'β',  # beta
    '&#x03B3;': 'γ',  # gamma
    '&#x03B4;': 'δ',  # delta
    '&#x03B5;': 'ε',  # epsilon
    '&#x03B6;': 'ζ',  # zeta
    '&#x03B7;': 'η',  # eta
    '&#x03B8;': 'θ',  # theta
    '&#x03B9;': 'ι',  # iota
    '&#x03BA;': 'κ',  # kappa
    '&#x03BB;': 'λ',  # lambda
    '&#x03BC;': 'μ',  # mu
    '&#x03BD;': 'ν',  # nu
    '&#x03BE;': 'ξ',  # xi
    '&#x03BF;': 'ο',  # omicron
    '&#x03C0;': 'π',  # pi
    '&#x03C1;': 'ρ',  # rho
    '&#x03C3;': 'σ',  # sigma
    '&#x03C4;': 'τ',  # tau
    '&#x03C5;': 'υ',  # upsilon
    '&#x03C6;': 'φ',  # phi
    '&#x03C7;': 'χ',  # chi
    '&#x03C8;': 'ψ',  # psi
    '&#x03C9;': 'ω',  # omega
    
    # 希腊字母(大写)
    '&#x0393;': 'Γ',  # Gamma
    '&#x0394;': 'Δ',  # Delta
    '&#x0398;': 'Θ',  # Theta
    '&#x039B;': 'Λ',  # Lambda
    '&#x039E;': 'Ξ',  # Xi
    '&#x03A0;': 'Π',  # Pi
    '&#x03A3;': 'Σ',  # Sigma
    '&#x03A5;': 'Υ',  # Upsilon
    '&#x03A6;': 'Φ',  # Phi
    '&#x03A8;': 'Ψ',  # Psi
    '&#x03A9;': 'Ω',  # Omega
    
    # 数学符号
    '&#x22EE;': '⋮',  # vdots (垂直省略号)
    '&#x22EF;': '⋯',  # cdots (中间省略号)
    '&#x22F0;': '⋰',  # addots (对角省略号)
    '&#x22F1;': '⋱',  # ddots (对角省略号)
    '&#x2026;': '…',  # ldots (水平省略号)
    '&#x2205;': '∅',  # emptyset
    '&#x2208;': '∈',  # in
    '&#x2209;': '∉',  # notin
    '&#x220B;': '∋',  # ni
    '&#x2211;': '∑',  # sum
    '&#x220F;': '∏',  # prod
    '&#x221A;': '√',  # sqrt
    '&#x221E;': '∞',  # infty
    '&#x2229;': '∩',  # cap
    '&#x222A;': '',  # cup
    '&#x2282;': '⊂',  # subset
    '&#x2283;': '⊃',  # supset
    '&#x2286;': '⊆',  # subseteq
    '&#x2287;': '⊇',  # supseteq
    '&#x2264;': '≤',  # leq
    '&#x2265;': '≥',  # geq
    '&#x2260;': '≠',  # neq
    '&#x2248;': '≈',  # approx
    '&#x2261;': '≡',  # equiv
    '&#x00D7;': '×',  # times
    '&#x00F7;': '÷',  # div
    '&#x00B1;': '±',  # pm
}

方案 2: 检查前端渲染(前端修复)

如果后端返回正确,需要检查前端:

步骤 1: 验证后端输出

使用诊断工具检查后端返回的内容:

python diagnose_latex_rendering.py "$\lambda + \vdots$"

或者直接调用 API 并检查响应:

curl -X POST "http://localhost:8000/api/v1/image/ocr" \
  -H "Content-Type: application/json" \
  -d '{"image_url": "...", "model_name": "paddle"}' | jq

检查返回的 latexmathmlmml 字段是否包含正确的字符。

步骤 2: 检查前端配置

如果使用 MathJax:

MathJax = {
  tex: {
    inlineMath: [['$', '$'], ['\\(', '\\)']],
    displayMath: [['$$', '$$'], ['\\[', '\\]']],
    processEscapes: true,
    processEnvironments: true,
  },
  svg: {
    fontCache: 'global'
  },
  options: {
    enableMenu: false
  }
};

如果使用 KaTeX:

renderMathInElement(document.body, {
  delimiters: [
    {left: '$$', right: '$$', display: true},
    {left: '$', right: '$', display: false},
    {left: '\\[', right: '\\]', display: true},
    {left: '\\(', right: '\\)', display: false}
  ],
  throwOnError: false
});

步骤 3: 检查字体加载

确保加载了数学字体:

<!-- MathJax -->
<script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>

<!-- 或 KaTeX -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css">
<script src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js"></script>

方案 3: 禁用有问题的后处理(临时解决)

如果确认是 MathML 后处理导致的问题,可以临时禁用部分后处理:

# 在 app/services/converter.py 中
@staticmethod
def _postprocess_mathml_for_word(mathml: str) -> str:
    # 跳过所有后处理,直接返回原始 MathML
    return mathml

使用诊断工具

我已经创建了一个诊断工具 diagnose_latex_rendering.py,使用方法:

# 测试单个字符
python diagnose_latex_rendering.py "$\lambda$"
python diagnose_latex_rendering.py "$\vdots$"

# 测试组合
python diagnose_latex_rendering.py "$$\lambda_1, \lambda_2, \vdots, \lambda_n$$"

# 测试矩阵
python diagnose_latex_rendering.py "$\begin{pmatrix} a \\ \vdots \\ z \end{pmatrix}$"

工具会输出:

  1. 字符检测结果
  2. 每个后处理阶段的变化
  3. 最终输出
  4. 问题定位建议

推荐的调试流程

  1. 运行诊断工具,确认后处理阶段是否修改了输入
  2. 检查 API 响应,确认后端返回的内容是否正确
  3. 检查前端渲染,使用浏览器开发者工具查看实际渲染的内容
  4. 根据问题位置,应用相应的解决方案

总结

根据代码分析:

  • LaTeX 语法正确
  • OCR 后处理不会破坏这些字符
  • ⚠️ 可能的问题:
    • MathML Unicode 实体映射不完整(缺少 \vdots 等字符)
    • Pandoc 转换配置问题
    • 前端渲染或二次处理问题

建议先使用诊断工具确定问题位置,然后应用相应的解决方案。