韓文技術文件製作
將韓文技術·商業文件製作成自包含的 HTML,並可依需求輸出為 PDF。
- 兩種輸出模式使用共同設計 token 與模式專用 CSS。
- 數值、表格、圖表根據提供的數據以程式生成。
- HTML 在執行時不請求外部資源。
- 正文字體僅在透過
--font指定時內嵌。
句子規範由 korean-report-style 技能負責。此技能的範圍僅限於製作。
1. 開始前決定
1.1 模式
| paper | deck | |
|---|---|---|
| 用途 | 分析 · 基準測試 · 技術報告 · 進度報告 | 會議 · 議程 · 決策請求 |
| 方向 | 垂直 | 水平 |
| 頁面 | 連續流動 | 1 區段 = 1 頁 |
| 正文寬度 | 720px | 1120px |
| 密度 | 完整文章 | 每頁一個重點 |
| 模板 | assets/paper_template.html | assets/deck_template.html |
| 正文結構 | <div class="doc"> 內的 <section> | <section class="tile ..."> 列舉 |
在本文件中,layout 指的是頁面與元素的配置,而 typesetting 指的是反映 CSS、字型、公式並生成最終 HTML 的處理階段。
不混用。 段落較長的 deck 會被視為布局歪斜的報告,而使用了方塊背景的 paper 則會被視為錯誤列印的投影片。
1.2 是否需要輸出文件
僅在收到文件輸出要求時製作。說明、摘要、分析以對話方式回應。
幫我做報告 · 幫我輸出成 PDF · 幫我整理成文件 是觸發信號。
1.3 執行環境
- HTML 建置需要 Node 20 以上與 KaTeX。
mathbuild.js會依序在工作目錄與技能安裝路徑中尋找 KaTeX。 - 渲染 QA、螢幕截圖、PDF 輸出需要 Python 3.11 以上、Playwright、Chromium。
- 要內嵌正文字體,請準備有使用權限的 WOFF2 檔案。
2. 建置管線
數據 ──▶ 生成器(Python) ──▶ raw HTML (公式標記 + 替換代碼)
│
▼
後處理(Node + KaTeX) — mathbuild.js
· ⟦I⟧ / ⟦D⟧ 渲染
· base.css + 模式 CSS 插入
· 指定的正文字體 · KaTeX woff2 base64 嵌入
│
▼
單一 .html ──▶ headless print ──▶ .pdf
模板僅是包含替換代碼的輕量外殼。實際規則位於 assets/css/。
| 代碼 | 填寫主體 |
|---|---|
__TITLE__ · __BODY__ | 生成器 |
__FONTCSS__ · __KATEXCSS__ · __BASECSS__ · __MODECSS__ | mathbuild.js |
不要直接將 CSS 寫在模板中。 曾發生過兩個模板各自複製規則,導致 deck 的列印規則覆蓋 paper 規則的意外。共用規則放在 css/base.css,模式專用規則放在 css/paper.css · css/deck.css 唯一位置。
2.1 生成器撰寫
import sys; sys.path.insert(0, "<技能路徑>/assets")
from figures import tbl, wide, fig_gantt, fig_flow, figcap, esc, BADGE_MEAS
def I(t): return "⟦I⟧" + t + "⟦/I⟧" # 行內公式
def D(t): return "⟦D⟧" + t + "⟦/D⟧" # 顯示公式
def sub(tpl, *args):
"""依序替換 %s 並將 %% 還原為 %"""
out, i, ai = [], 0, 0
while True:
j = tpl.find("%s", i)
if j < 0:
out.append(tpl[i:]); break
out.append(tpl[i:j]); out.append(str(args[ai])); ai += 1; i = j + 2
return "".join(out).replace("%%", "%")
BODY = sub('''<section id="s1"><h2><span class="sn">1</span>標題</h2>
%s
</section>''', tbl(...))
TPL = open("paper_template.html", encoding="utf-8").read()
out = TPL.replace("__BODY__", BODY).replace("__TITLE__", "文件標題")
open("raw.html", "w", encoding="utf-8").write(out)
公式分隔符必須使用 ⟦I⟧·⟦D⟧。 像 %%I%% 這樣的 ASCII 分隔符可能在單字符公式 I(r"D") 中意外產生 %%D%%,導致解析器誤判。這是實際發生過的錯誤。若建置發現舊版標記則會失敗。
不要在註解或正文中使用替換代碼。 Python 的 str.replace 會替換所有出現,如果在註解中寫了 __BODY__,正文會被插入兩次。這也是實際發生過的狀況。
整體生成流程為:將 assets/figures.py 的圖表放置在 assets/paper_template.html 或 assets/deck_template.html 中,然後透過 assets/mathbuild.js 進行後處理。
2.2 後處理
node mathbuild.js raw.html out.html \
--assets <技能路徑>/assets \
--font Pretendard-Regular.woff2 --font Pretendard-SemiBold.woff2
在建置時以 KaTeX 渲染,並僅選取渲染結果所引用的 woff2 進行 base64 嵌入。 整個字體約 1.2 MB,實際需要的僅約 160 KB。
失敗時 exit 1。 公式錯誤、未替換的代碼、舊版標記、找不到的字體路徑都會中斷建置。靜默地產生錯誤渲染的公式比沒有公式更糟。
若省略 --font,僅發出警告並繼續進行。此時文件會回退到讀者的系統字體,因此 typesetting 結果會因裝置而異。發布版本務必內嵌。
2.3 PDF
python <技能路徑>/assets/qa.py out.html --pdf --shot shots/
直接呼叫:
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
b = p.chromium.launch(); pg = b.new_page()
pg.goto('file:///abs/path/out.html'); pg.wait_for_timeout(2500)
pg.pdf(path='out.pdf', format='A4', print_background=True) # deck 需 landscape=True
b.close()
請給予充足的 wait_for_timeout。在字體·圖片加載完成前列印會導致渲染錯誤。
3. 圖表
所有圖表皆為內聯 SVG。 不製作 matplotlib PNG。 放大仍清晰、可繼承代碼、文字可搜尋、檔案不變大。
assets/figures.py 已準備 7 種類型 — 時間軸 · 甘特圖 · 卡片網格 ·
流程圖 · 垂直線 · 對比長條 · 散點圖。座標由 Python 計算後直接嵌入 SVG 文字。
若由瀏覽器 JS 計算,則在 PDF 輸出時無法保證相同執行結果。
顏色不用 hex,而是用類別(fi-* 填充 · st-* 線條)。base.css 會將這些類別連結到 CSS 變數,因此在深色方塊上只需更改代碼,圖表就會跟隨適應。
若使用 hex,#1d1d1f 文字在 #272729 方塊上會消失。
詳細規範請參閱 references/figures.md。
3.1 點陣例外
實際圖紙·點群上疊加量測數據的視覺化無法用 SVG 手動繪製。 在此情況下允許使用點陣,但需遵守三個條件。
- 以 base64 data URI 內嵌 — 相對路徑引用在檔案移動時會失效。
- 加上邊框 — 使用
.plate類別(1px hairline, 10px 半徑, 最大 820px)。 - 數值以原生文字並列 — 不讓點陣獨自承載判斷依據。
4. QA — 渲染後檢查
不相信原始碼。 務必以瀏覽器渲染後檢查。
python <技能路徑>/assets/qa.py out.html --shot shots/
檢查公式標記·替換代碼殘留、水平溢出、超出容器的表格、CSS 插入失敗、 超出 viewBox 的圖表、無標題的圖表,失敗時 exit 1。
deck 會檢查列印布局。 若方塊超過一頁(A4 橫向 210mm)則失敗,並告知哪個方塊超出多少 px。.tile 在列印時設有 overflow:hidden,因此超出內容會靜默地被裁剪 — 這是 deck 最常見的錯誤。
若超出,不要縮小字型,而是拆分區段(參見 design.md §7.1)。
4.1 需人工檢查的項目
機器無法檢測的部分透過螢幕截圖與 PDF 確認。
列印
- 頁碼符合預期(deck: 區段數 = 頁碼)
- 表格 · 公式 · 引用區塊未被頁面邊界截斷
- 無半頁以上空白頁
- 標題未獨自留在頁面末尾
- 深色方塊在列印時反轉
編號
- 圖 · 表 · 節 · 風險編號連續
- 正文參照(
§5.2,圖 8)指向實際對象
若進行多次編輯,請每次執行。刪除任一項目會導致編號與參照連鎖錯位。
5. 編輯請求處理
文件修改請求不是文字替換,而是結構運算。
| 請求 | 需同步處理的事項 |
|---|---|
| 刪除項目 | 後續編號重新排序 · 更新正文參照 · 檢查摘要 · 移除未使用定義 |
| 刪除章節 | 調整參數列表數量 · 檢查圖表函數是否未使用 · 調整子章節編號 |
| 刪除表格欄位 | 因欄位消失而無意義的引言 · 剩餘欄位的完整性 |
| 緩和用語 | 全域檢查相同表述是否也出現在圖表標籤 · 標題 · 表格儲存格 |
發現連鎖影響時請告知。 例如「刪除 S3 後,底下的摘要會參照 S4,要一起修正嗎?」 若靜默修正,用戶將不知道什麼被更改了。
6. 需要判斷的點
- 刪除限制性描述 — 刪除任意基準·未測量項目會讓數值看起來像已驗證。即使接受刪除請求,也應詢問是否保留一行說明。
- 更正通知 — 若先前分享的數值與計算基準已變更,即使語調放緩,也應保留事實。
- 分析與文件 layout 的界線 — 從數據中找出關係超出此技能的範圍,但會極大影響文件價值。若提供數值,請驗證其一致性,發現異常時應告知。
7. 參考檔案
references/design.md— 顏色 · 字體排版 · 元件 · 列印規範全集references/figures.md— 7 種圖表的使用方法與座標規範assets/paper_template.html·assets/deck_template.htmlassets/css/base.css·assets/css/paper.css·assets/css/deck.cssassets/figures.py·assets/mathbuild.js·assets/qa.py