# 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. ### Extraktion: neues Modul `lib/pdf_extract.py` Die Volltext-Konvertierung der 5 Hauptanleitungen läuft über das neue Modul `lib/pdf_extract.py` (`extract_manual()`), das gegenüber der ersten Version deutlich sauberere `.rst` erzeugt: - **Keine doppelte Nummerierung mehr:** Die im PDF vorhandene Gliederungsnummer (z. B. „1.7 Wichtige Informationen") wird nur zur Bestimmung der Überschriften-Ebene ausgewertet und im RST-Text **entfernt**. Sphinx/LaTeX nummeriert selbst → vorher „3.2.1 1.1 Wichtige Informationen", jetzt nur noch „3.2.1 Wichtige Informationen". - **Überschriften-Erkennung** nur bei führender PDF-Gliederungsnummer (kein „fett allein"), damit Tabellenzellen nicht fälschlich zu Überschriften werden. - **Bilder positionsbasiert extrahiert und referenziert:** pro Seite werden Text und Bilder nach Y-Position verwoben; jedes Bild wird als `.. figure::` mit korrektem Pfad und – falls vorhanden – der folgenden „Abbildung N: …"-Zeile als Caption eingebaut. (625 figure-Refs, 0 fehlende Bilddateien.) Duplikate werden per MD5 entfernt, Titelseiten-Deko und Vollseiten-Hintergründe herausgefiltert. - **Symbole/Warnzeichen zentral:** Kleine (≤ 260 px), mehrfach vorkommende Bilder (Warndreiecke, Piktogramme) werden per Perceptual-Hash (aHash + Hamming-Distanz ≤ 6) erkannt, **einmal** zentral nach `assets/shared/symbols/symbol_.png` abgelegt und im RST als `.. image::` (12 mm, zentriert) auf die eine Quelle verwiesen – dokumentübergreifend. Auch großformatige Inhaltsbild-Duplikate werden über den aHash zusammengeführt (nur einmal abgelegt, mehrfach referenziert). - **Bild-Routing nach Kapitel-Typ + Dateityp:** Generelle Kapitel (Steuerungs-Funktionsbeschreibung ILS/OMNIFLO/LoadingLoop) → `assets/shared/images/` (wiederverwendbar). Projektbezogene Kapitel (Betrieb/Wartung) → `projekte/fortna/images/`. **Fotos (.jpg) immer** projektspezifisch (`projekte/fortna/images/`), unabhängig vom Kapitel. Ziel-Bildordner werden vor jedem Lauf geleert. - **Bild-Benennung:** PNG mit direkt folgender Bildunterschrift → `_NN.png` (z. B. `Anlage_Uebersicht_01.png`, `Komponentenstatus_Barcode_Leser_01.png`). Fotos → `img_NNN.jpg`, schwarz-weiße Skizzen (> 10 KB) → `sketch_NNN.png`, Rest → `img_NNN.png`. - **Logos gesondert:** Nur wiederkehrende (≥ 3×) breite Grafiken im Seitenrand gelten als Logo (unterscheidet Kopf-/Fußzeilen-Logo von einmaligen breiten Diagrammen) → alle Auflösungen nach `assets/shared/logos/logo__px.png`, **nicht** inline referenziert (Deko). - **Wertlose Fragmente verworfen:** flache (≤ 55 px), breite, schwarz-weiße Schnipsel sind meist gerenderte Kapitelnummern („5.2.6", „3.2.3") und werden gar nicht extrahiert. - **Produktprogramm-Bilder:** `lib/extract_products.py` legt die Bilder der Produktprogramm-PDFs (`data/Produktprogramm/*.pdf`) als generelle Produktbilder nach `assets/shared/images/produktprogramm/{omniflo,ils,cpc,geruest,trolley}` ab. - **Versionierung:** Extrahierte Bildmassen (`assets/shared/images/`, `projekte/fortna/images/`) sind reproduzierbar und via `.gitignore` ausgeschlossen; nur die kuratierten `assets/shared/symbols/` und `assets/shared/logos/` werden versioniert. - **Fragment-„Überschriften" unterdrückt:** Bildlegenden/Tabellenzellen mit führender Nummer („POS", „li.", „re.", „bar, max. 10 bar") werden nicht mehr als Überschrift gesetzt. - **Fließtext zu Absätzen zusammengeführt:** PDF-Zeilenumbrüche werden nicht mehr zu je einem Absatz; zusammenhängende Zeilen bilden einen Absatz, Satzende beendet ihn. - **Aufzählungen als RST-Listen:** einzeln stehende Bullet-Zeichen werden mit der Folgezeile zusammengeführt, in eine Zeile zusammengelaufene Bullets aufgesplittet → `-`-Listenpunkte. - **Änderungshistorie-/Dokumentinfo-Tabellen** am Dokumentanfang werden übersprungen (zerfielen vorher in sinnlose Einzelzellen), ebenso Inhaltsverzeichnis-Seiten und Kopf-/Fußzeilen. ### Behobene Extraktionsprobleme - **Symbolfont-Zeichen** (Wingdings/Symbol Private-Use-Area, z. B. Aufzählungs-Bullet U+F0B7): via `clean_pua()` auf echte Unicode-Zeichen (•, →, ✓) gemappt, restliche PUA-Zeichen entfernt. Vorher erschienen leere Kästchen im PDF. (In `lib/pdf_extract.py`; die Variante in `extract_products.py` bleibt für die Produktprogramm-Extraktion bestehen.) - **Fremd-Altdateien** aus früheren `convert_to_rst.py`-Testläufen (NORD-Getriebe/-Motor im Anhang, alte Risikobewertung/Contents/Konfig/Ersatzteile-Volltexte) wurden entfernt; die betroffenen Kapitel liegen konzeptkonform als Verzeichnisliste vor. ### 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.