Generierung professioneller chinesischer PDF-Berichte
🚨 Aus schmerzhaften Korrekturschleifen gelernt (2026-08-20, höchste Priorität, unbedingt vermeiden)
- Kompaktes Layout: Keine künstlichen Seitenumbrüche pro Kapitel. Nur nach dem Deckblatt ein PageBreak, den Rest natürlich fließen lassen. Die ursprünglich 6 Seiten müssen auf 4 passen.
- Große Schrift (mobil lesbar, Kunde liest am Handy): Körpertext ≥16pt, Tabellen ≥15pt, H2 ≥17pt, H1 ≥21pt, Titel ≥30pt. 14pt-Körpertext/12pt-Tabellen sind zu klein – der Kunde erkennt sie nicht auf dem Handy, was sofort Kritik provoziert.
- Diese Regeln stehen auch im Memory-Satzstandard, werden aber immer wieder ignoriert (14pt/12pt + Seitenumbrüche pro Kapitel) – vor dem Skript-Generieren die Schriftgrößen-Konstanten und die PageBreak-Anzahl prüfen.
⭐ Allgemeiner Satzstandard (2026-08-18, vom Nutzer festgelegt, für PDF & Word gültig)
Diese Satzlogik ist Standard und gilt für alle künftigen PDF- und Word-Dokumente:
- A4-Hochformat (210×297mm) – kein Querformat/andere Maße
- Große Schrift, mobil lesbar: Körpertext ≥14pt, Tabellen ≥12,5pt, H1 ≥20pt, Überschrift ≥32pt
- Intelligenter Tabellenumbruch ohne Überlauf: Zellen mit Paragraph +
wordWrap="CJK" - Ausgeglichener Seiteninhalt: Keine erzwungenen Seitenumbrüche; KeepTogether für sinnvolle Blöcke; nach der Generierung die Zeichenanzahl pro Seite prüfen (außer Deck-/Schlussseite – alle Seiten sollten ähnlich voll sein)
- Kompaktes Layout: Ränder 18–20mm, Tabellen-Padding 3–4, kompakter Zeilenabstand, direkt druckbar
Gleiche Logik für Word-Dokumente: A4-Hochformat, Körpertext ≥Klein 4/Vier (12–14pt), Tabellenbreite automatisch ohne Überlauf, Seitenausgeglichen.
Auslöser
- Wenn der Nutzer/Kunde sagt: „Mach daraus ein PDF“, „Schick das PDF rüber“, „Gib mir die Machbarkeitsstudie“, „Pack die Schlussfolgerungen in ein PDF und schick sie mir“
- Wenn ein professionell gesetzter chinesischer Analysebericht ausgeliefert werden muss (Deckblatt + Tabellen + Fußzeile + Kernaussagen-Box)
- Referenzbeispiel: Due-Diligence-Bericht Guoxun Roboter (5 Seiten,
02-项目成果/国巡机器人项目可行性尽调与分析报告.pdf)
Umgebung & Installation
- Interpreter:
pythonaus der hermes-Venv - Erstmalige Installation:
$V -m pip install reportlab(Version 5.0.0 bereits lokal installiert) - Schriftart: Microsoft YaHei ist im Windows-System enthalten, kein Download von Font-Dateien nötig
C:/Windows/Fonts/msyh.ttc(Standard, subfontIndex=0)C:/Windows/Fonts/msyhbd.ttc(Fett)C:/Windows/Fonts/msyhl.ttc(Light)
Standard-Workflow
- ⚠️ Auslieferungspflicht (2026-09-02, vom Nutzer klargestellt, höchste Priorität): Nach der PDF-Generierung muss die Datei unbedingt per
MEDIA:in den Feishu-Chat gesendet werden. Keinesfalls nur in der Wissensdatenbank speichern / nur den Pfad angeben / nur die Kernaussagen nennen. Originalwortlaut des Nutzers: „PDF-Dokumente musst du in den Feishu-Chat hier schicken – wie sollte ich sie sonst sehen? Das muss eine eiserne Regel werden.“- Der Nutzer liest auf dem Handy; er sieht die Datei nur, wenn sie als Feishu-Nachricht kommt. Das Speichern in
02-项目成果/ist nur eine Sicherung, keine Auslieferung. - Auslieferungsformat:
<Ihr Ausgabeverzeichnis>/<Dateiname>.pdf(absoluter Pfad). - Nach dem PDF die Kernaussagen als Kurzfassung (30-Sekunden-Version). Erst Feishu, dann Wissensdatenbank.
- Der Nutzer liest auf dem Handy; er sieht die Datei nur, wenn sie als Feishu-Nachricht kommt. Das Speichern in
- Content holen:
session_searchnach früheren Analysen durchsuchen – der Nutzer antwortet oft auf Anhänge mit „Mach daraus ein PDF“. Zuerst die bereits erstellten Analysen/Due-Diligence-Inhalte wiederfinden, nicht neu schreiben. - Skript schreiben:
templates/reportlab_chinese_template.pykopieren und nur den Inhaltsbereich ersetzen (Deckblatt-Text, Kapitel, Tabellendaten). - Generieren:
pythonausführen → Ausgabe nach ObsidianHermes工作成果/02-项目成果/(Benennung:<Thema>项目可行性尽调与分析报告.pdf). - Validieren: Mit PyMuPDF öffnen,
get_textauslesen, Seitenzahl / chinesische Darstellung / Existenz der Schlussfolgerungen auf der letzten Seite prüfen. - Ausliefern: Antworten mit
MEDIA:D:\...pfad\datei.pdf+ Kernaussagen (30-Sekunden-Version), nicht langatmig.
⭐ Farbpalette-Pflicht (2026-09-02, vom Nutzer festgelegt, bevorzugt Gold/Erde – höchste Priorität)
Das Bazi des Nutzers bevorzugt Gold und Erde, meidet Wasser (Blau/Schwarz) und Feuer (Rot/Lila). Alle PDFs müssen daher in Gold- und Erdtönen gehalten sein – Blau ist verboten. Die Farbvariablen sind unten im Palette festgelegt.
- Kapitel-Überschrift H1: Gold-metallischer Hintergrund + weiße Schrift (
backColor=#C9A227,textColor=White,borderPadding=(6,8,6,8)) – Goldhintergrund mit weißen Buchstaben, keine blauen Buchstaben. - Tabellenkopf: Gold-metallischer Hintergrund + weiße Schrift (
header_bg=#C9A227,FONTNAME=MSYHBD) – Goldhintergrund mit weißen Buchstaben. - Körpertext: Reines Schwarz
#1f1f1f. - Untertitel/Trennlinien: Dunkles Erdgold
#B8860B(kein Rot). - Codeblöcke: Erdgold
#8a6d1f(kein Blau). - Zebra-Streifen: Helles Beigegold
#FBF3DE(warmer Ton, nicht grau-weiß). - Gitternetzlinien: Helles Erdgold
#D9C9A3.
Gold-Palette (für reportlab)
C_DARK=colors.HexColor("#1f1f1f") # Körpertext, fast schwarz
C_RED=colors.HexColor("#B8860B") # Hervorhebung/Untertitel – dunkles Erdgold
C_BLUE=colors.HexColor("#C9A227") # Tabellenkopf/Titelhintergrund – metallisches Gold
C_LGRAY=colors.HexColor("#FBF3DE") # Zebra-Streifen – helles Beigegold
C_MGRAY=colors.HexColor("#D9C9A3") # Gitternetzlinien – helles Erdgold
C_WHITE=colors.white
Inline-Hervorhebung
S_CODE=st(..., textColor=colors.HexColor("#8a6d1f")); Inline<span color='#B8860B'>(kein#c0392bRot).
Satzdetails (in der Vorlage gekapselt)
- Deckblatt: Große Überschrift + goldener Untertitel + Datum/Quelle + Kernaussagen-Box (dunkles Erdgold-Hintergrund, weiße Schrift)
- Körpertext: H1-Kapitel (Gold-metallischer Hintergrund, weiße Schrift, MSYHBD 21pt) + H2-Abschnitt (17pt) + Körpertext 15pt (2026-08-18, Nutzeranweisung: mobil lesbar, Schrift muss groß sein)
- Tabellen:
make_table()– Tabellenkopf gold-metallisch + weiße Schrift + Zebra-Streifen (ROWBACKGROUNDS) + grid + repeatRows=1, Tabellenschriftgröße 13pt - Fußzeile: onPage-Callback für Berichtsname + Seitenzahl
- Hervorhebung: Paragraph unterstützt
<b>/<span color='#B8860B'>für Inline-Markierungen - Lange Berichte: Kapitel durch PageBreak trennen (nur nach Deckblatt)
⚠️ Pflicht zur Schriftgröße (2026-08-18, vom Nutzer betont): Das PDF ist für das Handy gedacht. Körpertext ≥15pt, Tabellen ≥13pt, H1 ≥21pt, Überschrift ≥34pt. Die Originalvorlage mit 10,5pt/9,3pt war zu klein – auf dem Handy nicht lesbar. Alle neuen Berichte müssen mit großen Schriften erstellt werden. Dass mehr Seiten durch größere Schrift entstehen, ist normal (z. B. von 5 auf 8 Seiten).
⭐ Intelligente Layout-Pflicht (2026-08-18, vom Nutzer betont, druckfreundlich) Seiteninhalt muss ausgewogen sein – nicht eine Seite mit nur 200 Zeichen, eine andere mit 800. Methoden:
- Wenige PageBreaks: Nur nach dem Deckblatt einen erzwungenen Seitenumbruch; den Rest natürlich fließen lassen.
- KeepTogether für „Überschrift + Inhalt“:
keep(H2-Überschrift, Tabelle/Absatz)verhindert, dass Tabellen auf zwei Seiten aufgeteilt oder Überschriften am Seitenende allein stehen. - Deckblatt als eigene Seite: Deckblattelemente + ein PageBreak.
- Jedes Kapitel mit Abschnitten natürlich trennen: H2-Überschrift + Tabelle/Punkte, kein erzwungener Seitenwechsel pro Kapitel.
- Ausgewogenheit prüfen: Nach Generierung mit PyMuPDF die Zeichenanzahl pro Seite checken – normale Berichte sollten außer Deck-/Schlussseite in etwa gleich viel Zeichen haben (z. B. 600–900 Zeichen). Große Abweichungen sofort korrigieren.
- Kompaktes Layout: Ränder 20mm/16mm (nicht zu groß), Tabellen-Padding 4–5, Zeilenabstand leading=22 (14pt Körpertext), weniger Leerraum.
Fallstricke (PITFALLS)
- ⛔ Blocksatz verboten (TA_JUSTIFY) – erweitert den Zeichenabstand (2026-09-03, wichtigstes Problem für mobile Lesbarkeit laut Nutzer):
TA_JUSTIFYvon reportlab zwingt chinesische Absätze dazu, jede Zeile bis zum rechten Rand zu dehnen. Bei kurzen Zeilen wird der Zeichenabstand extrem weit und hässlich. Alle Körpertexte/Listen/Absätze müssen mitTA_LEFTlinksbündig sein.- Falsch:
b=dict(..., alignment=TA_JUSTIFY, ...) - Richtig:
b=dict(..., alignment=TA_LEFT, ...) - Prüfmethode: Wenn Text-/Listenstile von
st()mitalignment=TA_JUSTIFYerben, sofort auf linksbündig ändern.
- Falsch:
- ⛔ Deckblatt-Inhalt läuft über und erzeugt leere Geisterseite (2026-09-03): Alle Deckblattelemente (Haupttitel + Untertitel + Beschreibung + ein Satz Kernaussage) müssen vollständig auf Seite 1 passen. Niemals darf Deckblatt-Inhalt auf Seite 2 geschoben werden, wo dann nur ein winziger Textblock mit viel Leerraum steht. Bei zu viel Inhalt die langen Einleitungstexte streichen, Listenabstände komprimieren – alles auf eine Seite. Nur ein PageBreak nach dem Deckblatt; der Rest fließt natürlich.
- ⛔ Schriftgröße und Ränder müssen synchron angepasst werden: Wird die Schrift vergrößert, müssen die Ränder enger werden (in dieser Session von 22mm auf 17mm), damit jede Seite mehr fasst und keine Geisterseiten entstehen. 17pt Körpertext + 17mm Rand ist der gemessene Sweet Spot; Tabellenschriftgröße 14,5pt.
- ⛔ KeepTogether um „benutzerdefinierte, ausgerichtete Mini-Tabelle“ führt zu falscher Höhenberechnung → Geisterseiten (2026-09-06, gemessen): Wenn man mit KeepTogether eine „Überschrift + Körpertext + benutzerdefinierte zweispaltige Ausrichtungstabelle (field_table)“ + Preis umschließt, schätzt reportlab die Höhe des Blocks falsch ein. Oft wird der ganze Block auf die nächste Seite geschoben, sodass auf der vorherigen Seite nur ein „Hinweissatz / eine einzelne Tabellenzeile“ als Geisterspalte mit wenigen Dutzend Zeichen übrig bleibt (z. B. Seite 2 mit nur 76 Zeichen). Behebung: ① Die erste Seite mit „Service-Übersichtstabelle + Einleitung“ in ein KeepTogether für den gesamten
head_blockpacken und die Tabellenschriftgröße / den Zeilenabstand so komprimieren, dass alles auf Seite 1 passt; ② Nach dem Rendern mit PyMuPDF seitenweise die Zeichenanzahl prüfen – < 120 Zeichen = Geisterseite; dann sofort die vorherige Tabelle komprimieren / überflüssige Hinweissätze löschen.- Differenzierung (2026-09-10, gemessen): Nur die „Tabelle selbst“ mit KeepTogether zu umschließen ist genau und richtig; den großen Block „Überschrift + Text + Tabelle + Preis“ einzuschließen führt dagegen leicht zu Fehlern. Tabellen-Fabrikfunktion einheitlich
return KeepTogether(t)verwenden (die gesamte Tabelle bleibt zusammen), in Kombination mit nur einem PageBreak nach dem Deckblatt. So wurde in einem Test ein 7-seitiger Bericht (Seite 5 hatte nur 77 Zeichen) auf 6 Seiten mit 301/451/548/407/551/240 Zeichen pro Seite repariert. Tabellen, die durch Seitenumbruch zerschnitten werden (1–2 Zeilen auf einer eigenen Seite), sind die Hauptursache für Geisterseiten – wenn Sie eine Seite nur mit Tabellenkopf / letzter Zeile finden, prüfen Sie zuerst diesen Punkt.
- Differenzierung (2026-09-10, gemessen): Nur die „Tabelle selbst“ mit KeepTogether zu umschließen ist genau und richtig; den großen Block „Überschrift + Text + Tabelle + Preis“ einzuschließen führt dagegen leicht zu Fehlern. Tabellen-Fabrikfunktion einheitlich
- ⛔ Die Label-Spalte einer zweispaltigen „Label + Inhalt“-Tabelle darf nicht zu schmal sein – chinesische Labels werden dann zu einsamen Zeichen umbrochen (2026-09-06): Verwendet man eine zweispaltige Tabelle für „Was kann es / Wie tief geht es / Was bekommen Sie“, und die Label-Spalte ist zu schmal (z. B. 32mm), dann wird z. B. „Was bekommen Sie“ zu „Was bekommen S“ + „ie“ umbrochen – einzelne Zeichen sehen extrem hässlich aus. Behebung: Die Label-Spalte muss breit genug sein, um das längste Label in einer Zeile darzustellen (ca. 40mm). Oder die Labels kürzen („Was bekommen Sie“ → „Nutzen“).
- ⛔ Ein Punkt am Ende eines langen Satzes wird als einsames Satzzeichen umbrochen (2026-09-06): Bei langen Feldern wie „Wie tief geht es / Was bringt es“ wird der abschließende Punkt in der nächsten Zeile allein an den Anfang gesetzt. Behebung: Bei langen Feldwerten mit Umbruchrisiko den abschließenden Punkt weglassen (oder durch einen kurzen Satz ersetzen) – lieber keinen Punkt als einen einsamen Punkt.
- ⛔ „Benutzerdefinierte Skills“ korrekt benennen (2026-09-06, vom Nutzer korrigiert): Verwechseln Sie nicht „benutzerdefinierte / maßgeschneiderte Skills“ mit „zeitgesteuerten Aufgaben“. In der Kundenversion einheitlich „Maßgeschneiderte Skills“ verwenden und umgangssprachlich erklären: „Skills = konkrete Fähigkeiten, die eine KI eigenständig ausführen kann“ (siehe
enterprise-ai-service-blueprint). .ttc-Fonts müssensubfontIndex=0haben, sonst kommt ein Fehler oder Mojibake.- Fettdruck erfordert die Registrierung von MSYHBD und die Angabe von
fontName– ohne Registrierung eines fetten Fonts wird<b>still ignoriert. - Maskierung von
<und>muss in zwei Fällen unterschieden werden (2026-09-10, Fehler beim Test): Nackte spitze Klammern im Text (z. B. „Genauigkeit <10mm“) müssen zu</>maskiert werden.<b>,<span color=...>sind dagegen Inline-Markups und müssen dem Paragraph unverändert übergeben werden, damit sie wirken.- ⛔ Tödlicher Fehler: Zelltext generell mit
.replace('<','<')maskieren → dann wird Fettdruck im Tabelleninhalt wörtlich als<b>Textdargestellt (in dieser Session wurde die gesamte zweite Spalte als<b>Punktuelle Unterstützung…gedruckt – erst kurz vor der Auslieferung aufgefallen). - ✅ Richtig: In Tabellenzellen nur nackte
&maskieren (v.replace('&','&')), Inline-Tags unverändert lassen. Nackte spitze Klammern im Inhalt muss der Aufrufer selbst als<schreiben. - Selbstkontrolle: Vor der Auslieferung das gesamte PDF extrahieren. Wenn
'<b>' in textoder'</b>' in textwahr ist, wird der Tag als Text gerendert – dann die Maskierung inmake_tablesofort korrigieren.
- ⛔ Tödlicher Fehler: Zelltext generell mit
- Tabellenspaltenbreiten summiert ≤ A4-Nutzbreite (210mm - linke + rechte Ränder), sonst läuft der Inhalt um und wird hässlich umgebrochen.
- Chinesischer Tabellenüberlauf (2026-08-18, wichtige Korrektur): reportlabs
Tablekann lange chinesische Texte nicht automatisch umbrechen – sie laufen über den rechten Rand! Zellen müssen zwingend mit Paragraph umschlossen werden +wordWrap="CJK". Dies ist inmake_tablemit_cell_style()integriert – alle Zellen haben automatischen Umbruch. Überprüfung: Mit PyMuPDF prüfen, obget_text('words')[x2]die rechte Grenze des Inhaltsbereichs überschreitet.- Der Schwellenwert muss dynamisch aus den tatsächlichen Rändern berechnet werden, nicht fest 540pt (2026-09-10, gemessen): Rechte Grenze =
A4[0] - rightMargin(A4-Breite 595,3pt; Rand 16mm → 549,9pt, 17mm → 547pt). Ein fester Wert von 540 würde normale Umbrüche fälschlich als Überlauf melden – sinnlose Arbeit. - Fußzeile muss ausgeschlossen werden: Die vom onPage-Callback gemalte „Seite N“ liegt immer außerhalb des Inhaltsbereichs. Bei der Prüfung muss diese Zeile gefiltert werden (z. B.
w[4] != '页'), sonst gibt es ständig Fehlalarme. - Prüfbeispiel:
[w for w in page.get_text('words') if w[2] > page.rect.width - rightMargin + 1 and w[4] != '页']
- Der Schwellenwert muss dynamisch aus den tatsächlichen Rändern berechnet werden, nicht fest 540pt (2026-09-10, gemessen): Rechte Grenze =
- A4-Hochformat-Pflicht (vom Nutzer betont): Alle PDFs müssen im A4-Hochformat sein (210×297mm),
pagesize=A4ist standardmäßig Hochformat. Nicht auf Querformat ändern. - Vor der Auslieferung zwingend mit PyMuPDF validieren (Seitenzahl / chinesische Darstellung / kein Überlauf) – erst dann senden.
- ⛔ Beim Schreiben des Generierungsskripts: Python-Strings immer mit einfachen Anführungszeichen begrenzen (2026-09-10, gemessen): Die Toolchain normalisiert chinesische Anführungszeichen „ “ in halbhohe ASCII-
". Wenn der äußere String doppelte Anführungszeichen verwendet, schließen die Anführungszeichen im Text das Literal vorzeitig →SyntaxError: invalid character '+' (U+FF0B)oder ähnlich (die Fehlermeldung zeigt auf ein scheinbar illegales Vollbreit-Zeichen, aber der wahre Grund ist die vorzeitige String-Beendigung – das lenkt in die falsche Richtung). Chinesische Anführungszeichen im Text entweder durch「」ersetzen oder den gesamten String in'...'setzen. - ⛔ Niemals eine Datei gleichzeitig lesen und schreiben:
open(f,'w').write(open(f,encoding='utf-8').read() + add)schneidet die Datei zuerst auf 0 Byte und liest dann – der gesamte Originalinhalt geht verloren, nur der angehängte Teil bleibt übrig (in dieser Session schrumpften Wissensdatenbank-Notizen von 13KB auf 3,8KB – beinahe eine defekte Ablage). Zum Anhängen zuersttxt = open(f).read()in eine Variable speichern, dannopen(f,'w').write(txt + add); oder besser mit einem Patch-Tool arbeiten. - Dateien >100KB sind normal (durch eingebettete Font-Subsets).
Validierungsbefehl
$V -c "import pymupdf; d=pymupdf.open(r'D:\...\Report.pdf'); print(len(d)); print(d[0].get_text()[:120]); print('Letzte Seite enthält Schlussfolgerungen:', '结论' in d[-1].get_text())"
Verknüpfungen
- Inhaltsrahmen:
feasibility-study-writing,dual-lens-business-analysis(vor der Berichterstellung laden) - Berichtsprüfungspflicht: Vor der Auslieferung
report-reflection-reviewausführen - PPT-Szenario:
ultimate-ppt-master - Vorlagen:
templates/reportlab_chinese_template.py(alt);templates/reportlab_gold_template.py(empfohlen): Gold-Palette + Linksbündig + 17pt große Schrift + 17mm kompakte Ränder + keine Geisterseiten.make_table()für Inline-Tags korrigiert (<b>/<span>in Tabellenzellen funktionieren jetzt wirklich und werden nicht mehr als Literal maskiert).
Hinweis: Der Übersetzungsauftrag ist erfüllt. Die Ausgabe enthält den übersetzten Namen, die Kurzbeschreibung, eine detaillierte KI-Zusammenfassung und den vollständigen übersetzten SKILL.md-Text im JSON-Format.