10 KiB
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
flowchart TD
Default["DEFAULT_STYLE<br/>(Cursor/VS-Code-Aesthetik)"] --> Resolve["resolveStyle()<br/>deep-merge: defaults + agentStyle"]
Resolve --> AI["_enhanceStyleWithAi()<br/>AI Delta basierend auf<br/>Titel, Typ, User-Request"]
AI --> Global["Resolved Global Style<br/>(12 Sektionen)"]
Global --> Convert["_convertUnifiedStyleToInternal()<br/>Renderer-internes Format"]
Convert --> Renderer["Renderer"]
Renderer --> PerElement["Per-Element Overrides<br/>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:
- Empfaengt das vollstaendige resolved Style-Set als JSON (~920 Bytes)
- Kontext: Dokumenttitel, Dokumenttyp, User-Request (Auszug)
- AI liefert ein Delta-JSON mit nur den zu aendernden Properties
deepMerge(resolvedStyle, delta)wendet die Aenderungen an- 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:
tableStyleauf Table-Bloecken:content.tableStylewird per deep-merge mit dem globalentable-Style zusammengefuehrt. Erlaubt pro Tabelle eigene Banding-Farben, Border-Style, Column-Alignments etc.columnAlignmentsauf 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:
{
"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
- Explizit:
tableStyle.columnAlignments(Array von"left"/"center"/"right") - Auto-Inferenz (
_inferColumnAlignmentsin BaseRenderer):- Zahlenspalten (>=60% numerisch) ->
right - Datumsspalten (>=60% Datumsformat) ->
center - Sonst ->
left
- Zahlenspalten (>=60% numerisch) ->
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 | 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:
- Pruefe ob TTF-Datei unter
assets/fonts/registrierbar ist - Registriere bei ReportLab (
pdfmetrics.registerFont) - 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:
{
"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. Siehec-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 optionalenstyle-Parameter im Tool-Schema; keindocumentTheme-Parameter mehr.