博客在线生成工具 · 可行性报告
博客在线生成工具 —— 可行性报告
目标:在 suy2blog.cn(Halo 2.26.1)上部署一个入口,客户录入关键信息,系统识别后将信息填入指定 Word 文档,再把多个文档合并成一份 PDF 返回客户。 本文基于对本机(博客 VPS 106.55.246.220)实测的部署事实撰写。
1. 需求拆解
| 环节 | 输入 | 处理 | 输出 |
|---|---|---|---|
| A. 入口 | 浏览器打开博客页面 | Halo 静态页面承载表单 | JSON 表单数据 |
| B. 识别 | 客户关键信息字段 | 校验/归一化→灌入 word | 填好的 docx |
| C. 落版 | 模板 word | 定向替换 + 保持版式 | docx(可 .doc/.wps 输入) |
| D. 合并 | 多份 docx | 合成单文件 | 一份 docx |
| E. 转 PDF | 合并后 docx | 版式还原 | |
| F. 返回 | HTTP 下载/在线预览 | 客户浏览器 |
这四个字面上看起来是"浏览器一个页面的事",实际每步都涉及有状态的真实文件格式,所以选型核心在 C/D/E 三环。
1.1 已确定的两前提(形态基线)
本项目两个关键前提经确认后固定为默认基线,报告其余部分在此基础上收敛:
① 模板由你后台预置(形态甲,已采用)
- 模板(合同/报价等)由你在后台预置入库;客户只填表单字段,无法触碰/上传模板。
- 好处:范围小、永久保留版式、不需任意上传校验、安全最好、客户体验最好。
形态乙(客户端任意上传 .wps/.doc/.docx):暂不采用;如需开放,另做上传校验/格式兼容,作为独立延展。
② "识别" = 结构化表单字段逐一填(已采用)
- 模板内字段已由你以
{{占位符}}(或书签)预标;前端把表单字段名对齐,后端按名定向替换,无需 AI / NLP。 自然语言一大段话里抽字段:暂不采用;仅在将来接 AI 抽取时再评估,作为可选演进。
基线 = 甲(后台预置模板)+ 结构化字段逐一替换。全文的架构、安全、风险都按此口径收窄。
2. 可行性结论(先给答案)
可行(形态甲 + 结构化字段,见 §1.1)。前提是把"C/D/E 三环"的代码跑在后端——Halo 本身只是纯前端入口。
架构定式(本报告全篇基石):
客户浏览器
│ HTTPS:填结构化表单字段(姓名/金额/日期…)
▼
Halo 博客页面 ←── suy2blog.cn(nginx 反代 halo:8090)
│ 仅承载静态页面 + JS(不跑 word 逻辑;不接收/上传模板)
▼
你控制的后端机/VPS(模板由你后台预置在本机)
├─ 接收字段 JSON
├─ (LibreOffice headless) 兼容 .doc/.wps 占位模板
├─ python-docx 按 {{字段}} 定向填充 + 多份合并
└─ 返回合并后的 PDF
关键结论分三层:
- ✅ 入口层:Halo「页面」本就支持发 HTML/脚本,配
pub.suy2blog.cn或你选的新二级域即可。Halo 无需改插件、无需跑代码。 - ✅ 填充层:真实
.doc/.wps模板差异在于格式兼容链,本报告给出 LibreOffice headless 作为统一格式枢纽的稳妥办法。 - ⚠️ 资源约束:实测博客这台 VPS 仅 2 核 / 2GB 内存,已用 1.4G,且无 soffice/java/node/pip。若执行端也放这台,内存吃紧(LibreOffice 单实例约 300–500MB),需要精简并发或换更大执行机。评估已在 §6 量化。
3. 关键识别 — 填进 Word 的技术选型
识别"客户关键信息"本质是模板变量定位 + 定向替换。由于模板由你预置(§1.1 形态甲),实际就是你预先把字段以占位符/书签标好,后端按名填。三种做法按你手头模板的真实格式(可能本就含 .wps/.doc,或你愿整理成 .docx)排序:
3.1 曲线 A — .docx 原生占位符(推荐主路径,你的预置模板整理为 .docx)
- 你预置模板内写占位符
{{客户名称}}{{金额大写}}{{身份证}},后端一个不漏地替换成 field 数据。 - python-docx(纯 Python,进 zip 改 document.xml)即可逐段定位替换,不影响其它排版,最轻、部署最简单(pip 一个 wheel 就好)。
- 适合结构固定的合同/报价/委托书等。正式做成后台模板时,建议把 .wps/.doc 手头件用 Word/WPS「另存为 .docx」归到本曲线,转换最稳、失真最小、无需每次转码。
- 版式还原靠你预置模板的样式,几乎零失真。
3.2 曲线 B — LibreOffice headless 统一「格式枢纽」(.doc/.wps 也能转)
soffice --headless --convert-to docx "输入.doc" 能把旧式 .doc、甚至部分 .wps 先进 docx;.docx 也可再转 pdf。
- 生态标配,抗杂格式,能覆盖你"类型都可能"的场景,也是 §5 合并与转 PDF 的同一条链,代码量最少。
- 唯一注意:LibreOffice 转 wps 依赖它把 .wps 当 OpenDocument 旧格式读,个别细排版(窗体/特殊宏)可能丢,需样品实测。
- 代价:soffice 要装进执行机,内存偏大。
3.3 曲线 C — 富文本注入(若目标 doc 大量用「书签/表格填空」而非占位符)
某些模板是表格里留空格/书签(如 WPS 表单域)。此时识别不仅是查占位符,还要能定位 书签(TocBookmark) 或第几行第几列表格单元,用 python-docx 遍历 w:bookmarkStart+表逐个填。
- 复杂度线性上升,但更贴近"识别后插入到对应位置"的表述。报告按能支持为准。
前端 offer(备选说明):填字段、合并理论上全在浏览器可做(docx=zip+xml,有 browser-side 库)。但形态甲要后台保留版式一致性与记录,且
.doc/.wps需浏览器外先转码——故本项目不采用纯前端生成,统一由后端处理,前端只做表单采集。
4. 多份 word 合并成一份
| 方案 | 做法 | 保真 | 备注 |
|---|---|---|---|
| docx 原生拼接(推荐,后端 python-docx) | 把多份已填 docx 当作 ZipFile 读,逐段追加 paragraph 进同一 Document,保留每份样式 |
继承主流样式,失真小 | 同段合并时页码/页眉按宿主文档;若要各自分页,段落前插 w:pageBreakBefore |
| LibreOffice 合并 | 若干 docx 先转 pdf 再 pdf merge | 按"每份一屏"融合 | 用于你不想要 word 结构、只要整本 PDF,最简单 |
| Java docx4j | 纯 java 大批量/高保真 | 最高 | 执行机需 JVM,2GB 机器偏重 |
本项目推荐 python-docx 合并(C 端保持 docx),再由同一条 LibreOffice 链转整本 PDF。
5. 整体技术栈(推荐落地)
(前端入口 + 后端处理)推荐默认栈:
后端(执行机) 入口(博客侧 - Halo)
api 服务(FastAPI) ◄─── Halo 静态页面
python-docx(填/合并) (form + JS fetch → 后端)
LibreOffice headless
(.doc/.wps→docx;docx→pdf)
| 角色 | 选型 | 理由 |
|---|---|---|
| 语言 | Python 3.11+ | python-docx 生态最稳、代码最短;执行机现在可能需装 python3-pip |
| API | FastAPI | 自带 OpenAPI,前端能自动出客户端 |
| 填/合 | python-docx | 见 §3/§4 |
| 转 PDF + 兼容 | LibreOffice headless | 一条链满足 .doc/.wps 转 docx 与 docx→pdf |
| 进程 | systemd unit,监听 127.0.0.1 指定端口,nginx 反代对外 | 与本机其它服务一致 |
| 前端 | Halo 单页嵌入 <form>+fetch 到后端 |
纯静态,无插件依赖 |
(若执行机无 JVM,避免 Java/docx4j 路线,python-docx 足够。)
6. 执行机资源核算(实测约束)
博客 VPS 现况(本次实测):
- Debian 13 trixie,2 核 / 1.9GiB,used 1.4G、free 只有 ~100M、available ~515M。
- 已装 python3.13 但无 pip、无 soffice/LibreOffice、无 node、无 java;docker 26 可用。
- 目前仅跑 halo 容器 + nginx。
固 while 执行机能 Docker(已被 docker 可用证实),新增一个处理容器含 FastAPI+soffice,内存需求粗算:
- LibreOffice headless 转一份 office 文档约 200–450 MB 峰值(视模板/字体)。
- python API 服务本身 <120 MB。
- 单并发跑一次约需 350–550 MB。
∴ 如果就在这台 2GB 机器上同时顶着 halo+certbot+authelia,只宜设低并发(1–2),页面给用户提示排队;若想要 3+ 并发或模板很大,建议放到更大规格执行机(4G 或你其它机器),博客 VPS 只做反代。
推荐以「执行机 ≥4G」为基线;若坚持用这台 2GB 博客机,按「低并发 1–2」实现(正文 §6 已量化)。
7. 中文字体与单次耗时(客户感知关键)
中文字体是转 PDF 最常见的坑。
- LibreOffice 容器里若没装中文字体,docx→pdf 会用默认 latin 字体糊掉中文(乱码/方块)。
- 落地方案:执行机/容器内安装中文字体,例如
apt install fonts-noto-cjk fonts-wqy-microhei,并把模板用到的「宋体/黑体/Times」映射到已装字体(fonts 别名表或 soffice 的 fontconfig 配置)。这几行是上线的必要条件,MVP 就要验证。
单次耗时估算(冷启动最常见):
- 首次 soffice 启动 profile 较慢,服务应保持一个常驻 soffice(headless
--accept监听或系统进程方式),不要每次生成都起新实例。 - 单份模板填充 + 转 PDF(几页合同):冷启动可 1–3s,热启动 <1s;多份合并 + 转整本:通常 2–6s。
- 对在线入口几乎无感;只在并发排队的场景提示「正在生成,请稍候」。
8. 安全与鉴权
形态甲(模板后台预置、客户只提交结构化字段)把攻击面收敛得很窄,威胁面主要是表单滥用 + 后端入口暴露 + 生成文件泄露:
- 后端只允许从 nginx 本机(127.0.0.1)进来,不暴露公网;入参做长度/类型白名单(姓名/金额/日期等按字段限制格式)。
- 客户不接触模板文件,因此无任意文件上传/路径穿越/宏风险(LibreOffice 无宏更安全)。模板入库是 后台管理操作(非线上接口),存于只读卷。
- 生成过程跑在独立服务进程/轻量容器,工作目录用临时目录、每请求用完即删,避免残 file 与越权访问常量模板。
- 模板 id 与 PDF 均需权限:
/generate?template=<templateId>应对所用模板类型做权限判断(避免遍历他人成果);返回的 PDF 用一次性临时 URL + 短期失效,视客户场景可加访问口令(复用你的 authelia / 通用口令习惯)。 - 频控与成本:office 转换偏 CPU/内存,需按 IP 做速率限制,防止被刷形成拒绝服务耗光 §6 的低内存预算。
9. 推荐实施节奏(MVP → 增量)
- MVP:固定模板 .docx(含
{{}}占位符)→ FastAPI 一个端/generate(accept 字段 json + 模板 id)→ python-docx 填充 → LibreOffice 转 pdf → 返回二进制。博客页一个<form>(4–8 个字段)。 - 扩展:支持多份模板合并生成一份 PDF;
.doc/.wps模板经 LibreOffice 入库管理(这是你的后台操作,非客户功能,用于兼容旧格式手头模板)。 - 优化:result 缓存、排队提示、在线预览 PDF、结构化日志、后台模板 CRUD(增删改由你维护)。
10. 结论一句话
在单独的后端服务上(python-docx 处理 + LibreOffice headless 转 PDF),把 Halo 当纯前端入口,完全可以在 suy2blog.cn 上线线上 Word 生成+合并 PDF 工具;主要成本在执行机资源 ≥4G 与 .doc/.wps 需先实测一张模板转换保真,二者均可控可行。
