Files
docu_build/doc/plan_fortna_extraktion.md
T
Michael StanglandClaude Opus 4.8 e7aa3b4e4b feat: Fortna-Extraktion nach chapters/ + Sphinx-PDF-Build
Skripte zum Befuellen der Kapitelstruktur aus dem Fortna-Rohmaterial und
Aufbau eines vollstaendigen Sphinx/LaTeX-Builds (nur Code/Config/Doku,
generierte RST/Bilder/PDFs und Rohmaterial via .gitignore ausgeschlossen).

- lib/fortna_inventory.py: Rohmaterial scannen, Sprache+Zielkapitel+Aktion
  zuordnen, results/fortna_inventory.json schreiben
- lib/fortna_convert_chapters.py: 5 Hauptanleitungen volltextig (Text+Bilder)
  konvertieren, Verzeichnislisten (index.de.rst) fuer uebrige Kapitel
- lib/fortna_init_project.py: projekte/fortna/ (anlage.json, overrides, images)
- lib/build_index.py: index.rst mit toctrees aus chapters/**/*.de.rst generieren
- lib/extract_products.py: Symbolfont-Zeichen (PUA) auf Unicode mappen (clean_pua)
- conf.py: Sphinx-Build (lualatex, babel statt polyglossia, iconpackage=none)
- bin/: .bat/.sh-Wrapper fuer alle Skripte + build_pdf
- doc/: Konzept-Plan (plan_fortna_extraktion.md) und lib-Skript-Uebersicht
- requirements.txt: Sphinx + myst-parser ergaenzt

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-09-23 13:23:32 +02:00

241 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Konzept: Fortna-Extraktion nach chapters/ + Projektordner fortna/
Status: **Umgesetzt** (erster vollständiger Durchlauf inkl. PDF-Build). Antworten aus der
Rückfragerunde sind eingearbeitet (siehe Abschnitt "Entscheidungen"). Der tatsächliche
Ist-Stand ist unten unter "Umsetzung / Ist-Stand" dokumentiert.
## Umsetzung / Ist-Stand
Implementiert wurden vier Python-Skripte in `lib/` mit `bin/`-Wrappern (`.bat` + `.sh`):
| Skript | Zweck | Wrapper |
|---|---|---|
| `lib/fortna_inventory.py` | Scannt das Rohmaterial, ordnet jede Datei Sprache + Zielkapitel + Aktion zu, schreibt `results/fortna_inventory.json`. | `bin/fortna_inventory.*` |
| `lib/fortna_convert_chapters.py` | Volltext+Bilder für die 5 DE-Hauptanleitungen, Verzeichnislisten (`index.de.rst`) für alle übrigen Kapitel. `--dry-run` (Default) / `--apply`. | `bin/fortna_convert_chapters.*` |
| `lib/fortna_init_project.py` | Legt `projekte/fortna/` an (`anlage.json`, `overrides/`, `images/`, `README.md`). | `bin/fortna_init_project.*` |
| `lib/build_index.py` | Generiert `index.rst` mit toctrees aus allen `chapters/**/*.de.rst`. | (in `build_pdf.*`) |
| `bin/build_pdf.*` | Kompletter PDF-Build: index → `sphinx-build -b latex` → `latexmk -lualatex`. | — |
Ergebnis des ersten Laufs:
- 5 Hauptanleitungen volltextig konvertiert (Betriebs-/Wartungsanleitung, Funktionsbeschreibung
ILS/OMNIFLO/LoadingLoop), zusammen ~13.500 Textblöcke + mehrere Hundert entduplizierte Bilder.
- 9 Verzeichnislisten erzeugt (Zertifikate, Lieferantendoku nach Gewerk, Notstopp, Prüfberichte).
- `projekte/fortna/` mit `anlage.json`-Platzhalter angelegt.
- **Vollständiger PDF-Build erfolgreich**: `_build/latex/Fortna_Dokumentation_DE.pdf`, ~670 Seiten,
`latexmk`-Exit 0, keine LaTeX-Fehler.
### Umgebung / Build-Voraussetzungen (bereits erfüllt)
- Sphinx 9.1.0 + myst-parser 5.1.0 im `.venv` (ergänzt in `requirements.txt`).
- LaTeX: MiKTeX unter `C:\Program Files\MiKTeX\` (lualatex/latexmk vorhanden).
- `conf.py` erzeugt: LaTeX-Engine **lualatex**, **babel** statt polyglossia
(polyglossia 2.13 wirft unter lualatex einen bidi-Fehler), **`iconpackage=none`**
(FontAwesome7 in MiKTeX bricht unter lualatex ab). Beides in `conf.py` kommentiert.
### Behobene Extraktionsprobleme
- **Symbolfont-Zeichen** (Wingdings/Symbol Private-Use-Area, z. B. Aufzählungs-Bullet U+F0B7):
in `extract_products.py` via `clean_pua()` auf echte Unicode-Zeichen (•, →, ✓) gemappt,
restliche PUA-Zeichen entfernt. Vorher erschienen leere Kästchen im PDF.
### Bekannte Restpunkte (nicht Teil des Auftrags-Scopes)
- Zwei **Fremd-Altdateien** aus früheren `convert_to_rst.py`-Testläufen sind noch im Baum und
vom Build ausgeschlossen (`conf.py` + `build_index.py` SKIP-Liste):
`02_sicherheit/risikobewertung/rb_fortna_...de.rst` (unvollständiger Bildbestand) und
`00_inhaltsverzeichnis/contens_obsah_...de.rst` (keine RST-Überschrift). Zwei weitere
Altdateien in `10_anhang/` (Motor/Getriebe) sind noch im toctree und zeigen typische
Extraktionsartefakte – bei Bedarf mit `fortna_convert_chapters.py` sauber neu erzeugen.
- **Tabellen** (z. B. Änderungshistorie) werden weiterhin als Einzelzeilen extrahiert, nicht als
RST-Tabelle rekonstruiert (wie im Konzept angekündigt).
---
## Ausgangslage
- Reales Fortna-Rohmaterial liegt in `c:\10-Develop\projekte\Fortna\` (zusätzliches
Arbeitsverzeichnis dieser Session, **nicht** im Repo). Struktur wie in `doc/Fortna.txt`
dokumentiert (00_CONTENTS_NOTES … 05_SUPPLIER_DOC), Versionsstände dort sind aktueller als in
`doc/Fortna.txt` (z. B. Betriebsanleitung V2.4 statt V2.3, Wartungsanleitung V2.3, ILS V2.2,
OMNIFLO V1.1, LoadingLoop V2.3). `doc/Fortna.txt`/`doc/Fortna-size.txt` sind nur noch als
Struktur-Referenz zu verstehen, nicht als Quelle für den Extraktionslauf.
- `chapters/` (Base-Repo-Gerüst) existiert bereits vollständig mit `.gitkeep`-Platzhaltern gemäß
`doc/kapitelstruktur.md`. `06_steuerung/loading_loop/` wurde testweise mit `convert_to_rst.py`
aus der LoadingLoop-Word-Datei befüllt (2 RST + 74 Bilder). Qualität ist noch unzureichend:
Kopf-/Fußzeilen (Firmenadresse, Kontaktdaten) landen als normale Absätze im Fließtext,
Tabellen (Änderungshistorie) werden zu einzelnen Zeilen ohne Tabellenstruktur zerlegt. Das ist
ein bekanntes Problem der aktuellen `_html_to_blocks`-Logik in `convert_to_rst.py` und wird im
Zuge dieser Arbeit mit adressiert (siehe Abschnitt "Bekannte Schwachstellen").
- Vorhandene Skripte in `lib/` (siehe `doc/lib_skripte.md`):
- `convert_to_rst.py`: `.docx`/Word-PDF → RST, erkennt Zielkapitel nur anhand Dateiname-Pattern
im Root eines Ordners, kein Verständnis für den verschachtelten Fortna-Sprachordner-Baum.
- `extract_products.py`: Produktprogramm-PDFs → Bilder + RST (bereits fertig genutzt für
`data/Produktprogramm`).
- `jsonFromXlsx.py`, `extract_ids.py`, `project_from_xlsx.py`: Stücklisten-Auswertung, für
diese Aufgabe nicht direkt relevant.
- Kein Skript kennt bisher die komplette Fortna-Ordnerstruktur (Lieferantendoku-Baum, Layouts,
Schaltpläne, Prüfberichte) und keines erzeugt den projektspezifischen Ordner (`anlage.json`,
`overrides/`, `images/`) gemäß `doc/Kernkonzepte.md`.
## Entscheidungen (aus Rückfragen)
| Frage | Entscheidung |
|---|---|
| Lieferantendoku (~250 PDFs: SEW, Siemens, Leuze, Cognex, MiTek, Aventics, …) | **Nur Verzeichnisliste**, keine Kopie. RST-Referenztabelle mit Pfaden auf das Originalverzeichnis. |
| Sonstige PDFs (Zertifikate, Konfigurationsbeschreibung, Layouts, Schaltpläne, Notstopp/Bereichsstopp, Prüfberichte, Ersatzteilliste) | Gleiche Behandlung wie Lieferantendoku: **nur Verzeichnisliste**, keine Kopie nach `chapters/`. |
| Volltext-Konvertierung (Text + Bilder → RST) | **Nur die 5 Hauptanleitungen**: Betriebsanleitung, Wartungsanleitung, Funktionsbeschreibung ILS, Funktionsbeschreibung OMNIFLO, Funktionsbeschreibung LoadingLoop. |
| Projektordner-Ort | `projekte/fortna/` **innerhalb dieses Repos** (docu_build), pragmatisch für jetzt; spätere Auslagerung in eigenes Repo bleibt möglich. |
| Sprachumfang | **Nur Deutsch** in diesem Durchlauf. Namenskonvention `{name}.de.rst` einhalten, EN/CZ als späterer zweiter Durchlauf vorgesehen. |
| Quelle | `c:\10-Develop\projekte\Fortna\` (aktueller Stand), nicht `doc/Fortna.txt`. |
| Umgang mit bestehendem `chapters/06_steuerung/loading_loop/` | **Überschreiben/neu erzeugen** – konsistent aus einem Guss statt Altbestand stehen lassen. |
## Zielstruktur (Ergebnis nach Lauf)
```text
chapters/
01_zertifikate/
konformitaetserklaerung/index.de.rst # Verzeichnisliste -> Originalpfade
konfigurationsbeschreibung/index.de.rst
02_sicherheit/ # unverändert (kein Fortna-Rohmaterial 1:1 zuordenbar)
03_anlagenbeschreibung/ # unverändert (Modul-Mechanismus, nicht Teil dieser Aufgabe)
04_betrieb/betriebsanleitung/
betriebsanleitung_500592_135776_v2_4.de.rst # Volltext + Bilder
images/img_001.png ...
05_wartung/wartungsanleitung/
wartungsanleitung_500592_v2_3.de.rst # Volltext + Bilder
images/...
06_steuerung/
ils/funktion_steuerung_ils_500592_v2_2.de.rst # Volltext + Bilder
omniflo/funktion_steuerung_omniflo_500592_v1_1.de.rst
loading_loop/funktion_steuerung_loadingloop_500592_v2_3.de.rst # neu erzeugt, ersetzt Altbestand
07_ersatzteile/index.de.rst # Verzeichnisliste -> Originalpfad SPARE_PARTS PDF
08_lieferantendoku/
antriebe/index.de.rst # Verzeichnisliste SEW, NORD, Leantechnik, DTS
elektrik/index.de.rst # Siemens, Leuze, Cognex, Werma, ...
pneumatik/index.de.rst # Aventics, ITS
stahlbau/index.de.rst # MiTek (As-Built, Statik, Zertifikate, ...)
sicherheitseinrichtungen/index.de.rst # ABS Sicherheitslinie
09_technische_unterlagen/
layouts/mechanisch/index.de.rst
layouts/elektrisch/index.de.rst
schaltplaene/index.de.rst
notstopp/index.de.rst
bereichsstopp/index.de.rst
10_anhang/
pruefberichte/index.de.rst
projekte/
fortna/
anlage.json # Projektmetadaten (Platzhalter/Vorschlag, manuell nachzuschärfen)
overrides/ # leer angelegt, Struktur gemäß Kernkonzepte.md
images/ # leer angelegt (projektspezifische Bilder, Kundenlogo etc.)
README.md # kurze Erläuterung was hier reinkommt
```
Jede `index.de.rst`-Verzeichnisliste enthält eine Tabelle: Dateiname, Hersteller/Kategorie
(aus Ordnername abgeleitet), Originalpfad (relativ zu einer konfigurierbaren Basis, z. B.
`PV_FORTNA_SOURCE`), Dateigröße. Kein PDF wird kopiert oder eingebettet – das hält den
Kapitelbaum schlank und vermeidet Redundanz zum Rohmaterial, das ohnehin an anderer Stelle
(Nextcloud/Projektordner) verwaltet wird.
## Geplante Skripte (in `lib/`)
### 1. `fortna_inventory.py` (neu)
Scannt `c:\10-Develop\projekte\Fortna\` rekursiv und baut ein Inventar (JSON) aller Dateien mit:
Pfad, Größe, erkannte Sprache (aus Ordnername: `*_DE*`/`*_EN*`/`*_CZ*`/`*original*` → de),
vermutetem Fortna-Kapitel (oberste zwei Ebenen) und vermutetem Ziel-Kapitel gemäß Mapping-Tabelle
aus `doc/kapitelstruktur.md`. Dient als Kontrollartefakt (`results/fortna_inventory.json`), auf
dessen Basis sich beide folgenden Skripte konfigurieren bzw. dessen Output sich manuell prüfen
lässt, bevor tatsächlich geschrieben wird (`--dry-run` Default, `--apply` zum Ausführen).
Grund für ein separates Inventarskript: 387 Dateien über 6 Top-Level-Ordner mit inkonsistenter
Sprachordner-Benennung (`01_DE_original`, `01_EN_original`, `1_EN_original` [Tippfehler im
Quellbaum], `02_CZ`, `03_CZ_pro_celé_zařízení`, …) – ein Trockenlauf mit Report ist nötig, um
Mapping-Lücken zu erkennen, bevor Dateien verschoben/verarbeitet werden.
### 2. `fortna_convert_chapters.py` (neu)
Nutzt das Inventar aus Schritt 1 (oder scannt bei Bedarf direkt) und führt zwei Aktionsarten aus:
- **Volltext-Konvertierung** für die 5 Hauptanleitungen: ruft die vorhandene Konvertierungslogik
aus `convert_to_rst.py` wieder, aber mit expliziter Quelldatei-Liste (kein Verzeichnis-Scan)
und fest zugeordnetem Zielkapitel (aus der Tabelle unten), statt der generischen
`CHAPTER_MAPPING`-Heuristik. Überschreibt bestehende Ziel-RSTs/Bilder vollständig
(Ordnerinhalt vorher leeren, dann neu schreiben).
- **Verzeichnislisten-Generierung** für alle übrigen Kapitel (Zertifikate, Layouts, Schaltpläne,
Notstopp/Bereichsstopp, Prüfberichte, Ersatzteile, Lieferantendoku): läuft über die im
Inventar erkannten Dateien je Zielordner und rendert eine `index.de.rst` mit
RST-list-table (Dateiname, Pfad, Größe).
Fest zugeordnete Hauptanleitungen (Quelle → Ziel):
| Quelldatei (DE, aktuellster Stand in `projekte/Fortna`) | Zielkapitel |
|---|---|
| `02_INSTRUCTIONS.../01_DE_original/01_BETRIEBSANLEITUNG_500592_135776_V2.4.pdf` | `04_betrieb/betriebsanleitung/` |
| `02_INSTRUCTIONS.../01_DE_original/02_WARTUNGSANLEITUNG_500592_V2.3.pdf` | `05_wartung/wartungsanleitung/` |
| `02_INSTRUCTIONS.../01_DE_original/03_FUNKTION_STEUERUNG_ILS_500592_V2.2.pdf` | `06_steuerung/ils/` |
| `02_INSTRUCTIONS.../01_DE_original/04_FUNKTION_STEUERUNG_OMNIFLO_500592_V1.1.pdf` | `06_steuerung/omniflo/` |
| `02_INSTRUCTIONS.../01_DE_original/05_FUNKTION_STEUERUNG_LOADING_LOOP_500592_V2.3.pdf` | `06_steuerung/loading_loop/` (ersetzt Altbestand) |
Alle fünf sind PDFs (keine `.docx` im Quellordner mehr vorhanden), daher wird der
`is_word_pdf()`-Pfad aus `convert_to_rst.py` verwendet (pdfminer-Textextraktion). Die extra
`extract_products.py`-Textheuristik (Schriftgrößen-basierte Überschriftenerkennung,
Kopf-/Fußzeilen-Ausschluss nach Y-Position) ist für Word-erstellte PDFs wie diese *robuster* als
die aktuelle `convert_to_rst.py`-Textheuristik (siehe Bekannte Schwachstellen) – Vorschlag: die
Extraktionsroutine aus `extract_products.py` (`extract_text_to_rst`, `_is_noise`,
`extract_images`) wiederverwenden/verallgemeinern statt der schwächeren `pdfminer`-Variante aus
`convert_to_rst.py`.
### 3. `fortna_init_project.py` (neu)
Legt `projekte/fortna/` an: `anlage.json` (Platzhalter mit Projektnummer 500592/KA135776,
Sprache `["de"]`, `normen_region` offen als TODO), leere `overrides/`- und `images/`-Ordner mit
`.gitkeep`, sowie ein kurzes `README.md`. Einmaliger Lauf, kein Datei-Scan nötig – im
Wesentlichen ein Gerüst-Generator.
## Bekannte Schwachstellen der bisherigen Konvertierung (zu beheben)
Der Altbestand in `chapters/06_steuerung/loading_loop/` zeigt zwei konkrete Probleme der
aktuellen `convert_to_rst.py`-Logik, die für die 5 Hauptanleitungen behoben werden sollten:
1. **Kopf-/Fußzeilen als Fließtext**: Firmenadresse, Kontaktdaten, Projektnummer erscheinen als
normale Absätze mitten im Dokument (weil `pdfminer.high_level.extract_text` keine
Positionsinformation liefert, mit der man Kopf-/Fußzeilen herausfiltern könnte).
`extract_products.py` löst das bereits über `page.get_text("dict")` mit Y-Positions-Filter
(`bbox[1] < 100` / `bbox[3] > page_height - 50`) – diese Technik übernehmen.
2. **Tabellen zerfallen in Einzelzeilen**: Die Änderungshistorie-Tabelle wird zu einer Folge
einzelner Absätze ohne Tabellenstruktur. Vorschlag für ersten Wurf: Tabellen nicht als
RST-Table rekonstruieren (zu fehleranfällig aus PDF-Text), sondern als eingerückten
`.. code-block::` oder einfache Aufzählung kennzeichnen, mit `.. todo:: Tabelle manuell
nachbearbeiten`-Marker – ehrlich statt falsch-schön.
## Offene Punkte / Annahmen, die ich getroffen habe
- Ich gehe davon aus, dass `PV_FORTNA_SOURCE` (oder ein `--source-dir`-Argument) als neue
Umgebungsvariable/Parameter eingeführt wird, die auf `c:\10-Develop\projekte\Fortna\` zeigt,
da dieser Pfad außerhalb des Repos liegt und nicht über `PV_DATA`/`PV_EXAMPLES` erreichbar ist.
- `02_sicherheit/` und `03_anlagenbeschreibung/` bleiben in diesem Durchlauf unangetastet – es
gibt keine 1:1-Quelle dafür in `projekte/Fortna/` (Risikobewertung liegt als separate
`.docx`-Dateien direkt im Repo-Root von `chapters/`, siehe Git-Status, nicht Teil dieser
Aufgabe).
- Die generierten `index.de.rst`-Verzeichnislisten verweisen auf absolute oder
repo-relative-konfigurierbare Pfade zum Rohmaterial – das bedeutet, das Zielsystem (Sphinx)
bekommt keine eigenständig lauffähige Doku ohne Zugriff auf `projekte/Fortna/`. Das ist so
gewollt gemäß der Entscheidung "nur Verzeichnisliste", sollte aber vor dem produktiven
PDF-Build nochmal bewusst bestätigt werden (spätestens beim ersten `sphinx-build`-Versuch
fehlen dann die Downloads/Links).
## Nächste Schritte
1. Dieses Konzept abstimmen (insb. Umgang mit `02_sicherheit`/Risikobewertung-Docx im Root von
`chapters/`, sowie die Pfad-Referenzierung in den Verzeichnislisten).
2. `fortna_inventory.py` implementieren und Trockenlauf-Report gegen `projekte/Fortna/` prüfen.
3. `fortna_convert_chapters.py` implementieren (inkl. Wiederverwendung der
`extract_products.py`-Textextraktion), auf 5 Hauptanleitungen anwenden, Ergebnis stichprobenhaft
gegenlesen.
4. `fortna_init_project.py` implementieren, `projekte/fortna/` anlegen.
5. `bin/`-Wrapper-Skripte (`.bat`/`.sh`) für alle drei ergänzen, analog bestehender Konvention.