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

8.2 KiB
Raw Permalink Blame History

禁用微分规范化功能 - 防止破坏 LaTeX 命令

问题根源

用户发现 LaTeX 命令被错误拆分:

  • \vdots\vd ots
  • \lambda_{1}\lambd a_{1}

根本原因是 Stage 2 的微分规范化功能过于激进,会匹配和修改任何 d + 字母的组合。

设计缺陷分析

原始设计意图

微分规范化的目标是处理 OCR 识别的微分符号,例如:

  • dxd x (添加空格)
  • dyd y
  • dV\mathrm{d} V (大写用 mathrm)

为什么这个设计有问题

1. 无法区分上下文

dx 可能是:

  • 微分符号:\int f(x) dx
  • 变量名:let dx = x_2 - x_1
  • 下标:x_{dx}
  • 函数名的一部分

正则表达式无法理解语义,只能盲目匹配。

2. 破坏 LaTeX 命令

任何包含 d + 字母的 LaTeX 命令都会被破坏:

命令 内部匹配 破坏结果
\vdots do \vd ots
\lambda da \lambd a
\delta de \d elta
\cdots do \cd ots
\ldots do \ld ots
\iddots do \idd ots

即使添加了 (?<![a-zA-Z]) 也只是部分解决,因为还有其他风险。

3. 误判率极高

在数学表达式中,d + 字母的组合非常常见:

  • 变量名:dx, dy, dz, dr, ds, dt, du, dv, dw
  • 下标:x_{d}, y_{dx}
  • 自定义符号:d_1, d_2
  • 物理量:dE (能量变化), dP (压强变化)

无法可靠区分哪些是微分,哪些是变量名。

解决方案:禁用微分规范化

修改内容

文件: app/services/ocr_service.py

修改 1: 更新正则表达式(增加前后保护)

# 旧版本(仍然有风险)
_DIFFERENTIAL_LOWER_PATTERN = re.compile(r"(?<!\\)(?<![a-zA-Z])d([a-z])")

# 新版本(增加后向保护,但仍然禁用)
_DIFFERENTIAL_LOWER_PATTERN = re.compile(r"(?<!\\)(?<![a-zA-Z])d([a-z])(?![a-zA-Z])")

修改 2: 禁用微分规范化

def _postprocess_math(expr: str) -> str:
    """Postprocess a *math* expression (already inside $...$ or $$...$$)."""
    # stage0: fix OCR number errors
    expr = _fix_ocr_number_errors(expr)
    
    # stage1: split glued command tokens
    expr = _COMMAND_TOKEN_PATTERN.sub(
        lambda m: _split_glued_command_token(m.group(0)), expr
    )
    
    # stage2: differential normalization - DISABLED
    # (commented out to avoid false positives)
    
    return expr

为什么选择禁用而不是修复

成本收益分析

如果启用:

  • 小收益:某些微分符号格式更规范
  • 高风险:破坏 LaTeX 命令、变量名、下标等

如果禁用:

  • 小损失:微分符号可能没有空格(但仍然是有效的 LaTeX
  • 高收益:所有 LaTeX 命令和变量名都安全

结论: 禁用是更安全、更保守的选择。

微分符号即使不加空格也是有效的

\int dx        % 有效
\int d x       % 有效(规范化后)

两者在渲染时效果相同OCR 输出 dx 不加空格完全可以接受。

保留的功能

Stage 0: 数字错误修复 保留

修复 OCR 数字识别错误:

  • 2 2. 222.2
  • 1 5 0150

保留原因: 这是明确的错误修复,误判率极低。

Stage 1: 拆分粘连命令 保留

修复 OCR 识别的粘连命令:

  • \intdx\int dx
  • \cdotdS\cdot dS

保留原因:

  • 基于白名单,只处理已知的命令
  • 粘连是明确的 OCR 错误
  • 误判率低

Stage 2: 微分规范化 禁用

禁用原因:

  • 无法区分微分和变量名
  • 破坏 LaTeX 命令
  • 误判率高
  • 收益小

替代方案(可选)

如果确实需要微分规范化,我们提供了一个上下文感知的版本:

def _normalize_differentials_contextaware(expr: str) -> str:
    """Context-aware differential normalization.
    
    Only normalizes in specific safe contexts:
    1. After integral symbols: \\int dx → \\int d x
    2. In fraction denominators: \\frac{dy}{dx}\\frac{dy}{d x}
    """
    # Pattern 1: After integral commands
    integral_pattern = re.compile(
        r'(\\i+nt|\\oint)\s*([^\\]*?)\s*d([a-zA-Z])(?![a-zA-Z])'
    )
    expr = integral_pattern.sub(r'\1 \2 d \3', expr)
    
    # Pattern 2: In fraction denominators
    frac_pattern = re.compile(
        r'(\\frac\{[^}]*\}\{[^}]*?)d([a-zA-Z])(?![a-zA-Z])([^}]*\})'
    )
    expr = frac_pattern.sub(r'\1d \2\3', expr)
    
    return expr

特点:

  • 只在明确的数学上下文中应用(积分后、分式分母)
  • 仍然有风险,但比全局匹配安全得多
  • 默认不启用,用户可自行决定是否启用

测试验证

测试 1: LaTeX 命令不被破坏

test_cases = [
    r"\vdots",
    r"\lambda_{1}",
    r"\delta",
    r"\cdots",
    r"\ldots",
]

# 预期:全部保持不变
for expr in test_cases:
    result = _postprocess_math(expr)
    assert result == expr  # ✅ 通过

测试 2: 变量名不被修改

test_cases = [
    r"dx",
    r"dy",
    r"x_{dx}",
    r"f(x)dx",
]

# 预期:全部保持不变(因为微分规范化已禁用)
for expr in test_cases:
    result = _postprocess_math(expr)
    assert result == expr  # ✅ 通过

测试 3: OCR 错误修复仍然工作

# 数字错误修复
assert _fix_ocr_number_errors("2 2. 2") == "22.2"

# 粘连命令拆分
assert _postprocess_math(r"\intdx") == r"\int dx"

受影响的 LaTeX 命令列表

禁用微分规范化后,以下命令现在都是安全的:

包含 d 的希腊字母

  • \delta (δ)
  • \Delta (Δ)
  • \lambda (λ) - 通过下标间接受影响

包含 d 的省略号

  • \vdots (⋮) - 垂直省略号
  • \cdots (⋯) - 中间省略号
  • \ldots (…) - 水平省略号
  • \ddots (⋱) - 对角省略号
  • \iddots (⋰) - 反对角省略号

其他包含 d 的命令

  • 任何自定义命令
  • 包含 d 的变量名或函数名

部署步骤

  1. 代码已修改: app/services/ocr_service.py 已更新
  2. 验证语法: 无 linter 错误
  3. 重启服务: 重启 FastAPI 服务
  4. 测试验证:
    python test_disabled_differential_norm.py
    
  5. 前端测试: 测试包含 \vdots\lambda 的图片识别

性能影响

禁用微分规范化后:

  • 减少正则表达式匹配次数
  • 处理速度略微提升
  • 代码更简单,维护成本更低

向后兼容性

对现有用户的影响:

  • LaTeX 命令不再被破坏(改进)
  • 变量名不再被修改(改进)
  • ⚠️ 微分符号不再自动规范化(可能的退化,但实际影响很小)

评估: 总体上是正向改进,风险降低远大于功能损失。

总结

方面 状态
LaTeX 命令保护 完全保护
变量名保护 完全保护
数字错误修复 保留
粘连命令拆分 保留
微分规范化 禁用(可选的上下文感知版本可用)
误判风险 大幅降低
代码复杂度 降低

修复状态: 完成

建议:

  1. 重启服务使修改生效
  2. 测试包含 \vdots, \lambda, \delta 等命令的图片
  3. 验证不再出现命令拆分问题
  4. 如果确实需要微分规范化,可以评估启用上下文感知版本

附录:设计哲学

在 OCR 后处理中,应该遵循的原则:

应该做什么

  1. 修复明确的错误

    • OCR 数字识别错误(2 2. 222.2
    • 命令粘连错误(\intdx\int dx
  2. 基于白名单/黑名单

    • 只处理已知的情况
    • 避免泛化的模式匹配
  3. 保守而不是激进

    • 宁可不改也不要改错
    • 错误的修改比不修改更糟糕

不应该做什么

  1. 依赖语义理解

    • 无法区分微分和变量名
    • 无法理解数学上下文
  2. 全局模式匹配

    • 匹配所有 d[a-z] 过于宽泛
    • 误判率不可接受
  3. "智能"猜测

    • 除非有明确的规则,否则不要猜
    • 猜错的代价太高

核心原则: Do No Harm - 不确定的时候,不要修改。