fix: saubere PDF-Extraktion der Fortna-Anleitungen (lib/pdf_extract.py)
Neues Modul lib/pdf_extract.py fuer die Volltext-Konvertierung der 5 Hauptanleitungen, behebt die Qualitaetsprobleme der ersten Version: - Doppelte Nummerierung entfernt: PDF-Gliederungsnummer wird nur fuer die Ueberschriften-Ebene ausgewertet, im RST-Text weggelassen (Sphinx nummeriert) - Bilder positionsbasiert (bbox) extrahiert und als .. figure:: mit Caption an der richtigen Textstelle referenziert (625 Refs, 0 fehlende Bilder) - Fliesstext zu Absaetzen zusammengefuehrt statt je PDF-Zeile ein Absatz - Aufzaehlungen als RST-Listen (Bullet-only-Zeilen mit Folgezeile gemergt, zusammengelaufene Bullets aufgesplittet) - Aenderungshistorie-/Dokumentinfo-Tabellen und TOC-Seiten uebersprungen - Symbolfont-Zeichen (PUA) auf Unicode gemappt fortna_convert_chapters.py: nutzt pdf_extract statt extract_products, lesbare Dokumenttitel je Kapitel, Verzeichnislisten fuellen Kapitel ohne DE-Quelle mit vorhandenen Fremdsprachen (Ersatzteilliste EN). build_index.py / conf.py: Fremd-Altdateien aus dem Build ausgeschlossen. Alte Test-.rst aus fruehen convert_to_rst.py-Laeufen entfernt. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
e7aa3b4e4b
commit
c912b1e9d5
@@ -34,8 +34,9 @@ import sys
|
||||
from collections import defaultdict
|
||||
from pathlib import Path
|
||||
|
||||
# extract_products stellt die robuste PDF-Extraktion bereit (gleiches lib/-Verzeichnis)
|
||||
import extract_products as ep
|
||||
# pdf_extract stellt die positionsbasierte Text+Bild-Extraktion bereit
|
||||
# (verwebt Text und Bilder, entfernt PDF-Ueberschriftennummern).
|
||||
import pdf_extract
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@@ -71,6 +72,16 @@ def load_inventory(path: Path) -> dict:
|
||||
return json.load(f)
|
||||
|
||||
|
||||
# Lesbarer Dokumenttitel je Zielkapitel (statt PDF-Dateiname als Ueberschrift).
|
||||
CHAPTER_DOC_TITLE = {
|
||||
"04_betrieb/betriebsanleitung": "Betriebsanleitung",
|
||||
"05_wartung/wartungsanleitung": "Wartungsanleitung",
|
||||
"06_steuerung/ils": "Funktionsbeschreibung Steuerung ILS",
|
||||
"06_steuerung/omniflo": "Funktionsbeschreibung Steuerung OMNIFLO",
|
||||
"06_steuerung/loading_loop": "Funktionsbeschreibung Steuerung Loading Loop",
|
||||
}
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# action="convert": Volltext + Bilder
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -104,14 +115,13 @@ def convert_manual(item: dict, source_root: Path, chapters_dir: Path,
|
||||
for old in chapter_dir.glob("*.de.rst"):
|
||||
old.unlink()
|
||||
|
||||
# Bilder extrahieren (extract_products entfernt kleine Icons < 5KB automatisch)
|
||||
img_count = ep.extract_images(src_pdf, img_dir)
|
||||
dup = ep.dedup_images(img_dir)
|
||||
log.info(" %d Bilder (%d Duplikate entfernt)", img_count, dup)
|
||||
|
||||
# Text nach RST extrahieren (positionsbasiert, Kopf-/Fusszeilen gefiltert)
|
||||
blocks = ep.extract_text_to_rst(src_pdf, rst_path)
|
||||
log.info(" %d Textbloecke -> %s", blocks, rst_path.name)
|
||||
# Text + Bilder positionsbasiert extrahieren (verwoben in Lesereihenfolge,
|
||||
# PDF-Ueberschriftennummern entfernt, Bilder als .. figure:: referenziert).
|
||||
doc_title = CHAPTER_DOC_TITLE.get(item["chapter"], slugify(item["filename"]))
|
||||
blocks, img_count = pdf_extract.extract_manual(src_pdf, rst_path, img_dir,
|
||||
title=doc_title)
|
||||
log.info(" %d Textbloecke, %d Bilder (referenziert) -> %s",
|
||||
blocks, img_count, rst_path.name)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -254,7 +264,7 @@ def main() -> None:
|
||||
|
||||
items = [i for i in inv["items"] if i["lang"] == args.lang and i["chapter"]]
|
||||
|
||||
# 1. Volltext-Konvertierung
|
||||
# 1. Volltext-Konvertierung (nur Zielsprache)
|
||||
if args.only in (None, "convert"):
|
||||
conv = [i for i in items if i["action"] == "convert"]
|
||||
log.info("--- %d Hauptanleitungen konvertieren ---", len(conv))
|
||||
@@ -263,7 +273,14 @@ def main() -> None:
|
||||
|
||||
# 2. Verzeichnislisten
|
||||
if args.only in (None, "list"):
|
||||
list_items = [i for i in items if i["action"] == "list"]
|
||||
# Zielsprache bevorzugen; Kapitel, die in der Zielsprache KEINE list-Datei
|
||||
# haben (z.B. Ersatzteilliste nur EN), mit den vorhandenen Fremdsprachen
|
||||
# auffuellen, damit das Kapitel nicht leer bleibt.
|
||||
all_list = [i for i in inv["items"]
|
||||
if i["chapter"] and i["action"] == "list"]
|
||||
chapters_with_lang = {i["chapter"] for i in all_list if i["lang"] == args.lang}
|
||||
list_items = [i for i in all_list
|
||||
if i["lang"] == args.lang or i["chapter"] not in chapters_with_lang]
|
||||
by_chapter: dict[str, list[dict]] = defaultdict(list)
|
||||
for it in list_items:
|
||||
by_chapter[it["chapter"]].append(it)
|
||||
|
||||
Reference in New Issue
Block a user