Skip to content

Commit 098d485

Browse files
committed
Prepare FormulaOCR v1.0.0 release
1 parent caf0d6c commit 098d485

34 files changed

Lines changed: 8413 additions & 244 deletions

.github/workflows/ci.yml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
workflow_dispatch:
9+
10+
permissions:
11+
contents: read
12+
13+
concurrency:
14+
group: ci-${{ github.ref }}
15+
cancel-in-progress: true
16+
17+
jobs:
18+
windows-tests:
19+
runs-on: windows-2022
20+
steps:
21+
- name: Checkout
22+
uses: actions/checkout@v4
23+
24+
- name: Set up Python
25+
uses: actions/setup-python@v5
26+
with:
27+
python-version: "3.10"
28+
architecture: x64
29+
cache: pip
30+
31+
- name: Install dependencies
32+
shell: pwsh
33+
run: |
34+
python -m pip install --upgrade pip
35+
python -m pip install -r requirements.txt
36+
37+
- name: Run regression tests
38+
shell: pwsh
39+
run: |
40+
python -m unittest formula_ocr_app.recognition_tests
41+
python formula_ocr_app\app.py --ui-self-test
42+
python formula_ocr_app\app.py --word-mathml-self-test
43+
python formula_ocr_app\app.py --runtime-self-test

.github/workflows/release.yml

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*"
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: write
11+
12+
concurrency:
13+
group: release-${{ github.ref }}
14+
cancel-in-progress: false
15+
16+
jobs:
17+
windows-installer:
18+
runs-on: windows-2022
19+
steps:
20+
- name: Checkout
21+
uses: actions/checkout@v4
22+
23+
- name: Verify release version
24+
if: startsWith(github.ref, 'refs/tags/')
25+
shell: pwsh
26+
run: |
27+
$version = (Get-Content VERSION -Raw).Trim()
28+
if ("v$version" -ne "${{ github.ref_name }}") {
29+
throw "Tag ${{ github.ref_name }} does not match VERSION $version"
30+
}
31+
32+
- name: Set up Python
33+
uses: actions/setup-python@v5
34+
with:
35+
python-version: "3.10"
36+
architecture: x64
37+
cache: pip
38+
39+
- name: Install Python dependencies
40+
shell: pwsh
41+
run: |
42+
python -m pip install --upgrade pip
43+
python -m pip install -r requirements.txt
44+
45+
- name: Install Inno Setup
46+
shell: pwsh
47+
run: choco install innosetup --yes --no-progress
48+
49+
- name: Build Windows installer
50+
shell: pwsh
51+
run: |
52+
$env:FORMULA_OCR_CONDA_ENV = Split-Path (Get-Command python).Source
53+
.\build_installer.ps1
54+
55+
- name: Upload workflow artifact
56+
uses: actions/upload-artifact@v4
57+
with:
58+
name: FormulaOCR-Windows-Installer
59+
path: |
60+
dist/installer/FormulaOCRSetup-*.exe
61+
dist/installer/FormulaOCRSetup-*.exe.sha256
62+
if-no-files-found: error
63+
64+
- name: Publish GitHub Release assets
65+
if: startsWith(github.ref, 'refs/tags/')
66+
uses: softprops/action-gh-release@v2
67+
with:
68+
generate_release_notes: true
69+
files: |
70+
dist/installer/FormulaOCRSetup-*.exe
71+
dist/installer/FormulaOCRSetup-*.exe.sha256

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ build/
2121
build_fixed/
2222
dist/
2323
*.spec
24+
!FormulaOCR.spec
25+
release-assets/
2426

2527
# Third-party source/vendor trees
2628
PaddleOCR-main/
@@ -45,3 +47,4 @@ debug_exe_stderr.txt
4547
Thumbs.db
4648
.idea/
4749
.vscode/
50+
*:Zone.Identifier

FormulaOCR.spec

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
# -*- mode: python ; coding: utf-8 -*-
2+
from pathlib import Path
3+
import importlib.util
4+
import os
5+
import sys
6+
7+
from PyInstaller.utils.hooks import collect_all
8+
from PyInstaller.utils.hooks import copy_metadata
9+
10+
# PyInstaller exposes SPECPATH as the directory containing this spec file,
11+
# not the spec filename itself. Taking `.parent` here points one directory
12+
# above the project when the spec is invoked directly.
13+
ROOT = Path(SPECPATH).resolve()
14+
paddleocr_spec = importlib.util.find_spec('paddleocr')
15+
if paddleocr_spec is None or not paddleocr_spec.submodule_search_locations:
16+
raise SystemExit('paddleocr==3.6.0 is required to build FormulaOCR.')
17+
paddleocr_package_dir = Path(
18+
next(iter(paddleocr_spec.submodule_search_locations))
19+
).resolve()
20+
datas = [
21+
(str(paddleocr_package_dir), 'PaddleOCR-main/paddleocr'),
22+
(str(ROOT / 'icon.png'), '.'),
23+
(str(ROOT / 'icon.ico'), '.'),
24+
]
25+
bundled_models_root = os.environ.get('FORMULA_OCR_BUNDLED_PADDLE_MODELS', '').strip()
26+
if bundled_models_root:
27+
bundled_root = Path(bundled_models_root)
28+
required_model_files = {'inference.json', 'inference.yml', 'inference.pdiparams'}
29+
if bundled_root.is_dir():
30+
for model_dir in bundled_root.iterdir():
31+
required = required_model_files
32+
if model_dir.name == 'LaTeX_OCR_rec':
33+
required = required | {'config.json'}
34+
if model_dir.is_dir() and required.issubset(
35+
{item.name for item in model_dir.iterdir() if item.is_file()}
36+
):
37+
datas.append((str(model_dir), f'models/paddle/{model_dir.name}'))
38+
bundled_onnx_root = os.environ.get('FORMULA_OCR_BUNDLED_ONNX_MODELS', '').strip()
39+
onnx_model_files = {
40+
'RapidLaTeXOCR': {'image_resizer.onnx', 'encoder.onnx', 'decoder.onnx', 'tokenizer.json'},
41+
'MathCraftFormula': {
42+
'config.json', 'encoder_model.onnx', 'decoder_model.onnx',
43+
'generation_config.json', 'preprocessor_config.json',
44+
'special_tokens_map.json', 'tokenizer.json', 'tokenizer_config.json',
45+
},
46+
'Pix2TextMFR15': {
47+
'config.json', 'encoder_model.onnx', 'decoder_model.onnx',
48+
'generation_config.json', 'preprocessor_config.json',
49+
'special_tokens_map.json', 'tokenizer.json', 'tokenizer_config.json',
50+
},
51+
'MixTexZhEn': {
52+
'added_tokens.json', 'config.json', 'decoder_model_merged.onnx',
53+
'encoder_model.onnx', 'generation_config.json', 'merges.txt',
54+
'preprocessor_config.json', 'special_tokens_map.json', 'tokenizer.json',
55+
'tokenizer_config.json', 'vocab.json',
56+
},
57+
'UniMERNetSmallONNX': {
58+
'config.json', 'decoder_model_quantized.onnx',
59+
'decoder_with_past_model_quantized.onnx',
60+
'encoder_model_quantized.onnx', 'preprocessor_config.json',
61+
'tokenizer.json',
62+
},
63+
}
64+
if bundled_onnx_root:
65+
onnx_root = Path(bundled_onnx_root)
66+
if onnx_root.is_dir():
67+
for model_dir in onnx_root.iterdir():
68+
required = onnx_model_files.get(model_dir.name)
69+
if model_dir.is_dir() and required and required.issubset(
70+
{item.name for item in model_dir.iterdir() if item.is_file()}
71+
):
72+
datas.append((str(model_dir), f'models/onnx/{model_dir.name}'))
73+
binaries = []
74+
runtime_root = Path(sys.executable).resolve().parent
75+
runtime_bin_dirs = (
76+
runtime_root / 'Library' / 'bin',
77+
runtime_root / 'DLLs',
78+
runtime_root,
79+
)
80+
for dll_names in (
81+
('tcl86t.dll',),
82+
('tk86t.dll',),
83+
('libexpat.dll', 'expat.dll'),
84+
):
85+
dll_path = next(
86+
(
87+
directory / dll_name
88+
for directory in runtime_bin_dirs
89+
for dll_name in dll_names
90+
if (directory / dll_name).is_file()
91+
),
92+
None,
93+
)
94+
if dll_path is not None:
95+
binaries.append((str(dll_path), '.'))
96+
hiddenimports = ['paddle', 'paddlex', 'numpy', 'tokenizers', 'onnxruntime', 'rapid_latex_ocr']
97+
datas += copy_metadata('tokenizers')
98+
datas += copy_metadata('latex2mathml')
99+
datas += copy_metadata('paddleocr')
100+
for package_name in (
101+
'paddle',
102+
'paddlex',
103+
'cv2',
104+
'tokenizers',
105+
'pypdfium2',
106+
'latex2mathml',
107+
'onnxruntime',
108+
'rapid_latex_ocr',
109+
):
110+
package_datas, package_binaries, package_hiddenimports = collect_all(package_name)
111+
datas += package_datas
112+
binaries += package_binaries
113+
hiddenimports += package_hiddenimports
114+
hiddenimports = list(dict.fromkeys(hiddenimports))
115+
116+
117+
a = Analysis(
118+
[str(ROOT / 'formula_ocr_app' / 'app.py')],
119+
pathex=[str(ROOT)],
120+
binaries=binaries,
121+
datas=datas,
122+
hiddenimports=hiddenimports,
123+
hookspath=[],
124+
hooksconfig={},
125+
runtime_hooks=[],
126+
excludes=['tensorflow', 'torch', 'torchvision', 'torchaudio', 'modelscope', 'matplotlib', 'sklearn', 'scipy', 'paddle.tensorrt', 'paddlex.inference.serving', 'shapely.tests'],
127+
noarchive=False,
128+
optimize=0,
129+
)
130+
pyz = PYZ(a.pure)
131+
132+
exe_options = dict(
133+
name='FormulaOCR',
134+
debug=False,
135+
bootloader_ignore_signals=False,
136+
strip=False,
137+
upx=True,
138+
console=False,
139+
disable_windowed_traceback=False,
140+
argv_emulation=False,
141+
target_arch=None,
142+
codesign_identity=None,
143+
entitlements_file=None,
144+
icon=[str(ROOT / 'icon.ico')],
145+
)
146+
147+
exe = EXE(
148+
pyz,
149+
a.scripts,
150+
[],
151+
exclude_binaries=True,
152+
contents_directory='_internal',
153+
**exe_options,
154+
)
155+
coll = COLLECT(
156+
exe,
157+
a.binaries,
158+
a.datas,
159+
strip=False,
160+
upx=True,
161+
upx_exclude=[],
162+
name='FormulaOCR',
163+
)

NOTICE.md

Lines changed: 83 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ FormulaOCR depends on open-source OCR and formula-recognition components. This f
66

77
- Project: PaddleOCR
88
- Repository: https://github.com/PaddlePaddle/PaddleOCR
9+
- Pinned Python package used for builds: `paddleocr==3.6.0`
910
- Organization: PaddlePaddle / PaddleOCR Authors
1011
- License: Apache License 2.0
1112
- Use in this project: formula recognition through PaddleOCR/PaddleX formula-recognition models.
@@ -19,6 +20,86 @@ This software uses PaddleOCR, an open-source OCR toolkit from the PaddlePaddle e
1920
https://github.com/PaddlePaddle/PaddleOCR
2021
```
2122

22-
## Python Libraries
23+
## RapidLaTeXOCR and ONNX Runtime
2324

24-
The application also uses Python packages listed in `requirements.txt`, including Pillow, paddlepaddle, paddlex, latex2mathml, requests, aiohttp, tokenizers, ftfy, and PyInstaller. Their licenses are controlled by their respective upstream projects.
25+
- Project: RapidAI/RapidLaTeXOCR
26+
- Repository: https://github.com/RapidAI/RapidLaTeXOCR
27+
- License: MIT (the PyPI metadata currently labels it Apache-2.0; the distributed LICENSE file and repository state MIT)
28+
- Use: optional community formula-recognition backend derived from LaTeX-OCR/pix2tex.
29+
- Runtime: Microsoft ONNX Runtime, MIT License.
30+
31+
RapidLaTeXOCR model files are downloaded on demand from the project's official GitHub Release and verified with SHA-256. They are not committed to this repository or included in the default application archive.
32+
33+
## UniMERNet
34+
35+
UniMERNet was developed by Shanghai AI Laboratory and is exposed here through the official PaddleOCR/PaddleX inference model catalog. Users redistributing model weights should retain the upstream model card, license, and attribution applicable to the downloaded release.
36+
37+
## UniMERNet Small ONNX
38+
39+
- Original model: `wanderkid/unimernet_small`
40+
- ONNX conversion repository/model card: `Cooper114/unimernet-onnx`
41+
- Model card: https://huggingface.co/Cooper114/unimernet-onnx
42+
- License: Apache License 2.0 (model card and upstream source attribution)
43+
- Use: optional quantized UniMERNet Small backend using ONNX Runtime.
44+
45+
The `UniMERNetSmallONNX` files are downloaded from the pinned Hugging Face
46+
revision `411ee76221baaad144ffbf996d4deef8df013b54` and verified against the
47+
six-file SHA-256 manifest before use. The model is not committed to this
48+
repository or included in the default application archive. The ONNX export
49+
uses a first decoder plus a `decoder_with_past` KV-cache decoder; retain the
50+
upstream model-card attribution and license when redistributing an offline
51+
copy.
52+
53+
## MathCraft Formula ONNX
54+
55+
- Project: SakuraMathcraft/MathCraft-Models
56+
- Repository: https://github.com/SakuraMathcraft/MathCraft-Models
57+
- Model release: https://github.com/SakuraMathcraft/MathCraft-Models/releases/tag/v1.0.0
58+
- License: MIT (https://github.com/SakuraMathcraft/MathCraft-Models/blob/main/LICENSE)
59+
- Related implementation: SakuraMathcraft/LaTeXSnipper
60+
- Use: optional pure ONNX Runtime formula-recognition backend.
61+
62+
The `MathCraftFormula` archive is downloaded from the official release on demand. The archive SHA-256 is `807dd2d1ac40454424404b31a73d4242c37c76edf176ab544540028da20ec43f`; extracted files are checked against the upstream SHA-256 manifest before atomic installation. The model is not committed to this repository or included in the default application archive. Redistributors should retain the MathCraft-Models license and model-card terms with any offline copy.
63+
64+
## PaddlePaddle LaTeX-OCR Rec
65+
66+
- Project/model: PaddlePaddle `LaTeX_OCR_rec`
67+
- Model card: https://huggingface.co/PaddlePaddle/LaTeX_OCR_rec
68+
- License: Apache License 2.0 (model card)
69+
- Use: optional lightweight Paddle formula-recognition backend.
70+
71+
The `LaTeX_OCR_rec` files are downloaded from the pinned Hugging Face revision
72+
`563fb029dfdf5fc847d0677f3870039960e3a801` and verified with SHA-256 before
73+
installation. They are not committed to this repository or included in the
74+
default application archive. Redistributors should retain the upstream model
75+
card and license terms with any offline copy.
76+
77+
## Pix2Text MFR 1.5
78+
79+
- Project: Breezedeus/Pix2Text
80+
- Repository: https://github.com/breezedeus/Pix2Text
81+
- Model card: https://huggingface.co/breezedeus/pix2text-mfr-1.5
82+
- License: MIT (model card and upstream Pix2Text repository)
83+
- Use: optional Pix2Text mathematical formula recognition backend using ONNX Runtime.
84+
85+
The `Pix2TextMFR15` files are downloaded from the pinned Hugging Face revision `1cef9f0bdcd6a4c63df7de1311fb0894593340cc` on demand. All eight inference files are checked against the recorded SHA-256 manifest before use. They are not committed to this repository or included in the default application archive; redistributors should retain the upstream model-card terms.
86+
87+
## MixTeX
88+
89+
- Project: [RQLuo/MixTeX-Latex-OCR](https://github.com/RQLuo/MixTeX-Latex-OCR)
90+
- Release: `MixTeX-v3.2.4`
91+
- Release asset: `MixTeX.zip`
92+
- Use: optional Chinese/English formula OCR backend using the official merged-decoder ONNX export.
93+
94+
The MixTeX release archive is downloaded on demand from the upstream release and
95+
verified with SHA-256
96+
`734088e8c3ac6d0ebf02b3054ed0cdde7d8be2eb57c33b8f049a66d05e026750`.
97+
FormulaOCR extracts only the ONNX model payload and does not redistribute the
98+
upstream executable. The upstream `User Manual&Terms of Service.md` states that
99+
the software is AGPL-3.0 and that derivatives of the model may not be used for
100+
commercial purposes. FormulaOCR displays this restriction and asks the user to
101+
confirm it before first download/use. Do not include MixTeX weights in a
102+
commercial binary or offline package without written permission from the
103+
upstream rights holder.
104+
105+
The application also uses Python packages listed in `requirements.txt`, including Pillow, paddlepaddle, paddlex, ONNX Runtime, RapidLaTeXOCR, latex2mathml, requests, aiohttp, tokenizers, ftfy, and PyInstaller. Their licenses are controlled by their respective upstream projects.

0 commit comments

Comments
 (0)