Files
deep_research/.agent/skills/pdf-reportlab/SKILL.md
T

304 lines
9.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: pdf-reportlab
description: 用 ReportLab 生成专业中文 PDF 研究报告。集中样式管理、紧凑分页(widows/orphans/keepWithNext)、颜色层次、封面保密标识、页眉页脚简洁化。基于 9MW1911 综合战略报告的编排参考。
---
# ReportLab 中文 PDF 模板使用指南(v0.5)
## 一、为什么是 ReportLab
- **完全可控**:每个字号、行距、颜色由代码说了算,不被引擎意外改动
- **中文字体一次搞定**`pdfmetrics.registerFont` 注册后全局可用,子集嵌入 PDF,无授权问题
- **分页规则精确**:支持 widows/orphans、keepWithNext、splitByRow 等避免孤行/寡行
- **图表嵌入高质量**matplotlib 300 DPI PNG,速度快
- **样式集中在 StyleSheet**:避免字号不一
---
## 二、模板入口
脚本:`.opencode/templates/report-template.py`
调用:
```bash
uv run python .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
bash .opencode/templates/fonts/download-fonts.sh
```
---
## 三、字体注册(7 个字重)
```
SrcSerif-Regular 思源宋体 Regular 正文
SrcSerif-Bold 思源宋体 Bold 正文粗体
SrcSans-Light 思源黑体 Light 页眉页脚
SrcSans-Medium 思源黑体 Medium 三级标题/图表
SrcSans-Bold 思源黑体 Bold 一二级标题
SrcSans-Heavy 思源黑体 Heavy 封面大标题
Kai 霞鹜文楷 Regular 摘要/引文
```
---
## 四、样式表(StyleSheet,集中管理)
| 样式名 | 字体 | 字号 | 行高 | 颜色 | 备注 |
|---|---|---|---|---|---|
| `body` | SrcSerif | 10.5 | 18 | `#1a1a1a` | 正文,首行缩进 21pt |
| `body-bold` | SrcSerif-Bold | 10.5 | 18 | `#1a1a1a` | 行内加粗 |
| `h1` | SrcSans-Bold | 18 | 28 | `#1e3a8a` | 章标题,前强制分页 |
| `h2` | SrcSans-Bold | 14 | 22 | `#2c5282` | 节标题 |
| `h3` | SrcSans-Medium | 12 | 18 | `#374151` | 小节标题 |
| `quote` | Kai | 10.5 | 18 | `#4b5563` | 引文 |
| `caption` | SrcSans-Medium | 9 | 13 | `#6b7280` | 图表标题 |
| `footnote` | SrcSerif | 9 | 13 | `#374151` | 脚注/参考文献 |
| `header-footer` | SrcSans-Light | 8 | 12 | `#9ca3af` | 页眉页脚 |
| `cover-title` | SrcSans-Heavy | 28 | 40 | `#0f172a` | 封面主标题 |
| `cover-subtitle` | SrcSans-Medium | 15 | 24 | `#475569` | 封面副标题 |
| `cover-confidential` | SrcSans-Bold | 11 | 16 | `#dc2626` | 封面保密标识(红色)|
| `cover-meta` | SrcSerif | 11 | 18 | `#334155` | 封面元信息 |
| `summary` | SrcSerif | 11 | 20 | `#1a1a1a` | 执行摘要 |
---
## 五、分页规则(关键升级点)
### 章(h1
- `pageBreakBefore=1`(每章新起一页)
- `keepWithNext=1`(标题和下一段不分离)
### 节(h2
- **禁止单独触发分页**
- `keepWithNext=1`(标题紧跟内容)
### 小节(h3
- 同 h2`keepWithNext=1`
### 段落
- `widows=2, orphans=2`(避免寡行/孤行)
- 每段之间 `spaceBefore=6, spaceAfter=6`
### 表格
- `TableStyle` 中启用 `splitByRow=True`(长表格按行分页)
- `repeatRows=1`(表头在分页后重复)
- 单元格 padding 统一 4-6pt
### 摘要/术语表/目录/参考文献
- 每个独占起始页(用 `PageBreak`
---
## 六、封面模板(参考 9MW1911)
封面独立一页,无页眉页脚,布局:
```
(上 30% 空白)
主标题(cover-title,黑色,居中)
副标题(cover-subtitle,深灰,居中)
(中部 40% 空白)
[机密 | 仅供 XX 内部决策使用] cover-confidential,红色,居中)
(下部 20%
类型:研究类
作者:Deep Research 系统 / <公司名>
编制日期:YYYY 年 M 月
版本:v1.0
```
字段来源:
- `manifest.report_title` / `report_subtitle`
- `manifest.confidentiality` (如 "机密 | 仅供迈威生物内部决策使用")
- `manifest.author` / `manifest.date` / `manifest.version`
---
## 七、页眉页脚(简洁化)
### 页眉
左边:报告简称(从 `manifest.report_title` 取前 15 字)
右边:章节名(动态,从当前 h1 内容取)
底线:`#e5e7eb` 浅灰分隔线
### 页脚
居中:页码(格式 `— X —`
字号:8pt`#9ca3af` 浅灰
### 特殊页
- 封面:无页眉页脚
- 免责声明:无页眉,仅页脚
- 其他(摘要/术语表/目录/正文/附录/参考文献):有页眉页脚
---
## 八、报告结构(11 件套)
ReportLab 按以下顺序组装:
1. **封面**cover PageTemplate
2. **免责声明**normal PageTemplate,单页)
3. **Executive Summary / 执行摘要**summary PageTemplate1-2 页)
4. **Abstract / 摘要**normal,单页)
5. **Glossary / 术语表**normal
6. **Table of Contents / 目录**TOC,自动生成)
7. **正文各章**(normal,每章 h1 强制分页)
8. **结论与建议**(正文的一部分)
9. **附录**normal
10. **参考文献**bibliography PageTemplatefootnote 样式)
11. **版本信息**normal,单页)
---
## 九、Markdown 支持范围
| Markdown | ReportLab 渲染 |
|---|---|
| `# 第 X 章 ...` | h1(新起一页,深蓝色)|
| `## X.Y ...` | h2(节,蓝色,不分页)|
| `### X.Y.Z ...` | h3(小节,深灰)|
| `**粗体**` | inline `<b>` |
| `*斜体*` | inline `<i>` |
| `` `代码` `` | 等宽字体 |
| `> 引文` | quote 样式(楷体,浅底色)|
| `- 项` / `1. 项` | 项目符号列表 |
| 表格 `\| \| \|` | Table,自动列宽 + splitByRow |
| `![caption](path)` | 图片 + caption 样式 |
| `[src_001]` | 上标引用 |
| `---` | 分页符 |
**不支持**:HTML 标签、数学公式、代码块高亮。
---
## 十、图表嵌入
不用 ReportLab 原生绘图,全部预渲染为 PNG:
```python
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
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=300)
# ...
plt.savefig('projects/<slug>/phase4/figures/fig_01_XXX.png', dpi=300, bbox_inches='tight')
```
Markdown 中引用:`![图 1-12020-2025 GLP-1 市场规模(数据来源:[src_042]](figures/fig_01_XXX.png)`
---
## 十一、manifest 必需字段
```json
{
"slug": "...",
"report_title": "自研 O-糖苷酶立项可行性研究报告",
"report_subtitle": "对标 NEB 与 Merck 经典产品的技术路径、IP 壁垒与差异化战略",
"confidentiality": "机密 | 仅供内部决策使用",
"author": "Deep Research 系统",
"date": "2026-04-21",
"version": "1.0",
"type": "研究类",
"disclaimer": "本报告基于公开信息与 AI 辅助研究生成,仅供参考..."
}
```
---
## 十二、常见坑与对策
| 坑 | 对策 |
|---|---|
| 中文字号不一 | 集中 StyleSheet,不在 Paragraph 里 inline 改 fontSize |
| 行距太挤 | 行高 = 字号 × 1.5~1.7 |
| 换行断错 | `wordWrap='CJK'` 必设 |
| 表格被截断 | `splitByRow=True, repeatRows=1` |
| 标题孤行(页末一个标题后直接新页)| `keepWithNext=1` |
| 段落寡行(末段只剩一行在下页)| `widows=2, orphans=2` |
| 图片变形 | 先 matplotlib 出 300 DPI PNG,再 `Image(path, width=..., kind="proportional")` |
| 生成慢 | matplotlib 图表预渲染,不要在 PDF 生成阶段现算 |
| 参考文献丢失 | dr-reporter 出稿前检查:读 citations.md,确认内容已写入 final.md |
---
## 十三、dr-reporter 调用流程
```
1. 环境检查
- 字体 ≥6 个 OTF 文件
- final.md 存在
- manifest.json 有必需字段
2. 回填参考文献(关键步骤,修复 v0.4 的 bug)
- 读 citations.md 内容
- 在 final.md 中找到"## 参考文献"段落
- 如果段落内容是占位符(如 "[由 dr-reporter 自动生成]" 或为空)
→ 替换为 citations.md 的完整内容
- 写回 final.md
3. 图表检查
- 扫描 final.md 中所有 ![...](path) 图片引用
- 验证每个 path 在 figures/ 目录下存在
- 缺失图片 → 警告并继续,但汇报中注明
4. 生成 PDF
uv run python .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
5. 生成 DOCX(可选)
pandoc projects/<slug>/phase4/final.md \
--from markdown --to docx \
--output projects/<slug>/phase4/final.docx \
--toc --toc-depth=3
6. 验证
- PDF 文件大小 > 500KB(太小说明字体没嵌)
- PDF 页数合理(按字数估算)
- "参考文献"章节存在且非空
7. 汇报
```
---
## 十四、输出卫生检查(必跑)
生成 PDF 前:
```bash
# 加载 skill:output-hygiene
python3 .opencode/templates/hygiene_check.py projects/<slug>/phase4/final.md
```
禁止词残留 → 抛回 dr-polisher 再润色一轮。