DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

GOhaochen /

GOhaochen/dsh-document-mode

Verified

DSH 公文模式:按 GB/T 9704-2012 呈递公文、圈阅批示与 DOCX 导出,支持热启用/禁用

★ 0 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@d8caf87f

dsh-document-mode · DSH 公文模式

License: GPL-3.0 DSH

让 DeepSeek Harness 像党政机关一样向你呈递公文:回复自动排成 A4 公文页,可圈阅批示, 并可一键导出为真正的 .docx。

本项目复刻 codex-document-mode(B站视频 《让Codex向你呈递公文并接受批示圈阅》)的三块能力,并在 DeepSeek Harness Web GUI 上实现 热启用 / 热禁用;公文版面依据 GB/T 9704—2012《党政机关公文格式》。

能力 实现
① 回复呈递为公文 作用域样式表 + MutationObserver,把助手回复行改造成 A4 公文页:发文机关标志(红头)、发文字号、红色分隔线、标题、主送机关、正文、发文机关署名、成文日期。不替换任何 React 组件。每轮只给最终答复套纸,思考链的中间步骤保持原样。
② 正式文风与申论语气 向 systemPrompt 注册动态段落:公文文风为基底,可叠加申论笔法(提出问题—分析原因—提出对策—总结升华)。关闭时返回空串,空段落不会被装配。
⑤ 中文思考(合并自 dsh-zh-thinking) 再注册一个 systemPrompt 段落,约束内部思考使用简体中文并按【步骤 N|阶段名】组织,含 [调用]/[风险]/[修复] 事件标记与【结论】收束。只约束思考,不改回复内容。
③ 圈阅 输入框上方全宽圈阅栏内 240×80 绘制板:画圈 = 同意,画叉 = 不同意;识别成功写入 【反馈:同意】 / 【反馈:不同意】。栏可关闭(右上角 ×),工具栏「圈阅」按钮可重新展开,开合状态记在 localStorage。
④ 导出 DOCX 工具栏「导出」按钮把最近一份公文导出为真正的 .docx(OOXML):A4、GB/T 9704 页边距、红头、发文字号、红色分隔线、标题、主送机关、正文、落款、表格一应俱全。纯前端生成,无第三方依赖、无需主机参与。

关于中文思考:本能力原为独立插件 dsh-zh-thinking,现已合并进本插件并统一受 公文模式总开关节制——公文模式开启即自动带中文思考,关闭即两者同时静默。 原插件目录可保留作备份,但不应再在 profile 中注册,否则思考规范会被注入两次。

一、版面依据 GB/T 9704—2012

基准取正文 3 号仿宋(16pt),故 1em = 16pt = 5.6444mm;全部几何量由标准毫米值换算为 em,页面随 --dsh-doc-scale 等比缩放(窄屏自动降档)。

标准要素 规定 本插件实现
幅面 A4 210×297mm width: min(37.2em, 100%)(=版心156 + 左28 + 右26)
版心 156×225mm 内容区宽度恒为 27.632em ≈ 156mm
页边距 标准上 37、左 28mm;本渲染左右各 27mm(保证版心 156mm),上下按对话场景收敛 padding: 1.8em 4.784em 3.4em 4.784em
行数×字数 每面 22 行、每行 28 字 line-height: 1.812(225mm÷22≈29pt;标准未规定固定磅值)
正文 3 号仿宋 font-size: calc(16pt * var(--dsh-doc-scale))
发文机关标志(红头) 红色小标宋;标准为"上边缘至版心上边缘 35mm" margin-top: 1.812em(收为空一行,理由见下)
发文字号 3 号仿宋,红头下空二行,居中;年份用六角括号〔〕,序号不编虚位 ::before(节点锚点),margin-top: 3.624em;格式 代字〔年份〕N号,N 取该回复的会话轮次,故依次为 1号、2号、3号……
红色分隔线 发文字号下 4mm,与版心等宽 padding-bottom: .7087em + border-bottom: 2px solid var(--dsh-doc-red)
标题 2 号小标宋,红线下空二行,居中 ::before(正文容器),font-size: 1.375em,margin-top: 3.624em
主送机关 3 号仿宋,标题下空一行,居左顶格,末尾全角冒号 ::after(正文容器,用 order 提到正文之前)
正文 每自然段左空二字,回行顶格 p { text-indent: 2em }
层次序数 一级黑体、二级楷体、三/四级仿宋 段首行内序数按 data-doc-level 套字体;markdown 标题按 h1/h2→黑体、h3→楷体、h4-h6→仿宋
发文机关署名/成文日期 阿拉伯数字标全、年份全称、月日不编虚位;一般右空四字 ::after(行级),padding-right: 4em,2026年10月11日
文字颜色 均为黑色 卡片 color: #000

未实现的标准要素:页码、份号、密级和保密期限、紧急程度、签发人、附件说明、附注、抄送、 印发机关与日期——这些要素在无分页的对话流中没有对应物,强行渲染反而失真。

一处刻意的版面收敛:标准规定红头上边缘距版心上边缘 35mm,该空间是给上述 份号、密级和保密期限、紧急程度三行预留的。这三项在对话场景不适用且未渲染,若照搬, 叠加页面上白边后每页顶部会出现约 72mm 的空白。故本渲染把版头区收敛为空一行, 并把上下纸边压到必要值——这是省略不适用要素的结果,不是对红头字体的改动。

两处已排除的常见误传:

  • 红头 25mm/80mm 属 GB/T 9704—1999 旧规,2012 版统一为 35mm;
  • 成文日期用汉字、"零"写为"○"属 2012 年 7 月前后过渡期说法,2012 版已改为阿拉伯数字。

二、字体

本机已装入完整的公文字体族(来源:下载/796f80c8-….zip 字体包,用户级安装于 ~/.local/share/fonts/gongwen/):

用途 字体栈 本机实际命中
发文机关标志、标题 方正小标宋简体, 方正小标宋_GBK, FZXiaoBiaoSong-B05S, STZhongsong, 华文中宋, SimSun 方正小标宋简体
正文、发文字号、主送机关、署名 仿宋, 仿宋_GB2312, FangSong, FangSong_GB2312, 方正仿宋_GBK, 方正仿宋简体 仿宋(仿真仿宋,非替代字体)
一级层次序数 黑体, SimHei, 方正黑体简体, 方正黑体_GBK 黑体
二级层次序数 楷体, 楷体_GB2312, KaiTi, KaiTi_GB2312, 方正楷体简体, 方正楷体_GBK 楷体

早期版本在本机缺字体时曾用开源替代字体(朱雀仿宋、霞鹜文楷)。现已全部移除, 改用真正的公文字体族。

国标规定的字体与字号(本实现对照)

GB/T 9704—2012 只规定中文号数,不含磅值;下表磅值为通用印刷换算(二号 22pt、三号 16pt、 四号 14pt),实现中以三号 16pt 为基准,故 1em = 16pt = 5.6444mm。

要素 国标字体 国标字号 本实现字体 本实现字号
发文机关标志(红头) 红色小标宋 标准未规定,由机关按"醒目庄重"自定 方正小标宋简体 26pt(一号,本实现自选)
发文字号 仿宋 三号 仿宋 16pt
标题 小标宋 二号 方正小标宋简体 22pt
主送机关 仿宋 三号 仿宋 16pt
正文 仿宋 三号 仿宋 16pt
一级层次序数(一、) 黑体 三号 黑体 16pt
二级层次序数((一)) 楷体 三号 楷体 16pt
三级(1.)/四级((1)) 仿宋 三号 仿宋 16pt
发文机关署名 仿宋 三号 仿宋 16pt
成文日期 仿宋 三号 仿宋 16pt
页码 宋体 四号 —(无分页,未实现) —

两处与标准的取舍已在正文说明:红头字号标准未定,本实现取一号;页码在无分页的对话流中 没有对应物,未实现。

字体栈为何以标准名打头

Linux 的 fontconfig 在找不到某个族名时,会把该名字悄悄替换成 Noto Sans CJK SC(黑体)。 因此字体栈必须写标准族名、且本机确实装有这些字体;否则"font-family 写了却不生效"。

本机已装齐仿宋、仿宋_GB2312、黑体、楷体、楷体_GB2312、方正小标宋简体,故栈序直接以 标准名打头。换到未装公文字体的机器前,请先 fc-match 仿宋 确认命中,否则正文会显示 成黑体。

已安装的字体

~/.local/share/fonts/gongwen/仿宋.ttf
~/.local/share/fonts/gongwen/仿宋_GB2312.ttf
~/.local/share/fonts/gongwen/黑体.ttf
~/.local/share/fonts/gongwen/楷体.ttf
~/.local/share/fonts/gongwen/楷体_GB2312.ttf
~/.local/share/fonts/方正小标宋简体.ttf

均为用户级安装(无需 root),安装后已执行 fc-cache -f。

需要重启浏览器:Firefox / Chrome 在启动时缓存系统字体清单,新装字体要重启浏览器 才会被识别(DSH 服务端不必重启)。

字体授权由使用者自行负责:商用字体请确保取得合法授权。

三、热开关

三处入口绑定同一份实时状态:

  • 输入框工具栏按钮(conversation.input.left,文字「公文」)
  • 设置 → 通用 → 公文模式(settings.general.item:发文机关、主送机关、机关代字、发文字号、 圈阅后自动发送、显示题头、显示落款)
  • 多标签页同步:主机侧 SSE 广播

切换路径:浏览器立即更新 html[data-dsh-doc-mode] → POST /plugins/dsh-document-mode/config → 所有字段均为 schemastery .volatile(),Loader 就地提交(只发 loader/volatile-update, 不重挂插件)→ 值写回当前 profile 的 Cordis patch,重启后保持。

圈阅栏仅在本模式开启时渲染;关闭模式即整条消失。

四、安装

从 GitHub 安装(推荐)

dsh plugin --profile web add github:GOhaochen/dsh-document-mode

本地开发安装

git clone https://github.com/GOhaochen/dsh-document-mode.git
dsh plugin --profile web add link:$(pwd)/dsh-document-mode

dsh plugin add 会同时写入 profile 的 dependencies 与 dsh.profile.bundles,并应用本包的 cordis.patch.yml(insert 一行插件)。

关于 link: 协议:pnpm 在 link: 下不解析 peer 依赖,若裸模块解析报错,可在包内建 node_modules/@deepseek-ai/{schemastery,cordis,cosmokit} 软链指向 profile 的同名包。 github: 安装无此问题。

安装后需让 DSH 重组一次插件树:重启一次 dsh web,或在设置 → 插件里切换任意插件开关。

热重载范围:客户端 bundle(lib/client.js)由 dsh-client-hmr 轮询,改动约 1 秒内热替换, 无需刷新;主机侧代码(lib/index.js)不在 HMR 根内,改动配置字段后需重启一次 dsh web。

五、配置项

字段 默认 含义
enabled true 总开关(热切换)
signature DeepSeek Harness 发文机关标志与署名的机关全称/规范化简称
salutation 尊敬的领导: 主送机关,末尾用全角冒号
issueCode DSH 发文机关代字,用于自动生成发文字号
issueNumber '' 发文字号;留空则按「代字〔年份〕1号」自动生成
autoSend true 圈阅识别成功后自动发送(仅当草稿为空)
showHeader true 显示红头与发文字号、红色分隔线
showSignature true 显示发文机关署名与成文日期
essayTone true 申论语气:按“提出问题—分析原因—提出对策—总结升华”组织回复
thinkingZh true 中文思考:思考过程用简体中文,并按【步骤 N|阶段名】组织

六、端点(均只允许本机回环)

方法 路径 用途
GET /plugins/dsh-document-mode/config 读取当前配置
POST /plugins/dsh-document-mode/config 合并一个配置补丁
GET /plugins/dsh-document-mode/events SSE 状态广播

七、与主题 / 皮肤 / 壁纸的隔离

公文纸恒为"白纸黑字",而 DSH 官方 markdown 组件(MarkdownText、CodeBlock)取色一律走 --dsw-alias-label-* 与 --dsw-alias-markdown-* 令牌。当应用处于暗色主题、或安装了 会重映射令牌的皮肤(例如 blue-fantasy 在 body[data-ds-dark-theme] 下把 --dsw-alias-label-primary 改为 #dbe2f2、把 --dsw-alias-markdown-inline-code 改为 #1e27409e)时,浅色文字会落在白纸上近乎不可见,深色半透明底纹会变成灰块——表现为 "白字 + 半透明轮廓"。

本插件据此在公文页子树内就地重声明这批令牌(正文黑、代码类浅灰、边框与遮罩中性化), 并追加 -webkit-text-fill-color: currentColor 与 text-shadow: none 兜底。这样公文页 自带完整配色,任何主题、皮肤、壁纸下都保持标准要求的白纸黑字,无需停用你的主题插件。

令牌覆盖之外的兜底:!important 白纸黑字归位

实测发现仍有插件会在正文块上留下运行时生成的底色(静态样式表里检索不到),令牌覆盖 压不住,表现为每个段落各自带一块灰色圆角底。故在公文页子树内再加一层强制归位:

/* 正文块一律无底色、黑字、无阴影 */
html[data-dsh-doc-mode="on"] … :is(p, li, blockquote, h1…h6, table, span, strong, em, div…) {
  background-color: transparent !important;
  background-image: none !important;
  box-shadow: none !important;
  text-shadow: none !important;
  backdrop-filter: none !important;
}
/* 代码块与行内代码再单独恢复浅灰底,保持可读 */
html[data-dsh-doc-mode="on"] … pre,
html[data-dsh-doc-mode="on"] … :not(pre) > code { background-color: #f4f4f4 !important; }

这一层与具体插件无关:无论底色来自主题、皮肤还是外观类插件,公文页都只会是白纸黑字。

关于"启用公文模式时自动停用某插件":技术上可行——主机侧 plugin-manager 的 setPluginEnabled(id, enabled) 会把 disabled 覆盖写入 profile 的 cordis.patch.yml, 配合 HMR 即时重组。但此处不建议:皮肤/主题是全局外观,停用它会连带改变整个界面, 且每次切换都要改写 profile 并触发重组,成本与风险都高。令牌覆盖 + !important 归位 是局部、即时且与皮肤无关的正解。若确有需要,可作为可选配置另加。

标题:由"事由 + 文种"合成,文种按内容推断

标准 §7.3.1 要求标题为"发文机关 + 关于 + 事由 + 文种"。原实现直接取回复首句,会出现 "关于收到。字体安装一事收束。本次共完成四项……"这类病句与被截断的括号。现按优先级取事由:

  1. 回复内的标题元素(h1–h6);
  2. 会话标题——它代表整场对话的题旨,比截断首句更接近"事由";
  3. 回复首句,剥掉"收到/好的/明白"等口语开场,过长时退到第一个逗号分句;
  4. 兜底"工作情况 + 文种"。

文种不写死为"报告",由 detectGenre() 按《党政机关公文处理工作条例》的法定文种与 公文惯用收束语推断:

回复特征 文种
妥否,请批示/请予批准/请审批 请示
此复/现批复如下 批复
特此通知/通知如下/请遵照执行 通知
特此函告/敬请函复/请予支持 函
特此通报/通报如下 通报
会议纪要/纪要如下 纪要
提出如下意见/实施意见 意见
其余(陈述事项、汇报进展) 报告

因此标题会随内容变化,例如"关于事项审批的请示"、"关于来函答复的批复"、 "关于工作安排的通知",默认情况下仍是"关于……的报告"。事由已以"关于"开头时只补文种; 事由本身已以文种收尾时原样采用,避免"关于……的报告的报告"。

八、导出 DOCX

工具栏「导出」按钮把最近一份公文导出为真正的 .docx(Office Open XML)。生成在 浏览器内完成,不需要主机接口、不需要额外依赖,也不触发重启。

为什么不用主机侧转换

本机虽装有 LibreOffice,但主机侧转换要新增端点、多一次进程调用,且必须重启 DSH 才生效。 改为前端直接产出 OOXML:即时、离线可用、也不受部署环境影响。

产出内容

部分 实现
页面 w:pgSz A4 11906×16838 twips;w:pgMar 上 2098 / 右 1474 / 下 1984 / 左 1587 twips(37/26/35/28 mm)
行距 w:line="580" w:lineRule="exact"(29pt 固定值);w:docGrid w:linePitch="580"
红头 红色(E60012)方正小标宋简体,居中
发文字号 3 号仿宋,居中,格式 代字〔年份〕N号
红色分隔线 段落底边框 w:pBdr/w:bottom,与版心等宽
标题 2 号方正小标宋简体,居中
主送机关 3 号仿宋,顶格
正文 3 号仿宋,w:firstLineChars="200"(首行缩进 2 字),两端对齐
层次序数 h1/h2 黑体、h3 楷体、h4–h6 仿宋加粗
列表/代码/表格 列表加项目符号;代码块用 Consolas;表格转为带细边框的 w:tbl
落款 3 号仿宋,w:rightChars="400"(右空 4 字),阿拉伯数字成文日期

字体:导出件写入标准公文字体名

导出件直接写标准族名,本机 Word / LibreOffice 打开即所见即所得,在中文版 Windows 与 WPS 上同样可用:

用途 写入 .docx 的族名
正文、发文字号、主送机关、署名的仿宋 仿宋
红头与标题的小标宋 方正小标宋简体
一级层次序数的黑体 黑体
二级层次序数的楷体 楷体

若需更严格地贴合标准名,可把 DOCX_FONT.fangsong 改为 仿宋_GB2312、kaiti 改为 楷体_GB2312(两者本机均已安装)。

技术实现

.docx 本质是一个 ZIP,含 [Content_Types].xml、_rels/.rels、 word/_rels/document.xml.rels、word/styles.xml、word/document.xml。本插件用 **STORE(不压缩)**方式自建 ZIP 容器(自带 CRC32 表与中央目录),因此不依赖 CompressionStream,在任意浏览器上都能用;单份文档约 15–70 KB。

验证

node test/docx.mjs /tmp/sample.docx   # 用真实发行包生成样例
unzip -t /tmp/sample.docx             # 容器完整性
file /tmp/sample.docx                 # 应为 "Microsoft Word 2007+"
soffice --headless --convert-to txt --outdir /tmp /tmp/sample.docx   # 解析验证

实测:unzip -t 无错误,file 识别为 Microsoft Word 2007+,LibreOffice 可正常解析并 导出全文;页边距、行距、首行缩进、右空四字、红头色值、公文字体名均正确写入。

九、实现要点

  • DOM 锚点全部使用 DSH 官方稳定契约,不依赖 CSS-module 哈希类名。
  • 伪元素分工:行级 ::before/::after 承担红头与落款;槽位锚点承载发文字号与红色分隔线; 正文容器承载标题与主送机关。三者都是纵向弹性盒,用 order 把 ::after 提到正文之前—— 这是同一元素只能有一个 ::before 时的必要技巧。
  • 样式表带 data-plugin="dsh-document-mode",HMR 卸载时由模块系统回收。
  • 公文纸门控在 data-doc-paper 上,而该属性只由 decorateAll() 打在「每轮最后一个节点」上。 官方用 kind === 'assistant-step' && step === answerStep 判定最终答复,意味着思考链的每个 分步也是 assistant-step;若按 kind 直接套版面,每个思考步骤都会变成一整张红头白纸。 故按 data-chat-turn 分组,只保留每轮 DOM 顺序里的最后一个节点,其余节点用 clearDecoration() 撤掉装饰。
  • 失败降级:主机侧挂载动作全部包在 try/catch 内,任一服务缺失时插件保持惰性。
  • 代码块、命令、日志、表格在公文页内仍保持等宽原格式。

十、验证

node test/verify.mjs

103 项检查,覆盖:bundle 以经典脚本求值、模块 id 与包名一致、inject/apply 形状、根属性、 样式表注入与 data-plugin 标记、选择器作用域无泄漏、四处 attr() 装饰、 display:contents 提升为弹性盒、14 项 GB/T 9704—2012 版面参数(幅面/页边距/字号/行距/ 红头 35mm/分隔线 4mm/标题空二行/主送机关空一行/首行缩进 2 字/右空四字/字体栈)、 4 项公文要素内容规则(红头仅机关名、发文字号六角括号且不编虚位、阿拉伯数字日期、 汉字日期已移除)、7 项层次序数分层规则(一、/(一)/1./(1)→ 黑体/楷体/仿宋, 且序数与正文同段时不误涂),圈阅画板尺寸与槽位注册数量,以及从发行源码中提取的 圈阅分类器。

十一、已知边界

  • 圈阅使用笔画几何启发式(质心半径比 + 角覆盖 + 过心次数),非机器学习模型;信心不足时 不写入任何内容,避免误判。
  • 公文标题按"事由 + 文种"合成(详见第七节)。事由优先取回复标题,其次取会话标题,再次取 回复首句;因此同一会话内各条回复的标题通常相同——这符合"一场对话即一份公文"的语义, 但若你希望每条回复各自成题,可调整优先级。GB/T 9704 规定的"梯形/菱形"回行排布仍由 浏览器断行决定,未做人工断行。
  • 发文机关署名与成文日期统一按"右空四字"右对齐;标准 §7.3.5.2 针对不加盖印章公文另有 "日期首字比署名首字右移二字"的弹性算法,需实测文本宽度,未实现。
  • 层次序数只在整段为标题行(序数之后无句末标点)时套用对应字体。若写成 "一、总体要求。坚持稳中求进……"这类序数与正文同段的形式,整段仍是仿宋——CSS 无法只给 行首几个字换字体,这是浏览器渲染的硬限制。

十二、变更记录

v0.2.0(2026-11-07)

  • 合并 dsh-zh-thinking:中文思考规范并入本插件,作为第二个 systemPrompt 段落 (dsh-zh-thinking:reasoning-style,order 450,沿用原标识),随公文模式统一启停。
  • 新增申论语气:renderStyleGuide() 追加「提出问题—分析原因—提出对策—总结升华」行文脉络, 并附不改写事实的护栏。
  • 新增配置项:thinkingZh、essayTone,可在设置面板独立关闭。
  • 新增测试:test/host.mjs,29 项主机半断言(配置投影、文本渲染、section 注册与开关联动)。
  • 原 dsh-zh-thinking 插件应从 profile 中移除,避免思考规范重复注入。

v0.1.0(2026-10-26)

  • 首次发布:GB/T 9704—2012 公文版面、正式文风约束、圈阅反馈、DOCX 导出、 热启用/热禁用。

免责声明

  • 本项目为个人技术实践,与 DeepSeek、OpenAI、任何党政机关均无关联,亦非官方产品。
  • 生成的公文仅为格式演示,不具备任何法定效力,不得用于伪造真实公文或冒充机关行文。
  • 版式依据 GB/T 9704—2012 公开标准,但属于近似实现,不保证与正式排版软件逐像素一致。
  • 字体授权由使用者自行负责:公文常用字体(方正小标宋、仿宋、黑体、楷体等)多为商业 字体,请确保已取得合法授权后再安装使用。

许可

本项目采用 GNU General Public License v3.0 许可,全文见 LICENSE。

Copyright (C) 2026 GOhaochen

本程序是自由软件:你可以依据自由软件基金会发布的 GNU 通用公共许可证(第 3 版或你选择的 任何更高版本)条款重新发布和/或修改它。本程序基于"有用"的目的发布,但不提供任何担保, 甚至不包含适销性或特定用途适用性的默示担保。详见 GNU 通用公共许可证。

注:仓库内 LICENSE 为 GPLv3 标准全文;package.json 中 SPDX 标识记为 GPL-3.0-only。若你希望采用"第 3 版或更高版本"的表述,把该字段改为 GPL-3.0-or-later 并在源码头部补充相应声明即可。

—/ 5

No ratings yet

Verified DSH bundle

Commit d8caf87f7855

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout