Files
claude-plugins/MEMORY.md
T
2026-02-10 22:26:22 +00:00

5.7 KiB

Doc-Converter Memory

SPRACHE: Alle Antworten auf Deutsch!

WICHTIG: Visuelle Prüfung immer mit Chromium!

chromium --headless --disable-gpu --no-sandbox --screenshot=/tmp/screenshot.png --window-size=1200,3000 "URL"

Topic-Dateien (Details)


3-Phasen-Hybrid-Architektur (2026-02-10)

Kurzfassung: Phase 1 (Strukturerkennung + Crop-Koordinaten via Gemini, 3 Content-Seiten) → crop_page_images() → Phase 2a (TOC/Footer) → Phase 2b (Content mit gecroppten Bildern, KEINE Header/Footer-Referenzbilder). Pre-Content-Seiten werden NICHT an Content-Gemini gesendet.

Gemini-basierte Crop-Erkennung (2026-02-10)

  • Phase 1 sendet 3 Content-Seiten (nicht 2) an Gemini
  • RECOGNITION_PROMPT: "Finde wiederkehrende Elemente auf mind. 2 Seiten am oberen/unteren Rand"
  • Gemini liefert header_bottom_percent und footer_top_percent als physische Crop-Grenzen
  • detect_footer_boundary() wird NICHT mehr für Crop-Override verwendet (nur noch Gemini)
  • crop_page_images() schneidet alle Seitenbilder physisch zu → Gemini sieht NIE Header/Footer
  • Phase 2b Prompts: "Kopf-/Fußzeile bereits entfernt, konvertiere ALLES"

50-Seiten-Testergebnisse (test50_v3, 2026-02-10)

Metrik Vorher (test50) Nachher (test50_v3)
Kosten $0.471 $0.392
visual_layouts 3 1
Footer-Artefakte vorhanden 0

Content-Normalisierung (2026-02-10)

normalize_content_structure(html_content, detected_type="standard") — Steps: 0. Block-Elemente aus <p> befreien (html.parser-Bug-Fix)

  1. Excessive Margins (>30pt, ≥5%) + justify entfernen
  2. Bold <p> mit Sektionsnummern → h2/h3/h4, Heading-Level-Korrektur
  3. Silbentrennung reparieren
  4. Serif-Fonts → Arial
  5. Font-Family auf ALLE Elemente
  6. Gebrochene Absätze zusammenführen
  7. Em-Dash-Listen → disc bullets
  8. Padding von Paragraphen/Headings außerhalb Tabellen entfernen 8b. Hierarchische Einrückung (hängende Einzüge für h2/h3/h4 + Content)
  9. Tabellen-Borders + Backgrounds (Definition-Tables 9b, Category-Tables 9c) 9d. Seitenübergreifende Tabellen zusammenführen (gleiche Spaltenanzahl, keine Überschrift dazwischen)
  10. Wingdings → Unicode ♦
  11. Fehlende CSS-Semikolons reparieren
  12. Doppelte Semikolons bereinigen

Pipeline: strip_invalid_image_refs → strip_toc_from_content → normalize_content_structure → normalize_font_sizes → make_content_left_aligned

Font-Sizes: h1=16pt, h2=12pt, h3/h4=11pt, p/li=11pt, footer=8pt

Tabellen-Farben: detected_type="va" → #E6B8B7, detected_type="standard" → #B8CCE4

Gemini-Kontext: Erste Tabellen-Hintergrundfarbe wird an Folgeseiten-Prompts übergeben (±5% Toleranz)

Dokumenttitel: h1 aus Titelseite (text_by_page[1]) + Untertitel 11pt, KEINE Bilder. Ausnahme: "1. Inhaltsverzeichnis" im TOC → kein h1, Titel wird h2 "1. ".


Bekannte Pitfalls

KRITISCH: soup.find('body') bei HTML-Fragmenten

merge_chunked_html() liefert HTML OHNE <body> Tag! Fix: body = soup.find('body') or soup — dann funktioniert body.children auch ohne <body>.

<tbody> bei Tabellen (Step 9)

table.find_all('tr', recursive=False) gibt 0 zurück wenn <tbody> existiert! Fix: tbody = table.find('tbody', recursive=False); row_container = tbody if tbody else table

strip_toc_from_content — Absolute Positioning

Rule 5: NICHT .decompose()! Nur CSS-Properties position: absolute, top, left, right, bottom strippen.

CSS-Semikolons (Step 11)

Gemini generiert text-align: left font-weight: bold (fehlt ;). Regex erkennt CSS-Properties ohne vorangehendes ;.

KRITISCH: html.parser nestet Block-Elemente in <p> (2026-02-10)

BS4 html.parser schließt <p> NICHT automatisch vor <div>!

<p>text<div><img src="visual_layout_43.png"></div></p>
→ BS4 parsed als: <p> enthält <div> als Kind!

Effekt: Step 6 current.clear() zerstört das nested <div><img>. Fix: Step 0 extrahiert Block-Elemente aus <p> Tags:

block_tags = {'div', 'table', 'h1',...,'blockquote'}
for p_tag in soup.find_all('p'):
    block_children = [c for c in p_tag.children if c.name in block_tags]
    for block in block_children:
        block.extract(); p_tag.insert_after(block)

Zusätzlich: Safety-Guards in Step 3 + Step 6:

if current.find(['div', 'table', 'img'], recursive=False): continue

BeautifulSoup decomposed Elements

Fix: if hasattr(el, 'decomposed') and el.decomposed or el.parent is None: continue

Isoliertes Post-Processing Testen

docker exec n8n-doc-converter python3 -c "
import sys; sys.path.insert(0, '/app')
from server import normalize_content_structure
html = open('/data/bsp/7787ddc0_test15/content.html').read()
result = normalize_content_structure(html, detected_type='standard')
open('/data/bsp/7787ddc0_test15/content.html', 'w').write(result)
"

Spart ~$0.17 pro Test.

Step 8b: Hierarchische Einrückung

HEADING_INDENT = {
  'h2': margin-left:0, padding-left:10pt, text-indent:-10pt
  'h3': margin-left:10pt, padding-left:12pt, text-indent:-12pt
  'h4': margin-left:22pt, padding-left:14pt, text-indent:-14pt
}
CONTENT_MARGIN = { 'h2':10pt, 'h3':22pt, 'h4':36pt }

Iteriert über direkte Children von body/soup, trackt current_heading_level. PITFALL: collect_elements() muss in Wrapper-<div>s absteigen (ohne class), da merge_chunked_html() + Titel-Insertion Content in <div> wrappen kann.