Files
deep_research/.opencode/skills/pdf-reportlab/SKILL.md
T
2026-04-21 12:31:58 +08:00

8.2 KiB
Raw Blame History

name, description
name description
pdf-reportlab 用 ReportLab 生成专业中文 PDF 研究报告。包含思源宋体/黑体+霞鹜文楷的字体注册、集中样式管理、封面/目录/正文/参考文献多页模板、matplotlib 图表嵌入。dr-reporter 用于 Phase 4 出 PDF 稿;也可被用户直接调用渲染单章。

ReportLab 中文 PDF 模板使用指南

一、为什么是 ReportLab

  • 完全可控:每个字号、行距、缩进都是代码说了算,不像 CSS/LaTeX 会被引擎意外改变
  • 中文字体一次搞定pdfmetrics.registerFont 注册后全局可用,子集嵌入 PDF,分发无忧
  • 速度快:纯 Python30,000 字报告 3-5 秒出稿(matplotlib 图表预渲染后)
  • 图表质量高matplotlib 生成 300 DPI PNG 嵌入,比 LaTeX 的 pgfplots 快得多
  • 样式集中:用 StyleSheet 管理,避免你之前碰到的"中文字号不一"问题

二、项目模板入口

模板脚本:.opencode/templates/report-template.py

调用方式:

python3 .opencode/templates/report-template.py \
    --input projects/<slug>/phase4/final.md \
    --manifest projects/<slug>/manifest.json \
    --output projects/<slug>/phase4/final.pdf \
    --fonts-dir .opencode/templates/fonts

首次运行前必须:

bash .opencode/templates/fonts/download-fonts.sh

三、字体注册(模板已封装,此处仅说明原理)

from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont

# 思源宋体 = 正文
pdfmetrics.registerFont(TTFont('SrcSerif',      'fonts/SourceHanSerifSC-Regular.otf'))
pdfmetrics.registerFont(TTFont('SrcSerif-Bold', 'fonts/SourceHanSerifSC-Bold.otf'))
pdfmetrics.registerFontFamily('SrcSerif', normal='SrcSerif', bold='SrcSerif-Bold')

# 思源黑体 = 标题/UI
pdfmetrics.registerFont(TTFont('SrcSans-Light',  'fonts/SourceHanSansSC-Light.otf'))
pdfmetrics.registerFont(TTFont('SrcSans-Medium', 'fonts/SourceHanSansSC-Medium.otf'))
pdfmetrics.registerFont(TTFont('SrcSans-Bold',   'fonts/SourceHanSansSC-Bold.otf'))
pdfmetrics.registerFont(TTFont('SrcSans-Heavy',  'fonts/SourceHanSansSC-Heavy.otf'))

# 霞鹜文楷 = 引文/摘要
pdfmetrics.registerFont(TTFont('Kai', 'fonts/LXGWWenKai-Regular.ttf'))

关键TTFont 虽然类名含 "TT",但也接受 .otfOpenType),别犹豫。


四、样式表(集中管理,避免字号不一)

所有样式集中在模板的 build_styles() 函数:

样式名 字体 字号 行高 用途
body SrcSerif 10.5 18 正文
body-bold SrcSerif-Bold 10.5 18 术语
h1 SrcSans-Bold 18 28 章标题
h2 SrcSans-Bold 14 22 section 标题
h3 SrcSans-Medium 12 18 sub-section
quote Kai 10.5 18 引文、摘要
caption SrcSans-Medium 9 13 图表标题
footnote SrcSerif 9 13 脚注/参考文献
header-footer SrcSans-Light 8 12 页眉页脚
cover-title SrcSans-Heavy 32 42 封面大标题

行高 = 字号 × 1.5~1.7,不要用默认值。


五、报告 11 件套结构

模板会按以下顺序生成页面:

  1. 封面页PageTemplate: cover

    • 主标题:cover-title
    • 副标题:h2
    • 作者、日期:body
    • 单独版心,无页眉页脚
  2. 免责声明PageTemplate: normal

    • 固定模板,来源 manifest.json 的 disclaimer 字段
  3. 执行摘要Executive Summary

    • quote 样式,1-2 页
    • 来源 final.md 的 ## 摘要
  4. 术语表

    • 两列表格,术语+解释
    • 来源 final.md 的 ## 术语表
  5. 目录

    • 自动从 h1/h2 生成,支持超链接
  6. 主体正文

    • 来源 final.md 的各 ## 第 N 章 ...
    • 页眉:左=主题缩写 / 右=章节名
    • 页脚:居中页码
  7. 结论与建议

    • final.md 的最后一章
  8. 参考文献

    • 来源 projects/<slug>/phase4/citations.bibsources.jsonl
    • 按引用顺序编号,GB/T 7714 格式
    • footnote 样式
  9. 附录 A:数据表(可选)

  10. 附录 B:方法论说明(可选)

  11. 版本信息

    • 生成时间、版本号、生成者(dr-reporter)、字数统计

六、图表嵌入规范

不要用 ReportLab 原生绘图,全部预渲染为 PNG

# 在 dr-analyst / dr-reporter 阶段,用 matplotlib 出图
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm

# 注册中文字体给 matplotlib
font_path = '.opencode/templates/fonts/SourceHanSansSC-Medium.otf'
fm.fontManager.addfont(font_path)
plt.rcParams['font.family'] = 'Source Han Sans SC'
plt.rcParams['axes.unicode_minus'] = False

fig, ax = plt.subplots(figsize=(6, 4), dpi=150)
# ...绘图代码
plt.savefig('projects/<slug>/phase4/figures/fig_01_market_size.png', dpi=300, bbox_inches='tight')

然后在 final.md 里用标准 Markdown 引用:

![图 12020-2025 GLP-1 市场规模](figures/fig_01_market_size.png)

模板会自动:

  • 按 Markdown 解析图片
  • caption 样式渲染标题
  • 图表居中,宽度适配页宽

七、Markdown → ReportLab 的支持范围

模板支持以下 Markdown 元素:

Markdown ReportLab 渲染
# 标题 h1(章标题,自动分页)
## 标题 h2section,不分页)
### 标题 h3sub-section
**粗体** <b> inline
*斜体* <i> inline
`代码` 等宽字体 inline
> 引文 quote 样式块
- 列表项 / 1. 项 项目符号列表
表格| | | ReportLab Table,自动列宽
![caption](path) 图片 + caption
[src_001] 上标引用链接到参考文献
--- 分页符(PageBreak

不支持(请在 Markdown 里避免):

  • HTML 标签(除少数 inline
  • 数学公式(后续可加 matplotlib 渲染)
  • 代码块高亮(只保留等宽显示)

八、manifest.json 的必需字段

{
  "slug": "glp1-obesity-2026",
  "topic": "GLP-1 减重药物竞争格局与投资机会",
  "subtitle": "2026 年产业深度研究",
  "author": "Deep Research 系统 v0.1",
  "date": "2026-04-20",
  "type": "研究类",
  "version": "1.0",
  "disclaimer": "本报告基于公开信息与 AI 辅助研究生成,仅供参考,不构成投资建议。",
  "cover_theme": "blue"
}

九、常见坑与对策

对策
中文字号不一 集中 StyleSheet,不在 Paragraph 里 inline 改 fontSize
行距太挤 行高 = 字号 × 1.5~1.7,不要用默认
换行断错 wordWrap='CJK' 必设
字体子集缺字 用完整版思源字体(非 subset 精简版)
图片变形 先 matplotlib 出 300 DPI PNG,再 Image(path, width=..., height=...)
页眉页脚重叠 BaseDocTemplate + PageTemplateFrame 的 margin 留足
英文中文混排间距怪 思源系列自带 CJK metrics,间距会自适应,一般不用额外处理
生成慢 matplotlib 图表预渲染,不要在 PDF 生成阶段现算

十、调用流程(dr-reporter 阶段)

1. 检查字体:ls .opencode/templates/fonts/*.otf | wc -l ≥ 6
2. 检查输入:projects/<slug>/phase4/final.md 存在
3. 检查配置:projects/<slug>/manifest.json 有必需字段
4. 执行:
   python3 .opencode/templates/report-template.py \
       --input projects/<slug>/phase4/final.md \
       --manifest projects/<slug>/manifest.json \
       --output projects/<slug>/phase4/final.pdf
5. 验证:
   - PDF 打得开
   - 文件大小 > 500KB(太小说明字体没嵌)
   - 页数合理(30,000 字约 60-80 页)
6. 汇报:输出路径、页数、文件大小

十一、MVP 阶段注意

目前(MVPreport-template.py基础版,支持:

  • 思源字体注册
  • 标题 / 正文 / 引文 / 表格 / 图片
  • 简单封面 + 目录
  • 参考文献自动编号

暂未实现Phase 4 能力阶段补齐):

  • 自动书签/大纲(PDF navigation pane
  • 交叉引用("见第 3 章"自动跳转)
  • 复杂页眉(左右对称排版)
  • 附录 B 自动生成(方法论模板)

如需上述功能,在 manifest.json 里标 "template_features": ["bookmarks", "xref", ...],未来版本会处理。