bit-ppt-generator 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +118 -50
- package/package.json +10 -2
- package/src/http-server.mjs +86 -2
- package/src/layout-guides.mjs +409 -1
package/README.md
CHANGED
|
@@ -6,6 +6,25 @@
|
|
|
6
6
|
项目目标不是把幻灯片截图塞进 PPT,而是尽量生成原生 Office 对象:
|
|
7
7
|
文本框、形状、表格、图表、图片和 Office Math 公式都应保持可编辑。
|
|
8
8
|
|
|
9
|
+
在线测试地址:[http://47.109.207.16:8080/](http://47.109.207.16:8080/)
|
|
10
|
+
|
|
11
|
+
欢迎试用并在 [GitHub Issues](https://github.com/yang-kun-long/bit-ppt-template/issues)
|
|
12
|
+
反馈问题、语法建议、版式需求或生成失败案例。
|
|
13
|
+
|
|
14
|
+
## 项目来源与相关路线
|
|
15
|
+
|
|
16
|
+
本项目的视觉风格和最初需求来自 TeXPage 上的北京理工大学 LaTeX 幻灯片模板:
|
|
17
|
+
[BIThesis Beamer Slide Template](https://www.texpage.com/zh/template/18f4a5d2-2167-47b8-b193-85e2475e7a06)。
|
|
18
|
+
原模板适合熟悉 LaTeX / Beamer 的用户,但 LaTeX 工具链较重,输出也通常是 PDF。
|
|
19
|
+
PDF 用 WPS 播放比较方便;如果没有 WPS,常见的 PDF 转 PPT 流程又容易造成格式错乱。
|
|
20
|
+
|
|
21
|
+
因此这里提供另一条路线:用 YAML 描述内容,直接生成可编辑 PPTX,尽量保留文本、
|
|
22
|
+
表格、图表、形状和 Office Math 公式的可编辑性。
|
|
23
|
+
|
|
24
|
+
如果你的需求是“已有 PDF 幻灯片,只想在线展示或播放”,可以使用另一个项目
|
|
25
|
+
[pptView](https://github.com/yang-kun-long/pptView)。在线演示:
|
|
26
|
+
[https://ppt.yangkunlong.top](https://ppt.yangkunlong.top)。
|
|
27
|
+
|
|
9
28
|
代码使用 MIT License。北京理工大学名称、标识和视觉参考归其各自权利人所有。
|
|
10
29
|
|
|
11
30
|
## 特性
|
|
@@ -19,9 +38,14 @@
|
|
|
19
38
|
- 支持 `--json` 和 `--strict`,便于脚本、CI 和 AI agent 自动调用
|
|
20
39
|
- 支持图片尺寸读取和 `imageText` 自动排版
|
|
21
40
|
|
|
22
|
-
##
|
|
41
|
+
## 三种使用方式
|
|
42
|
+
|
|
43
|
+
同一个 npm 包同时提供 Web UI、CLI 和 MCP 三个入口。普通用户优先使用 Web UI;
|
|
44
|
+
脚本和 CI 使用 CLI;Codex、Claude Code 等本地 agent 使用 MCP。
|
|
45
|
+
|
|
46
|
+
### 1. 普通用户:打开本地网页
|
|
23
47
|
|
|
24
|
-
|
|
48
|
+
无需安装,直接启动:
|
|
25
49
|
|
|
26
50
|
```powershell
|
|
27
51
|
npx bit-ppt-generator
|
|
@@ -35,88 +59,107 @@ http://127.0.0.1:3000/
|
|
|
35
59
|
|
|
36
60
|
本地网页默认不需要登录;只有部署者配置了鉴权环境变量时才会显示登录区。
|
|
37
61
|
|
|
38
|
-
|
|
62
|
+
也可以全局安装后启动:
|
|
39
63
|
|
|
40
64
|
```powershell
|
|
41
65
|
npm install -g bit-ppt-generator
|
|
42
66
|
bit-ppt-generator
|
|
43
67
|
```
|
|
44
68
|
|
|
45
|
-
|
|
69
|
+
### 2. 命令行用户:检查和生成 PPTX
|
|
46
70
|
|
|
47
71
|
```powershell
|
|
48
|
-
npm install
|
|
72
|
+
npm install -g bit-ppt-generator
|
|
73
|
+
bit-ppt check content/example.yaml --json
|
|
74
|
+
bit-ppt generate content/example.yaml output/example.pptx
|
|
49
75
|
```
|
|
50
76
|
|
|
51
|
-
|
|
77
|
+
常用 CLI:
|
|
52
78
|
|
|
53
|
-
```
|
|
54
|
-
|
|
79
|
+
```text
|
|
80
|
+
bit-ppt generate <input.yaml> <output.pptx> [--json] [--strict] [font options]
|
|
81
|
+
bit-ppt check <input.yaml> [--json] [--strict]
|
|
82
|
+
bit-ppt list-layouts [--json]
|
|
83
|
+
bit-ppt guide [topic] [name] [--json]
|
|
84
|
+
bit-ppt doctor [--json]
|
|
55
85
|
```
|
|
56
86
|
|
|
57
|
-
|
|
87
|
+
### 3. Agent 用户:配置 MCP
|
|
88
|
+
|
|
89
|
+
全局安装后,MCP 客户端可以直接启动 npm 包提供的 `bit-ppt-mcp` 命令:
|
|
58
90
|
|
|
59
91
|
```powershell
|
|
60
|
-
npm
|
|
61
|
-
bit-ppt --help
|
|
92
|
+
npm install -g bit-ppt-generator
|
|
93
|
+
bit-ppt-mcp --help
|
|
62
94
|
```
|
|
63
95
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
启动本地网页:
|
|
96
|
+
MCP 客户端配置示例:
|
|
67
97
|
|
|
68
|
-
```
|
|
69
|
-
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"mcpServers": {
|
|
101
|
+
"bit-ppt": {
|
|
102
|
+
"command": "bit-ppt-mcp",
|
|
103
|
+
"args": []
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
70
107
|
```
|
|
71
108
|
|
|
72
|
-
|
|
109
|
+
如果 MCP 客户端不继承系统 PATH,改用 `npx` 启动:
|
|
73
110
|
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"mcpServers": {
|
|
114
|
+
"bit-ppt": {
|
|
115
|
+
"command": "npx",
|
|
116
|
+
"args": ["-y", "--package", "bit-ppt-generator", "bit-ppt-mcp"]
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
78
120
|
```
|
|
79
121
|
|
|
80
|
-
输出文件位于:
|
|
81
122
|
|
|
82
|
-
|
|
83
|
-
output/example.pptx
|
|
84
|
-
output/body-layout-test.pptx
|
|
85
|
-
output/chart-flow-test.pptx
|
|
86
|
-
```
|
|
123
|
+
## 仓库开发
|
|
87
124
|
|
|
88
|
-
|
|
125
|
+
克隆仓库后安装依赖:
|
|
89
126
|
|
|
90
127
|
```powershell
|
|
91
|
-
|
|
128
|
+
npm install
|
|
92
129
|
```
|
|
93
130
|
|
|
94
|
-
|
|
131
|
+
启动本地网页:
|
|
95
132
|
|
|
96
133
|
```powershell
|
|
97
|
-
|
|
98
|
-
node bin/bit-ppt.mjs generate content/example.yaml output/example.pptx --json
|
|
134
|
+
npm run serve
|
|
99
135
|
```
|
|
100
136
|
|
|
101
|
-
|
|
137
|
+
生成示例 PPT:
|
|
102
138
|
|
|
103
139
|
```powershell
|
|
104
|
-
|
|
105
|
-
|
|
140
|
+
npm run build:ppt
|
|
141
|
+
npm run build:body-layouts
|
|
142
|
+
npm run build:charts
|
|
106
143
|
```
|
|
107
144
|
|
|
108
|
-
|
|
145
|
+
源码入口:
|
|
109
146
|
|
|
110
|
-
|
|
147
|
+
```powershell
|
|
148
|
+
node bin/bit-ppt.mjs --help
|
|
149
|
+
node bin/bit-ppt-http.mjs --help
|
|
150
|
+
node bin/bit-ppt-mcp.mjs --help
|
|
151
|
+
```
|
|
111
152
|
|
|
112
|
-
|
|
153
|
+
本仓库采用单主干、多入口策略。Web UI、CLI、MCP 和 Node HTTP API 都复用同一套核心生成逻辑。
|
|
154
|
+
|
|
155
|
+
## npm 包入口
|
|
113
156
|
|
|
114
157
|
- Web UI:默认入口为 `bit-ppt-generator`,适合 npm 用户本地打开网页
|
|
115
158
|
- CLI:已支持,入口为 `bit-ppt` 或 `node bin/bit-ppt.mjs`
|
|
116
159
|
- MCP:已支持,入口为 `bit-ppt-mcp` 或 `node bin/bit-ppt-mcp.mjs`
|
|
117
160
|
- Node HTTP API:已支持,入口为 `bit-ppt-http` 或 `node bin/bit-ppt-http.mjs`
|
|
118
161
|
|
|
119
|
-
|
|
162
|
+
一个 npm release 同时包含 Web UI、CLI 和 MCP 三个入口,不拆成三个包。
|
|
120
163
|
|
|
121
164
|
## CLI 命令
|
|
122
165
|
|
|
@@ -134,10 +177,10 @@ bit-ppt-http
|
|
|
134
177
|
常用命令:
|
|
135
178
|
|
|
136
179
|
```powershell
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
180
|
+
bit-ppt list-layouts
|
|
181
|
+
bit-ppt list-layouts --json
|
|
182
|
+
bit-ppt doctor
|
|
183
|
+
bit-ppt doctor --json
|
|
141
184
|
```
|
|
142
185
|
|
|
143
186
|
`doctor` 会检查 Node 版本、依赖、关键素材、示例 deck、输出目录可写性。
|
|
@@ -150,24 +193,23 @@ MCP 只是 adapter,仍复用 CLI 背后的同一套生成和校验函数。
|
|
|
150
193
|
本地运行:
|
|
151
194
|
|
|
152
195
|
```powershell
|
|
153
|
-
|
|
196
|
+
bit-ppt-mcp
|
|
154
197
|
```
|
|
155
198
|
|
|
156
|
-
|
|
199
|
+
从源码运行:
|
|
157
200
|
|
|
158
201
|
```powershell
|
|
159
|
-
bit-ppt-mcp
|
|
202
|
+
node bin/bit-ppt-mcp.mjs
|
|
160
203
|
```
|
|
161
204
|
|
|
162
|
-
MCP
|
|
205
|
+
MCP 客户端配置示例,优先使用 npm 包命令:
|
|
163
206
|
|
|
164
207
|
```json
|
|
165
208
|
{
|
|
166
209
|
"mcpServers": {
|
|
167
210
|
"bit-ppt": {
|
|
168
|
-
"command": "
|
|
169
|
-
"args": [
|
|
170
|
-
"cwd": "D:/atuodl/presentation-slide/bit-ppt-template"
|
|
211
|
+
"command": "bit-ppt-mcp",
|
|
212
|
+
"args": []
|
|
171
213
|
}
|
|
172
214
|
}
|
|
173
215
|
}
|
|
@@ -593,6 +635,32 @@ npm run check:charts
|
|
|
593
635
|
npm pack --dry-run
|
|
594
636
|
```
|
|
595
637
|
|
|
638
|
+
## 发布
|
|
639
|
+
|
|
640
|
+
npm 包名为 `bit-ppt-generator`。后续版本通过 GitHub Release 触发
|
|
641
|
+
`.github/workflows/publish.yml`,并使用 npm Trusted Publisher 发布,不需要在
|
|
642
|
+
GitHub Secrets 保存 npm token。
|
|
643
|
+
|
|
644
|
+
Trusted Publisher 配置:
|
|
645
|
+
|
|
646
|
+
```text
|
|
647
|
+
Publisher: GitHub Actions
|
|
648
|
+
Organization or user: yang-kun-long
|
|
649
|
+
Repository: bit-ppt-template
|
|
650
|
+
Workflow filename: publish.yml
|
|
651
|
+
Environment name: 留空
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
发布新版本:
|
|
655
|
+
|
|
656
|
+
```powershell
|
|
657
|
+
npm version patch
|
|
658
|
+
git push
|
|
659
|
+
git push --tags
|
|
660
|
+
```
|
|
661
|
+
|
|
662
|
+
随后在 GitHub 创建并发布对应 tag 的 Release。
|
|
663
|
+
|
|
596
664
|
## 项目结构
|
|
597
665
|
|
|
598
666
|
```text
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bit-ppt-generator",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "LaTeX-free Beijing Institute of Technology style PPTX generator with Web UI, CLI, and MCP entrypoints.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -38,5 +38,13 @@
|
|
|
38
38
|
"pptxgenjs": "^4.0.1",
|
|
39
39
|
"yaml": "^2.8.4",
|
|
40
40
|
"zod": "^4.4.3"
|
|
41
|
-
}
|
|
41
|
+
},
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "git+https://github.com/yang-kun-long/bit-ppt-template.git"
|
|
45
|
+
},
|
|
46
|
+
"bugs": {
|
|
47
|
+
"url": "https://github.com/yang-kun-long/bit-ppt-template/issues"
|
|
48
|
+
},
|
|
49
|
+
"homepage": "https://github.com/yang-kun-long/bit-ppt-template#readme"
|
|
42
50
|
}
|
package/src/http-server.mjs
CHANGED
|
@@ -40,11 +40,25 @@ const WEB_APP_HTML = String.raw`<!doctype html>
|
|
|
40
40
|
button { border: 1px solid var(--red); background: var(--red); color: #fff; border-radius: 6px; padding: 9px 12px; font: inherit; cursor: pointer; }
|
|
41
41
|
button.secondary { background: #fff; color: var(--red); }
|
|
42
42
|
button:disabled { opacity: .55; cursor: not-allowed; }
|
|
43
|
+
a { color: var(--red); text-decoration: none; }
|
|
44
|
+
a:hover { text-decoration: underline; }
|
|
45
|
+
.intro { margin: 0 0 14px; color: var(--muted); font-size: 13px; line-height: 1.6; }
|
|
46
|
+
.repo-link { display: inline-flex; align-items: center; gap: 6px; margin-bottom: 12px; font-size: 13px; font-weight: 650; }
|
|
47
|
+
.repo-icon { width: 16px; height: 16px; fill: currentColor; flex: 0 0 auto; }
|
|
48
|
+
.guide { display: grid; gap: 10px; margin: 10px 0 14px; }
|
|
49
|
+
.guide-step { border-left: 3px solid #d9b6b8; padding: 2px 0 2px 10px; }
|
|
50
|
+
.guide-step strong { display: block; margin-bottom: 4px; font-size: 13px; }
|
|
51
|
+
.guide-step p { margin: 0; color: var(--muted); font-size: 12px; line-height: 1.55; }
|
|
52
|
+
.yaml-section { min-width: 0; }
|
|
53
|
+
.yaml-workspace { display: grid; gap: 16px; grid-template-columns: minmax(0, 1fr) 290px; align-items: start; }
|
|
54
|
+
.yaml-workspace textarea { min-height: 640px; }
|
|
55
|
+
.side-guide { border-left: 1px solid var(--line); padding-left: 16px; }
|
|
43
56
|
.status { min-height: 42px; white-space: pre-wrap; font-family: Consolas, "Cascadia Mono", monospace; font-size: 12px; color: var(--muted); }
|
|
44
57
|
.ok { color: #137333; }
|
|
45
58
|
.err { color: #b3261e; }
|
|
46
59
|
.hidden { display: none; }
|
|
47
|
-
@media (max-width:
|
|
60
|
+
@media (max-width: 1060px) { .yaml-workspace { grid-template-columns: 1fr; } .side-guide { border-left: 0; border-top: 1px solid var(--line); padding: 14px 0 0; } }
|
|
61
|
+
@media (max-width: 860px) { main { grid-template-columns: 1fr; padding: 14px; } textarea, .yaml-workspace textarea { min-height: 420px; } }
|
|
48
62
|
</style>
|
|
49
63
|
</head>
|
|
50
64
|
<body>
|
|
@@ -63,6 +77,13 @@ const WEB_APP_HTML = String.raw`<!doctype html>
|
|
|
63
77
|
</div>
|
|
64
78
|
<div id="authStatus" class="status"></div>
|
|
65
79
|
</div>
|
|
80
|
+
<a class="repo-link" href="https://github.com/yang-kun-long/bit-ppt-template" target="_blank" rel="noreferrer">
|
|
81
|
+
<svg class="repo-icon" viewBox="0 0 16 16" aria-hidden="true">
|
|
82
|
+
<path d="M8 0C3.58 0 0 3.64 0 8.13c0 3.59 2.29 6.63 5.47 7.7.4.07.55-.18.55-.39 0-.19-.01-.83-.01-1.51-2.01.38-2.53-.5-2.69-.96-.09-.23-.48-.96-.82-1.15-.28-.15-.68-.52-.01-.53.63-.01 1.08.59 1.23.83.72 1.23 1.87.88 2.33.67.07-.53.28-.88.51-1.09-1.78-.2-3.64-.9-3.64-4.01 0-.89.31-1.61.82-2.18-.08-.2-.36-1.03.08-2.15 0 0 .67-.22 2.2.83A7.5 7.5 0 0 1 8 3.92c.68 0 1.36.09 2 .27 1.53-1.05 2.2-.83 2.2-.83.44 1.12.16 1.95.08 2.15.51.57.82 1.29.82 2.18 0 3.12-1.87 3.81-3.65 4.01.29.25.54.74.54 1.5 0 1.09-.01 1.97-.01 2.24 0 .21.15.46.55.39A8.03 8.03 0 0 0 16 8.13C16 3.64 12.42 0 8 0Z"/>
|
|
83
|
+
</svg>
|
|
84
|
+
GitHub 仓库
|
|
85
|
+
</a>
|
|
86
|
+
<p class="intro">这是一个把 YAML 生成可编辑 PPTX 的网页入口。推荐先让 AI 产出 YAML,再在这里检查和生成;报错时把检查结果交给 AI 修改。</p>
|
|
66
87
|
<h2>输出</h2>
|
|
67
88
|
<label for="outputName">文件名</label>
|
|
68
89
|
<input id="outputName" value="bit-ppt" />
|
|
@@ -75,6 +96,8 @@ const WEB_APP_HTML = String.raw`<!doctype html>
|
|
|
75
96
|
<div class="row">
|
|
76
97
|
<button id="copyPromptBtn" class="secondary">复制提示词</button>
|
|
77
98
|
<button id="copyRulesBtn" class="secondary">复制语法规则</button>
|
|
99
|
+
<button id="copyWorkflowBtn" class="secondary">复制使用教程</button>
|
|
100
|
+
<button id="copyErrorHelpBtn" class="secondary">复制报错求助</button>
|
|
78
101
|
<button id="insertExampleBtn" class="secondary">插入最小示例</button>
|
|
79
102
|
<button id="insertFullExampleBtn" class="secondary">插入完整示例</button>
|
|
80
103
|
</div>
|
|
@@ -343,6 +366,42 @@ YAML 与公式注意事项:
|
|
|
343
366
|
- 表格中有公式时,建议用单引号包住单元格。
|
|
344
367
|
- 图片没有真实路径时使用 placeholder,不要写不存在的 assets 路径。
|
|
345
368
|
- 每页文字保持短;如果 check 返回 warnings,按 repairPrompt 压缩或拆页。</textarea>
|
|
369
|
+
<textarea id="workflowGuide" hidden>请按这个流程和 AI 协作生成 PPT:
|
|
370
|
+
|
|
371
|
+
1. 先发“提示词”
|
|
372
|
+
- 告诉 AI:只输出 YAML,不要 Markdown 代码块,不要解释。
|
|
373
|
+
- 补充你的任务:主题、页数、受众、用途、是否需要演讲稿。
|
|
374
|
+
|
|
375
|
+
2. 再发“语法规则”
|
|
376
|
+
- 让 AI 使用支持的 layout 和字段。
|
|
377
|
+
- 告诉 AI:没有真实图片路径时必须用 image.mode: placeholder。
|
|
378
|
+
- 告诉 AI:公式用 LaTeX,生成后要能通过 check。
|
|
379
|
+
|
|
380
|
+
3. 最后发材料
|
|
381
|
+
- 可以贴论文摘要、章节结构、实验结果、表格数据、图片说明、参考文献。
|
|
382
|
+
- 要求 AI 生成完整 YAML。
|
|
383
|
+
|
|
384
|
+
4. 在网页里检查
|
|
385
|
+
- 把 YAML 粘到网页的 YAML 输入框,先点“检查”。
|
|
386
|
+
- 没有 errors 再点“生成 PPTX”。
|
|
387
|
+
|
|
388
|
+
5. 如果检查有问题
|
|
389
|
+
- 把 check 返回的 errors、warnings、repairPrompt 和当前 YAML 一起发给 AI。
|
|
390
|
+
- 要求 AI 只修改 YAML,不要解释,不要改变核心内容。</textarea>
|
|
391
|
+
<textarea id="errorHelpPrompt" hidden>下面是 BIT PPT Generator 的检查/生成报错。请你只输出修复后的完整 YAML,不要 Markdown 代码块,不要解释。
|
|
392
|
+
|
|
393
|
+
修复要求:
|
|
394
|
+
1. 保留原始内容意图和页面顺序。
|
|
395
|
+
2. 修复未知 layout、字段结构错误、YAML 语法错误。
|
|
396
|
+
3. 如果 warnings 说明文字过长,请压缩文字或拆成多页。
|
|
397
|
+
4. 如果图片路径不存在,请改成 image.mode: placeholder,并补充具体 prompt。
|
|
398
|
+
5. 如果公式导致 YAML 转义问题,请避免双引号,优先使用 plain scalar 或单引号。
|
|
399
|
+
6. 输出必须能重新通过 check。
|
|
400
|
+
|
|
401
|
+
网页报错 / check 结果:
|
|
402
|
+
|
|
403
|
+
当前 YAML:
|
|
404
|
+
</textarea>
|
|
346
405
|
<textarea id="exampleYaml" hidden>meta:
|
|
347
406
|
title: 北理工风格汇报
|
|
348
407
|
author: BIT PPT Generator
|
|
@@ -617,8 +676,9 @@ slides:
|
|
|
617
676
|
收尾时提示听众:生成结果是可编辑 PPTX。
|
|
618
677
|
后续可以在 PowerPoint 或 WPS 中继续调整。</textarea>
|
|
619
678
|
</section>
|
|
620
|
-
<section>
|
|
679
|
+
<section class="yaml-section">
|
|
621
680
|
<h2>YAML</h2>
|
|
681
|
+
<div class="yaml-workspace">
|
|
622
682
|
<textarea id="yaml" spellcheck="false">meta:
|
|
623
683
|
title: 北理工风格 PPT
|
|
624
684
|
author: BIT PPT Generator
|
|
@@ -633,6 +693,28 @@ slides:
|
|
|
633
693
|
- 输出为可编辑 PPTX
|
|
634
694
|
- 支持公式、图表和多种版式
|
|
635
695
|
</textarea>
|
|
696
|
+
<aside class="side-guide">
|
|
697
|
+
<h3>使用教程</h3>
|
|
698
|
+
<div class="guide">
|
|
699
|
+
<div class="guide-step">
|
|
700
|
+
<strong>1. 先复制提示词</strong>
|
|
701
|
+
<p>发给 AI,说明它的角色、输出格式和页面限制。再补一句你的主题,例如“请做一份 10 页组会汇报”。</p>
|
|
702
|
+
</div>
|
|
703
|
+
<div class="guide-step">
|
|
704
|
+
<strong>2. 再复制语法规则</strong>
|
|
705
|
+
<p>继续发给 AI,让它按支持的 layout 和字段写 YAML。最后把论文摘要、实验结果、表格数据、图片说明等材料贴给 AI。</p>
|
|
706
|
+
</div>
|
|
707
|
+
<div class="guide-step">
|
|
708
|
+
<strong>3. 粘贴 YAML 后先检查</strong>
|
|
709
|
+
<p>把 AI 输出粘到左侧输入框,点“检查”。如果有 errors / warnings,把检查结果和当前 YAML 一起发回 AI,让它只修 YAML。</p>
|
|
710
|
+
</div>
|
|
711
|
+
<div class="guide-step">
|
|
712
|
+
<strong>4. 生成失败时这样沟通</strong>
|
|
713
|
+
<p>复制“报错求助”模板,把网页显示的错误、check 结果、当前 YAML 一起发给 AI;要求它保留内容意图,只修字段、长度、图片路径或公式写法。</p>
|
|
714
|
+
</div>
|
|
715
|
+
</div>
|
|
716
|
+
</aside>
|
|
717
|
+
</div>
|
|
636
718
|
</section>
|
|
637
719
|
</main>
|
|
638
720
|
<script>
|
|
@@ -795,6 +877,8 @@ slides:
|
|
|
795
877
|
$("generateBtn").addEventListener("click", generateDeck);
|
|
796
878
|
$("copyPromptBtn").addEventListener("click", () => copyTextFrom("aiPrompt", "提示词"));
|
|
797
879
|
$("copyRulesBtn").addEventListener("click", () => copyTextFrom("syntaxRules", "语法规则"));
|
|
880
|
+
$("copyWorkflowBtn").addEventListener("click", () => copyTextFrom("workflowGuide", "使用教程"));
|
|
881
|
+
$("copyErrorHelpBtn").addEventListener("click", () => copyTextFrom("errorHelpPrompt", "报错求助模板"));
|
|
798
882
|
$("insertExampleBtn").addEventListener("click", insertExample);
|
|
799
883
|
$("insertFullExampleBtn").addEventListener("click", insertFullExample);
|
|
800
884
|
loadServerConfig();
|
package/src/layout-guides.mjs
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { listLayouts as listSupportedLayouts } from "./core/layouts.mjs";
|
|
2
|
+
|
|
1
3
|
const writingRules = [
|
|
2
4
|
"Keep slide text short and concrete; use validation warnings as rewrite hints.",
|
|
3
5
|
"Prefer editable PPTX objects: text boxes, shapes, tables, charts, OMML formulas, and native images.",
|
|
@@ -226,8 +228,414 @@ const layoutGuides = {
|
|
|
226
228
|
},
|
|
227
229
|
};
|
|
228
230
|
|
|
231
|
+
const additionalLayoutGuides = {
|
|
232
|
+
title: {
|
|
233
|
+
layout: "title",
|
|
234
|
+
purpose: "Create the deck cover slide from top-level metadata.",
|
|
235
|
+
whenToUse: "Use as the first slide; title content usually comes from the deck-level `meta` object.",
|
|
236
|
+
fields: {
|
|
237
|
+
layout: { type: "literal", required: true, value: "title" },
|
|
238
|
+
"meta.title": { type: "string", required: false },
|
|
239
|
+
"meta.subtitle": { type: "string", required: false },
|
|
240
|
+
"meta.author": { type: "string", required: false },
|
|
241
|
+
"meta.advisor": { type: "string", required: false },
|
|
242
|
+
"meta.date": { type: "string", required: false },
|
|
243
|
+
},
|
|
244
|
+
limits: {
|
|
245
|
+
"meta.title": { recommendedChars: 28 },
|
|
246
|
+
"meta.subtitle": { recommendedChars: 42 },
|
|
247
|
+
},
|
|
248
|
+
notes: [
|
|
249
|
+
"The slide object normally only needs `layout: title`.",
|
|
250
|
+
"Cover text is read from deck metadata.",
|
|
251
|
+
],
|
|
252
|
+
example: { layout: "title" },
|
|
253
|
+
},
|
|
254
|
+
agenda: {
|
|
255
|
+
layout: "agenda",
|
|
256
|
+
purpose: "Show the main agenda or chapter list.",
|
|
257
|
+
whenToUse: "Use near the beginning of a deck to preview sections.",
|
|
258
|
+
fields: {
|
|
259
|
+
layout: { type: "literal", required: true, value: "agenda" },
|
|
260
|
+
title: { type: "string", required: true },
|
|
261
|
+
items: { type: "string[]", required: true },
|
|
262
|
+
},
|
|
263
|
+
limits: { items: { maxItems: 7, recommendedChars: 24 } },
|
|
264
|
+
notes: ["Keep agenda labels short and parallel.", "Use `section` slides for major chapter breaks."],
|
|
265
|
+
example: { layout: "agenda", title: "目录", items: ["研究背景", "方法设计", "实验结果", "总结展望"] },
|
|
266
|
+
},
|
|
267
|
+
section: {
|
|
268
|
+
layout: "section",
|
|
269
|
+
purpose: "Create a visual chapter divider.",
|
|
270
|
+
whenToUse: "Use before a major topic shift or report section.",
|
|
271
|
+
fields: {
|
|
272
|
+
layout: { type: "literal", required: true, value: "section" },
|
|
273
|
+
sectionNo: { type: "string", required: false },
|
|
274
|
+
title: { type: "string", required: true },
|
|
275
|
+
subtitle: { type: "string", required: false },
|
|
276
|
+
},
|
|
277
|
+
limits: { title: { recommendedChars: 24 }, subtitle: { recommendedChars: 42 } },
|
|
278
|
+
notes: ["`sectionNo` can be supplied explicitly, for example `01`.", "Keep the subtitle as context, not body content."],
|
|
279
|
+
example: { layout: "section", sectionNo: "01", title: "研究背景", subtitle: "从问题定义与现有瓶颈切入" },
|
|
280
|
+
},
|
|
281
|
+
bullets: {
|
|
282
|
+
layout: "bullets",
|
|
283
|
+
purpose: "Show a lead sentence and a concise bullet list.",
|
|
284
|
+
whenToUse: "Use for findings, observations, requirements, and short argument chains.",
|
|
285
|
+
fields: {
|
|
286
|
+
layout: { type: "literal", required: true, value: "bullets" },
|
|
287
|
+
title: { type: "string", required: true },
|
|
288
|
+
lead: { type: "string", required: false },
|
|
289
|
+
bullets: { type: "string[]", required: true },
|
|
290
|
+
fontSize: { type: "number", required: false },
|
|
291
|
+
},
|
|
292
|
+
limits: { lead: { recommendedChars: 58 }, bullets: { maxItems: 8, recommendedChars: 38 } },
|
|
293
|
+
notes: ["Inline `$...$` and `\\(...\\)` formulas are supported.", "Long bullet lists may be split during preflight."],
|
|
294
|
+
example: { layout: "bullets", title: "核心发现", lead: "结构化输入能降低排版漂移。", bullets: ["模型只填写短字段。", "模板负责视觉规范。", "预检负责溢出修复。"] },
|
|
295
|
+
},
|
|
296
|
+
claim: {
|
|
297
|
+
layout: "claim",
|
|
298
|
+
purpose: "Emphasize one central claim with supporting evidence.",
|
|
299
|
+
whenToUse: "Use when a slide needs one clear takeaway rather than several equal points.",
|
|
300
|
+
fields: {
|
|
301
|
+
layout: { type: "literal", required: true, value: "claim" },
|
|
302
|
+
title: { type: "string", required: true },
|
|
303
|
+
claim: { type: "string", required: true },
|
|
304
|
+
evidence: { type: "string[]", required: false },
|
|
305
|
+
},
|
|
306
|
+
limits: { claim: { recommendedChars: 54 }, evidence: { maxItems: 5, recommendedChars: 38 } },
|
|
307
|
+
notes: ["Make `claim` a complete sentence.", "Use evidence bullets for proof, not extra claims."],
|
|
308
|
+
example: { layout: "claim", title: "核心结论", claim: "AI 生成 PPT 的关键是稳定内容结构。", evidence: ["YAML 限定字段。", "PPTX 对象保持可编辑。"] },
|
|
309
|
+
},
|
|
310
|
+
twoColumn: {
|
|
311
|
+
layout: "twoColumn",
|
|
312
|
+
purpose: "Compare or separate two parallel content blocks.",
|
|
313
|
+
whenToUse: "Use for before/after, baseline/ours, or two-topic explanation.",
|
|
314
|
+
fields: {
|
|
315
|
+
layout: { type: "literal", required: true, value: "twoColumn" },
|
|
316
|
+
title: { type: "string", required: true },
|
|
317
|
+
left: { type: "{ title, text? | bullets? }", required: true },
|
|
318
|
+
right: { type: "{ title, text? | bullets? }", required: true },
|
|
319
|
+
},
|
|
320
|
+
limits: { columnTitle: { recommendedChars: 16 }, columnText: { recommendedChars: 105 }, columnBullets: { maxItems: 5, recommendedChars: 34 } },
|
|
321
|
+
notes: ["Each column can use either `text` or `bullets`.", "Use `comparison` when the point is explicitly adversarial or directional."],
|
|
322
|
+
example: { layout: "twoColumn", title: "两种路线", left: { title: "传统做法", bullets: ["手工排版", "一致性依赖人工"] }, right: { title: "模板化做法", bullets: ["结构化输入", "生成器固定样式"] } },
|
|
323
|
+
},
|
|
324
|
+
cards: {
|
|
325
|
+
layout: "cards",
|
|
326
|
+
purpose: "Show several peer points as compact cards.",
|
|
327
|
+
whenToUse: "Use for features, modules, contributions, or categories with equal weight.",
|
|
328
|
+
fields: {
|
|
329
|
+
layout: { type: "literal", required: true, value: "cards" },
|
|
330
|
+
title: { type: "string", required: true },
|
|
331
|
+
cards: { type: "{ title, text }[]", required: true },
|
|
332
|
+
},
|
|
333
|
+
limits: { cards: { maxItems: 6 }, cardTitle: { recommendedChars: 14 }, cardText: { recommendedChars: 52 } },
|
|
334
|
+
notes: ["Cards work best when each item has similar importance.", "Use no more than six cards on one slide."],
|
|
335
|
+
example: { layout: "cards", title: "能力模块", cards: [{ title: "校验", text: "检查字段与长度风险。" }, { title: "生成", text: "写入可编辑 PPTX 对象。" }] },
|
|
336
|
+
},
|
|
337
|
+
comparison: {
|
|
338
|
+
layout: "comparison",
|
|
339
|
+
purpose: "Show a direct comparison between two options.",
|
|
340
|
+
whenToUse: "Use when one side is preferred, rejected, or contrasted against another.",
|
|
341
|
+
fields: {
|
|
342
|
+
layout: { type: "literal", required: true, value: "comparison" },
|
|
343
|
+
title: { type: "string", required: true },
|
|
344
|
+
left: { type: "{ label?, title, bullets }", required: true },
|
|
345
|
+
right: { type: "{ label?, title, bullets }", required: true },
|
|
346
|
+
},
|
|
347
|
+
limits: { comparisonTitle: { recommendedChars: 18 }, bullets: { maxItems: 5, recommendedChars: 32 } },
|
|
348
|
+
notes: ["`left.label` and `right.label` are short tags.", "Keep the two sides structurally parallel."],
|
|
349
|
+
example: { layout: "comparison", title: "技术路线取舍", left: { label: "不优先", title: "端到端 Agent", bullets: ["流程封闭", "复核成本高"] }, right: { label: "优先", title: "MCP 工具链", bullets: ["跨客户端", "人类可介入"] } },
|
|
350
|
+
},
|
|
351
|
+
timeline: {
|
|
352
|
+
layout: "timeline",
|
|
353
|
+
purpose: "Show milestones along a horizontal timeline.",
|
|
354
|
+
whenToUse: "Use for roadmaps, phases, history, or scheduled work.",
|
|
355
|
+
fields: {
|
|
356
|
+
layout: { type: "literal", required: true, value: "timeline" },
|
|
357
|
+
title: { type: "string", required: true },
|
|
358
|
+
items: { type: "{ date? | phase?, title, text }[]", required: true },
|
|
359
|
+
},
|
|
360
|
+
limits: { items: { maxItems: 6 }, itemTitle: { recommendedChars: 10 }, itemText: { recommendedChars: 24 } },
|
|
361
|
+
notes: ["Use `date` for calendar time and `phase` for abstract stages.", "Avoid paragraph text in timeline nodes."],
|
|
362
|
+
example: { layout: "timeline", title: "路线图", items: [{ date: "阶段 1", title: "模板", text: "固化视觉规范。" }, { date: "阶段 2", title: "校验", text: "加入预检修复。" }] },
|
|
363
|
+
},
|
|
364
|
+
process: {
|
|
365
|
+
layout: "process",
|
|
366
|
+
purpose: "Show a linear process as connected steps.",
|
|
367
|
+
whenToUse: "Use for workflows, generation pipelines, or execution procedures.",
|
|
368
|
+
fields: {
|
|
369
|
+
layout: { type: "literal", required: true, value: "process" },
|
|
370
|
+
title: { type: "string", required: true },
|
|
371
|
+
steps: { type: "{ title, text }[]", required: true },
|
|
372
|
+
},
|
|
373
|
+
limits: { steps: { maxItems: 5 }, stepTitle: { recommendedChars: 8 }, stepText: { recommendedChars: 24 } },
|
|
374
|
+
notes: ["Steps are rendered left-to-right.", "Use `flowchart` for branching or non-linear processes."],
|
|
375
|
+
example: { layout: "process", title: "生成流程", steps: [{ title: "解析", text: "读取 YAML。" }, { title: "校验", text: "检查字段。" }, { title: "导出", text: "生成 PPTX。" }] },
|
|
376
|
+
},
|
|
377
|
+
problemSolution: {
|
|
378
|
+
layout: "problemSolution",
|
|
379
|
+
purpose: "Present problem, solution, and impact in three panels.",
|
|
380
|
+
whenToUse: "Use for proposal framing or product/research motivation.",
|
|
381
|
+
fields: {
|
|
382
|
+
layout: { type: "literal", required: true, value: "problemSolution" },
|
|
383
|
+
title: { type: "string", required: true },
|
|
384
|
+
problem: { type: "{ label?, title, bullets }", required: true },
|
|
385
|
+
solution: { type: "{ label?, title, bullets }", required: true },
|
|
386
|
+
impact: { type: "{ label?, title, bullets }", required: true },
|
|
387
|
+
},
|
|
388
|
+
limits: { panelTitle: { recommendedChars: 12 }, bullets: { maxItems: 4, recommendedChars: 26 } },
|
|
389
|
+
notes: ["Use this when the three blocks form one argument.", "Each panel supports a custom short `label`."],
|
|
390
|
+
example: { layout: "problemSolution", title: "问题与方案", problem: { title: "排版不稳", bullets: ["模型自由发挥导致溢出。"] }, solution: { title: "结构约束", bullets: ["YAML 固定字段。"] }, impact: { title: "可复核", bullets: ["输出可编辑 PPTX。"] } },
|
|
391
|
+
},
|
|
392
|
+
painOpportunity: {
|
|
393
|
+
layout: "painOpportunity",
|
|
394
|
+
purpose: "Frame current status, pain points, and opportunity.",
|
|
395
|
+
whenToUse: "Use for background analysis before introducing a solution.",
|
|
396
|
+
fields: {
|
|
397
|
+
layout: { type: "literal", required: true, value: "painOpportunity" },
|
|
398
|
+
title: { type: "string", required: true },
|
|
399
|
+
status: { type: "{ title, text? | bullets? }", required: true },
|
|
400
|
+
pain: { type: "{ title, text? | bullets? }", required: true },
|
|
401
|
+
opportunity: { type: "{ title, text? | bullets? }", required: true },
|
|
402
|
+
},
|
|
403
|
+
limits: { panelTitle: { recommendedChars: 12 }, bullets: { maxItems: 4, recommendedChars: 30 } },
|
|
404
|
+
notes: ["Panels use the same structure as `twoColumn` column blocks.", "Best for moving from observation to opportunity."],
|
|
405
|
+
example: { layout: "painOpportunity", title: "现状痛点与机会", status: { title: "现状", bullets: ["PPT 生成需求高。"] }, pain: { title: "痛点", bullets: ["直接生成不稳定。"] }, opportunity: { title: "机会", bullets: ["模板化生成可控。"] } },
|
|
406
|
+
},
|
|
407
|
+
experimentDesign: {
|
|
408
|
+
layout: "experimentDesign",
|
|
409
|
+
purpose: "Summarize an experiment setup.",
|
|
410
|
+
whenToUse: "Use before result slides to define data, variables, metrics, and baselines.",
|
|
411
|
+
fields: {
|
|
412
|
+
layout: { type: "literal", required: true, value: "experimentDesign" },
|
|
413
|
+
title: { type: "string", required: true },
|
|
414
|
+
dataset: { type: "string | string[]", required: false },
|
|
415
|
+
variables: { type: "string | string[]", required: false },
|
|
416
|
+
metrics: { type: "string | string[]", required: false },
|
|
417
|
+
baselines: { type: "string | string[]", required: false },
|
|
418
|
+
procedure: { type: "string[]", required: false },
|
|
419
|
+
},
|
|
420
|
+
limits: { eachBlock: { maxItems: 4, recommendedChars: 26 }, procedure: { maxItems: 5 } },
|
|
421
|
+
notes: ["Scalar strings are accepted and rendered as one bullet.", "Keep procedure items short because they render on one line."],
|
|
422
|
+
example: { layout: "experimentDesign", title: "实验设计", dataset: ["公开数据集 A"], variables: ["是否启用预检"], metrics: ["溢出页数"], baselines: ["直接生成 PPT"], procedure: ["准备输入", "生成", "人工复核"] },
|
|
423
|
+
},
|
|
424
|
+
resultAnalysis: {
|
|
425
|
+
layout: "resultAnalysis",
|
|
426
|
+
purpose: "State one finding, key metrics, and analysis bullets.",
|
|
427
|
+
whenToUse: "Use after experiments to connect numbers to interpretation.",
|
|
428
|
+
fields: {
|
|
429
|
+
layout: { type: "literal", required: true, value: "resultAnalysis" },
|
|
430
|
+
title: { type: "string", required: true },
|
|
431
|
+
finding: { type: "string", required: true },
|
|
432
|
+
metrics: { type: "{ value, label, note? }[]", required: false },
|
|
433
|
+
analysis: { type: "string[]", required: false },
|
|
434
|
+
},
|
|
435
|
+
limits: { finding: { recommendedChars: 52 }, metrics: { maxItems: 3 }, analysis: { maxItems: 4, recommendedChars: 38 } },
|
|
436
|
+
notes: ["Put the strongest result in `finding`.", "Metrics are compact; use `chart` for richer data."],
|
|
437
|
+
example: { layout: "resultAnalysis", title: "结果分析", finding: "预检显著减少长列表造成的页面溢出。", metrics: [{ value: "-80%", label: "溢出页", note: "相对基线" }], analysis: ["主要收益来自 bullets 和 references 拆页。"] },
|
|
438
|
+
},
|
|
439
|
+
riskMitigation: {
|
|
440
|
+
layout: "riskMitigation",
|
|
441
|
+
purpose: "Show risks, impacts, and mitigations in a table.",
|
|
442
|
+
whenToUse: "Use for project planning, deployment risk, or limitation handling.",
|
|
443
|
+
fields: {
|
|
444
|
+
layout: { type: "literal", required: true, value: "riskMitigation" },
|
|
445
|
+
title: { type: "string", required: true },
|
|
446
|
+
items: { type: "{ risk, impact, mitigation }[]", required: true },
|
|
447
|
+
},
|
|
448
|
+
limits: { items: { maxItems: 5 }, cell: { recommendedChars: 28 } },
|
|
449
|
+
notes: ["Keep mitigation actionable.", "Use this for risks; use `table` for arbitrary structured data."],
|
|
450
|
+
example: { layout: "riskMitigation", title: "风险与对策", items: [{ risk: "图片缺失", impact: "生成失败", mitigation: "使用 placeholder 并补 prompt" }] },
|
|
451
|
+
},
|
|
452
|
+
contribution: {
|
|
453
|
+
layout: "contribution",
|
|
454
|
+
purpose: "List the main contributions with numbered emphasis.",
|
|
455
|
+
whenToUse: "Use near the end of a research or project deck.",
|
|
456
|
+
fields: {
|
|
457
|
+
layout: { type: "literal", required: true, value: "contribution" },
|
|
458
|
+
title: { type: "string", required: true },
|
|
459
|
+
items: { type: "{ title, text }[]", required: true },
|
|
460
|
+
},
|
|
461
|
+
limits: { items: { maxItems: 4 }, itemTitle: { recommendedChars: 14 }, itemText: { recommendedChars: 44 } },
|
|
462
|
+
notes: ["Use one contribution per item.", "Avoid turning this into a general summary slide."],
|
|
463
|
+
example: { layout: "contribution", title: "主要贡献", items: [{ title: "可编辑输出", text: "文本、表格、图表均保留为 PPTX 对象。" }, { title: "公式支持", text: "LaTeX 公式转换为原生 OMML。" }] },
|
|
464
|
+
},
|
|
465
|
+
summary: {
|
|
466
|
+
layout: "summary",
|
|
467
|
+
purpose: "Close a section with one takeaway and supporting points.",
|
|
468
|
+
whenToUse: "Use at section endings or before the closing slide.",
|
|
469
|
+
fields: {
|
|
470
|
+
layout: { type: "literal", required: true, value: "summary" },
|
|
471
|
+
title: { type: "string", required: true },
|
|
472
|
+
takeaway: { type: "string", required: true },
|
|
473
|
+
points: { type: "string[]", required: false },
|
|
474
|
+
},
|
|
475
|
+
limits: { takeaway: { recommendedChars: 52 }, points: { maxItems: 5, recommendedChars: 36 } },
|
|
476
|
+
notes: ["`takeaway` should be a sentence, not a heading.", "Use `closing` only for the final thank-you page."],
|
|
477
|
+
example: { layout: "summary", title: "章节小结", takeaway: "结构化内容让 PPT 生成更稳定也更容易修复。", points: ["页面类型明确。", "校验信息可回传模型。"] },
|
|
478
|
+
},
|
|
479
|
+
architecture: {
|
|
480
|
+
layout: "architecture",
|
|
481
|
+
purpose: "Show a layered architecture with components and notes.",
|
|
482
|
+
whenToUse: "Use for systems, model stacks, or pipeline architecture.",
|
|
483
|
+
fields: {
|
|
484
|
+
layout: { type: "literal", required: true, value: "architecture" },
|
|
485
|
+
title: { type: "string", required: true },
|
|
486
|
+
layers: { type: "{ title, components, note? }[]", required: true },
|
|
487
|
+
},
|
|
488
|
+
limits: { layers: { maxItems: 4 }, layerTitle: { recommendedChars: 8 }, components: { maxItems: 5, recommendedChars: 10 }, note: { recommendedChars: 44 } },
|
|
489
|
+
notes: ["Layer order is top-to-bottom.", "Use short component labels so chips stay readable."],
|
|
490
|
+
example: { layout: "architecture", title: "系统架构", layers: [{ title: "输入层", components: ["YAML", "图片"], note: "收集结构化材料。" }, { title: "生成层", components: ["校验", "PPTX", "OMML"], note: "写入可编辑对象。" }] },
|
|
491
|
+
},
|
|
492
|
+
ablation: {
|
|
493
|
+
layout: "ablation",
|
|
494
|
+
purpose: "Summarize ablation factors, settings, deltas, and conclusions.",
|
|
495
|
+
whenToUse: "Use for research experiments that remove or vary components.",
|
|
496
|
+
fields: {
|
|
497
|
+
layout: { type: "literal", required: true, value: "ablation" },
|
|
498
|
+
title: { type: "string", required: true },
|
|
499
|
+
baseline: { type: "string", required: false },
|
|
500
|
+
items: { type: "{ factor, setting, delta, conclusion }[]", required: true },
|
|
501
|
+
},
|
|
502
|
+
limits: { baseline: { recommendedChars: 58 }, items: { maxItems: 6 }, factor: { recommendedChars: 18 }, setting: { recommendedChars: 18 }, delta: { recommendedChars: 18 }, conclusion: { recommendedChars: 28 } },
|
|
503
|
+
notes: ["Use `delta` for numeric or qualitative change.", "Keep conclusions short enough for table-like rendering."],
|
|
504
|
+
example: { layout: "ablation", title: "消融实验", baseline: "基线启用所有模块。", items: [{ factor: "预检", setting: "关闭", delta: "+3 overflow", conclusion: "长列表风险上升" }] },
|
|
505
|
+
},
|
|
506
|
+
caseStudy: {
|
|
507
|
+
layout: "caseStudy",
|
|
508
|
+
purpose: "Show one visual case with context, method, and result.",
|
|
509
|
+
whenToUse: "Use for qualitative examples, screenshots, or representative samples.",
|
|
510
|
+
fields: {
|
|
511
|
+
layout: { type: "literal", required: true, value: "caseStudy" },
|
|
512
|
+
title: { type: "string", required: true },
|
|
513
|
+
image: { type: "string | { path, fit? } | { mode: placeholder, prompt, aspectRatio? }", required: true },
|
|
514
|
+
caption: { type: "string", required: false },
|
|
515
|
+
context: { type: "string[]", required: false },
|
|
516
|
+
method: { type: "string[]", required: false },
|
|
517
|
+
result: { type: "string[]", required: false },
|
|
518
|
+
},
|
|
519
|
+
limits: { caption: { recommendedChars: 40 }, context: { maxItems: 2, recommendedChars: 34 }, method: { maxItems: 2, recommendedChars: 34 }, result: { maxItems: 2, recommendedChars: 34 } },
|
|
520
|
+
notes: ["Image placeholders are supported.", "Use `imageGrid` when comparing multiple images."],
|
|
521
|
+
example: { layout: "caseStudy", title: "案例分析", image: "assets/bit-campus-photo.png", caption: "示例图片,可替换为实验结果图。", context: ["输入是一段论文草稿。"], method: ["生成器按 layout 写入 PPTX。"], result: ["输出可继续编辑。"] },
|
|
522
|
+
},
|
|
523
|
+
imageGrid: {
|
|
524
|
+
layout: "imageGrid",
|
|
525
|
+
purpose: "Show multiple images in a regular grid.",
|
|
526
|
+
whenToUse: "Use for visual result sets, comparisons, or qualitative examples.",
|
|
527
|
+
fields: {
|
|
528
|
+
layout: { type: "literal", required: true, value: "imageGrid" },
|
|
529
|
+
title: { type: "string", required: true },
|
|
530
|
+
images: { type: "(string | { path, caption? } | { mode: placeholder, prompt, caption?, aspectRatio? })[]", required: true },
|
|
531
|
+
},
|
|
532
|
+
limits: { images: { maxItems: 6 }, caption: { recommendedChars: 16 } },
|
|
533
|
+
notes: ["Each image can be a local path or an image object.", "Use short captions to avoid crowding the grid."],
|
|
534
|
+
example: { layout: "imageGrid", title: "多图结果", images: [{ path: "assets/bit-campus-photo.png", caption: "输入" }, { path: "assets/bit-campus-photo.png", caption: "输出" }] },
|
|
535
|
+
},
|
|
536
|
+
code: {
|
|
537
|
+
layout: "code",
|
|
538
|
+
purpose: "Show pseudocode or a compact code block with notes.",
|
|
539
|
+
whenToUse: "Use for algorithms, command snippets, or implementation sketches.",
|
|
540
|
+
fields: {
|
|
541
|
+
layout: { type: "literal", required: true, value: "code" },
|
|
542
|
+
title: { type: "string", required: true },
|
|
543
|
+
language: { type: "string", required: false },
|
|
544
|
+
code: { type: "string", required: false },
|
|
545
|
+
algorithm: { type: "string", required: false },
|
|
546
|
+
noteTitle: { type: "string", required: false },
|
|
547
|
+
notes: { type: "string[]", required: false },
|
|
548
|
+
},
|
|
549
|
+
limits: { code: { recommendedLines: 12, recommendedCharsPerLine: 72 }, notes: { maxItems: 5, recommendedChars: 32 } },
|
|
550
|
+
notes: ["Use either `code` or `algorithm`; `code` takes precedence.", "A YAML block scalar is recommended for multi-line code."],
|
|
551
|
+
example: { layout: "code", title: "算法伪代码", language: "Algorithm", code: "Input: deck D\n1. validate D\n2. generate PPTX", noteTitle: "关键约束", notes: ["代码块保持短行。"] },
|
|
552
|
+
},
|
|
553
|
+
appendix: {
|
|
554
|
+
layout: "appendix",
|
|
555
|
+
purpose: "Create an appendix index or supplemental topic list.",
|
|
556
|
+
whenToUse: "Use for backup slides, extra details, or appendix navigation.",
|
|
557
|
+
fields: {
|
|
558
|
+
layout: { type: "literal", required: true, value: "appendix" },
|
|
559
|
+
title: { type: "string", required: true },
|
|
560
|
+
items: { type: "{ key?, title, text }[]", required: true },
|
|
561
|
+
},
|
|
562
|
+
limits: { items: { maxItems: 8 }, itemTitle: { recommendedChars: 14 }, itemText: { recommendedChars: 42 } },
|
|
563
|
+
notes: ["`key` is optional and defaults to a numbered label.", "Use this as an index, not as dense body text."],
|
|
564
|
+
example: { layout: "appendix", title: "附录索引", items: [{ key: "A1", title: "数据细节", text: "样本来源与筛选规则。" }] },
|
|
565
|
+
},
|
|
566
|
+
metrics: {
|
|
567
|
+
layout: "metrics",
|
|
568
|
+
purpose: "Highlight up to four key metrics.",
|
|
569
|
+
whenToUse: "Use when numeric or compact KPI-style facts should dominate the slide.",
|
|
570
|
+
fields: {
|
|
571
|
+
layout: { type: "literal", required: true, value: "metrics" },
|
|
572
|
+
title: { type: "string", required: true },
|
|
573
|
+
metrics: { type: "{ value, label, note? }[]", required: true },
|
|
574
|
+
},
|
|
575
|
+
limits: { metrics: { maxItems: 4 }, value: { recommendedChars: 8 }, label: { recommendedChars: 12 }, note: { recommendedChars: 30 } },
|
|
576
|
+
notes: ["Use compact values such as `12+`, `-8%`, or `0`.", "Use `chart` when the reader needs to inspect a trend or distribution."],
|
|
577
|
+
example: { layout: "metrics", title: "关键指标", metrics: [{ value: "12+", label: "正文页型", note: "覆盖常见汇报页面" }, { value: "100%", label: "可编辑", note: "原生 PPTX 对象" }] },
|
|
578
|
+
},
|
|
579
|
+
matrix: {
|
|
580
|
+
layout: "matrix",
|
|
581
|
+
purpose: "Show four quadrants or a compact 2x2 decision matrix.",
|
|
582
|
+
whenToUse: "Use for strategy tradeoffs, option classification, or two-axis judgment.",
|
|
583
|
+
fields: {
|
|
584
|
+
layout: { type: "literal", required: true, value: "matrix" },
|
|
585
|
+
title: { type: "string", required: true },
|
|
586
|
+
cells: { type: "{ title, text }[]", required: true },
|
|
587
|
+
},
|
|
588
|
+
limits: { cells: { maxItems: 4 }, cellTitle: { recommendedChars: 18 }, cellText: { recommendedChars: 52 } },
|
|
589
|
+
notes: ["Cells render row-major in a 2x2 grid.", "Provide exactly four cells for a complete matrix."],
|
|
590
|
+
example: { layout: "matrix", title: "方案判断矩阵", cells: [{ title: "低成本 / 高控制", text: "YAML 内容加模板生成。" }, { title: "高成本 / 高控制", text: "完整设计系统与截图校验。" }] },
|
|
591
|
+
},
|
|
592
|
+
quote: {
|
|
593
|
+
layout: "quote",
|
|
594
|
+
purpose: "Show a short quote or memorable statement.",
|
|
595
|
+
whenToUse: "Use for thesis statements, external quotes, or section openers.",
|
|
596
|
+
fields: {
|
|
597
|
+
layout: { type: "literal", required: true, value: "quote" },
|
|
598
|
+
title: { type: "string", required: false },
|
|
599
|
+
quote: { type: "string", required: true },
|
|
600
|
+
source: { type: "string", required: false },
|
|
601
|
+
},
|
|
602
|
+
limits: { quote: { recommendedChars: 70 } },
|
|
603
|
+
notes: ["Keep the quote short enough to remain visually dominant.", "`source` is optional and rendered below the quote."],
|
|
604
|
+
example: { layout: "quote", title: "引用页", quote: "让模型生成结构化内容,让模板承担视觉和排版责任。", source: "BIT PPT Template Generator" },
|
|
605
|
+
},
|
|
606
|
+
references: {
|
|
607
|
+
layout: "references",
|
|
608
|
+
purpose: "List references or citations.",
|
|
609
|
+
whenToUse: "Use near the end of academic or research decks.",
|
|
610
|
+
fields: {
|
|
611
|
+
layout: { type: "literal", required: true, value: "references" },
|
|
612
|
+
title: { type: "string", required: false },
|
|
613
|
+
items: { type: "string[]", required: true },
|
|
614
|
+
fontSize: { type: "number", required: false },
|
|
615
|
+
},
|
|
616
|
+
limits: { items: { recommendedChars: 140 } },
|
|
617
|
+
notes: ["Long reference lists may be split during preflight.", "Keep each reference as one string item."],
|
|
618
|
+
example: { layout: "references", title: "参考文献", items: ["PptxGenJS project documentation. Generate editable PowerPoint presentations with JavaScript."] },
|
|
619
|
+
},
|
|
620
|
+
closing: {
|
|
621
|
+
layout: "closing",
|
|
622
|
+
purpose: "Create the final thank-you slide.",
|
|
623
|
+
whenToUse: "Use as the final slide of a deck.",
|
|
624
|
+
fields: {
|
|
625
|
+
layout: { type: "literal", required: true, value: "closing" },
|
|
626
|
+
title: { type: "string", required: false },
|
|
627
|
+
subtitle: { type: "string", required: false },
|
|
628
|
+
},
|
|
629
|
+
limits: { title: { recommendedChars: 12 }, subtitle: { recommendedChars: 28 } },
|
|
630
|
+
notes: ["Defaults to a BIT green closing slide.", "Use `subtitle` for defense/Q&A wording."],
|
|
631
|
+
example: { layout: "closing", title: "谢谢", subtitle: "敬请各位老师批评指正" },
|
|
632
|
+
},
|
|
633
|
+
};
|
|
634
|
+
|
|
635
|
+
Object.assign(layoutGuides, additionalLayoutGuides);
|
|
636
|
+
|
|
229
637
|
function listGuideLayouts() {
|
|
230
|
-
return
|
|
638
|
+
return listSupportedLayouts();
|
|
231
639
|
}
|
|
232
640
|
|
|
233
641
|
function getLayoutGuide(layout) {
|