中文專業PDF報告生成
🚨 用戶兩次糾正的修痛教訓(2026-08-20,最高優先級,禁止再犯)
- 緊凑排版:嚴禁「一點點內容就一頁」。禁止每個章節加 PageBreak 撐頁數──只在封面後加一個 PageBreak,正文讓它自然流動。之前6頁的內容壓到4頁才對。
- 大字號(手機可讀,客戶在手機看):正文≥16pt、表格≥15pt、H2≥17pt、H1≥21pt、標題≥30pt。14pt正文/12pt表格太小,客戶手機看不清,用戶會當場批評。
- 這兩條在 memory 排版標準裡也寫著,但執行時仍會偷懶用 14pt/12pt + 每章分頁──生成腳本前必須自查字號常量和 PageBreak 數量。
⭐ 全軍排版標準(2026-08-18 用戶欽定,PDF/Word 通用)
這套排版邏輯是標準,以後所有 PDF 和 Word 文檔都參照執行:
- A4豎排(210×297mm)──不用橫排/其他尺寸
- 大字號,手機可讀:正文≥14pt、表格≥12.5pt、H1≥20pt、標題≥32pt
- 表格智能換行不溢出:單元格用 Paragraph + wordWrap="CJK"
- 頁面內容均衡:不用強制分頁,KeepTogether 智能分塊,生成後檢查每頁字符數(除封面/收尾頁外,各頁應均衡)
- 排版緊凑:邊距 18-20mm、表格 padding 3-4、行距緊凑,直接列印可用
Word 文檔同邏輯:A4豎排、正文≥小四/四號(12-14pt)、表格列寬自適應不溢出、頁面均衡。
觸發條件
- 用戶/客戶要求「把結論做成PDF」、「發PDF上來」、「可研給我」、「結論做出來發我」
- 需要交付專業排版的中文分析報告(封面 + 表格 + 頁腳 + 核心結論框)
- 參考實例:國巡機器人盡調報告(5頁,02-項目成果/國巡機器人項目可行性盡調與分析報告.pdf)
環境與安裝
- 用 hermes venv 解釋器:
python - 首次安裝:
$V -m pip install reportlab(本機已裝 5.0.0) - 字體:Windows 系統自帶微軟雅黑,無需下載字體文件
C:/Windows/Fonts/msyh.ttc(常規,subfontIndex=0)C:/Windows/Fonts/msyhbd.ttc(粗體)C:/Windows/Fonts/msyhl.ttc(細體)
標準工作流
- ⚠️ 交付鐵律(2026-09-02 用戶明示,最高優先級):PDF 生成後必須
MEDIA:發到飛書聊天框,絕不能只存知識庫 / 只給路徑 / 只發要點。用戶原話:「PDF文檔你要發到飛書聊天框這裡來,要不然我怎麼看到呢?就是要形成鐵律一樣的東西。」- 用戶在手機端看,點飛書訊息裡的文件才看得到;存進
02-項目成果/只是備份,不是交付。 - 交付格式:
<你的輸出目錄>/<文件名>.pdf(絕對路徑)。 - 發完 PDF 附核心結論要點(30秒版)。先發飛書,再存知識庫復盤。
- 用戶在手機端看,點飛書訊息裡的文件才看得到;存進
- 取內容:session_search 查歷史分析──用戶常對附件回「結論做成PDF」,先找回之前出過的研判/盡調內容,不要重寫
- 寫腳本:複製
templates/reportlab_chinese_template.py,只替換內容區(封面文字、章節、表格數據) - 生成:python 運行 → 輸出到 Obsidian
Hermes工作成果/02-項目成果/(命名:<主題>項目可行性盡調與分析報告.pdf) - 驗證:pymupdf 打開讀 get_text,確認頁數 / 中文渲染 / 末頁結論存在
- 交付:回覆
MEDIA:D:\...pdf路徑 + 核心結論要點(30秒版),不囉嗦
⭐ 配色鐵律(2026-09-02 用戶欽定,喜用神金/土──最高優先級)
用戶八字喜金喜土,忌水(藍/黑)忌火(紅/紫)。所有 PDF 一律用金土系配色,禁止再用藍色。顏色變量見下方 palette。
- 章節大標題 H1:金屬金底 + 白字(
backColor=#C9A227,textColor=white,borderPadding=(6,8,6,8))──金底白字,不是藍色文字。 - 表格表頭:金屬金底 + 白字(
header_bg=#C9A227,FONTNAME=MSYHBD)──金底白字。 - 正文:純黑
#1f1f1f。 - 副題 / 分隔線:深土金
#B8860B(去紅色)。 - 程式碼塊:土金
#8a6d1f(去藍色)。 - 斑馬紋:淺米金
#FBF3DE(暖調,不是灰白)。 - 網格線:淺土金
#D9C9A3。
金色系 palette(reportlab 用)
C_DARK=colors.HexColor("#1f1f1f") # 正文近黑
C_RED=colors.HexColor("#B8860B") # 強調/副題-深土金
C_BLUE=colors.HexColor("#C9A227") # 表頭/標題底-金屬金
C_LGRAY=colors.HexColor("#FBF3DE") # 斑馬紋-淺米金
C_MGRAY=colors.HexColor("#D9C9A3") # 網格線-淺土金
C_WHITE=colors.white
行內強調
S_CODE=st(..., textColor=colors.HexColor("#8a6d1f"));行內<span color='#B8860B'>(不用#c0392b紅色)。
排版要點(模板已封裝)
- 封面頁:大標題 + 金色副題 + 日期/來源 + 核心結論框(深土金底白字表)
- 正文:H1 章節(金屬金底白字 MSYHBD 21pt)+ H2 小節(17pt)+ 正文 15pt(2026-08-18 用戶指示:手機端可讀,字號必須大)
- 表格:
make_table()表頭金屬金底白字 + 斑馬紋(ROWBACKGROUNDS)+ grid + repeatRows=1,表格字號 13pt - 頁腳:onPage 回調畫報告名 + 頁碼
- 強調:Paragraph 支援
<b>/<span color='#B8860B'>行內標記 - 長報告分章節:PageBreak 分隔封面與正文
⚠️ 字號鐵律(2026-08-18 用戶強調):PDF 是給手機看的,正文≥15pt、表格≥13pt、H1≥21pt、標題≥34pt。原模板 10.5pt/9.3pt 太小,手機看不清──所有新報告必須用大字號。字號大導致頁數變多是正常的(如5頁→8頁)。
⭐ 智能排版鐵律(2026-08-18 用戶強調,列印友好)頁面內容必須均衡──不能某頁只有200字符、某頁擠800字符。方法:
- 少用 PageBreak:只在封面後強制分頁,正文讓它自然流動
- 用 KeepTogether 包裹「標題+內容」:
keep(H2標題, 表格/段落)防止表格被拆到兩頁、防止標題孤懸頁底 - 封面獨立一頁:封面元素 + 一個 PageBreak
- 每章用小節自然分隔:H2標題 + 表格/要點,不強制每章換頁
- 驗證均衡度:生成後用 pymupdf 檢查每頁字符數──正常報告除封面/收尾頁外,各頁字符數應接近(如600-900字符),差異過大就要調整
- 排版緊凑:邊距 20mm/16mm(不要過大),表格 padding 4-5,行距 leading=22(14pt正文),減少空白浪費
坑(PITFALLS)
- ⛔ 禁止兩端對齊(TA_JUSTIFY)──字間距被拉寬(2026-09-03 用戶最在意的手機可讀問題):reportlab 的
TA_JUSTIFY會對中文段落強制把每行拉伸到右邊界,某行字少時字間距被撐得極寬、極難看。所有正文/列表/段落一律用TA_LEFT左對齊。- 錯誤:
b=dict(..., alignment=TA_JUSTIFY, ...) - 正確:
b=dict(..., alignment=TA_LEFT, ...) - 排查:正文/列表樣式若繼承
st()且alignment=TA_JUSTIFY,必改左對齊。
- 錯誤:
- ⛔ 封面內容溢出成空白孤頁(2026-09-03):封面元素(主標題+副題+說明+核心一句話)必須全部壓在第1頁內,絕不能讓封面內容被推到第2頁形成「一小段字+大片空白」。封面內容過多時刪掉大段引言、壓縮列表間距,讓它在1頁內放完。每章之間只保留封面後一個 PageBreak,正文自然流動。
- ⛔ 字號/邊距要同頻調整:放大字號後,邊距要同步收窄(本會話 22mm→17mm)才能讓每頁裝更多、不產生孤頁。字號 17pt 正文 + 17mm 邊距是實測平衡點;表格字號 14.5pt。
- ⛔ KeepTogether 包「自定義對齊小表」會導致頁高誤判→孤頁(2026-09-06 實測):用 KeepTogether 包裹「標題+正文+自定義兩列對齊表(field_table)」+價格時,reportlab 對該塊的高度估算不準確,常把整塊推到下一頁,造成上一頁只剩「提示句/表尾一行」變成幾十字符的孤頁(本會話第2頁只有76字符)。修復:① 首屏「服務一覽表+引言」用 KeepTogether 包整個 head_block 並壓縮表格字號/行距確保能在第1頁放完;② 自建段渲染後用 pymupdf 逐頁看字符數,<120字符的頁就是孤頁,立即壓縮前頁表格/刪多餘提示句。
- 區分(2026-09-10 實測):只包「表格本身」是準且該做的;包「標題+正文+表+價格」大塊才容易誤判。 讓表格工廠函數統一
return KeepTogether(t)(表格整體不跨頁),配合只保留封面後一個 PageBreak,實測把 7 頁(第5頁僅 77 字)修成 6 頁、每頁 301/451/548/407/551/240 字。表格被分頁切斷、切出的 1–2 行獨佔一頁,是孤頁的頭號成因;發現「某頁只有表頭/末行」先查這個。
- 區分(2026-09-10 實測):只包「表格本身」是準且該做的;包「標題+正文+表+價格」大塊才容易誤判。 讓表格工廠函數統一
- ⛔ 兩列「標籤+內容」對齊表的標籤列不能太窄──中文標籤會折行成孤字(2026-09-06):用兩列對齊表做「能做什麼/做到多深/您能得到什麼」時,標籤列若太窄(如 32mm),「您能得到什麼」會折成「您能得到什」+「麼」,孤字極難看。修復:標籤列寬度要 > 最長標籤單行放置(40mm 左右),或把標籤改短(「您能得到什麼」→「帶來什麼」)。
- ⛔ 長句末尾的「。」會單獨折行成孤兒標點(2026-09-06):「做到多深/帶來什麼」這類長字段,整句末尾的「。」在換行時被甩到下一行開頭。修復:字段值較長、有折行風險時去掉末尾句號(或用規避短句),寧可不要句號也不留孤點。
- ⛔ 「定制技能」要寫對口徑(2026-09-06 用戶糾正):不要把「定制/定做skills」誤寫成「定時任務」。客戶版統一用「專屬技能定制」並口語化解釋「技能=一件AI能照著幹的具體本事」(見 enterprise-ai-service-blueprint)。
.ttc字體必須subfontIndex=0,否則報錯或亂碼- 加粗必須註冊 MSYHBD 並設置 fontName──
<b>標籤在無粗體字體註冊時靜默不加粗 <>的轉義要分兩種情況(2026-09-10 實測踩坑):正文裡的裸尖括號(如「精度<10mm」)才轉義成</>;而<b>、<span color=...>是內聯標記,必須原樣傳給 Paragraph 才生效。- ⛔ 致命寫法:單元格文本一律
.replace('<','<')全轉義 → 表格裡的加粗會原樣顯示成<b>字樣(本會話第2頁整列都印成<b>點名支援…,交付前才發現)。 - ✅ 正確:表格單元格只轉義裸
&(v.replace('&','&')),保留內聯標籤;內容裡的裸尖括號由調用方自己寫<。 - 自檢:交付前抓全文,
'<b>' in text或'</b>' in text為真即說明標籤被當文字渲染了,必須回查 make_table 的轉義。
- ⛔ 致命寫法:單元格文本一律
- 表格列寬總和 ≤ A4 可用寬度(210mm - 左右邊距),否則溢出換行難看
- 表格中文溢出(2026-08-18 重要修復):reportlab 的 Table 直接放長中文不會自動換行,會溢出到右邊!必須用 Paragraph 包裹單元格 +
wordWrap="CJK"。已在 make_table 內置_cell_style()處理──所有單元格自動換行。驗證:用 pymupdf 查get_text('words')的 x2 是否越過內容區右邊界。- 閾值必須按實際邊距算,不能寫死 540pt(2026-09-10 實測):右邊界 =
A4[0] - rightMargin(A4 寬 595.3pt;16mm 邊距 → 549.9pt,17mm → 547pt)。寫死 540 會把正常換行誤報成溢出,白折騰。 - 必須排除頁腳:onPage 畫的「第 N 頁」永遠超出內容區,判定時要按文本過濾掉(如
w[4] != '頁'),否則每次都有假警報。 - 判定示例:
[w for w in page.get_text('words') if w[2] > page.rect.width - rightMargin + 1 and w[4] != '頁']
- 閾值必須按實際邊距算,不能寫死 540pt(2026-09-10 實測):右邊界 =
- A4豎排鐵律(用戶強調):所有PDF必須 A4 豎排(210×297mm),pagesize=A4 預設就是豎排,不要改 landscape
- 交付前必須用 pymupdf 驗證一次(頁數/中文/亂碼/無溢出)──驗證通過才發
- ⛔ 寫生成腳本時,Python 字串一律用單引號定界(2026-09-10 實測):工具鏈會把中文引號 “ ” 規範化成半角
",字串外層若用雙引號定界,正文裡的引號會提前閉合字面量 → 報SyntaxError: invalid character '+' (U+FF0B)之類(報錯點看著像全角字符非法,真因是引號截斷,會誤導排查方向)。正文裡的中文引號要嘛改用「」,要嘛整條字串用'...'包。 - ⛔ 絕不要「邊寫邊讀」同一個文件:
open(f,'w').write(open(f,encoding='utf-8').read() + add)會先把文件截斷成 0 位元組再讀,結果是原文全丟、只剩追加段(本會話知識庫筆記從 13KB 縮成 3.8KB,差點交了殘檔)。追加內容時先txt = open(f).read()存變量,再open(f,'w').write(txt + add);或直接用 patch 工具改。 - 文件 >100KB 通常正常(嵌入字體子集)
驗證命令
$V -c "import pymupdf; d=pymupdf.open(r'D:\...\報告.pdf'); print(len(d)); print(d[0].get_text()[:120]); print('末頁含結論:', '結論' in d[-1].get_text())"
關聯
- 內容框架:
feasibility-study-writing、dual-lens-business-analysis(雙光研判出報告前先載入) - 報告審查鐵律:嚴謹報告出稿前執行
report-reflection-review - PPT 場景:
ultimate-ppt-master - 模板:
templates/reportlab_chinese_template.py(舊);templates/reportlab_gold_template.py(推薦):金色系 + 左對齊 + 17pt大字 + 17mm緊凑邊距 + 無孤頁。已修make_table()內聯標籤處理(表格單元格內<b>/<span>現在真正生效,不再被轉義成字面