# Dokumenten-Rendering & Style-System ## Ueberblick Der **Generation-Service** (`serviceGeneration` / `mainServiceGeneration.py`) wandelt strukturierten JSON-Content in formatierte Dokumente um. Pipeline: **Markdown -> JSON -> Rendered File** (PDF, DOCX, PPTX, XLSX, HTML). Styling wird ueber ein **4-Schichten-Modell** aufgeloest — von generischen Defaults bis zu element-spezifischen Overrides. Keine statischen Theme-Presets; stattdessen AI-getriebene kontextuelle Anpassung. --- ## Style-Resolution-Pipeline ```mermaid flowchart TD Default["DEFAULT_STYLE
(Cursor/VS-Code-Aesthetik)"] --> Resolve["resolveStyle()
deep-merge: defaults + agentStyle"] Resolve --> AI["_enhanceStyleWithAi()
AI Delta basierend auf
Titel, Typ, User-Request"] AI --> Global["Resolved Global Style
(12 Sektionen)"] Global --> Convert["_convertUnifiedStyleToInternal()
Renderer-internes Format"] Convert --> Renderer["Renderer"] Renderer --> PerElement["Per-Element Overrides
z.B. tableStyle pro Tabelle"] PerElement --> Final["Gerendertes Element"] ``` ### Schicht 1: DEFAULT_STYLE (Basis) Datei: `styleDefaults.py`. Neutrale, moderne Basis-Aesthetik inspiriert von Cursor/VS-Code Markdown-Rendering. | Sektion | Schluessel | Beschreibung | |---------|-----------|-------------| | `fonts` | `primary`, `monospace` | Calibri / Consolas | | `colors` | `primary`, `secondary`, `accent`, `background` | GitHub-inspirierte Farbpalette (#24292e, #586069, #0366d6) | | `documentTitle` | `sizePt`, `weight`, `color`, `align`, `spaceBeforePt`, `spaceAfterPt` | Dokumenttitel-Formatierung | | `headings` | `h1`-`h4` mit `sizePt`, `weight`, `color`, `spaceBeforePt`, `spaceAfterPt` | Ueberschriften-Hierarchie | | `paragraph` | `sizePt`, `lineSpacing`, `color`, `align` | Fliesstext | | `table` | `headerBg/Fg`, `headerSizePt`, `bodySizePt`, `rowBandingEven/Odd`, `borderColor`, `borderWidthPt`, `borderStyle`, `bandingEnabled`, `cellPaddingPt` | Tabellen-Styling | | `list` | `bulletChar`, `indentPt`, `sizePt` | Aufzaehlungen | | `image` | `defaultWidthPt`, `maxWidthPt`, `alignment` | Bild-Defaults | | `codeBlock` | `fontSizePt`, `background`, `borderColor` | Code-Bloecke | | `coverPage` | `titleSizePt`, `subtitleSizePt`, `authorSizePt`, `dateSizePt`, `titleColor`, `subtitleColor` | Deckblatt | | `caption` | `sizePt`, `color`, `italic`, `align` | Bild-/Tabellen-Beschriftungen | | `page` | `format`, `marginsPt`, `showPageNumbers`, `headerHeight/footerHeight`, `headerLogo`, `headerText`, `footerText` | Seitenlayout | ### Schicht 2: Agent Explicit Overrides Der Agent kann ein `style`-Objekt in `metadata.style` des JSON-Dokuments mitgeben. `resolveStyle(agentStyle)` macht ein rekursives Deep-Merge: `DEFAULT_STYLE <- agentStyle`. Nur explizit gesetzte Keys werden ueberschrieben. ### Schicht 3: AI Style Enhancement `_enhanceStyleWithAi()` in `mainServiceGeneration.py`: 1. Empfaengt das **vollstaendige** resolved Style-Set als JSON (~920 Bytes) 2. Kontext: Dokumenttitel, Dokumenttyp, User-Request (Auszug) 3. AI liefert ein **Delta-JSON** mit nur den zu aendernden Properties 4. `deepMerge(resolvedStyle, delta)` wendet die Aenderungen an 5. Bei Fehler: graceful fallback auf den unmodifizierten Style Beispiele fuer AI-Anpassungen: - Rechtsschrift: Serif-Fonts, justified Paragraphs - Finanzbericht: konservative Farben, rechtausgerichtete Zahlen-Spalten - Marketing: kraeftige Farben, groessere Abstände ### Schicht 4: Per-Element Overrides JSON-Content-Bloecke koennen element-spezifische Style-Overrides tragen. Aktuell unterstuetzt: - **`tableStyle`** auf Table-Bloecken: `content.tableStyle` wird per deep-merge mit dem globalen `table`-Style zusammengefuehrt. Erlaubt pro Tabelle eigene Banding-Farben, Border-Style, Column-Alignments etc. - **`columnAlignments`** auf Table-Bloecken: Explizite Liste (`["left", "right", "center"]`) pro Spalte. --- ## Tabellen-Rendering-Modell ### Globale Tabellen-Styles Aus `DEFAULT_STYLE["table"]`: | Key | Default | Beschreibung | |-----|---------|-------------| | `headerBg` / `headerFg` | `#f6f8fa` / `#24292e` | Header-Hintergrund und -Textfarbe | | `headerSizePt` / `bodySizePt` | 10 / 10 | Schriftgroessen | | `rowBandingEven` / `rowBandingOdd` | `#f6f8fa` / `#FFFFFF` | Alternierende Zeilenfarben | | `borderColor` / `borderWidthPt` | `#e1e4e8` / 0.5 | Rahmenfarbe und -staerke | | `borderStyle` | `"grid"` | `grid` (Vollraster), `horizontal` (nur horizontale Linien), `none` (kein Rahmen) | | `bandingEnabled` | `true` | Aktiviert/deaktiviert Zeilenbanding | | `cellPaddingPt` | 4 | Zellen-Innenabstand | ### Per-Table Overrides Ein Table-Block im JSON kann ein `tableStyle`-Objekt tragen: ```json { "content_type": "table", "elements": [{ "headers": ["Name", "Betrag", "Datum"], "rows": [...], "tableStyle": { "borderStyle": "horizontal", "bandingEnabled": false, "columnAlignments": ["left", "right", "center"] } }] } ``` Der Renderer mergt: `globalTableStyle <- perTableStyle` (deep-merge). ### Spaltenausrichtung 1. **Explizit:** `tableStyle.columnAlignments` (Array von `"left"` / `"center"` / `"right"`) 2. **Auto-Inferenz** (`_inferColumnAlignments` in BaseRenderer): - Zahlenspalten (>=60% numerisch) -> `right` - Datumsspalten (>=60% Datumsformat) -> `center` - Sonst -> `left` --- ## Renderer-Architektur ### Basisklasse `DocumentRendererBaseTemplate` (ABC) stellt bereit: - `_convertUnifiedStyleToInternal(style)` — Wandelt das 12-Sektionen Unified-Style-Dict in ein flaches internes Format um - `_inferColumnAlignments(headers, rows, tableStyle)` — Spaltenausrichtungs-Heuristik - `_inlineRunsFromContent()` / `_inlineRunsForCell()` / `_inlineRunsForListItem()` — Inline-Run-Normalisierung - `_lazyResolveImageBase64()` — On-Demand Bild-Aufloesung fuer Grossdokumente ### Format-Renderer | Renderer | Bibliothek | Formate | Besonderheiten | |----------|-----------|---------|----------------| | `rendererPdf.py` | ReportLab | PDF | TTF-Font-Registration (`_resolveFontFamily`), Temp-File-Bilder fuer Memory-Effizienz, Emoji-Fallback (NotoEmoji) | | `rendererDocx.py` | python-docx | DOCX | XML-basierte Tabellen-Borders, Word-Styles fuer h1-h4, Inline-Run-Formatting | | `rendererPptx.py` | python-pptx | PPTX | Slide-Layout pro Section, RGBColor-Konvertierung, Shape-basierte Bilder | | `rendererXlsx.py` | openpyxl | XLSX | PatternFill fuer Banding, Side/Border fuer Rahmen, Cell-Anchor fuer Bilder | | `rendererHtml.py` | Jinja2/String | HTML | CSS-Generierung aus Unified Style, Inline-Styles | ### Font-Resolution (PDF) `_resolveFontFamily(fontName)` in rendererPdf.py: 1. Pruefe ob TTF-Datei unter `assets/fonts/` registrierbar ist 2. Registriere bei ReportLab (`pdfmetrics.registerFont`) 3. Fallback-Kette: gewuenschter Font -> Helvetica (ReportLab Core) -> Courier --- ## AI Style Enhancement — Details ### Prompt-Struktur ``` You are a document styling expert. [...] Document title: {docTitle} Document type: {docType} User request (excerpt): {userHint} Current style (full schema): {vollstaendiges resolvedStyle JSON} You may adjust any property: fonts, colors, documentTitle, headings, paragraph, table, list, image, codeBlock, coverPage, caption, page. [...] Return ONLY a valid JSON object. ``` ### Erwartete Antwort Ein JSON-Delta-Objekt mit NUR den zu aendernden Keys: ```json { "fonts": {"primary": "Georgia"}, "paragraph": {"align": "justified"}, "colors": {"primary": "#1a1a2e"} } ``` Leeres `{}` = keine Aenderungen noetig. ### Fehlerbehandlung - Leere Antwort -> Original-Style beibehalten - Ungültiges JSON -> Markdown-Fences strippen, `{` bis `}` extrahieren, nochmal parsen - Parse-Fehler oder Exception -> Warning loggen, Original-Style beibehalten - Operation Type: `DATA_GENERATE` --- ## Design-Entscheidungen | Datum | Entscheidung | Begruendung | |-------|-------------|-------------| | 2026-04-29 | Kein Theme-Katalog, kein Mandate-CI-Konzept | ADR: Agent fuellt generischen Style-Block | | 2026-06-02 | THEME_PRESETS + documentTheme temporaer eingefuehrt | A3-Reconciliation | | 2026-06-03 | THEME_PRESETS + documentTheme entfernt, AI-Enhancement statt Presets | Zurueck zum ADR-Original; AI passt kontextbasiert an | | 2026-06-03 | DEFAULT_STYLE: Cursor/VS-Code-Aesthetik | Moderne, neutrale Basis; GitHub-Farbpalette | | 2026-06-03 | AI bekommt vollstaendiges Style-Set im Prompt | Alle 12 Sektionen muessen anpassbar sein | | 2026-06-03 | Per-Table Overrides via content.tableStyle | Jede Tabelle kann eigene Styles haben | | 2026-06-03 | Auto-Column-Alignment via _inferColumnAlignments | Zahlen rechts, Daten zentriert — ohne AI-Call | --- ## Schluessel-Dateien | Datei | Rolle | |-------|-------| | `serviceGeneration/styleDefaults.py` | `DEFAULT_STYLE`, `resolveStyle()`, `deepMerge()` | | `serviceGeneration/mainServiceGeneration.py` | `renderReport()`, `_enhanceStyleWithAi()` | | `serviceGeneration/renderers/documentRendererBaseTemplate.py` | `BaseRenderer`, `_convertUnifiedStyleToInternal()`, `_inferColumnAlignments()` | | `serviceGeneration/renderers/rendererPdf.py` | PDF via ReportLab | | `serviceGeneration/renderers/rendererDocx.py` | DOCX via python-docx | | `serviceGeneration/renderers/rendererPptx.py` | PPTX via python-pptx | | `serviceGeneration/renderers/rendererXlsx.py` | XLSX via openpyxl | | `serviceGeneration/renderers/rendererHtml.py` | HTML via String/Jinja | | `serviceAgent/coreTools/_mediaTools.py` | `renderDocument` Agent-Tool | --- ## Auch wichtig - **Grossdokumente:** Lazy File-Ref-Bilder (`_lazyResolveImageBase64`) + Temp-File-Bilder fuer PDF vermeiden OOM bei vielen eingebetteten Bildern. Siehe `c-work/4-done/2026-06-po-cleanup-neutralization-docgen.md` (A3/AC15). - **Markdown-Renderer/Text-Renderer** ignorieren `style` (dokumentiert, kein Bug). - **Agent-Tool `renderDocument`:** Akzeptiert optionalen `style`-Parameter im Tool-Schema; kein `documentTheme`-Parameter mehr.