Commit Graph

6 Commits

Author SHA1 Message Date
93d070930a fix(omml2latex): fragmented-function 前缀匹配,修复 sinx 误输出
mrow_visitor 的 _check_fragmented_function_at_position 把所有连续单字母
拼成整串后只查整串是否在 MATH_FUNCTIONS,导致 <mi>s</mi><mi>i</mi><mi>n</mi>
<mi>x</mi> 输出 'sinx' 而非 '\sin x'。

改为前缀匹配(对齐 legacy_adapter._check_fragmented_function_at_level),
从最长到最短找已知函数名,只消耗函数名对应字母,其余留给调用方。

验证:sinx/cosx/tanx → \sin x/\cos x/\tan x;纯 sin/log、log_2(msub)、
BC 拼接、abc 非函数等场景零回归;test_mixed.docx 130 公式输出不变。
2026-10-15 01:27:13 +08:00
d4c2fd1fca fix(omml2latex): 修复多字母标识符被拆开的问题
OMML2MML 会把 Word 里连写的多字母标识符(线段名 BC、三角形 △ABC、
角度 45° 等)拆成相邻的 <mi>/<mn> 元素,原转换器用空格 join 导致
'BC' 被渲染成 'B C'(B×C),'45°' 变成 '4 5°'。

三处修复:
- mrow_visitor: 连续单字母 <mi> 拼接
- legacy_adapter: <math> 根节点多子元素时连续单字母 <mi> 拼接
- math_strategy: Unicode+字母混合内容按'LaTeX命令后跟字母才加空格'规则 join

回归验证:test_mixed.docx 130 个 OMML 公式,16 个发生变化且全部为
正确改善(线段名/角度/三角形/隐式乘法拼接),零误伤。
2026-10-15 01:01:10 +08:00
b00f8d7f46 config: 直接提交 application.yml(删 .example 模板)
- 删除 .gitignore 对 application.yml 的忽略
- 删除 application.yml.example 和 application.yml.bak-pua
- 提交真实配置(rustfsadmin 凭证)用于直接部署
2026-10-12 10:13:36 +08:00
6071a2d98c feat(symbol): 正文标准 Unicode 数学符号 → LaTeX(与公式同一条渲染路径)
背景:公式(OMML/MathType/EQ)已转 LaTeX,但正文里的裸 Unicode 符号
(⊆ ∈ ∪ ≤ × → ∅ ∞ ∑ √ …)docx4j 只原样输出,靠系统字体渲染,字形/字号
与公式不一致;且 EqToLatexUtil 未覆盖的符号会以裸字符留在公式 LaTeX 内部。

实现 UnicodeSymbolLatex:
- 53 条映射,取自 jby omml_mathml2latex/data/symbols.py,保证与公式内转换一致
  (⊆→\subseteq、∈→\in、≤→\leqslant、×→\times、→→\rightarrow、∅→\emptyset …)
- 文本节点内:符号 → \( … \)(MathJax 渲染)
- 已在 \(…\)/\[…\] 内的片段:只换命令不加包裹(修 LaTeX 内部裸字符)
- 跳过 <script>/<style>/<textarea> 与所有标签属性
- 开关 wordparse.convert-unicode-symbols(默认 true)

效果:46 份教辅重新生成后,正文裸 Unicode 符号 0 处,公式片段 5394 处
2026-09-29 15:33:33 +08:00
09c58defa3 fix(symbol): 私有区(PUA)数学符号处理修复 + 去掉 jby CDN 依赖
问题:docx 里的私有区符号(教辅排版软件把 ⊆/⇌ 等写成 PUA)输出成豆腐块。
实测语料:46 份教辅里 \ue089 共 11 处(3 份文件)全部丢失。

根因:
1. SYMBOL 数组沿用反编译产物的字面量写法 {"\\ue0fc", "\\ue100", "\\ue101"}
   (反斜杠+ue0fc 共 7 字符),而文档里是 1 个 PUA 字符,replace 永远不命中
   → 整个符号占位符机制从未生效;连带 sym.substring(2) 在真字符下取不到编号。
2. 只有 3 个硬编码码位,没有通用 PUA→Unicode 映射。

修复:
- SYMBOL 改为真 PUA 字符;编号统一走 symbolCode()(%04X,与 static/symbols 文件名一致)
- 新增 PUA_TO_UNICODE(证据驱动):\ue089 → ⊆
- 新增 warnUnknownPua():扫描 E000–F8FF 未映射码位并 WARN,便于持续扩充
- 新增配置 wordparse.symbol-base-url(默认我们自己的 RustFS
  https://fs.code-lab.cn/temp/wordparse-symbols/),不再引用 resource.xinjiaoyu.com
- ⇌(\ue225\ue226)替换移出循环体

验证:含真 PUA 字节的 docx 过服务后 —— E0FC/E100/E101 输出我们托管的 svg 图、
\ue089→⊆、\ue225\ue226→\(\rightleftharpoons\)、标准 ⊆ 原样保留、残留 PUA=0;
3 份受影响教辅已重新生成并覆盖线上(exercise-html3)
2026-09-29 15:19:58 +08:00
3271fee5cc init: WordFileParse docx→HTML 解析服务(含 Word EQ 域公式修复)
服务:Spring Boot 3.2 + docx4j 8.3.9,POST /api/v3/server_office_file/file/parse
      接受 .docx,返回 HTML(公式 → LaTeX,图片 → RustFS 外链)

公式支持三类来源:
- OMML(Word 2007+ 公式)      → Python omml_mathml2latex
- MathType OLE 对象            → Ruby mathtype2mathml → MathML → LaTeX
- Word EQ 域(老教辅主力)      → EqToLatexUtil(本次新增)

本次改动:
1. 新增 java-svc/.../core/EqToLatexUtil.java:
   移植自 jby backend-services office-core,EQ 语法 → LaTeX
   (\f→\dfrac、\r→\sqrt、\i→\int/\sum/\prod、\s→^{}/_{}、\b→\left\right、
     \a→array、\x→\boxed/\overline、\o\al 堆叠、圈码、化学符号、极限、连等式)
   品牌标记 JBYU* → WPU*,与采集端一致
2. CtoMathFinder:接上 EQ 分支(原为 not-ported 桩),域代码经
   EqToLatexUtil.convert 转 LaTeX 写入 eqLatexMap(WPEQNUM 占位符)
3. WordParseUtil.dealPlaceholder:EQ 的 LaTeX 同样加 \( \) 包裹
   (原先因 WPEQNUM 例外不加包裹,前端/MathJax 不渲染)

修前症状:教辅 Word 里分式/方程组/上下标整段丢失(如 {−1/3, 1} 变成 {-,1})
修后实测:46 份教辅 2908 处 EQ 域全部还原,公式总数 2954 处、零未包裹残留

安全:application.yml(含 RustFS 密钥)不入库,提供 application.yml.example;
      OssService 的 @Value 默认密钥已清空
2026-09-29 09:43:13 +08:00