Skip to content

feat: format alignment engine — 從既有 docx 逆向 template schema 並單指令重建(word reverse 深化) #130

Description

@kiki830621

Problem

Original text(使用者口述構想,逐字保留):
「我正在設計word的test,可以參考這個:對,這樣就不是「從零生成 Word」,而是更精確地說:

從既有 Word 文件中逆向工程出可重用的格式範本,然後讓新內容自動對齊那個格式。

這比較像:reference document → template extraction → content mapping → regenerated document

也就是「格式模仿器」或「文件格式對齊引擎」。核心任務不是生成內容,而是抽取格式規則。

你要的系統大概會做這幾件事:

  1. 讀入一份範本文檔 docx
  2. 分析它的標題、段落、表格、頁面設定、字體、縮排、間距
  3. 把這些格式抽成一個 template schema
  4. 將新的內容塞進對應位置
  5. 輸出一份格式高度相似的新 docx

這跟一般 AI 寫作不一樣。它的重點是 style/layout fidelity,不是內容創造。

你真正需要抽取的東西 — 一份 Word 文件其實可以分成幾層格式:

  1. Page-level format:紙張大小、直式/橫式、上下左右邊界、頁首頁尾、頁碼、行距基準、分節設定
  2. Paragraph-level format:標題層級、段前段後距離、縮排、首行縮排、對齊方式、行距、項目符號/編號
  3. Run-level format:字型、字體大小、粗體、斜體、底線、顏色、上標/下標、中英文字型差異
  4. Table-level format:欄寬、列高、框線、儲存格底色、文字垂直置中、表格對齊、合併儲存格
  5. Structural role(最重要但最難):不是只知道「這段是 16pt 粗體」,而是要知道它的角色 — 文件標題/章標題/節標題/正文/引用/表格標題/註腳/簽名檔/附件清單/日期/收件者。也就是 format → semantic role。這一步才是真正的「逆向工程範本」。

比較合理的架構
Reference DOCX → DOCX Parser → Style Extractor → Template Schema → Content Aligner → DOCX Renderer → New DOCX

Template schema 範例:

{
  "page": { "size": "A4", "margins": { "top": "2.54cm", "bottom": "2.54cm", "left": "3.18cm", "right": "3.18cm" } },
  "styles": {
    "title": { "font": "標楷體", "size": 18, "bold": true, "alignment": "center", "space_after": 12 },
    "body": { "font": "標楷體", "size": 12, "line_spacing": 1.5, "first_line_indent": "2em" }
  },
  "structure": [
    { "role": "title", "source_pattern": "first_centered_bold_paragraph" },
    { "role": "body", "source_pattern": "normal_paragraphs" }
  ]
}

最難的是「內容對齊」:新內容的語意角色 → 範本文檔中的格式位置。需要 content slot system:

{ "slots": [
  { "name": "title", "role": "document_title", "style": "title", "position": 0 },
  { "name": "body", "role": "main_body", "style": "body", "position": 3 } ] }

未來只要輸入 { "title": "...", "body": "..." } 就可以套進去。

兩種模式

  • A. Strict template mode:精準保留原文件結構,只替換內容(placeholder {{title}} {{date}} {{body}} {{signature}})。適合公文/會議紀錄/邀請函/報帳文件/表格文件/固定格式報告。優點穩定,缺點要先人工標記 slot。
  • B. Inferred template mode:程式自己推斷(第一個置中粗體大字 = title、日期附近段落 = date、最後幾段 = signature、表格 = structured data section)。優點神奇,缺點容易錯。
  • 建議 MVP 先做 Strict template mode,再慢慢做 inferred mode。

測試策略

  • Smoke test:能不能讀入 docx 並輸出新的 docx
  • Unit test:每個 style extractor 是否能正確讀出字型、行距、縮排
  • Round-trip test:docx → template schema → docx,格式是否盡量保持
  • Snapshot test:同一份範本產生的輸出是否穩定
  • Regression test:修某個表格 bug 後,不要弄壞標題或段落
  • Visual diff test:把兩份 docx 轉成 PDF 或圖片,比較版面差異(最關鍵 — Word 格式最終不是只看 XML,而是看「視覺上像不像」)
  • Fuzz test:丟格式混亂的 docx,看程式會不會崩潰

精準定義:給定一份 Word 範本文檔,系統自動抽取其版面、段落、字型、表格與結構規則,形成一個可重用的 template schema。之後使用者只要提供新內容,系統就能自動將內容對齊到原本的格式,並輸出新的 .docx。這不是普通 Word clone,而是 Word template induction + document rendering。

我現在想做的是,如果我給一個docx,你有沒有辦法用一條入境(指令)從頭開始做成這個檔案,只用合法的word處理
— Source: 使用者貼上文字(2026-07-07 口述構想,「一條入境」依上下文解讀為「一條指令」)

解讀:這是 format alignment engine(Word template induction)的完整構想。核心 ask 是最後一句 —— 給一個 docx,用一條指令從頭重建出這個檔案(只用合法的 OOXML 處理),即「docx → 可執行的重建腳本 → 內容等價的新 docx」單指令閉環。這正是 word-aligned-state-sync 的 reverse 方向延伸到完整格式保真。

與 macdoc 現況的關聯(起點不是零)

剛出貨的 word-aligned-state-sync(archived 2026-07-06,ooxml-swift v1.0.3)已交付這個願景的骨架:

構想元素 現況 缺口
「一條指令逆向」 macdoc word reverse <docx> --to-mdocx out.mdocx.swift 已存在(Phase 4 task 5.7) 只覆蓋段落文字 + styleId;page/table/run 級格式未抽取
Template schema .mdocx DSL(WordDSLSwift)即 schema 的 Swift 形;WordStyle/defineStyle 是 styles 段 run-level 屬性只有 bold/italic/color;page-level(sectPr:紙張/邊界/頁首頁尾)完全沒有 reverse 通道
DOCX Renderer WordDocument{}.save(to:) 三檔原子寫;reducer/tree 路徑保真 Table/Hyperlink/Bookmark 的 DSL authoring 是 loud-throw(5.5 已知範圍)
Structural role 推斷 Inferred mode 的核心;heuristic-output rule 的既有原則適用
Content slots Strict mode 的 placeholder 系統
Visual diff test 無(現有為 XML/byte 級 round-trip + live-Word gated) convert --to pdf + 圖像比對可組裝

Type

feature

Expected

  1. 單指令重建閉環(MVP 驗收)macdoc word reverse ref.docx --to-mdocx t.mdocx.swift 抽出的腳本執行後產出的 docx,與原檔在「五層格式」上高度相似(先段落層完整 → 再 page/run/table 層逐步補齊)
  2. Template schema 層(.mdocx 或衍生 JSON)覆蓋 page/paragraph/run/table 四層格式屬性
  3. Strict template mode:content slots(placeholder 替換)先行;inferred mode 後續
  4. 測試矩陣落地:round-trip / snapshot / visual diff(docx→PDF→圖像比對)/ fuzz

Actual

word reverse 只逆向段落文字 + styleId + paraId;格式四層中 page/run 細節/table 全部走 // @op raw escape 或直接略過(stderr 警告)。無 template schema 抽象、無 content slots、無 visual diff 測試設施。

Impact

  • 這是 word-aligned-state-sync follow-up register 的自然延伸(Table/Hyperlink/Bookmark canonical authoring、WordStyle properties 深化都在 register 內)
  • 使用者當前的 Word 測試設計(round-trip 驗證)直接受益:visual diff test 是現有 byte-level 測試的正交補充
  • 潛在拆分:此 issue 可作為 umbrella,後續拆 Spectra change(template-schema 抽取 / content slots / visual diff infra 三塊)

Clarity Surface(idd-clarify run 2026-07-07T00:37:03Z)

Type Source Suggested canonical Status
ambiguity 「用一條入境從頭開始做成這個檔案」 「入境」依上下文解讀為「指令」(speech-to-text 誤植)——但也可能是「引擎」(one engine);影響驗收形態(CLI 單指令 vs 單一 engine API) resolved @ 2026-07-07T00:43:34Z(使用者確認 =「路徑」— 一條完整 pipeline 路徑)
ambiguity 「只用合法的word處理" 三種解讀:(a) 只產生合法 ECMA-376 OOXML(macdoc 現行路線)(b) 只透過 Word 應用程式本身處理 (c) 不做 binary hack。建議 canonical:(a) resolved @ 2026-07-07T00:43:34Z(使用者確認 (a))
ambiguity 「輸出一份格式高度相似的新 docx」 「高度相似」驗收標準未定:byte-equal / XML 結構等價 / visual diff 閾值?五層格式各自的相似度定義需要 per-layer 驗收條款 resolved @ 2026-07-07T00:43:34Z(使用者定調:要完全一樣,byte-equal——「我要看的是你仿作的能力」。最強驗收層級)
missing-context 「把兩份 docx 轉成 PDF 或圖片,比較版面差異」 docx→PDF 轉換通道未指定:macdoc 現有 pdf 輸出僅 html→pdf(playwright);docx→PDF 需 Word/LibreOffice export 或新增通道 resolved @ 2026-07-07T00:43:34Z(使用者委託:「你要看看怎麼用」— 通道調查轉為 diagnose 階段工作項)
missing-context 「讀入一份範本文檔 docx」 MVP 驗收用的 reference docx 樣本集未指定(公文/會議紀錄/報告——哪一類先行?現有 test-files 與 NTPU thesis fixture 是否適用) resolved @ 2026-07-07T00:43:34Z(使用者:建範本資料夾;候選 = 日本心理學範本,即先前記錄的 90_template_ja.docx)

Current Status

Phase: diagnosed
Last updated: 2026-07-07 by idd-diagnose

Key Decisions

  • 驗收雙軸定調:byte-equal(Stage A per-part → Stage B 全 part 集合;Stage C zip 容器傾向豁免,待 discuss 拍板)+ DSL-form coverage %(仿作能力真分數)
  • 五個 Clarity 疑點全 resolved:「一條入境」=「一條路徑」(pipeline);合法處理 = ECMA-376 OOXML;範本 = 90_template_ja.docx(已定位)
  • 實證基線已量:96/96 段落 DSL-form(0 raw escape),但只抽 text+styleId;13 parts 中 12 個不在腳本內
  • Complexity = Spectra;使用者選 spectra-discuss 先對齊(未決:Stage C 豁免、change 拆分、範本資料夾隱私模式)
  • docx→PDF 通道建議:Word AppleScript export 首選(visual diff 用)

Scope Changes

  • (none)

Blocking

  • 進 spectra-discuss 前無 blocker

Commits

  • (none — issue/diagnose 階段)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions