从Markdown到Typst:大一新生vibe coding转译器实录

从Markdown到Typst:大一新生vibe coding转译器实录

声明:本文出现的所有博客内容均来自互联网公开内容仅作工具效果验证,不作商业用途 ,不代表作者观点。如原作者认为不妥请联系我,我将立刻替换测试用例。

0.我为什么会想要做这个项目

大一开学,我开始迷上了看博客,觉得博客里面的知识很前沿对我很有帮助。但是博客网站的广告太多了,而且我本人很喜欢手写批注,产生了去广告和排版的需求,于是我开始筹划做自己的排版工具,做出来以后自己用了下发现效果很好:

等到回过头来看才发现自己做了个转译器,难掩激动之情所以想要写个博客纪念一下。

1.我的技术选型之路

我一开始并没有想到简悦这样的去广告插件,所以我的思路是LLM做语义筛选 ,从语义上把广告去掉。我在自己的AI树洞里谈论这件事的时候无意知道了all2md可以把HTML转换成Markdown,个人认为因为LLM训练的时候大部分数据都是Markdown形式的所以让LLM读Markdown比读HTML效果更好,语义理解更准确,我就从这里开始构思管道。

一开始我是想要这样的管道设计的:

复制代码
     归一化           LLM提取语义          附上CSS
HTML-------->Markdown----------->文本内容--------->网页--------->打印

但是看到我们学校大物实验网站在电脑上操作效果很好但是一旦在手机上打开交互模式变成了地狱,网页的流式排版如果落到A4上未必可以保证排版效果 ,对于我来说,产物必须是可以打印成纸质版本小册子的PDF文件,我意识到我必须用专业的排版语言了。

我把我的管道落实进README里和Deepseek交流了一下,Deepseek给了我两个排版引擎一个LaTex一个Typst,个人感觉LaTex太重了语法太长了所以我选择了轻量级的Typst。但是Markdown的语法和Typst差异有点大,如果让LLM直接提取的话容易出现语法错误渲染失败。于是我想到两个语言都可以算是编程语言(个人理解勿喷),可以通过抽象语法树 作为中间表示,再加上schema校验保证LLM吐出来的AST是符合要求可以被Typst编译的。

目前的管道如下所示:

复制代码
用户需求:把这篇文章排成看得清、能打印、能上手批注的纸质文档
  │
  │  python -m ep.cli build --from-ast doc.json -o out.pdf --theme article-annotated
  ▼
[1] 归一化 normalize ------ 确定性 · 静态工具(基于 all2md)
    html / md / pdf   ->  规范 Markdown
    只做格式转换,不做任何排版判断;PDF 仅支持纯文本型
  ▼
[2] 语义化 semanticize ------ LLM · 全流程唯一需要模型的环节
    规范 Markdown  ->  语义 AST (doc.json)
    只决定「这段内容是什么」,不决定字号/颜色/边距/版式
    不输出 toc 节点:目录由 gate 从 heading 自动生成,页码由 Typst 计算
  ▼
[3] 渲染 render ------ 确定性 · Typst
    doc.json + theme.tokens.json  ->  doc.typ  ->  typst compile  ->  out.pdf
    页码、图号、章号、交叉引用、运行页眉、PDF 书签 全部由 Typst 计算
  ▼
[4] 自检 validate ------ 确定性 · 6 项硬指标
    AST schema / 页边溢出 / 字体嵌入 / 图片有效 DPI / 目录一致性 / 封面单页
    失败 -> 结构化报告交给 agent 修复后重跑(≤3 次);仍失败则终止,不发布任何交付物
  ▼
[5] 发布 publish ------ 全有或全无
    通过才由 publish() 原子写入发布目录/<title>-<artifact-id>.pdf
    交付物内嵌 artifact_id,可用 python -m ep.cli verify 独立复核;
    不通过时发布目录里不会多出任何文件(诊断包留在 work/,不算交付物)

2.管道建设之路

定义好了管道,那我就开始着手vibe coding。我担心AI乱写代码给我写出屎山,于是我先让起草架构的会话把各个模块的开发要点和可编译代码落实到agent_development.md里面。

紧接着我新开了一个会话作为红队专门审查上一个会话留下来的开发要点有没有矛盾的地方,代码里面有没有P0级的bug(有一个会话因为过拟合了逮着个漏洞就说P0,我怒开新会话)

最后我单独开了一个会话专门用来搬砖,因为我把可编译代码留在了开发文档里,给LLM脑补的空间非常有限确保了稳定性。

做完整体以后我用提示词工程让LLM生成了一份类似于白皮书的主题模板,做成了现在我的项目里的theme.json。

3.数据解耦之路

一开始的V1.0最方便的方式是把下载下来的博客网页丢进工作区,但这样的方式后面我提交github很容易把网页的内容提交上去。于是我效仿我自己目前正在做的AIOJ,做了个ep.workspace.json用json作为我的工作区配置

字段 作用
version 工作区配置版本号
source_dir 网页来源,在编程平台指定<name>后去source_dir/<name>文件夹下找文件
output_dir 产物落在output_dir/<name>文件夹内

4.排版优化之路

其实一开始用的时候算是磕磕绊绊吧,AI可以帮我生成一个看上去很不错的模板,但是自己用的时候发现AI生成的theme.json只是个毛坯房,真把AST和theme.json交付给typst编译发现有好几处地方是重叠的。而且中文下两端对齐会导致行间距不均匀看着反而更难受。

我只好一点点微调行间距,把两端对齐改成左端对齐,才有了开头的效果。

5.开源合规之路

做完V1.1之后我觉得神功大成,于是打上了GPL3.0 ,打完以后的某一天刷B站看到协议污染感觉有点害怕,作为一个开源萌新我就让AI看看有没有出现协议污染,一开始我做V1.0图省事用Windows内置字体的回旋镖丢了过来,我在GPL3.0的项目里放了闭源字体,我只好紧急下载开源字体进系统然后把所有闭源字体换成开源。我舍不得我那些commit记录又不想git回溯搞崩仓库只能在README里面留了一句

由于本人初入开源社区未注意字体问题误使用闭源字体并打tag导致旧版本出现协议污染,现已修正,已发布新版本v1.2。特此声明

做完之后我还顺便补充了all2md和typst的协议。

我实在想说,Windows装个字体体验真是拉跨完了,完全没法全自动导致我release的时候只能委委屈屈的把我用到的字体文件打包进仓库,真难绷!

6.架构抉择之路

    1. 为什么没有选择网页打印?(流式排版放到A4容易崩盘)
    1. 为什么用typst不用LaTex?(轻量化)
    1. 如何解决LLM幻觉?(用schema死门禁,不通过无产物。巧妇难为无米之炊)

7.写到最后

目前这个项目已经打上了V1.3的tag,目前仓库可以被clone下来使用。个人自测排版HTML网页目前稳定(当然也有可能是我没看到过很极端的博客) , 但是知网论文PDF 会出现图片全黑的情况,不支持复杂化学式,复杂的LaTex公式,LaTex公式支持请见docs/LaTex_test.md。以下是仓库链接

https://github.com/RobertTerisa/EssayPrinter

欢迎各位使用,如果有问题可以在此博客下评论或者提issue,如果好用给我点个star,谢谢!

相关推荐
泯泷2 小时前
AI 社交的真问题:助理拥有“我”,平台拥有“别人”
人工智能·llm·agent
泯泷14 小时前
让 Agent 分清“马上办、等一等、顺手办”
人工智能·llm·agent
泯泷16 小时前
语音,正在成为 AI Agent 最自然的接口
人工智能·llm·agent
泯泷18 小时前
该 SFT、RL 还是 Mid-training?先搞清楚模型到底"缺"了什么
llm·agent·强化学习
泯泷20 小时前
SFT 的真相:它不教模型"知道什么",只教它"怎么说"
人工智能·llm·agent
泯泷1 天前
为什么 RL 比 SFT 更会"举一反三"?
人工智能·llm·agent
泯泷1 天前
模型"缺课"了:为什么该补底座,而不是急着上 RL
llm·agent·强化学习
泯泷1 天前
RL 训练真正难的不是算法:环境、奖励与样本效率
llm·agent
Baihai_IDP2 天前
RAG vs SKILL vs MCP vs RLM
llm·agent·mcp