docs: Dokumentation nach Projektstandard, MIT-Lizenz
- README knapp: Zweck, Schnellstart, Stand, Abschnitt "Documentation", Lizenz - FUNKTIONSWEISE.md neu: Aufbau, Datenfluss (Mermaid), Entscheidungsregel, Normalform, elastischer Bildvergleich, Quellen, Sicherheit, Messungen, Designentscheidungen, Grenzen - BEDIENUNGSANLEITUNG gegliedert: Installation, Modellserver, Benutzung, Konfiguration (Umgebungsvariablen, workspace.json), Betrieb, Werkzeuge, Fehlersuche mit echten Meldungen und Rückgabecodes - CHANGELOG im Format Keep a Changelog mit "Beim Update zu tun" - LICENSE (MIT) - cli.py: Hilfetexte beschreiben die Regel p2t und z-ai/glm-4.6v statt des Pixelvergleichs und gemini-2.5-flash - requirements.txt: requests ergänzt Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
be6ba0b926
commit
6a0e9587f5
7 changed files with 871 additions and 581 deletions
|
|
@ -4,17 +4,32 @@ Dieses Programm ersetzt Formelbilder in den Markdown-Dateien von epub2md und pdf
|
|||
LaTeX-Formeln. Dadurch passen die Formeln beim Neubau als EPUB oder PDF in Größe und Schrift zum Text.
|
||||
|
||||
Es liest jede Formel zuerst mit dem Formel-OCR **pix2text** und ersetzt sie nur, wenn das Bildmodell
|
||||
**Qwen** dieselbe Formel liest (bei Uneinigkeit darf das zweite Bildmodell Gemma pix2text bestätigen) und
|
||||
das gerenderte LaTeX dem Bild grob ähnelt. Eingesetzt wird die Lesart von pix2text, ohne ihre
|
||||
überflüssigen Leerzeichen. Alles läuft lokal. Bei Zweifeln fragt es dich in einer
|
||||
Review-Seite im Browser. Ohne deine Zustimmung bleibt die Formel ein Bild.
|
||||
**Qwen** dieselbe Formel liest (bei Uneinigkeit darf das zweite Bildmodell **Gemma** pix2text bestätigen)
|
||||
und das gerenderte LaTeX dem Bild grob ähnelt. Eingesetzt wird die Lesart von pix2text. Alles läuft lokal.
|
||||
Bei Zweifeln fragt es dich in einer Review-Seite im Browser; ohne deine Zustimmung bleibt die Formel ein
|
||||
Bild.
|
||||
|
||||
„Dieselbe Formel“ heißt: jedes Zeichen stimmt und steht an der richtigen Stelle. Abstände, Pfeillängen,
|
||||
Schriftgröße, kursiv/aufrecht und Fettdruck dürfen abweichen.
|
||||
Schriftgröße, kursiv/aufrecht und Fettdruck dürfen abweichen. Wie das intern geprüft wird, steht in
|
||||
[FUNKTIONSWEISE.md](FUNKTIONSWEISE.md).
|
||||
|
||||
---
|
||||
|
||||
## 1. Einrichtung (einmalig)
|
||||
## Inhalt
|
||||
|
||||
1. [Installation](#1-installation)
|
||||
2. [Modellserver starten und beenden](#2-modellserver-starten-und-beenden)
|
||||
3. [Ein Buch bearbeiten](#3-ein-buch-bearbeiten)
|
||||
4. [Einzelne Schritte und Optionen](#4-einzelne-schritte-und-optionen)
|
||||
5. [Konfiguration](#5-konfiguration)
|
||||
6. [Betrieb](#6-betrieb)
|
||||
7. [Werkzeuge zum Messen und Einstellen](#7-werkzeuge-zum-messen-und-einstellen)
|
||||
8. [Fehlersuche](#8-fehlersuche)
|
||||
9. [Häufige Fragen](#9-häufige-fragen)
|
||||
|
||||
---
|
||||
|
||||
## 1. Installation
|
||||
|
||||
```bash
|
||||
sudo apt install texlive-latex-extra texlive-fonts-extra texlive-science pandoc dvipng
|
||||
|
|
@ -23,40 +38,14 @@ pip install -r requirements.txt
|
|||
python3 formula_img2latex.py --version
|
||||
```
|
||||
|
||||
### Die beiden lokalen Bildmodelle starten
|
||||
|
||||
Zwei Vision-Sprachmodelle lesen jede Formel, je eines pro Grafikkarte (je ~18–21 GB). In zwei Terminals:
|
||||
|
||||
```bash
|
||||
# Modell A: Qwen3-VL auf GPU 1, Port 8011
|
||||
M=~/endeavour_home/lm_studio/models/lmstudio-community/Qwen3-VL-30B-A3B-Instruct-GGUF
|
||||
CUDA_VISIBLE_DEVICES=1 ~/.local/bin/llama-server \
|
||||
-m $M/Qwen3-VL-30B-A3B-Instruct-Q4_K_M.gguf --mmproj $M/mmproj-Qwen3-VL-30B-A3B-Instruct-F16.gguf \
|
||||
--host 127.0.0.1 --port 8011 -ngl 99 -c 32768 --parallel 8
|
||||
|
||||
# Modell B: Gemma 4 auf GPU 2, Port 8012
|
||||
M=~/nvme2n1p7_home/huggingface/models/gemma4
|
||||
CUDA_VISIBLE_DEVICES=2 ~/.local/bin/llama-server \
|
||||
-m $M/gemma-4-26B-A4B-it-Q4_0.gguf --mmproj $M/mmproj-gemma-4-26B-A4B-it-BF16.gguf \
|
||||
--host 127.0.0.1 --port 8012 -ngl 99 -c 16384 --parallel 4
|
||||
```
|
||||
|
||||
Qwen läuft mit 8 Plätzen zu je 4096 Tokens (zusammen 32768) und belegt rund 22,6 GB; `run` stellt bis zu
|
||||
8 Anfragen gleichzeitig. Gemma braucht auf GPU 2 rund 17,5 GB. Laufen dort Chatterbox-TTS und der STT-Server, reicht der Speicher
|
||||
nicht (Gemma bricht beim ersten Bild mit „out of memory“ ab); dann vorher stoppen und danach wieder starten:
|
||||
|
||||
```bash
|
||||
systemctl --user stop chatterbox-tts.service open-notebook-stt.service
|
||||
systemctl --user start chatterbox-tts.service open-notebook-stt.service # nach der Arbeit
|
||||
```
|
||||
|
||||
pix2text läuft zusätzlich auf der ersten sichtbaren GPU (unter 1 GB). Beenden mit Strg+C in beiden
|
||||
Terminals.
|
||||
- **TeX Live** setzt die Formeln für den Bildabgleich (pdflatex, Schriften `lmodern`, `newtx`, `newpx`,
|
||||
`stix2`, `eulervm`, `txfonts`).
|
||||
- **Pandoc** prüft, dass jede Formel später als MathML gesetzt werden kann.
|
||||
- **dvipng** braucht nur `calibrate --synthetic`.
|
||||
|
||||
### pix2text (Formel-OCR)
|
||||
|
||||
pix2text läuft ohne Server im Programm selbst, auf der ersten sichtbaren Grafikkarte (sonst auf der CPU,
|
||||
dann ~5× langsamer). Einmalig:
|
||||
pix2text läuft ohne Server im Programm selbst. Einmalig:
|
||||
|
||||
```bash
|
||||
pip install "pix2text[multilingual]"
|
||||
|
|
@ -64,24 +53,64 @@ pip install --no-deps pix2tex munch # nur für post_p
|
|||
pip uninstall -y onnxruntime && pip install onnxruntime-gpu # für die GPU
|
||||
```
|
||||
|
||||
Das Modell (~300 MB) wird beim ersten Lauf nach `~/.pix2text` geladen. Ohne Angabe nimmt pix2text die
|
||||
Grafikkarte mit dem meisten freien Speicher und liest die Formeln gebündelt. Gerät festlegen mit
|
||||
`FORMULA_P2T_DEVICE=cpu` oder `cuda:N` (`N` zählt innerhalb von `CUDA_VISIBLE_DEVICES`).
|
||||
`pix2tex` wird ohne Abhängigkeiten installiert, weil es sonst eine alte `timm`-Version erzwingen würde.
|
||||
Das Modell (~300 MB) wird beim ersten Lauf nach `~/.pix2text` geladen. pix2text nimmt die sichtbare
|
||||
Grafikkarte mit dem meisten freien Speicher (unter 1 GB) und liest die Formeln gebündelt; ohne
|
||||
`onnxruntime-gpu` läuft es auf der CPU, dann etwa 5× langsamer.
|
||||
|
||||
Gemma (Port 8012) wird nur für Formeln gefragt, bei denen pix2text und Qwen uneinig sind. Läuft Gemma
|
||||
nicht, bleiben diese Formeln im Review.
|
||||
### Modelle für die Bildmodelle
|
||||
|
||||
### Frühere Regel mit Cloud (optional)
|
||||
| Modell | Datei | Ort |
|
||||
|---|---|---|
|
||||
| Qwen3-VL-30B-A3B-Instruct | `Qwen3-VL-30B-A3B-Instruct-Q4_K_M.gguf` + `mmproj-Qwen3-VL-30B-A3B-Instruct-F16.gguf` | `~/endeavour_home/lm_studio/models/lmstudio-community/Qwen3-VL-30B-A3B-Instruct-GGUF/` |
|
||||
| Gemma-4-26B-A4B-it | `gemma-4-26B-A4B-it-Q4_0.gguf` + `mmproj-gemma-4-26B-A4B-it-BF16.gguf` (ggml-org, zusammen 15,8 GB) | `~/nvme2n1p7_home/huggingface/models/gemma4/` |
|
||||
|
||||
Bis Version 0.2.0 kam die Bestätigung von **GLM-4.6V** über OpenRouter (Qwen = Gemma = GLM). Diese Regel
|
||||
ist weiter wählbar: im Arbeitsordner in `workspace.json` unter `settings` den Eintrag
|
||||
`"consensus_rule": "vlm3"` setzen; dann muss `OPENROUTER_API_KEY` gesetzt sein.
|
||||
Gemma neu laden:
|
||||
|
||||
```bash
|
||||
cd ~/nvme2n1p7_home/huggingface/models/gemma4
|
||||
hf download ggml-org/gemma-4-26B-A4B-it-GGUF gemma-4-26B-A4B-it-Q4_0.gguf \
|
||||
mmproj-gemma-4-26B-A4B-it-BF16.gguf --local-dir .
|
||||
```
|
||||
|
||||
Optional, nur für den Strukturvergleich (aus): `pip install sympy lark`.
|
||||
|
||||
---
|
||||
|
||||
## 2. Ein Buch bearbeiten
|
||||
## 2. Modellserver starten und beenden
|
||||
|
||||
### Schritt 1: Buch wie gewohnt umwandeln
|
||||
Zwei Bildmodelle laufen als llama.cpp-Server, je eines pro Grafikkarte. In zwei Terminals:
|
||||
|
||||
```bash
|
||||
# Qwen3-VL auf GPU 1, Port 8011: 8 Plätze zu je 4096 Tokens, rund 22,6 GB
|
||||
M=~/endeavour_home/lm_studio/models/lmstudio-community/Qwen3-VL-30B-A3B-Instruct-GGUF
|
||||
CUDA_VISIBLE_DEVICES=1 ~/.local/bin/llama-server \
|
||||
-m $M/Qwen3-VL-30B-A3B-Instruct-Q4_K_M.gguf --mmproj $M/mmproj-Qwen3-VL-30B-A3B-Instruct-F16.gguf \
|
||||
--host 127.0.0.1 --port 8011 -ngl 99 -c 32768 --parallel 8
|
||||
|
||||
# Gemma 4 auf GPU 2, Port 8012: rund 17,5 GB
|
||||
M=~/nvme2n1p7_home/huggingface/models/gemma4
|
||||
CUDA_VISIBLE_DEVICES=2 ~/.local/bin/llama-server \
|
||||
-m $M/gemma-4-26B-A4B-it-Q4_0.gguf --mmproj $M/mmproj-gemma-4-26B-A4B-it-BF16.gguf \
|
||||
--host 127.0.0.1 --port 8012 -ngl 99 -c 16384 --parallel 4
|
||||
```
|
||||
|
||||
Laufen auf GPU 2 Chatterbox-TTS und der STT-Server, reicht der Speicher für Gemma nicht. Dann vorher
|
||||
stoppen und nach der Arbeit wieder starten:
|
||||
|
||||
```bash
|
||||
systemctl --user stop chatterbox-tts.service open-notebook-stt.service
|
||||
systemctl --user start chatterbox-tts.service open-notebook-stt.service # nach der Arbeit
|
||||
```
|
||||
|
||||
Gemma wird nur für Formeln gefragt, bei denen pix2text und Qwen uneinig sind. Läuft Gemma nicht, meldet
|
||||
`run` das einmal, und diese Formeln bleiben im Review. Beenden: Strg+C in beiden Terminals.
|
||||
|
||||
---
|
||||
|
||||
## 3. Ein Buch bearbeiten
|
||||
|
||||
### Schritt 1: Buch umwandeln
|
||||
|
||||
```bash
|
||||
cd ~/Python_Programs/epub2md
|
||||
|
|
@ -90,7 +119,7 @@ python3 epub2md.py buch.epub output/buch
|
|||
|
||||
Bei PDFs mit pdf2md immer `--images` (oder `--epub`) angeben, sonst gibt es keine Formelbilder. Für
|
||||
Mathebücher **`--formulas`** verwenden: Dann findet pdf2md jede Formel auf der Seite, auch im Fließtext und
|
||||
in Merkkästen, und schneidet sie als Bild aus (braucht pix2text, siehe oben):
|
||||
in Merkkästen, und schneidet sie als Bild aus (braucht pix2text):
|
||||
|
||||
```bash
|
||||
cd ~/Python_Programs/pdf2md
|
||||
|
|
@ -106,10 +135,11 @@ cd ~/Python_Programs/formula_img2latex
|
|||
python3 formula_img2latex.py run ~/Python_Programs/epub2md/output/buch
|
||||
```
|
||||
|
||||
Bei pdf2md zusätzlich die Original-PDF angeben. Dann schneidet das Programm jede Formel scharf aus dem PDF:
|
||||
Bei pdf2md die Markdown-Datei angeben und die Original-PDF dazu; Box-Bilder werden dann scharf aus dem PDF
|
||||
neu ausgeschnitten:
|
||||
|
||||
```bash
|
||||
python3 formula_img2latex.py run Output/buch.md --pdf buch.pdf
|
||||
python3 formula_img2latex.py run ~/Python_Programs/pdf2md/Output/buch/buch.md --pdf buch.pdf
|
||||
```
|
||||
|
||||
Das Programm arbeitet in Paketen zu 50 Formeln und meldet nach jedem Paket den Stand und die Zeiten je
|
||||
|
|
@ -119,7 +149,7 @@ Stufe (die Stufen laufen teils gleichzeitig, daher ist die Summe größer als di
|
|||
100/940 verarbeitet: automatisch ersetzt 78 (78%), Review 20, bleibt Bild/keine Formel 2 [Paket 35 s; pix2text 3 s, Qwen 30 s, Prüfung 14 s, Gemma 21 s]
|
||||
```
|
||||
|
||||
Am Ende steht eine Übersicht je Status, beim Gehrke-Brückenkurs zum Beispiel:
|
||||
Am Ende steht eine Übersicht je Status, zum Beispiel:
|
||||
|
||||
```text
|
||||
auto_accepted 942 ← Lesart bestätigt, wird ersetzt
|
||||
|
|
@ -128,15 +158,7 @@ Am Ende steht eine Übersicht je Status, beim Gehrke-Brückenkurs zum Beispiel:
|
|||
pending 539 ← Abbildungen/Symbole, nicht geprüft
|
||||
```
|
||||
|
||||
Dauer: etwa 0,8 s je Formel, also 35–50 Sekunden je Paket (Corral mit `--formulas`: 940 Formeln in
|
||||
13 Minuten, das ganze Buch mit 9239 Formeln rund 2 Stunden). Am längsten braucht die Bestätigung durch Qwen.
|
||||
Der Scan liest beim ersten Mal alle Bilder ein (Corral: 6 Minuten); beim Fortsetzen entfällt er, solange
|
||||
sich das Markdown nicht geändert hat.
|
||||
Abbrechen (Strg+C) und erneut starten ist kein Problem: Bereits gelesene Formeln werden nicht noch einmal
|
||||
gefragt, der Lauf setzt fort. `--chunk 100` ändert die Paketgröße, `--limit 200` verarbeitet nur die ersten
|
||||
200 Bilder.
|
||||
|
||||
Neben dem Buchordner entsteht ein Arbeitsordner `buch.formulas/`. Er enthält alle Ergebnisse. Lösch ihn nicht,
|
||||
Neben dem Buchordner entsteht ein Arbeitsordner `buch.formulas/` mit allen Ergebnissen. Lösch ihn nicht,
|
||||
solange du am Buch arbeitest.
|
||||
|
||||
### Schritt 3: Zweifelsfälle im Browser entscheiden
|
||||
|
|
@ -152,12 +174,10 @@ Der Browser öffnet `http://127.0.0.1:8765/`. Für jede Formel siehst du:
|
|||
stimmt etwas nicht (Exponent, Vorzeichen, Klammer).
|
||||
- **Diff:** schwarz = beide gleich, rot = nur im Original, blau = nur im LaTeX, gelb = deutliche Abweichung.
|
||||
- **LaTeX:** Text im Eingabefeld (die Lesart von pix2text), darunter die Lesarten der Modelle zum
|
||||
Anklicken. Oben steht der Grund für das Review, z. B. „Modelle uneinig“ mit den abweichenden Lesarten.
|
||||
|
||||
Schaltflächen:
|
||||
Anklicken. Oben steht der Grund für das Review, z. B. „pix2text und Qwen uneinig“.
|
||||
|
||||
| Schaltfläche | Wirkung |
|
||||
| --- | --- |
|
||||
|---|---|
|
||||
| LaTeX prüfen | rendert dein (korrigiertes) LaTeX neu und zeigt Overlay und Messwerte |
|
||||
| LaTeX übernehmen | die Formel wird beim nächsten `apply` ersetzt |
|
||||
| Bild behalten | die Formel bleibt ein Bild |
|
||||
|
|
@ -165,7 +185,8 @@ Schaltflächen:
|
|||
| Zurücksetzen | Entscheidung zurücknehmen |
|
||||
|
||||
Jede Entscheidung wird sofort gespeichert. Du kannst jederzeit aufhören (Strg+C im Terminal) und später
|
||||
weitermachen. `--all` zeigt auch die automatisch angenommenen Formeln.
|
||||
weitermachen. `--all` zeigt auch die automatisch angenommenen Formeln, `--port` ändert den Port,
|
||||
`--no-browser` öffnet keinen Browser.
|
||||
|
||||
### Schritt 4: Formeln ins Markdown schreiben
|
||||
|
||||
|
|
@ -176,31 +197,21 @@ python3 formula_img2latex.py apply ~/Python_Programs/epub2md/output/buch
|
|||
|
||||
Aus `` wird `$L = \{-\sqrt{2};\sqrt{2}\}$` im Text bzw. `$$…$$` als eigener
|
||||
Absatz. Die Bilddateien bleiben liegen. Hat die Formelerkennung bei einer Formel im Text ein Satzzeichen
|
||||
mit ausgeschnitten, steht es danach als normaler Text hinter der Formel (`$a^{x}$,`).
|
||||
mit ausgeschnitten, steht es danach als normaler Text hinter der Formel (`$a^{x}$,`). In deutschen
|
||||
Büchern werden Dezimalzahlen zu `3{,}6`; eine Gleichungsnummer steht als Text hinter der Formel.
|
||||
|
||||
Bei pdf2md-Büchern baut `pdf2md.py --from-md` das EPUB neu, mit allen Formeln als MathML:
|
||||
|
||||
```bash
|
||||
cd ~/Python_Programs/pdf2md && python3 pdf2md.py --from-md Output/buch/buch.md
|
||||
```
|
||||
|
||||
**Danach die Gesamtdatei neu bauen**, sie enthält sonst noch die Bilder:
|
||||
**Danach das Buch neu bauen:**
|
||||
|
||||
```bash
|
||||
# epub2md: Gesamtdatei neu, dann z. B. EPUB mit MathML
|
||||
cd ~/Python_Programs/epub2md
|
||||
python3 epub2md_merge.py output/buch --force
|
||||
```
|
||||
|
||||
Für EPUB und PDF mit Formeln gelten die Pandoc-Befehle aus der epub2md-Anleitung mit `--mathml`, z. B.:
|
||||
|
||||
```bash
|
||||
cd ~/Python_Programs/epub2md/output/buch
|
||||
P=~/Python_Programs/epub2md/pandoc
|
||||
cd output/buch && P=~/Python_Programs/epub2md/pandoc
|
||||
pandoc buch.md --toc --mathml --lua-filter $P/callouts.lua -o buch.epub
|
||||
```
|
||||
|
||||
In deutschen Büchern schreibt `apply` Dezimalzahlen als `3{,}6`, sonst setzt LaTeX „3, 6“. Eine
|
||||
Gleichungsnummer steht als Text hinter der Formel, wie bei epub2md.
|
||||
# pdf2md: EPUB mit allen Formeln als MathML
|
||||
cd ~/Python_Programs/pdf2md && python3 pdf2md.py --from-md Output/buch/buch.md
|
||||
```
|
||||
|
||||
### Rückgängig machen
|
||||
|
||||
|
|
@ -208,64 +219,173 @@ Gleichungsnummer steht als Text hinter der Formel, wie bei epub2md.
|
|||
python3 formula_img2latex.py revert ~/Python_Programs/epub2md/output/buch
|
||||
```
|
||||
|
||||
Das stellt die Kapiteldateien wie vor dem ersten `apply` wieder her. Hast du eine Datei seitdem von Hand
|
||||
geändert, wird sie übersprungen. `--force` setzt sie trotzdem zurück, dann ist die Handänderung weg.
|
||||
Das stellt die Markdown-Dateien wie vor dem ersten `apply` wieder her. Hast du eine Datei seitdem von Hand
|
||||
geändert, wird sie übersprungen; `--force` setzt sie trotzdem zurück, dann ist die Handänderung weg.
|
||||
|
||||
---
|
||||
|
||||
## 3. Einzelne Schritte statt `run`
|
||||
## 4. Einzelne Schritte und Optionen
|
||||
|
||||
```bash
|
||||
python3 formula_img2latex.py scan AUSGABE # Bilder finden
|
||||
python3 formula_img2latex.py recognize AUSGABE --engine p2t # pix2text (zuerst)
|
||||
python3 formula_img2latex.py recognize AUSGABE --engine local # Qwen (bestätigt)
|
||||
python3 formula_img2latex.py scan AUSGABE # Bilder finden (immer neu)
|
||||
python3 formula_img2latex.py recognize AUSGABE --engine p2t # pix2text
|
||||
python3 formula_img2latex.py recognize AUSGABE --engine local # Qwen
|
||||
python3 formula_img2latex.py verify AUSGABE # prüfen und entscheiden
|
||||
python3 formula_img2latex.py recognize AUSGABE --engine local2 --only-unresolved # Gemma (Stichwahl)
|
||||
python3 formula_img2latex.py recognize AUSGABE --engine local2 --only-unresolved # Gemma
|
||||
python3 formula_img2latex.py verify AUSGABE
|
||||
python3 formula_img2latex.py status AUSGABE
|
||||
python3 formula_img2latex.py status AUSGABE # Zählung je Status (--json)
|
||||
```
|
||||
|
||||
Nützliche Optionen:
|
||||
| Option | Befehle | Wirkung |
|
||||
|---|---|---|
|
||||
| `--limit 50` | run, recognize | nur die ersten 50 Bilder (zum Ausprobieren) |
|
||||
| `--chunk 100` | run | Paketgröße (Standard 50) |
|
||||
| `--pdf BUCH.pdf` | run, scan | pdf2md: Original-PDF für scharfe Neuausschnitte |
|
||||
| `--preset cm` | run, verify | Schrift für den Bildabgleich fest vorgeben (`cm`, `times`, `txfonts`, `palatino`, `stix`, `euler`); Standard: automatisch je Buch |
|
||||
| `--include-figures` | run, recognize, verify | auch Bilder versuchen, die wie Abbildungen aussehen |
|
||||
| `--model NAME`, `--url URL` | run, recognize | anderes Modell bzw. anderer Server |
|
||||
| `--workers N` | run, recognize, verify | parallele Anfragen bzw. Prüfprozesse |
|
||||
| `--redo` | verify | bereits geprüfte Formeln neu prüfen |
|
||||
| `--workspace ORDNER` | alle außer calibrate | Arbeitsordner an anderem Ort |
|
||||
| `--quiet`, `-q` | alle | nur Fehler ausgeben |
|
||||
|
||||
| Option | Wirkung |
|
||||
| --- | --- |
|
||||
| `--limit 50` | nur die ersten 50 Bilder (zum Ausprobieren) |
|
||||
| `--preset cm` | Schrift fest vorgeben (`cm`, `times`, `txfonts`, `palatino`, `stix`, `euler`); Standard: automatisch |
|
||||
| `--include-figures` | auch Bilder versuchen, die wie Abbildungen aussehen |
|
||||
| `--model NAME` | anderes Modell (lokal: Servername, Cloud: OpenRouter-ID) |
|
||||
| `--workspace ORDNER` | Arbeitsordner an anderem Ort |
|
||||
| `--redo` (verify) | bereits geprüfte Formeln neu prüfen, z. B. nach einem Programm-Update |
|
||||
Alle Optionen: `python3 formula_img2latex.py BEFEHL --help`.
|
||||
|
||||
---
|
||||
|
||||
## 4. Häufige Fragen
|
||||
## 5. Konfiguration
|
||||
|
||||
### Umgebungsvariablen
|
||||
|
||||
| Variable | Standard | Wirkung |
|
||||
|---|---|---|
|
||||
| `FORMULA_LOCAL_URL`, `FORMULA_LOCAL_MODEL` | `http://127.0.0.1:8011/v1`, Modell des Servers | Qwen-Server |
|
||||
| `FORMULA_LOCAL2_URL`, `FORMULA_LOCAL2_MODEL` | `http://127.0.0.1:8012/v1`, Modell des Servers | Gemma-Server |
|
||||
| `FORMULA_LOCAL_API_KEY`, `FORMULA_LOCAL2_API_KEY` | – | falls der Server einen Schlüssel verlangt |
|
||||
| `FORMULA_P2T_DEVICE` | `auto` | pix2text: `auto`, `cpu` oder `cuda:N` (`N` zählt innerhalb von `CUDA_VISIBLE_DEVICES`) |
|
||||
| `FORMULA_P2T_MODEL` | `mfr-1.5` | pix2text-Modell |
|
||||
| `FORMULA_CLOUD_URL`, `FORMULA_CLOUD_MODEL` | `https://openrouter.ai/api/v1`, `z-ai/glm-4.6v` | nur Regel `vlm3` |
|
||||
| `OPENROUTER_API_KEY` | – | nur Regel `vlm3` |
|
||||
| `FORMULA_LOCAL_THINKING`, `FORMULA_LOCAL2_THINKING`, `FORMULA_CLOUD_THINKING` | `0` | `1` schaltet das „Nachdenken“ der Modelle wieder ein |
|
||||
| `FORMULA_STRUCTURAL` | `0` | `1` schaltet den Strukturvergleich mit sympy ein |
|
||||
|
||||
### Einstellungen je Buch (`workspace.json`)
|
||||
|
||||
Im Arbeitsordner unter `settings`, zum Beispiel:
|
||||
|
||||
```json
|
||||
{
|
||||
"settings": {
|
||||
"consensus_rule": "p2t",
|
||||
"consensus_thresholds": {"veto_ncc": 0.65, "bold_relevant": 0}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
| Schlüssel | Werte | Wirkung |
|
||||
|---|---|---|
|
||||
| `consensus_rule` | `p2t` (Standard), `vlm3` | Regel `vlm3`: Qwen = Gemma, bestätigt von GLM-4.6V über OpenRouter (bis 0.2.0) |
|
||||
| `decide` | `consensus` (Standard), `pixel` | `pixel`: alter Pixel-Entscheider (bis 0.1.0) |
|
||||
| `consensus_thresholds` | siehe [FUNKTIONSWEISE.md, Schwellen](FUNKTIONSWEISE.md#schwellen-settingsconsensus_thresholds-in-workspacejson) | Veto-Schwelle, Fettdruck, Schiedsrichter, PDF-Textebene … |
|
||||
| `preset` | wird beim ersten Prüfen gesetzt | Schrift für den Bildabgleich |
|
||||
|
||||
Nach einer Änderung `verify` aufrufen; die Modelle werden nicht neu gefragt.
|
||||
|
||||
---
|
||||
|
||||
## 6. Betrieb
|
||||
|
||||
**Dauer:** etwa 0,8 s je Formel, also 35–50 Sekunden je Paket (Corral mit `--formulas`: 940 Formeln in
|
||||
13 Minuten, das ganze Buch mit 9239 Formeln rund 2 Stunden). Am längsten braucht die Bestätigung durch
|
||||
Qwen. Der Scan liest beim ersten Mal alle Bilder ein (Corral: 6 Minuten); beim Fortsetzen entfällt er,
|
||||
solange sich das Markdown nicht geändert hat.
|
||||
|
||||
**Abbrechen und fortsetzen:** Strg+C und erneut `run` ist kein Problem. Bereits gelesene Formeln werden
|
||||
nicht noch einmal gefragt; fehlgeschlagene Anfragen werden wiederholt.
|
||||
|
||||
**Neu umgewandeltes Buch:** Nach `epub2md --force` erst `scan`, dann `apply`. Die Entscheidungen hängen am
|
||||
Bildinhalt und bleiben erhalten.
|
||||
|
||||
**Arbeitsordner:** `<ausgabe>.formulas/` neben der Ausgabe. Er enthält die Datensätze, Ausschnitte,
|
||||
Vergleichsbilder und die Sicherung von `apply`. Aufbau: [FUNKTIONSWEISE.md, Arbeitsordner](FUNKTIONSWEISE.md#3-arbeitsordner-und-datensätze).
|
||||
|
||||
**Datenschutz:** Mit der Standardregel verlässt nichts den Rechner. Die Regel `vlm3` schickt Formelbilder,
|
||||
bei denen Qwen und Gemma einig sind, samt eines kurzen Textausschnitts um die Formel (höchstens 240
|
||||
Zeichen) an OpenRouter; beim Gehrke-Brückenkurs waren das 967 Anfragen für zusammen rund 0,15–0,20 $.
|
||||
|
||||
---
|
||||
|
||||
## 7. Werkzeuge zum Messen und Einstellen
|
||||
|
||||
Die Werkzeuge schreiben nach `vergleich/` bzw. in den Arbeitsordner; beides wird nicht ins Git übernommen
|
||||
(Buchausschnitte).
|
||||
|
||||
| Werkzeug | Zweck |
|
||||
|---|---|
|
||||
| `tools/vergleich.py AUSGABE` | feste Stichprobe von 50 Formeln eines Buchs, verarbeitet wie `run`; Seite `vergleich/<name>/index.html` mit Original, gerenderten Lesarten, Entscheidung und Bildabgleich |
|
||||
| `tools/buch_bericht.py AUSGABE` | Ergebnisseite eines ganzen Buchs nach `run`, filterbar; liegt in `<arbeitsordner>/bericht/index.html` |
|
||||
| `tools/regeltest.py EPUB [--n 50] [--reuse …] [--refresh local,local2]` | Standardregel an Formeln mit bekanntem TeX, wie `run`; Seite mit wahrer Formel, allen Lesarten und Urteil |
|
||||
| `tools/zeittest.py EPUB` | Zeit und Trefferquote je Erkenner, seriell an 15 Formeln mit bekanntem TeX |
|
||||
| `tools/vergleich_bericht.py --regeltest VORHER:NACHHER` | Vorher/Nachher-Seite zweier Läufe auf denselben Lesarten |
|
||||
| `tools/konsens_bericht.py BERICHT.json EPUB` | Übersichtsseite zu `calibrate --consensus --report` |
|
||||
| `formula_img2latex.py calibrate --consensus --engines local,local2,cloud,p2t --report X.json EPUB` | alle Regeln an Formeln mit bekanntem TeX messen; `--reuse X.json` rechnet ohne Modellabfragen neu, `--synthetic` erzeugt zusätzlich Gehrke-ähnliche Nachbildungen |
|
||||
|
||||
Formeln mit bekanntem TeX liefern Springer-EPUBs, die das TeX jeder Formel im alt-Text tragen (z. B.
|
||||
Göllmann).
|
||||
|
||||
---
|
||||
|
||||
## 8. Fehlersuche
|
||||
|
||||
| Meldung oder Beobachtung | Ursache | Abhilfe |
|
||||
|---|---|---|
|
||||
| `Lokaler Modellserver unter http://127.0.0.1:8011/v1 nicht erreichbar` | Qwen-Server läuft nicht | Server starten ([2](#2-modellserver-starten-und-beenden)) |
|
||||
| `Stichwahl (Gemma) nicht möglich, strittige Formeln bleiben im Review` | Gemma-Server läuft nicht | Gemma starten und `run` erneut aufrufen |
|
||||
| Gemma bricht beim ersten Bild mit „out of memory“ ab | GPU 2 ist belegt | Chatterbox-TTS und STT stoppen ([2](#2-modellserver-starten-und-beenden)) |
|
||||
| `pix2text ist nicht installiert` / `pix2tex ist nicht installiert` | Pakete fehlen | Befehle aus [1](#pix2text-formel-ocr) ausführen |
|
||||
| `onnxruntime ohne CUDA – pip install onnxruntime-gpu` | nur die CPU-Version von onnxruntime | `pip uninstall -y onnxruntime && pip install onnxruntime-gpu` |
|
||||
| pix2text sehr langsam | läuft auf der CPU | `onnxruntime-gpu` installieren oder `FORMULA_P2T_DEVICE=cuda:0` |
|
||||
| `pdflatex nicht gefunden` / `pandoc nicht gefunden` | TeX Live bzw. Pandoc fehlen | `sudo apt install texlive-latex-extra pandoc` |
|
||||
| `Kein Arbeitsordner gefunden … (zuerst 'scan' ausführen)` | `verify`, `apply` usw. vor dem ersten `scan`/`run` | `scan` oder `run` ausführen |
|
||||
| `… ist weder eine epub2md-Ausgabe … noch eine pdf2md-Ausgabe` | falscher Pfad | epub2md-Ordner bzw. pdf2md-`.md`-Datei angeben |
|
||||
| `Arbeitsordner existiert und ist kein formula_img2latex-Ordner` | Zielordner von `--workspace` belegt | anderen Ordner wählen |
|
||||
| `Bildverweis nicht mehr gefunden: datei.md:123` | Markdown wurde neu erzeugt oder von Hand geändert | `scan` ausführen |
|
||||
| `revert` überspringt Dateien | seit `apply` von Hand geändert | prüfen, dann `revert --force` |
|
||||
| `OPENROUTER_API_KEY ist nicht gesetzt` | Regel `vlm3` oder `--engine cloud` ohne Schlüssel | Schlüssel setzen oder Regel `p2t` verwenden |
|
||||
| Formel bleibt in EPUB/PDF als TeX-Text stehen | Pandoc konnte sie nicht umsetzen (sollte die Pandoc-Prüfung verhindern) | Formel im Review korrigieren, Fall melden |
|
||||
|
||||
**Rückgabecodes:**
|
||||
|
||||
| Code | Bedeutung |
|
||||
|---|---|
|
||||
| 0 | Erfolg |
|
||||
| 1 | Bedienfehler: Parameter, Eingabe oder Arbeitsordner nicht lesbar oder belegt |
|
||||
| 2 | Eingabe ist keine epub2md- oder pdf2md-Ausgabe |
|
||||
| 3 | Externes Werkzeug fehlt oder versagt: pdflatex, pandoc, Modellserver, pix2text |
|
||||
| 4 | Unerwarteter interner Fehler (Traceback wird ausgegeben) |
|
||||
|
||||
---
|
||||
|
||||
## 9. Häufige Fragen
|
||||
|
||||
**Das Buch wurde mit epub2md `--force` neu umgewandelt. Ist meine Arbeit weg?**
|
||||
Nein. Die Entscheidungen hängen am Inhalt der Bilder, nicht an Dateinamen. `scan`, dann `apply`.
|
||||
|
||||
**Warum landet ein Teil im Review?**
|
||||
Ersetzt wird nur, was pix2text liest und Qwen (oder bei Uneinigkeit Gemma) bestätigt. Sind Qwen und Gemma
|
||||
gemeinsam anderer Meinung als pix2text, entscheidest du. Häufige Gründe für Review: ein Modell liest ein
|
||||
Zeichen anders (oft pix2text: `\nu` statt fettem v, Wörter wie „fir“ statt „für“), sehr kleine oder
|
||||
unscharfe Bilder, mehrzeilige Rechnungen mit anderen Zeilenumbrüchen oder `\underbrace`. Verschiedene
|
||||
Rahmen derselben Zeilen (`aligned`, `cases`, `&`) gelten seit 0.4.0 als gleich. Im Review stehen die Lesarten
|
||||
gemeinsam anderer Meinung als pix2text, entscheidest du. Häufige Gründe: ein Modell liest ein Zeichen anders
|
||||
(oft pix2text: `\nu` statt fettem v, Wörter wie „fir“ statt „für“), sehr kleine oder unscharfe Bilder,
|
||||
mehrzeilige Rechnungen mit anderen Zeilenumbrüchen oder `\underbrace`. Im Review stehen die Lesarten
|
||||
nebeneinander; oft genügt ein Blick und „LaTeX übernehmen“.
|
||||
|
||||
**Wie sicher ist „automatisch ersetzt“?**
|
||||
Gemessen an 300 Formeln mit bekannter Lösung: keine einzige falsche Formel wurde angenommen (Fehlerquote
|
||||
sehr wahrscheinlich unter 2 %). Am Gehrke-Brückenkurs wurden 62 automatisch ersetzte Formeln von Hand
|
||||
geprüft, alle korrekt. Fettdruck wird bewusst nicht geprüft: Ein fetter Vektor **v** kann als normales v
|
||||
übernommen werden.
|
||||
An einigen hundert Formeln mit bekannter Lösung wurde keine falsche Formel angenommen (Fehlerquote sehr
|
||||
wahrscheinlich unter 2 %). Fettdruck wird bewusst nicht geprüft: Ein fetter Vektor **v** kann als normales
|
||||
v übernommen werden. Messungen: [FUNKTIONSWEISE.md](FUNKTIONSWEISE.md#12-messungen).
|
||||
|
||||
**Ich will erst ein paar Formeln ansehen, bevor das ganze Buch läuft.**
|
||||
`python3 tools/vergleich.py AUSGABE` verarbeitet eine feste Stichprobe von 50 Formeln genau wie `run`
|
||||
und schreibt `vergleich/<name>/index.html`: Originalbild, die gerenderten Lesarten aller Modelle, die
|
||||
Entscheidung mit Grund und den Bildabgleich. Der Ordner `vergleich/` wird nicht ins Git übernommen.
|
||||
`python3 tools/vergleich.py AUSGABE` verarbeitet eine feste Stichprobe von 50 Formeln genau wie `run` und
|
||||
schreibt `vergleich/<name>/index.html`.
|
||||
|
||||
**Geht die blaue Hinterlegung mancher Formeln verloren?**
|
||||
Ja. Das Bild hatte die Farbe eingebaut, LaTeX-Formeln haben keinen Hintergrund.
|
||||
|
||||
**Werden Buchinhalte ins Internet geschickt?**
|
||||
Nein, mit der Standardregel bleibt alles lokal. Nur die frühere Regel `vlm3` schickt die Formelbilder, bei
|
||||
denen Qwen und Gemma einig sind, samt eines kurzen Textausschnitts um die Formel (höchstens 240 Zeichen)
|
||||
an OpenRouter/GLM.
|
||||
|
|
|
|||
247
CHANGELOG.md
247
CHANGELOG.md
|
|
@ -1,136 +1,151 @@
|
|||
# Changelog
|
||||
# Änderungsprotokoll
|
||||
|
||||
## Unveröffentlicht
|
||||
Alle nennenswerten Änderungen an formula_img2latex. Format nach
|
||||
[Keep a Changelog](https://keepachangelog.com/de/1.1.0/), Versionen nach
|
||||
[Semantic Versioning](https://semver.org/lang/de/) (vor 1.0: Nebenversion = möglicher Bruch).
|
||||
Messergebnisse im Einzelnen: [FUNKTIONSWEISE.md, Messungen](FUNKTIONSWEISE.md#12-messungen).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
Alle Formeln eines PDF-Buchs, auch im Fließtext, und etwa dreimal schneller.
|
||||
|
||||
- **pdf2md --formulas** (Nachbarprojekt): Die Formelerkennung von pix2text (MFD) findet jede Formel auf der
|
||||
Seite, eingebettet oder abgesetzt, auch in Merkkästen. Sie wird zeichengenau aus dem Text geschnitten
|
||||
(300 dpi) und mit Seite, Rechteck und PDF-Text in `formulas-*.json` vermerkt. "Formel"-Boxen mit Text
|
||||
werden zu Text, solche mit Kurven zu Grafiken. formula_img2latex liest die Liste
|
||||
(`sources/pdf2md.listed`). Corral, 10 % der 9239 Formeln: **79 % automatisch** (im Text 83 %).
|
||||
- **Eingebettete Formeln:** Ein Satzzeichen am Ende wird vor dem Vergleich abgetrennt und als Text hinter
|
||||
die Formel gesetzt (`final_suffix`).
|
||||
- **Normalform:** `\underset{…}{\lim}` = `\lim_{…}`, Gleichungsnummer am Ende = `\tag`, `\textbf` als
|
||||
Fettdruck, `\cfrac` = `\frac` (pix2text schreibt `\dfrac`), wörtliches `\n` aus Modellantworten entfällt.
|
||||
- **Tempo** (Pilot 869 Formeln: 70 → ~24 min):
|
||||
- Markdown-Verweise und Ausschnitte nur einmal lesen (`crops/`);
|
||||
- pix2text gebündelt nach Pixelbudget, auf der freiesten GPU, einmal geladen;
|
||||
- Lesen und Prüfen überlappen, die Prüfprozesse starten per `forkserver`;
|
||||
- Qwen mit 8 parallelen Anfragen (`llama-server --parallel 8 -c 32768`);
|
||||
- pdflatex beim Entscheiden nur, wenn gleiche Bilder möglich sind;
|
||||
- kein neuer Scan beim Fortsetzen;
|
||||
- je Paket nur dessen Datensätze laden;
|
||||
- Zeiten je Stufe in der Statuszeile.
|
||||
- **Bildprüfung:** Originale höchstens 1600 px breit, über 2,5 MP nicht, Lesarten mit mehr als 2,5-fach
|
||||
falschen Proportionen sofort abgelehnt. Vorher hielten einzelne Formeln den Lauf über 10 Minuten auf.
|
||||
- **Gemessen und verworfen:**
|
||||
- PDF-Textebene als Bestätigung: 12 von 319 widersprachen Qwen, fehlende Punkte und Indizes; Schalter
|
||||
`pdftext` bleibt aus.
|
||||
- pix2texts eigene Sicherheit: Fehler auch bei 1,0.
|
||||
- Qwen3-VL-8B: nicht schneller als das MoE-30B-Modell (3B aktiv), etwas schlechter.
|
||||
- **Offen:** Formeln in Tabellen.
|
||||
### Neu
|
||||
- **Formeln im Fließtext** über `pdf2md --formulas` (Nachbarprojekt): Die Formelerkennung von pix2text (MFD)
|
||||
findet jede Formel auf der Seite, auch in Merkkästen; pdf2md schneidet sie zeichengenau aus (300 dpi) und
|
||||
vermerkt Seite, Rechteck und PDF-Text in `formulas-*.json`. formula_img2latex liest die Liste
|
||||
(`sources/pdf2md.listed`). Corral, Stichprobe 10 % von 9239 Formeln: 79 % automatisch (im Text 83 %).
|
||||
- Ein Satzzeichen am Ende einer Formel im Text wird vor dem Vergleich abgetrennt und als Text hinter die
|
||||
Formel gesetzt (`final_suffix`).
|
||||
- Normalform: `\underset{…}{\lim}` = `\lim_{…}`, Gleichungsnummer am Ende = `\tag`, `\textbf` als Fettdruck,
|
||||
`\cfrac` = `\frac`, wörtliches `\n` aus Modellantworten entfällt.
|
||||
- Schalter `pdftext` (aus): Die PDF-Textebene einer flachen Formel darf pix2text bestätigen.
|
||||
- `LICENSE` (MIT) und `FUNKTIONSWEISE.md` (Aufbau, Datenfluss, Designentscheidungen, Grenzen).
|
||||
|
||||
## 0.4.0 – 2026-10-09
|
||||
### Geändert
|
||||
- **Tempo** (Pilot 869 Formeln: 70 → ~24 Minuten): Markdown-Verweise und Ausschnitte nur einmal lesen
|
||||
(`crops/`); pix2text gebündelt nach Pixelbudget auf der freiesten GPU, einmal geladen; Lesen und Prüfen
|
||||
überlappen, die Prüfprozesse starten per `forkserver`; Qwen mit 8 parallelen Anfragen; pdflatex beim
|
||||
Entscheiden nur, wenn gleiche Bilder möglich sind; kein neuer Scan beim Fortsetzen; je Paket nur dessen
|
||||
Datensätze laden; Zeiten je Stufe in der Statuszeile.
|
||||
- Bildprüfung: Originale höchstens 1600 px breit, über 2,5 MP nicht verglichen, Lesarten mit mehr als
|
||||
2,5-fach falschen Proportionen sofort abgelehnt (einzelne Formeln hielten den Lauf über 10 Minuten auf).
|
||||
- Dokumentation nach dem Projektstandard gegliedert: README knapp mit Abschnitt „Documentation“,
|
||||
Bedienungsanleitung mit Konfiguration, Betrieb und Fehlersuche, Hintergrund und Messungen in
|
||||
`FUNKTIONSWEISE.md`.
|
||||
- Hilfetexte der Kommandozeile beschreiben die Regel `p2t` statt des Pixelvergleichs; Cloud-Standard
|
||||
`z-ai/glm-4.6v` statt `google/gemini-2.5-flash`.
|
||||
|
||||
### Behoben
|
||||
- `requirements.txt` enthält `requests` (von den Modell-Engines benötigt).
|
||||
|
||||
Gemessen und verworfen: PDF-Textebene als Bestätigung (12 von 319 widersprachen Qwen), pix2texts eigene
|
||||
Sicherheit (Fehler auch bei 1,0), Qwen3-VL-8B (nicht schneller, etwas schlechter).
|
||||
|
||||
### Beim Update zu tun
|
||||
- `pip install -r requirements.txt`.
|
||||
- Qwen-Server mit `--parallel 8 -c 32768` neu starten (BEDIENUNGSANLEITUNG, Abschnitt 2).
|
||||
- Für Formeln im Fließtext: aktuelles pdf2md verwenden und das Buch mit `--formulas` neu umwandeln.
|
||||
- Bestehende Arbeitsordner bleiben gültig; Lesarten werden nicht neu gefragt.
|
||||
|
||||
## [0.4.0] – 2026-10-09
|
||||
|
||||
Bessere Normalform: Lesarten, die sich nur in der Schreibweise unterscheiden, gelten als gleich.
|
||||
Göllmann (400 Formeln mit bekannter Lösung, gleiche Lesarten): **+17 automatisch, weiterhin 0 falsch**.
|
||||
Göllmann (400 Formeln mit bekannter Lösung, gleiche Lesarten): +17 automatisch, weiterhin 0 falsch.
|
||||
|
||||
- **Mehrzeilige Formeln:** gleich bei gleichen Zeilen mit gleichen Zeichen, egal in welchem Rahmen
|
||||
### Neu
|
||||
- **Mehrzeilige Formeln** sind gleich bei gleichen Zeilen mit gleichen Zeichen, egal in welchem Rahmen
|
||||
(`aligned`/`gathered`/`split` mit `&` oder nur `\\`; `cases` = `\left\{array\right.` =
|
||||
`\left\{aligned\right.`); eine leere letzte Zeile zählt nicht. In Matrizen trennt `&` weiter Spalten.
|
||||
- **Argumente nach Argumentzahl:** Eine Gruppe ist nur Argument, wenn der Befehl noch eines erwartet
|
||||
(`t^{2}\,{\sqrt{2}}` = `t^2\sqrt{2}`, `\Delta{x_{n}}` = `\Delta x_n`).
|
||||
- **Weitere Gleichsetzungen:** `\cdot\cdot\cdot` und `...` = `\dots`, `\root3\of{x}` = `\sqrt[3]{x}`,
|
||||
- Weitere Gleichsetzungen: `\cdot\cdot\cdot` und `...` = `\dots`, `\root3\of{x}` = `\sqrt[3]{x}`,
|
||||
`\left.`/`\right.` entfallen.
|
||||
- **Messung genauer:** Der Wahrheitsvergleich nutzt dieselbe Normalform; richtige mehrzeilige Lesarten
|
||||
zählten bisher als falsch (pix2text allein richtig: Band 2 jetzt 45/50 und 47/50).
|
||||
- **Ergebnis:** Band 1 89 % / 88 % automatisch (bisher 86 % / 85 %), Band 2 44 und 45 von 50 (bisher 39
|
||||
und 43), 0 falsch.
|
||||
- **Strukturvergleich mit sympy** (`structure.py`, neu, optional, aus): gleicher unausgewerteter
|
||||
Ausdrucksbaum, nichts umgerechnet; Relationen nie an sympy, Zeichen durch Platzhalter geschützt.
|
||||
Brachte vor der neuen Normalform +1 Formel, danach nichts – `structural` = 1 bzw.
|
||||
`FORMULA_STRUCTURAL=1` schaltet ihn ein (`pip install sympy lark`).
|
||||
- **Bild-Schiedsrichter** (`verify.image_arbiter`, gemessen, aus): bei „Qwen = Gemma gegen pix2text“
|
||||
entscheidet der Bildbeleg. +11 Formeln ab Schwelle 8, aber der gemeinsame Fehler `\mathcal{E}_r`
|
||||
bekam Beleg 7,2 – zu knapp. Einstellungen `arbiter`, `arbiter_margin`.
|
||||
- **Prompt-Stilvorgabe** getestet und verworfen (Band 2: 44/44 statt 44/45; die Modelle schrieben nach
|
||||
`\\` ein wörtliches `\n`). Prompt-Version bleibt 2, gespeicherte Lesarten bleiben gültig.
|
||||
- **Werkzeuge:** `tools/vergleich_bericht.py` (Vorher/Nachher-Seite zweier Läufe), `regeltest.py
|
||||
--refresh` (Engines trotz `--reuse` neu fragen) und `--arbiter`; `calibrate` misst den
|
||||
Schiedsrichter (Werte je Fall, Schwellen) und listet nur strukturell gefundene Übereinstimmungen;
|
||||
`tools/buch_bericht.py` (Ergebnisseite eines ganzen Buchs: jede Formel mit Original, gesetztem
|
||||
LaTeX, Status, Begründung und allen Lesarten, filterbar).
|
||||
- **Erstes ganzes PDF-Buch** (Corral, *Elementary Calculus*, 346 Seiten, pdf2md): 1150 Ausschnitte,
|
||||
**429 automatisch ersetzt (37 %)**, 633 Review, 61 keine Formel. Gefundene und behobene Probleme:
|
||||
- pix2text schreibt hier Brüche als `\cfrac`: in der Normalform = `\frac`, beim Bereinigen zu
|
||||
`\dfrac` (Pandoc kennt `\cfrac` nicht und ließ die Formel als TeX-Text stehen).
|
||||
- Qwen und Gemma schreiben Zeilenumbrüche als wörtliches `\n` (`\begin{aligned}\n…`): wird zu
|
||||
Leerraum (`tex.fix_literal_newlines`), echte Befehle wie `\nu`, `\neq` bleiben.
|
||||
- 600-dpi-Ausschnitte bis 3800 × 2700 Pixel: Qwen lehnte sie ab („400 Bad Request“, Kontext voll),
|
||||
eine ganzseitige Abbildung (33 MP) brachte den Bildvergleich zum Absturz. Jetzt: Bilder für die
|
||||
Modelle höchstens 1600 Pixel lang, Bildvergleich nur bis 4 MP (größte übernommene Formel: 1,7 MP).
|
||||
- Fehlgeschlagene Modellanfragen werden beim nächsten Lauf wiederholt (zählten als „schon gefragt“).
|
||||
- Göllmann danach unverändert: 0 falsch.
|
||||
- Grenze: pdf2md schneidet in diesem Buch auch Merkkästen mit Text, Tabellen und ganze
|
||||
Herleitungsblöcke als „Formel“ aus; sie bilden den Großteil des Reviews.
|
||||
- **Strukturvergleich mit sympy** (`structure.py`, optional, aus): gleicher unausgewerteter
|
||||
Ausdrucksbaum. Einschalten mit `structural` = 1 bzw. `FORMULA_STRUCTURAL=1`.
|
||||
- **Bild-Schiedsrichter** (`verify.image_arbiter`, aus): bei „Qwen = Gemma gegen pix2text“ entscheidet
|
||||
der Bildbeleg. Einstellungen `arbiter`, `arbiter_margin`.
|
||||
- Werkzeuge: `tools/vergleich_bericht.py` (Vorher/Nachher-Seite), `tools/buch_bericht.py`
|
||||
(Ergebnisseite eines ganzen Buchs), `regeltest.py --refresh` und `--arbiter`.
|
||||
|
||||
## 0.3.0 – 2026-10-09
|
||||
### Geändert
|
||||
- Eine Klammergruppe ist nur Argument, wenn der Befehl noch eines erwartet (`t^{2}\,{\sqrt{2}}` =
|
||||
`t^2\sqrt{2}`, `\Delta{x_{n}}` = `\Delta x_n`).
|
||||
- Der Wahrheitsvergleich der Messung nutzt dieselbe Normalform (richtige mehrzeilige Lesarten zählten
|
||||
bisher als falsch).
|
||||
- Bilder für die Modelle höchstens 1600 Pixel lang.
|
||||
|
||||
Neue Standardregel `p2t`: **pix2text liest zuerst, Qwen bestätigt, Gemma nur bei Uneinigkeit**; GLM (Cloud)
|
||||
wird nicht mehr benutzt.
|
||||
### Behoben
|
||||
- pix2texts `\cfrac` wird beim Bereinigen zu `\dfrac` (Pandoc kennt `\cfrac` nicht und ließ die Formel als
|
||||
TeX-Text stehen).
|
||||
- Wörtliches `\n` in Antworten von Qwen und Gemma wird zu Leerraum (`tex.fix_literal_newlines`).
|
||||
- Sehr große Ausschnitte: Qwen lehnte sie ab („400 Bad Request“), eine ganzseitige Abbildung brachte den
|
||||
Bildvergleich zum Absturz.
|
||||
- Fehlgeschlagene Modellanfragen werden beim nächsten Lauf wiederholt (zählten als „schon gefragt“).
|
||||
|
||||
Gemessen und verworfen: Strukturvergleich (nach der neuen Normalform kein Gewinn), Bild-Schiedsrichter
|
||||
(der gemeinsame Fehler `\mathcal{E}_r` bekam Beleg 7,2), Prompt-Stilvorgabe (keine Verbesserung).
|
||||
Erstes ganzes PDF-Buch: Corral, *Elementary Calculus*, 1150 Ausschnitte, 429 automatisch (37 %).
|
||||
|
||||
### Beim Update zu tun
|
||||
- Nichts Pflichtiges. Prompt-Version bleibt 2, gespeicherte Lesarten bleiben gültig; `run` rechnet die
|
||||
Entscheidungen mit der neuen Normalform neu.
|
||||
- Optional für den Strukturvergleich: `pip install sympy lark`.
|
||||
|
||||
## [0.3.0] – 2026-10-09
|
||||
|
||||
Neue Standardregel `p2t`: pix2text liest zuerst, Qwen bestätigt, Gemma nur bei Uneinigkeit; GLM (Cloud) wird
|
||||
nicht mehr benutzt. Göllmann Band 1: 86 % / 85 % automatisch, 0 falsch (bisher 78 % / 70 %).
|
||||
|
||||
### Neu
|
||||
- **pix2text** (Formel-OCR MFR 1.5, ONNX) als Engine `p2t`, im Prozess, auf der GPU mit `onnxruntime-gpu`
|
||||
(`FORMULA_P2T_DEVICE`: `auto`, `cpu`, `cuda:N`). Allein am häufigsten richtig (Göllmann Band 1: 90 % /
|
||||
85 %) und am schnellsten (0,1 s/Formel auf der GPU, Qwen 0,7 s, Gemma 1,8 s).
|
||||
- **Regel:** übernommen wird immer pix2texts Lesart (trifft den Fettdruck am besten), wenn Qwen sie
|
||||
bestätigt oder – nur bei Uneinigkeit gefragt – Gemma. Qwen und Gemma gemeinsam gegen pix2text gehen
|
||||
an einen Menschen (so kamen an Band 1 die gemeinsamen Fehler der beiden Bildmodelle durch). Der
|
||||
Schlusspunkt muss bestätigt sein. Bild-Veto und Pandoc wie bisher, geprüft auf pix2texts Lesart.
|
||||
Die alte Regel bleibt als `"consensus_rule": "vlm3"` in `workspace.json` wählbar.
|
||||
- **pix2text-Ausgabe bereinigt:** Leerzeichen mit `post_process` aus pix2tex (installiert mit
|
||||
`--no-deps`), Fettschreibweisen `\mathrm{\boldmath~ x ~}` / `\mathrm{\bf~ r o t}` →
|
||||
`\boldsymbol{x}` / `\mathbf{rot}`. An 400 Lesarten geprüft: gleiches gesetztes Bild.
|
||||
- **Normalform:** `\operatorname{l i m}` = `\lim`, `\ddot{u}` in Text = ü, `^{\prime}` = `'`,
|
||||
abschließendes `\\` vor `\end`, `\begin{array}[t]`, `\mathop{…}`.
|
||||
- **calibrate:** beliebig viele Engines (`--engines`), Regel-Tabelle, `--reuse` rechnet aus einem
|
||||
früheren Bericht ohne Modellabfragen; wahre Formeln aus dem alt-Text werden bereinigt
|
||||
(einzeiliges `aligned`, `\mathop{}\!\mathrm{d}`, upgreek).
|
||||
- **Werkzeuge:** `tools/zeittest.py` (Zeit und Trefferquote je Tool), `tools/regeltest.py` (Standardregel
|
||||
an Formeln mit bekanntem TeX, Seite zum Mitbeurteilen; `--reuse`, `--exclude`).
|
||||
- **Messung:** Göllmann Band 1 (2 × 150) 86 % / 85 % automatisch, 0 falsch (bisher 78 % / 70 %);
|
||||
Band 2, zwei frische Stichproben zu 50: 78 % und 86 % automatisch, 0 falsch.
|
||||
(`FORMULA_P2T_DEVICE`: `auto`, `cpu`, `cuda:N`).
|
||||
- **Regel `p2t`:** übernommen wird pix2texts Lesart, wenn Qwen sie bestätigt oder – nur bei Uneinigkeit
|
||||
gefragt – Gemma. Qwen und Gemma gemeinsam gegen pix2text gehen an einen Menschen.
|
||||
- `calibrate`: beliebig viele Engines (`--engines`), Regel-Tabelle, `--reuse` ohne Modellabfragen.
|
||||
- Werkzeuge: `tools/zeittest.py`, `tools/regeltest.py`.
|
||||
|
||||
## 0.2.0 – 2026-10-07
|
||||
### Geändert
|
||||
- pix2text-Ausgabe bereinigt: Leerzeichen mit `post_process` aus pix2tex, Fettschreibweisen
|
||||
`\mathrm{\boldmath~ x ~}` → `\boldsymbol{x}`. An 400 Lesarten geprüft: gleiches gesetztes Bild.
|
||||
- Normalform: `\operatorname{l i m}` = `\lim`, `\ddot{u}` in Text = ü, `^{\prime}` = `'`, abschließendes
|
||||
`\\` vor `\end`, `\begin{array}[t]`, `\mathop{…}`.
|
||||
|
||||
Entscheider ist jetzt der **Konsens dreier Bildmodelle** statt eines Pixelvergleichs.
|
||||
### Beim Update zu tun
|
||||
- pix2text installieren: `pip install "pix2text[multilingual]"`, `pip install --no-deps pix2tex munch`,
|
||||
für die GPU `pip uninstall -y onnxruntime && pip install onnxruntime-gpu`.
|
||||
- Bestehende Arbeitsordner: `run` erneut aufrufen; pix2text liest nach, Qwen-Lesarten bleiben gültig.
|
||||
- Wer die Regel mit GLM behalten will: `"consensus_rule": "vlm3"` in `workspace.json`.
|
||||
|
||||
- **Annahmeregel:** jedes Zeichen richtig und an der richtigen Stelle; Abstände, Längen, Schriftgröße,
|
||||
kursiv/aufrecht und Fettdruck egal.
|
||||
- **Konsens:** Qwen3-VL-30B-A3B (lokal) = Gemma-4-26B-A4B (lokal) = GLM-4.6V (OpenRouter, andere
|
||||
Modellfamilie); Pandoc muss die Formel umsetzen; grobes Bild-Veto (elastischer Vergleich,
|
||||
Ähnlichkeit ≥ 0,65). Bei 2:1 entscheidet ein Mensch.
|
||||
- **`consensus.py`:** Normalform auf Baumbasis (Abstände, `\left`/`\right`, freistehende Klammern,
|
||||
`\vec`/`\overrightarrow`, `\frac`/`\dfrac`, `\iff`/`\Leftrightarrow`, Matrix-Umgebungen, TeX-Umlaute,
|
||||
`\atop`/`\substack`, kursiv/aufrecht, fett/normal) und Render-Gleichheit als Rückfallebene.
|
||||
- **Engines:** zweite lokale Engine `local2`; Token-Wahrscheinlichkeiten aus Logprobs; Nachdenken
|
||||
abgeschaltet (Gemma ~10× schneller, GLM besser und ~25× billiger); Antworten auf 800 Tokens begrenzt;
|
||||
Prompt fragt ausdrücklich nach Fettdruck; Prompt-Version und Nachdenk-Einstellung im Cache-Schlüssel.
|
||||
- **`run`:** in Paketen zu 50 mit Statuszeile; beide lokalen Modelle parallel; GLM nur für Einige;
|
||||
geprüft wird nur die übernommene Lesart; Prüfergebnisse mit Verfahrensversion.
|
||||
- **Bildvergleich:** elastische Ausrichtung (DTW über Spalten und Zeilen, Dehnen kostet proportional zur
|
||||
Tinte); layouttreue Prüfvarianten und rauschnormierter Kontrast im Pixel-Modus (`decide=pixel`).
|
||||
- **apply:** deutsches Dezimalkomma `3{,}6`.
|
||||
- **Behoben:** Gleichungsnummern wurden aus alten, verworfenen Lesarten übernommen (erfundene „(3.7)“);
|
||||
sie kommen jetzt nur aus der übernommenen Lesart. Gleichzeitige Speicherungen zweier Engines sind
|
||||
abgesichert. Verify stürzte bei Formeln ohne aktuelle Lesart ab.
|
||||
- **Werkzeuge:** `calibrate --consensus`, `tools/vergleich.py` (50er-Stichprobe mit Bildern),
|
||||
`tools/konsens_bericht.py`; Ausgaben in `vergleich/` (nicht versioniert).
|
||||
- **Messung** (2 × 150 Formeln mit bekanntem TeX): 63–68 % automatisch, 0 falsch.
|
||||
Gehrke-Brückenkurs: 942 von 1505 automatisch (63 %), 62 von 62 geprüften korrekt.
|
||||
## [0.2.0] – 2026-10-07
|
||||
|
||||
## 0.1.0 – 2026-10-07
|
||||
Entscheider ist der Konsens dreier Bildmodelle statt eines Pixelvergleichs.
|
||||
Gehrke-Brückenkurs: 942 von 1505 automatisch (63 %), 62 von 62 geprüften korrekt.
|
||||
|
||||
Erste Fassung: scan, recognize (ein Vision-Modell), verify mit Pixelvergleich und Kontrasttest gegen
|
||||
Verwechslungsvarianten, Review-Galerie, apply/revert, calibrate. Sicher (0 Falsch-Annahmen), aber an
|
||||
echten Büchern nur 1–2 % automatisch.
|
||||
### Neu
|
||||
- **Konsens:** Qwen3-VL-30B-A3B (lokal) = Gemma-4-26B-A4B (lokal) = GLM-4.6V (OpenRouter); Pandoc muss die
|
||||
Formel umsetzen; grobes Bild-Veto (elastischer Vergleich, Ähnlichkeit ≥ 0,65).
|
||||
- `consensus.py`: Normalform auf Baumbasis und Render-Gleichheit als Rückfallebene.
|
||||
- Zweite lokale Engine `local2`; Token-Wahrscheinlichkeiten aus Logprobs.
|
||||
- `run` in Paketen zu 50 mit Statuszeile; `calibrate --consensus`; `tools/vergleich.py`,
|
||||
`tools/konsens_bericht.py`.
|
||||
- `apply`: deutsches Dezimalkomma `3{,}6`.
|
||||
|
||||
### Geändert
|
||||
- Nachdenken der Modelle abgeschaltet (Gemma ~10× schneller, GLM besser und ~25× billiger); Antworten auf
|
||||
800 Tokens begrenzt; Prompt fragt ausdrücklich nach Fettdruck.
|
||||
- Elastischer Bildvergleich (DTW über Spalten und Zeilen, Dehnen kostet proportional zur Tinte).
|
||||
- Geprüft wird nur die übernommene Lesart; Prüfergebnisse tragen eine Verfahrensversion.
|
||||
|
||||
### Behoben
|
||||
- Gleichungsnummern wurden aus alten, verworfenen Lesarten übernommen (erfundene „(3.7)“).
|
||||
- Gleichzeitiges Speichern zweier Engines; Absturz bei Formeln ohne aktuelle Lesart.
|
||||
|
||||
### Beim Update zu tun
|
||||
- Zwei llama.cpp-Server starten (Qwen auf Port 8011, Gemma auf Port 8012) und Gemma laden
|
||||
(BEDIENUNGSANLEITUNG, Abschnitte 1 und 2); `OPENROUTER_API_KEY` setzen.
|
||||
- Arbeitsordner aus 0.1.0: Standard ist jetzt der Konsens; den alten Entscheider behält
|
||||
`"decide": "pixel"` in `workspace.json`.
|
||||
|
||||
## [0.1.0] – 2026-10-07
|
||||
|
||||
Erstveröffentlichung: scan, recognize (ein Bildmodell), verify mit Pixelvergleich und Kontrasttest gegen
|
||||
Verwechslungsvarianten, Review-Galerie, apply/revert, calibrate. Sicher (0 Falsch-Annahmen), aber an echten
|
||||
Büchern nur 1–2 % automatisch.
|
||||
|
|
|
|||
432
FUNKTIONSWEISE.md
Normal file
432
FUNKTIONSWEISE.md
Normal file
|
|
@ -0,0 +1,432 @@
|
|||
# formula_img2latex – Funktionsweise
|
||||
|
||||
Dieses Dokument erklärt, **wie formula_img2latex innen arbeitet und warum es so gebaut ist**. Für die
|
||||
Benutzung siehe [BEDIENUNGSANLEITUNG.md](BEDIENUNGSANLEITUNG.md), für Änderungen je Version
|
||||
[CHANGELOG.md](CHANGELOG.md).
|
||||
|
||||
Stand: Version 0.4.0 und unveröffentlichte Änderungen (siehe CHANGELOG, Abschnitt `[Unreleased]`)
|
||||
|
||||
---
|
||||
|
||||
## Inhaltsverzeichnis
|
||||
|
||||
1. [Überblick](#1-überblick)
|
||||
2. [Module](#2-module)
|
||||
3. [Arbeitsordner und Datensätze](#3-arbeitsordner-und-datensätze)
|
||||
4. [Ablauf von `run`](#4-ablauf-von-run)
|
||||
5. [Die Erkenner](#5-die-erkenner)
|
||||
6. [Entscheidungsregel](#6-entscheidungsregel)
|
||||
7. [Wann zwei Lesarten dieselbe Formel sind](#7-wann-zwei-lesarten-dieselbe-formel-sind)
|
||||
8. [Bild-Veto: der elastische Bildvergleich](#8-bild-veto-der-elastische-bildvergleich)
|
||||
9. [apply und revert](#9-apply-und-revert)
|
||||
10. [Quellen: epub2md und pdf2md](#10-quellen-epub2md-und-pdf2md)
|
||||
11. [Sicherheit](#11-sicherheit)
|
||||
12. [Messungen](#12-messungen)
|
||||
13. [Designentscheidungen](#13-designentscheidungen)
|
||||
14. [Grenzen](#14-grenzen)
|
||||
|
||||
---
|
||||
|
||||
## 1. Überblick
|
||||
|
||||
Ein Formelbild wird nur durch LaTeX ersetzt, wenn **zwei verschiedenartige Erkenner dieselbe Formel lesen**
|
||||
und ein grober Bildabgleich nicht widerspricht. Die Annahmeregel des Projekts:
|
||||
|
||||
> Jedes Zeichen muss stimmen und an der richtigen Stelle relativ zu den anderen stehen. Abstände,
|
||||
> Pfeil- und Bruchstrichlängen, Schriftgröße, kursiv/aufrecht und Fettdruck dürfen abweichen.
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
A["Markdown von<br/>epub2md oder pdf2md<br/>mit Formelbildern"] --> S["scan<br/>Bildverweise finden,<br/>Formel oder Abbildung?"]
|
||||
S --> R1["pix2text<br/>(Formel-OCR)<br/>liest jede Formel"]
|
||||
R1 --> R2["Qwen3-VL<br/>(Bildmodell)<br/>liest jede Formel"]
|
||||
R2 --> V["Bild-Veto<br/>pix2texts Lesart rendern<br/>und elastisch vergleichen"]
|
||||
V --> D{"Entscheidung<br/>pix2text = Qwen?"}
|
||||
D -->|"uneinig"| G["Gemma 4<br/>(zweites Bildmodell)<br/>Stichwahl"]
|
||||
G --> D2{"Gemma = pix2text?"}
|
||||
D -->|"einig, Veto und<br/>Pandoc bestanden"| OK["auto_accepted"]
|
||||
D2 -->|"ja"| OK
|
||||
D2 -->|"nein"| RV["needs_review<br/>Review-Galerie"]
|
||||
RV -->|"Mensch übernimmt<br/>oder korrigiert"| OK
|
||||
OK --> AP["apply<br/>Bildverweis im Markdown<br/>→ LaTeX-Formel"]
|
||||
```
|
||||
|
||||
Übernommen wird immer die Lesart von pix2text; Qwen und Gemma bestätigen nur. Was nicht bestätigt ist,
|
||||
bleibt Bild, bis ein Mensch entscheidet.
|
||||
|
||||
---
|
||||
|
||||
## 2. Module
|
||||
|
||||
| Modul | Aufgabe | Wichtigste Namen |
|
||||
|---|---|---|
|
||||
| `cli.py` | Unterbefehle, Rückgabecodes | `main`, `build_parser` |
|
||||
| `pipeline.py` | scan, recognize, verify, Entscheidung, `run` in Paketen, apply/revert | `scan`, `recognize`, `verify_all`, `decide_all_consensus`, `run_consensus`, `apply`, `revert` |
|
||||
| `decide.py` | Annahmeregeln und Schwellen | `decide_pair_tiebreak` (Regel `p2t`), `decide_consensus` (Regel `vlm3`), `decide` (Pixel-Modus), `CONSENSUS_DEFAULTS` |
|
||||
| `consensus.py` | Sagen zwei Lesarten dasselbe? | `canonical`, `same_reading`, `render_equal` |
|
||||
| `structure.py` | Strukturvergleich mit sympy (optional, aus) | `structural_equal` |
|
||||
| `engines/p2t.py` | pix2text (MFR 1.5, ONNX) im Prozess, gebündelt, CPU oder GPU | `Pix2TextEngine`, `tidy_p2t`, `resolve_device` |
|
||||
| `engines/vlm.py` | Bildmodelle über die OpenAI-API (llama.cpp, OpenRouter), Logprobs | `VisionEngine`, `PROMPT`, `PROMPT_VERSION`, `prepare_image`, `parse_answer` |
|
||||
| `verify.py` | Bildprüfung einer Lesart (Veto bzw. Pixel-Entscheider) | `verify`, `image_arbiter` |
|
||||
| `compare.py` | Ausrichtung, elastische Verzerrung, Kennzahlen, Kontrast, Diff-Bilder | `compare`, `elastic_warp`, `contrast`, `diff_image` |
|
||||
| `render.py` | pdflatex-Batch, Schrift-Presets, Rasterung | `render_many`, `PRESETS` |
|
||||
| `confusables.py` | Verwechslungsvarianten (nur Pixel-Modus) | `variants`, `EQUIVALENT` |
|
||||
| `tex.py` | TeX-Hilfen: Begrenzer, Sicherheitsprüfung, Gleichungsnummern | `unsafe_reason`, `split_tag`, `prepare_for_render`, `text_to_tex` |
|
||||
| `imageio.py` | Originale laden: PNG/GIF/JPG/SVG, Transparenz, getönter Hintergrund | `load_ink`, `gray_to_ink`, `color_stats` |
|
||||
| `classify.py` | Vorfilter: Formel, unklar oder Abbildung | `classify` |
|
||||
| `checks.py` | Pandoc/MathML-Prüfung | `pandoc_mathml_ok` |
|
||||
| `sources/` | Quellen: Markdown-Scan, Begrenzer, Dezimalkomma; epub2md, pdf2md | `open_source`, `scan_markdown`, `Epub2MdSource`, `Pdf2MdSource` |
|
||||
| `pdfcrop.py` | Box-Bild auf der PDF-Seite finden, 600-dpi-Neuausschnitt | `PdfCropper` |
|
||||
| `store.py` | Arbeitsordner, ein JSON-Datensatz je Formel | `Workspace`, `Formula`, `STATUSES` |
|
||||
| `calibrate.py` | Messung an Formelbildern mit bekanntem TeX | `calibrate`, `calibrate_consensus` |
|
||||
| `review/` | lokaler Review-Server und Seite | `serve` |
|
||||
| `tools/` | Mess- und Berichtswerkzeuge (nicht Teil des Pakets) | `vergleich.py`, `regeltest.py`, `zeittest.py`, `buch_bericht.py`, `konsens_bericht.py`, `vergleich_bericht.py` |
|
||||
|
||||
---
|
||||
|
||||
## 3. Arbeitsordner und Datensätze
|
||||
|
||||
```text
|
||||
<ausgabe>.formulas/
|
||||
├── workspace.json # Quelle, Schrift, Einstellungen, letzter Scan, apply-Zustand
|
||||
├── formulas/f-<sha12>-<d|i>.json # ein Datensatz je Bild und Darstellung (d = abgesetzt, i = im Text)
|
||||
├── crops/<id>.png # Original je Formel, einmal ausgeschnitten (PDF-Quellen)
|
||||
├── review/<id>-{orig,render,rigid,diff}.png # Bilder des Bildabgleichs
|
||||
├── bericht/ # Ergebnisseite (tools/buch_bericht.py)
|
||||
└── backup/ # Markdown-Dateien vor dem ersten apply
|
||||
```
|
||||
|
||||
Der Arbeitsordner liegt **neben** der Ausgabe, weil `epub2md --force` die Ausgabe vollständig ersetzt.
|
||||
|
||||
Ein Datensatz (`store.Formula`) hält: Bildpfad und SHA-256, Darstellung (abgesetzt oder im Text), alle
|
||||
Fundstellen im Markdown (Datei, Zeile, genauer Bildverweis, Textausschnitt), die Vorklassifikation, **alle
|
||||
Lesarten** (je Engine, Modell, Prompt-Version und Nachdenk-Einstellung, mit Zeit und Token-Wahrscheinlichkeiten),
|
||||
das Ergebnis des Bildabgleichs, Status, Begründung und das endgültige LaTeX (`final_tex`, dazu
|
||||
`final_suffix` für ein abgetrenntes Satzzeichen).
|
||||
|
||||
**Schlüssel und Zwischenspeicher:**
|
||||
|
||||
| Was | Schlüssel | Wirkung |
|
||||
|---|---|---|
|
||||
| Datensatz | SHA-256 des Bildes + Darstellung | ein erneuter epub2md-Lauf verliert keine Entscheidung |
|
||||
| Lesart | Engine, Modell, `PROMPT_VERSION`, Nachdenken | dieselbe Frage wird nie zweimal gestellt; fehlgeschlagene Anfragen werden wiederholt |
|
||||
| Bildabgleich | `VERIFY_VERSION` + geprüfte Lesart | nach einer Änderung am Vergleich wird neu gerechnet |
|
||||
| Scan | Größe und Zeitstempel aller Markdown-Dateien | beim Fortsetzen entfällt der Scan, solange sich das Markdown nicht ändert |
|
||||
|
||||
**Status:** `pending`, `auto_accepted`, `needs_review`, `not_formula`, `rejected_keep_image`,
|
||||
`render_failed`, `no_candidate`; nach dem Review `accepted_by_human`, `corrected_by_human`,
|
||||
`kept_by_human`. `apply` schreibt `auto_accepted`, `accepted_by_human` und `corrected_by_human`.
|
||||
|
||||
---
|
||||
|
||||
## 4. Ablauf von `run`
|
||||
|
||||
`run` verarbeitet die Formeln in **Paketen zu 50** und meldet nach jedem Paket eine Statuszeile mit Zeiten
|
||||
je Stufe. Beide Stufen laufen gleichzeitig: Während die CPU Paket n gegen die Bilder prüft, lesen
|
||||
pix2text und Qwen auf der GPU schon Paket n+1.
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph GPU["GPU: Lesen (Paket n+1)"]
|
||||
direction TB
|
||||
P["pix2text<br/>gebündelt nach<br/>Pixelbudget"] --> Q["Qwen<br/>bis 8 Anfragen<br/>gleichzeitig"]
|
||||
end
|
||||
subgraph CPU["CPU: Prüfen (Paket n)"]
|
||||
direction TB
|
||||
V1["Bild-Veto<br/>Prozesspool"] --> E1["Entscheidung"]
|
||||
E1 --> T{"Stichwahl<br/>nötig?"}
|
||||
T -->|"ja"| G["Gemma<br/>(zweite GPU)"]
|
||||
G --> E2["Entscheidung"]
|
||||
T -->|"nein"| Z["Statuszeile"]
|
||||
E2 --> Z
|
||||
end
|
||||
```
|
||||
|
||||
- **Scan** (`pipeline.scan`): findet jeden Bildverweis außerhalb von Codeblöcken, fasst gleiche Bilder
|
||||
zusammen, klassifiziert (Farbe der Tinte, Graustufen, Höhe, Stellung im Text) und speichert. Abbildungen
|
||||
(`figure`) werden nicht gelesen, unklare (`maybe`) schon.
|
||||
- **Lesen:** pix2text liest jede Formel, Qwen ebenfalls. Gemma nur, wenn pix2text und Qwen uneinig sind.
|
||||
- **Prüfen** (`verify_all`): rendert nur die Lesart, die übernommen werden kann (pix2texts), und vergleicht
|
||||
sie mit dem Original. Die Prozesse starten per `forkserver`, weil der Lesefaden gleichzeitig in
|
||||
CUDA/pix2text arbeitet und ein `fork` mitten darin halb gehaltene Sperren erbt.
|
||||
- **Entscheiden** (`decide_all_consensus`): siehe [6](#6-entscheidungsregel).
|
||||
|
||||
Ein abgebrochener Lauf setzt beim nächsten `run` fort: Lesarten und Prüfergebnisse liegen im
|
||||
Arbeitsordner.
|
||||
|
||||
---
|
||||
|
||||
## 5. Die Erkenner
|
||||
|
||||
| Engine | Modell | Art | Rolle (Regel `p2t`) |
|
||||
|---|---|---|---|
|
||||
| `p2t` | pix2text MFR 1.5 (ONNX) | Formel-OCR, im Prozess | liest zuerst, **seine Lesart wird übernommen** |
|
||||
| `local` | Qwen3-VL-30B-A3B-Instruct (llama.cpp, Port 8011) | Bildmodell (MoE, ~3B aktiv) | bestätigt |
|
||||
| `local2` | Gemma-4-26B-A4B-it (llama.cpp, Port 8012) | Bildmodell | Stichwahl bei Uneinigkeit |
|
||||
| `cloud` | GLM-4.6V über OpenRouter | Bildmodell | nur Regel `vlm3` |
|
||||
|
||||
**pix2text** (`engines/p2t.py`) läuft auf der sichtbaren GPU mit dem meisten freien Speicher (sonst CPU) und
|
||||
liest gebündelt. Seine Ausgabe wird bereinigt (`tidy_p2t`): überflüssige Leerzeichen entfernt
|
||||
`post_process` aus pix2tex (`\frac{\alpha} {3 6 0}` → `\frac{\alpha}{360}`), Fettschreibweisen wie
|
||||
`\mathrm{\boldmath~ x ~}` werden zu `\boldsymbol{x}`, `\cfrac` zu `\dfrac` (Pandoc kennt `\cfrac` nicht),
|
||||
eine Gleichungsnummer nach großem Abstand zu `\tag{…}`.
|
||||
|
||||
**Bildmodelle** (`engines/vlm.py`) bekommen das Bild vorbereitet (`prepare_image`): auf Weiß gelegt,
|
||||
kleine Formeln auf mindestens 96 px Höhe vergrößert, große auf höchstens 1600 px Kantenlänge verkleinert.
|
||||
Der Prompt verlangt eine buchstabengetreue Abschrift (ausdrücklich mit Fettdruck), `\tag{}` für
|
||||
Gleichungsnummern und eine JSON-Antwort; ein kurzer Textausschnitt um die Formel wird zur Orientierung
|
||||
mitgegeben. Weitere Festlegungen:
|
||||
|
||||
- **Nachdenken aus:** Gemma 4 wird ~10× schneller, GLM liest ohne besser und billiger.
|
||||
- **Antwortlänge** höchstens 800 Tokens: lange mehrzeilige Formeln brauchen ~400, Endlosschleifen werden
|
||||
gekappt.
|
||||
- **Token-Wahrscheinlichkeiten** (Logprobs) des LaTeX-Teils werden gespeichert. Die Selbstauskunft
|
||||
(„confidence“) wird erfragt, entscheidet aber nicht.
|
||||
- **Robuste Auswertung:** JSON mit einfachen Backslashes (`\frac` → Seitenvorschub + `rac`) wird erkannt
|
||||
und wörtlich neu gelesen; wörtliches `\n` in Antworten wird zu Leerraum.
|
||||
|
||||
---
|
||||
|
||||
## 6. Entscheidungsregel
|
||||
|
||||
### Regel `p2t` (Standard, `decide.decide_pair_tiebreak`)
|
||||
|
||||
Lesarten: Qwen (0), pix2text (1), Gemma (2, nur bei Bedarf).
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
S["Qwen: keine Formel<br/>(und Gemma auch)?"] -->|"ja"| NF["not_formula"]
|
||||
S -->|"nein"| A{"pix2text = Qwen?"}
|
||||
A -->|"ja"| C["Prüfungen"]
|
||||
A -->|"nein"| B{"Gemma gefragt?"}
|
||||
B -->|"nein"| W["needs_review:<br/>Stichwahl fehlt<br/>→ Gemma fragen"]
|
||||
B -->|"ja"| G{"Gemma = pix2text?"}
|
||||
G -->|"ja"| C
|
||||
G -->|"nein, aber<br/>Gemma = Qwen"| H["needs_review:<br/>Mensch entscheidet"]
|
||||
G -->|"alle uneinig"| H
|
||||
C --> K{"Pandoc ok und<br/>Ähnlichkeit ≥ 0,65?"}
|
||||
K -->|"ja"| OK["auto_accepted<br/>(pix2texts Lesart)"]
|
||||
K -->|"nein"| R["needs_review"]
|
||||
```
|
||||
|
||||
- Übernommen wird **immer pix2texts Lesart**: Sie trifft den Fettdruck am besten.
|
||||
- **Qwen und Gemma gemeinsam gegen pix2text** gehen an einen Menschen. In der Messung waren genau das die
|
||||
Fehler, die beide Bildmodelle teilen (`\mathcal{E}_r` statt `\varepsilon_r`, ein erfundenes `\tilde{z}`).
|
||||
Der Bild-Schiedsrichter (`arbiter`, siehe [12](#12-messungen)) könnte diese Fälle entscheiden; er ist aus.
|
||||
- **Satzzeichen:** Bei abgesetzten Formeln muss auch der Schlusspunkt bestätigt sein. Bei Formeln im Text
|
||||
wird ein Satzzeichen am Ende vor dem Vergleich abgetrennt und als Text hinter die Formel gesetzt
|
||||
(`$a^{x}$,`), denn es gehört zum Satz.
|
||||
- **PDF-Textebene** (`pdftext`, aus): Bei `pdf2md --formulas` könnte der PDF-Text einer „flachen“ Formel
|
||||
(eine Grundlinie, eine Größe) Qwen ersetzen. Gemessen fehlten dort in 12 von 319 Fällen Punkte, Striche
|
||||
oder Indizes.
|
||||
|
||||
### Regel `vlm3` (bis 0.2.0, `decide.decide_consensus`)
|
||||
|
||||
Qwen = Gemma, bestätigt von GLM-4.6V aus einer anderen Modellfamilie; eine 2:1-Mehrheit reicht nicht.
|
||||
Übernommen wird Qwens Lesart; der bestätigenden Lesart darf der Schlusspunkt fehlen. Wählbar mit
|
||||
`"consensus_rule": "vlm3"` in `workspace.json`.
|
||||
|
||||
### Pixel-Modus (bis 0.1.0, `decide.decide`)
|
||||
|
||||
Eine Lesart wird gerendert und muss jede Verwechslungsvariante (`confusables.variants`: andere Ziffer,
|
||||
hoch statt tief, `,`/`;`, ähnliche Buchstaben …) im Bild deutlich schlagen. Sicher, aber an kleinen
|
||||
JPEG-Formeln zu streng. Wählbar mit `"decide": "pixel"`.
|
||||
|
||||
### Schwellen (`settings.consensus_thresholds` in `workspace.json`)
|
||||
|
||||
| Schlüssel | Standard | Bedeutung |
|
||||
|---|---|---|
|
||||
| `veto_ncc` | 0,65 | Mindestähnlichkeit nach elastischer Ausrichtung |
|
||||
| `veto_scale_dev` | 0 (aus) | erlaubte Abweichung der Schriftgröße vom Buchmittel |
|
||||
| `bold_relevant` | 0 | 1: fett und normal gelten als verschiedene Zeichen |
|
||||
| `require_third` | 1 | Regel `vlm3`: dritte Lesart muss zustimmen |
|
||||
| `min_p_mean`, `min_p_min` | 0 | Mindest-Token-Wahrscheinlichkeiten (Mittel, kleinste) |
|
||||
| `structural` | 0 | Strukturvergleich mit sympy |
|
||||
| `arbiter`, `arbiter_margin` | 0, 5 | Bild-Schiedsrichter bei „Qwen = Gemma gegen pix2text“ |
|
||||
| `pdftext` | 0 | PDF-Textebene darf pix2text bestätigen |
|
||||
|
||||
---
|
||||
|
||||
## 7. Wann zwei Lesarten dieselbe Formel sind
|
||||
|
||||
`consensus.same_reading` prüft in dieser Reihenfolge:
|
||||
|
||||
1. **Normalform** (`canonical`): Beide Lesarten werden in Tokens zerlegt und vereinheitlicht.
|
||||
- **Entfällt:** Abstände (`\,`, `\quad` …), `\left`/`\right`/`\big`, `\displaystyle`, aufrecht/kursiv
|
||||
(`\mathrm`, `\text`, `\operatorname` behalten nur ihren Inhalt), standardmäßig auch Fettdruck.
|
||||
- **Synonyme:** `\vec` = `\overrightarrow`, `\frac` = `\dfrac` = `\cfrac`, `\le` = `\leq`,
|
||||
`\iff` = `\Leftrightarrow`, `\cdots` = `\dots`, `\root3\of{x}` = `\sqrt[3]{x}`,
|
||||
`\underset{…}{\lim}` = `\lim_{…}`, TeX-Umlaute (`f{\"u}r` = `für`), `\atop` = `\substack`.
|
||||
- **Umgebungen:** `pmatrix` = `\left(\begin{matrix}…\right)`, `array` = `matrix`. Mehrzeilige Formeln
|
||||
sind gleich, wenn sie dieselben Zeilen mit denselben Zeichen haben, egal ob `aligned`, `gathered`,
|
||||
`split` oder nur `\\`; `cases` = `\left\{\begin{array}…\right.`. In Matrizen trennt `&` weiter Spalten.
|
||||
- **Klammergruppen:** Eine Gruppe ist nur dann Argument, wenn der Befehl davor noch eines erwartet
|
||||
(`\frac` 2, `\sqrt` 1, `\Delta` 0). So wird `t^{2}\,{\sqrt{2}}` = `t^2\sqrt{2}`, aber
|
||||
`\frac{a}{b+c}` ≠ `\frac{a}{b}+c`.
|
||||
- Eine Gleichungsnummer ist Teil der Normalform: Alle Lesarten müssen dieselbe tragen.
|
||||
2. **Strukturvergleich** (`structure.py`, nur mit `structural` = 1): gleicher *unausgewerteter* sympy-Baum
|
||||
(`\frac{a}{b}` = `a/b`). Nichts wird umgerechnet (`a+b` ≠ `b+a`), Relationen gehen nie an sympy, jedes
|
||||
Zeichen ist durch einen Platzhalter geschützt.
|
||||
3. **Render-Gleichheit** (`render_equal`): Beide Lesarten werden mit pdflatex gesetzt und Pixel gegen Pixel
|
||||
verglichen (höchstens 0,2 % abweichende Tintenpixel). Das ist ein Vergleich **Render gegen Render**,
|
||||
exakt und rauschfrei. Haben die Normalformen verschiedene Buchstaben oder Ziffern, entfällt dieser
|
||||
Schritt.
|
||||
|
||||
---
|
||||
|
||||
## 8. Bild-Veto: der elastische Bildvergleich
|
||||
|
||||
Das Veto fängt Fehler ab, die mehrere Erkenner gemeinsam machen (weggelassener Term, mitgelesene
|
||||
Gleichungsnummer, Halluzination). Es entscheidet nicht über Kleinigkeiten.
|
||||
|
||||
1. **Rendern** (`render.py`): pdflatex mit dem Paket `preview`, viele Formeln je Lauf. Formeln mit
|
||||
TeX-Fehlern werden über die Zeilennummern im Log erkannt und herausgenommen, der Rest neu übersetzt.
|
||||
Die Schrift wählt `choose_preset` je Buch an einer Stichprobe: `cm`, `times`, `txfonts`, `palatino`,
|
||||
`stix` oder `euler`.
|
||||
2. **Normalisieren** (`imageio.gray_to_ink`): Transparenz auf Weiß, helle Schrift auf dunklem Grund wird
|
||||
umgekehrt, die Tinte zwischen Papierton und dunkelstem Pixel gestreckt (ein getönter Kasten wird so zu
|
||||
Papier), JPEG-Rauschen unter einer Schwelle entfernt, zugeschnitten. Breite Originale werden auf
|
||||
1600 px verkleinert, Ausschnitte über 2,5 MP nicht verglichen.
|
||||
3. **Ausrichten** (`compare.py`): gleichmäßig skalieren (nie strecken), auf Viertelpixel verschieben.
|
||||
Weichen die Proportionen mehr als 2,5-fach ab, gibt es keinen Vergleich.
|
||||
4. **Elastisch verzerren** (`elastic_warp`): dynamische Zeitverzerrung (DTW) über Spalten, dann Zeilen.
|
||||
Jede Originalspalte schiebt den Kandidaten um 0–3 Spalten weiter. Dehnen kostet proportional zur Tinte
|
||||
der Spalte, übersprungene Tinte ihren vollen Wert. Abstände und Pfeilschäfte dürfen sich so ändern,
|
||||
Zeichenformen praktisch nicht, und kein Zeichen kann verschwinden.
|
||||
5. **Messen:** Korrelation (NCC) nach der Verzerrung; das Veto verlangt ≥ 0,65.
|
||||
|
||||
Die Bilder (Original, starr und elastisch ausgerichtetes Render, farbiges Diff) landen in `review/` und
|
||||
erscheinen in der Review-Galerie.
|
||||
|
||||
---
|
||||
|
||||
## 9. apply und revert
|
||||
|
||||
- **Sicherung:** Das erste `apply` kopiert jede betroffene Markdown-Datei nach `backup/`. Jedes `apply`
|
||||
baut aus dieser Sicherung neu auf, ist also wiederholbar. Hat sich eine Datei seitdem geändert
|
||||
(neuer epub2md-Lauf), gilt sie als neues Original.
|
||||
- **Ersetzen:** Der genaue Bildverweis in der gespeicherten Zeile wird ersetzt: abgesetzt durch `$$…$$`,
|
||||
im Text durch `$…$` (epub2md `--math tex`: `\[…\]` bzw. `\(…\)`).
|
||||
- **Gleichungsnummer:** Sie kommt nur aus der übernommenen Lesart und steht bei abgesetzten Formeln als
|
||||
`\qquad\text{(3.7)}` hinter der Formel, wie bei epub2md.
|
||||
- **Deutsche Bücher:** Dezimalzahlen werden zu `3{,}6`, sonst setzt LaTeX „3, 6“.
|
||||
- **revert** spielt die Sicherung zurück, außer bei Dateien, die seit `apply` von Hand geändert wurden
|
||||
(mit `--force` auch diese).
|
||||
|
||||
---
|
||||
|
||||
## 10. Quellen: epub2md und pdf2md
|
||||
|
||||
| Quelle | Erkennung | Original für den Vergleich |
|
||||
|---|---|---|
|
||||
| epub2md-Ordner | `conversion-report.json` (`tool: epub2md`); Warnungen `formula-image` markieren sichere Formeln | das extrahierte Bild |
|
||||
| pdf2md (Box-Bilder) | Bildname `<pdf>-<seite>-<box>`; mit `--pdf` per Template-Matching auf der Seite gefunden | 600-dpi-Neuausschnitt aus dem Vektor-PDF (`pdfcrop.py`), einmal in `crops/` |
|
||||
| pdf2md `--formulas` | Bildname `<pdf>-<seite>-f<nr>.png`, Liste `formulas-*.json` mit Seite, Rechteck, Art und PDF-Text | das Bild selbst (300 dpi aus dem Vektor-PDF) |
|
||||
|
||||
Mit `pdf2md --formulas` findet die Formelerkennung von pix2text (MFD) jede Formel auf der Seite, auch im
|
||||
Fließtext und in Merkkästen; pdf2md schneidet sie zeichengenau aus dem Text. Ob ein Box-Bild eine Formel
|
||||
ist, verraten bei Box-Bildern die Schriften im Ausschnitt (CMMI, CMSY, EURM …).
|
||||
|
||||
---
|
||||
|
||||
## 11. Sicherheit
|
||||
|
||||
- **Lesarten sind unsicher:** Sie kommen von Modellen. Vor pdflatex lehnt `tex.unsafe_reason` Befehle ab,
|
||||
die Dateien lesen oder schreiben, Code ausführen oder Makros umdefinieren (`\input`, `\write`, `\def`,
|
||||
`\catcode`, `\csname` …), außerdem `^^`-Zeichencodes, Begrenzer und unausgeglichene Klammern.
|
||||
- **pdflatex** läuft mit `-no-shell-escape`, `openout_any=p`, `openin_any=p` und Zeitlimit.
|
||||
- **Review-Server** bindet nur an `127.0.0.1`; jede Entscheidung muss ein Zufallstoken der Seite
|
||||
mitschicken, damit fremde Webseiten im selben Browser nichts entscheiden können.
|
||||
- **Daten nach außen:** Mit der Standardregel verlässt nichts den Rechner. Nur die Regel `vlm3` schickt
|
||||
Formelbilder samt Textausschnitt an OpenRouter.
|
||||
|
||||
---
|
||||
|
||||
## 12. Messungen
|
||||
|
||||
Gemessen wird an Formelbildern mit **bekanntem TeX**: Springer-EPUBs (Göllmann) tragen das TeX jeder Formel
|
||||
im alt-Text. Dazu kommen Nachbildungen im Stil von Gehrke (LaTeX + dvipng mit Bitmap-Schriften, ~102 dpi,
|
||||
JPEG). Werkzeuge: `calibrate --consensus`, `tools/regeltest.py`, `tools/zeittest.py`.
|
||||
|
||||
### Regeln im Vergleich (Göllmann Band 1, je 150 echte und 150 nachgebildete Formeln, Stand 0.3.0)
|
||||
|
||||
| Regel | echt: automatisch / falsch | Gehrke-Stil: automatisch / falsch |
|
||||
|---|---|---|
|
||||
| Qwen = Gemma | 73 % / 1 | 69 % / 2 |
|
||||
| Qwen = Gemma = Gemini 2.5 Flash | 67 % / 0 | 57 % / 1 |
|
||||
| Qwen = Gemma = GLM-4.6V (Regel `vlm3`) | 78 % / 0 | 70 % / 0 |
|
||||
| pix2text = Qwen | 81 % / 0 | 76 % / 0 |
|
||||
| **pix2text zuerst, bereinigt, Stichwahl Gemma** (Regel `p2t`) | **86 % / 0** | **85 % / 0** |
|
||||
| + Stichwahl auch Qwen = Gemma gegen pix2text | 92 % / 1 | 91 % / 2 |
|
||||
|
||||
Mit der mehrzeiligen Normalform (0.4.0), gleiche Lesarten: **89 % / 0** und **88 % / 0**; Göllmann Band 2
|
||||
(zwei Stichproben zu 50): 44 und 45 automatisch, 0 falsch.
|
||||
|
||||
Allein richtig (Stand 0.3.0): pix2text 90 % / 85 %, Qwen 86 % / 84 %, Gemma 86 % / 80 %, GLM 86 % / 83 %.
|
||||
Zeit je Formel seriell: pix2text 0,10 s (GPU) bzw. 0,51 s (CPU), Qwen 0,72 s, GLM 1,19 s, Gemma 1,77 s.
|
||||
|
||||
### Ganze Bücher (ohne bekannte Lösung)
|
||||
|
||||
| Buch | Version | Formelbilder | automatisch | Review | Prüfung von Hand |
|
||||
|---|---|---|---|---|---|
|
||||
| Gehrke, Brückenkurs Mathematik (EPUB) | 0.2.0, Regel `vlm3` | 1505 | 942 (63 %) | 478 | 62 von 62 korrekt |
|
||||
| Corral, *Elementary Calculus* (PDF, Box-Bilder) | 0.4.0 | 1150 | 429 (37 %) | 633 | – |
|
||||
| Corral mit `pdf2md --formulas`, Stichprobe 10 % | unveröffentlicht | 940 | 747 (79 %) | 174 | – |
|
||||
|
||||
Bei Gehrke ergab Pandoc `--mathml` nach `apply` für 945 von 945 Formeln MathML. Bei Corral (Box-Bilder)
|
||||
bestand das Review überwiegend aus Ausschnitten, die keine einzelne Formel waren (Merkkästen mit Text,
|
||||
Tabellen, Herleitungen); `--formulas` behebt das weitgehend.
|
||||
|
||||
### Gemessen und verworfen
|
||||
|
||||
- **Selbstauskunft** der Modelle („95 % sicher“) und **pix2texts eigene Sicherheit**: Fehler auch bei 1,0.
|
||||
- **Token-Wahrscheinlichkeiten** als Schwelle: neben der Bestätigung kein Gewinn, nur weniger Abdeckung.
|
||||
- **Gemini als dritte Lesart:** mit Gemma verwandt, ließ einen gemeinsamen Fehler durch.
|
||||
- **GLM mit Nachdenken:** 79 % statt 85 % allein richtig, ~25× mehr Tokens.
|
||||
- **Bild-Schiedsrichter** (`verify.image_arbiter`) bei „Qwen = Gemma gegen pix2text“: In 16 Fällen hatte
|
||||
Qwen 14-mal recht, aber der gemeinsame Fehler `\mathcal{E}_r` bekam Beleg 7,2 – zu knapp für eine
|
||||
Schwelle von 8.
|
||||
- **Strukturvergleich mit sympy:** nach der mehrzeiligen Normalform kein zusätzlicher Treffer.
|
||||
- **Prompt-Stilvorgabe** (feste Schreibweisen): keine Verbesserung, die Modelle schrieben wörtliches `\n`.
|
||||
- **PDF-Textebene als Bestätigung:** 12 von 319 widersprachen Qwen, mit fehlenden Punkten und Indizes.
|
||||
- **Qwen3-VL-8B statt 30B-A3B:** nicht schneller (das MoE-Modell rechnet nur ~3B je Token), etwas schlechter.
|
||||
- **Schriftgrößen-Prüfung im Veto:** nur Fehlalarme.
|
||||
|
||||
„0 falsch“ bei einigen hundert Formeln bedeutet eine Fehlerquote sehr wahrscheinlich unter ~2 %, nicht
|
||||
null. Die Kalibrierung lief ohne den Textausschnitt, den `run` mitgibt.
|
||||
|
||||
---
|
||||
|
||||
## 13. Designentscheidungen
|
||||
|
||||
| Entscheidung | Verworfene Alternativen | Grund |
|
||||
|---|---|---|
|
||||
| **Eigenes Nachbearbeitungs-Werkzeug** | Option in epub2md/pdf2md | Die Konverter bleiben schlank und offline; torch, Modelle und GPU-Server gehören nicht hinein. |
|
||||
| **Erkenner entscheiden, Bild nur Veto** | Pixelvergleich als Entscheider (0.1.0) | Bei 15 px hohen JPEG-Formeln mit Bitmap-Hinting trennte der Pixelvergleich richtig und falsch zu schlecht: 1–2 % automatisch. |
|
||||
| **Zwei verschiedenartige Erkenner** | ein Modell mit Selbstauskunft; zwei Modelle einer Familie | Selbstauskünfte sind wertlos; verwandte Modelle machen dieselben Fehler (Gemini/Gemma). pix2text (Formel-OCR) und Qwen (Bildmodell) irren verschieden. |
|
||||
| **pix2texts Lesart übernehmen** | Lesart des Bildmodells | pix2text liest allein am häufigsten richtig und trifft den Fettdruck am besten. |
|
||||
| **Qwen + Gemma gegen pix2text → Mensch** | 2:1-Mehrheit | Genau diese Fälle waren die gemeinsamen Fehler der Bildmodelle (+6 % Abdeckung, aber Fehler). |
|
||||
| **Normalform statt String-Vergleich** | Zeichenkette; sympy-Auswertung | Die Erkenner schreiben dieselbe Formel verschieden; sympy rechnet um und verwischt Unterschiede (`v=(3,4)ᵀ` und `\nu=(3,4)ᵀ` werden beide `False`). |
|
||||
| **Render gegen Render als Rückfallebene** | Render gegen Original | Zwei Renders sind exakt vergleichbar; das Original ist verrauscht und anders gesetzt. |
|
||||
| **Elastischer Vergleich mit Tintenkosten** | starre Ausrichtung; freie Verzerrung | Starr scheitert an anderen Abständen und Pfeillängen; frei könnte ein falsches Zeichen passend biegen. |
|
||||
| **Fettdruck zählt nicht** | Fettdruck als eigenes Zeichen | Vorgabe des Nutzers; alle Bildmodelle lesen Fettdruck schlecht. |
|
||||
| **Nachdenken der Modelle aus** | Standard der Server | Schneller, billiger, bei GLM sogar genauer. |
|
||||
| **Arbeitsordner neben der Ausgabe, Schlüssel = Bildinhalt** | Daten in der Ausgabe; Dateinamen als Schlüssel | `epub2md --force` ersetzt die Ausgabe; Dateinamen ändern sich, Bildinhalte nicht. |
|
||||
| **apply aus Sicherung** | Ersetzen im laufenden Markdown | Wiederholbar, rückgängig zu machen, neue Konverterläufe werden erkannt. |
|
||||
| **Pakete zu 50, Lesen und Prüfen überlappt** | alles nacheinander | Statuszeilen für den Nutzer; die GPUs warten nicht auf die CPU (Pilot 869 Formeln: 70 → ~24 Minuten). |
|
||||
| **Lokale Modelle, Cloud optional** | Cloud als Standard | Buchinhalte bleiben auf dem Rechner; die lokale Regel misst besser als die mit GLM. |
|
||||
| **MIT-Lizenz** | GPL | Einfache Wiederverwendung. |
|
||||
|
||||
---
|
||||
|
||||
## 14. Grenzen
|
||||
|
||||
| Grenze | Auswirkung | Mögliche Abhilfe |
|
||||
|---|---|---|
|
||||
| Mehrzeilige Rechnungen mit verschiedenen Zeilenumbrüchen, `\underbrace`, fehlenden Integrationsgrenzen | landen im Review | Normalform erweitern |
|
||||
| Fettdruck wird nicht geprüft | ein fetter Vektor kann als normales v übernommen werden | `bold_relevant` = 1 schickt solche Fälle ins Review |
|
||||
| Formeln auf farbig hinterlegten Kästen | verlieren beim Ersetzen die Hinterlegung | – |
|
||||
| Formeln in Tabellen | erfasst `pdf2md --formulas` noch nicht | Erkennung in Tabellenzellen |
|
||||
| Riesenausschnitte (Grafiken, ganze Herleitungen) | ohne Bildvergleich abgelehnt (über 2,5 MP, Proportionen über 2,5-fach) | bessere Trennung in pdf2md |
|
||||
| Messbasis | einige hundert Formeln eines Verlags; Textausschnitt nicht kalibriert | weitere Bücher mit bekannter Lösung |
|
||||
| Laufzeit | ~0,8 s je Formel mit zwei RTX 3090 | – |
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2026 Dieter Schlüter
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
377
README.md
377
README.md
|
|
@ -3,357 +3,56 @@
|
|||
Nachbearbeitungs-Werkzeug für die Markdown-Ausgaben von
|
||||
[epub2md](https://kitux.de/forgejo/dschlueter/epub2md) und
|
||||
[pdf2md](https://kitux.de/forgejo/dschlueter/pdf2md): Formeln, die nur als Bild vorliegen, werden durch
|
||||
LaTeX ersetzt – **aber nur, wenn zwei unabhängige Erkenner dieselbe Formel lesen** (zuerst das Formel-OCR
|
||||
pix2text, bestätigt vom Bildmodell Qwen; bei Uneinigkeit darf Gemma pix2text bestätigen) und ein grober
|
||||
Bildabgleich nicht widerspricht. Alles andere geht in eine Review-Galerie oder bleibt Bild.
|
||||
LaTeX ersetzt. Beim Neubau als EPUB oder PDF passen sie dann in Größe und Schrift zum Text.
|
||||
|
||||
Für PDF-Bücher findet `pdf2md --formulas` jede Formel auf der Seite, auch im Fließtext und in Merkkästen,
|
||||
und schneidet sie als Bild aus; formula_img2latex übersetzt sie dann ebenso (siehe [Quellen](#quellen)).
|
||||
- **Nur bestätigte Formeln:** Das Formel-OCR **pix2text** liest jede Formel, das Bildmodell **Qwen3-VL**
|
||||
muss dieselbe Formel lesen (bei Uneinigkeit darf **Gemma 4** pix2text bestätigen), und ein grober
|
||||
Bildabgleich darf nicht widersprechen. Alles andere geht in eine Review-Galerie oder bleibt Bild.
|
||||
- **Annahmeregel:** jedes Zeichen richtig und an der richtigen Stelle; Abstände, Längen, Schriftgröße,
|
||||
kursiv/aufrecht und Fettdruck dürfen abweichen.
|
||||
- **Lokal:** pix2text im Prozess, Qwen und Gemma über llama.cpp; keine Buchinhalte verlassen den Rechner.
|
||||
- **Wiederholbar und umkehrbar:** Ergebnisse liegen in einem Arbeitsordner neben der Ausgabe, `apply`
|
||||
schreibt aus einer Sicherung, `revert` stellt den alten Stand wieder her.
|
||||
- **PDF-Bücher:** Mit `pdf2md --formulas` werden auch Formeln im Fließtext und in Merkkästen erfasst.
|
||||
|
||||
Schritt-für-Schritt-Anleitung: [BEDIENUNGSANLEITUNG.md](BEDIENUNGSANLEITUNG.md). Änderungen je Version:
|
||||
[CHANGELOG.md](CHANGELOG.md). Hintergrund und ursprüngliche Planung: `Idee/`.
|
||||
## Schnellstart
|
||||
|
||||
## Annahmeregel
|
||||
|
||||
> Jedes Zeichen muss stimmen und an der richtigen Stelle relativ zu den anderen stehen. Abstände,
|
||||
> Pfeil- und Bruchstrichlängen, Schriftgröße, kursiv/aufrecht und Fettdruck dürfen abweichen.
|
||||
|
||||
Eine Formel wird automatisch ersetzt (Regel `p2t`, Standard), wenn
|
||||
|
||||
1. **pix2text** (Formel-OCR MFR 1.5, lokal, GPU) sie zuerst liest und **Qwen3-VL-30B-A3B** (Bildmodell,
|
||||
lokal, llama.cpp) dieselbe Formel liest **oder**, wenn die beiden uneinig sind, **Gemma-4-26B-A4B**
|
||||
(lokal) die Lesart von pix2text bestätigt. Übernommen wird immer **pix2texts Lesart** – sie trifft den
|
||||
Fettdruck am besten. Ihre überflüssigen Leerzeichen entfernt vorher `post_process` aus pix2tex (LaTeX-OCR):
|
||||
`\frac{\alpha} {3 6 0}` → `\frac{\alpha}{360}`; am gesetzten Bild ändert das nichts, geprüft an
|
||||
400 Lesarten. Auch der Schlusspunkt muss bestätigt sein,
|
||||
2. Pandoc sie nach MathML umsetzen kann (sonst bliebe sie im EPUB/PDF roher TeX-Text) und
|
||||
3. das gerenderte LaTeX dem Original grob ähnelt (Bild-Veto, elastischer Vergleich, Ähnlichkeit ≥ 0,65).
|
||||
|
||||
Sind Qwen und Gemma gemeinsam gegen pix2text einig, entscheidet ein Mensch: Genau das sind die Fehler,
|
||||
die beide Bildmodelle teilen (`\mathcal{E}_r` statt `\varepsilon_r`, erfundenes `\tilde{z}`).
|
||||
|
||||
Die frühere Regel `vlm3` (Qwen = Gemma, bestätigt von **GLM-4.6V** über OpenRouter) bleibt wählbar:
|
||||
`"consensus_rule": "vlm3"` unter `settings` in `workspace.json` des Arbeitsordners.
|
||||
|
||||
„Dieselbe Formel“ prüft `consensus.py`: gleiche Normalform (Abstände, `\left`/`\right`, überflüssige
|
||||
Klammern, `\vec`/`\overrightarrow`, `\frac`/`\dfrac`, `\iff`/`\Leftrightarrow`, `pmatrix`/`\left(\begin{matrix}`,
|
||||
TeX-Umlaute, `\atop`/`\substack`, `\cdot\cdot\cdot`/`\cdots`, `\root3\of{x}`/`\sqrt[3]{x}`, kursiv/aufrecht,
|
||||
fett/normal …) oder – als Rückfallebene – zeichengleiches Rendering der beiden Lesarten (Render gegen
|
||||
Render, nicht gegen das verrauschte Original). Eine Gleichungsnummer muss in allen Lesarten
|
||||
übereinstimmen und wird als Text hinter die Formel gesetzt.
|
||||
|
||||
**Mehrzeilige Formeln** (seit 0.4.0): gleich, wenn sie dieselben Zeilen mit denselben Zeichen haben,
|
||||
egal in welchem Rahmen. `aligned`/`gathered`/`split` und ihr `&` fallen weg (`a\\b` =
|
||||
`\begin{aligned}a&\\b\end{aligned}`), eine leere letzte Zeile zählt nicht; `cases`,
|
||||
`\left\{\begin{array}{ll}…\right.` und pix2texts `\left\{\begin{aligned}…\right.` sind dasselbe.
|
||||
Matrizen bleiben Matrizen: Dort trennt `&` Spalten (`1&2` ≠ `12`). Ob eine Gruppe ein Argument ist,
|
||||
entscheidet die Argumentzahl des Befehls (`\frac` 2, `\sqrt` 1, `\Delta` 0), nicht ihre Stellung:
|
||||
`t^{2}\,{\sqrt{2}}` = `t^2\sqrt{2}`, `\Delta{x_{n}}` = `\Delta x_n`.
|
||||
|
||||
**Gleiche Struktur** (`structure.py`, sympy, **optional, standardmäßig aus**): Beide Lesarten ergeben
|
||||
denselben *unausgewerteten* Ausdrucksbaum (`\frac{a}{b}` = `a/b`, `a\cdot b` = `ab`); nichts wird
|
||||
umgerechnet oder umgestellt (`a+b` ≠ `b+a`, `2x=4` ≠ `x=2`, `a-b` ≠ `a+(-b)`). Relationen gehen nie an
|
||||
sympy (es wertet `v=(3,4)ᵀ` und `\nu=(3,4)ᵀ` beide zu `False` aus), jedes Zeichen wird durch einen
|
||||
Platzhalter geschützt (sympy macht aus `\varepsilon` und `\epsilon` ein Symbol), sichtbare Klammern
|
||||
zählen, Ungedecktes fällt auf den Render-Vergleich zurück. Gemessen: vor der mehrzeiligen Normalform
|
||||
+1 Formel bei 400, danach **nichts mehr** – deshalb aus. Einschalten: `structural` = 1 oder
|
||||
`FORMULA_STRUCTURAL=1`; braucht `pip install sympy lark`.
|
||||
|
||||
Sind sich die Modelle uneinig oder widerspricht das Veto, entscheidet ein Mensch im Review.
|
||||
|
||||
## Messung
|
||||
|
||||
### Regel `p2t` (Standard)
|
||||
|
||||
Göllmann Band 1, 150 echte Bilder und 150 Nachbildungen im Gehrke-Stil, Lesarten aller Modelle:
|
||||
|
||||
| Regel | echt: automatisch / falsch | Gehrke-Stil: automatisch / falsch |
|
||||
| --- | --- | --- |
|
||||
| pix2text = Qwen | 81 % / 0 | 76 % / 0 |
|
||||
| + Stichwahl: Gemma bestätigt pix2text, Qwens Lesart (erste Fassung) | 85 % / 0 | 80 % / 0 |
|
||||
| **pix2text zuerst und übernommen, bereinigt, Stichwahl Gemma** (Standard) | **86 % / 0** | **85 % / 0** |
|
||||
| + Stichwahl auch Qwen = Gemma gegen pix2text | 92 % / 1 | 91 % / 2 |
|
||||
| Qwen = Gemma = GLM (Regel `vlm3`) | 78 % / 0 | 70 % / 0 |
|
||||
|
||||
Ab 0.4.0 mit mehrzeiliger Normalform, gleiche Lesarten (`--reuse`): **89 % / 0** (134) und **88 % / 0**
|
||||
(132); Band 2 (`tools/regeltest.py`, zwei Stichproben zu 50): **44 und 45** automatisch statt 39 und 43,
|
||||
**0 falsch**, 6 bzw. 5 Review. Zusammen +17 Formeln bei 400. Die Tabelle und die folgenden Absätze
|
||||
zeigen den Stand 0.3.0.
|
||||
|
||||
Allein richtig: pix2text 90 % / 85 %, Qwen 86 % / 84 %, Gemma 86 % / 80 %, GLM 86 % / 83 %.
|
||||
Zeit je Formel (seriell, 15 Formeln): pix2text 0,10 s (GPU) bzw. 0,51 s (CPU), Qwen 0,72 s, GLM 1,19 s,
|
||||
Gemma 1,77 s. Gegenprobe an Göllmann Band 2 (`tools/regeltest.py`, zwei getrennte Stichproben zu 50
|
||||
Formeln): 39 bzw. 43 automatisch (78 % bzw. 86 %), **0 falsch**, 11 bzw. 7 Review; Gemma wurde für 14
|
||||
bzw. 9 Formeln gefragt. Lesen je Formel im Mittel 2,3 bzw. 1,5 s (alle Tools nacheinander, ohne Bildprüfung).
|
||||
pix2text ist nicht unfehlbar: In den Reviews standen auch Fälle, in denen nur pix2text sich verlesen hatte
|
||||
(fehlende Wurzelexponenten, zerfallene Vektoren, `\nu` statt fettem v) – deshalb bleibt die Bestätigung
|
||||
durch Qwen Pflicht.
|
||||
|
||||
**Bild-Schiedsrichter** (0.4.0, gemessen, **aus**): Bei „Qwen = Gemma gegen pix2text“ misst
|
||||
`verify.image_arbiter`, wie deutlich das Original Qwens Lesart zeigt (gleiches Kontrastmaß wie der
|
||||
Variantentest). In 16 solchen Fällen (Band 1 und 2) hatte Qwen 14-mal recht, mit Belegen von 3 bis 50.
|
||||
Aber: Beim gemeinsamen Fehler `\mathcal{E}_r` statt `\varepsilon_r` sprach das Bild mit 7,2 sogar für
|
||||
die falsche Lesart. Ab Schwelle 8 wären es +11 Formeln bei 0 falsch – der Abstand ist bei zwei
|
||||
Gegenbeispielen nicht belastbar. Einschalten: `arbiter` = 1, `arbiter_margin` (5).
|
||||
|
||||
**Prompt-Stilvorgabe** (0.4.0, gemessen, verworfen): feste Schreibweisen für `aligned`, `pmatrix`,
|
||||
`cases`, `\dots`, `\text`. Band 2: 44 und 44 statt 44 und 45 – die Normalform gleicht die Schreibweisen
|
||||
schon aus, und mit der Zeilenvorgabe schrieben beide Modelle nach `\\` ein wörtliches `\n`.
|
||||
|
||||
### Regel `vlm3` (Standard bis 0.2.0)
|
||||
|
||||
An Formelbildern mit bekanntem TeX (Göllmann, Springer: TeX im alt-Text), je 150 echte Bilder und 150
|
||||
Nachbildungen im Stil von Gehrke (LaTeX + dvipng mit Bitmap-Schriften, ~102 dpi, JPEG):
|
||||
|
||||
| Regel | echt: automatisch / davon falsch | Gehrke-Stil: automatisch / davon falsch |
|
||||
| --- | --- | --- |
|
||||
| Qwen = Gemma | 73 % / 1 | 69 % / 2 |
|
||||
| Qwen = Gemma = Gemini 2.5 Flash | 67 % / 0 | 57 % / 1 |
|
||||
| **Qwen = Gemma = GLM-4.6V** ohne Nachdenken (Standard) | **68 % / 0** | **63 % / 0** |
|
||||
|
||||
- Fehler, bei denen zwei Modelle gemeinsam irren, gibt es: `\mathcal{E}_r` statt `\varepsilon_r`, ein
|
||||
erfundenes `\tilde{z}`, `x^{f}` statt `x'`. Die dritte Lesart aus einer **anderen Modellfamilie** fängt
|
||||
sie ab; Gemini (mit Gemma verwandt) machte einen davon mit.
|
||||
- Selbstauskünfte der Modelle („95 % sicher“) sind wertlos. Token-Wahrscheinlichkeiten (Logprobs) werden
|
||||
gespeichert, brachten aber neben der dritten Lesart keinen Gewinn (Schwellen bleiben einstellbar).
|
||||
- „Nachdenken“ (Reasoning) ist für alle Modelle abgeschaltet: Gemma 4 wird ~10× schneller, GLM-4.6V liest
|
||||
ohne Nachdenken sogar besser (85 % statt 79 % allein richtig) und braucht ~25× weniger Tokens.
|
||||
- Fettdruck lesen alle Modelle schlecht (fette Vektoren werden zu normalen Buchstaben); nach Vorgabe zählt
|
||||
er nicht. Mit `bold_relevant=1` würden diese Fälle ins Review gehen.
|
||||
- Das Bild-Veto fing den einzigen Fall ab, in dem alle drei Modelle gemeinsam irrten (Ähnlichkeit
|
||||
0,5–0,6); richtige Lesarten lagen bei ≥ 0,66. Daher die Schwelle 0,65. Eine Prüfung der Schriftgröße
|
||||
(Pixel pro Punkt gegen das Buchmittel) erzeugte nur Fehlalarme und ist abgeschaltet.
|
||||
- Die Messung lief **ohne** Textausschnitt um die Formel; `run` gibt den Modellen einen kurzen
|
||||
Textausschnitt (≤ 240 Zeichen) mit. Die Stichproben am Buch (62 von 62 korrekt) sprechen nicht gegen
|
||||
den Kontext, gemessen ist er aber nicht.
|
||||
|
||||
Gehrke, Brückenkurs Mathematik (EPUB, 1505 Formelbilder): siehe [Stand](#stand).
|
||||
|
||||
## Ablauf
|
||||
|
||||
```text
|
||||
scan Bildverweise in chapters/*.md (bzw. pdf2md-Markdown) finden, Formel/Abbildung vorklassifizieren
|
||||
run in Paketen zu 50: pix2text, dann Qwen lesen, prüfen, Gemma nur für Uneinige, prüfen;
|
||||
nach jedem Paket eine Statuszeile mit Zeiten je Stufe (Regel vlm3: Qwen + Gemma, GLM nur
|
||||
für Einige). Die GPUs lesen schon das nächste Paket, während die CPU das vorige prüft.
|
||||
review Zweifelsfälle im Browser: Original / Render / Overlay / Diff, LaTeX korrigieren und neu prüfen
|
||||
apply angenommene Formeln ins Markdown schreiben (aus einer Sicherung, idempotent)
|
||||
revert Markdown-Dateien auf den Stand vor apply zurücksetzen
|
||||
recognize einzelne Engine (local, local2, cloud, p2t) laufen lassen
|
||||
verify prüfen und entscheiden (ohne neue Modellabfragen)
|
||||
status Zählung je Status
|
||||
calibrate Messung an Formelbildern mit bekanntem TeX (--consensus: Konsensregel)
|
||||
```
|
||||
|
||||
```bash
|
||||
python3 formula_img2latex.py run output/buch # epub2md-Ausgabeordner
|
||||
python3 formula_img2latex.py review output/buch
|
||||
python3 formula_img2latex.py apply output/buch
|
||||
python3 epub2md_merge.py output/buch --force # Gesamtdatei danach neu bauen
|
||||
```
|
||||
|
||||
PDF-Buch mit allen Formeln, auch im Fließtext:
|
||||
|
||||
```bash
|
||||
cd ~/Python_Programs/pdf2md
|
||||
python3 pdf2md.py --formulas --epub buch.pdf Output/buch/buch.md # Formeln als Bilder + Liste
|
||||
cd ~/Python_Programs/formula_img2latex
|
||||
python3 formula_img2latex.py run ~/Python_Programs/pdf2md/Output/buch/buch.md --pdf buch.pdf
|
||||
python3 formula_img2latex.py apply ~/Python_Programs/pdf2md/Output/buch/buch.md
|
||||
cd ~/Python_Programs/pdf2md && python3 pdf2md.py --from-md Output/buch/buch.md # EPUB mit MathML
|
||||
```
|
||||
|
||||
Status je Formel: `auto_accepted`, `needs_review`, `rejected_keep_image`, `render_failed`, `no_candidate`,
|
||||
`not_formula`, nach Review `accepted_by_human`, `corrected_by_human`, `kept_by_human`.
|
||||
|
||||
## Modelle und Server
|
||||
|
||||
| Engine | Standard | Konfiguration |
|
||||
| --- | --- | --- |
|
||||
| `local` | llama.cpp `http://127.0.0.1:8011/v1` (Qwen3-VL-30B-A3B-Instruct Q4_K_M + mmproj), 8 parallele Anfragen | `FORMULA_LOCAL_URL`, `FORMULA_LOCAL_MODEL` |
|
||||
| `local2` | llama.cpp `http://127.0.0.1:8012/v1` (Gemma-4-26B-A4B-it Q4_0 + mmproj) | `FORMULA_LOCAL2_URL`, `FORMULA_LOCAL2_MODEL` |
|
||||
| `cloud` | OpenRouter, `z-ai/glm-4.6v` (nur Regel `vlm3`) | `OPENROUTER_API_KEY`, `FORMULA_CLOUD_MODEL` |
|
||||
| `p2t` | pix2text MFR 1.5 (ONNX) im Prozess, die sichtbare GPU mit dem meisten freien Speicher, sonst CPU; gebündelt nach Pixelbudget | `FORMULA_P2T_DEVICE` (`auto`, `cpu`, `cuda:N`), `FORMULA_P2T_MODEL` |
|
||||
|
||||
pix2text auf der GPU braucht `onnxruntime-gpu` statt `onnxruntime` (cuDNN kommt aus den nvidia-Paketen
|
||||
von torch). Für `post_process` wird `pix2tex` ohne seine Abhängigkeiten installiert
|
||||
(`pip install --no-deps pix2tex munch`), weil es sonst `timm==0.5.4` erzwingen würde. `cuda:N` zählt innerhalb von `CUDA_VISIBLE_DEVICES`.
|
||||
|
||||
`FORMULA_<ENGINE>_THINKING=1` schaltet das Nachdenken wieder ein. Antworten sind auf 800 Tokens begrenzt
|
||||
(lange mehrzeilige Formeln brauchen ~400; einzelne Antworten von Gemma liefen sonst in
|
||||
Wiederholungsschleifen bis 165 s). Jede Lesart wird mit Modell, Prompt-Version und Nachdenk-Einstellung
|
||||
gespeichert; dieselbe Frage wird nie zweimal gestellt, ein abgebrochener Lauf setzt dort fort.
|
||||
|
||||
Qwen-Server mit `--parallel 8 -c 32768` (je Platz 4096 Tokens) starten; `run` stellt bis zu 8 Anfragen
|
||||
gleichzeitig (BEDIENUNGSANLEITUNG). Gemessen und verworfen: Qwen3-VL-8B statt 30B-A3B ist nicht schneller
|
||||
(das MoE-Modell rechnet je Token nur ~3B Parameter) und liest etwas schlechter (Göllmann 42/44 statt 44/45
|
||||
automatisch).
|
||||
|
||||
Kosten der Cloud-Stufe (nur Regel `vlm3`): GLM liest nur Formeln, bei denen Qwen und Gemma einig sind. Gehrke: 967
|
||||
Anfragen, Ø 2,6 s, zusammen rund 0,15–0,20 $.
|
||||
|
||||
## Bildvergleich (Veto)
|
||||
|
||||
`compare.py` rendert die Lesart mit pdflatex (Schrift je Buch automatisch: `cm`, `times`, `txfonts`,
|
||||
`palatino`, `stix`, `euler`), richtet sie auf das Original aus und verzerrt sie **elastisch**
|
||||
(dynamische Zeitverzerrung über Spalten und Zeilen; Dehnen kostet proportional zur Tinte), damit
|
||||
Abstände und Längen keine Rolle spielen. Die Ähnlichkeit danach ist das Veto. Geprüft wird nur
|
||||
die Lesart, die übernommen werden kann: die von pix2text (Regel `vlm3`: die von Qwen). Bestätigende
|
||||
Lesarten werden nie übernommen und brauchen keine Prüfung. Die Prüfergebnisse tragen eine
|
||||
Versionsnummer des Verfahrens und werden nach Änderungen neu berechnet. Der alte Pixel-Entscheider mit
|
||||
Verwechslungsvarianten und Kontrasttest bleibt als Modus `decide=pixel` erhalten.
|
||||
|
||||
Sicherheit: Kandidaten kommen von Modellen und gelten als unsicher. Vor pdflatex werden Befehle wie
|
||||
`\input`, `\write`, `\def`, `\catcode` abgelehnt; pdflatex läuft mit `-no-shell-escape`,
|
||||
`openout_any=p`, Zeitlimit.
|
||||
|
||||
## Arbeitsordner
|
||||
|
||||
```text
|
||||
<ausgabe>.formulas/ # neben der Ausgabe, weil epub2md --force die Ausgabe ersetzt
|
||||
├── workspace.json # Quelle, Schrift, Einstellungen, apply-Zustand
|
||||
├── formulas/f-<sha12>-<d|i>.json # je Bild und Darstellung: Lesarten, Prüfung, Entscheidung
|
||||
├── crops/<id>.png # Original je Formel, einmal ausgeschnitten (PDF-Quellen)
|
||||
├── review/<id>-{orig,render,rigid,diff}.png
|
||||
├── bericht/ # Ergebnisseite (tools/buch_bericht.py)
|
||||
└── backup/ # Markdown-Dateien vor dem ersten apply
|
||||
```
|
||||
|
||||
Die Datensätze hängen am SHA-256 des Bildes: Ein erneuter epub2md-Lauf verliert keine Entscheidungen.
|
||||
|
||||
Einstellungen in `workspace.json` → `settings.consensus_thresholds`: `require_third` (1),
|
||||
`bold_relevant` (0), `structural` (0), `arbiter` (0), `arbiter_margin` (5), `veto_ncc` (0,65),
|
||||
`veto_scale_dev` (0 = aus), `min_p_mean`/`min_p_min` (0), `pdftext` (0: die PDF-Textebene bestätigt nie;
|
||||
gemessen: in 12 von 319 Fällen fehlten dort Punkte, Striche oder Indizes, die Qwen sah).
|
||||
|
||||
## Quellen
|
||||
|
||||
| Quelle | Erkennung | Begrenzer |
|
||||
| --- | --- | --- |
|
||||
| epub2md-Ordner | `conversion-report.json`; Warnungen `formula-image` markieren sichere Formeln | `--math auto`: `$…$`/`$$…$$`, `--math tex`: `\(…\)`/`\[…\]`; deutsche Bücher: `3{,}6` |
|
||||
| pdf2md (`<name>.md` + `<name>_images/` oder `--split`-Ordner) | Bildname `<pdf>-<seite>-<box>`; mit `--pdf` per Template-Matching auf der Seite gefunden und mit 600 dpi aus dem Vektor-PDF neu ausgeschnitten | `$…$`/`$$…$$` |
|
||||
| pdf2md `--formulas` | Bildname `<pdf>-<seite>-f<nr>.png` (300 dpi), Liste `<name>_images/formulas-*.json` mit Seite, Rechteck, Art (im Text/abgesetzt) und PDF-Text; das Bild wird direkt verwendet | `$…$`/`$$…$$` |
|
||||
|
||||
Mit `pdf2md --formulas` findet die Formelerkennung von pix2text (MFD) jede Formel auf der Seite, auch im
|
||||
Fließtext und in Merkkästen; pdf2md schneidet sie zeichengenau aus dem Text (statt Glyphensalat wie `x4n`).
|
||||
Ein Satzzeichen am Ende einer eingebetteten Formel wird vor dem Vergleich abgetrennt und als Text hinter
|
||||
die Formel gesetzt (`$a^{x}$,`). Codeblöcke werden nie verändert. Formeln in Tabellen erfasst die
|
||||
Erkennung noch nicht.
|
||||
|
||||
## Werkzeuge zum Einstellen
|
||||
|
||||
- `tools/vergleich.py AUSGABE` – feste Stichprobe (50 Formeln), verarbeitet wie `run`, schreibt
|
||||
`vergleich/<name>/index.html` mit Original, gerenderten Lesarten, Entscheidung und Veto-Overlay.
|
||||
- `tools/konsens_bericht.py BERICHT.json EPUB` – Übersichtsseite zu `calibrate --consensus --report`.
|
||||
- `tools/zeittest.py EPUB` – Zeit und Trefferquote je Tool, seriell an 15 Formeln mit bekanntem TeX.
|
||||
- `tools/regeltest.py EPUB [--n 50] [--reuse ergebnis.json] [--refresh local,local2] [--arbiter 8]` – die
|
||||
Standardregel an Formeln mit bekanntem TeX, wie `run`; Seite mit Original, wahrer Formel, allen
|
||||
Lesarten und Entscheidung. `--refresh` fragt trotz `--reuse` diese Engines neu (Prompt-Test).
|
||||
- `tools/buch_bericht.py AUSGABE` – Ergebnisseite eines ganzen Buchs nach `run`: jede Formel mit
|
||||
Original, gesetztem LaTeX, Status, Begründung und allen Lesarten, filterbar; liegt in
|
||||
`<arbeitsordner>/bericht/index.html` (Buchausschnitte, nicht versioniert).
|
||||
- `tools/vergleich_bericht.py --regeltest VORHER:NACHHER --kalibrierung VORHER.json:NACHHER.json` –
|
||||
Vorher/Nachher-Seite zweier Läufe auf denselben Lesarten: Zahlen, jede geänderte Entscheidung und
|
||||
jedes geänderte Urteil gegen die Wahrheit, mit Original und gerenderten Lesarten.
|
||||
- `calibrate --consensus --engines local,local2,cloud,p2t --report X.json` misst alle Regeln;
|
||||
`--reuse X.json` rechnet sie ohne Modellabfragen neu.
|
||||
- `vergleich/` ist nicht versioniert (Ausschnitte aus Büchern).
|
||||
|
||||
## Stand
|
||||
|
||||
**Formeln im Fließtext** (unveröffentlicht, nach 0.4.0): Corral mit `pdf2md --formulas`: 9239 Formelbilder
|
||||
(davon ~88 % eingebettet). Stichprobe 10 % (940): **747 automatisch (79 %)**, im Text 83 %, abgesetzte
|
||||
Box-Bilder (Herleitungen, Kästen) nur ~29 %; 174 Review, 19 keine Formel; 13 Minuten, hochgerechnet ~2 h
|
||||
für das ganze Buch. Beschleunigung am Pilot (869 Formeln): 70 → ~24 Minuten, Entscheidungen zu 863/876
|
||||
gleich (die Abweichungen kommen von den Modellen selbst). Qualität ist hier ohne bekannte Lösung –
|
||||
vor dem Einsatz eine Stichprobe der übernommenen Formeln von Hand prüfen.
|
||||
|
||||
Version 0.4.0 (Regel `p2t`, mehrzeilige Normalform) ist an Göllmann Band 1 und 2 gemessen (siehe
|
||||
[Messung](#messung)), aber noch **nicht am ganzen Gehrke** gelaufen.
|
||||
|
||||
**Erstes ganzes PDF-Buch** (0.4.0): Corral, *Elementary Calculus* (346 Seiten, TeX-PDF, pdf2md mit
|
||||
600-dpi-Neuausschnitt): 1150 Ausschnitte → **429 automatisch ersetzt (37 %)**, 633 Review, 61 keine
|
||||
Formel, 27 Abbildungen. EPUB (`pdf2md --from-md`, jetzt mit `--mathml`): 429 Formeln als MathML, kein
|
||||
TeX-Rest. Laufzeit rund 4 Stunden (pix2text Ø 3,9 s, Qwen Ø 8,1 s, Gemma Ø 15 s je Anfrage – große
|
||||
Ausschnitte). Das Review besteht überwiegend aus Ausschnitten, die keine einzelne Formel sind
|
||||
(Merkkästen mit Text, Tabellen, Diagramme, ganze Herleitungen) – das muss pdf2md besser trennen. Die folgenden Zahlen stammen von Version 0.2.0 (Regel `vlm3`, mit GLM).
|
||||
|
||||
Version 0.2.0 (Konsens), getestet am Gehrke, Brückenkurs Mathematik (EPUB, CM-Formeln als kleine JPGs):
|
||||
|
||||
| | Anzahl |
|
||||
| --- | --- |
|
||||
| Formelbilder verarbeitet (sicher oder unklar klassifiziert) | 1505 |
|
||||
| **automatisch ersetzt** | **942 (63 %)** |
|
||||
| Review: Qwen und Gemma uneinig | 410 |
|
||||
| Review: GLM weicht ab | 65 |
|
||||
| Review: Bild-Veto / Pandoc | 2 / 1 |
|
||||
| keine Formel (laut Modellen) | 85 |
|
||||
| nicht geprüft (Abbildungen, Symbole) | 539 |
|
||||
|
||||
- **Von Hand geprüft:** die 42 automatisch ersetzten Formeln der festen 50er-Stichprobe und 20 zufällig
|
||||
gezogene weitere – **62 von 62 Zeichen für Zeichen korrekt** (Brüche, Wurzeln mit Index, `cases`,
|
||||
Grenzwerte, Integrale, Vektorpfeile, Überstriche über mehreren Buchstaben).
|
||||
- **apply** an einer Kopie: 946 Ersetzungen in 258 Kapiteldateien (manche Formeln kommen mehrfach vor).
|
||||
`epub2md_merge.py` → 945 Formeln in der Gesamtdatei (eine stand in einer doppelten Fußnote, die das
|
||||
Zusammenfügen entfernt). Pandoc `--mathml`: **945 von 945** als MathML, keine „Could not convert TeX
|
||||
math“-Meldung. EPUB daraus in 10 s gebaut.
|
||||
- **Laufzeit** mit beiden lokalen Modellen parallel (zwei RTX 3090) und GLM: ~5 Minuten je 50 Formeln,
|
||||
das Buch also rund 2,5 Stunden.
|
||||
|
||||
Grenzen und offene Punkte:
|
||||
|
||||
- Mehrzeilige Rechnungen: Rahmen und `&` gleicht die Normalform seit 0.4.0 aus; verschiedene
|
||||
Zeilenumbrüche, `\underbrace` und fehlende Integrationsgrenzen bleiben im Review.
|
||||
- Formeln auf farbig hinterlegten Kästen verlieren beim Ersetzen die Hinterlegung.
|
||||
- Fettdruck wird nicht geprüft (Vorgabe).
|
||||
- Die Messung umfasst 2 × 150 Formeln eines Buches ohne Textausschnitt; „0 Fehler“ bedeutet eine
|
||||
Fehlerquote sehr wahrscheinlich unter ~2 %.
|
||||
- pdf2md-Bücher: am ganzen Corral getestet (ohne `--formulas` 0.4.0, mit `--formulas` 10 %); Formeln in
|
||||
Tabellen fehlen noch.
|
||||
- Einzelne Riesenausschnitte (Grafiken, dreizeilige Herleitungen mit völlig anderer Lesart) werden ohne
|
||||
Bildvergleich abgelehnt: über 2,5 MP oder mehr als 2,5-fach falsche Proportionen; breite Originale werden
|
||||
für den Vergleich auf 1600 px verkleinert.
|
||||
|
||||
## Installation
|
||||
Voraussetzungen und das Starten der Modellserver: [BEDIENUNGSANLEITUNG.md](BEDIENUNGSANLEITUNG.md).
|
||||
|
||||
```bash
|
||||
sudo apt install texlive-latex-extra texlive-fonts-extra texlive-science pandoc dvipng
|
||||
pip install -r requirements.txt # pymupdf, numpy, scipy, scikit-image, opencv, Pillow, lxml, requests
|
||||
pip install -r requirements-dev.txt # pytest
|
||||
pip install -r requirements.txt
|
||||
pip install "pix2text[multilingual]" && pip install --no-deps pix2tex munch
|
||||
|
||||
python3 formula_img2latex.py run ~/Python_Programs/epub2md/output/buch # lesen, prüfen, entscheiden
|
||||
python3 formula_img2latex.py review ~/Python_Programs/epub2md/output/buch # Zweifelsfälle im Browser
|
||||
python3 formula_img2latex.py apply ~/Python_Programs/epub2md/output/buch # Formeln ins Markdown schreiben
|
||||
```
|
||||
|
||||
Modelle: siehe BEDIENUNGSANLEITUNG (llama-server starten).
|
||||
## Stand
|
||||
|
||||
## Tests
|
||||
Version 0.4.0 plus unveröffentlichte Änderungen (siehe [CHANGELOG.md](CHANGELOG.md)). An Formelbildern
|
||||
mit bekannter Lösung (Göllmann, Springer) werden 88–89 % automatisch ersetzt, **keine davon falsch**.
|
||||
Ganze Bücher: Gehrke-Brückenkurs (EPUB) 63 %, alle 62 von Hand geprüften korrekt; Corral mit
|
||||
`pdf2md --formulas` 79 % (Stichprobe). Einzelheiten: [FUNKTIONSWEISE.md, Messungen](FUNKTIONSWEISE.md#12-messungen).
|
||||
|
||||
## Documentation
|
||||
|
||||
| Dokument | Inhalt |
|
||||
|---|---|
|
||||
| [BEDIENUNGSANLEITUNG.md](BEDIENUNGSANLEITUNG.md) | Installation, Modellserver, ein Buch bearbeiten, Konfiguration, Betrieb, Fehlersuche |
|
||||
| [FUNKTIONSWEISE.md](FUNKTIONSWEISE.md) | Aufbau, Datenfluss, Entscheidungsregel, Normalform, Bildabgleich, Messungen, Designentscheidungen, Grenzen |
|
||||
| [CHANGELOG.md](CHANGELOG.md) | Änderungen je Version und was beim Update zu tun ist |
|
||||
| [LICENSE](LICENSE) | MIT |
|
||||
| `Idee/` | ursprüngliche Problemstellung und Planung |
|
||||
|
||||
## Entwicklung
|
||||
|
||||
```bash
|
||||
pip install -r requirements-dev.txt
|
||||
python3 -m pytest -q # ca. 45 s; synthetische Bilder, kein Modellserver, keine Buchinhalte
|
||||
```
|
||||
|
||||
Rückgabecodes: `0` Erfolg, `1` Bedienfehler, `2` Eingabe ist keine epub2md-/pdf2md-Ausgabe,
|
||||
`3` externes Werkzeug fehlt (pdflatex, pandoc, Modellserver), `4` interner Fehler.
|
||||
## License
|
||||
|
||||
## Architektur
|
||||
|
||||
```text
|
||||
formula_img2latex/
|
||||
├── cli.py Unterbefehle, Exit-Codes
|
||||
├── pipeline.py scan, recognize, verify, Entscheidung (Konsens/Pixel), run in Paketen, apply/revert
|
||||
├── consensus.py Normalform, Render-Gleichheit: sagen zwei Lesarten dasselbe?
|
||||
├── decide.py Annahmeregeln und Schwellen (Konsens- und Pixel-Modus)
|
||||
├── engines/ Vision-Modelle über die OpenAI-API (llama.cpp, OpenRouter), Logprobs, Prompt-Version;
|
||||
│ p2t.py: pix2text-Formel-OCR (ONNX, CPU/GPU)
|
||||
├── compare.py Ausrichtung, elastische Verzerrung, Kennzahlen, Kontrasttest, Diff-Bilder
|
||||
├── confusables.py Verwechslungsvarianten (Pixel-Modus)
|
||||
├── verify.py Bildprüfung einer Lesart (Veto bzw. Pixel-Entscheider)
|
||||
├── render.py pdflatex-Batch, Schrift-Presets, Rasterung
|
||||
├── imageio.py Originale laden (PNG/GIF/JPG/SVG, Transparenz, Tönung)
|
||||
├── sources/ epub2md.py, pdf2md.py, base.py (Markdown-Scan, Begrenzer, Dezimalkomma)
|
||||
├── structure.py Strukturvergleich mit sympy (optional, aus)
|
||||
├── pdfcrop.py Formelbild auf der PDF-Seite finden, 600-dpi-Neuausschnitt
|
||||
├── classify.py Formel / unklar / Abbildung
|
||||
├── checks.py Pandoc/MathML-Prüfung
|
||||
├── calibrate.py Messung an Formelbildern mit bekanntem TeX
|
||||
├── store.py Arbeitsordner, Datensätze
|
||||
└── review/ lokaler Review-Server + Seite
|
||||
```
|
||||
MIT, siehe [LICENSE](LICENSE).
|
||||
|
|
|
|||
|
|
@ -15,13 +15,14 @@ from .render import PRESETS
|
|||
|
||||
DESCRIPTION = """\
|
||||
Ersetzt Formelbilder in Markdown-Ausgaben von epub2md und pdf2md durch LaTeX – aber nur, wenn
|
||||
das gerenderte LaTeX nachweislich so aussieht wie das Original. Zweifelsfälle gehen in eine
|
||||
Review-Galerie, alles andere bleibt Bild.
|
||||
zwei Erkenner dieselbe Formel lesen (pix2text, bestätigt von Qwen oder bei Uneinigkeit von Gemma)
|
||||
und ein grober Bildabgleich nicht widerspricht. Zweifelsfälle gehen in eine Review-Galerie,
|
||||
alles andere bleibt Bild.
|
||||
"""
|
||||
|
||||
EPILOG = """\
|
||||
Typischer Ablauf:
|
||||
formula_img2latex.py run output/buch # scan, erkennen (lokal, dann Cloud), prüfen
|
||||
formula_img2latex.py run output/buch # scan, lesen (pix2text, Qwen, Gemma), prüfen
|
||||
formula_img2latex.py review output/buch # Zweifelsfälle im Browser entscheiden
|
||||
formula_img2latex.py apply output/buch # geprüfte Formeln ins Markdown schreiben
|
||||
formula_img2latex.py revert output/buch # alles rückgängig machen
|
||||
|
|
@ -56,10 +57,10 @@ def build_parser() -> argparse.ArgumentParser:
|
|||
sp.add_argument("--quiet", "-q", action="store_true", help="nur Fehler ausgeben")
|
||||
|
||||
def recog_opts(sp: argparse.ArgumentParser) -> None:
|
||||
sp.add_argument("--model", default=None, help="Modellname (Standard: local = Modell des Servers, "
|
||||
"cloud = $FORMULA_CLOUD_MODEL oder google/gemini-2.5-flash)")
|
||||
sp.add_argument("--model", default=None, help="Modellname (Standard: local/local2 = Modell des Servers, "
|
||||
"cloud = $FORMULA_CLOUD_MODEL oder z-ai/glm-4.6v, p2t = mfr-1.5)")
|
||||
sp.add_argument("--url", default=None, help="API-Basis-URL (Standard: local http://127.0.0.1:8011/v1, "
|
||||
"cloud https://openrouter.ai/api/v1)")
|
||||
"local2 http://127.0.0.1:8012/v1, cloud https://openrouter.ai/api/v1)")
|
||||
sp.add_argument("--include-figures", action="store_true",
|
||||
help="auch Bilder versuchen, die wie Abbildungen aussehen")
|
||||
sp.add_argument("--limit", type=int, default=0, help="höchstens N Bilder (zum Ausprobieren)")
|
||||
|
|
@ -70,7 +71,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|||
sp.add_argument("--pdf", type=Path, default=None,
|
||||
help="pdf2md: Original-PDF, um Formeln scharf neu auszuschneiden")
|
||||
|
||||
sp = sub.add_parser("recognize", help="LaTeX-Kandidaten mit einem Vision-Modell erzeugen")
|
||||
sp = sub.add_parser("recognize", help="Lesarten einer Engine erzeugen (p2t, local, local2, cloud)")
|
||||
common(sp)
|
||||
recog_opts(sp)
|
||||
sp.add_argument("--engine", choices=["local", "local2", "cloud", "p2t"], default="local")
|
||||
|
|
@ -85,13 +86,13 @@ def build_parser() -> argparse.ArgumentParser:
|
|||
sp.add_argument("--include-figures", action="store_true")
|
||||
sp.add_argument("--redo", action="store_true", help="auch bereits geprüfte Formeln neu prüfen")
|
||||
|
||||
sp = sub.add_parser("run", help="scan + recognize (lokal, dann Cloud) + verify")
|
||||
sp = sub.add_parser("run", help="scan + lesen + prüfen + entscheiden, in Paketen mit Statuszeile")
|
||||
common(sp)
|
||||
recog_opts(sp)
|
||||
sp.add_argument("--pdf", type=Path, default=None)
|
||||
sp.add_argument("--cloud-model", default=None, help="Modell für die Cloud-Stufe")
|
||||
sp.add_argument("--no-local", action="store_true", help="lokale Stufe überspringen")
|
||||
sp.add_argument("--no-cloud", action="store_true", help="Cloud-Stufe überspringen")
|
||||
sp.add_argument("--cloud-model", default=None, help="Regel vlm3: Modell für die Cloud-Stufe")
|
||||
sp.add_argument("--no-local", action="store_true", help="nur Modus decide=pixel: lokale Stufe überspringen")
|
||||
sp.add_argument("--no-cloud", action="store_true", help="Regel vlm3 bzw. decide=pixel: Cloud-Stufe überspringen")
|
||||
sp.add_argument("--preset", choices=["auto", *PRESETS], default="auto")
|
||||
sp.add_argument("--chunk", type=int, default=50, help="Paketgröße; nach jedem Paket eine Statuszeile (Standard 50)")
|
||||
|
||||
|
|
|
|||
|
|
@ -5,4 +5,6 @@ scikit-image>=0.22
|
|||
opencv-python-headless>=4.8
|
||||
Pillow>=10.0
|
||||
lxml>=5.0
|
||||
requests>=2.31
|
||||
# pix2text separat, siehe BEDIENUNGSANLEITUNG: pip install "pix2text[multilingual]"; pip install --no-deps pix2tex munch
|
||||
# optional, only for the structural comparison (FORMULA_STRUCTURAL=1): sympy>=1.13, lark>=1.1
|
||||
|
|
|
|||
Loading…
Reference in a new issue