专利公式格式转换(WPS 公式 3.0 KSEE3 / MathType / OMML)
版本与打包命名规则(v1.1.1 起)
- skill 压缩包共 3 个,文件名必须带版本号,格式:
- 标准版(含 Texo OCR 模型):
patent-formula-converter-skill-{version}.zip - 标准版 lite(不含 Texo OCR 模型,体积小、可上传):
patent-formula-converter-skill-{version}-lite.zip - 离线版(vendor 5 个 wheel + 模型):
patent-formula-converter-skill-{version}-offline.zip - 三个版本的差异:
- 标准版 = skill 主体 + Texo OCR 模型(无 vendor,联网
pip install装依赖) - lite 版 = skill 主体(无模型、无 vendor,体积最小;图片 OCR 功能自动跳过,其余公式转换正常)
- 离线版 = skill 主体 + 模型 + vendor(无网络环境可直接装依赖)
- 例如版本
1.1.1:patent-formula-converter-skill-1.1.1.zip、patent-formula-converter-skill-1.1.1-lite.zip、patent-formula-converter-skill-1.1.1-offline.zip。 - 打包脚本
scripts/pack_versioned.py会从SKILL.md的 frontmatterversion:字段自动读取版本号命名,一次性产出 3 个包。
∑/∏/∫ 等求和符号的上下限规则(v1.1.1 起)
WPS 的 m:nary(求和 ∑、连乘 ∏、积分 ∫ 等)用 <m:supHide m:val="1"/> / <m:subHide m:val="1"/> 标记隐藏的上限/下限。
- 原公式只有一个下限(如
Σ_{e∈E},supHide=1)→ 转档后只能有下限,不得多出空上限槽。 - 原公式只有一个上限(如
Σ^{n},subHide=1)→ 转档后只能有上限,不得多出空下限槽。 - 处理:
omml_to_ksee3在转 MathML 前,遍历m:nary,检测supHide/subHide(或对应槽文本为空)时删除空的m:sup/m:sub,让 omml_converter 走munder(只有下限)/mover(只有上限)而非munderover。
⚠️ 重要:.doc 文件必须先转成 .docx(复制粘贴法,不是改扩展名)
本 skill 只能处理 .docx(OOXML/zip 格式),不能直接处理 .doc(OLE2 二进制老格式)。
如果输入是 .doc,必须先转成 .docx 中间文件,且不能用改扩展名的方式(把 .doc 改名 .docx 是错的——公式会变成图片/v:shape 对象,无法正确处理)。
正确做法(复制粘贴法):
1. 用 WPS 打开 .doc 文件
2. 全选(Ctrl+A)→ 复制(Ctrl+C)
3. 新建空白 .docx 文档
4. 粘贴(Ctrl+V)
5. 另存为 .docx
为什么必须复制粘贴:WPS「另存为 docx」只是换容器,老式公式对象 v:shape + equationxml 原样保留(看着像图片);而「全选复制 → 粘贴到空白 docx」会触发公式对象的重新序列化,把老式 v:shape equationxml 转成 docx 原生的 m:oMath(OMML),这才是本 skill 能正确处理的标准格式。
> 实测:同一份 .doc,另存为得到 19 个 v:shape equationxml(v1.2.0~v1.5.2 一直在死磕这种格式,是弯路);复制粘贴后得到 18 个标准 m:oMath(OMML),v:shape 归零。
也可以用脚本自动化这一步:scripts/doc_to_docx_copy.py(WPS COM 全选复制 → 新建 → 粘贴 → 另存 docx)。
把发明人交底书或申请文件撰写稿(docx)里各种格式的公式,统一转成三种目标格式之一:
- KSEE3 OLE(
Equation.KSEE3)—— WPS 公式编辑器 3.0,双击唤起 WPS 公式编辑器。WPS 环境下的 OLE 格式。 - MathType OLE(
Equation.DSMT6)—— 微软 MathType,双击唤起 MathType 编辑器。Word 环境下的 OLE 格式。 - OMML(WPS/Word 原生公式,
Alt+=)—— 原生 XML 公式,不如 KSEE3 / MathType 稳定(见下方「格式稳定性」)。
默认自动判断:--target 未指定时,读 docProps/app.xml 的 <Application> 字段判断输入来源——WPS 来源 → KSEE3,Word 来源 → MathType;匹配不到默认按 WPS。
底层链路:
- KSEE3:OMML(or 文本公式→OMML)→ MTEF v3 → KSEE3 OLE(scripts/ksee3.py 字节级复刻真实样本)
- MathType:OMML → MathML → MTEF v5 → DSMT6 OLE(omml-converter + header 修复后处理)
- OMML:直接保留
段落处理硬约束(v1.5.0):所有公式转换步骤(vertAlign / 纯文本含数学符号 / equationxml / OMML→KSEE3 / 图片)都必须 lxml 直接解析 + deep copy 整段 <w:p> 副本,在副本上识别 + 替换,再换回原位置。不能图省事用 iter() + 同树修改——python-docx 的 p.text / cell.text 不会读 OMML,必须深拷贝段落才能脱离原树独立操作。
全程纯 Python,不启动 WPS/Word、不调 COM、不需要安装 MathType 软件。
格式稳定性:KSEE3 / MathType 比 OMML 稳定
专利代理实务经验:KSEE3(WPS 公式 3.0)和 MathType(DSMT6)比 OMML 稳定,不要默认 OMML 更稳。
- KSEE3 / MathType 是嵌入对象(OLE):公式作为整体二进制对象嵌入文档,稳定、不破坏。
- OMML 是 XML 公式:在转码、上传环节易出问题——丢失、变形、CPC 上传破坏。
因此:默认用 KSEE3 / MathType;仅在接收方明确要求原生 OMML(打开即显示的 XML 公式)时才用 --target omml。
KSEE3 与 MathType 的关系
两者都是"嵌入式公式对象"(OLE),用途相同——让公式能双击编辑,只是实现与宿主不同:
| Equation.KSEE3 | Equation.DSMT6 | |
|---|---|---|
| 归属 | WPS 公式编辑器 3.0(金山) | 微软 MathType(第三方软件) |
| 宿主环境 | WPS | Word(WPS 也能用,但需装 MathType) |
| 内部格式 | MTEF v3 | MTEF v5 |
| 双击唤起 | WPS 公式编辑器 | MathType 编辑器 |
本 skill 同时支持两者,按输入文档来源自动选择,也支持 --target 手动覆盖。
支持的输入公式格式
| 输入格式 | 示例 | 处理方式 |
|---|---|---|
| 自然语言/纯文本公式 | U_out = U_in * R2/(R1+R2)、P = I^2 * R |
mathfmt 识别并转 OMML |
| LaTeX 定界符公式 | $E=mc^2$、$$...$$ |
mathfmt 识别并转 OMML |
| 已有 OMML 公式 | WPS 自带公式编辑器(Alt+=)产生的 m:oMath |
转 KSEE3 / MathType OLE(byte 级保留数据) |
| Word 上下标文本公式(v1.2.0 新增) | E_e ∈ ℝ^(V_e × d_e)、P_dense、r_e(V_e+d_e) ≤ τV_ed_e |
vertAlign subscript/superscript + Unicode 数学符号(步骤 0 自动识别 + 转 OMML);命名式下标(P_dense)和真公式片段(E_e ∈ ℝ^...)一并识别转 OMML,再走步骤 2 转 KSEE3 / MathType |
| 含数学符号的纯文本公式(v1.4.0 新增) | e ∈ E、∈ R^{m_c × n_c} 这种含 ∈ × ≤ ≥ ± 但无下标格式的纯文本 |
步骤 -0.4 自动识别(以中文 run 为边界,避开已有公式对象段落);数学符号和字母/数字都用 m:r 包 m:t(标准 OMML 写法,v1.5.3 修正——之前误用 m:mo 导致被 omml_converter 吞掉),转 OMML |
| 表格单元格里的公式 | 上面任意一种,但嵌在表格里(body > tbl > tc > p 三层嵌套) |
v1.5.0 必须 deep copy 整段 <w:p> 副本:操作(识别 + 替换)在副本上进行,最后把副本换回原位置。原树零污染、跨段落零污染、跨表格零污染。不能图省事用 iter() + 同树修改——多段同表格时会有共享 Element 风险。 |
三种输出目标
执行命令(脚本位于本 skill 的 scripts/formula_convert.py):
python "<skill目录>/scripts/formula_convert.py" 输入.docx 输出.docx \
[--target ksee3|mathtype|omml] [--source auto|wps|word] \
[--mode inplace|extract] [--select all|high] [--wps-render] [--yes]
| 需求 | 命令参数 | 说明 |
|---|---|---|
| 自动判断(默认) | 不指定 --target |
读 app.xml 判断 WPS/Word,WPS→KSEE3、Word→MathType,匹配不到默认 WPS |
| KSEE3(WPS 公式 3.0) | --target ksee3 |
WPS 环境双击可编辑 |
| MathType(DSMT6) | --target mathtype |
Word 环境双击可编辑 |
| OMML(原生公式) | --target omml |
打开即显示,无需预览渲染 |
--source {auto,wps,word}:配合未显式指定--target时使用。auto(默认)自动检测来源;wps→KSEE3;word→MathType。--mode {inplace,extract}:inplace(默认)保留其他文字;extract只输出公式(居中+编号)。--select:文本公式识别置信度阈值。high(默认)只转高置信度候选,避免把集合名/变量名(如S1、S2)误识别成公式;all转全部识别到的公式,可能误转,需人工核对。--wps-render(可选,仅 Windows + WPS 桌面 + pywin32 + psutil):用 WPS COM 自动化模拟双击所有 KSEE3 OLE,触发真实 wmf 预览。内置「每 25 个公式杀 WPS 重建 + 两阶段兜底」分片重启策略。会强制关闭所有 WPS 窗口,检测到已运行 WPS 时需加--yes。--yes:配合--wps-render,显式确认允许强制关闭所有 WPS 窗口。- 输出路径如不指定
--report,会在输出同目录生成<输出名>.report.json报告,包含转换统计。
执行流程(大模型按此操作)
- 确认输入输出路径与目标格式:根据用户描述判断目标(不确定时用默认自动判断,或询问用户 WPS 还是 Word 环境)。
- 检查依赖:先确保
mathfmt、omml-converter、lxml、psutil已安装。未安装则执行:
bash python -m pip install mathfmt omml-converter lxml psutil
(注意必须用python -m pip,与本机python解释器保持一致。离线部署见references/setup-guide.md。) - 运行脚本:按上表命令执行转换。
- 可选 WPS 自动化(仅 Windows + WPS 桌面):加
--wps-render自动模拟双击生成 wmf 预览。需额外python -m pip install pywin32,且需--yes确认杀进程。 - 报告结果:向用户说明输出文件路径、转换统计(文本公式转 OMML 数量、OMML→OLE 数量、跳过/失败数量)。如
--select all有文本公式被误转,建议改用--select high重跑。
重要注意事项(务必告知用户)
- OLE 预览图依赖宿主软件:KSEE3/DSMT6 OLE 的
v:imagedata引用最小 WMF(34 字节,无内容),纯 Python 无法离线生成预览图。WPS/Word 打开时显示空白矩形占位框,需双击唤起编辑器才能看到真实公式,编辑保存后自动用真实 wmf 替换占位。如需"打开即看到公式",加--wps-render(仅 WPS 桌面 + Windows)。 - 不要对已转换过的文档重复运行:脚本会检测输入是否已含
Equation.KSEE3/Equation.DSMT6并告警。重复转换可能产生嵌套 OLE。 - KSEE3 / MathType 比 OMML 稳定:KSEE3 / MathType 是嵌入对象(OLE),稳定不破坏;OMML 是 XML 公式,转码/上传环节易丢失、变形、CPC 上传破坏。不要默认 OMML 更稳。默认用 KSEE3 / MathType;仅在接收方明确要求原生 OMML 时才用
--target omml。 - 表格公式:脚本用 lxml 全树遍历,正文和表格单元格内的公式都会被处理,无需特殊操作。
- 文本公式识别有边界:mathfmt 依赖启发式识别纯文本公式。典型误识别:把发明人定义的集合变量名(如
S1、S2、S3)当作公式转成 OLE。判断「不确定是否为公式的字符」遵循两条规则:① 字符带上下标(如U_out、S_1)则算作公式;② 除+和-外(这两个太常见、难判断),其他数学符号(=、×、÷、≤、≥等)连接的式子大概率是公式。本 skill 默认--select high(只转高置信度)规避误转;如需转全部识别到的候选(包括中低置信度),加--select all,但必须人工核对报告中的候选清单。 - OMML 编码字节级复刻真实样本:
scripts/ksee3.py(MTEF v3 编码 + WPS KSEE3 OLE CFB 生成)通过对照用户原始 KSEE3 OLE 的 byte 级验证,CLSID、reserved 时间戳、Mini-Stream 红黑树目录都与 WPS KSEE3 输出完全一致。 - OLE 边框:脚本已自动在 v:shape 上加
filled="f" stroked="f",OLE 不显示矩形边框线。 - KSEE3 批量渲染须分片重启:
--wps-render用 COM 逐个Activate()渲染预览,WPS 主进程扛不住连续高频激活(约 100+ 个后 COM RPC 通道崩坏、后续全失败)。脚本已内置「每 25 个公式杀 WPS 重建 + 两阶段兜底」,成功率可到 100%。不要把 BATCH_SIZE 调太大。 - WPS 绿色版 COM ProgID:绿色版是
Kwps.Application(安装版是WPS.Application),脚本已兼容两者;Kwps 不支持.Hwnd,进程 PID 用 psutil 按进程名取。 --wps-render会强杀 WPS 进程:渲染前会按进程名(wps.exe/kwps.exe 等)强制关闭所有 WPS 窗口,未保存内容会丢失。脚本已内置保护:检测到已运行的 WPS 进程时,必须加--yes才继续,否则跳过渲染并提示。运行前请先保存并关闭 WPS。--target mathtype语义已变更(v1.1.0 起):早期版本里--target mathtype实际输出 KSEE3(名不副实);现在它输出真正的 MathType DSMT6。旧用户若之前用--target mathtype是想得到 WPS 公式,请改用--target ksee3。- MathType 路径丢掉了 OMML 兜底:转 MathType(DSMT6)时会剥掉 omml-converter 的
mc:AlternateContent包装、只保留 OLE,不再带 OMML Fallback。因此 Word 若未安装 MathType 软件,公式会显示为空白占位框(不像原设计那样降级显示 OMML)。用--target mathtype前请确认接收方装了 MathType;否则用--target omml。 - vertAlign 上下标文本公式自动识别(v1.2.0 新增):脚本现在能识别 Word/WPS 里用 vertAlign subscript/superscript 格式 + Unicode 数学符号拼成的"上下标文本公式"(如
E_e ∈ ℝ^(V_e × d_e)、P_dense、r_e(V_e+d_e) ≤ τV_ed_e),自动转成 OMML 公式对象,再走步骤 2 转 KSEE3 / MathType。所有含 vertAlign 的"标准下标结构"都按公式处理(命名式下标P_dense也会一并转)。表单字段段落(含中文 vertAlign,如"发明"中的"明"字下标)会自动跳过,不会被误转。 - WPS VML+equationxml 公式提取(v1.3.0 新增):WPS 写的交底书常把公式嵌在
<v:shape>的equationxml属性里(OMML 藏在 VML 里)。脚本现在能识别 v:shape 里的 equationxml、提取m:oMath、转 KSEE3 OLE 替换 v:shape。这是青砚等 WPS 文档的关键能力——之前完全漏掉。 - 图片公式 OCR(v1.3.0 新增,可选):扫描 docx 里
word/media/*.png图片,用 Texo OCR(76MB ONNX 模型,纯 onnxruntime 推理,无 torch 依赖)识别为 LaTeX,再走 latex2mathml → ksee3 链路。模型随 skill 打包(在models/目录)。适用于真图片公式(流程图/架构图不会被误转,因为不含数学符号)。 - 含数学符号的纯文本公式识别(v1.4.0 新增):扫描段落里含
∈ × ≤ ≥ ± τ ℝ等数学符号但无 vertAlign / 无 v:shape equationxml 的纯文本片段(以中文 run 为边界),转成 OMML 公式对象(数学符号用 m:mo,字母/数字用 m:r)。这就是 v1.1.1 时你提的"数学符号连接大概率公式"那部分,现在在 v1.4.0 真正落地了。注意:会避开已有公式对象(m:oMath / v:shape / w:object)的段落,避免重复。 - 段落级 deep copy 是硬约束(v1.5.0 新增):所有公式转换步骤都必须 deep copy 整段
<w:p>副本,在副本上做识别 + 替换,再把副本换回原位置。这不是可选优化,是必须做的事——理由如下:
- python-docx 的 p.text 不会读 OMML——Paragraph.text属性只提取<w:t>文本,公式对象m:oMath/v:shape都被吞掉;
- cell.text 同样不会读 OMML——表格单元格(tbl > tc > p)的公式对象在 python-docx 里同样被吞;
- 所以必须用 lxml 直接解析源 document.xml,再深拷贝<w:p>元素——只有 deep copy 才能让段落脱离原树独立操作,又保留完整 OMML/VML 上下文。
- 旧版本用iter()遍历 + 同树修改的捷径不可靠:多段落同一表格时会有共享底层 Element 的风险,已在 v1.5.0 改为按「段落 → 该段落内 oMath 列表」分组、每段落一次性 deep copy + 一次性替换所有 oMath。原树零污染、跨段落零污染、跨表格零污染。 - 公式渲染正确的关键(v1.5.1 修复):以下 3 个 bug 会让 KSEE3 OLE 渲染错位,必须全部修复:
- equationxml_to_ksee3 必须先 OMML→MathML 再 MTEF:
ksee3.mathml_to_mtef3()只认 MathML 命名空间(msub/msup/msubsup),传 OMML 元素(m:sSub/m:sSup)会被吞掉所有 sub/sup 模板,渲染成Ee∈RV_ed_e水平堆叠。修复:第 337 行mtef = ksee3.mathml_to_mtef3(omml_to_mathml(omath))。 - text_math_to_omml 必须跳过含 vertAlign 的段落:避免与步骤 0 vertAlign 重复处理,把整段所有数学符号合成一个大公式片段,产生
Ee ∈e Ve×de这种乱码。修复:开头加has_vert检查。 m:mo必须是m:oMath的直接子级(不是嵌在m:r里):否则 OMML parser 会忽略m:mo,∈ × ≤等数学符号全部丢失。修复:_tm_build_omath用m:mo = SubElement(omath, ...)而非m:mo = SubElement(mr, ...)。- vertAlign 公式片段的边界(v1.5.1 增强):遇到
∈ × ≤等数学符号时也要断,让E_e ∈ R^{Ve×de}这种独立公式正确分段(之前只断中文)。修复:_va_identify_segments用增强的_va_is_chinese_or_math判边界。
- equationxml_to_ksee3 必须先 OMML→MathML 再 MTEF:
实现细节(理解后可跳读)
KSEE3 路径(scripts/ksee3.py):
- MTEF v3 编码器 + WPS KSEE3 OLE CFB 文件生成器,字节级复刻真实 WPS 导出:CLSID {0002CE21-0000-0000-C000-000000000046}、ProgID Equation.KSEE3、Equation Native header version 0xc3f70002、reserved 时间戳、Mini-Stream CFB 布局、红黑树 directory(root→ObjInfo,ObjInfo→CompObj 和 Equation Native)。
MathType 路径(omml-converter + 后处理):
1. omml-converter 把 OMML → MathML → MTEF v5 → DSMT6 OLE
2. 剥掉 omml-converter 的 mc:AlternateContent 包装(WPS 不遵循 MCE 降级会显示空;直接嵌入 <w:object> 才能双击编辑)
3. 修 make_equation_native 的 header bug(struct.pack("<HIHI", ...) 把 cbHdr 错写成 WORD、version 用错 0x00020000),重写为标准 EQNOLEFILEHDR:struct.pack("<III", 28, 0x00020002, cb_object) + bytes(16)
ShapeID/ObjectID 唯一:从 _x0000_i1100 开始(避开文档已有 OLE 的 _x0000_i1025),否则 WPS 因 ID 冲突不渲染新 OLE。
脚本参数说明
input(必填):输入 docx 路径。output(必填):输出 docx 路径。--target {ksee3,mathtype,omml}:目标格式,默认None(自动判断)。ksee3=WPS 公式 3.0 OLE;mathtype=MathType OLE(DSMT6,Word 环境);omml=原生公式。--source {auto,wps,word}:输入文档来源,默认auto(读 app.xml 自动检测,匹配不到默认 wps)。--mode {inplace,extract}:inplace保留其他文字,extract只输出公式。--select {all,high}:文本公式识别置信度,默认high(避免误转集合名)。--report PATH:报告输出路径。--wps-render:可选,用 WPS COM 自动化模拟双击生成 wmf 预览(Windows + WPS 桌面 + pywin32 + psutil;兼容 WPS/Kwps.Application;会强杀 WPS 进程)。--yes:配合--wps-render,显式确认允许强制关闭所有 WPS 窗口。
依赖与部署
- 依赖清单:
skill-dependencies.json - 安装指引:
references/setup-guide.md(含离线/在线两种方式) - 环境自检:
scripts/check_environment.py - 离线版 vendor 目录含 5 个 wheel(mathfmt、omml-converter、lxml、psutil、pywin32),仅 Windows x64 + Python 3.13;其他版本需联网
pip install自动匹配。