内容
<p align="center"><img src="./assets/brand/autohwp-banner.png" alt="自动韩文 (auto-hwp) — AI 加持,一屏共写韩文" width="100%"></p>
# 自动韩文 (auto-hwp)
**AI 加持,一屏共写韩文.** `.hwp`/`.hwpx` 打开后原样呈现 —
鼠标点击或语音输入,AI 建议编辑,确认后文档生成。
全过程在服务器端以外 100% 本地运行(WebAssembly · MCP · CLI)。
[English](./README.en.md) · [在线演示](https://kwakseongjae.github.io/auto-hwp/) ·
[嵌入指南](./docs/EMBED-GUIDE.md) · [MCP](./docs/MCP-GUIDE.md) · [贡献](./CONTRIBUTING.md)
## AI 眼中的 HWP 是 "不可见文档"
对大型语言模型(LLM)来说,HWP 文档一直是一个挑战。传统的处理方式是 **文本提取**,但这会导致文档分裂成两个世界:**AI 读取的文本** 和 **人类看到的页面**。这使得 AI 无法准确理解文档的结构和布局。
自动韩文通过 **拥有渲染引擎** 来解决这个问题。我们将 HWP 文档解析、排版、渲染、编辑和保存都在一个 **语义文档(SemanticDoc)** 上进行:
```
.hwp / .hwpx ──▶ SemanticDoc(IR) ──▶ 排版(hwp-typeset) ──▶ SVG 页面 (屏幕 · 碰撞检测)
│ ├▶ PDF (布局保留,krilla)
│ └▶ 文档配置文件 · Markdown (AI 读取窗口)
└── 意图 JSON ──▶ 操作 ──▶ IR 变化 (编辑 · 撤销/重做) ──▶ HWPX 保存
```
这个架构在 AI 识别层面实现了三点:
**① AI 读取的内容 = 屏幕显示的内容.** 文档上传后,引擎会 **确定性地提取文档配置文件**(标题、目录、表格清单、文章摘录),并将其附加到每个请求上。这样,AI 可以准确地理解文档的结构和布局。
**② AI 的操作是类型化的 Intent.** 模型只能输出 **19 种白名单 Intent JSON**,并且需要经过 **模式验证** 和 **未知字段拒绝** 后才能应用到文档上。这样可以确保 AI 的操作是可控的和可预测的。
**③ 结果可以通过数值验证.** 由于我们拥有渲染引擎,可以通过 **页面数量、布局、文本内容** 等指标来验证编辑结果的准确性。
## 软件包(npm)
| 软件包 | 层级 | 角色 |
|---|---|---|
| **`@auto-hwp/engine`** | L1 | **无头引擎(wasm)** — 解析、排版、SVG/HTML/PDF/HWPX、Intent 编辑、撤销。无 UI |
| `@auto-hwp/editor-core` | L2 | 无头编辑器状态(选择、编辑、会话)— 最小化 DOM,与 React 无关 |
| `@auto-hwp/ai-protocol` | L2′ | 协作编辑 LLM 协议(提示/上下文/验证)— 无 fetch,无密钥 |
| `@auto-hwp/react` | L3 | **选择** 层:参考编辑器 `<HwpWorkspace/>` + React 绑定 |
```bash
npm i @auto-hwp/engine # 仅使用无头引擎
npm i @auto-hwp/react @auto-hwp/engine @auto-hwp/editor-core @auto-hwp/ai-protocol
```
嵌入完整配方(wasm 静态服务、CSP、字体、AI 代理)请参考 [docs/EMBED-GUIDE.md](./docs/EMBED-GUIDE.md),示例请参考 [examples/vite-embed](./examples/vite-embed)。
## 快速开始 ① — 无头引擎(自定义 UI)
无需 React 或我们的编辑器。引擎会返回 SVG 字符串和字节:
```js
import { initEngine, HwpDoc } from '@auto-hwp/engine';
await initEngine(); // wasm 实例化
const bytes = new Uint8Array(await file.arrayBuffer());
const doc = HwpDoc.open(bytes, file.name); // 自动检测 .hwp / .hwpx
// 渲染 — 每页 SVG 字符串。可以自定义如何显示
for (let p = 0; p < doc.pageCount(); p++) {
container.insertAdjacentHTML('beforeend', doc.renderPageSvgSanitized(p));
}
// 编辑 — 意图 JSON(模式 v0,docs/INTENT-SCHEMA.md)
doc.applyIntent({ intent: 'SetTableCell', section: 0, index: 1, row: 0, col: 0, text: '值' });
doc.undo();
// 导出
const html = doc.exportHtml(); // 语义重流 HTML
const pdf = doc.exportPdf(); // 布局保留 PDF(Uint8Array)
const hwpx = doc.toHwpx(); // round-trip 安全 HWPX(Uint8Array)
doc.free();
```
## 快速开始 ② — 参考编辑器(React)
```tsx
import { HwpWorkspace, WasmAdapter } from '@auto-hwp/react';
import '@auto-hwp/react/styles.css';
<HwpWorkspace
adapter={adapter} // WasmAdapter(Web)或自定义适配器
document={{ bytes, name }}
enableEditing
onAiRequest={myLlmBridge} // 可选:协作编辑 — LLM 在您的服务器上(BYOK)
/>
```
## AI 工具/终端直接使用(无需网站,全本地)
- **MCP 服务器** — 用于 Claude Code/Desktop·Cursor:`cargo install --git https://github.com/kwakseongjae/auto-hwp hwp-mcp --features rhwp` → `claude mcp add auto-hwp -- hwp-mcp`。
打开/结构上下文/编辑(预览→确认)/查找/撤销/HWPX·PDF 导出 15 种工具。文档不会离开本地。→ [docs/MCP-GUIDE.md](docs/MCP-GUIDE.md)
- **Claude Code 技能** — `cp -r skills/hwp ~/.claude/skills/` 后,在任意会话中输入 "将此 hwp 转换为 pdf":
CLI(`auto-hwp`)封装转换、提取、预览、编辑为本地执行。→ [skills/hwp/SKILL.md](skills/hwp/SKILL.md)
## 本地演示
```bash
git clone --recurse-submodules https://github.com/kwakseongjae/auto-hwp
cd auto-hwp
# 引擎 wasm 构建(需要 Rust + wasm-bindgen — 参考 CONTRIBUTING.md)
cargo build -p hwp-wasm --profile wasm-size --target wasm32-unknown-unknown
wasm-bindgen --target web --out-dir packages/engine/pkg target/wasm32-unknown-unknown/wasm-size/hwp_wasm.wasm
# 演示应用
cd apps/hwp-lab && npm install && npm run dev # http://localhost:3000
```
## 协作编辑(AI)
点击文档的单元格/段落/表格作为锚点 — **也可以直接语音输入**:文档上传后,引擎会 **确定性地提取文档配置文件**(标题、结构、目录、表格清单、文章摘录,无需 LLM 调用),并将其附加到每个请求上。这样,AI 可以准确地理解文档的结构和布局。
- 编辑词汇 19 种:填充单元格/段落、插入表格/段落/图表、添加行、移动/删除块,以及 **查找替换、字符格式、表格列宽、页面边距** 等全局编辑。
- 建议以卡片形式预览 — **"查看位置"** 以可视化更改的块,确认后应用。
- LLM 调用始终在 **主机服务器上**(BYOK — 我们的任何软件包都不需要 API 密钥),模型输出在模式验证和未知字段拒绝后才应用到文档上。
- 代理模式:网页搜索 → 引用 → 编辑建议流式传输。
## 设计笔记 — 什么是正本?
最初的想法是 "HWP → XML(结构)+ CSS(设计)→ LLM 选择编辑内容"。在实现过程中,我们将其 **改为基于语义文档(SemanticDoc)和类型化 Intent 编辑**([`docs/PIVOT-DESIGN.md`](./docs/PIVOT-DESIGN.md)):
- 渲染正本:**SemanticDoc → 排版 → SVG**(与 HWP 原版像素级对比)
- 编辑正本:**Intent JSON → 操作 → IR 变化**(LLM 输出受模式约束 — 自由 XML/CSS 补丁不可控且撤销不准确)
- XML+CSS 表现在 [`hwp-jsx`](./crates/hwp-jsx) **选择 codec**(JSX/CSS 投影,round-trip 验证)中,HTML 导出是其分支。
## 准确性
| 基准 | 韓文渲染 | 自动韩文 | 结果 |
|---|---|---|---|
| benchmark.hwp(政府模板,8 页) | 8 页 | 8 页 | ✅ 匹配 |
| benchmark1.hwp(申请书,18 页) | 18 页 | 18 页 | ✅ 匹配 |
| 换行位置匹配率 | — | 98.9%+ | 合格 |
`scripts/verify-local.sh` 强制每次提交都通过此验证。除了代码验证外,**49 种政府模板**(创业支持模板、公告、新闻稿、通知等,[来源](./corpus/GOV-SOURCES.md))都通过了打开 → 渲染 → PDF → 文本的整个流程。性能测试结果为 130 页文档编辑 → 屏幕渲染 136ms(工作线程,UI 非阻塞),撤销内存上限为文档大小(128MiB)。
## 已知限制(诚实披露)
- **PDF 公式/图表**:虽然在屏幕和 HTML 中正确渲染,但在 PDF 后端 **无法以矢量形式导出**,而是显示为 **占位框**(导出时应用程序会发出警告)。SVG → PDF 矢量化的后续工作正在进行中。
- **加密 `.hwp`**:不支持加密的 `.hwp` 文件,并会直接拒绝。
- **`.hwp`(二进制)无法重新保存**:保存格式为 HWPX。打开 `.hwp` 文件编辑后,保存为 HWPX(未编辑区域按字节原样保留)。
## 字体(全部 OFL — 允许重新分发和 PDF 嵌入)
默认使用 ** 나눔哥特/ 나눔明朝**(自动区分明朝和哥特)。在 **功能区** 中选择 **Pretendard·Noto Sans/Serif KR·IBM Plex Sans KR·高运돋움/바탕** 等 8 种目录字体时,会自动加载并在 **屏幕和 PDF 中显示为实际字体**。由于许可证限制,商业字体(如 樊籇体)不会被捆绑,但可以使用 OFL 字体代替。 → [docs/FONT-CATALOG.md](./docs/FONT-CATALOG.md)
## Rust 工具链(引擎内部)
`hwp-model`(IR)· `hwp-hwpx`(HWPX 编码)· `hwp-rhwp`(.hwp 解析引导,[rhwp](https://github.com/kwakseongjae/rhwp) MIT)·
`hwp-typeset`(排版:金尺 · 段落间距 · 字符间距 · 古韩文)· `hwp-render`(PaintOp → SVG)· `hwp-export`(PDF/HTML)·
`hwp-ops`(操作总线 · 撤销)· `hwp-mcp`(Intent 模式)· `hwp-session`(几何)· `hwp-wasm`(绑定)·
`hwp-crypto`(分发文档解密)· `auto-hwp-cli`(CLI)
CLI 也可以单独使用:
```bash
cargo run -p auto-hwp-cli --features rhwp -- own-render 文档.hwp --out page.svg
cargo run -p auto-hwp-cli --features rhwp -- export-pdf 文档.hwpx -o out.pdf
```
## 许可证
MIT OR Apache-2.0 ([LICENSE-MIT](./LICENSE-MIT) / [LICENSE-APACHE](./LICENSE-APACHE)).
第三方通知请参考 [NOTICE](./NOTICE) — 包括 rhwp(MIT)、 나눔字体(OFL)、oracle 的 GPL 隔离方法。