mirror of
https://github.com/larksuite/cli.git
synced 2026-08-03 08:32:46 +08:00
Compare commits
1 Commits
main
...
docs/trans
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c40b7cfcbd |
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: lark-slides
|
||||
version: 1.0.0
|
||||
description: "飞书幻灯片:创建和编辑幻灯片。创建演示文稿、读取幻灯片内容、管理幻灯片页面(创建、删除、读取、局部替换)。当用户需要创建或编辑幻灯片、读取或修改单个页面时使用。当用户给出 doubao.com 的 /slides/ URL/token 时,也应直接使用本 skill,不要因为域名不是飞书而回退到 WebFetch;路由依据是 URL 路径模式和 token,而不是域名。不负责:云文档内容编辑(走 lark-doc)、云文档里的独立画板对象(走 lark-whiteboard,注意 slide 内嵌的流程图/架构图仍属本 skill)、上传或下载普通文件(走 lark-drive)。"
|
||||
description: "Feishu Slides: create and edit slides. Create presentations, read slide content, manage slide pages (create, delete, read, partial replace). Use when the user needs to create or edit slides, or read or modify a single page. When the user provides a doubao.com /slides/ URL/token, also use this skill directly; do not fall back to WebFetch just because the domain is not Feishu — routing is based on the URL path pattern and token, not the domain. Not responsible for: cloud document content editing (use lark-doc), standalone whiteboard objects inside cloud documents (use lark-whiteboard; note that flowcharts/architecture diagrams embedded in a slide still belong to this skill), uploading or downloading regular files (use lark-drive)."
|
||||
metadata:
|
||||
requires:
|
||||
bins: ["lark-cli"]
|
||||
@@ -10,185 +10,185 @@ metadata:
|
||||
|
||||
# slides (v1)
|
||||
|
||||
**CRITICAL — 全局硬约束:PPT 的尺寸是 960x540,确保主体内容在页面边界内。**
|
||||
**CRITICAL — Global hard constraint: the PPT canvas is 960x540; keep all primary content inside the page bounds.**
|
||||
|
||||
**CRITICAL — 图片至关重要:必须有意识的主动多用图片!素材图使用生图工具和搜图工具,缺图时用生图工具生成配图补足;背景图必须使用生图工具,且生图指令中必须明确要求不要出现任何文字。**
|
||||
**CRITICAL — Images matter: deliberately and proactively use plenty of images! Use image-generation and image-search tools for asset images, and generate supporting images when assets are missing; background images must come from an image-generation tool, and the generation prompt must explicitly require that no text appear.**
|
||||
|
||||
**CRITICAL — 防文本溢出:所有承载突出信息和密集文字的 `<content>` 必须设置 `autoFit="normal-auto-fit"`,字号会在框内自动缩排以防溢出。**
|
||||
**CRITICAL — Prevent text overflow: every `<content>` that carries highlighted information or dense text must set `autoFit="normal-auto-fit"` so the font size auto-shrinks within the box to avoid overflow.**
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| 用户需求 | 优先动作 | 关键文档 / 命令 |
|
||||
| User need | Preferred action | Key docs / commands |
|
||||
|----------|----------|-----------------|
|
||||
| 新建 PPT | 先规划 `slide_plan.json`,再按复杂度选择一步或两步创建 | `planning-layer.md`、`visual-planning.md`、`asset-planning.md`、`slides +create` |
|
||||
| 从模板创建或编辑已有本地 PPTX | 导入 PPTX 为 Slides | `lark-slides-pptx-template-workflows.md` |
|
||||
| 编辑单个标题、文本块、图片或局部元素 | 优先块级替换/插入,不改页序 | `slides +replace-slide`、`lark-slides-replace-slide.md` |
|
||||
| 读取或分析已有 PPT | 解析 slides/wiki token,用 shortcut 回读全文 XML 或读取单页 XML,保存 `xml_presentation_id`、`slide_id`、`revision_id` | `slides +xml-get`、`xml_presentation.slide.get` |
|
||||
| 获取幻灯片页面截图 | 用 `slide_id` 或页号指定页面,一次不超过 10 页 | `slides +screenshot`、`lark-slides-screenshot.md` |
|
||||
| 上传或使用图片 | 先上传为 `file_token`,禁止直接写 http(s) 外链 | `slides +media-upload`,或 `+create --slides` 的 `@./path` 占位符 |
|
||||
| 绘制图表 | 原生图表用 `<chart>`,其他用 `<shape>` + `<line>`,只有复杂 Mermaid、SVG 用 `<whiteboard>` | `xml-schema-quick-ref.md`、`slides_chart_demo.xml` |
|
||||
| 绘制表格 | 优先用 `rect` 和 `text` 模拟,其他用 `<table>` | `xml-schema-quick-ref.md` |
|
||||
| 使用图标 | 禁止盲猜 `iconType`,必须先检索 IconPark,再写 `<icon iconType="...">`,图标必须填充颜色并和背景有足够对比,禁止使用 emoji 图标 | `iconpark_tool.py search → resolve`、`iconpark.md` |
|
||||
| 创建失败、空白页、3350001、布局异常 | 先回读状态,再按排障清单修复,不假设原操作原子成功 | `troubleshooting.md`、`validation-checklist.md` |
|
||||
| Create a new PPT | Plan `slide_plan.json` first, then choose one-step or two-step creation by complexity | `planning-layer.md`, `visual-planning.md`, `asset-planning.md`, `slides +create` |
|
||||
| Create from a template or edit an existing local PPTX | Import the PPTX as Slides | `lark-slides-pptx-template-workflows.md` |
|
||||
| Edit a single title, text block, image, or local element | Prefer block-level replace/insert; do not change page order | `slides +replace-slide`, `lark-slides-replace-slide.md` |
|
||||
| Read or analyze an existing PPT | Resolve the slides/wiki token, use the shortcut to read back the full XML or a single page's XML, save `xml_presentation_id`, `slide_id`, `revision_id` | `slides +xml-get`, `xml_presentation.slide.get` |
|
||||
| Capture slide page screenshots | Specify pages by `slide_id` or page number, no more than 10 pages per call | `slides +screenshot`, `lark-slides-screenshot.md` |
|
||||
| Upload or use images | Upload first to get a `file_token`; never write http(s) external links directly | `slides +media-upload`, or the `@./path` placeholder of `+create --slides` |
|
||||
| Draw charts | Use `<chart>` for native charts, `<shape>` + `<line>` for others; only complex Mermaid/SVG goes into `<whiteboard>` | `xml-schema-quick-ref.md`, `slides_chart_demo.xml` |
|
||||
| Draw tables | Prefer simulating with `rect` and `text`; use `<table>` for the rest | `xml-schema-quick-ref.md` |
|
||||
| Use icons | Never guess `iconType` blindly — search IconPark first, then write `<icon iconType="...">`; icons must have a fill color with sufficient contrast against the background; emoji icons are forbidden | `iconpark_tool.py search → resolve`, `iconpark.md` |
|
||||
| Creation failure, blank pages, 3350001, broken layout | Read back the current state first, then fix per the troubleshooting checklist; never assume the original operation succeeded atomically | `troubleshooting.md`, `validation-checklist.md` |
|
||||
|
||||
**CRITICAL — 开始前 MUST 先用 Read 工具读取 [`../lark-shared/SKILL.md`](../lark-shared/SKILL.md),认证、权限和全局参数均以 lark-shared 为准。**
|
||||
**CRITICAL — Before starting, you MUST use the Read tool to read [`../lark-shared/SKILL.md`](../lark-shared/SKILL.md); authentication, permissions, and global parameters all follow lark-shared.**
|
||||
|
||||
**CRITICAL — 生成任何 XML 之前,MUST 先用 Read 工具读取 [xml-schema-quick-ref.md](references/xml-schema-quick-ref.md),禁止凭记忆猜测 XML 结构。**
|
||||
**CRITICAL — Before generating any XML, you MUST use the Read tool to read [xml-schema-quick-ref.md](references/xml-schema-quick-ref.md); guessing XML structure from memory is forbidden.**
|
||||
|
||||
**CRITICAL — 新建演示文稿或大幅改写页面时,MUST 先生成 `.lark-slides/plan/<deck-or-task-id>/slide_plan.json`,再生成 XML。先创建对应目录,规划层规则和中间产物生命周期见 [planning-layer.md](references/planning-layer.md)。仅替换一个标题、插入一个块等小型已有页编辑可豁免。**
|
||||
**CRITICAL — When creating a new presentation or substantially rewriting pages, you MUST first generate `.lark-slides/plan/<deck-or-task-id>/slide_plan.json`, then generate the XML. Create the directory first; planning-layer rules and intermediate artifact lifecycle are in [planning-layer.md](references/planning-layer.md). Small edits to existing pages, such as replacing one title or inserting one block, are exempt.**
|
||||
|
||||
**CRITICAL — 新建演示文稿或大幅改写页面时,生成 XML 前 MUST 读取 [visual-planning.md](references/visual-planning.md),确保 `layout_type`、`visual_focus`、`text_density` 实际改变页面几何、主视觉和文本量。**
|
||||
**CRITICAL — When creating a new presentation or substantially rewriting pages, you MUST read [visual-planning.md](references/visual-planning.md) before generating XML, ensuring `layout_type`, `visual_focus`, and `text_density` actually change the page geometry, primary visual, and amount of text.**
|
||||
|
||||
**CRITICAL — 新建演示文稿或大幅改写页面时,规划 `asset_need` MUST 遵循 [asset-planning.md](references/asset-planning.md)。**
|
||||
**CRITICAL — When creating a new presentation or substantially rewriting pages, planning `asset_need` MUST follow [asset-planning.md](references/asset-planning.md).**
|
||||
|
||||
**CRITICAL — 将完整 `<slide>` XML 提交给 `slides +create --slides`、`xml_presentation.slide create` 或 `slides +replace-pages` 之前,MUST 先把待提交 XML 保存到本地文件并运行 [`scripts/xml_text_overlap_lint.py`](scripts/xml_text_overlap_lint.py);`summary.error_count` 必须为 0 才能调用接口。**
|
||||
**CRITICAL — Before submitting a complete `<slide>` XML to `slides +create --slides`, `xml_presentation.slide create`, or `slides +replace-pages`, you MUST first save the XML to a local file and run [`scripts/xml_text_overlap_lint.py`](scripts/xml_text_overlap_lint.py); `summary.error_count` must be 0 before calling the API.**
|
||||
|
||||
**CRITICAL — 创建或大幅改写后,MUST 按 [validation-checklist.md](references/validation-checklist.md) 做显式验证:回读全文 XML、核对页数和关键元素、检查空白/破损页、明显溢出、布局风险。**
|
||||
**CRITICAL — After creating or substantially rewriting, you MUST perform explicit validation per [validation-checklist.md](references/validation-checklist.md): read back the full XML, verify page count and key elements, and check for blank/broken pages, obvious overflow, and layout risks.**
|
||||
|
||||
**CRITICAL — 创建前自检或失败排障时,MUST 按 [troubleshooting.md](references/troubleshooting.md) 检查 XML 转义、结构、shell 截断、图片 token、3350001 和布局风险。**
|
||||
**CRITICAL — For pre-creation self-checks or failure troubleshooting, you MUST follow [troubleshooting.md](references/troubleshooting.md) to check XML escaping, structure, shell truncation, image tokens, 3350001, and layout risks.**
|
||||
|
||||
**编辑已有幻灯片页面**:单个标题、文本块、图片或局部元素优先用 [`+replace-slide`](references/lark-slides-replace-slide.md)(块级替换/插入,不动页序);已有 Slides 的多页大改优先用 [`+replace-pages`](references/lark-slides-replace-pages.md) 在原 presentation 内批量重建页面,避免 `slides +create` 生成新链接。选择 action 和完整读-改-写流程见 [`lark-slides-edit-workflows.md`](references/lark-slides-edit-workflows.md)。
|
||||
**Editing existing slide pages**: for a single title, text block, image, or local element, prefer [`+replace-slide`](references/lark-slides-replace-slide.md) (block-level replace/insert, page order untouched); for large multi-page changes to existing Slides, prefer [`+replace-pages`](references/lark-slides-replace-pages.md) to rebuild pages in bulk within the original presentation, avoiding a new link from `slides +create`. See [`lark-slides-edit-workflows.md`](references/lark-slides-edit-workflows.md) for choosing an action and the full read-modify-write flow.
|
||||
|
||||
## 身份选择
|
||||
## Identity Selection
|
||||
|
||||
飞书幻灯片通常是用户自己的内容资源。**默认应优先显式使用 `--as user`(用户身份)执行 slides 相关操作**,始终显式指定身份。
|
||||
Feishu slides are usually the user's own content resources. **By default, explicitly prefer `--as user` (user identity) for slides operations**, and always specify the identity explicitly.
|
||||
|
||||
- **`--as user`(推荐)**:以当前登录用户身份创建、读取、管理演示文稿。执行前先完成用户授权:
|
||||
- **`--as user` (recommended)**: create, read, and manage presentations as the currently logged-in user. Complete user authorization first:
|
||||
|
||||
```bash
|
||||
lark-cli auth login --domain slides
|
||||
```
|
||||
|
||||
- **`--as bot`**:仅在用户明确要求以应用身份操作,或需要让 bot 持有/创建资源时使用。使用 bot 身份时,要额外确认 bot 是否真的有目标演示文稿的访问权限。
|
||||
- **`--as bot`**: only when the user explicitly asks to operate as the app identity, or when the bot needs to own/create the resource. When using the bot identity, additionally confirm that the bot actually has access to the target presentation.
|
||||
|
||||
**执行规则**:
|
||||
**Execution rules**:
|
||||
|
||||
1. 创建、读取、增删 slide、按用户给出的链接继续编辑已有 PPT,默认都先用 `--as user`。
|
||||
2. 如果出现权限不足,先检查当前是否误用了 bot 身份;不要默认回退到 bot。
|
||||
3. 只有在用户明确要求"用应用身份 / bot 身份操作",或当前工作流就是 bot 创建资源后再做协作授权时,才切换到 `--as bot`。
|
||||
1. Creating, reading, adding/deleting slides, and continuing to edit an existing PPT from a user-provided link all default to `--as user` first.
|
||||
2. On insufficient permission, first check whether the bot identity was used by mistake; do not fall back to bot by default.
|
||||
3. Only switch to `--as bot` when the user explicitly asks to "operate as the app / bot identity", or when the current workflow is bot-creates-resource-then-grants-collaboration.
|
||||
|
||||
## 执行前必做
|
||||
## Required Reading Before Execution
|
||||
|
||||
> **重要**:`references/slides_xml_schema_definition.xml` 是此 skill 唯一正确的 XML 协议来源;其他 md 仅是对它和 CLI schema 的摘要。
|
||||
> **Important**: `references/slides_xml_schema_definition.xml` is the only authoritative XML protocol source for this skill; the other md files are merely summaries of it and of the CLI schema.
|
||||
|
||||
高频只读:
|
||||
High-frequency, read-only:
|
||||
|
||||
- [xml-schema-quick-ref.md](references/xml-schema-quick-ref.md)
|
||||
- [planning-layer.md](references/planning-layer.md)(新建 / 大幅改写)
|
||||
- [visual-planning.md](references/visual-planning.md)(新建 / 大幅改写)
|
||||
- [asset-planning.md](references/asset-planning.md)(新建 / 大幅改写)
|
||||
- [validation-checklist.md](references/validation-checklist.md)(创建 / 大幅改写后)
|
||||
- [planning-layer.md](references/planning-layer.md) (new deck / substantial rewrite)
|
||||
- [visual-planning.md](references/visual-planning.md) (new deck / substantial rewrite)
|
||||
- [asset-planning.md](references/asset-planning.md) (new deck / substantial rewrite)
|
||||
- [validation-checklist.md](references/validation-checklist.md) (after creation / substantial rewrite)
|
||||
|
||||
按需再读:
|
||||
Read on demand:
|
||||
|
||||
- 创建:[`lark-slides-create.md`](references/lark-slides-create.md)
|
||||
- 编辑:[`lark-slides-edit-workflows.md`](references/lark-slides-edit-workflows.md)、[`lark-slides-replace-slide.md`](references/lark-slides-replace-slide.md)、[`lark-slides-replace-pages.md`](references/lark-slides-replace-pages.md)
|
||||
- 截图:[`lark-slides-screenshot.md`](references/lark-slides-screenshot.md)
|
||||
- 图片:[`lark-slides-media-upload.md`](references/lark-slides-media-upload.md)
|
||||
- 图标:[`iconpark.md`](references/iconpark.md)、[`scripts/iconpark_tool.py`](scripts/iconpark_tool.py)
|
||||
- 排障:[`troubleshooting.md`](references/troubleshooting.md)
|
||||
- 完整协议:[`slides_xml_schema_definition.xml`](references/slides_xml_schema_definition.xml)
|
||||
- Creation: [`lark-slides-create.md`](references/lark-slides-create.md)
|
||||
- Editing: [`lark-slides-edit-workflows.md`](references/lark-slides-edit-workflows.md), [`lark-slides-replace-slide.md`](references/lark-slides-replace-slide.md), [`lark-slides-replace-pages.md`](references/lark-slides-replace-pages.md)
|
||||
- Screenshots: [`lark-slides-screenshot.md`](references/lark-slides-screenshot.md)
|
||||
- Images: [`lark-slides-media-upload.md`](references/lark-slides-media-upload.md)
|
||||
- Icons: [`iconpark.md`](references/iconpark.md), [`scripts/iconpark_tool.py`](scripts/iconpark_tool.py)
|
||||
- Troubleshooting: [`troubleshooting.md`](references/troubleshooting.md)
|
||||
- Full protocol: [`slides_xml_schema_definition.xml`](references/slides_xml_schema_definition.xml)
|
||||
|
||||
## Workflow
|
||||
|
||||
> **这是演示文稿,不是文档。** 每页 slide 是独立的视觉画面,信息密度要适当,排版要留白。
|
||||
> **This is a presentation, not a document.** Each slide is an independent visual canvas; keep information density appropriate and leave whitespace in the layout.
|
||||
|
||||
### Design Ideas
|
||||
|
||||
不要生成无设计感的幻灯片。纯白背景 + 标题 + bullets 只能作为极简临时稿,不能作为正式交付。
|
||||
Do not generate slides with no sense of design. Plain white background + title + bullets is only acceptable as a minimal interim draft, never as a formal deliverable.
|
||||
|
||||
开始写 XML 前,先在 `slide_plan.json` 里确定 deck 级视觉策略:
|
||||
Before writing any XML, settle the deck-level visual strategy in `slide_plan.json`:
|
||||
|
||||
- **主题化配色**:配色必须服务本次主题、行业和受众,不要默认蓝色商务风。如果把同一套颜色换到另一个完全不同主题仍然成立,说明配色不够具体。
|
||||
- **主次比例**:选择 1 个主色承担约 60-70% 视觉权重,1-2 个辅助色承担结构和分区,1 个强调色只用于关键数字、结论或行动点。不要让所有颜色权重相同。
|
||||
- **背景一致性**:先确定全 deck 的背景策略,默认保持同一明暗基调和底色体系;只有分节、转场或强调页才有意改变背景,并必须通过相同主色、纹理、边栏或 motif 让变化看起来属于同一套设计。无论深浅,都要保证正文、图标和线条对比充足。
|
||||
- **统一 motif**:选择一个可复用视觉母题贯穿全文,例如粗侧边栏、圆形图标底、半出血图片区、编号节点、卡片左上角色块或大号数字。不要每页换一套装饰语言。
|
||||
- **Theme-driven palette**: the palette must serve this deck's topic, industry, and audience — do not default to a blue corporate look. If the same palette would work equally well for a completely different topic, it is not specific enough.
|
||||
- **Primary/secondary ratio**: pick 1 primary color carrying roughly 60-70% of the visual weight, 1-2 secondary colors for structure and sectioning, and 1 accent color used only for key numbers, conclusions, or action points. Do not give all colors equal weight.
|
||||
- **Background consistency**: decide the whole deck's background strategy first; by default keep the same light/dark tone and base color system. Only section dividers, transitions, or emphasis pages may deliberately change the background, and the change must still read as the same design via shared primary colors, textures, sidebars, or motifs. Whether light or dark, ensure sufficient contrast for body text, icons, and lines.
|
||||
- **Unified motif**: choose one reusable visual motif that runs through the deck, e.g. a thick sidebar, circular icon bases, half-bleed image areas, numbered nodes, a corner color block on cards, or oversized numerals. Do not switch decorative languages on every page.
|
||||
|
||||
每页至少要有一个视觉元素:图片、图标、图表、表格、流程、对比结构、大号数字、示意图或由 shape 组成的抽象视觉。文本框本身不算主视觉。
|
||||
Every page needs at least one visual element: an image, icon, chart, table, flow, comparison structure, big number, schematic, or an abstract visual composed of shapes. A text box by itself does not count as a primary visual.
|
||||
|
||||
可优先考虑这些页面形态:
|
||||
Prefer these page forms:
|
||||
|
||||
- **双栏结构**:左文右图或左图右文,视觉区域占 35-45% 宽度。
|
||||
- **图标行**:图标在色块或圆形底中,右侧是短标题和一句解释。
|
||||
- **2x2 / 2x3 网格**:适合能力、模块、风险、行动项,每格内容保持同等层级。
|
||||
- **半出血视觉**:图片或抽象形状占据左/右半屏,文字覆盖或贴边排布。
|
||||
- **大数字卡片**:关键指标用 60-72pt 数字,下面配 10-14pt 标签。
|
||||
- **对比列**:before/after、方案 A/B、问题/解法用左右并列,标题和基线严格对齐。
|
||||
- **时间线/流程图**:步骤用节点和箭头表达,流程方向必须一眼可见。
|
||||
- **Two-column structure**: text left / visual right or vice versa, with the visual area taking 35-45% of the width.
|
||||
- **Icon rows**: icons on color blocks or circular bases, with a short title and one-line explanation to the right.
|
||||
- **2x2 / 2x3 grids**: good for capabilities, modules, risks, action items; keep every cell at the same hierarchy level.
|
||||
- **Half-bleed visuals**: an image or abstract shape occupies the left/right half of the screen, with text overlaid or edge-aligned.
|
||||
- **Big-number cards**: key metrics in 60-72pt numerals with 10-14pt labels underneath.
|
||||
- **Comparison columns**: before/after, option A/B, problem/solution side by side, with titles and baselines strictly aligned.
|
||||
- **Timeline/flow diagrams**: express steps with nodes and arrows; the flow direction must be obvious at a glance.
|
||||
|
||||
字体和间距建议:
|
||||
Typography and spacing suggestions:
|
||||
|
||||
- 标题 36-44pt,关键结论可更大;正文 14-18pt;注释 10-12pt。
|
||||
- 正文默认左对齐;只在封面、结尾或大号数字场景中使用居中。
|
||||
- 页面边距至少 40px;内容块之间保持 24-40px 间距,并在同一 deck 内保持一致。
|
||||
- 卡片内边距要真实留出空间,不要让文字贴边;对齐 shape 和文字时要考虑文本框 padding。
|
||||
- Titles 36-44pt, key conclusions can be larger; body text 14-18pt; annotations 10-12pt.
|
||||
- Body text defaults to left-aligned; use centering only on covers, closing pages, or big-number scenes.
|
||||
- Page margins at least 40px; keep 24-40px spacing between content blocks, consistent within the same deck.
|
||||
- Card padding must leave real space — do not let text touch the edges; account for text-box padding when aligning shapes and text.
|
||||
|
||||
常见错误必须避免:
|
||||
Common mistakes to avoid:
|
||||
|
||||
- 不要所有页面复用同一种标题 + 三 bullets 版式。
|
||||
- 不要用低对比文字或低对比图标,例如浅灰字压在浅色背景上。
|
||||
- 不要让装饰线穿过文字,或让页脚、来源、编号挤压主体内容。
|
||||
- 不要把素材缺失表现为空白图片框;必须按 `fallback_if_missing` 生成 XML-native 视觉。
|
||||
- 不要留下模板占位文案、示例公司名、示例日期或与用户主题无关的原模板内容。
|
||||
- 不要使用 emoji。
|
||||
- 不要为了画出一个具象物体而堆叠 3 个以上仅用于拟形的 shape。
|
||||
- Do not reuse the same title + three-bullets layout on every page.
|
||||
- Do not use low-contrast text or icons, e.g. light gray text on a light background.
|
||||
- Do not let decorative lines cut through text, or let footers, sources, or page numbers crowd the main content.
|
||||
- Do not represent missing assets as empty image boxes; you must render an XML-native visual per `fallback_if_missing`.
|
||||
- Do not leave template placeholder copy, sample company names, sample dates, or original template content unrelated to the user's topic.
|
||||
- Do not use emoji.
|
||||
- Do not stack more than 3 shapes solely to mimic a concrete object.
|
||||
|
||||
### 创建方式选择
|
||||
### Choosing a Creation Method
|
||||
|
||||
| 场景 | 推荐方式 |
|
||||
| Scenario | Recommended approach |
|
||||
|------|----------|
|
||||
| 简单 XML(1-3 页、结构简单、几乎无复杂中文和特殊字符) | `slides +create --slides '[...]'` 一步创建 |
|
||||
| 复杂 XML(多页、含中文、大段文本、复杂布局、嵌套引号、特殊字符较多) | **两步创建**:先 `slides +create` 创建空白 PPT,再用 `xml_presentation.slide create` 逐页添加 |
|
||||
| 已有 PPT 继续追加或插入页面 | 使用 `xml_presentation.slide create`,必要时配合 `before_slide_id` |
|
||||
| Simple XML (1-3 pages, simple structure, almost no complex Chinese or special characters) | One-step creation with `slides +create --slides '[...]'` |
|
||||
| Complex XML (many pages, Chinese text, long passages, complex layouts, nested quotes, many special characters) | **Two-step creation**: `slides +create` an empty PPT first, then add pages one by one with `xml_presentation.slide create` |
|
||||
| Appending or inserting pages into an existing PPT | Use `xml_presentation.slide create`, with `before_slide_id` when needed |
|
||||
|
||||
> [!WARNING]
|
||||
> `--slides '[...]'` 的风险点主要在 shell 参数传递,而不是单纯页数。即使只有 1 页,只要 XML 足够复杂,也建议使用两步创建法。
|
||||
> The risk of `--slides '[...]'` lies mainly in shell argument passing, not page count alone. Even a single page warrants two-step creation if its XML is complex enough.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> `slides +create --slides` 底层会逐页创建,不是原子操作。中途失败时先记录 `xml_presentation_id`,回读确认当前状态,再继续修复或追加。
|
||||
> Under the hood, `slides +create --slides` creates pages one by one — it is not atomic. On mid-way failure, record the `xml_presentation_id` first, read back to confirm the current state, then continue fixing or appending.
|
||||
|
||||
### 生成流程
|
||||
### Generation Flow
|
||||
|
||||
```text
|
||||
Step 1: 需求澄清 & 读取知识
|
||||
- 澄清主题、受众、页数、风格;若用户上传 PPTX 作为模板,按顶部『用户自定义模板』规则处理
|
||||
- 读取 xml-schema-quick-ref.md;新建 / 大幅改写时还要读取 planning-layer.md、visual-planning.md、asset-planning.md
|
||||
Step 1: Clarify requirements & read knowledge
|
||||
- Clarify topic, audience, page count, style; if the user uploads a PPTX as a template, follow the "user custom template" rules at the top
|
||||
- Read xml-schema-quick-ref.md; for new decks / substantial rewrites also read planning-layer.md, visual-planning.md, asset-planning.md
|
||||
|
||||
Step 2: 生成大纲 → 用户确认 → 写入 slide_plan.json
|
||||
- 生成结构化大纲供用户确认
|
||||
- 新建 / 大幅改写必须先创建目录并写入 `.lark-slides/plan/<deck-or-task-id>/slide_plan.json`
|
||||
- plan 字段、路径命名和 `asset_need` 结构按 planning-layer.md / asset-planning.md 执行
|
||||
Step 2: Generate outline → user confirmation → write slide_plan.json
|
||||
- Generate a structured outline for the user to confirm
|
||||
- New decks / substantial rewrites must first create the directory and write `.lark-slides/plan/<deck-or-task-id>/slide_plan.json`
|
||||
- Plan fields, path naming, and the `asset_need` structure follow planning-layer.md / asset-planning.md
|
||||
|
||||
Step 3: 按 slide_plan.json 生成 XML → 创建
|
||||
- 逐页消费 plan:key_message 定主结论,layout_type 定几何,visual_focus 定主视觉,text_density 定文本量
|
||||
- 缺少真实素材时必须用 `fallback_if_missing` 生成 XML-native 兜底视觉;不要留空
|
||||
- 调用创建或整页替换接口前,先保存待提交 XML 并运行 xml_text_overlap_lint.py;error_count 不为 0 必须先修
|
||||
- 创建方式按“创建方式选择”判断;图片、复杂 XML、转义和 3350001 排查按 lark-slides-create.md、media-upload.md、troubleshooting.md 执行
|
||||
Step 3: Generate XML per slide_plan.json → create
|
||||
- Consume the plan page by page: key_message sets the main conclusion, layout_type sets geometry, visual_focus sets the primary visual, text_density sets text amount
|
||||
- When real assets are missing, use `fallback_if_missing` to render an XML-native fallback visual; never leave blanks
|
||||
- Before calling create or full-page replace APIs, save the pending XML and run xml_text_overlap_lint.py; a nonzero error_count must be fixed first
|
||||
- Choose the creation method per "Choosing a Creation Method"; handle images, complex XML, escaping, and 3350001 per lark-slides-create.md, media-upload.md, troubleshooting.md
|
||||
|
||||
Step 4: 审查 & 交付
|
||||
- 创建完成后,必须用 `slides +xml-get` 读取全文 XML,并按 validation-checklist.md 做显式验证记录
|
||||
- 失败或部分成功按 troubleshooting.md 处理;局部问题优先用 `+replace-slide` 修正
|
||||
- 没问题 → 交付:告知用户演示文稿 ID 和访问方式
|
||||
Step 4: Review & deliver
|
||||
- After creation, you must read the full XML with `slides +xml-get` and record explicit validation per validation-checklist.md
|
||||
- Handle failure or partial success per troubleshooting.md; fix local issues preferably with `+replace-slide`
|
||||
- All good → deliver: tell the user the presentation ID and how to access it
|
||||
```
|
||||
|
||||
### jq 命令模板(编辑已有 PPT 时使用)
|
||||
### jq Command Templates (for editing an existing PPT)
|
||||
|
||||
新建 PPT 推荐用 `+create --slides`。以下 jq 模板适用于向已有演示文稿追加页面的场景,可以避免手动转义双引号:
|
||||
For new PPTs, prefer `+create --slides`. The jq templates below apply when appending pages to an existing presentation, avoiding manual double-quote escaping:
|
||||
|
||||
```bash
|
||||
# 追加到末尾
|
||||
# Append to the end
|
||||
lark-cli slides xml_presentation.slide create \
|
||||
--as user \
|
||||
--params '{"xml_presentation_id":"YOUR_ID"}' \
|
||||
--data "$(jq -n --arg content '<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
||||
<style><fill><fillColor color="BACKGROUND_COLOR"/></fill></style>
|
||||
<data>
|
||||
<!-- 在这里放置 shape、line、table、chart 等元素 -->
|
||||
<!-- Place shape, line, table, chart, and other elements here -->
|
||||
</data>
|
||||
</slide>' '{slide:{content:$content}}')"
|
||||
|
||||
# 插到指定页之前:before_slide_id 必须在 --data body 里,与 slide 同级
|
||||
# ⚠️ 不要把 before_slide_id 写进 --params —— CLI 会当未知 query 参数静默下发,服务端忽略,新页跑到末尾
|
||||
# Insert before a specific page: before_slide_id must go in the --data body, as a sibling of slide
|
||||
# WARNING: do not put before_slide_id in --params -- the CLI silently sends it as an unknown query param, the server ignores it, and the new page lands at the end
|
||||
lark-cli slides xml_presentation.slide create \
|
||||
--as user \
|
||||
--params '{"xml_presentation_id":"YOUR_ID"}' \
|
||||
@@ -196,90 +196,90 @@ lark-cli slides xml_presentation.slide create \
|
||||
'{slide:{content:$content}, before_slide_id:$before}')"
|
||||
```
|
||||
|
||||
> 渐变色必须使用 `rgba()` 格式并带百分比停靠点,如 `linear-gradient(135deg,rgba(15,23,42,1) 0%,rgba(56,97,140,1) 100%)`。使用 `rgb()` 或省略停靠点会导致服务端回退为白色。
|
||||
> Gradients must use the `rgba()` format with percentage stops, e.g. `linear-gradient(135deg,rgba(15,23,42,1) 0%,rgba(56,97,140,1) 100%)`. Using `rgb()` or omitting stops causes the server to fall back to white.
|
||||
|
||||
### 大纲模板
|
||||
### Outline Template
|
||||
|
||||
生成大纲时使用以下格式,交给用户确认:
|
||||
Use the following format when generating the outline for user confirmation:
|
||||
|
||||
```text
|
||||
[PPT 标题] — [定位描述],面向 [目标受众]
|
||||
[PPT title] -- [positioning statement], targeted at [target audience]
|
||||
|
||||
页面结构(N 页):
|
||||
1. 封面页:[标题文案]
|
||||
2. [页面主题]:[要点1]、[要点2]、[要点3]
|
||||
3. [页面主题]:[要点描述]
|
||||
Page structure (N pages):
|
||||
1. Cover page: [title copy]
|
||||
2. [Page topic]: [point 1], [point 2], [point 3]
|
||||
3. [Page topic]: [point description]
|
||||
...
|
||||
N. 结尾页:[结尾文案]
|
||||
N. Closing page: [closing copy]
|
||||
|
||||
风格:[配色方案],[排版风格]
|
||||
Style: [color scheme], [layout style]
|
||||
```
|
||||
|
||||
## 核心概念
|
||||
## Core Concepts
|
||||
|
||||
### URL 格式与 Token
|
||||
### URL Formats and Tokens
|
||||
|
||||
| URL 格式 | 示例 | Token 类型 | 处理方式 |
|
||||
| URL format | Example | Token type | Handling |
|
||||
|----------|------|-----------|----------|
|
||||
| `/slides/` | `https://example.larkoffice.com/slides/xxxxxxxxxxxxx` | `xml_presentation_id` | URL 路径中的 token 直接作为 `xml_presentation_id` 使用 |
|
||||
| `/wiki/` | `https://example.larkoffice.com/wiki/wikcnxxxxxxxxx` | `wiki_token` | ⚠️ **不能直接使用**,需要先查询获取真实的 `obj_token` |
|
||||
| `/slides/` | `https://example.larkoffice.com/slides/xxxxxxxxxxxxx` | `xml_presentation_id` | Use the token in the URL path directly as `xml_presentation_id` |
|
||||
| `/wiki/` | `https://example.larkoffice.com/wiki/wikcnxxxxxxxxx` | `wiki_token` | ⚠️ **Cannot be used directly** — query first to obtain the real `obj_token` |
|
||||
|
||||
> `+replace-slide` 和 `+media-upload` shortcut 会自动解析以上两种 URL;直接调用原生 API 时仍需手动解析 wiki 链接。
|
||||
> The `+replace-slide` and `+media-upload` shortcuts automatically resolve both URL forms; you still need to resolve wiki links manually when calling native APIs directly.
|
||||
|
||||
### Wiki 链接特殊处理(关键!)
|
||||
### Special Handling for Wiki Links (critical!)
|
||||
|
||||
知识库链接(`/wiki/TOKEN`)不能直接当 `xml_presentation_id`。直接调用原生 API 前,先查询 wiki 节点,确认 `node.obj_type == "slides"`,再用 `node.obj_token` 作为真实 presentation ID。
|
||||
A knowledge-base link (`/wiki/TOKEN`) cannot be used directly as an `xml_presentation_id`. Before calling native APIs directly, query the wiki node, confirm `node.obj_type == "slides"`, then use `node.obj_token` as the real presentation ID.
|
||||
|
||||
```bash
|
||||
lark-cli wiki spaces get_node --as user --params '{"token":"wiki_token"}'
|
||||
```
|
||||
|
||||
Shortcut `+replace-slide` 和 `+media-upload` 会自动解析 `/wiki/` URL;手动调用 `xml_presentations.*` / `xml_presentation.slide.*` 时才需要自己做这一步。
|
||||
Shortcuts `+replace-slide` and `+media-upload` resolve `/wiki/` URLs automatically; only manual calls to `xml_presentations.*` / `xml_presentation.slide.*` require this step.
|
||||
|
||||
### 资源关系
|
||||
### Resource Relationships
|
||||
|
||||
```text
|
||||
Wiki Space (知识空间)
|
||||
└── Wiki Node (知识库节点, obj_type: slides)
|
||||
Wiki Space (knowledge space)
|
||||
└── Wiki Node (knowledge-base node, obj_type: slides)
|
||||
└── obj_token → xml_presentation_id
|
||||
|
||||
Slides (演示文稿)
|
||||
├── xml_presentation_id (演示文稿唯一标识)
|
||||
├── revision_id (版本号)
|
||||
└── Slide (幻灯片页面)
|
||||
└── slide_id (页面唯一标识)
|
||||
Slides (presentation)
|
||||
├── xml_presentation_id (unique presentation identifier)
|
||||
├── revision_id (revision number)
|
||||
└── Slide (slide page)
|
||||
└── slide_id (unique page identifier)
|
||||
```
|
||||
|
||||
## Shortcuts 与 API
|
||||
## Shortcuts and APIs
|
||||
|
||||
Shortcut 是对常用操作的高级封装(`lark-cli slides +<verb> [flags]`)。有 Shortcut 的操作优先使用。
|
||||
Shortcuts are high-level wrappers for common operations (`lark-cli slides +<verb> [flags]`). Prefer shortcuts whenever one exists for the operation.
|
||||
|
||||
| Shortcut | 说明 |
|
||||
| Shortcut | Description |
|
||||
|----------|------|
|
||||
| [`+create`](references/lark-slides-create.md) | 创建 PPT(可选 `--slides` 一步添加页面,支持 `<img src="@./local.png">` 占位符自动上传) |
|
||||
| [`+xml-get`](references/lark-slides-xml-get.md) | 读取全文或单页 XML,并可保存到本地文件,避免终端输出被截断 |
|
||||
| [`+media-upload`](references/lark-slides-media-upload.md) | 上传本地图片到指定演示文稿,返回 `file_token`(用作 `<img src="...">`),最大 20 MB |
|
||||
| [`+replace-slide`](references/lark-slides-replace-slide.md) | 对已有幻灯片页面进行块级替换/插入(`block_replace` / `block_insert`),自动注入 id 和 `<content/>`,不改变页序 |
|
||||
| [`+replace-pages`](references/lark-slides-replace-pages.md) | 在原演示文稿内批量重建多个页面:先创建新页到旧页前,再删除旧页;适合已有 Slides 的多页大改,不新建链接 |
|
||||
| [`+create`](references/lark-slides-create.md) | Create a PPT (optionally add pages in one step with `--slides`; supports `<img src="@./local.png">` placeholders with automatic upload) |
|
||||
| [`+xml-get`](references/lark-slides-xml-get.md) | Read the full or single-page XML, optionally saving to a local file to avoid terminal output truncation |
|
||||
| [`+media-upload`](references/lark-slides-media-upload.md) | Upload a local image to a specific presentation and return a `file_token` (used as `<img src="...">`), max 20 MB |
|
||||
| [`+replace-slide`](references/lark-slides-replace-slide.md) | Block-level replace/insert on an existing slide page (`block_replace` / `block_insert`); auto-injects ids and `<content/>` without changing page order |
|
||||
| [`+replace-pages`](references/lark-slides-replace-pages.md) | Bulk-rebuild multiple pages within the original presentation: create new pages before the old ones, then delete the old ones; suited for large multi-page changes to existing Slides without creating a new link |
|
||||
|
||||
没有 Shortcut 覆盖时使用原生 API。高频资源:`slides +xml-get` 读取全文;`xml_presentation.slide.create/delete/get/replace` 管理单页。
|
||||
Use native APIs when no shortcut covers the operation. High-frequency resources: `slides +xml-get` reads the full document; `xml_presentation.slide.create/delete/get/replace` manage single pages.
|
||||
|
||||
```bash
|
||||
lark-cli schema slides.<resource>.<method> # 调用 API 前必须先查看参数结构
|
||||
lark-cli slides <resource> <method> [flags] # 调用 API
|
||||
lark-cli schema slides.<resource>.<method> # Must inspect the parameter structure before calling an API
|
||||
lark-cli slides <resource> <method> [flags] # Call the API
|
||||
```
|
||||
|
||||
> **重要**:使用原生 API 时,必须先运行 `schema` 查看 `--data` / `--params` 参数结构,不要猜测字段格式。
|
||||
> **Important**: when using native APIs, you must run `schema` first to inspect the `--data` / `--params` structure; do not guess field formats.
|
||||
|
||||
## 核心规则
|
||||
## Core Rules
|
||||
|
||||
1. **先规划再写 XML**:新建演示文稿或大幅改写页面时,必须先写入 `.lark-slides/plan/<deck-or-task-id>/slide_plan.json`;模板、风格和大纲只能作为规划输入,不能绕过规划层
|
||||
2. **创建流程**:简单短 XML(1-3 页、结构简单、特殊字符少)可用 `slides +create --slides '[...]'` 一步创建;复杂内容、含图片/中文大段文本/嵌套引号/较多特殊字符,或超过 10 页时,默认先 `slides +create` 创建空白 PPT,再用 `xml_presentation.slide.create` 逐页添加
|
||||
3. **`<slide>` 直接子元素只有 `<style>`、`<data>`、`<note>`**:文本和图形必须放在 `<data>` 内
|
||||
4. **文本通过 `<content>` 表达**:必须用 `<content><p>...</p></content>`,不能把文字直接写在 shape 内
|
||||
5. **保存关键 ID**:后续操作需要 `xml_presentation_id`、`slide_id`、`revision_id`
|
||||
6. **删除谨慎**:删除操作不可逆,且至少保留一页幻灯片
|
||||
7. **编辑已有页面优先原链接更新**:修改单个 shape/img 用 `+replace-slide`(`block_replace` / `block_insert`),不要整页重建;已有 Slides 的多页整页重建用 `+replace-pages`,不要用 `slides +create` 新建整份 PPT;只有没有 shortcut 覆盖的特殊单页整页操作才手动 `slide.create` + `slide.delete`
|
||||
8. **`<img src>` 只能用上传到飞书 drive 的 `file_token`,禁止使用 http(s) 外链 URL**:飞书 slides 渲染端不会代理外链图片,外链 src 在 PPT 里通常不显示或显示破图。流程必须是「先把图存到本地 → 用 `slides +media-upload` 上传或 `+create --slides` 的 `@./path` 占位符自动上传 → 拿 `file_token` 写进 `<img src>`」。如果用户给了网图链接,先 `curl`/下载到 CWD 内再走上传流程,不要直接把外链 URL 塞进 `src`。**图片最大 20 MB**(slides upload API 不支持分片上传)。
|
||||
1. **Plan before writing XML**: when creating a new presentation or substantially rewriting pages, you must first write `.lark-slides/plan/<deck-or-task-id>/slide_plan.json`; templates, styles, and outlines are only planning inputs and cannot bypass the planning layer
|
||||
2. **Creation flow**: simple short XML (1-3 pages, simple structure, few special characters) can use one-step `slides +create --slides '[...]'`; for complex content — images, long Chinese passages, nested quotes, many special characters — or more than 10 pages, default to `slides +create` for an empty PPT first, then add pages one by one with `xml_presentation.slide.create`
|
||||
3. **The only direct children of `<slide>` are `<style>`, `<data>`, and `<note>`**: text and graphics must live inside `<data>`
|
||||
4. **Text is expressed through `<content>`**: it must be `<content><p>...</p></content>`; text cannot be written directly inside a shape
|
||||
5. **Save key IDs**: later operations need `xml_presentation_id`, `slide_id`, `revision_id`
|
||||
6. **Delete with caution**: deletion is irreversible, and at least one slide must remain
|
||||
7. **Prefer in-place updates when editing existing pages**: to modify a single shape/img use `+replace-slide` (`block_replace` / `block_insert`), do not rebuild whole pages; for multi-page full rebuilds of existing Slides use `+replace-pages`, do not create a whole new PPT with `slides +create`; only special single-page full-page operations not covered by any shortcut warrant manual `slide.create` + `slide.delete`
|
||||
8. **`<img src>` may only use a `file_token` uploaded to Feishu drive; http(s) external URLs are forbidden**: the Feishu slides renderer does not proxy external images, so external `src` values usually render as missing or broken images in the PPT. The flow must be "save the image locally first → upload via `slides +media-upload` or the auto-uploading `@./path` placeholder of `+create --slides` → write the `file_token` into `<img src>`". If the user provides a web image link, first `curl`/download it into the CWD and then go through the upload flow; never put the external URL into `src` directly. **Max image size 20 MB** (the slides upload API does not support multipart upload).
|
||||
|
||||
> **注意**:如果 md 内容与 `slides_xml_schema_definition.xml` 或 `lark-cli schema slides.<resource>.<method>` 输出不一致,以后两者为准。
|
||||
> **Note**: if any md content conflicts with `slides_xml_schema_definition.xml` or the output of `lark-cli schema slides.<resource>.<method>`, the latter two take precedence.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Asset Planning
|
||||
|
||||
新建演示文稿或大幅改写页面时,在写入 `slide_plan.json` 前后都可以参考本文件。目标是让 agent 主动识别有价值的图、图标、图表、流程图、时序图、架构图、装饰图案、截图或示意图需求,同时保持 deck 在没有真实素材时也能完整执行。
|
||||
When creating a new presentation or substantially rewriting the page, you can refer to this file before and after writing `slide_plan.json`. The goal is to allow the agent to proactively identify valuable diagrams, icons, diagrams, flow charts, sequence diagrams, architecture diagrams, decorative patterns, screenshots or schematic diagram requirements, while maintaining complete execution of the deck even without real materials.
|
||||
|
||||
本文件只定义轻量资产规划。不要把它理解成素材采集流程。
|
||||
This document only defines lightweight asset planning. Don’t understand it as a material collection process.
|
||||
|
||||
## Core Rules
|
||||
|
||||
@@ -71,7 +71,7 @@ For `asset_type: "chart"`:
|
||||
- `user_provided`: when the user provides concrete values, tables, CSV, or metric lists, use those values and do not replace them with mock data.
|
||||
- `mock_placeholder`: when the user asks for a placeholder, template, example, or chart position to replace later, use mock data in a native `<chart>`.
|
||||
- `mock_required_by_intent`: when the user does not provide concrete values but asks for data expression, charts, trends, comparisons, or distributions, use mock data in a native `<chart>`.
|
||||
- Mock data must be labeled as `模拟数据,仅占位,待替换真实数据` or equivalent. Do not present mock values as facts.
|
||||
- Mock data must be labeled as `Mock data, placeholder only, to be replaced with real data` or equivalent. Do not present mock values as facts.
|
||||
- Manual drawing fallbacks are allowed only for unsupported chart types such as scatter, funnel, waterfall-like custom visuals, or decorative non-data visuals.
|
||||
|
||||
`fallback_if_missing` must be concrete enough to turn into XML, for example:
|
||||
@@ -79,7 +79,7 @@ For `asset_type: "chart"`:
|
||||
- "Draw a simplified attention matrix with 5 token labels, semi-transparent cells, and arrows to output token."
|
||||
- "Use three grouped boxes with arrows from client to gateway to service; add small protocol labels."
|
||||
- "Render a native `<chart>` using the user-provided series."
|
||||
- "Render a native `<chart>` with mock placeholder values and label it as `模拟数据,仅占位,待替换真实数据`."
|
||||
- "Render a native `<chart>` with mock placeholder values and label it as `Simulated data, placeholder only, to be replaced with real data`."
|
||||
- "Use a bordered placeholder panel with product area labels, not an empty image."
|
||||
|
||||
Weak fallbacks to avoid:
|
||||
|
||||
@@ -1,44 +1,44 @@
|
||||
# 完整操作示例
|
||||
# Complete Operation Examples
|
||||
|
||||
本文档提供与 CLI schema 一致的调用示例,XML 内容均遵循 [slides_xml_schema_definition.xml](slides_xml_schema_definition.xml)。
|
||||
This document provides invocation examples consistent with the CLI schema; all XML content follows [slides_xml_schema_definition.xml](slides_xml_schema_definition.xml).
|
||||
|
||||
> **重要**:新建 PPT 请使用 `slides +create --slides`,传入由 `<slide>` XML 字符串组成的 JSON 数组;每个元素必须是一页完整的 `<slide>`。复杂内容建议先创建空白 PPT,再通过 `xml_presentation.slide.create` 逐页添加。完整 `<presentation>` XML 可用于本地 lint 或读取,但不能直接作为 `+create` 的提交参数。
|
||||
> **Important**: to create a new PPT, use `slides +create --slides` with a JSON array of `<slide>` XML strings; each element must be one complete `<slide>` page. For complex content, create an empty PPT first, then add pages one by one via `xml_presentation.slide.create`. A complete `<presentation>` XML can be used for local lint or reading, but cannot be submitted directly as the `+create` argument.
|
||||
|
||||
## 目录
|
||||
## Table of Contents
|
||||
|
||||
- [示例 1:可靠创建 6 页 PPT](#示例-1可靠创建-6-页-ppt)
|
||||
- [示例 7: +replace-slide + block_insert 给已有页加图](#示例-7-replace-slide--block_insert-给已有页加图)
|
||||
- [示例 8: +replace-slide + block_replace 替换一个块](#示例-8-replace-slide--block_replace-替换一个块)
|
||||
- [Example 1: Reliably create a 6-page PPT](#example-1-reliably-create-a-6-page-ppt)
|
||||
- [Example 7: +replace-slide + block_insert to add an image to an existing page](#example-7-replace-slide--block_insert-to-add-an-image-to-an-existing-page)
|
||||
- [Example 8: +replace-slide + block_replace to replace one block](#example-8-replace-slide--block_replace-to-replace-one-block)
|
||||
|
||||
## 示例 1:可靠创建 6 页 PPT
|
||||
## Example 1: Reliably create a 6-page PPT
|
||||
|
||||
### 1. 写入规划文件
|
||||
### 1. Write the plan file
|
||||
|
||||
```bash
|
||||
DECK_DIR=".lark-slides/plan/reliable-six-page-ppt"
|
||||
mkdir -p "$DECK_DIR"
|
||||
|
||||
# 按 planning-layer.md 写入 "$DECK_DIR/slide_plan.json",
|
||||
# 至少记录 6 页的顺序和标题。
|
||||
# Write "$DECK_DIR/slide_plan.json" per planning-layer.md,
|
||||
# recording at least the order and titles of the 6 pages.
|
||||
```
|
||||
|
||||
### 2. 为每页保存独立 XML
|
||||
### 2. Save a standalone XML file per page
|
||||
|
||||
每个文件都是完整的 `<slide>`。下面的循环会生成 6 个独立 XML 文件;实际项目中可将每页主体替换为规划内容。
|
||||
Each file is a complete `<slide>`. The loop below generates 6 standalone XML files; in a real project, replace each page body with the planned content.
|
||||
|
||||
```bash
|
||||
titles=("主题与结论" "问题背景" "核心方法" "关键数据" "执行计划" "总结与行动")
|
||||
titles=("Topic and Conclusion" "Problem Background" "Core Method" "Key Data" "Execution Plan" "Summary and Actions")
|
||||
for i in {1..6}; do
|
||||
printf -v page '%02d' "$i"
|
||||
cat > "$DECK_DIR/slide-$page.xml" <<XML
|
||||
<slide xmlns="http://www.larkoffice.com/sml/2.0"><style><fill><fillColor color="rgb(248,250,252)"/></fill></style><data><shape type="rect" topLeftX="56" topLeftY="56" width="12" height="428"><fill><fillColor color="rgb(37,99,235)"/></fill></shape><shape type="text" topLeftX="100" topLeftY="160" width="760" height="90"><content textType="title" autoFit="normal-auto-fit"><p>${titles[$((i-1))]}</p></content></shape><shape type="text" topLeftX="100" topLeftY="290" width="700" height="70"><content textType="body" autoFit="normal-auto-fit"><p>页面主体内容。</p></content></shape></data></slide>
|
||||
<slide xmlns="http://www.larkoffice.com/sml/2.0"><style><fill><fillColor color="rgb(248,250,252)"/></fill></style><data><shape type="rect" topLeftX="56" topLeftY="56" width="12" height="428"><fill><fillColor color="rgb(37,99,235)"/></fill></shape><shape type="text" topLeftX="100" topLeftY="160" width="760" height="90"><content textType="title" autoFit="normal-auto-fit"><p>${titles[$((i-1))]}</p></content></shape><shape type="text" topLeftX="100" topLeftY="290" width="700" height="70"><content textType="body" autoFit="normal-auto-fit"><p>Page body content.</p></content></shape></data></slide>
|
||||
XML
|
||||
done
|
||||
```
|
||||
|
||||
### 3. 逐页运行 lint
|
||||
### 3. Run lint on each page
|
||||
|
||||
提交前检查每个独立 XML。`summary.error_count` 必须为 `0`,否则先修复 XML 或布局问题。
|
||||
Check every standalone XML before submission. `summary.error_count` must be `0`; otherwise fix the XML or layout issues first.
|
||||
|
||||
```bash
|
||||
for slide_xml in "$DECK_DIR"/slide-0{1,2,3,4,5,6}.xml; do
|
||||
@@ -49,13 +49,13 @@ done
|
||||
test "$(jq -s 'map(.summary.error_count) | add' "$DECK_DIR"/slide-0{1,2,3,4,5,6}.lint.json)" = "0"
|
||||
```
|
||||
|
||||
### 4. 使用 `+create` 创建 6 页 PPT
|
||||
### 4. Create the 6-page PPT with `+create`
|
||||
|
||||
`--slides` 接收由 6 个完整 `<slide>` XML 字符串组成的 JSON 数组;使用 `jq --rawfile` 避免手动处理 XML 引号和换行。
|
||||
`--slides` receives a JSON array of 6 complete `<slide>` XML strings; use `jq --rawfile` to avoid manually handling XML quotes and newlines.
|
||||
|
||||
```bash
|
||||
lark-cli slides +create --as user \
|
||||
--title "可靠创建 6 页 PPT" \
|
||||
--title "Reliably created 6-page PPT" \
|
||||
--slides "$(jq -n \
|
||||
--rawfile s1 "$DECK_DIR/slide-01.xml" \
|
||||
--rawfile s2 "$DECK_DIR/slide-02.xml" \
|
||||
@@ -78,9 +78,9 @@ fi
|
||||
echo "$PRESENTATION_ID" > "$DECK_DIR/xml_presentation_id"
|
||||
```
|
||||
|
||||
如果创建中途失败,先保存已经返回的 `xml_presentation_id`,再回读确认实际已创建页数。
|
||||
If creation fails midway, save the already-returned `xml_presentation_id` first, then read back to confirm how many pages were actually created.
|
||||
|
||||
### 5. 用 `+xml-get` 回读全文 XML
|
||||
### 5. Read back the full XML with `+xml-get`
|
||||
|
||||
```bash
|
||||
lark-cli slides +xml-get --as user \
|
||||
@@ -88,4 +88,3 @@ lark-cli slides +xml-get --as user \
|
||||
--output "$DECK_DIR/readback.xml" \
|
||||
--json | tee "$DECK_DIR/readback.json"
|
||||
```
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
# IconPark 图标
|
||||
# IconPark Icons
|
||||
|
||||
IconPark 图标通过 `<icon>` 写入 slides XML,`iconType` 必须来自本 skill 的离线索引,避免凭记忆拼路径。
|
||||
IconPark icons are written into slides XML via `<icon>`; `iconType` must come from this skill's offline index — never assemble paths from memory.
|
||||
|
||||
## 机器优先流程
|
||||
## Machine-First Flow
|
||||
|
||||
```bash
|
||||
python3 skills/lark-slides/scripts/iconpark_tool.py search --query "增长趋势" --limit 8
|
||||
python3 skills/lark-slides/scripts/iconpark_tool.py search --query "growth trend" --limit 8
|
||||
python3 skills/lark-slides/scripts/iconpark_tool.py resolve --name chart-line
|
||||
python3 skills/lark-slides/scripts/iconpark_tool.py list-categories
|
||||
```
|
||||
|
||||
`search` 返回 JSON 数组,每项包含 `iconType`、`category`、`name`、`tags`、`score`。直接把选中的 `iconType` 写入 XML,并为图标指定可见颜色:
|
||||
`search` returns a JSON array where each item contains `iconType`, `category`, `name`, `tags`, `score`. Write the chosen `iconType` directly into the XML and give the icon a visible color:
|
||||
|
||||
```xml
|
||||
<icon iconType="iconpark/Charts/chart-line.svg" topLeftX="80" topLeftY="120" width="32" height="32">
|
||||
@@ -20,27 +20,27 @@ python3 skills/lark-slides/scripts/iconpark_tool.py list-categories
|
||||
</icon>
|
||||
```
|
||||
|
||||
## 使用规则
|
||||
## Usage Rules
|
||||
|
||||
- 默认先检索:语义图标需求必须先用 `iconpark_tool.py search --limit 8` 或 `--limit 10`,让 agent 从候选里结合版面语义二次判断;不要阅读全文索引,也不要编造不存在的 `iconType`。
|
||||
- 图标用于概念提示、步骤、状态、指标、角色和导航;不要用无关装饰图标填充版面。
|
||||
- 常用尺寸:行内状态图标 16-24px,卡片标题图标 28-40px,主视觉图标 56-96px。
|
||||
- 视觉规范要求图标设置非透明 `fillColor`,显式指定颜色并和背景有足够对比;深色背景优先放在浅色圆形/方形底上,或使用 `rgba(255, 255, 255, 1)` 作为图标填充色。
|
||||
- 查不到合适图标时,用 shape、line、text 画 XML-native fallback,不留空图标位。
|
||||
- Search first by default: semantic icon needs must first go through `iconpark_tool.py search --limit 8` or `--limit 10`, letting the agent make a second-pass choice among candidates based on the layout semantics; do not read the full index, and do not invent nonexistent `iconType` values.
|
||||
- Icons are for concept cues, steps, statuses, metrics, roles, and navigation; do not fill the layout with irrelevant decorative icons.
|
||||
- Common sizes: inline status icons 16-24px, card title icons 28-40px, primary visual icons 56-96px.
|
||||
- The visual spec requires icons to set a non-transparent `fillColor`, explicitly specifying a color with sufficient contrast against the background; on dark backgrounds, prefer placing icons on light circular/square bases, or use `rgba(255, 255, 255, 1)` as the icon fill color.
|
||||
- When no suitable icon can be found, draw an XML-native fallback with shapes, lines, and text; do not leave an empty icon slot.
|
||||
|
||||
## 高频示例
|
||||
## High-Frequency Examples
|
||||
|
||||
| 语义 | iconType |
|
||||
| Semantics | iconType |
|
||||
|---|---|
|
||||
| 设置/配置 | `iconpark/Base/setting.svg` |
|
||||
| 目标 | `iconpark/Base/aiming.svg` |
|
||||
| 增长趋势 | `iconpark/Charts/positive-dynamics.svg` |
|
||||
| 折线趋势 | `iconpark/Charts/chart-line.svg` |
|
||||
| 占比 | `iconpark/Charts/chart-proportion.svg` |
|
||||
| 数据看板 | `iconpark/Charts/data-screen.svg` |
|
||||
| 成功 | `iconpark/Character/check-one.svg` |
|
||||
| 失败/风险 | `iconpark/Character/close-one.svg` |
|
||||
| 团队/用户 | `iconpark/Peoples/peoples.svg` |
|
||||
| 安全防护 | `iconpark/Safe/protect.svg` |
|
||||
| 全球/市场 | `iconpark/Travel/world.svg` |
|
||||
| 邮件/联系 | `iconpark/Office/envelope-one.svg` |
|
||||
| Settings/configuration | `iconpark/Base/setting.svg` |
|
||||
| Target | `iconpark/Base/aiming.svg` |
|
||||
| Growth trend | `iconpark/Charts/positive-dynamics.svg` |
|
||||
| Line trend | `iconpark/Charts/chart-line.svg` |
|
||||
| Proportion | `iconpark/Charts/chart-proportion.svg` |
|
||||
| Data dashboard | `iconpark/Charts/data-screen.svg` |
|
||||
| Success | `iconpark/Character/check-one.svg` |
|
||||
| Failure/risk | `iconpark/Character/close-one.svg` |
|
||||
| Team/users | `iconpark/Peoples/peoples.svg` |
|
||||
| Security | `iconpark/Safe/protect.svg` |
|
||||
| Global/market | `iconpark/Travel/world.svg` |
|
||||
| Email/contact | `iconpark/Office/envelope-one.svg` |
|
||||
|
||||
@@ -1,140 +1,140 @@
|
||||
|
||||
# slides +create(创建飞书幻灯片)
|
||||
# slides +create (Create a Feishu Slides Presentation)
|
||||
|
||||
> **前置条件:** 先阅读 [`../lark-shared/SKILL.md`](../../lark-shared/SKILL.md) 了解认证、全局参数和安全规则。
|
||||
> **Prerequisite:** Read [`../lark-shared/SKILL.md`](../../lark-shared/SKILL.md) first to understand authentication, global parameters, and safety rules.
|
||||
|
||||
创建一个新的飞书幻灯片演示文稿,可选一步添加页面内容。
|
||||
Creates a new Feishu Slides presentation, with the option to add page content in one step.
|
||||
|
||||
- 禁止:从完整 <presentation> XML 解析/拆分/重序列化生成提交 payload。
|
||||
- 推荐:提交源直接就是单页 <slide> XML;+create --slides 只接受已经人工/程序直接生成的 slide 数组,不接受由
|
||||
presentation 动态拆出来的数组。
|
||||
- Forbidden: generating the submission payload by parsing/splitting/re-serializing a full <presentation> XML.
|
||||
- Recommended: the submission source should be single-page <slide> XML directly; +create --slides only accepts slide arrays that were produced directly by hand or by a program, not arrays
|
||||
dynamically split out of a presentation.
|
||||
|
||||
- 最稳:复杂 deck 默认空 deck + 单页 slide create,每次只提交一个 <slide>。
|
||||
- Most reliable: for complex decks, default to an empty deck + per-page slide create, submitting only one <slide> at a time.
|
||||
|
||||
- 注意:复杂 XML 不适合直接塞命令行,中文、引号、特殊字符较多时,直接拼接 --slides 容易发生 shell 转义或截断。建议将每页 XML 保存为独立文件,使用 `jq --rawfile` 组装 JSON 数组,避免手动处理 XML 引号和换行。
|
||||
- Note: complex XML is not suitable for inlining directly on the command line. When there is a lot of non-ASCII text, quotes, or special characters, concatenating `--slides` directly can easily cause shell escaping errors or truncation. Save each page's XML as a separate file and assemble the JSON array with `jq --rawfile` to avoid handling XML quotes and newlines manually.
|
||||
|
||||
## 命令
|
||||
## Command
|
||||
|
||||
```bash
|
||||
# 创建空白 PPT
|
||||
lark-cli slides +create --title "项目汇报"
|
||||
# Create a blank presentation
|
||||
lark-cli slides +create --title "Project Report"
|
||||
|
||||
# 创建 PPT + 添加 slide 页面
|
||||
lark-cli slides +create --title "项目汇报" --slides '[
|
||||
"<slide xmlns=\"http://www.larkoffice.com/sml/2.0\"><data><shape type=\"text\" topLeftX=\"80\" topLeftY=\"80\" width=\"800\" height=\"120\"><content textType=\"title\"><p>封面</p></content></shape></data></slide>",
|
||||
"<slide xmlns=\"http://www.larkoffice.com/sml/2.0\"><data><shape type=\"text\" topLeftX=\"80\" topLeftY=\"80\" width=\"800\" height=\"120\"><content textType=\"title\"><p>第二页</p></content></shape></data></slide>"
|
||||
# Create a presentation + add slide pages
|
||||
lark-cli slides +create --title "Project Report" --slides '[
|
||||
"<slide xmlns=\"http://www.larkoffice.com/sml/2.0\"><data><shape type=\"text\" topLeftX=\"80\" topLeftY=\"80\" width=\"800\" height=\"120\"><content textType=\"title\"><p>Cover</p></content></shape></data></slide>",
|
||||
"<slide xmlns=\"http://www.larkoffice.com/sml/2.0\"><data><shape type=\"text\" topLeftX=\"80\" topLeftY=\"80\" width=\"800\" height=\"120\"><content textType=\"title\"><p>Page 2</p></content></shape></data></slide>"
|
||||
]'
|
||||
|
||||
# 以应用身份创建(自动授权当前用户)
|
||||
lark-cli slides +create --title "项目汇报" --as bot
|
||||
# Create as the app identity (automatically grants access to the current user)
|
||||
lark-cli slides +create --title "Project Report" --as bot
|
||||
|
||||
# 预览(不执行)
|
||||
lark-cli slides +create --title "项目汇报" --slides '[...]' --dry-run
|
||||
# Preview (does not execute)
|
||||
lark-cli slides +create --title "Project Report" --slides '[...]' --dry-run
|
||||
```
|
||||
|
||||
复杂内容建议按页保存 XML,再用 `jq --rawfile` 组装 `--slides` 参数:
|
||||
For complex content, save the XML per page and assemble the `--slides` argument with `jq --rawfile`:
|
||||
|
||||
```bash
|
||||
lark-cli slides +create --as user --title "项目汇报" \
|
||||
lark-cli slides +create --as user --title "Project Report" \
|
||||
--slides "$(jq -n \
|
||||
--rawfile s1 .lark-slides/plan/project/slide-01.xml \
|
||||
--rawfile s2 .lark-slides/plan/project/slide-02.xml \
|
||||
'[$s1, $s2]')"
|
||||
```
|
||||
|
||||
`--rawfile` 会把文件内容作为字符串读入 JSON,自动处理 XML 中的引号和换行;不要手动拼接带大量转义符的 JSON 字符串。
|
||||
`--rawfile` reads the file content into JSON as a string, automatically handling quotes and newlines inside the XML; do not manually concatenate JSON strings full of escape characters.
|
||||
|
||||
## 返回值
|
||||
## Return Value
|
||||
|
||||
工具成功执行后,返回一个 JSON 对象,包含以下字段:
|
||||
On success, the tool returns a JSON object with the following fields:
|
||||
|
||||
- **`xml_presentation_id`**(string):演示文稿的唯一标识符,后续添加页面时需要此 ID
|
||||
- **`title`**(string):演示文稿标题
|
||||
- **`url`**(string,可选):演示文稿的在线链接,如有返回则务必展示给用户(需要 drive 相关权限;若获取失败则不返回此字段)
|
||||
- **`revision_id`**(integer):演示文稿版本号
|
||||
- **`slide_ids`**(string[],可选):仅传 `--slides` 时返回,成功添加的页面 ID 列表
|
||||
- **`slides_added`**(integer,可选):仅传 `--slides` 时返回,成功添加的页面数量
|
||||
- **`images_uploaded`**(integer,可选):仅 `--slides` 中含 `@<本地路径>` 占位符时返回,已上传的去重后图片数量
|
||||
- **`permission_grant`**(object,可选):仅 `--as bot` 时返回,说明是否已自动为当前 CLI 用户授予可管理权限
|
||||
- **`xml_presentation_id`** (string): the unique identifier of the presentation; this ID is required when adding pages later
|
||||
- **`title`** (string): the presentation title
|
||||
- **`url`** (string, optional): the online link to the presentation. If returned, always show it to the user (requires drive-related permissions; if retrieval fails, this field is not returned)
|
||||
- **`revision_id`** (integer): the presentation revision number
|
||||
- **`slide_ids`** (string[], optional): returned only when `--slides` is passed; the list of successfully added page IDs
|
||||
- **`slides_added`** (integer, optional): returned only when `--slides` is passed; the number of successfully added pages
|
||||
- **`images_uploaded`** (integer, optional): returned only when `--slides` contains `@<local path>` placeholders; the number of deduplicated images uploaded
|
||||
- **`permission_grant`** (object, optional): returned only with `--as bot`; indicates whether manage permission was automatically granted to the current CLI user
|
||||
|
||||
> [!IMPORTANT]
|
||||
> 不传 `--slides` 时,`slides +create` 只创建空白演示文稿。创建后需要使用 `xml_presentation.slide create` 逐页添加 slide 内容。
|
||||
> Without `--slides`, `slides +create` only creates a blank presentation. After creation, use `xml_presentation.slide create` to add slide content page by page.
|
||||
>
|
||||
> 传了 `--slides` 时,CLI 先创建空白演示文稿,再逐页调用 `xml_presentation.slide create` 添加页面。如果某一页添加失败,CLI 会停止并报错,已创建的演示文稿和已添加的页面会保留。
|
||||
> With `--slides`, the CLI first creates a blank presentation, then calls `xml_presentation.slide create` page by page to add pages. If adding any page fails, the CLI stops and reports an error; the created presentation and already-added pages are kept.
|
||||
>
|
||||
> 如果演示文稿是**以应用身份(bot)创建**的,如 `lark-cli slides +create --as bot`,CLI 会**尝试为当前 CLI 用户自动授予该演示文稿的 `full_access`(可管理权限)**。
|
||||
> If the presentation is **created as the app identity (bot)**, e.g. `lark-cli slides +create --as bot`, the CLI will **attempt to automatically grant the current CLI user `full_access` (manage permission) on the presentation**.
|
||||
>
|
||||
> 以应用身份创建时,结果里会额外返回 `permission_grant` 字段,明确说明授权结果:
|
||||
> - `status = granted`:当前 CLI 用户已获得该演示文稿的可管理权限
|
||||
> - `status = skipped`:本地没有可用的当前用户 `open_id`,因此不会自动授权
|
||||
> - `status = failed`:演示文稿已创建成功,但自动授权用户失败
|
||||
> When creating as the app identity, the result additionally includes a `permission_grant` field that explicitly states the grant outcome:
|
||||
> - `status = granted`: the current CLI user has been granted manage permission on the presentation
|
||||
> - `status = skipped`: no usable current-user `open_id` is available locally, so no automatic grant is performed
|
||||
> - `status = failed`: the presentation was created successfully, but automatically granting the user failed
|
||||
>
|
||||
> **不要擅自执行 owner 转移。** 如果用户需要把 owner 转给自己,必须单独确认。
|
||||
> **Never transfer ownership on your own initiative.** If the user wants ownership transferred to themselves, that must be confirmed separately.
|
||||
|
||||
## 参数
|
||||
## Parameters
|
||||
|
||||
| 参数 | 必填 | 说明 |
|
||||
| Parameter | Required | Description |
|
||||
|------|------|------|
|
||||
| `--title` | 否 | 演示文稿标题(不传则默认 "Untitled") |
|
||||
| `--slides` | 否 | slide 内容 JSON 数组,每个元素是一个 `<slide>` XML 字符串(最多 10 个;超过 10 页请先用 `+create` 创建空白 PPT,再用 `xml_presentation.slide create` 逐页添加) |
|
||||
| `--title` | No | Presentation title (defaults to "Untitled" if omitted) |
|
||||
| `--slides` | No | JSON array of slide content, each element a `<slide>` XML string (max 10; for more than 10 pages, first create a blank presentation with `+create`, then add pages one by one with `xml_presentation.slide create`) |
|
||||
|
||||
## `--slides` 参数格式
|
||||
## `--slides` Parameter Format
|
||||
|
||||
```json
|
||||
[
|
||||
"<slide xmlns=\"http://www.larkoffice.com/sml/2.0\">...第1页XML...</slide>",
|
||||
"<slide xmlns=\"http://www.larkoffice.com/sml/2.0\">...第2页XML...</slide>"
|
||||
"<slide xmlns=\"http://www.larkoffice.com/sml/2.0\">...page 1 XML...</slide>",
|
||||
"<slide xmlns=\"http://www.larkoffice.com/sml/2.0\">...page 2 XML...</slide>"
|
||||
]
|
||||
```
|
||||
|
||||
JSON string 数组,每个元素是一页 slide 的完整 XML。CLI 内部负责包装成 API 所需的 `{"slide": {"content": "..."}}` 格式并逐页调用。
|
||||
A JSON string array where each element is the complete XML of one slide page. The CLI internally wraps each into the `{"slide": {"content": "..."}}` format required by the API and calls it page by page.
|
||||
|
||||
### 本地图片:`@<path>` 占位符
|
||||
### Local Images: `@<path>` Placeholders
|
||||
|
||||
`<img>` 元素的 `src` 属性如果以 `@` 开头,CLI 会把它当作本地文件路径,自动上传到当前演示文稿,并把占位符替换为返回的 `file_token`。
|
||||
If the `src` attribute of an `<img>` element starts with `@`, the CLI treats it as a local file path, automatically uploads it to the current presentation, and replaces the placeholder with the returned `file_token`.
|
||||
|
||||
```bash
|
||||
lark-cli slides +create --as user --title "图测试" --slides '[
|
||||
lark-cli slides +create --as user --title "Image Test" --slides '[
|
||||
"<slide xmlns=\"http://www.larkoffice.com/sml/2.0\"><data><img src=\"@./assets/chart.png\" topLeftX=\"100\" topLeftY=\"100\" width=\"320\" height=\"180\"/></data></slide>"
|
||||
]'
|
||||
```
|
||||
|
||||
行为:
|
||||
Behavior:
|
||||
|
||||
- 路径相对于**当前工作目录**(CWD)解析;**必须是 CWD 内的相对路径**(如 `./pic.png`、`./assets/x.png`)
|
||||
- 同一份图被多次引用时**只上传一次**(按路径去重)
|
||||
- `src` 不以 `@` 开头的会原样保留,但**只允许写 `slides +media-upload` 拿到的 `file_token`**;**禁止写 http(s) 外链 URL**:飞书 slides 渲染端不会代理外链图片,外链 src 通常显示破图。要用网图必须先下载到 CWD 内、再走上传流程
|
||||
- 单张图片最大 20 MB(slides upload API 不支持分片上传)
|
||||
- 校验阶段就会检查所有占位符文件存在及大小;缺文件或超限直接报错,不会创建空白 PPT 占位
|
||||
- 创空白 PPT → 上传所有图 → 替换 token → 逐页创建 slide,按这个顺序执行
|
||||
- Paths are resolved relative to the **current working directory** (CWD); they **must be relative paths inside the CWD** (e.g. `./pic.png`, `./assets/x.png`)
|
||||
- The same image referenced multiple times is **uploaded only once** (deduplicated by path)
|
||||
- `src` values not starting with `@` are kept as-is, but **only `file_token` values obtained from `slides +media-upload` are allowed**; **http(s) external URLs are forbidden**: the Feishu slides renderer does not proxy external images, so external `src` values usually render as broken images. To use a web image, download it into the CWD first and go through the upload workflow
|
||||
- Maximum 20 MB per image (the slides upload API does not support chunked upload)
|
||||
- All placeholder files are checked for existence and size during the validation phase; a missing or oversized file fails immediately, without creating a blank placeholder presentation
|
||||
- Execution order: create the blank presentation → upload all images → replace tokens → create slides page by page
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **路径必须在 CWD 内**:`@/abs/path/x.png` 或 `@../up/x.png` 这种会被 CLI 拒绝(报 `unsafe file path`)。如果素材在别的目录,先 `cd` 过去再执行。
|
||||
> **Paths must be inside the CWD**: forms like `@/abs/path/x.png` or `@../up/x.png` are rejected by the CLI (with an `unsafe file path` error). If the assets live in another directory, `cd` there first, then run the command.
|
||||
|
||||
### 给已有 PPT 加带图新页
|
||||
### Adding a New Page with an Image to an Existing Presentation
|
||||
|
||||
`+create --slides` 只在新建 PPT 时使用 `@` 占位符。给已有 PPT 加带图新页要分两步(CLI 没封装这个组合):
|
||||
`+create --slides` only supports `@` placeholders when creating a new presentation. Adding a new page with an image to an existing presentation takes two steps (the CLI does not wrap this combination):
|
||||
|
||||
```bash
|
||||
# 1) 上传图片
|
||||
# 1) Upload the image
|
||||
TOKEN=$(lark-cli slides +media-upload --as user \
|
||||
--file ./pic.png --presentation $PRES_ID | jq -r .data.file_token)
|
||||
|
||||
# 2) 用返回的 file_token 创建带图新页
|
||||
# 2) Create the new page with the image using the returned file_token
|
||||
lark-cli slides xml_presentation.slide create --as user \
|
||||
--params "{\"xml_presentation_id\":\"$PRES_ID\"}" \
|
||||
--data "{\"slide\":{\"content\":\"<slide xmlns=\\\"http://www.larkoffice.com/sml/2.0\\\"><data><img src=\\\"$TOKEN\\\" topLeftX=\\\"100\\\" topLeftY=\\\"100\\\" width=\\\"200\\\" height=\\\"200\\\"/></data></slide>\"}}"
|
||||
```
|
||||
|
||||
## 创建后续步骤
|
||||
## Next Steps After Creation
|
||||
|
||||
如果没有使用 `--slides`,`slides +create` 返回的 `xml_presentation_id` 用于后续操作:
|
||||
If `--slides` was not used, the `xml_presentation_id` returned by `slides +create` is used for subsequent operations:
|
||||
|
||||
```bash
|
||||
# 第 1 步:创建空白 PPT
|
||||
PRES_ID=$(lark-cli slides +create --title "项目汇报" | jq -r '.data.xml_presentation_id')
|
||||
# Step 1: create a blank presentation
|
||||
PRES_ID=$(lark-cli slides +create --title "Project Report" | jq -r '.data.xml_presentation_id')
|
||||
|
||||
# 第 2 步:添加页面(使用返回的 xml_presentation_id)
|
||||
# Step 2: add a page (using the returned xml_presentation_id)
|
||||
lark-cli slides xml_presentation.slide create --as user \
|
||||
--params "{\"xml_presentation_id\":\"$PRES_ID\"}" \
|
||||
--data '{
|
||||
@@ -144,13 +144,13 @@ lark-cli slides xml_presentation.slide create --as user \
|
||||
}'
|
||||
```
|
||||
|
||||
## 常见错误
|
||||
## Common Errors
|
||||
|
||||
| 错误码 | 含义 | 解决方案 |
|
||||
| Error Code | Meaning | Solution |
|
||||
|--------|------|----------|
|
||||
| 400 | 参数错误 | 检查参数格式是否正确 |
|
||||
| 403 | 权限不足 | 检查是否拥有 `slides:presentation:create` 和 `slides:presentation:write_only` scope |
|
||||
| 400 | Invalid parameters | Check that the parameter format is correct |
|
||||
| 403 | Insufficient permissions | Check that you have the `slides:presentation:create` and `slides:presentation:write_only` scopes |
|
||||
|
||||
## 相关命令
|
||||
## Related Commands
|
||||
|
||||
- [slides +xml-get](lark-slides-xml-get.md) — 读取 PPT 内容并保存到本地文件
|
||||
- [slides +xml-get](lark-slides-xml-get.md) — read presentation content and save it to a local file
|
||||
|
||||
@@ -1,83 +1,83 @@
|
||||
# 编辑已有 PPT:读-改-写闭环
|
||||
# Edit existing PPT: read-modify-write closed loop
|
||||
|
||||
局部编辑走 **shortcut [`+replace-slide`](lark-slides-replace-slide.md)**(块级替换 / 插入),配合 `xml_presentation.slide.get` 读原页拿 `block_id`。已有 Slides 的多页整页重建走 **[`+replace-pages`](lark-slides-replace-pages.md)**,保持原 presentation 链接不变。
|
||||
For partial editing, use **shortcut [`+replace-slide`](lark-slides-replace-slide.md)** (block-level replacement/insertion), and use `xml_presentation.slide.get` to read the original page and get `block_id`. Rebuild multiple full pages of existing Slides using **[`+replace-pages`](lark-slides-replace-pages.md)**, keeping the original presentation link unchanged.
|
||||
|
||||
> 生成 XML 前**必读** [xml-schema-quick-ref.md](xml-schema-quick-ref.md)。
|
||||
> **Must read** before generating XML [xml-schema-quick-ref.md](xml-schema-quick-ref.md).
|
||||
|
||||
## 决策树:block_replace vs block_insert
|
||||
## Decision tree: block_replace vs block_insert
|
||||
|
||||
| 需求 | 推荐 action | 理由 |
|
||||
| Requirements | Recommended actions | Reasons |
|
||||
|------|------------|------|
|
||||
| 已知某块的 `block_id`,要换这块内容(改标题、换图、挪坐标) | `block_replace` | 精准替换,原子性好;`replacement` 根 `id` 由 CLI 自动注入为 `block_id` |
|
||||
| 只加 1~N 个元素、不动现有布局 | `block_insert` | 新增不覆盖,可选 `insert_before_block_id` 指定位置 |
|
||||
| 一次动多个元素(如:换标题 + 加图) | 单次 `--parts` 里拼多条 | 整批作为原子事务,任一失败整批不生效;`block_replace` 和 `block_insert` 可混用 |
|
||||
| 多页版式重建、整页坐标重排 | `+replace-pages` | 原 presentation 内批量 create-before/delete-old,不生成新 Slides 链接 |
|
||||
| Knowing the `block_id` of a certain block, you need to replace the content of this block (change the title, change the picture, move the coordinates) | `block_replace` | Accurate replacement, good atomicity; `replacement` root `id` is automatically injected into `block_id` by CLI |
|
||||
| Only add 1~N elements, leaving the existing layout unchanged | `block_insert` | Add new elements without overwriting, optional `insert_before_block_id` specifies the position |
|
||||
| Move multiple elements at one time (e.g. change title + add picture) | Move multiple elements in a single `--parts` | The entire batch is treated as an atomic transaction, and the entire batch will not take effect if any one fails; `block_replace` and `block_insert` can be mixed |
|
||||
| Multi-page layout reconstruction, whole-page coordinate rearrangement | `+replace-pages` | Batch create-before/delete-old in the original presentation, without generating new Slides links |
|
||||
|
||||
> **没有字段级 patch**:即便只想改一个 `shape` 的 `topLeftX`,也得把整个块的新 XML 写出来用 `block_replace`。这不是"微调",是块级重写。
|
||||
> **No field-level patch**: Even if you only want to change `topLeftX` of a `shape`, you have to write out the new XML of the entire block and use `block_replace`. This isn't "tweaking", it's a block-level rewrite.
|
||||
|
||||
## 最小读-改-写闭环
|
||||
## Minimum read-modify-write closed loop
|
||||
|
||||
```bash
|
||||
PID="xml_presentation_id_here"
|
||||
SID="slide_id_here"
|
||||
|
||||
# 1. 读原页,从 XML 里挑出要改的块的 3 位 short id(如 bUn / bab)
|
||||
# 1. Read the original page and pick out the 3-digit short id of the block to be changed from the XML (such as bUn / bab)
|
||||
lark-cli slides xml_presentation.slide get --as user \
|
||||
--params "{\"xml_presentation_id\":\"$PID\",\"slide_id\":\"$SID\"}"
|
||||
|
||||
# 2. 用 +replace-slide 直接改那个块(不需要搬原 XML)
|
||||
# 2. Use +replace-slide to directly change that block (no need to move the original XML)
|
||||
lark-cli slides +replace-slide --as user \
|
||||
--presentation "$PID" --slide-id "$SID" \
|
||||
--parts '[{"action":"block_replace","block_id":"bUn","replacement":"<shape type=\"text\" topLeftX=\"80\" topLeftY=\"80\" width=\"800\" height=\"120\"><content textType=\"title\"><p>新标题</p></content></shape>"}]'
|
||||
--parts '[{"action":"block_replace","block_id":"bUn","replacement":"<shape type=\"text\" topLeftX=\"80\" topLeftY=\"80\" width=\"800\" height=\"120\"><content textType=\"title\"><p>New title</p></content></shape>"}]'
|
||||
```
|
||||
|
||||
`slide_id` / 页序不会变。`block_replace` 的 `replacement` 根元素 `id` 会自动注入为 `block_id`,用户手写 XML 时不需要自己加。
|
||||
`slide_id` / The page order will not change. The `replacement` root element `id` of `block_replace` will be automatically injected as `block_id`, and users do not need to add it themselves when handwriting XML.
|
||||
|
||||
## `revision_id` 参数
|
||||
## `revision_id` parameter
|
||||
|
||||
`--revision-id` 默认 `-1`,表示基于当前最新版执行。传具体版本号时,服务端以该版本为 base 应用变更:
|
||||
`--revision-id` defaults to `-1`, which means execution based on the latest version. When passing a specific version number, the server uses this version as the base to apply the changes:
|
||||
|
||||
```bash
|
||||
# 读时拿当前 revision_id
|
||||
# Get the current revision_id when reading
|
||||
REV=$(lark-cli slides xml_presentation.slide get --as user \
|
||||
--params "{\"xml_presentation_id\":\"$PID\",\"slide_id\":\"$SID\"}" \
|
||||
| jq '.data.revision_id')
|
||||
|
||||
# 写时传该版本号,服务端以此为 base
|
||||
# Pass the version number when writing, and the server will use this as the base
|
||||
lark-cli slides +replace-slide --as user \
|
||||
--presentation "$PID" --slide-id "$SID" --revision-id "$REV" \
|
||||
--parts '[{"action":"block_replace","block_id":"bUn","replacement":"<shape type=\"rect\" topLeftX=\"100\" topLeftY=\"100\" width=\"200\" height=\"100\"/>"}]'
|
||||
```
|
||||
|
||||
注意:传不存在的版本号(超过当前 revision)会返回 3350002 not found;不确定时用 `-1` 即可。
|
||||
Note: Passing a version number that does not exist (exceeds the current revision) will return 3350002 not found; use `-1` when unsure.
|
||||
|
||||
## `--tid` 事务锁
|
||||
## `--tid` transaction lock
|
||||
|
||||
跨请求的并发事务 ID,多人协作长事务才用得上。**单人单次调用留空**即可。
|
||||
The cross-request concurrent transaction ID is only useful when multiple people collaborate on long transactions. **Single person single call can be left blank**.
|
||||
|
||||
## 两种 action 详解
|
||||
## Detailed explanation of two actions
|
||||
|
||||
### block_replace — 整块替换
|
||||
### block_replace — Whole block replacement
|
||||
|
||||
适合"已知块 ID,要换这块整体内容"的场景。`replacement` 根元素的 `id="<block_id>"` 由 CLI 自动注入(用户手写的 XML 如果没带 `id` 直接省略即可;如果带了错的会被覆盖为正确值)。
|
||||
Suitable for scenarios where "the block ID is known and the entire content of this block needs to be changed". The `id="<block_id>"` of the `replacement` root element is automatically injected by the CLI (if the user's handwritten XML does not contain `id`, it can be omitted directly; if it contains the wrong one, it will be overwritten with the correct value).
|
||||
|
||||
```bash
|
||||
lark-cli slides +replace-slide --as user \
|
||||
--presentation "$PID" --slide-id "$SID" \
|
||||
--parts '[{"action":"block_replace","block_id":"bab","replacement":"<shape type=\"text\" topLeftX=\"80\" topLeftY=\"80\" width=\"800\" height=\"120\"><content textType=\"title\"><p>新标题</p></content></shape>"}]'
|
||||
--parts '[{"action":"block_replace","block_id":"bab","replacement":"<shape type=\"text\" topLeftX=\"80\" topLeftY=\"80\" width=\"800\" height=\"120\"><content textType=\"title\"><p>New title</p></content></shape>"}]'
|
||||
```
|
||||
|
||||
字段说明:
|
||||
Field description:
|
||||
|
||||
| 字段 | 必填 | 说明 |
|
||||
| Field | Required | Description |
|
||||
|------|------|------|
|
||||
| `action` | 是 | 固定为 `block_replace` |
|
||||
| `block_id` | 是 | 目标块的 3 位 short element ID(从 `slide.get` 返回的 XML 里读)|
|
||||
| `replacement` | 是 | 新 XML 片段;根元素 `id` 会被 CLI 自动注入为 `block_id` |
|
||||
| `action` | Yes | Fixed to `block_replace` |
|
||||
| `block_id` | Yes | The 3-digit short element ID of the target block (read from the XML returned by `slide.get`) |
|
||||
| `replacement` | Yes | New XML fragment; the root element `id` will be automatically injected by the CLI as `block_id` |
|
||||
|
||||
### block_insert — 整块插入
|
||||
### block_insert — Whole block insertion
|
||||
|
||||
适合"只想加一个元素,不动现有元素"的场景(典型:给已有页加图)。
|
||||
Suitable for scenarios where "you only want to add one element and leave the existing elements unchanged" (typical: adding a picture to an existing page).
|
||||
|
||||
```bash
|
||||
lark-cli slides +replace-slide --as user \
|
||||
@@ -86,59 +86,59 @@ lark-cli slides +replace-slide --as user \
|
||||
'[{action:"block_insert",insertion:("<img src=\""+$token+"\" topLeftX=\"500\" topLeftY=\"100\" width=\"200\" height=\"150\"/>"),insert_before_block_id:"baa"}]')"
|
||||
```
|
||||
|
||||
字段说明:
|
||||
Field description:
|
||||
|
||||
| 字段 | 必填 | 说明 |
|
||||
| Field | Required | Description |
|
||||
|------|------|------|
|
||||
| `action` | 是 | 固定为 `block_insert` |
|
||||
| `insertion` | 是 | 要插入的完整 XML 片段 |
|
||||
| `insert_before_block_id` | 否 | 插到这个块之前;省略(不提供此字段)则追加到页面末尾 |
|
||||
| `action` | Yes | Fixed to `block_insert` |
|
||||
| `insertion` | Yes | The complete XML fragment to insert |
|
||||
| `insert_before_block_id` | No | Insert before this block; if omitted (this field is not provided), it will be appended to the end of the page |
|
||||
|
||||
> **`<img>` 必须用 `file_token`**,不能用外链 URL——先 `slides +media-upload --file ./pic.png --presentation $PID` 拿 token。
|
||||
> **`<img>` must use `file_token`**, and external link URL cannot be used - first `slides +media-upload --file ./pic.png --presentation $PID` to get the token.
|
||||
|
||||
### 批量 parts
|
||||
### Batch parts
|
||||
|
||||
一次 `--parts` 最多 200 条,按数组顺序串行执行。`block_replace` 和 `block_insert` 可以在同一批次混用。举例:一次性把标题块替换、然后在末尾追加一个装饰图。
|
||||
`--parts` can run up to 200 items at a time, executed serially in array order. `block_replace` and `block_insert` can be mixed in the same batch. Example: Replace the title block at once, and then add a decorative image at the end.
|
||||
|
||||
```bash
|
||||
lark-cli slides +replace-slide --as user \
|
||||
--presentation "$PID" --slide-id "$SID" \
|
||||
--parts '[
|
||||
{"action":"block_replace","block_id":"bab","replacement":"<shape type=\"text\" topLeftX=\"80\" topLeftY=\"80\" width=\"800\" height=\"120\"><content textType=\"title\"><p>新标题</p></content></shape>"},
|
||||
{"action":"block_replace","block_id":"bab","replacement":"<shape type=\"text\" topLeftX=\"80\" topLeftY=\"80\" width=\"800\" height=\"120\"><content textType=\"title\"><p>New title</p></content></shape>"},
|
||||
{"action":"block_insert","insertion":"<img src=\"<file_token>\" topLeftX=\"700\" topLeftY=\"400\" width=\"180\" height=\"100\"/>"}
|
||||
]'
|
||||
```
|
||||
|
||||
整批作为原子事务:任一条失败整批不生效。失败时后端通常返回 3350001;若响应中带 `failed_part_index` / `failed_reason` 字段,shortcut 会原样透传。
|
||||
The entire batch is treated as an atomic transaction: if any transaction fails, the entire batch will not take effect. The backend usually returns 3350001 when it fails; if the response contains the `failed_part_index` / `failed_reason` fields, shortcut will be transparently transmitted as is.
|
||||
|
||||
## 大 --parts 用 jq 或 stdin 组装
|
||||
## Large --parts assembled with jq or stdin
|
||||
|
||||
`--parts` 支持 `@file`(读文件)和 `-`(stdin)作为值来源,适合批量 XML 场景:
|
||||
`--parts` supports `@file` (reading files) and `-` (stdin) as value sources, suitable for batch XML scenarios:
|
||||
|
||||
```bash
|
||||
# 从文件读
|
||||
# Read from file
|
||||
lark-cli slides +replace-slide --as user --presentation "$PID" --slide-id "$SID" \
|
||||
--parts @parts.json
|
||||
|
||||
# 从 stdin 读
|
||||
# Read from stdin
|
||||
cat parts.json | lark-cli slides +replace-slide --as user --presentation "$PID" --slide-id "$SID" \
|
||||
--parts -
|
||||
```
|
||||
|
||||
## 错误排查
|
||||
## Error troubleshooting
|
||||
|
||||
| 现象 | 原因 | 对策 |
|
||||
| Phenomenon | Cause | Countermeasures |
|
||||
|------|------|------|
|
||||
| 3350001,hint 含 "block_id not found" | `parts[i].block_id` 在当前页不存在 | 重新 `slide.get` 拿最新 XML,按里面的 short ID 再填 |
|
||||
| 3350002 not found | `--revision-id` 传了不存在的版本号 | 用 `-1` 或实际存在的 `revision_id` |
|
||||
| `<img>` 不显示 / 显示破图 | `src` 写了外链 URL | 换成通过 `+media-upload` 拿到的 `file_token` |
|
||||
| 3350001(block_replace 返回) | 正常情况下 CLI 已自动注入 `id` 和 `<content/>`;如果仍报错,确认 `block_id` 在当前页存在(重新 `slide.get`),检查 XML 结构是否合法;坐标是否超出 960×540 范围 | — |
|
||||
| 3350001, hint contains "block_id not found" | `parts[i].block_id` does not exist in the current page | Re-slide.get` to get the latest XML, press the short ID inside and fill in |
|
||||
| 3350002 not found | `--revision-id` passed a version number that does not exist | Use `-1` or an actual `revision_id` |
|
||||
| `<img>` does not display / displays broken images | `src` writes the external link URL | Replace with `file_token` obtained through `+media-upload` |
|
||||
| 3350001 (returned by block_replace) | Under normal circumstances, CLI has automatically injected `id` and `<content/>`; if an error is still reported, confirm that `block_id` exists in the current page (retry `slide.get`), check whether the XML structure is legal; whether the coordinates exceed the 960×540 range | — |
|
||||
|
||||
## 相关文档
|
||||
## Related documents
|
||||
|
||||
- [lark-slides-replace-slide.md](lark-slides-replace-slide.md) — +replace-slide shortcut 参数详情
|
||||
- [lark-slides-replace-pages.md](lark-slides-replace-pages.md) — 多页整页重建 shortcut
|
||||
- [lark-slides-xml-presentation-slide-get.md](lark-slides-xml-presentation-slide-get.md) — slide.get 参考(拿 `block_id` / `revision_id`)
|
||||
- [lark-slides-xml-presentation-slide-replace.md](lark-slides-xml-presentation-slide-replace.md) — 底层 replace API 参考(一般直接用 shortcut 即可)
|
||||
- [lark-slides-media-upload.md](lark-slides-media-upload.md) — 上传图片拿 file_token
|
||||
- [xml-schema-quick-ref.md](xml-schema-quick-ref.md) — XML 元素和属性速查
|
||||
- [lark-slides-replace-slide.md](lark-slides-replace-slide.md) — +replace-slide shortcut parameter details
|
||||
- [lark-slides-replace-pages.md](lark-slides-replace-pages.md) — Multi-page full page reconstruction shortcut
|
||||
- [lark-slides-xml-presentation-slide-get.md](lark-slides-xml-presentation-slide-get.md) — slide.get reference (get `block_id` / `revision_id`)
|
||||
- [lark-slides-xml-presentation-slide-replace.md](lark-slides-xml-presentation-slide-replace.md) — Low-level replace API reference (generally use shortcut directly)
|
||||
- [lark-slides-media-upload.md](lark-slides-media-upload.md) — Upload pictures and get file_token
|
||||
- [xml-schema-quick-ref.md](xml-schema-quick-ref.md) — A quick look at XML elements and attributes
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
|
||||
# slides +media-upload(上传本地图片到飞书幻灯片)
|
||||
# slides +media-upload (Upload a Local Image to Feishu Slides)
|
||||
|
||||
> **前置条件:** 先阅读 [`../lark-shared/SKILL.md`](../../lark-shared/SKILL.md) 了解认证、全局参数和安全规则。
|
||||
> **Prerequisite:** Read [`../lark-shared/SKILL.md`](../../lark-shared/SKILL.md) first to understand authentication, global parameters, and safety rules.
|
||||
|
||||
把本地图片上传到指定演示文稿的 drive 媒体库,返回 `file_token`。**返回的 token 作为 `<img src="...">` 的值塞进 slide XML 即可显示图片。**
|
||||
Uploads a local image to the drive media library of the specified presentation and returns a `file_token`. **Put the returned token into `<img src="...">` in the slide XML to display the image.**
|
||||
|
||||
## 命令
|
||||
## Command
|
||||
|
||||
```bash
|
||||
# 直接传 xml_presentation_id
|
||||
# Pass the xml_presentation_id directly
|
||||
lark-cli slides +media-upload --as user \
|
||||
--file ./pic.png \
|
||||
--presentation slidesXXXXXXXXXXXXXXXXXXXXXX
|
||||
|
||||
# 传 slides URL 也行
|
||||
# A slides URL also works
|
||||
lark-cli slides +media-upload --as user \
|
||||
--file ./chart.png \
|
||||
--presentation "https://xxx.feishu.cn/slides/slidesXXXXXXXXXXXXXXXXXXXXXX"
|
||||
|
||||
# 传 wiki URL(CLI 自动 wiki.spaces.get_node 解析为真实 token,校验 obj_type=slides)
|
||||
# A wiki URL works too (the CLI automatically resolves it to the real token via wiki.spaces.get_node, verifying obj_type=slides)
|
||||
lark-cli slides +media-upload --as user \
|
||||
--file ./pic.png \
|
||||
--presentation "https://xxx.feishu.cn/wiki/wikcnXXXXXX"
|
||||
|
||||
# 预览(不实际上传)
|
||||
# Preview (does not actually upload)
|
||||
lark-cli slides +media-upload --file ./pic.png --presentation $PRES_ID --dry-run
|
||||
```
|
||||
|
||||
## 返回值
|
||||
## Return Value
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -38,90 +38,90 @@ lark-cli slides +media-upload --file ./pic.png --presentation $PRES_ID --dry-run
|
||||
}
|
||||
```
|
||||
|
||||
- **`file_token`**:把它写进 `<img src="...">`
|
||||
- **`file_name` / `size`**:上传文件元信息
|
||||
- **`presentation_id`**:解析后的真实 `xml_presentation_id`(wiki URL 解析后会变化)
|
||||
- **`file_token`**: write it into `<img src="...">`
|
||||
- **`file_name` / `size`**: metadata of the uploaded file
|
||||
- **`presentation_id`**: the resolved real `xml_presentation_id` (changes after resolving a wiki URL)
|
||||
|
||||
## 参数
|
||||
## Parameters
|
||||
|
||||
| 参数 | 必填 | 说明 |
|
||||
| Parameter | Required | Description |
|
||||
|------|------|------|
|
||||
| `--file` | 是 | 本地图片路径,**必须是 CWD 内的相对路径**(如 `./pic.png`)。**最大 20 MB**(slides upload API 不支持分片上传) |
|
||||
| `--presentation` | 是 | `xml_presentation_id`、`/slides/<token>` URL,或 `/wiki/<token>` URL |
|
||||
| `--file` | Yes | Local image path; **must be a relative path inside the CWD** (e.g. `./pic.png`). **Max 20 MB** (the slides upload API does not support chunked upload) |
|
||||
| `--presentation` | Yes | `xml_presentation_id`, a `/slides/<token>` URL, or a `/wiki/<token>` URL |
|
||||
|
||||
> [!IMPORTANT]
|
||||
> **路径必须在 CWD 内**:`--file /abs/path/x.png` 或 `--file ../up/x.png` 会被 CLI 拒绝(报 `unsafe file path`)。如果素材在别的目录,先 `cd` 过去再执行。
|
||||
> **Paths must be inside the CWD**: `--file /abs/path/x.png` or `--file ../up/x.png` is rejected by the CLI (with an `unsafe file path` error). If the assets live in another directory, `cd` there first, then run the command.
|
||||
|
||||
## 使用流程
|
||||
## Usage Workflows
|
||||
|
||||
### 给已有 PPT 加带图新页
|
||||
### Adding a New Page with an Image to an Existing Presentation
|
||||
|
||||
```bash
|
||||
# 1) 上传图片
|
||||
# 1) Upload the image
|
||||
TOKEN=$(lark-cli slides +media-upload --as user \
|
||||
--file ./pic.png \
|
||||
--presentation $PRES_ID | jq -r .data.file_token)
|
||||
|
||||
# 2) 用 file_token 创建带图新页
|
||||
# 2) Create the new page with the image using the file_token
|
||||
lark-cli slides xml_presentation.slide create --as user \
|
||||
--params "{\"xml_presentation_id\":\"$PRES_ID\"}" \
|
||||
--data "{\"slide\":{\"content\":\"<slide xmlns=\\\"http://www.larkoffice.com/sml/2.0\\\"><data><img src=\\\"$TOKEN\\\" topLeftX=\\\"100\\\" topLeftY=\\\"100\\\" width=\\\"320\\\" height=\\\"180\\\"/></data></slide>\"}}"
|
||||
```
|
||||
|
||||
### 新建带图 PPT(推荐用 `+create --slides` 的 `@` 占位符,一步到位)
|
||||
### Creating a New Presentation with Images (recommended: use the `@` placeholder of `+create --slides` for a one-step flow)
|
||||
|
||||
```bash
|
||||
# 不需要单独 +media-upload,写 src="@<本地路径>" 即可
|
||||
lark-cli slides +create --as user --title "图测试" --slides '[
|
||||
# No separate +media-upload needed; just write src="@<local path>"
|
||||
lark-cli slides +create --as user --title "Image Test" --slides '[
|
||||
"<slide xmlns=\"http://www.larkoffice.com/sml/2.0\"><data><img src=\"@./pic.png\" topLeftX=\"100\" topLeftY=\"100\" width=\"320\" height=\"180\"/></data></slide>"
|
||||
]'
|
||||
```
|
||||
|
||||
详见 [+create 文档](lark-slides-create.md#本地图片path-占位符)。
|
||||
See the [+create documentation](lark-slides-create.md#local-images-path-placeholders) for details.
|
||||
|
||||
### 给已有 PPT 的已有页加图
|
||||
### Adding an Image to an Existing Page of an Existing Presentation
|
||||
|
||||
拿到 `file_token` 后走 [`+replace-slide`](lark-slides-replace-slide.md) 的 `block_insert`,不用搬原 XML、不改 `slide_id`、不打乱页序:
|
||||
After getting the `file_token`, use `block_insert` via [`+replace-slide`](lark-slides-replace-slide.md); no need to move the original XML, change the `slide_id`, or disturb the page order:
|
||||
|
||||
```bash
|
||||
PRES_ID=xxx
|
||||
SID=yyy # 要加图的那一页
|
||||
SID=yyy # the page to add the image to
|
||||
|
||||
# 1) 上传图片拿 file_token
|
||||
# 1) Upload the image to get the file_token
|
||||
TOKEN=$(lark-cli slides +media-upload --as user \
|
||||
--file ./pic.png --presentation $PRES_ID | jq -r '.data.file_token')
|
||||
|
||||
# 2) block_insert 到页末(或用 insert_before_block_id 指定插入位置)
|
||||
# 2) block_insert at the end of the page (or use insert_before_block_id to specify the insertion position)
|
||||
lark-cli slides +replace-slide --as user \
|
||||
--presentation "$PRES_ID" --slide-id "$SID" \
|
||||
--parts "$(jq -n --arg token "$TOKEN" \
|
||||
'[{action:"block_insert",insertion:("<img src=\""+$token+"\" topLeftX=\"500\" topLeftY=\"100\" width=\"200\" height=\"150\"/>")}]')"
|
||||
```
|
||||
|
||||
注意事项:
|
||||
Notes:
|
||||
|
||||
1. **`<img>` 坐标避开现有元素** —— 先读现有元素 bbox 挑空白区;空间不够就先用 `block_replace` 挪动/缩小现有元素后再放图
|
||||
2. **`<img>` 的 `width:height` 对齐原图比例** —— 比例不一致会被裁剪,参见 [xml-schema-quick-ref.md](xml-schema-quick-ref.md) `<img>` 说明
|
||||
1. **Keep `<img>` coordinates clear of existing elements** — read the bounding boxes of existing elements first and pick an empty area; if there is not enough space, use `block_replace` to move/shrink existing elements first, then place the image
|
||||
2. **Match the `<img>` `width:height` to the original image's aspect ratio** — a mismatched ratio gets cropped; see the `<img>` notes in [xml-schema-quick-ref.md](xml-schema-quick-ref.md)
|
||||
|
||||
## 工作原理
|
||||
## How It Works
|
||||
|
||||
`+media-upload` 内部调用 `POST /open-apis/drive/v1/medias/upload_all`(单次上传,最大 20 MB),固定使用:
|
||||
`+media-upload` internally calls `POST /open-apis/drive/v1/medias/upload_all` (single-shot upload, max 20 MB), always using:
|
||||
|
||||
- `parent_type=slide_file`(slides 后端唯一接受的取值,已实测验证)
|
||||
- `parent_type=slide_file` (the only value the slides backend accepts, verified in practice)
|
||||
- `parent_node=<xml_presentation_id>`
|
||||
|
||||
**不要尝试用 `slides_image`、`slide_image` 等 parent_type**——后端会返回 1061001 / 1061002 错误。这是 slides 的特殊约定。
|
||||
**Do not try `slides_image`, `slide_image`, or other parent_type values** — the backend returns 1061001 / 1061002 errors. This is a slides-specific convention.
|
||||
|
||||
## 常见错误
|
||||
## Common Errors
|
||||
|
||||
| 错误码 | 含义 | 解决方案 |
|
||||
| Error Code | Meaning | Solution |
|
||||
|--------|------|----------|
|
||||
| 1061002 | params error / 不支持的 parent_type | 不要用原生 API 自己拼 parent_type;用 `+media-upload` 即可 |
|
||||
| 1061004 | forbidden:当前身份对该演示文稿无编辑权限 | 确认当前身份(user 或 bot)对目标 PPT 有编辑权限。bot 模式常见原因:PPT 不是该 bot 创建的——可用 `+create --as bot` 新建,或以 user 身份给 bot 授权 `lark-cli drive permission.members create --as user ...` |
|
||||
| 1061044 | parent node not exist | `--presentation` 给的 token 不对,或不是 slides 类型 |
|
||||
| 403 | 权限不足 | 检查 `docs:document.media:upload` scope;wiki URL 还需要 `wiki:node:read` |
|
||||
| 1061002 | params error / unsupported parent_type | Do not assemble the parent_type yourself with the raw API; just use `+media-upload` |
|
||||
| 1061004 | forbidden: the current identity has no edit permission on the presentation | Confirm that the current identity (user or bot) has edit permission on the target presentation. Common cause in bot mode: the presentation was not created by that bot — create a new one with `+create --as bot`, or grant the bot access as the user via `lark-cli drive permission.members create --as user ...` |
|
||||
| 1061044 | parent node not exist | The token given to `--presentation` is wrong, or is not a slides resource |
|
||||
| 403 | Insufficient permissions | Check the `docs:document.media:upload` scope; wiki URLs additionally require `wiki:node:read` |
|
||||
|
||||
## 相关命令
|
||||
## Related Commands
|
||||
|
||||
- [+create](lark-slides-create.md) — 新建 PPT(支持 `@` 占位符自动上传图片)
|
||||
- [+replace-slide](lark-slides-replace-slide.md) — 给已有页加图 / 换图(`block_insert` / `block_replace`)
|
||||
- [+create](lark-slides-create.md) — create a new presentation (supports `@` placeholders for automatic image upload)
|
||||
- [+replace-slide](lark-slides-replace-slide.md) — add / swap an image on an existing page (`block_insert` / `block_replace`)
|
||||
|
||||
@@ -1,89 +1,89 @@
|
||||
# PPT Template Rewrite Principles
|
||||
|
||||
本页只约束“用户指定 PPT 模板、底稿、已有 PPTX/PDF/Slides,并要求基于它二次创作”的场景。核心原则:模板不是风格参考,而是必须沿用的编辑底稿。
|
||||
This page only governs the scenario where the user designates a PPT template, base deck, or existing PPTX/PDF/Slides file and asks for derivative work based on it. Core principle: the template is not a style reference; it is the editing base that must be carried forward.
|
||||
|
||||
## Import First
|
||||
|
||||
用户指定 PPT 模板时,先把模板导入成 Lark Slides。后续写入目标是导入后的 Slides,不是新建一个脱离模板的 deck,也不是先在本地重画 PPTX 再导入。
|
||||
When the user designates a PPT template, first import the template as Lark Slides. All subsequent writes target the imported Slides — do not create a new deck detached from the template, and do not redraw a PPTX locally first and then import it.
|
||||
|
||||
直接使用以下命令,不需要先加载 `lark-drive` skill:
|
||||
Use the following command directly; there is no need to load the `lark-drive` skill first:
|
||||
|
||||
```bash
|
||||
lark-cli drive +import --as user --file "<template.pptx>" --type slides --json
|
||||
```
|
||||
|
||||
可选参数:用 `--name "<title>"` 指定导入后的 Slides 标题;用 `--folder-token <FOLDER_TOKEN>` 指定目标文件夹。若返回 `ready=false` / `timed_out=true`,直接执行返回值里的 `next_command`;等价形式是:
|
||||
Optional parameters: use `--name "<title>"` to set the title of the imported Slides; use `--folder-token <FOLDER_TOKEN>` to specify the target folder. If the response returns `ready=false` / `timed_out=true`, run the `next_command` from the response directly; the equivalent form is:
|
||||
|
||||
```bash
|
||||
lark-cli drive +task_result --scenario import --ticket <TICKET>
|
||||
```
|
||||
|
||||
导入后必须回读 Slides 内容,理解每页的真实版式、字体、层级、图片、图表、shape、表格和文本容器。回读结果是模板二创的事实来源。
|
||||
After importing, you must read back the Slides content and understand each page's real layout, fonts, hierarchy, images, charts, shapes, tables, and text containers. The readback result is the source of truth for the template rewrite.
|
||||
|
||||
## Read Before Editing
|
||||
|
||||
编辑任何 PPT 页面前,必须先阅读该页面。
|
||||
Before editing any slide page, you must read that page first.
|
||||
|
||||
如果当前上下文中没有该页内容,必须重新读取页面;这里的“当前上下文”不包含 System Prompt。不能只凭记忆、文件名、缩略图印象或模板整体风格判断来编辑具体页面。
|
||||
If the page content is not in the current context, you must re-read the page; "current context" here does not include the System Prompt. Never edit a specific page based only on memory, the file name, a thumbnail impression, or a judgment about the template's overall style.
|
||||
|
||||
阅读页面时至少判断:
|
||||
When reading a page, determine at least:
|
||||
|
||||
- 该页原本承担的角色,例如封面、章节页、目录、流程、对比、数据、总结。
|
||||
- 该页的主要版式结构,例如图文关系、箭头、时间线、节点、表格、图表、左右对照、背景图或产品图。
|
||||
- 哪些文本框、shape 标签、表格单元格或图表标签承载内容。
|
||||
- 原页面的字体、字号、颜色、对齐、层级和留白关系。
|
||||
- The role the page originally plays, such as cover, section divider, agenda, process, comparison, data, or summary.
|
||||
- The page's main layout structure, such as image-text relationships, arrows, timelines, nodes, tables, charts, side-by-side comparisons, background images, or product images.
|
||||
- Which text boxes, shape labels, table cells, or chart labels carry the content.
|
||||
- The original page's fonts, font sizes, colors, alignment, hierarchy, and whitespace relationships.
|
||||
|
||||
## Edit The Imported Slides Directly
|
||||
|
||||
理解页面后,直接在导入后的 Slides 上编辑。允许的操作包括:
|
||||
After understanding a page, edit the imported Slides directly. Allowed operations include:
|
||||
|
||||
- 填写、替换、凝练或删除文字。
|
||||
- 替换或补充图片。
|
||||
- 更新图表、表格、数字标签或节点标签里的内容。
|
||||
- 按需复制、删除或重排模板页。
|
||||
- 在源页面没有合适承载位置时,做局部、小范围新增元素。
|
||||
- Filling in, replacing, condensing, or deleting text.
|
||||
- Replacing or adding images.
|
||||
- Updating the content of charts, tables, number labels, or node labels.
|
||||
- Copying, deleting, or reordering template pages as needed.
|
||||
- Making local, small-scale element additions when the source page has no suitable container.
|
||||
|
||||
新增元素只能补足内容缺口,不能成为新的主版式。页面主体仍应由模板原有版式承载。
|
||||
New elements may only fill content gaps; they must not become a new primary layout. The body of the page should still be carried by the template's original layout.
|
||||
|
||||
## Preserve Design
|
||||
|
||||
模板二创必须严格沿用原版式和字体,只改内容,不做设计。
|
||||
A template rewrite must strictly follow the original layout and fonts: change only the content, do no redesign.
|
||||
|
||||
默认保留:
|
||||
Preserve by default:
|
||||
|
||||
- 页面布局、视觉层级、留白和对齐关系。
|
||||
- 原字体、字号体系、颜色、文本框位置和 shape 顺序。
|
||||
- 背景图、图片、logo、图表、表格、装饰形状、线条、图标和页面结构。
|
||||
- 模板中不同页型之间的差异。
|
||||
- Page layout, visual hierarchy, whitespace, and alignment relationships.
|
||||
- Original fonts, font-size system, colors, text box positions, and shape order.
|
||||
- Background images, images, logos, charts, tables, decorative shapes, lines, icons, and page structure.
|
||||
- The differences between different page types within the template.
|
||||
|
||||
不要把模板页改造成统一的通用卡片、白板、标题栏、三栏、2x2 卡片或大面积遮罩。不要把模板当作背景图后另起一套设计系统。
|
||||
Do not remodel template pages into uniform generic cards, whiteboards, title bars, three-column layouts, 2x2 card grids, or large overlay masks. Do not treat the template as a background image and start a separate design system on top of it.
|
||||
|
||||
## Content Only
|
||||
|
||||
内容必须优先进入原页面已有的文本框、shape 标签、节点、表格单元格、图表标签或注释容器。
|
||||
Content must go first into the page's existing text boxes, shape labels, nodes, table cells, chart labels, or annotation containers.
|
||||
|
||||
如果原容器空间不足,优先:
|
||||
If an original container lacks space, prefer to:
|
||||
|
||||
- 凝练文字。
|
||||
- 降低字号但保持原字体体系。
|
||||
- 拆分到页面已有的邻近容器。
|
||||
- 使用模板已有的注释、标签或补充说明区域。
|
||||
- 复制同页或同模板中的原生容器样式做局部补充。
|
||||
- Condense the text.
|
||||
- Reduce the font size while keeping the original font system.
|
||||
- Split the content into adjacent containers that already exist on the page.
|
||||
- Use the template's existing annotation, label, or supplementary note regions.
|
||||
- Copy the style of a native container from the same page or the same template for a local addition.
|
||||
|
||||
不要为了容纳长文案而重画页面主体结构。不要用新增大卡片遮住原图表、箭头、图片、背景或关键 shape。
|
||||
Do not redraw the main structure of a page to fit long copy. Do not cover the original charts, arrows, images, background, or key shapes with newly added large cards.
|
||||
|
||||
## Readback And Tune
|
||||
|
||||
完成编辑后必须回读结果,并逐页微调。
|
||||
After editing, you must read back the result and fine-tune page by page.
|
||||
|
||||
回读时重点检查:
|
||||
During readback, focus on:
|
||||
|
||||
- 文字是否溢出、截断、压线或超出容器。
|
||||
- 文本是否遮挡图片、图表、shape、箭头、节点或其他文字。
|
||||
- shape 顺序是否导致内容被覆盖或遮住。
|
||||
- 新内容是否仍然落在模板原有版式中,而不是覆盖模板结构。
|
||||
- 字体、字号、颜色、对齐和层级是否仍贴近原页。
|
||||
- Whether text overflows, is truncated, presses against edges, or exceeds its container.
|
||||
- Whether text covers images, charts, shapes, arrows, nodes, or other text.
|
||||
- Whether shape ordering causes content to be overwritten or hidden.
|
||||
- Whether new content still lands within the template's original layout rather than covering the template structure.
|
||||
- Whether fonts, font sizes, colors, alignment, and hierarchy still stay close to the original page.
|
||||
|
||||
发现文字溢出时,优先凝练文字或缩减字号。发现遮挡时,调整 shape 顺序、局部位置或复用原有空白区域解决。只有在这些方法都不能满足内容表达时,才做局部新增或删除。
|
||||
When text overflows, prefer condensing the text or reducing the font size. When occlusion is found, fix it by adjusting shape order, making local position tweaks, or reusing existing empty regions. Only when none of these methods can express the content should you make local additions or deletions.
|
||||
|
||||
模板二创的完成标准不是“生成了一套看起来统一的新 PPT”,而是“原模板的版式、字体和视觉结构仍清晰存在,内容已经被准确替换,并且回读后没有溢出和遮挡”。
|
||||
The completion criterion for a template rewrite is not "a new deck that looks uniform was generated" but "the original template's layout, fonts, and visual structure are still clearly present, the content has been accurately replaced, and readback shows no overflow or occlusion."
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# slides +replace-pages(多页整页重建)
|
||||
# slides +replace-pages (Multi-Page Full Rebuild)
|
||||
|
||||
批量替换已有演示文稿里的多个页面,保持原 `xml_presentation_id` 和原 Slides 链接不变。适合多页版式大改、坐标重排、整页视觉重建;单个文本框、图片或 shape 的局部编辑仍优先用 [`+replace-slide`](lark-slides-replace-slide.md)。
|
||||
Replaces multiple pages of an existing presentation in batch, keeping the original `xml_presentation_id` and the original Slides link unchanged. Suited to large multi-page layout overhauls, coordinate rework, and full-page visual rebuilds; for local edits to a single text box, image, or shape, still prefer [`+replace-slide`](lark-slides-replace-slide.md).
|
||||
|
||||
> 重要:这是多步编排,不是后端原子事务。CLI 对每页执行“先创建新页到旧页前,再删除旧页”;创建失败时旧页会保留。删除失败时可能出现新旧页同时存在,需要按返回结果继续处理。
|
||||
> Important: this is multi-step orchestration, not an atomic backend transaction. For each page the CLI performs "create the new page before the old page, then delete the old page"; if creation fails, the old page is kept. If deletion fails, the new and old pages may coexist, and you need to continue handling them according to the returned results.
|
||||
|
||||
## 命令
|
||||
## Command
|
||||
|
||||
```bash
|
||||
lark-cli slides +replace-pages \
|
||||
@@ -13,15 +13,15 @@ lark-cli slides +replace-pages \
|
||||
--pages @pages.json
|
||||
```
|
||||
|
||||
## 参数
|
||||
## Parameters
|
||||
|
||||
| 参数 | 必需 | 说明 |
|
||||
| Parameter | Required | Description |
|
||||
|------|------|------|
|
||||
| `--presentation` | 是 | `xml_presentation_id`、`/slides/` URL 或 `/wiki/` URL |
|
||||
| `--pages` | 是 | JSON 数组,每项包含 `slide_id` 和 `content`;支持 literal、`@file`、stdin `-` |
|
||||
| `--dry-run` | 否 | 基于 `slide_id` 输入输出替换计划,不执行 create/delete |
|
||||
| `--continue-on-error` | 否 | 默认失败即停;开启后继续处理后续页,并在结果中标记失败项 |
|
||||
| `--validate-only` | 否 | 只校验输入并生成替换计划,不执行 Slides get/create/delete |
|
||||
| `--presentation` | Yes | `xml_presentation_id`, a `/slides/` URL, or a `/wiki/` URL |
|
||||
| `--pages` | Yes | JSON array, each item containing `slide_id` and `content`; supports literal, `@file`, and stdin `-` |
|
||||
| `--dry-run` | No | Outputs the replacement plan based on the `slide_id` input, without executing create/delete |
|
||||
| `--continue-on-error` | No | Stops on failure by default; when enabled, continues with subsequent pages and marks failed items in the result |
|
||||
| `--validate-only` | No | Only validates the input and generates the replacement plan, without executing Slides get/create/delete |
|
||||
|
||||
## pages.json
|
||||
|
||||
@@ -38,12 +38,12 @@ lark-cli slides +replace-pages \
|
||||
]
|
||||
```
|
||||
|
||||
规则:
|
||||
Rules:
|
||||
|
||||
- 每项必须提供 `slide_id`;不支持 `slide_number`。
|
||||
- `content` 必须是完整 `<slide>...</slide>` XML。
|
||||
- 同一批次不能重复 `slide_id`。
|
||||
- CLI 不会回读整份 presentation;如果 `slide_id` 已失效,create/delete 阶段会返回对应错误。
|
||||
- Every item must provide `slide_id`; `slide_number` is not supported.
|
||||
- `content` must be complete `<slide>...</slide>` XML.
|
||||
- No duplicate `slide_id` within the same batch.
|
||||
- The CLI does not read back the whole presentation; if a `slide_id` has become invalid, the create/delete phase returns the corresponding error.
|
||||
|
||||
## Dry Run
|
||||
|
||||
@@ -54,9 +54,9 @@ lark-cli slides +replace-pages --as user \
|
||||
--dry-run
|
||||
```
|
||||
|
||||
输出包含 `xml_presentation_id`、`pages_count`、`plan`,以及每页的 `old_slide_id`、`insert_before_slide_id` 和动作 `create_before_then_delete_old`。Dry-run 只基于输入的 `slide_id` 构造计划,不会调用 `xml_presentations.get`,也不会执行 create/delete。
|
||||
The output includes `xml_presentation_id`, `pages_count`, `plan`, and for each page its `old_slide_id`, `insert_before_slide_id`, and the action `create_before_then_delete_old`. Dry-run builds the plan purely from the input `slide_id` values; it neither calls `xml_presentations.get` nor executes create/delete.
|
||||
|
||||
## 成功输出
|
||||
## Success Output
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -79,17 +79,17 @@ lark-cli slides +replace-pages --as user \
|
||||
}
|
||||
```
|
||||
|
||||
如果使用 `--continue-on-error` 且任一页面失败,CLI 会继续处理后续页,但最终以 partial failure 非零退出;stdout 仍保留完整 `results`,顶层 `ok` 为 `false`,`status` 为 `partial_failure`。
|
||||
If `--continue-on-error` is used and any page fails, the CLI continues with the remaining pages but ultimately exits non-zero with a partial failure; stdout still contains the complete `results`, with top-level `ok` set to `false` and `status` set to `partial_failure`.
|
||||
|
||||
`status` 可能为:
|
||||
`status` can be:
|
||||
|
||||
- `replaced`:新页创建成功,旧页删除成功。
|
||||
- `create_failed`:新页创建失败,旧页保留。
|
||||
- `delete_failed`:新页已创建,但旧页删除失败。
|
||||
- `replaced`: the new page was created successfully and the old page was deleted successfully.
|
||||
- `create_failed`: creating the new page failed; the old page is kept.
|
||||
- `delete_failed`: the new page was created, but deleting the old page failed.
|
||||
|
||||
## 使用建议
|
||||
## Usage Tips
|
||||
|
||||
1. 大幅改写前先 `slides +xml-get` 保存当前 XML,并记录要替换页面的 `slide_id`。
|
||||
2. 生成只含 `slide_id` 的 `pages.json` 后先跑 `--dry-run` 或 `--validate-only`。
|
||||
3. 默认不要开 `--continue-on-error`,除非能接受部分页面已替换。
|
||||
4. 替换后再回读全文 XML 并截图检查,确认页序、视觉和文本没有破损。
|
||||
1. Before a large rewrite, save the current XML with `slides +xml-get` and record the `slide_id` of the pages to replace.
|
||||
2. After generating a `pages.json` containing only the target `slide_id` entries, run `--dry-run` or `--validate-only` first.
|
||||
3. Do not enable `--continue-on-error` by default, unless you can accept some pages having already been replaced.
|
||||
4. After replacement, read back the full XML and take screenshots to confirm the page order, visuals, and text are intact.
|
||||
|
||||
@@ -1,119 +1,119 @@
|
||||
# slides +replace-slide(块级替换 / 插入)
|
||||
# slides +replace-slide (Block-Level Replace / Insert)
|
||||
|
||||
> **前置条件:** 先阅读 [`../lark-shared/SKILL.md`](../../lark-shared/SKILL.md) 了解认证、全局参数和安全规则。
|
||||
> **Prerequisite:** First read [`../lark-shared/SKILL.md`](../../lark-shared/SKILL.md) for authentication, global parameters, and safety rules.
|
||||
|
||||
对指定 slide 做块级替换或插入。编辑已有 PPT 的主路径——`slide_id` 不变、页序不动、只影响被指定的块。
|
||||
Performs block-level replacement or insertion on a specified slide. This is the primary path for editing an existing deck — `slide_id` stays the same, page order is untouched, and only the specified blocks are affected.
|
||||
|
||||
相比直接调 `xml_presentation.slide.replace`,这个 shortcut 的四个额外价值:
|
||||
Compared to calling `xml_presentation.slide.replace` directly, this shortcut adds four extra benefits:
|
||||
|
||||
1. `--presentation` 接受 `xml_presentation_id` / `/slides/` URL / `/wiki/` URL(wiki 自动解析);
|
||||
2. `block_replace` 的 `replacement` 根元素 `id="<block_id>"` 由 CLI 自动注入——底层 API 的硬约束(不注入返回 3350001);直接调原生 API 需自己加,用 Shortcut 则自动注入;
|
||||
3. `<shape>` 元素缺少 `<content/>` 子元素时由 CLI 自动注入——SML 2.0 schema 要求每个 `<shape>` 必须有 `<content/>` 子元素,缺失同样触发 3350001;自闭合的 `<shape .../>` 也会被自动展开为 `<shape ...><content/></shape>`;
|
||||
4. 3350001 错误时提供上下文感知的 hint,帮助 AI agent 和用户快速定位原因。
|
||||
1. `--presentation` accepts an `xml_presentation_id` / `/slides/` URL / `/wiki/` URL (wiki URLs are resolved automatically);
|
||||
2. For `block_replace`, the `replacement` root element's `id="<block_id>"` is injected automatically by the CLI — a hard constraint of the underlying API (missing it returns 3350001); when calling the native API directly you must add it yourself, with the shortcut it is injected automatically;
|
||||
3. When a `<shape>` element is missing its `<content/>` child, the CLI injects it automatically — the SML 2.0 schema requires every `<shape>` to have a `<content/>` child, and a missing one also triggers 3350001; self-closing `<shape .../>` is likewise auto-expanded to `<shape ...><content/></shape>`;
|
||||
4. On 3350001 errors it provides context-aware hints, helping AI agents and users quickly locate the cause.
|
||||
|
||||
## 命令
|
||||
## Command
|
||||
|
||||
```bash
|
||||
# block_insert:在页末追加一个新元素
|
||||
# block_insert: append a new element at the end of the page
|
||||
lark-cli slides +replace-slide --as user \
|
||||
--presentation slidesXXXXXXXXXXXXXXXXXXXXXX \
|
||||
--slide-id pfG \
|
||||
--parts '[{"action":"block_insert","insertion":"<shape type=\"rect\" topLeftX=\"500\" topLeftY=\"100\" width=\"200\" height=\"100\"/>"}]'
|
||||
|
||||
# block_replace:已知某块 id,整块替换(replacement 根 id 自动注入为 bUn)
|
||||
# block_replace: with a known block id, replace the whole block (replacement root id auto-injected as bUn)
|
||||
lark-cli slides +replace-slide --as user \
|
||||
--presentation slidesXXXXXXXXXXXXXXXXXXXXXX \
|
||||
--slide-id pfG \
|
||||
--parts '[{"action":"block_replace","block_id":"bUn","replacement":"<shape type=\"text\" topLeftX=\"80\" topLeftY=\"80\" width=\"800\" height=\"120\"><content textType=\"title\"><p>新标题</p></content></shape>"}]'
|
||||
--parts '[{"action":"block_replace","block_id":"bUn","replacement":"<shape type=\"text\" topLeftX=\"80\" topLeftY=\"80\" width=\"800\" height=\"120\"><content textType=\"title\"><p>New title</p></content></shape>"}]'
|
||||
|
||||
# 大 --parts 走文件或 stdin(auto-gen 命令不支持 @file,但 shortcut 支持)
|
||||
# Large --parts via file or stdin (auto-gen commands do not support @file, but shortcuts do)
|
||||
lark-cli slides +replace-slide --as user \
|
||||
--presentation $PID --slide-id $SID --parts @parts.json
|
||||
cat parts.json | lark-cli slides +replace-slide --as user \
|
||||
--presentation $PID --slide-id $SID --parts -
|
||||
|
||||
# wiki URL 直接传(CLI 自动 get_node → 拿真实 xml_presentation_id)
|
||||
# Pass a wiki URL directly (CLI auto get_node -> resolves the real xml_presentation_id)
|
||||
lark-cli slides +replace-slide --as user \
|
||||
--presentation "https://xxx.feishu.cn/wiki/wikcnXXXXXX" --slide-id pfG \
|
||||
--parts '[{"action":"block_insert","insertion":"<shape type=\"rect\" width=\"100\" height=\"100\"/>"}]'
|
||||
|
||||
# 预览(不实际调用)
|
||||
# Preview (does not execute)
|
||||
lark-cli slides +replace-slide --as user \
|
||||
--presentation $PID --slide-id $SID --parts "$PARTS" --dry-run
|
||||
```
|
||||
|
||||
## 参数
|
||||
## Parameters
|
||||
|
||||
| 参数 | 必填 | 说明 |
|
||||
| Parameter | Required | Description |
|
||||
|------|------|------|
|
||||
| `--presentation` | 是 | `xml_presentation_id`、`/slides/<token>` URL,或 `/wiki/<token>` URL |
|
||||
| `--slide-id` | 是 | 页面 ID(`xml_presentation.slide.get` / `slides +xml-get` 都能拿到) |
|
||||
| `--parts` | 是 | JSON 数组(`[{...}, ...]`),单次最多 200 条。支持 `@<file>` 和 `-`(stdin)读取 |
|
||||
| `--revision-id` | 否 | 基础版本号;默认 `-1` 表示基于最新版执行;传具体版本号时,服务端以该版本为 base 执行;**传不存在的版本号(超过当前 revision)返回 3350002** |
|
||||
| `--tid` | 否 | 并发事务 ID;多人协作长事务才用,单次单人调用留空 |
|
||||
| `--presentation` | Yes | `xml_presentation_id`, `/slides/<token>` URL, or `/wiki/<token>` URL |
|
||||
| `--slide-id` | Yes | Slide ID (available from `xml_presentation.slide.get` / `slides +xml-get`) |
|
||||
| `--parts` | Yes | JSON array (`[{...}, ...]`), at most 200 items per call. Supports `@<file>` and `-` (stdin) input |
|
||||
| `--revision-id` | No | Base revision number; default `-1` means execute against the latest revision; when a specific revision is passed, the server executes with that revision as base; **passing a nonexistent revision (beyond the current one) returns 3350002** |
|
||||
| `--tid` | No | Concurrent transaction ID; only for long multi-user collaborative transactions, leave empty for single one-off calls |
|
||||
|
||||
## parts 元素结构
|
||||
## parts Element Structure
|
||||
|
||||
> **限制**:最多 200 条;`block_replace` 和 `block_insert` 可以在同一批次混用。**其他 action(含 `str_replace`)CLI 会直接报错拒绝**。
|
||||
> **Limits**: at most 200 items; `block_replace` and `block_insert` can be mixed in the same batch. **Any other action (including `str_replace`) is rejected outright by the CLI.**
|
||||
|
||||
每条 part 按 `action` 取不同字段:
|
||||
Each part takes different fields depending on `action`:
|
||||
|
||||
### action = `block_replace`
|
||||
|
||||
| 字段 | 必填 | 说明 |
|
||||
| Field | Required | Description |
|
||||
|------|------|------|
|
||||
| `action` | 是 | `"block_replace"` |
|
||||
| `block_id` | 是 | 目标块的 3 位 short element ID(从 `slide.get` 返回 XML 里读) |
|
||||
| `replacement` | 是 | 新 XML 片段;**根元素 `id` 会被 CLI 自动注入为 `block_id`**,用户不用自己加(如果已经加了且不一致会被覆盖为正确值) |
|
||||
| `action` | Yes | `"block_replace"` |
|
||||
| `block_id` | Yes | The target block's 3-character short element ID (read from the XML returned by `slide.get`) |
|
||||
| `replacement` | Yes | New XML fragment; **the root element's `id` is auto-injected by the CLI as `block_id`** — you do not need to add it yourself (if you added one that differs, it is overwritten with the correct value) |
|
||||
|
||||
### action = `block_insert`
|
||||
|
||||
| 字段 | 必填 | 说明 |
|
||||
| Field | Required | Description |
|
||||
|------|------|------|
|
||||
| `action` | 是 | `"block_insert"` |
|
||||
| `insertion` | 是 | 要插入的 XML 片段 |
|
||||
| `insert_before_block_id` | 否 | 插到这个块之前;省略(不提供此字段)则追加到页末 |
|
||||
| `action` | Yes | `"block_insert"` |
|
||||
| `insertion` | Yes | The XML fragment to insert |
|
||||
| `insert_before_block_id` | No | Insert before this block; when omitted (field not provided), append at the end of the page |
|
||||
|
||||
## 合法根元素速查
|
||||
## Valid Root Element Cheat Sheet
|
||||
|
||||
`block_replace.replacement` 和 `block_insert.insertion` 必须以 SML 2.0 定义的合法元素为根。完整权威定义看 [`slides_xml_schema_definition.xml`](slides_xml_schema_definition.xml);这里只列能作为**根**的类型 + 每种类型的最小可工作片段。
|
||||
`block_replace.replacement` and `block_insert.insertion` must be rooted at an element that SML 2.0 defines as valid. See [`slides_xml_schema_definition.xml`](slides_xml_schema_definition.xml) for the full authoritative definition; here we only list the types that can act as the **root**, plus a minimal working fragment for each type.
|
||||
|
||||
| 元素 | 用途 | 关键点 |
|
||||
| Element | Purpose | Key points |
|
||||
|---|---|---|
|
||||
| `<shape>` | 矩形/椭圆/三角/文本框等所有形状 | `type` 必填;`<content/>` 缺失时 CLI 会自动注入 |
|
||||
| `<line>` | 直线 | 需 `startX/startY/endX/endY` |
|
||||
| `<polyline>` | 折线 | `points` 读回时被服务端规整丢弃(几何已入库) |
|
||||
| `<img>` | 图片 | `src` 必须是 [`+media-upload`](lark-slides-media-upload.md) 返回的 `file_token`,不能是 URL |
|
||||
| `<icon>` | 图标 | `iconType` 取自 iconpark 资源;语义图标先用 `scripts/iconpark_tool.py search` 检索 |
|
||||
| `<table>` | 表格 | 整表替换会**重建内部 td id**,旧 td block_id 立即失效 |
|
||||
| `<td>` | 单元格局部替换 | 只能 `block_replace`,不能 `block_insert`;`block_id` 必须是最新 `slide.get` 拿到的 td id |
|
||||
| `<chart>` | 图表(line/bar/column/pie/area/radar/combo) | 必须嵌 `<chartPlotArea>` + `<chartData>` + `<dim1>/<dim2>/<chartField>` |
|
||||
| `<whiteboard>` | 画板(SVG 或 Mermaid) | 内嵌 `<svg>` 或 `<mermaid>`;`slide.get` 返回结构不含内部数据,但可直接写完整新 XML 做 `block_replace` 覆盖;详见 [`lark-slides-whiteboard.md`](lark-slides-whiteboard.md) |
|
||||
| `<shape>` | All shapes: rectangle/ellipse/triangle/text box, etc. | `type` is required; the CLI auto-injects `<content/>` when missing |
|
||||
| `<line>` | Straight line | Requires `startX/startY/endX/endY` |
|
||||
| `<polyline>` | Polyline | `points` is normalized away by the server on read-back (geometry already stored) |
|
||||
| `<img>` | Image | `src` must be a `file_token` returned by [`+media-upload`](lark-slides-media-upload.md), not a URL |
|
||||
| `<icon>` | Icon | `iconType` comes from iconpark assets; search semantic icons first with `scripts/iconpark_tool.py search` |
|
||||
| `<table>` | Table | Replacing a whole table **rebuilds internal td ids**; old td block_ids become invalid immediately |
|
||||
| `<td>` | Partial cell replacement | Only `block_replace`, not `block_insert`; `block_id` must be a td id from the latest `slide.get` |
|
||||
| `<chart>` | Chart (line/bar/column/pie/area/radar/combo) | Must nest `<chartPlotArea>` + `<chartData>` + `<dim1>/<dim2>/<chartField>` |
|
||||
| `<whiteboard>` | Whiteboard (SVG or Mermaid) | Embeds `<svg>` or `<mermaid>`; the structure returned by `slide.get` omits the internal data, but you can write a complete new XML directly as a `block_replace` overwrite; see [`lark-slides-whiteboard.md`](lark-slides-whiteboard.md) |
|
||||
|
||||
**不可作为根元素**:
|
||||
**Cannot be a root element**:
|
||||
|
||||
- `<video>` / `<audio>` —— SML 2.0 没有这两个原生元素;`<undefined type="video|audio">` 是**导出时**的占位符(服务端遇到不支持的类型时用它代替),**不能写入**。尝试 insert/replace 都会返回 3350001。
|
||||
- `<video>` / `<audio>` — SML 2.0 has no such native elements; `<undefined type="video|audio">` is an **export-time** placeholder (used by the server when it encounters an unsupported type) and **cannot be written**. Attempting insert/replace returns 3350001.
|
||||
|
||||
### 最小 XML 片段(JSON 嵌入时记得把 `"` 转义成 `\"`)
|
||||
### Minimal XML Fragments (remember to escape `"` as `\"` when embedding in JSON)
|
||||
|
||||
`<shape>`(文本框;`type` 还可选 `rect`/`ellipse`/`triangle`/`custom` 等):
|
||||
`<shape>` (text box; `type` can also be `rect`/`ellipse`/`triangle`/`custom`, etc.):
|
||||
```xml
|
||||
<shape type="text" topLeftX="80" topLeftY="80" width="800" height="120">
|
||||
<content textType="title"><p>标题</p></content>
|
||||
<content textType="title"><p>Title</p></content>
|
||||
</shape>
|
||||
```
|
||||
|
||||
`<img>`:
|
||||
`<img>`:
|
||||
```xml
|
||||
<img src="{file_token}" topLeftX="600" topLeftY="20" width="80" height="80"/>
|
||||
```
|
||||
|
||||
`<polyline>`:
|
||||
`<polyline>`:
|
||||
```xml
|
||||
<polyline topLeftX="10" topLeftY="10" width="100" height="50" points="0,0 50,50 100,0"/>
|
||||
```
|
||||
|
||||
`<table>`(2×2):
|
||||
`<table>` (2x2):
|
||||
```xml
|
||||
<table topLeftX="30" topLeftY="80">
|
||||
<colgroup><col span="2" width="110"/></colgroup>
|
||||
@@ -122,12 +122,12 @@ lark-cli slides +replace-slide --as user \
|
||||
</table>
|
||||
```
|
||||
|
||||
`<td>`(`block_replace` 单元格;`block_id` 必须是最新 `slide.get` 拿到的 td id):
|
||||
`<td>` (`block_replace` a single cell; `block_id` must be a td id from the latest `slide.get`):
|
||||
```xml
|
||||
<td><content><p>新内容</p></content></td>
|
||||
<td><content><p>New content</p></content></td>
|
||||
```
|
||||
|
||||
`<chart>`(`type` 改成 `bar`/`column`/`pie`/`area`/`radar`/`combo` 切换图型):
|
||||
`<chart>` (change `type` to `bar`/`column`/`pie`/`area`/`radar`/`combo` to switch chart type):
|
||||
```xml
|
||||
<chart topLeftX="30" topLeftY="300" width="300" height="200">
|
||||
<chartPlotArea><chartPlot type="line"/></chartPlotArea>
|
||||
@@ -138,7 +138,7 @@ lark-cli slides +replace-slide --as user \
|
||||
</chart>
|
||||
```
|
||||
|
||||
## 返回值
|
||||
## Return Value
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -149,92 +149,92 @@ lark-cli slides +replace-slide --as user \
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 说明 |
|
||||
| Field | Description |
|
||||
|------|------|
|
||||
| `xml_presentation_id` | 解析后的真实 token(wiki URL 解析后会变化) |
|
||||
| `slide_id` | 与入参一致 |
|
||||
| `parts_count` | 本次提交的 parts 条数 |
|
||||
| `revision_id` | 成功后的新版本号,下次做乐观锁时用 |
|
||||
| `failed_part_index` | 有部分失败时存在,指向第几条 part 失败 |
|
||||
| `failed_reason` | 失败原因文字描述 |
|
||||
| `xml_presentation_id` | The resolved real token (changes after wiki URL resolution) |
|
||||
| `slide_id` | Same as the input |
|
||||
| `parts_count` | Number of parts submitted in this call |
|
||||
| `revision_id` | The new revision number after success; use it for optimistic locking next time |
|
||||
| `failed_part_index` | Present when some part failed; points to which part failed |
|
||||
| `failed_reason` | Textual description of the failure reason |
|
||||
|
||||
整批作为原子事务:任一 part 失败则整批不生效,服务端通过 `failed_part_index` / `failed_reason` 告诉你是哪条;按此定位修正后重发。
|
||||
The whole batch runs as an atomic transaction: if any part fails, the whole batch takes no effect, and the server tells you which one via `failed_part_index` / `failed_reason`; fix accordingly and resubmit.
|
||||
|
||||
## 使用流程
|
||||
## Usage Workflows
|
||||
|
||||
### 给已有页加图(典型场景)
|
||||
### Adding an Image to an Existing Page (Typical Scenario)
|
||||
|
||||
```bash
|
||||
PID=xxx
|
||||
SID=yyy
|
||||
|
||||
# 1) 上传图片
|
||||
# 1) Upload the image
|
||||
TOKEN=$(lark-cli slides +media-upload --as user \
|
||||
--file ./pic.png --presentation "$PID" | jq -r '.data.file_token')
|
||||
|
||||
# 2) block_insert 到页末
|
||||
# 2) block_insert at the end of the page
|
||||
lark-cli slides +replace-slide --as user \
|
||||
--presentation "$PID" --slide-id "$SID" \
|
||||
--parts "$(jq -n --arg token "$TOKEN" \
|
||||
'[{action:"block_insert",insertion:("<img src=\""+$token+"\" topLeftX=\"500\" topLeftY=\"100\" width=\"200\" height=\"150\"/>")}]')"
|
||||
```
|
||||
|
||||
### 改标题(block_replace)
|
||||
### Changing a Title (block_replace)
|
||||
|
||||
```bash
|
||||
# 先拿原页 XML,从里面找到标题块的 3 位 short id(如 bUn)
|
||||
# First fetch the page XML and find the title block's 3-character short id (e.g. bUn)
|
||||
lark-cli slides xml_presentation.slide get --as user \
|
||||
--params "{\"xml_presentation_id\":\"$PID\",\"slide_id\":\"$SID\"}"
|
||||
|
||||
# block_replace 换掉整个标题块(id 自动注入)
|
||||
# block_replace the whole title block (id auto-injected)
|
||||
lark-cli slides +replace-slide --as user \
|
||||
--presentation "$PID" --slide-id "$SID" \
|
||||
--parts '[{"action":"block_replace","block_id":"bUn","replacement":"<shape type=\"text\" topLeftX=\"80\" topLeftY=\"80\" width=\"800\" height=\"120\"><content textType=\"title\"><p>新标题</p></content></shape>"}]'
|
||||
--parts '[{"action":"block_replace","block_id":"bUn","replacement":"<shape type=\"text\" topLeftX=\"80\" topLeftY=\"80\" width=\"800\" height=\"120\"><content textType=\"title\"><p>New title</p></content></shape>"}]'
|
||||
```
|
||||
|
||||
### 批量:一次换标题 + 追加装饰图
|
||||
### Batch: Replace a Title + Append a Decorative Image in One Call
|
||||
|
||||
`block_replace` 和 `block_insert` 可以在同一个 `--parts` 里混用,整批原子执行。
|
||||
`block_replace` and `block_insert` can be mixed in the same `--parts`; the whole batch executes atomically.
|
||||
|
||||
```bash
|
||||
lark-cli slides +replace-slide --as user \
|
||||
--presentation "$PID" --slide-id "$SID" \
|
||||
--parts '[
|
||||
{"action":"block_replace","block_id":"bab","replacement":"<shape type=\"text\" topLeftX=\"80\" topLeftY=\"80\" width=\"800\" height=\"120\"><content textType=\"title\"><p>新标题</p></content></shape>"},
|
||||
{"action":"block_replace","block_id":"bab","replacement":"<shape type=\"text\" topLeftX=\"80\" topLeftY=\"80\" width=\"800\" height=\"120\"><content textType=\"title\"><p>New title</p></content></shape>"},
|
||||
{"action":"block_insert","insertion":"<img src=\"<file_token>\" topLeftX=\"700\" topLeftY=\"400\" width=\"180\" height=\"100\"/>"}
|
||||
]'
|
||||
```
|
||||
|
||||
### 乐观锁
|
||||
### Optimistic Locking
|
||||
|
||||
```bash
|
||||
# 读时记录 revision_id
|
||||
# Record revision_id at read time
|
||||
REV=$(lark-cli slides xml_presentation.slide get --as user \
|
||||
--params "{\"xml_presentation_id\":\"$PID\",\"slide_id\":\"$SID\"}" \
|
||||
| jq '.data.revision_id')
|
||||
|
||||
# 写时传 --revision-id;传不存在的版本号(超过当前 revision)返回 3350002
|
||||
# Pass --revision-id at write time; a nonexistent revision (beyond the current one) returns 3350002
|
||||
lark-cli slides +replace-slide --as user \
|
||||
--presentation "$PID" --slide-id "$SID" --revision-id "$REV" \
|
||||
--parts "$PARTS"
|
||||
```
|
||||
|
||||
## 常见错误
|
||||
## Common Errors
|
||||
|
||||
| 现象 | 原因 | 对策 |
|
||||
| Symptom | Cause | Fix |
|
||||
|------|------|------|
|
||||
| 3350001 + hint "block_id not found" | `parts[i].block_id` 在当前页不存在 | 重新 `slide.get` 拿最新 XML,按里面的 short ID 再填 |
|
||||
| 3350002 not found | `--revision-id` 传了不存在的版本号(超过当前 revision) | 用 `-1` 或用 `slide.get` 拿到的有效 `revision_id` |
|
||||
| `--parts[i] action "str_replace" is not supported` | CLI 不暴露 `str_replace` | 把替换需求改写成 `block_replace` / `block_insert` |
|
||||
| `--parts contains N items, exceeds maximum of 200` | 一次提交 parts 太多 | 拆多次调用 |
|
||||
| `--parts[i] (block_replace) requires non-empty block_id` / `replacement` | 字段缺失 | 按 parts 元素结构补齐 |
|
||||
| `<img>` 不显示 / 显示破图 | `src` 写了外链 URL | 换成通过 [`+media-upload`](lark-slides-media-upload.md) 拿到的 `file_token` |
|
||||
| 3350001 | `replacement` 不是合法单根 XML 片段,或 `block_id` 不存在 | CLI 已自动注入 `id` 和 `<content/>`;如果仍报错,重新 `slide.get` 拿最新 XML 确认 `block_id` 存在;检查 XML 结构是否合法;坐标是否超出 960×540 |
|
||||
| 403 | 权限不足 | 需要 `slides:presentation:update` 或 `slides:presentation:write_only`;wiki URL 还需要 `wiki:node:read` |
|
||||
| 3350001 + hint "block_id not found" | `parts[i].block_id` does not exist on the current page | Re-run `slide.get` for the latest XML and refill using the short IDs in it |
|
||||
| 3350002 not found | `--revision-id` was a nonexistent revision (beyond the current one) | Use `-1` or a valid `revision_id` from `slide.get` |
|
||||
| `--parts[i] action "str_replace" is not supported` | The CLI does not expose `str_replace` | Rewrite the replacement as `block_replace` / `block_insert` |
|
||||
| `--parts contains N items, exceeds maximum of 200` | Too many parts in one call | Split into multiple calls |
|
||||
| `--parts[i] (block_replace) requires non-empty block_id` / `replacement` | Missing fields | Fill in per the parts element structure |
|
||||
| `<img>` not displayed / broken image | `src` was an external URL | Replace with a `file_token` obtained via [`+media-upload`](lark-slides-media-upload.md) |
|
||||
| 3350001 | `replacement` is not a valid single-root XML fragment, or `block_id` does not exist | The CLI already auto-injects `id` and `<content/>`; if it still fails, re-run `slide.get` for the latest XML to confirm `block_id` exists; check that the XML structure is valid and coordinates do not exceed 960x540 |
|
||||
| 403 | Insufficient permission | Requires `slides:presentation:update` or `slides:presentation:write_only`; wiki URLs additionally require `wiki:node:read` |
|
||||
|
||||
## 相关命令
|
||||
## Related Commands
|
||||
|
||||
- [xml_presentation.slide get](lark-slides-xml-presentation-slide-get.md) — 读原页拿 `block_id` / `revision_id`
|
||||
- [xml_presentation.slide replace](lark-slides-xml-presentation-slide-replace.md) — 底层 replace API 参考
|
||||
- [+media-upload](lark-slides-media-upload.md) — 上传图片拿 `file_token`
|
||||
- [lark-slides-edit-workflows.md](lark-slides-edit-workflows.md) — 读-改-写闭环 + 决策树
|
||||
- [xml_presentation.slide get](lark-slides-xml-presentation-slide-get.md) — read the original page for `block_id` / `revision_id`
|
||||
- [xml_presentation.slide replace](lark-slides-xml-presentation-slide-replace.md) — reference for the underlying replace API
|
||||
- [+media-upload](lark-slides-media-upload.md) — upload an image to get a `file_token`
|
||||
- [lark-slides-edit-workflows.md](lark-slides-edit-workflows.md) — read-modify-write loop + decision tree
|
||||
|
||||
@@ -1,40 +1,40 @@
|
||||
# slides +screenshot
|
||||
|
||||
## 用途
|
||||
## Purpose
|
||||
|
||||
获取幻灯片页面截图并保存为本地图片文件。默认用于已存在 PPT 页面截图;传入 `--content` 时用于直接渲染单个 `<slide>` XML 片段预览。本 shortcut 会在 CLI 进程内解码并写入文件,stdout 只返回文件路径、大小、页面 ID 等元信息,避免把图片 Base64 输出给模型。
|
||||
Takes screenshots of slide pages and saves them as local image files. By default it screenshots pages of an existing deck; when `--content` is passed, it directly renders a single `<slide>` XML fragment for preview. This shortcut decodes and writes the files inside the CLI process; stdout only returns metadata such as file path, size, and slide ID, avoiding sending image Base64 to the model.
|
||||
|
||||
注意:该截图能力受应用白名单限制,绝大多数应用不可用。若截图失败,记录错误即可;不要引导用户申请 `slides:presentation:screenshot` 权限。后续按 `validation-checklist.md` 走非截图验证,不要声称已完成截图验收。
|
||||
Note: this screenshot capability is gated by an application allowlist, and the vast majority of applications cannot use it. If a screenshot fails, just record the error; do not steer the user toward requesting the `slides:presentation:screenshot` permission. Then follow `validation-checklist.md` for non-screenshot validation, and do not claim that screenshot-based acceptance was completed.
|
||||
|
||||
## 命令
|
||||
## Command
|
||||
|
||||
```bash
|
||||
lark-cli slides +screenshot --as user \
|
||||
--presentation '<xml_presentation_id 或 slides/wiki URL>' \
|
||||
--presentation '<xml_presentation_id or slides/wiki URL>' \
|
||||
--slide-number 1
|
||||
```
|
||||
|
||||
渲染本地 XML 内容:
|
||||
Render local XML content:
|
||||
|
||||
```bash
|
||||
lark-cli slides +screenshot --as user \
|
||||
--content @slide.xml
|
||||
```
|
||||
|
||||
## 参数
|
||||
## Parameters
|
||||
|
||||
| 参数 | 必需 | 说明 |
|
||||
| Parameter | Required | Description |
|
||||
|------|------|------|
|
||||
| `--presentation` | list 模式必需 | `xml_presentation_id`、`/slides/` URL,或解析后为 slides 的 `/wiki/` URL。传 `--content` 时不能使用 |
|
||||
| `--slide-id` | list 模式至少提供 `--slide-id` / `--slide-number` 之一 | 页面 short ID;多页截图时重复传入;一次最多 10 页(`--slide-id` + `--slide-number` 合计小于等于 10) |
|
||||
| `--slide-number` | list 模式至少提供 `--slide-id` / `--slide-number` 之一 | 页面页号;多页截图时重复传入;一次最多 10 页(`--slide-id` + `--slide-number` 合计小于等于 10) |
|
||||
| `--content` | render 模式必需 | 要直接渲染的 `<slide>` XML 片段;支持直接传值、`@file`、`-` stdin。传入后不能同时传 `--slide-id` / `--slide-number` |
|
||||
| `--output-dir` | 否 | 输出目录,默认 `.lark-slides/screenshots`;必须是当前目录内的相对路径 |
|
||||
| `--output-name` | 否 | render 模式的输出文件名 stem;未指定时优先用返回的 `slide_id`,否则用 `rendered-slide`。若目标文件已存在,会自动追加递增后缀避免覆盖 |
|
||||
| `--presentation` | Required in list mode | `xml_presentation_id`, `/slides/` URL, or a `/wiki/` URL that resolves to slides. Cannot be used when `--content` is passed |
|
||||
| `--slide-id` | List mode requires at least one of `--slide-id` / `--slide-number` | Slide short ID; repeat the flag for multiple pages; at most 10 pages per call (`--slide-id` + `--slide-number` combined at most 10) |
|
||||
| `--slide-number` | List mode requires at least one of `--slide-id` / `--slide-number` | Slide page number; repeat the flag for multiple pages; at most 10 pages per call (`--slide-id` + `--slide-number` combined at most 10) |
|
||||
| `--content` | Required in render mode | The `<slide>` XML fragment to render directly; supports a literal value, `@file`, or `-` stdin. When passed, `--slide-id` / `--slide-number` cannot be used at the same time |
|
||||
| `--output-dir` | No | Output directory, default `.lark-slides/screenshots`; must be a relative path inside the current directory |
|
||||
| `--output-name` | No | Output file name stem in render mode; when unspecified, the returned `slide_id` is preferred, otherwise `rendered-slide`. If the target file already exists, an incrementing suffix is appended automatically to avoid overwriting |
|
||||
|
||||
## 示例
|
||||
## Examples
|
||||
|
||||
### 单页截图
|
||||
### Single-Page Screenshot
|
||||
|
||||
```bash
|
||||
lark-cli slides +screenshot --as user \
|
||||
@@ -42,9 +42,9 @@ lark-cli slides +screenshot --as user \
|
||||
--slide-number 1
|
||||
```
|
||||
|
||||
### 多页截图
|
||||
### Multi-Page Screenshot
|
||||
|
||||
一次不要超过 10 页;如需更多页面,分批调用。
|
||||
Do not exceed 10 pages per call; for more pages, call in batches.
|
||||
|
||||
```bash
|
||||
lark-cli slides +screenshot --as user \
|
||||
@@ -54,7 +54,7 @@ lark-cli slides +screenshot --as user \
|
||||
--output-dir .lark-slides/screenshots/demo
|
||||
```
|
||||
|
||||
### 渲染 XML 预览
|
||||
### Rendering an XML Preview
|
||||
|
||||
```bash
|
||||
lark-cli slides +screenshot --as user \
|
||||
@@ -62,9 +62,9 @@ lark-cli slides +screenshot --as user \
|
||||
--output-name preview
|
||||
```
|
||||
|
||||
## 返回值
|
||||
## Return Value
|
||||
|
||||
返回 JSON 不包含 Base64 图片内容:
|
||||
The returned JSON does not include Base64 image content:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -86,12 +86,12 @@ lark-cli slides +screenshot --as user \
|
||||
}
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
## Notes
|
||||
|
||||
1. 优先使用 `slides +screenshot` 保存本地图片,不要把图片 Base64 打到 stdout。
|
||||
2. 已存在 PPT 页面截图时,不传 `--content`,用 `--presentation` + `--slide-id` 或 `--slide-number`。
|
||||
3. 本地 XML 预览时,传 `--content @file` 或 `--content -`,内容应为单个 `<slide>` XML 片段;此时不要传 `--presentation` / `--slide-id` / `--slide-number`。
|
||||
4. `slide_id` 是页面 short ID,页码请用 `--slide-number`。
|
||||
5. list 模式一次最多传 10 页(`--slide-id` + `--slide-number` 合计小于等于 10);更多页面请分批截图。
|
||||
6. list 模式默认文件名包含 presentation ID、页码和/或 slide ID;文件已存在时自动追加 `_2`、`_3` 等后缀,避免覆盖旧截图。
|
||||
7. 截图来自服务端渲染结果,适合创建/替换后验证页面是否为空白、破图或布局明显异常。
|
||||
1. Prefer `slides +screenshot` to save local images; never dump image Base64 to stdout.
|
||||
2. When screenshotting pages of an existing deck, do not pass `--content`; use `--presentation` + `--slide-id` or `--slide-number`.
|
||||
3. For local XML preview, pass `--content @file` or `--content -`; the content should be a single `<slide>` XML fragment; in this case do not pass `--presentation` / `--slide-id` / `--slide-number`.
|
||||
4. `slide_id` is the slide's short ID; for page numbers use `--slide-number`.
|
||||
5. List mode accepts at most 10 pages per call (`--slide-id` + `--slide-number` combined at most 10); screenshot more pages in batches.
|
||||
6. In list mode the default file name contains the presentation ID, page number, and/or slide ID; when the file already exists, a `_2`, `_3`, etc. suffix is appended automatically to avoid overwriting old screenshots.
|
||||
7. Screenshots come from the server-side rendering result, which is suitable for verifying after create/replace whether a page is blank, has broken images, or is obviously mis-laid-out.
|
||||
|
||||
@@ -1,94 +1,94 @@
|
||||
# Whiteboard 画板元素
|
||||
# Whiteboard artboard element
|
||||
|
||||
`<whiteboard>` 放在 `<data>` 内,内部可放 **SVG** 或 **Mermaid**,用于绘制流程图、时序图、架构图、散点图、漏斗图、自定义图标、装饰图案等 `<chart>` 和 `<shape>` 难以覆盖的视觉内容。
|
||||
`<whiteboard>` is placed inside `<data>`, which can contain **SVG** or **Mermaid**, which is used to draw flow charts, sequence diagrams, architecture diagrams, scatter plots, funnel charts, custom icons, decorative patterns, etc. visual content that is difficult to cover with `<chart>` and `<shape>`.
|
||||
|
||||
普通柱状图、条形图、折线图、面积图、雷达图、饼图 / 环图和组合图应优先使用原生 `<chart>`。除非用户明确要求像素级自定义,或图表类型确实不受 `<chart>` 支持,否则不要用 `<whiteboard>` + SVG / Mermaid 重画这些标准图表。
|
||||
Ordinary column charts, bar charts, line charts, area charts, radar charts, pie charts/donut charts and combination charts should give priority to using the native `<chart>`. Do not redraw these standard charts with `<whiteboard>` + SVG/Mermaid unless the user explicitly requires pixel-level customization, or the chart type is truly not supported by `<chart>`.
|
||||
|
||||
> 前置条件:使用本文档前先阅读 [lark-slides SKILL.md](../SKILL.md)。
|
||||
> Prerequisite: Read [lark-slides SKILL.md](../SKILL.md) before using this document.
|
||||
|
||||
---
|
||||
|
||||
## `<chart>` 还是 `<whiteboard>`?
|
||||
## `<chart>` or `<whiteboard>`?
|
||||
|
||||
**先判断内容类型,再进入本文档:**
|
||||
**Determine the content type first before entering this document:**
|
||||
|
||||
| 场景 | 推荐元素 |
|
||||
| Scene | Recommended elements |
|
||||
|------|---------|
|
||||
| 有结构化数据序列的柱/条/折线/面积/雷达/饼/环/组合图 | `<chart>` — 原生渲染,支持 legend / tooltip / 系列配色 |
|
||||
| 散点图、漏斗图(`<chart>` 不支持)或其他非原生数据视觉 | `<whiteboard>` SVG |
|
||||
| 流程图、时序图、架构图、类图、ER 图等拓扑图 | `<whiteboard>` Mermaid 或 SVG |
|
||||
| 自定义图标、徽标、示意性图形(需要 path/polygon 精确控制) | `<whiteboard>` SVG |
|
||||
| 进度条、波浪背景、装饰图案、像素级自定义可视化 | `<whiteboard>` SVG |
|
||||
| Column/bar/polyline/area/radar/pie/ring/combination chart with structured data sequence | `<chart>` — native rendering, supports legend / tooltip / series color matching |
|
||||
| Scatter plots, funnel charts (not supported by `<chart>`), or other non-native data visuals | `<whiteboard>` SVG |
|
||||
| Flow charts, sequence diagrams, architecture diagrams, class diagrams, ER diagrams and other topology diagrams | `<whiteboard>` Mermaid or SVG |
|
||||
| Custom icons, logos, schematic graphics (requires path/polygon precise control) | `<whiteboard>` SVG |
|
||||
| Progress bars, wavy backgrounds, decorative patterns, pixel-level custom visualization | `<whiteboard>` SVG |
|
||||
|
||||
> 适合 `<chart>` 的内容就用 `<chart>`,不要用 SVG / Mermaid 手绘——原生渲染更省力、结构更稳定,也更容易被回读和后续编辑。
|
||||
> Use `<chart>` for content that is suitable for `<chart>`, and do not use SVG/Mermaid hand-drawing - native rendering is less labor-intensive, the structure is more stable, and it is easier to be read back and subsequently edited.
|
||||
|
||||
---
|
||||
|
||||
## whiteboard 公共属性
|
||||
## whiteboard public property
|
||||
|
||||
| 属性 | 必需 | 说明 |
|
||||
| Properties | Required | Description |
|
||||
|------|------|------|
|
||||
| `topLeftX` | 是 | 左上角 X 坐标(slide 坐标系,slide 默认宽 960) |
|
||||
| `topLeftY` | 是 | 左上角 Y 坐标(slide 坐标系,slide 默认高 540) |
|
||||
| `width` | 是 | 画板宽度(像素) |
|
||||
| `height` | 是 | 画板高度(像素) |
|
||||
| `topLeftX` | Yes | X coordinate of the upper left corner (slide coordinate system, slide default width is 960) |
|
||||
| `topLeftY` | Yes | Y coordinate of the upper left corner (slide coordinate system, slide default height is 540) |
|
||||
| `width` | Yes | Artboard width (pixels) |
|
||||
| `height` | Yes | Artboard height (pixels) |
|
||||
|
||||
> SVG 模式下 `<svg>` 需声明 `xmlns="http://www.w3.org/2000/svg"`;内容大小由子元素包围盒决定,`width`/`height`/`viewBox` 不影响渲染(仅当元素属性使用百分比值时需要 `viewBox` 提供计算基准)。Mermaid 模式不需要额外属性。
|
||||
> In SVG mode, `<svg>` needs to declare `xmlns="http://www.w3.org/2000/svg"`; the content size is determined by the bounding box of the child element, and `width`/`height`/`viewBox` does not affect rendering (only when the element attribute uses a percentage value, `viewBox` is required to provide a calculation basis). Mermaid mode requires no additional attributes.
|
||||
|
||||
SVG 内的坐标相对于 whiteboard 自身左上角(0,0),与 slide 坐标系无关。
|
||||
The coordinates in the SVG are relative to the upper left corner (0,0) of the whiteboard itself and have nothing to do with the slide coordinate system.
|
||||
|
||||
---
|
||||
|
||||
## SVG 还是 Mermaid?
|
||||
## SVG or Mermaid?
|
||||
|
||||
选择分三步:**先排除原生 `<chart>`,再判断 whiteboard 类型,最后看当前模型身份**。
|
||||
The selection is divided into three steps: **First exclude the native `<chart>`, then determine the whiteboard type, and finally look at the current model identity**.
|
||||
|
||||
### 第一步:先确认是否应该使用 `<chart>`
|
||||
### Step one: Confirm whether you should use `<chart>`
|
||||
|
||||
如果内容是柱状图、条形图、折线图、面积图、雷达图、饼图 / 环图或组合图,返回使用原生 `<chart>`,不要继续套用本文档的 SVG / Mermaid 路径。
|
||||
If the content is a column chart, bar chart, line chart, area chart, radar chart, pie/donut chart, or combination chart, return to using the native `<chart>` and do not continue to apply the SVG / Mermaid path of this document.
|
||||
|
||||
### 第二步:whiteboard 类型优先判断
|
||||
### Step 2: Whiteboard type priority judgment
|
||||
|
||||
以下类型**推荐 Mermaid**,自动布局、代码简洁;如需精确匹配品牌配色或自定义节点样式,可改用 SVG:
|
||||
The following types **recommend Mermaid**, with automatic layout and concise code; if you need to accurately match the brand color or customize the node style, you can use SVG instead:
|
||||
|
||||
| 图表类型 | Mermaid 关键字 |
|
||||
| Chart Types | Mermaid Keywords |
|
||||
|----------|--------------|
|
||||
| 流程图、决策树、架构图 | `flowchart TD` / `flowchart LR` |
|
||||
| 时序图 | `sequenceDiagram` |
|
||||
| 类图 | `classDiagram` |
|
||||
| 甘特图 | `gantt` |
|
||||
| 状态图 | `stateDiagram-v2` |
|
||||
| 思维导图 | `mindmap` |
|
||||
| ER 图 | `erDiagram` |
|
||||
| Flowchart, decision tree, architecture diagram | `flowchart TD` / `flowchart LR` |
|
||||
| Sequence diagram | `sequenceDiagram` |
|
||||
| Class Diagram | `classDiagram` |
|
||||
| Gantt chart | `gantt` |
|
||||
| State Diagram | `stateDiagram-v2` |
|
||||
| Mind map | `mindmap` |
|
||||
| ER Diagram | `erDiagram` |
|
||||
|
||||
### 第三步:非原生图表与装饰元素按模型身份选路径
|
||||
### Step 3: Select paths for non-native charts and decorative elements based on model identity
|
||||
|
||||
上表以外的场景(散点图、漏斗图、进度条、时间线、波浪背景、星点纹理等)需要精确控制坐标和配色,SVG 表达力更强,但各模型生成 SVG 的能力有差异:
|
||||
Scenes other than the above table (scatter charts, funnel charts, progress bars, timelines, wave backgrounds, star point textures, etc.) require precise control of coordinates and color matching. SVG is more expressive, but the ability of each model to generate SVG is different:
|
||||
|
||||
| 模型身份 | 路径 |
|
||||
| Model Identity | Path |
|
||||
|----------|------|
|
||||
| Claude / Gemini / GPT / GLM | **SVG** — 精确控制坐标、颜色、透明度 |
|
||||
| Doubao / Seed / Other | **Mermaid** — 用 `gantt`、`flowchart` 等近似表达;确实无法用 Mermaid 表达时才回退到简单 SVG 矩形/线条 |
|
||||
| Claude / Gemini / GPT / GLM | **SVG** — precise control of coordinates, color, transparency |
|
||||
| Doubao / Seed / Other | **Mermaid** — Use `gantt`, `flowchart`, etc. to approximate expression; only fall back to simple SVG rectangle/line when it is really impossible to express with Mermaid |
|
||||
|
||||
> **先自报身份再选路径**:在决定使用 SVG 之前,确认当前模型属于哪一类。不要跳过这一步。
|
||||
> **Report your identity first and then choose a path**: Before deciding to use SVG, confirm which category the current model belongs to. Don't skip this step.
|
||||
|
||||
---
|
||||
|
||||
## 模式一:SVG
|
||||
## Mode 1: SVG
|
||||
|
||||
### ⚠️ 设计品质要求
|
||||
### ⚠️ Design quality requirements
|
||||
|
||||
在 slide 里嵌入 `<whiteboard>` 的目的是**表达原生 `<chart>` 或基础 `<shape>` 难以覆盖的视觉关系**,不是把标准数据图表手绘一遍。
|
||||
The purpose of embedding `<whiteboard>` in slides is to express visual relationships that are difficult to cover with native `<chart>` or basic `<shape>`, rather than hand-drawing standard data charts.
|
||||
|
||||
- **不要只用矩形加文字应付**:通篇纯白底色 + 方块 + 黑字等于白做,这是不及格输出
|
||||
- **非原生数据视觉必须有坐标系**:散点、漏斗等仍要有必要的坐标轴、刻度、数值标注或分段说明,不要只画点或色块
|
||||
- **字号必须有层级**:标题 ≠ 标签 ≠ 数值,混用同一字号会消灭视觉焦点
|
||||
- **配色要与 slide 主题呼应**:深色 slide 背景下图表用透明底或深色卡片;浅色背景下避免再加纯白底块
|
||||
- **每个 whiteboard 都是设计机会**:主动用圆角、半透明填充、清晰分组、节点状态等细节拉开与默认模板的差距
|
||||
- **写 SVG 前先判断背景亮度**:背景亮度 < 30% 时,装饰元素"对比不足"比"过强"危害更大,宁重勿轻;
|
||||
- **装饰层次用亮度跳跃,不用线性叠透明度**:`α=0.04→0.08→0.12` 的等差递增在深色底上几乎看不出差异(相邻层亮度差 ≈20);正确做法是非线性跳跃如 `0.10→0.40→0.70→1.0`,相邻层亮度差 ≥60。
|
||||
- **Don’t just use rectangles and text to deal with it**: Pure white background + squares + black text throughout the article equals nothing, which is a failed output.
|
||||
- **Non-native data vision must have a coordinate system**: Scatter points, funnels, etc. must still have the necessary coordinate axes, scales, numerical labels or segmented descriptions, do not just draw points or color blocks
|
||||
- **Font sizes must have levels**: title ≠ label ≠ value. Mixing the same font size will eliminate visual focus.
|
||||
- **Color matching should echo the slide theme**: Use transparent background or dark cards for charts on dark slide backgrounds; avoid adding pure white background blocks on light backgrounds
|
||||
- **Every whiteboard is a design opportunity**: Actively use details such as rounded corners, translucent filling, clear grouping, node status, etc. to widen the gap with the default template
|
||||
- **Judge the background brightness before writing SVG**: When the background brightness is < 30%, "insufficient contrast" of decorative elements is more harmful than "excessive contrast", so it is better to be heavy than light;
|
||||
- **Decoration levels use brightness jumps instead of linear stacking transparency**: The arithmetic increment of `α=0.04→0.08→0.12` has almost no difference on a dark background (the brightness difference of adjacent layers is ≈20); the correct approach is to use non-linear jumps such as `0.10→0.40→0.70→1.0`, and the brightness difference of adjacent layers is ≥60.
|
||||
|
||||
### 语法
|
||||
### grammar
|
||||
|
||||
```xml
|
||||
<whiteboard width="400" height="300" topLeftX="500" topLeftY="120">
|
||||
@@ -99,44 +99,44 @@ SVG 内的坐标相对于 whiteboard 自身左上角(0,0),与 slide 坐标
|
||||
</whiteboard>
|
||||
```
|
||||
|
||||
`<svg>` 需声明 `xmlns="http://www.w3.org/2000/svg"`;`width`/`height`/`viewBox` 无需填写,若元素属性使用百分比值则需额外声明 `viewBox`。
|
||||
`<svg>` needs to declare `xmlns="http://www.w3.org/2000/svg"`; `width`/`height`/`viewBox` does not need to be filled in. If the element attribute uses a percentage value, an additional `viewBox` needs to be declared.
|
||||
|
||||
### ⚠️ 渲染包围盒规则
|
||||
### ⚠️ Rendering bounding box rules
|
||||
|
||||
whiteboard 渲染时以**所有子元素的几何包围盒合并结果**为内容区域,自适应缩放到容器。
|
||||
When whiteboard is rendered, the combined result of the geometric bounding boxes of all child elements is used as the content area and is adaptively scaled to the container.
|
||||
|
||||
`<svg>` 上的 `width`、`height`、`viewBox` 不影响内容区域的计算,但 `viewBox` 有一个实际用途:**为百分比属性提供计算基准**。若元素使用 `width="50%"` 等百分比值,必须声明 `viewBox` 才能正确解析;绝对坐标元素则无需关心。推荐统一使用绝对坐标,避免引入百分比依赖。
|
||||
`width`, `height`, `viewBox` on `<svg>` do not affect the calculation of the content area, but `viewBox` has a practical purpose: **provide a basis for calculation of the percentage attribute**. If the element uses percentage values such as `width="50%"`, a `viewBox` must be declared for correct parsing; there is no need to care about absolute coordinate elements. It is recommended to use absolute coordinates uniformly to avoid introducing percentage dependence.
|
||||
|
||||
### 支持的 SVG 元素
|
||||
### Supported SVG elements
|
||||
|
||||
| 元素 | 说明 | 典型用途 |
|
||||
| Element | Description | Typical uses |
|
||||
|------|------|---------|
|
||||
| `<rect>` | 矩形,支持 `rx` 圆角 | 卡片、进度条、分段色块 |
|
||||
| `<circle>` | 圆 | 节点、装饰点、环形图 |
|
||||
| `<ellipse>` | 椭圆 | 自定义轮廓图形 |
|
||||
| `<line>` | 直线 | 轴线、分隔线、连接线 |
|
||||
| `<path>` | 任意路径(支持 Q/C 曲线) | 波浪、曲线、弧形 |
|
||||
| `<text>` | 文本,支持中文 | 标签、数值 |
|
||||
| `<polygon>` | 多边形 | 箭头、星形、面积填充 |
|
||||
| `<g>` | 分组 | 批量变换、语义分组 |
|
||||
| `<linearGradient>` | 线性渐变定义,配合 `fill="url(#id)"` 使用 | 渐变背景、渐变填充 |
|
||||
| `<rect>` | Rectangle, supports `rx` rounded corners | Cards, progress bars, segmented color blocks |
|
||||
| `<circle>` | Circle | Node, decorative point, donut chart |
|
||||
| `<ellipse>` | Ellipse | Custom outline graphics |
|
||||
| `<line>` | straight line | axis, dividing line, connecting line |
|
||||
| `<path>` | Any path (supports Q/C curve) | Wave, curve, arc |
|
||||
| `<text>` | Text, supports Chinese | Label, value |
|
||||
| `<polygon>` | Polygon | Arrow, star, area fill |
|
||||
| `<g>` | Grouping | Batch transformation, semantic grouping |
|
||||
| `<linearGradient>` | Linear gradient definition, used with `fill="url(#id)"` | Gradient background, gradient fill |
|
||||
|
||||
**颜色:** 统一用 `rgba(R,G,B,A)`,对深浅背景都友好。
|
||||
**虚线:** `stroke-dasharray="4,4"` 用于网格线 / 坐标轴。
|
||||
**变换:** `transform="translate(x,y)"` / `rotate(deg cx cy)` / `scale(n)` 均支持。
|
||||
**Color:** Use `rgba(R,G,B,A)` uniformly, which is friendly to both dark and light backgrounds.
|
||||
**Dash:** `stroke-dasharray="4,4"` for gridlines/axes.
|
||||
**Transformation:** `transform="translate(x,y)"` / `rotate(deg cx cy)` / `scale(n)` are all supported.
|
||||
|
||||
---
|
||||
### 元素计算
|
||||
### Element calculation
|
||||
|
||||
SVG 中只要涉及批量定位、等间距排布或数据映射,**建议额外运行一个 Python 脚本把坐标算出来再填入 SVG**,而不是手动估值。适用范围包括散点、漏斗、装饰性点阵、等间距圆、重复图案等;普通柱状图、折线图、饼图仍应回到原生 `<chart>`。
|
||||
As long as batch positioning, equal spacing or data mapping is involved in SVG, it is recommended to run an additional Python script to calculate the coordinates and then fill them into the SVG instead of manual estimation. The scope of application includes scatter points, funnels, decorative dots, equally spaced circles, repeating patterns, etc.; ordinary bar charts, line charts, and pie charts should still return to the original `<chart>`.
|
||||
|
||||
> **主动去算**:写 SVG 之前先运行脚本,把输出当注释贴在 `<svg>` 开头,再照着填坐标。估值几乎每次都需要反复调整,跳过这步反而更慢。
|
||||
> **Actively calculate**: Run the script before writing SVG, paste the output as a comment at the beginning of `<svg>`, and then fill in the coordinates accordingly. Valuation needs to be adjusted repeatedly almost every time, and skipping this step will make it slower.
|
||||
|
||||
**散点图 / 装饰性点阵范式**
|
||||
**Scatter Plot/Ornamental Dot Pattern**
|
||||
|
||||
```python
|
||||
W, H = 360, 260
|
||||
origin_x, origin_y = 50, 216 # 左下角,SVG Y 轴向下
|
||||
origin_x, origin_y = 50, 216 # Lower left corner, SVG Y axis downward
|
||||
cw, ch = 290, 184
|
||||
|
||||
points = [(12, 40), (28, 80), (45, 65)]
|
||||
@@ -147,7 +147,7 @@ for i, (xv, yv) in enumerate(points):
|
||||
print(f"point-{i}: cx={x} cy={y}")
|
||||
```
|
||||
|
||||
**装饰性元素(等间距范式)**
|
||||
**Decorative elements (equal spacing paradigm)**
|
||||
|
||||
```python
|
||||
n, total_w, cy, r = 8, 340, 40, 4
|
||||
@@ -156,12 +156,12 @@ for i in range(n):
|
||||
print(f"circle-{i}: cx={round(i * step)} cy={cy} r={r}")
|
||||
```
|
||||
|
||||
**最大包围盒 → whiteboard 尺寸**
|
||||
**Maximum bounding box → whiteboard size**
|
||||
|
||||
所有元素坐标算完后,汇总出整体包围盒,直接作为 whiteboard 的 `width`/`height`:
|
||||
After the coordinates of all elements are calculated, the overall bounding box is summarized and used directly as the `width`/`height` of the whiteboard:
|
||||
|
||||
```python
|
||||
# 每个元素登记 (x, y, w, h),含 stroke 外扩
|
||||
# Register (x, y, w, h) for each element, including stroke expansion
|
||||
elements = [
|
||||
(10, 20, 80, 160), # item-0
|
||||
(107, 10, 80, 170), # item-1
|
||||
@@ -179,12 +179,12 @@ wb_h = max(y2) - min(ys)
|
||||
print(f"whiteboard width={wb_w} height={wb_h}")
|
||||
```
|
||||
|
||||
输出即 `<whiteboard width=... height=...>` 的值,无需手动估算。
|
||||
The output is the value of `<whiteboard width=... height=...>`, no manual estimation is required.
|
||||
|
||||
---
|
||||
### 布局模式
|
||||
### Layout mode
|
||||
|
||||
**全屏装饰层**
|
||||
**Full screen decoration layer**
|
||||
```xml
|
||||
<whiteboard width="960" height="540" topLeftX="0" topLeftY="0">
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
@@ -193,13 +193,13 @@ print(f"whiteboard width={wb_w} height={wb_h}")
|
||||
</whiteboard>
|
||||
```
|
||||
|
||||
> ⚠️ 全屏装饰 whiteboard 必须放在所有 `<shape>` / `<img>` / `<table>` 之前,否则会遮挡文字内容。XML 中元素位置越靠后,渲染层级越高。
|
||||
> ⚠️ Full-screen decoration whiteboard must be placed before all `<shape>` / `<img>` / `<table>`, otherwise the text content will be obscured. The later the element is in XML, the higher the rendering level.
|
||||
|
||||
**侧栏图表(与文字 shape 并排)**
|
||||
**Sidebar chart (side by side with text shape)**
|
||||
```xml
|
||||
<!-- 左侧文字 -->
|
||||
<!-- Text on the left -->
|
||||
<shape type="text" topLeftX="60" topLeftY="120" width="500" height="340">...</shape>
|
||||
<!-- 右侧图表 -->
|
||||
<!-- Chart on the right -->
|
||||
<whiteboard width="340" height="340" topLeftX="580" topLeftY="120">
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
...
|
||||
@@ -207,7 +207,7 @@ print(f"whiteboard width={wb_w} height={wb_h}")
|
||||
</whiteboard>
|
||||
```
|
||||
|
||||
**底部装饰条**
|
||||
**Bottom decorative strip**
|
||||
```xml
|
||||
<whiteboard width="960" height="100" topLeftX="0" topLeftY="440">
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
@@ -218,114 +218,114 @@ print(f"whiteboard width={wb_w} height={wb_h}")
|
||||
|
||||
---
|
||||
|
||||
### 禁止使用的 SVG 特性
|
||||
### Prohibited SVG features
|
||||
|
||||
以下特性在 slide `<whiteboard>` 渲染端不支持或行为不可预测,必须避免:
|
||||
The following features are not supported or behave unpredictably on the slide `<whiteboard>` rendering side and must be avoided:
|
||||
|
||||
| 禁止 | 原因 | 替代方案 |
|
||||
| Banned | Reasons | Alternatives |
|
||||
|------|------|---------|
|
||||
| `<radialGradient>` | 渲染失败 | 用 `<linearGradient>` 或 `rgba()` 透明度模拟深浅层次 |
|
||||
| `<filter>`(阴影、模糊等) | 渲染失败 | 用半透明 `<rect>` 叠加模拟阴影 |
|
||||
| `<clipPath>` / `<mask>` | 渲染失败 | 调整元素坐标和尺寸自然裁切 |
|
||||
| `<pattern>` | 渲染失败 | 手动铺 `<circle>` / `<rect>` 点阵 |
|
||||
| `skewX` / `skewY` / `matrix(...)` | 空间扭曲,降级渲染 | 用 `rotate` + `translate` 替代 |
|
||||
| `<image>` 外链 URL | 不支持外链 | 先上传得到 file_token,再用 `<img>` 元素 |
|
||||
| `<radialGradient>` | Rendering failed | Use `<linearGradient>` or `rgba()` transparency to simulate shades |
|
||||
| `<filter>` (shadow, blur, etc.) | Rendering failed | Simulating shadows with translucent `<rect>` overlay |
|
||||
| `<clipPath>` / `<mask>` | Rendering failed | Adjust element coordinates and size for natural cropping |
|
||||
| `<pattern>` | Rendering failed | Manual paving `<circle>` / `<rect>` lattice |
|
||||
| `skewX` / `skewY` / `matrix(...)` | Space distortion, degraded rendering | Use `rotate` + `translate` instead |
|
||||
| `<image>` external link URL | External links are not supported | Upload the file_token first, then use the `<img>` element |
|
||||
|
||||
---
|
||||
|
||||
|
||||
## 模式二:Mermaid
|
||||
## Mode 2: Mermaid
|
||||
|
||||
### 语法
|
||||
### grammar
|
||||
|
||||
```xml
|
||||
<whiteboard topLeftX="72" topLeftY="60" width="816" height="360">
|
||||
<mermaid>
|
||||
<![CDATA[
|
||||
flowchart TD
|
||||
A[检查 lark-cli 与 jq] --> B[编写每页 slide XML]
|
||||
B --> C[通过 jq 生成 slides JSON]
|
||||
C --> D[执行 slides +create]
|
||||
D --> E[读取 xml_presentation_id]
|
||||
E --> F[回读并验证创建结果]
|
||||
A[Check lark-cli and jq] --> B[Write slide XML for each page]
|
||||
B --> C[Generate slides JSON through jq]
|
||||
C --> D[execute slides +create]
|
||||
D --> E[Read xml_presentation_id]
|
||||
E --> F [Read back and verify the creation results]
|
||||
]]>
|
||||
</mermaid>
|
||||
</whiteboard>
|
||||
```
|
||||
|
||||
**关键点:**
|
||||
- 内容用 `<![CDATA[...]]>` 包裹——Mermaid 语法里的 `[`、`>`、`-->` 是 XML 特殊字符,CDATA 避免转义问题
|
||||
- whiteboard 只需 `topLeftX`、`topLeftY`、`width`、`height`
|
||||
**Key Points:**
|
||||
- Content is wrapped with `<![CDATA[...]]>` - `[`, `>`, `-->` in Mermaid syntax are XML special characters, CDATA avoids escaping problems
|
||||
- whiteboard only needs `topLeftX`, `topLeftY`, `width`, `height`
|
||||
|
||||
### 支持的 Mermaid 图表类型
|
||||
### Supported Mermaid chart types
|
||||
|
||||
| 类型 | 关键字 | 适用场景 |
|
||||
| Type | Keywords | Applicable scenarios |
|
||||
|------|--------|---------|
|
||||
| 流程图 | `flowchart TD` / `flowchart LR` | 业务流程、决策树、工作流 |
|
||||
| 时序图 | `sequenceDiagram` | 系统交互、API 调用链 |
|
||||
| 甘特图 | `gantt` | 项目计划、里程碑 |
|
||||
| 类图 | `classDiagram` | 对象关系、架构设计 |
|
||||
| ER 图 | `erDiagram` | 数据库结构 |
|
||||
| 状态图 | `stateDiagram-v2` | 状态机、生命周期 |
|
||||
| 思维导图 | `mindmap` | 主题梳理、知识架构 |
|
||||
| 用户旅程 | `journey` | 用户体验路径 |
|
||||
| Flowchart | `flowchart TD` / `flowchart LR` | Business process, decision tree, workflow |
|
||||
| Sequence diagram | `sequenceDiagram` | System interaction, API call chain |
|
||||
| Gantt chart | `gantt` | Project plan, milestones |
|
||||
| Class diagram | `classDiagram` | Object relationship, architecture design |
|
||||
| ER diagram | `erDiagram` | Database structure |
|
||||
| State diagram | `stateDiagram-v2` | State machine, life cycle |
|
||||
| Mind map | `mindmap` | Topic sorting, knowledge structure |
|
||||
| User journey | `journey` | User experience path |
|
||||
|
||||
### Mermaid 布局建议
|
||||
### Mermaid Layout Suggestions
|
||||
|
||||
Mermaid 图表会自动撑满 whiteboard 区域。建议:
|
||||
- 流程图留足高度,节点较多时适当增加 height(比如 400-480)
|
||||
- 避免一页放超过 15 个节点,内容太密时考虑分页
|
||||
- 推荐尺寸参考:
|
||||
Mermaid charts will automatically fill the whiteboard area. suggestion:
|
||||
- Leave enough height for the flow chart. When there are many nodes, increase the height appropriately (for example, 400-480)
|
||||
- Avoid placing more than 15 nodes on one page, and consider paging when the content is too dense.
|
||||
- Recommended size reference:
|
||||
|
||||
| 图表类型 | 建议 width | 建议 height |
|
||||
| Chart type | Recommended width | Recommended height |
|
||||
|---------|-----------|------------|
|
||||
| 流程图(5-8 节点) | 720-816 | 300-400 |
|
||||
| 时序图(3-5 参与者) | 720-816 | 320-420 |
|
||||
| 甘特图 | 816 | 280-360 |
|
||||
| 思维导图 | 816 | 380-480 |
|
||||
| Flowchart (5-8 nodes) | 720-816 | 300-400 |
|
||||
| Sequence diagram (3-5 participants) | 720-816 | 320-420 |
|
||||
| Gantt Chart | 816 | 280-360 |
|
||||
| Mind Map | 816 | 380-480 |
|
||||
|
||||
---
|
||||
|
||||
## 注意事项 & 已知问题
|
||||
## Notes & Known Issues
|
||||
|
||||
### z-order(SVG 模式)
|
||||
### z-order (SVG mode)
|
||||
|
||||
whiteboard 在 XML 中的位置决定渲染层级:在 shape 前 → 在下层;在 shape 后 → 在上层。全屏装饰 whiteboard 应放在所有 shape 之前。
|
||||
The position of the whiteboard in the XML determines the rendering level: before the shape → on the lower layer; after the shape → on the upper layer. The full-screen decorative whiteboard should be placed before all shapes.
|
||||
|
||||
### Mermaid CDATA 必要性
|
||||
### Mermaid CDATA Necessity
|
||||
|
||||
Mermaid 语法包含 `[`、`>`、`-->`,不用 CDATA 直接写会破坏 XML 解析。始终使用 `<![CDATA[ ... ]]>`。
|
||||
Mermaid syntax contains `[`, `>`, `-->`, and writing directly without CDATA will destroy XML parsing. Always use `<![CDATA[ ... ]]>`.
|
||||
|
||||
---
|
||||
|
||||
## 快速自检清单
|
||||
## Quick self-check checklist
|
||||
|
||||
**SVG 模式——结构检查:**
|
||||
- [ ] `<svg>` 声明了 `xmlns="http://www.w3.org/2000/svg"`
|
||||
- [ ] whiteboard 的 `width`/`height` 由所有元素的最大包围盒(含 stroke 外扩)计算得出,不手动估值
|
||||
**SVG Mode - Structure Check:**
|
||||
- [ ] `<svg>` declares `xmlns="http://www.w3.org/2000/svg"`
|
||||
- [ ] `width`/`height` of whiteboard is calculated from the maximum bounding box of all elements (including stroke expansion), no manual estimation is required
|
||||
- [ ] `topLeftX + width ≤ 960`,`topLeftY + height ≤ 540`
|
||||
- [ ] 无 `<radialGradient>` / `<filter>` / `<clipPath>`
|
||||
- [ ] 文字 `y` 坐标为 baseline 位置,最小值 ≥ font-size(避免被裁切)
|
||||
- [ ] None `<radialGradient>` / `<filter>` / `<clipPath>`
|
||||
- [ ] The text `y` coordinate is the baseline position, the minimum value is ≥ font-size (to avoid being cropped)
|
||||
|
||||
**SVG 模式——视觉品质检查:**
|
||||
- [ ] 非原生数据视觉有必要的坐标轴、网格线、数值标注或分段说明,没有"裸点"或无解释色块
|
||||
- [ ] 字号有层级:标题 > 数值 > 轴标签,非全部相同
|
||||
- [ ] 单一数据系列用同一颜色,多系列用不同颜色且对比充足
|
||||
- [ ] 轴标签与图表元素互不遮挡,留有足够空间
|
||||
- [ ] 坐标推导有注释(写明 originX/Y、chartW/H、数据映射公式)
|
||||
**SVG Mode - Visual Quality Check:**
|
||||
- [ ] Non-native data visuals have necessary coordinate axes, grid lines, numerical labels or segmentation instructions, but no "bare points" or unexplained color blocks.
|
||||
- [ ] There are levels of font sizes: title > value > axis label, not all the same
|
||||
- [ ] Use the same color for a single data series, use different colors for multiple series with sufficient contrast.
|
||||
- [ ] Axis labels and chart elements do not block each other, leaving enough space
|
||||
- [ ] Coordinate derivation has comments (indicate originX/Y, chartW/H, data mapping formula)
|
||||
|
||||
**Mermaid 模式:**
|
||||
- [ ] 内容包在 `<![CDATA[...]]>` 内
|
||||
- [ ] CDATA 结束符 `]]>` 不出现在 Mermaid 代码本身中
|
||||
**Mermaid Mode:**
|
||||
- [ ] Content is wrapped in `<![CDATA[...]]>`
|
||||
- [ ] CDATA terminator `]]>` does not appear in the Mermaid code itself
|
||||
- [ ] `topLeftX + width ≤ 960`,`topLeftY + height ≤ 540`
|
||||
- [ ] 节点数量合理(单图不超过 15-20 个节点)
|
||||
- [ ] The number of nodes is reasonable (no more than 15-20 nodes in a single graph)
|
||||
|
||||
**通用:**
|
||||
- [ ] XML 标签全部闭合,属性引号完整
|
||||
- [ ] 如果失败,检查是否是偶发 5001000,重试一次
|
||||
**General:**
|
||||
- [ ] XML tags are all closed and attribute quotes are complete
|
||||
- [ ] If it fails, check whether it is an accidental 5001000 and try again.
|
||||
|
||||
---
|
||||
|
||||
## 参考
|
||||
## refer to
|
||||
|
||||
- [lark-slides SKILL.md](../SKILL.md)
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# slides +xml-get(读取 XML)
|
||||
# slides +xml-get (Read XML)
|
||||
|
||||
读取已有演示文稿的完整 XML,或按 `slide_id` / 页码读取单页 XML。适合创建后验收、编辑前备份、获取 `slide_id` / `revision_id`,以及排查空白页、破图、文本溢出等问题。相比直接调用底层 `xml_presentations.get` / `xml_presentation.slide.get`,本 shortcut 会自动解析 Slides URL / Wiki URL,并可把 XML 保存到本地文件,避免终端输出被截断。
|
||||
Read the full XML of an existing presentation, or read a single slide's XML by `slide_id` / slide number. Suitable for post-creation acceptance checks, backups before editing, obtaining `slide_id` / `revision_id`, and troubleshooting blank pages, broken images, or text overflow. Compared to calling the underlying `xml_presentations.get` / `xml_presentation.slide.get` directly, this shortcut automatically resolves Slides URLs / Wiki URLs and can save the XML to a local file, avoiding truncated terminal output.
|
||||
|
||||
## 命令
|
||||
## Command
|
||||
|
||||
|
||||
```bash
|
||||
@@ -12,22 +12,22 @@ lark-cli slides +xml-get \
|
||||
--output .lark-slides/plan/<deck-id>/readback.xml
|
||||
```
|
||||
|
||||
## 参数
|
||||
## Parameters
|
||||
|
||||
| 参数 | 必需 | 说明 |
|
||||
| Parameter | Required | Description |
|
||||
|------|------|------|
|
||||
| `--presentation` | 是 | `xml_presentation_id`、`/slides/` URL 或 `/wiki/` URL |
|
||||
| `--output` | 否 | 本地 XML 保存路径,必须是当前工作目录内的相对路径,不能传绝对路径。传入时 XML 内容保存到文件,stdout 只返回保存后的绝对路径、大小等简短元信息;省略时默认返回 JSON envelope |
|
||||
| `--slide-id` | 否 | 页面 short ID;传入后只读取该页 XML。不能和 `--slide-number` 同时使用 |
|
||||
| `--slide-number` | 否 | 1-based 页码;传入后只读取该页 XML。不能和 `--slide-id` 同时使用 |
|
||||
| `--revision-id` | 否 | 读取指定版本;默认 `-1`,表示最新版本 |
|
||||
| `--remove-attr-id` | 否 | 仅全文读取可用。移除返回 XML 中的 `id` 属性;适合只读检查,不适合精确块级编辑 |
|
||||
| `--raw` | 否 | 省略 `--output` 时直接把 XML 原文写到 stdout,不包 JSON envelope。不能和 `--output` / `--jq` / 非 json `--format` 同时使用 |
|
||||
| `--dry-run` | 否 | 预览将调用的 API 和输出方式,不读取真实 XML |
|
||||
| `--presentation` | Yes | `xml_presentation_id`, `/slides/` URL, or `/wiki/` URL |
|
||||
| `--output` | No | Local path to save the XML; must be a relative path inside the current working directory, absolute paths are not allowed. When provided, the XML content is saved to the file and stdout only returns brief metadata such as the saved absolute path and size; when omitted, a JSON envelope is returned by default |
|
||||
| `--slide-id` | No | Slide short ID; when provided, only that slide's XML is read. Cannot be used together with `--slide-number` |
|
||||
| `--slide-number` | No | 1-based slide number; when provided, only that slide's XML is read. Cannot be used together with `--slide-id` |
|
||||
| `--revision-id` | No | Read a specific revision; defaults to `-1`, meaning the latest revision |
|
||||
| `--remove-attr-id` | No | Full-document reads only. Removes the `id` attributes from the returned XML; suitable for read-only inspection, not for precise block-level editing |
|
||||
| `--raw` | No | When `--output` is omitted, write the raw XML directly to stdout without a JSON envelope. Cannot be used together with `--output` / `--jq` / a non-json `--format` |
|
||||
| `--dry-run` | No | Preview the API to be called and the output mode without reading the actual XML |
|
||||
|
||||
## 输出到文件
|
||||
## Output to a File
|
||||
|
||||
推荐普通工作流都传 `--output`,尤其是中大型 PPT。`--output` 必须是当前工作目录内的相对路径,例如 `.lark-slides/plan/$PID/readback.xml`,不要传 `/tmp/readback.xml` 这类绝对路径。XML 会写入本地文件,stdout 只保留元信息,便于后续脚本读取。
|
||||
For normal workflows, passing `--output` is recommended, especially for medium and large decks. `--output` must be a relative path inside the current working directory, for example `.lark-slides/plan/$PID/readback.xml`; do not pass absolute paths like `/tmp/readback.xml`. The XML is written to the local file and stdout only keeps the metadata, which makes it easy for subsequent scripts to read.
|
||||
|
||||
```bash
|
||||
lark-cli slides +xml-get --as user \
|
||||
@@ -35,7 +35,7 @@ lark-cli slides +xml-get --as user \
|
||||
--output .lark-slides/plan/$PID/readback.xml
|
||||
```
|
||||
|
||||
成功输出中的 `data` 类似:
|
||||
The `data` in a successful output looks like:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -47,13 +47,13 @@ lark-cli slides +xml-get --as user \
|
||||
}
|
||||
```
|
||||
|
||||
其中 `path` 是 CLI 解析后的绝对路径。
|
||||
Here `path` is the absolute path resolved by the CLI.
|
||||
|
||||
如果传入 `--remove-attr-id`,返回元信息中会包含 `"remove_attr_id": true`。
|
||||
If `--remove-attr-id` is passed, the returned metadata includes `"remove_attr_id": true`.
|
||||
|
||||
## 读取单页
|
||||
## Reading a Single Slide
|
||||
|
||||
已知页面 short ID 时,用 `--slide-id`:
|
||||
When you know the slide's short ID, use `--slide-id`:
|
||||
|
||||
```bash
|
||||
lark-cli slides +xml-get --as user \
|
||||
@@ -62,7 +62,7 @@ lark-cli slides +xml-get --as user \
|
||||
--output .lark-slides/plan/$PID/slide-$SID.xml
|
||||
```
|
||||
|
||||
已知页码时,用 `--slide-number`(页码从 1 开始):
|
||||
When you know the slide number, use `--slide-number` (numbers start at 1):
|
||||
|
||||
```bash
|
||||
lark-cli slides +xml-get --as user \
|
||||
@@ -71,11 +71,11 @@ lark-cli slides +xml-get --as user \
|
||||
--output .lark-slides/plan/$PID/slide-2.xml
|
||||
```
|
||||
|
||||
单页模式底层调用 `xml_presentation.slide.get`,返回或保存的是单个 `<slide>` XML 片段。`--slide-id` 和 `--slide-number` 不能同时传;`--remove-attr-id` 只支持全文读取。
|
||||
Single-slide mode calls `xml_presentation.slide.get` under the hood, and returns or saves a single `<slide>` XML fragment. `--slide-id` and `--slide-number` cannot be passed together; `--remove-attr-id` only supports full-document reads.
|
||||
|
||||
## 输出到终端
|
||||
## Output to the Terminal
|
||||
|
||||
省略 `--output` 时,CLI 默认输出 JSON envelope,XML 位于 `data.xml_presentation.content`(全文)或 `data.slide.content`(单页)。这个模式适合配合 `--jq` 临时提取:
|
||||
When `--output` is omitted, the CLI outputs a JSON envelope by default, with the XML located at `data.xml_presentation.content` (full document) or `data.slide.content` (single slide). This mode is suitable for ad-hoc extraction with `--jq`:
|
||||
|
||||
```bash
|
||||
lark-cli slides +xml-get --as user \
|
||||
@@ -83,7 +83,7 @@ lark-cli slides +xml-get --as user \
|
||||
--jq '.data.xml_presentation.content'
|
||||
```
|
||||
|
||||
需要把 XML 原文直接写到 stdout 时,加 `--raw`:
|
||||
To write the raw XML directly to stdout, add `--raw`:
|
||||
|
||||
```bash
|
||||
lark-cli slides +xml-get --as user \
|
||||
@@ -92,9 +92,9 @@ lark-cli slides +xml-get --as user \
|
||||
--raw
|
||||
```
|
||||
|
||||
## 相关命令
|
||||
## Related Commands
|
||||
|
||||
- [slides +screenshot](lark-slides-screenshot.md) - 获取页面截图做视觉验证
|
||||
- [slides +replace-slide](lark-slides-replace-slide.md) - 局部替换或插入页面元素
|
||||
- [slides +replace-pages](lark-slides-replace-pages.md) - 多页整页重建
|
||||
- [xml_presentations get](lark-slides-xml-presentations-get.md) - 底层原生 API 参考
|
||||
- [slides +screenshot](lark-slides-screenshot.md) - Take slide screenshots for visual verification
|
||||
- [slides +replace-slide](lark-slides-replace-slide.md) - Partially replace or insert slide elements
|
||||
- [slides +replace-pages](lark-slides-replace-pages.md) - Rebuild multiple slides as whole pages
|
||||
- [xml_presentations get](lark-slides-xml-presentations-get.md) - Underlying native API reference
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
# lark-slides xml_presentation.slide delete
|
||||
|
||||
## 用途
|
||||
## Purpose
|
||||
|
||||
删除指定 XML 演示文稿中的幻灯片页面。
|
||||
Delete a slide from the specified XML presentation.
|
||||
|
||||
## 命令
|
||||
## Command
|
||||
|
||||
```bash
|
||||
lark-cli slides xml_presentation.slide delete --as user --params '<json_params>'
|
||||
```
|
||||
|
||||
## 参数说明
|
||||
## Parameter Description
|
||||
|
||||
| 参数 | 类型 | 必需 | 说明 |
|
||||
| Parameter | Type | Required | Description |
|
||||
|------|------|------|------|
|
||||
| `--params` | JSON string | 是 | 路径参数与查询参数 |
|
||||
| `--params` | JSON string | Yes | Path and query parameters |
|
||||
|
||||
### params JSON 结构
|
||||
### params JSON Structure
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -27,16 +27,16 @@ lark-cli slides xml_presentation.slide delete --as user --params '<json_params>'
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 必需 | 说明 |
|
||||
| Field | Type | Required | Description |
|
||||
|------|------|------|------|
|
||||
| `xml_presentation_id` | string | 是 | 演示文稿的唯一标识符 |
|
||||
| `slide_id` | string | 是 | 要删除的幻灯片唯一标识符 |
|
||||
| `revision_id` | integer | 否 | 演示文稿版本号,`-1` 表示最新版本 |
|
||||
| `tid` | string | 否 | 锁的事务 ID |
|
||||
| `xml_presentation_id` | string | Yes | Unique identifier of the presentation |
|
||||
| `slide_id` | string | Yes | Unique identifier of the slide to delete |
|
||||
| `revision_id` | integer | No | Presentation revision number, `-1` means the latest revision |
|
||||
| `tid` | string | No | Transaction ID of the lock |
|
||||
|
||||
## 使用示例
|
||||
## Usage Examples
|
||||
|
||||
### 删除指定幻灯片
|
||||
### Delete a Specific Slide
|
||||
|
||||
```bash
|
||||
lark-cli slides xml_presentation.slide delete --as user --params '{
|
||||
@@ -45,22 +45,22 @@ lark-cli slides xml_presentation.slide delete --as user --params '{
|
||||
}'
|
||||
```
|
||||
|
||||
### 结合查询删除(使用 jq)
|
||||
### Delete After Inspection (with jq)
|
||||
|
||||
```bash
|
||||
# 先读取 XML 内容,确认待删除页面
|
||||
# First read the XML content to confirm the slide to delete
|
||||
lark-cli slides +xml-get --as user \
|
||||
--presentation "slides_example_presentation_id" \
|
||||
--output .lark-slides/plan/slides_example_presentation_id/readback.xml \
|
||||
--json
|
||||
|
||||
# 然后按已知 slide_id 删除
|
||||
# Then delete by the known slide_id
|
||||
lark-cli slides xml_presentation.slide delete --as user --params '{"xml_presentation_id":"slides_example_presentation_id","slide_id":"slide_example_id"}'
|
||||
```
|
||||
|
||||
## 返回值
|
||||
## Return Value
|
||||
|
||||
成功时返回删除确认信息:
|
||||
On success, returns a deletion confirmation:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -72,46 +72,46 @@ lark-cli slides xml_presentation.slide delete --as user --params '{"xml_presenta
|
||||
}
|
||||
```
|
||||
|
||||
### 返回字段说明
|
||||
### Return Field Description
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| Field | Type | Description |
|
||||
|------|------|------|
|
||||
| `data.revision_id` | integer | 删除后的最新版本号 |
|
||||
| `data.revision_id` | integer | The latest revision number after deletion |
|
||||
|
||||
## 常见错误
|
||||
## Common Errors
|
||||
|
||||
| 错误码 | 含义 | 解决方案 |
|
||||
| Error Code | Meaning | Solution |
|
||||
|--------|------|----------|
|
||||
| 404 | 演示文稿不存在 | 检查 `xml_presentation_id` 是否正确 |
|
||||
| 404 | 幻灯片不存在 | 检查 `slide_id` 是否正确,或该幻灯片已被删除 |
|
||||
| 400 | 无法删除唯一幻灯片 | 演示文稿至少保留一页幻灯片 |
|
||||
| 403 | 权限不足 | 检查是否拥有 `slides:presentation:update` 或 `slides:presentation:write_only` scope |
|
||||
| 404 | Presentation does not exist | Check whether `xml_presentation_id` is correct |
|
||||
| 404 | Slide does not exist | Check whether `slide_id` is correct, or the slide may have already been deleted |
|
||||
| 400 | Cannot delete the only slide | The presentation must keep at least one slide |
|
||||
| 403 | Insufficient permissions | Check whether you have the `slides:presentation:update` or `slides:presentation:write_only` scope |
|
||||
|
||||
## 注意事项
|
||||
## Notes
|
||||
|
||||
1. **执行前必做**: 使用 `lark-cli schema slides.xml_presentation.slide.delete` 查看最新的参数结构
|
||||
2. **删除不可逆**: 删除操作无法撤销,请确保已备份重要内容
|
||||
3. **至少保留一页**: 演示文稿必须至少保留一页幻灯片,删除最后一页会报错
|
||||
4. **版本控制**: 如果依赖版本号并发控制,删除前先确认 `revision_id`
|
||||
5. **获取 slide_id**: 创建幻灯片时请保存返回值;仅靠 `get` 返回的 XML 无法直接推导服务端 short ID
|
||||
1. **Do this before executing**: use `lark-cli schema slides.xml_presentation.slide.delete` to check the latest parameter structure
|
||||
2. **Deletion is irreversible**: the delete operation cannot be undone; make sure important content is backed up
|
||||
3. **Keep at least one slide**: the presentation must keep at least one slide; deleting the last slide returns an error
|
||||
4. **Version control**: if you rely on revision numbers for concurrency control, confirm the `revision_id` before deleting
|
||||
5. **Getting slide_id**: save the return value when creating slides; the server-side short ID cannot be derived directly from the XML returned by `get` alone
|
||||
|
||||
## 如何获取 slide_id
|
||||
## How to Get slide_id
|
||||
|
||||
### 方法 1: 创建时保存
|
||||
### Method 1: Save at Creation Time
|
||||
|
||||
```bash
|
||||
lark-cli slides xml_presentation.slide create --as user --params '{"xml_presentation_id":"slides_example_presentation_id"}' --data '{
|
||||
"slide": {
|
||||
"content": "<slide xmlns=\"http://www.larkoffice.com/sml/2.0\"><data><shape type=\"text\" topLeftX=\"80\" topLeftY=\"80\" width=\"800\" height=\"120\"><content textType=\"title\"><p>新页面</p></content></shape></data></slide>"
|
||||
"content": "<slide xmlns=\"http://www.larkoffice.com/sml/2.0\"><data><shape type=\"text\" topLeftX=\"80\" topLeftY=\"80\" width=\"800\" height=\"120\"><content textType=\"title\"><p>New Slide</p></content></shape></data></slide>"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
返回结果中的 `slide_id` 就是后续删除所需的值。
|
||||
The `slide_id` in the response is the value needed for later deletion.
|
||||
|
||||
## 批量删除建议
|
||||
## Batch Deletion Suggestions
|
||||
|
||||
如果需要删除多张幻灯片,建议先整理好待删 `slide_id` 列表,再逐个删除:
|
||||
If you need to delete multiple slides, prepare the list of `slide_id`s to delete first, then delete them one by one:
|
||||
|
||||
```bash
|
||||
for slide_id in sld_a sld_b sld_c; do
|
||||
@@ -119,7 +119,7 @@ for slide_id in sld_a sld_b sld_c; do
|
||||
done
|
||||
```
|
||||
|
||||
## 相关命令
|
||||
## Related Commands
|
||||
|
||||
- [slides +create](lark-slides-create.md) - 创建 PPT / 添加幻灯片页面
|
||||
- [slides +xml-get](lark-slides-xml-get.md) - 读取 PPT 内容并保存到本地文件
|
||||
- [slides +create](lark-slides-create.md) - Create a PPT / add slides
|
||||
- [slides +xml-get](lark-slides-xml-get.md) - Read PPT content and save it to a local file
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
# lark-slides xml_presentation.slide get
|
||||
|
||||
## 用途
|
||||
## Purpose
|
||||
|
||||
按 `slide_id` 拉取指定演示文稿单页的 XML 内容(可指定历史版本)。常用于"读-改-写"编辑闭环的第一步。
|
||||
Fetch the XML content of a single slide in a presentation by `slide_id` (a historical revision can be specified). Commonly used as the first step of the "read-modify-write" editing loop.
|
||||
|
||||
## 命令
|
||||
## Command
|
||||
|
||||
```bash
|
||||
lark-cli slides xml_presentation.slide get --as user --params '<json_params>'
|
||||
```
|
||||
|
||||
## 参数说明
|
||||
## Parameter Description
|
||||
|
||||
| 参数 | 类型 | 必需 | 说明 |
|
||||
| Parameter | Type | Required | Description |
|
||||
|------|------|------|------|
|
||||
| `--params` | JSON string | 是 | 路径参数与查询参数 |
|
||||
| `--params` | JSON string | Yes | Path and query parameters |
|
||||
|
||||
### params JSON 结构
|
||||
### params JSON Structure
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -26,15 +26,15 @@ lark-cli slides xml_presentation.slide get --as user --params '<json_params>'
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 必需 | 说明 |
|
||||
| Field | Type | Required | Description |
|
||||
|------|------|------|------|
|
||||
| `xml_presentation_id` | string | 是 | 目标演示文稿唯一标识 |
|
||||
| `slide_id` | string | 是 | 目标页面唯一标识 |
|
||||
| `revision_id` | integer | 否 | 版本号,`-1` 表示最新版(默认)|
|
||||
| `xml_presentation_id` | string | Yes | Unique identifier of the target presentation |
|
||||
| `slide_id` | string | Yes | Unique identifier of the target slide |
|
||||
| `revision_id` | integer | No | Revision number, `-1` means the latest revision (default) |
|
||||
|
||||
## 使用示例
|
||||
## Usage Examples
|
||||
|
||||
### 读最新版本
|
||||
### Read the Latest Revision
|
||||
|
||||
```bash
|
||||
lark-cli slides xml_presentation.slide get --as user --params '{
|
||||
@@ -43,7 +43,7 @@ lark-cli slides xml_presentation.slide get --as user --params '{
|
||||
}'
|
||||
```
|
||||
|
||||
### 只提取 XML 内容
|
||||
### Extract Only the XML Content
|
||||
|
||||
```bash
|
||||
lark-cli slides xml_presentation.slide get --as user \
|
||||
@@ -51,7 +51,7 @@ lark-cli slides xml_presentation.slide get --as user \
|
||||
| jq -r '.data.slide.content'
|
||||
```
|
||||
|
||||
### 读指定历史版本
|
||||
### Read a Specific Historical Revision
|
||||
|
||||
```bash
|
||||
lark-cli slides xml_presentation.slide get --as user --params '{
|
||||
@@ -61,7 +61,7 @@ lark-cli slides xml_presentation.slide get --as user --params '{
|
||||
}'
|
||||
```
|
||||
|
||||
## 返回值
|
||||
## Return Value
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -77,24 +77,24 @@ lark-cli slides xml_presentation.slide get --as user --params '{
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| Field | Type | Description |
|
||||
|------|------|------|
|
||||
| `data.slide.slide_id` | string | 页面唯一标识 |
|
||||
| `data.slide.content` | string | 页面完整 XML(`<slide>` 根节点,不含 xmlns)|
|
||||
| `data.revision_id` | integer | 此次读到的版本号,可用于后续 replace 的乐观锁 |
|
||||
| `data.slide.slide_id` | string | Unique identifier of the slide |
|
||||
| `data.slide.content` | string | Full slide XML (`<slide>` root node, without xmlns) |
|
||||
| `data.revision_id` | integer | Revision number returned by this read; can be used as an optimistic lock for a subsequent replace |
|
||||
|
||||
## 常见错误
|
||||
## Common Errors
|
||||
|
||||
| 错误码 | 含义 | 解决方案 |
|
||||
| Error Code | Meaning | Solution |
|
||||
|--------|------|----------|
|
||||
| 404 | 演示文稿或页面不存在 | 检查 `xml_presentation_id` / `slide_id` |
|
||||
| 403 | 权限不足 | 需要 `slides:presentation:read` scope,并对该 PPT 有访问权限 |
|
||||
| 400 | `revision_id` 不存在 | 传了无效版本号,用 `-1` 或真实存在的版本号 |
|
||||
| 404 | Presentation or slide does not exist | Check `xml_presentation_id` / `slide_id` |
|
||||
| 403 | Insufficient permissions | Requires the `slides:presentation:read` scope and access permission to the PPT |
|
||||
| 400 | `revision_id` does not exist | An invalid revision number was passed; use `-1` or a revision number that actually exists |
|
||||
|
||||
## 注意事项
|
||||
## Notes
|
||||
|
||||
1. **执行前必做**:`lark-cli schema slides.xml_presentation.slide.get` 查看最新参数结构
|
||||
2. **block_id 提取**:返回 XML 里每个顶层块(shape、img、table、chart、whiteboard 等)的 `id` 属性即为 `block_id`,通常是 3 字符短码,例如 `<shape id="bUn" ...>`。用以下命令列出当前页所有 block_id:
|
||||
1. **Do this before executing**: run `lark-cli schema slides.xml_presentation.slide.get` to check the latest parameter structure
|
||||
2. **block_id extraction**: in the returned XML, the `id` attribute of each top-level block (shape, img, table, chart, whiteboard, etc.) is the `block_id`, usually a 3-character short code, e.g. `<shape id="bUn" ...>`. Use the following command to list all block_ids on the current slide:
|
||||
|
||||
```bash
|
||||
lark-cli slides xml_presentation.slide get --as user \
|
||||
@@ -102,9 +102,9 @@ lark-cli slides xml_presentation.slide get --as user --params '{
|
||||
| jq -r '.data.slide.content' | grep -oE 'id="[^"]+"' | sed 's/id="//;s/"//'
|
||||
```
|
||||
|
||||
## 相关命令
|
||||
## Related Commands
|
||||
|
||||
- [slides +replace-slide](lark-slides-replace-slide.md) — 块级替换 shortcut(推荐)
|
||||
- [xml_presentation.slide replace](lark-slides-xml-presentation-slide-replace.md) — 底层 replace API 参考
|
||||
- [slides +xml-get](lark-slides-xml-get.md) — 读整个 PPT 并保存到本地文件
|
||||
- [lark-slides-edit-workflows.md](lark-slides-edit-workflows.md) — 读-改-写闭环
|
||||
- [slides +replace-slide](lark-slides-replace-slide.md) — Block-level replace shortcut (recommended)
|
||||
- [xml_presentation.slide replace](lark-slides-xml-presentation-slide-replace.md) — Underlying replace API reference
|
||||
- [slides +xml-get](lark-slides-xml-get.md) — Read the whole PPT and save it to a local file
|
||||
- [lark-slides-edit-workflows.md](lark-slides-edit-workflows.md) — Read-modify-write loop
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
# lark-slides xml_presentation.slide replace
|
||||
|
||||
## 用途
|
||||
## Purpose
|
||||
|
||||
对单页做**块级局部替换**:不覆盖整页,按 patch 列表做 `block_replace`(整块替换)或 `block_insert`(整块插入)。适合"只想加 / 换一个元素、不动其他元素"的场景。
|
||||
Performs **block-level partial replacement** on a single page: instead of overwriting the whole page, it applies a patch list of `block_replace` (replace a whole block) or `block_insert` (insert a whole block) operations. Suited to scenarios where you "only want to add / swap one element without touching the others".
|
||||
|
||||
> **推荐**:优先使用 [`+replace-slide`](lark-slides-replace-slide.md) Shortcut——它会自动注入 `id` 和 `<content/>`,直接调本 API 需自己处理这两个约束(见注意事项 5、6)。
|
||||
> **Recommended**: prefer the [`+replace-slide`](lark-slides-replace-slide.md) shortcut — it automatically injects `id` and `<content/>`. Calling this API directly means handling those two constraints yourself (see Notes 5 and 6).
|
||||
|
||||
## 命令
|
||||
## Command
|
||||
|
||||
```bash
|
||||
lark-cli slides xml_presentation.slide replace --as user --params '<json_params>' --data '<json_data>'
|
||||
```
|
||||
|
||||
## 参数说明
|
||||
## Parameter Description
|
||||
|
||||
| 参数 | 类型 | 必需 | 说明 |
|
||||
| Parameter | Type | Required | Description |
|
||||
|------|------|------|------|
|
||||
| `--params` | JSON string | 是 | 路径参数与查询参数 |
|
||||
| `--data` | JSON string | 是 | patch 列表 |
|
||||
| `--params` | JSON string | Yes | Path and query parameters |
|
||||
| `--data` | JSON string | Yes | Patch list |
|
||||
|
||||
### params JSON 结构
|
||||
### params JSON Structure
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -30,14 +30,14 @@ lark-cli slides xml_presentation.slide replace --as user --params '<json_params>
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 必需 | 说明 |
|
||||
| Field | Type | Required | Description |
|
||||
|------|------|------|------|
|
||||
| `xml_presentation_id` | string | 是 | 演示文稿唯一标识 |
|
||||
| `slide_id` | string | 是 | 页面唯一标识 |
|
||||
| `revision_id` | integer | 否 | 默认 `-1`(以最新版为基准);传具体版本号做乐观锁 |
|
||||
| `tid` | string | 否 | 事务 ID,一般留空 |
|
||||
| `xml_presentation_id` | string | Yes | Unique identifier of the presentation |
|
||||
| `slide_id` | string | Yes | Unique identifier of the page |
|
||||
| `revision_id` | integer | No | Defaults to `-1` (based on the latest revision); pass a specific revision number for optimistic locking |
|
||||
| `tid` | string | No | Transaction ID, usually left empty |
|
||||
|
||||
### data JSON 结构
|
||||
### data JSON Structure
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -48,33 +48,33 @@ lark-cli slides xml_presentation.slide replace --as user --params '<json_params>
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 必需 | 说明 |
|
||||
| Field | Type | Required | Description |
|
||||
|------|------|------|------|
|
||||
| `parts` | array | 是 | patch 列表,长度 1~200,顺序执行 |
|
||||
| `parts` | array | Yes | Patch list, length 1~200, executed in order |
|
||||
|
||||
### parts[] 字段(按 action 不同)
|
||||
### parts[] Fields (by action)
|
||||
|
||||
本期 CLI 文档化两种 action:
|
||||
Two actions are documented for the CLI in this release:
|
||||
|
||||
#### action = "block_replace" — 整块替换
|
||||
#### action = "block_replace" — Replace a Whole Block
|
||||
|
||||
| 字段 | 必填 | 说明 |
|
||||
| Field | Required | Description |
|
||||
|------|------|------|
|
||||
| `action` | 是 | 固定 `block_replace` |
|
||||
| `block_id` | 是 | 目标块的 3 位 short element ID(从 `slide.get` 返回的 XML 里读到) |
|
||||
| `replacement` | 是 | 新 XML 片段,替换整个目标块 |
|
||||
| `action` | Yes | Fixed value `block_replace` |
|
||||
| `block_id` | Yes | The 3-character short element ID of the target block (read from the XML returned by `slide.get`) |
|
||||
| `replacement` | Yes | New XML fragment that replaces the entire target block |
|
||||
|
||||
#### action = "block_insert" — 整块插入
|
||||
#### action = "block_insert" — Insert a Whole Block
|
||||
|
||||
| 字段 | 必填 | 说明 |
|
||||
| Field | Required | Description |
|
||||
|------|------|------|
|
||||
| `action` | 是 | 固定 `block_insert` |
|
||||
| `insertion` | 是 | 要插入的完整 XML 片段 |
|
||||
| `insert_before_block_id` | 否 | 插到这个块之前;省略则追加到页面末尾 |
|
||||
| `action` | Yes | Fixed value `block_insert` |
|
||||
| `insertion` | Yes | The complete XML fragment to insert |
|
||||
| `insert_before_block_id` | No | Insert before this block; if omitted, appends to the end of the page |
|
||||
|
||||
## 使用示例
|
||||
## Usage Examples
|
||||
|
||||
### block_replace:换一个 shape 的整体内容
|
||||
### block_replace: Replace the Entire Content of a Shape
|
||||
|
||||
```bash
|
||||
lark-cli slides xml_presentation.slide replace --as user --params '{
|
||||
@@ -85,16 +85,16 @@ lark-cli slides xml_presentation.slide replace --as user --params '{
|
||||
{
|
||||
"action": "block_replace",
|
||||
"block_id": "bab",
|
||||
"replacement": "<shape type=\"text\" topLeftX=\"80\" topLeftY=\"80\" width=\"800\" height=\"120\"><content textType=\"title\"><p>新标题</p></content></shape>"
|
||||
"replacement": "<shape type=\"text\" topLeftX=\"80\" topLeftY=\"80\" width=\"800\" height=\"120\"><content textType=\"title\"><p>New Title</p></content></shape>"
|
||||
}
|
||||
]
|
||||
}'
|
||||
```
|
||||
|
||||
### block_insert:在已有页上加一张图
|
||||
### block_insert: Add an Image to an Existing Page
|
||||
|
||||
```bash
|
||||
# 先拿 file_token
|
||||
# Get the file_token first
|
||||
TOKEN=$(lark-cli slides +media-upload --file ./pic.png --presentation "$PID" --as user | jq -r '.data.file_token')
|
||||
|
||||
lark-cli slides xml_presentation.slide replace --as user --params "{
|
||||
@@ -110,7 +110,7 @@ lark-cli slides xml_presentation.slide replace --as user --params "{
|
||||
}')"
|
||||
```
|
||||
|
||||
### 多条 parts 原子执行
|
||||
### Multiple parts Executed Atomically
|
||||
|
||||
```bash
|
||||
lark-cli slides xml_presentation.slide replace --as user --params '{
|
||||
@@ -118,15 +118,15 @@ lark-cli slides xml_presentation.slide replace --as user --params '{
|
||||
"slide_id": "slide_example_id"
|
||||
}' --data '{
|
||||
"parts": [
|
||||
{"action":"block_replace","block_id":"bab","replacement":"<shape type=\"text\" topLeftX=\"80\" topLeftY=\"80\" width=\"800\" height=\"120\"><content textType=\"title\"><p>新标题</p></content></shape>"},
|
||||
{"action":"block_replace","block_id":"bab","replacement":"<shape type=\"text\" topLeftX=\"80\" topLeftY=\"80\" width=\"800\" height=\"120\"><content textType=\"title\"><p>New Title</p></content></shape>"},
|
||||
{"action":"block_insert","insertion":"<img src=\"<file_token>\" topLeftX=\"700\" topLeftY=\"400\" width=\"180\" height=\"100\"/>"}
|
||||
]
|
||||
}'
|
||||
```
|
||||
|
||||
## 返回值
|
||||
## Return Value
|
||||
|
||||
### 成功
|
||||
### Success
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -138,9 +138,9 @@ lark-cli slides xml_presentation.slide replace --as user --params '{
|
||||
}
|
||||
```
|
||||
|
||||
### 失败(任一 part 失败,整批不生效)
|
||||
### Failure (if any part fails, the whole batch does not take effect)
|
||||
|
||||
失败时命令以非零退出码结束,stderr 返回类型化错误信封(`error.code`(如 3350001)/ `error.message` / `error.hint`),stdout 不会打印后端原始响应:
|
||||
On failure, the command exits with a non-zero exit code, and stderr returns a typed error envelope (`error.code` (e.g. 3350001) / `error.message` / `error.hint`); stdout does not print the raw backend response:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -156,34 +156,34 @@ lark-cli slides xml_presentation.slide replace --as user --params '{
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| Field | Type | Description |
|
||||
|------|------|------|
|
||||
| `data.revision_id` | integer | 成功时返回更新后最新版本号 |
|
||||
| `data.revision_id` | integer | On success, returns the updated latest revision number |
|
||||
|
||||
## 常见错误
|
||||
## Common Errors
|
||||
|
||||
| 错误码 | 含义 | 解决方案 |
|
||||
| Error Code | Meaning | Solution |
|
||||
|--------|------|----------|
|
||||
| 3350001 | `block_id` 在当前页不存在,或 XML 格式 / 结构错误 | 重新 `slide.get` 拿最新 XML,确认 `block_id` 存在;检查 `replacement` / `insertion` 是否合法 XML |
|
||||
| 400 | `parts` 长度超过 200 | 拆多次调用 |
|
||||
| 3350002 | `revision_id` 不存在(超过当前版本号) | 用 `-1` 或实际存在的 `revision_id` |
|
||||
| 400 | XML 格式错误 | `replacement` / `insertion` 必须为合法的 XML 片段,标签闭合 + 属性引号 |
|
||||
| 403 | 权限不足 | 需要 `slides:presentation:update` 或 `slides:presentation:write_only` |
|
||||
| 3350001 | `block_id` does not exist on the current page, or the XML format / structure is invalid | Re-run `slide.get` to fetch the latest XML and confirm the `block_id` exists; check that `replacement` / `insertion` is valid XML |
|
||||
| 400 | `parts` length exceeds 200 | Split into multiple calls |
|
||||
| 3350002 | `revision_id` does not exist (exceeds the current revision number) | Use `-1` or an actually existing `revision_id` |
|
||||
| 400 | Invalid XML format | `replacement` / `insertion` must be valid XML fragments, with closed tags and quoted attributes |
|
||||
| 403 | Insufficient permissions | Requires `slides:presentation:update` or `slides:presentation:write_only` |
|
||||
|
||||
## 注意事项
|
||||
## Notes
|
||||
|
||||
1. **parts 原子事务**:任一条失败整批回滚,不会出现"前几条成功、后几条失败"的中间态。
|
||||
2. **block_id 的获取**:`slide.get` 返回的 XML 里每个块(shape、img、table、chart、whiteboard 等)会带 3 位 short element ID,用这个值填 `block_id` / `insert_before_block_id`。
|
||||
3. **`<img>` 必须用 file_token**:不能用外链 URL——先 [`slides +media-upload`](lark-slides-media-upload.md) 拿 token。
|
||||
4. **不能字段级 patch**:要改一个块的某个属性(比如只改 `topLeftX`),得写整块新 XML 走 `block_replace`;API 不支持"只改一个字段"。
|
||||
5. **`block_replace` 要求 `replacement` 根元素带 `id="<block_id>"`**:底层 API 的硬约束,缺失会返回 3350001。推荐走 shortcut [`+replace-slide`](lark-slides-replace-slide.md)——它会自动把 `id` 注入到 `replacement` 根元素上,用户写 XML 时不用自己加。
|
||||
6. **`<shape>` 必须有 `<content/>` 子元素**:SML 2.0 schema 要求,缺失同样触发 3350001。shortcut [`+replace-slide`](lark-slides-replace-slide.md) 会自动注入 `<content/>`,直接调底层 API 需要自己加。
|
||||
7. **`<whiteboard>` 返回结构不含内部数据**:`slide.get` 返回的 whiteboard 块只有外层标签和位置属性,SVG / Mermaid 内容不会随 XML 一起返回。但 `block_replace` 仍然可以强行覆盖——直接写入完整新 whiteboard XML 即可。
|
||||
8. **执行前必做**:`lark-cli schema slides.xml_presentation.slide.replace` 查看最新参数结构。
|
||||
1. **parts is an atomic transaction**: if any single part fails, the whole batch is rolled back; there is no intermediate state where "the first few succeed and the rest fail".
|
||||
2. **Getting block_id**: in the XML returned by `slide.get`, every block (shape, img, table, chart, whiteboard, etc.) carries a 3-character short element ID; use that value for `block_id` / `insert_before_block_id`.
|
||||
3. **`<img>` must use a file_token**: external URLs are not allowed — get a token first via [`slides +media-upload`](lark-slides-media-upload.md).
|
||||
4. **No field-level patching**: to change one attribute of a block (e.g. only `topLeftX`), you must write the whole block's new XML and use `block_replace`; the API does not support "changing just one field".
|
||||
5. **`block_replace` requires the root element of `replacement` to carry `id="<block_id>"`**: this is a hard constraint of the underlying API; omitting it returns 3350001. The recommended path is the [`+replace-slide`](lark-slides-replace-slide.md) shortcut — it automatically injects the `id` into the root element of `replacement`, so users do not have to add it when writing XML.
|
||||
6. **`<shape>` must have a `<content/>` child element**: required by the SML 2.0 schema; omitting it also triggers 3350001. The [`+replace-slide`](lark-slides-replace-slide.md) shortcut injects `<content/>` automatically; calling the underlying API directly requires adding it yourself.
|
||||
7. **The returned `<whiteboard>` structure does not include internal data**: whiteboard blocks in the XML returned by `slide.get` only have the outer tag and position attributes; the SVG / Mermaid content is not returned with the XML. However, `block_replace` can still forcibly overwrite it — just write the complete new whiteboard XML.
|
||||
8. **Always do this before executing**: run `lark-cli schema slides.xml_presentation.slide.replace` to check the latest parameter structure.
|
||||
|
||||
## 相关命令
|
||||
## Related Commands
|
||||
|
||||
- [slides +replace-slide](lark-slides-replace-slide.md) — 块级替换 shortcut(推荐,自动注入 id)
|
||||
- [xml_presentation.slide get](lark-slides-xml-presentation-slide-get.md) — 读原页拿 block short ID
|
||||
- [slides +media-upload](lark-slides-media-upload.md) — 上传图片拿 file_token
|
||||
- [lark-slides-edit-workflows.md](lark-slides-edit-workflows.md) — 读-改-写闭环 + 决策树
|
||||
- [slides +replace-slide](lark-slides-replace-slide.md) — block-level replacement shortcut (recommended, auto-injects id)
|
||||
- [xml_presentation.slide get](lark-slides-xml-presentation-slide-get.md) — read the original page to get block short IDs
|
||||
- [slides +media-upload](lark-slides-media-upload.md) — upload images to get a file_token
|
||||
- [lark-slides-edit-workflows.md](lark-slides-edit-workflows.md) — read-modify-write loop + decision tree
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
# lark-slides xml_presentations get
|
||||
|
||||
## 用途
|
||||
## Purpose
|
||||
|
||||
读取飞书幻灯片(PPT)演示文稿的完整 XML 内容信息。
|
||||
Read the full XML content of a Feishu Slides (PPT) presentation.
|
||||
|
||||
## 底层原生命令形态
|
||||
## Underlying Native Command Form
|
||||
|
||||
```bash
|
||||
lark-cli slides xml_presentations get --as user --params '<json_params>'
|
||||
```
|
||||
|
||||
## 参数说明
|
||||
## Parameter Description
|
||||
|
||||
| 参数 | 类型 | 必需 | 说明 |
|
||||
| Parameter | Type | Required | Description |
|
||||
|------|------|------|------|
|
||||
| `--params` | JSON string | 是 | 路径参数与查询参数,结构以 schema 为准 |
|
||||
| `--params` | JSON string | Yes | Path and query parameters; the structure follows the schema |
|
||||
|
||||
### params JSON 结构
|
||||
### params JSON Structure
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -25,37 +25,37 @@ lark-cli slides xml_presentations get --as user --params '<json_params>'
|
||||
}
|
||||
```
|
||||
|
||||
| 字段 | 类型 | 必需 | 说明 |
|
||||
| Field | Type | Required | Description |
|
||||
|------|------|------|------|
|
||||
| `xml_presentation_id` | string | 是 | 演示文稿的唯一标识符 |
|
||||
| `revision_id` | integer | 否 | 版本号,`-1` 表示最新版本 |
|
||||
| `xml_presentation_id` | string | Yes | Unique identifier of the presentation |
|
||||
| `revision_id` | integer | No | Revision number, `-1` means the latest revision |
|
||||
|
||||
## 使用示例
|
||||
## Usage Examples
|
||||
|
||||
### 基础示例
|
||||
### Basic Example
|
||||
|
||||
```bash
|
||||
lark-cli slides xml_presentations get --as user \
|
||||
--params '{"xml_presentation_id":"slides_example_presentation_id","revision_id":-1}'
|
||||
```
|
||||
|
||||
### 指定版本读取
|
||||
### Read a Specific Revision
|
||||
|
||||
```bash
|
||||
lark-cli slides xml_presentations get --as user \
|
||||
--params '{"xml_presentation_id":"slides_example_presentation_id","revision_id":10}'
|
||||
```
|
||||
|
||||
### 移除 XML id 属性后读取
|
||||
### Read with XML id Attributes Removed
|
||||
|
||||
```bash
|
||||
lark-cli slides xml_presentations get --as user \
|
||||
--params '{"xml_presentation_id":"slides_example_presentation_id","revision_id":-1,"remove_attr_id":true}'
|
||||
```
|
||||
|
||||
## 返回值
|
||||
## Return Value
|
||||
|
||||
成功时返回演示文稿的完整信息:
|
||||
On success, returns the full presentation information:
|
||||
|
||||
```json
|
||||
{
|
||||
@@ -71,29 +71,29 @@ lark-cli slides xml_presentations get --as user \
|
||||
}
|
||||
```
|
||||
|
||||
### 返回字段说明
|
||||
### Return Field Description
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
| Field | Type | Description |
|
||||
|------|------|------|
|
||||
| `data.xml_presentation.presentation_id` | string | 演示文稿唯一标识 |
|
||||
| `data.xml_presentation.revision_id` | integer | 版本号 |
|
||||
| `data.xml_presentation.content` | string | XML 格式的完整内容 |
|
||||
| `data.xml_presentation.presentation_id` | string | Unique identifier of the presentation |
|
||||
| `data.xml_presentation.revision_id` | integer | Revision number |
|
||||
| `data.xml_presentation.content` | string | Full content in XML format |
|
||||
|
||||
## 常见错误
|
||||
## Common Errors
|
||||
|
||||
| 错误码 | 含义 | 解决方案 |
|
||||
| Error Code | Meaning | Solution |
|
||||
|--------|------|----------|
|
||||
| 404 | 演示文稿不存在 | 检查 `xml_presentation_id` 是否正确 |
|
||||
| 403 | 权限不足 | 检查是否拥有 `slides:presentation:read` scope,或是否有访问权限 |
|
||||
| 400 | 参数格式错误 | 确保 `--params` 是合法的 JSON 字符串 |
|
||||
| 404 | Presentation does not exist | Check whether `xml_presentation_id` is correct |
|
||||
| 403 | Insufficient permissions | Check whether you have the `slides:presentation:read` scope, or whether you have access permission |
|
||||
| 400 | Malformed parameters | Make sure `--params` is a valid JSON string |
|
||||
|
||||
## 注意事项
|
||||
## Notes
|
||||
|
||||
1. 直接调用底层 API 前,使用 `lark-cli schema slides.xml_presentations.get` 查看最新的参数结构
|
||||
2. 返回的 XML 在 `data.xml_presentation.content` 字段中
|
||||
3. 如果只需要部分信息,可以使用 `jq` 等工具过滤返回结果
|
||||
1. Before calling the underlying API directly, use `lark-cli schema slides.xml_presentations.get` to check the latest parameter structure
|
||||
2. The returned XML is in the `data.xml_presentation.content` field
|
||||
3. If you only need part of the information, you can filter the result with tools like `jq`
|
||||
|
||||
## 相关命令
|
||||
## Related Commands
|
||||
|
||||
- [slides +create](lark-slides-create.md) - 创建 PPT / 添加幻灯片页面
|
||||
- [xml_presentation.slide delete](lark-slides-xml-presentation-slide-delete.md) - 删除幻灯片页面
|
||||
- [slides +create](lark-slides-create.md) - Create a PPT / add slides
|
||||
- [xml_presentation.slide delete](lark-slides-xml-presentation-slide-delete.md) - Delete a slide
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
# Planning Layer
|
||||
|
||||
新建演示文稿或大幅改写页面时,必须先写 `.lark-slides/plan/<deck-or-task-id>/slide_plan.json`,再生成 XML。这个文件是 deck 的设计中间层,用来把叙事、页面角色、布局、视觉重点和文字密度固定下来,避免从用户提示直接跳到 XML。
|
||||
When creating a new presentation or substantially rewriting pages, you must first write `.lark-slides/plan/<deck-or-task-id>/slide_plan.json`, then generate XML. This file is the deck's design intermediate layer; it pins down narrative, page roles, layout, visual focus, and text density so the agent does not jump straight from the user prompt to XML.
|
||||
|
||||
小型已有页编辑可豁免,例如只替换一个标题、改一个数字、插入一个块、上传并插入一张图。只要任务会重排多页、生成新 deck、替换整页结构,仍然需要规划层。
|
||||
Small edits to existing pages are exempt, for example replacing a single title, changing one number, inserting one block, or uploading and inserting one image. Any task that reorders multiple pages, generates a new deck, or replaces whole-page structure still requires the planning layer.
|
||||
|
||||
## Required Flow
|
||||
|
||||
1. 理解用户需求,必要时澄清主题、受众、页数、风格。
|
||||
2. 选择唯一 plan 目录:`.lark-slides/plan/<deck-or-task-id>/`。
|
||||
3. 先创建目录:`mkdir -p .lark-slides/plan/<deck-or-task-id>`。
|
||||
4. 写入 `.lark-slides/plan/<deck-or-task-id>/slide_plan.json`。
|
||||
5. 读取 `xml-schema-quick-ref.md`、`visual-planning.md` 和 `asset-planning.md`。
|
||||
6. 按 plan、visual planning 和 asset planning 规则逐页生成 XML,把 `layout_type`、`visual_focus`、`text_density` 转成具体页面几何和文本量约束,并把缺失素材转成可执行兜底视觉。
|
||||
7. 创建 PPT 后用 `slides +xml-get` 回读,核对页面数量、关键元素和 plan 到 XML 的对应关系。
|
||||
1. Understand the user's needs; clarify topic, audience, page count, and style when necessary.
|
||||
2. Choose a unique plan directory: `.lark-slides/plan/<deck-or-task-id>/`.
|
||||
3. Create the directory first: `mkdir -p .lark-slides/plan/<deck-or-task-id>`.
|
||||
4. Write `.lark-slides/plan/<deck-or-task-id>/slide_plan.json`.
|
||||
5. Read `xml-schema-quick-ref.md`, `visual-planning.md`, and `asset-planning.md`.
|
||||
6. Generate XML page by page following the plan, visual planning, and asset planning rules: turn `layout_type`, `visual_focus`, and `text_density` into concrete page geometry and text-volume constraints, and turn missing assets into executable fallback visuals.
|
||||
7. After creating the presentation, fetch it back with `slides +xml-get` and verify page count, key elements, and the plan-to-XML correspondence.
|
||||
|
||||
## Plan Path
|
||||
|
||||
@@ -219,7 +219,7 @@ Good examples:
|
||||
|
||||
- `{"asset_type":"architecture_diagram","purpose":"Explain component relationships.","suggested_query":"service architecture diagram","fallback_if_missing":"Draw a component diagram with grouped boxes, connector arrows, and short labels."}`
|
||||
- `{"asset_type":"logo","purpose":"Identify the customer context.","suggested_query":"customer logo","fallback_if_missing":"Use a text label in a small badge."}`
|
||||
- `{"asset_type":"chart","purpose":"Show adoption trend.","suggested_query":"monthly adoption trend chart","fallback_if_missing":"Render a native `<chart>` using the provided series when available; otherwise render a native `<chart>` with mock placeholder values and label it as 模拟数据,仅占位,待替换真实数据."}`
|
||||
- `{"asset_type":"chart","purpose":"Show adoption trend.","suggested_query":"monthly adoption trend chart","fallback_if_missing":"Render a native `<chart>` using the provided series when available; otherwise render a native `<chart>` with mock placeholder values and label it as Mock data, placeholder only, to be replaced with real data."}`
|
||||
|
||||
## XML Generation Contract
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Slide XML 模板
|
||||
# Slide XML Template
|
||||
|
||||
可直接复制使用的 slide XML 模板。纯文本/形状模板可使用 `jq` 包装后传给 `xml_presentation.slide.create`:
|
||||
The slide XML template can be copied directly for use. Plain text/shape templates can be wrapped using `jq` and passed to `xml_presentation.slide.create`:
|
||||
|
||||
```bash
|
||||
lark-cli slides xml_presentation.slide create --as user \
|
||||
@@ -8,28 +8,28 @@ lark-cli slides xml_presentation.slide create --as user \
|
||||
--data "$(jq -n --arg content 'PASTE_XML_HERE' '{slide:{content:$content}}')"
|
||||
```
|
||||
|
||||
> **带图模板不要直接按上面的命令提交。** 新建 PPT 时可在 `+create --slides` 中使用 `src="@./local.png"`,CLI 会自动上传并替换为 `file_token`;给已有 PPT 添加或修改图片时,必须先用 `slides +media-upload` 拿到 `file_token`,再写进 `<img src="...">`。
|
||||
> **Do not submit templates with pictures directly according to the above command. ** When creating a new PPT, you can use `src="@./local.png"` in `+create --slides`, and the CLI will automatically upload and replace it with `file_token`; when adding or modifying images to an existing PPT, you must first use `slides +media-upload` to get the `file_token`, and then write it into `<img src="...">`.
|
||||
|
||||
## 深色封面页
|
||||
## Dark cover page
|
||||
|
||||
```xml
|
||||
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
||||
<style><fill><fillColor color="linear-gradient(135deg,rgba(15,23,42,1) 0%,rgba(56,97,140,1) 100%)"/></fill></style>
|
||||
<data>
|
||||
<shape type="text" topLeftX="80" topLeftY="160" width="800" height="70">
|
||||
<content><p textAlign="center"><strong><span color="rgb(255,255,255)" fontSize="44">主标题</span></strong></p></content>
|
||||
<content><p textAlign="center"><strong><span color="rgb(255,255,255)" fontSize="44">Main title</span></strong></p></content>
|
||||
</shape>
|
||||
<shape type="text" topLeftX="80" topLeftY="250" width="800" height="35">
|
||||
<content><p textAlign="center"><span color="rgb(148,163,184)" fontSize="20">副标题</span></p></content>
|
||||
<content><p textAlign="center"><span color="rgb(148,163,184)" fontSize="20">Subtitle</span></p></content>
|
||||
</shape>
|
||||
<shape type="text" topLeftX="80" topLeftY="420" width="800" height="25">
|
||||
<content><p textAlign="center"><span color="rgb(100,116,139)" fontSize="14">底部信息</span></p></content>
|
||||
<content><p textAlign="center"><span color="rgb(100,116,139)" fontSize="14">Bottom information</span></p></content>
|
||||
</shape>
|
||||
</data>
|
||||
</slide>
|
||||
```
|
||||
|
||||
## 浅色内容页
|
||||
## Light content page
|
||||
|
||||
```xml
|
||||
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
||||
@@ -39,15 +39,15 @@ lark-cli slides xml_presentation.slide create --as user \
|
||||
<fill><fillColor color="rgb(59,130,246)"/></fill>
|
||||
</shape>
|
||||
<shape type="text" topLeftX="76" topLeftY="36" width="600" height="45">
|
||||
<content><p><strong><span color="rgb(15,23,42)" fontSize="28">页面标题</span></strong></p></content>
|
||||
<content><p><strong><span color="rgb(15,23,42)" fontSize="28">Page title</span></strong></p></content>
|
||||
</shape>
|
||||
<shape type="text" topLeftX="60" topLeftY="100" width="840" height="380">
|
||||
<content textType="body" lineSpacing="multiple:1.8">
|
||||
<p><span color="rgb(51,65,85)" fontSize="15">正文段落</span></p>
|
||||
<p><span color="rgb(51,65,85)" fontSize="15">Text paragraph</span></p>
|
||||
<ul>
|
||||
<li><p><span color="rgb(51,65,85)" fontSize="15">要点一</span></p></li>
|
||||
<li><p><span color="rgb(51,65,85)" fontSize="15">要点二</span></p></li>
|
||||
<li><p><span color="rgb(51,65,85)" fontSize="15">要点三</span></p></li>
|
||||
<li><p><span color="rgb(51,65,85)" fontSize="15">Point 1</span></p></li>
|
||||
<li><p><span color="rgb(51,65,85)" fontSize="15">Point 2</span></p></li>
|
||||
<li><p><span color="rgb(51,65,85)" fontSize="15">Point 3</span></p></li>
|
||||
</ul>
|
||||
</content>
|
||||
</shape>
|
||||
@@ -55,125 +55,125 @@ lark-cli slides xml_presentation.slide create --as user \
|
||||
</slide>
|
||||
```
|
||||
|
||||
## 数据卡片页(横排指标)
|
||||
## Data card page (horizontal indicators)
|
||||
|
||||
```xml
|
||||
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
||||
<style><fill><fillColor color="rgb(248,250,252)"/></fill></style>
|
||||
<data>
|
||||
<shape type="text" topLeftX="60" topLeftY="36" width="600" height="45">
|
||||
<content><p><strong><span color="rgb(15,23,42)" fontSize="28">数据概览</span></strong></p></content>
|
||||
<content><p><strong><span color="rgb(15,23,42)" fontSize="28">Data Overview</span></strong></p></content>
|
||||
</shape>
|
||||
<!-- 卡片 1 -->
|
||||
<!-- Card 1 -->
|
||||
<shape type="rect" topLeftX="60" topLeftY="100" width="260" height="140">
|
||||
<fill><fillColor color="rgb(255,255,255)"/></fill>
|
||||
<border color="rgba(0,0,0,0.08)" width="1"/>
|
||||
</shape>
|
||||
<shape type="text" topLeftX="60" topLeftY="115" width="260" height="50">
|
||||
<content><p textAlign="center"><strong><span color="rgb(59,130,246)" fontSize="36">数值</span></strong></p></content>
|
||||
<content><p textAlign="center"><strong><span color="rgb(59,130,246)" fontSize="36">Value</span></strong></p></content>
|
||||
</shape>
|
||||
<shape type="text" topLeftX="60" topLeftY="175" width="260" height="25">
|
||||
<content><p textAlign="center"><span color="rgb(100,116,139)" fontSize="14">指标名称</span></p></content>
|
||||
<content><p textAlign="center"><span color="rgb(100,116,139)" fontSize="14">Indicator name</span></p></content>
|
||||
</shape>
|
||||
<!-- 卡片 2:topLeftX="350" -->
|
||||
<!-- 卡片 3:topLeftX="640" -->
|
||||
<!-- Card 2: topLeftX="350" -->
|
||||
<!-- Card 3: topLeftX="640" -->
|
||||
</data>
|
||||
</slide>
|
||||
```
|
||||
|
||||
## 带图版式
|
||||
## Format with pictures
|
||||
|
||||
> **关键提醒**:`<img>` 的 `width:height` = 原图比例时才不会被裁剪。每个模板都标注了图框比例和建议原图比例,**选模板前先对照你的素材比例**,不要硬塞(如把横图放进竖框,会被左右裁掉大半)。把 `@./your-image.jpg` 替换为实际路径(仅 `+create --slides` 支持 `@` 占位符;其他场景需先用 `slides +media-upload` 拿 `file_token`)。
|
||||
> **Key reminder**: `<img>` will not be cropped if its `width:height` = the proportion of the original image. Each template is marked with the proportion of the picture frame and the recommended ratio of the original picture. **Check the proportions of your material before choosing a template**, and don't force it (if you put a horizontal picture into a vertical frame, most of it will be cropped off left and right). Replace `@./your-image.jpg` with the actual path (only `+create --slides` supports the `@` placeholder; in other scenarios, you need to use `slides +media-upload` to get `file_token` first).
|
||||
|
||||
### 封面右图(左字右图)
|
||||
### Right picture on the cover (left picture on the right)
|
||||
|
||||
图框 400×225(**16:9**),建议原图:横幅 16:9(桌面壁纸、产品 banner、landscape 照片)
|
||||
Picture frame 400×225 (**16:9**), recommended original picture: banner 16:9 (desktop wallpaper, product banner, landscape photo)
|
||||
|
||||
```xml
|
||||
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
||||
<style><fill><fillColor color="linear-gradient(135deg,rgba(15,23,42,1) 0%,rgba(56,97,140,1) 100%)"/></fill></style>
|
||||
<data>
|
||||
<shape type="text" topLeftX="60" topLeftY="180" width="450" height="80">
|
||||
<content><p><strong><span color="rgb(255,255,255)" fontSize="44">主标题</span></strong></p></content>
|
||||
<content><p><strong><span color="rgb(255,255,255)" fontSize="44">Main title</span></strong></p></content>
|
||||
</shape>
|
||||
<shape type="text" topLeftX="60" topLeftY="270" width="450" height="40">
|
||||
<content><p><span color="rgb(186,230,253)" fontSize="20">副标题</span></p></content>
|
||||
<content><p><span color="rgb(186,230,253)" fontSize="20">Subtitle</span></p></content>
|
||||
</shape>
|
||||
<line startX="60" startY="350" endX="180" endY="350">
|
||||
<border color="rgb(59,130,246)" width="3"/>
|
||||
</line>
|
||||
<shape type="text" topLeftX="60" topLeftY="370" width="450" height="30">
|
||||
<content><p><span color="rgb(203,213,225)" fontSize="13">底部信息</span></p></content>
|
||||
<content><p><span color="rgb(203,213,225)" fontSize="13">Bottom information</span></p></content>
|
||||
</shape>
|
||||
<!-- 图框 400×225 = 16:9;原图建议 16:9 横幅 -->
|
||||
<!-- Picture frame 400×225 = 16:9; original picture recommends 16:9 banner -->
|
||||
<img src="@./your-landscape.jpg" topLeftX="540" topLeftY="157" width="400" height="225"/>
|
||||
</data>
|
||||
</slide>
|
||||
```
|
||||
|
||||
### 三卡片带图(上图下文)
|
||||
### Three cards with pictures (above and below)
|
||||
|
||||
每个图框 240×180(**4:3**),建议原图:4:3 或接近正方形的图(产品照、截图、icon 类)
|
||||
Each picture frame is 240×180 (**4:3**). It is recommended that the original picture be: 4:3 or close to a square picture (product photos, screenshots, icons)
|
||||
|
||||
```xml
|
||||
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
||||
<style><fill><fillColor color="rgb(248,250,252)"/></fill></style>
|
||||
<data>
|
||||
<shape type="text" topLeftX="60" topLeftY="40" width="600" height="45">
|
||||
<content><p><strong><span color="rgb(15,23,42)" fontSize="28">核心亮点</span></strong></p></content>
|
||||
<content><p><strong><span color="rgb(15,23,42)" fontSize="28">Core Highlights</span></strong></p></content>
|
||||
</shape>
|
||||
<line startX="60" startY="95" endX="140" endY="95">
|
||||
<border color="rgb(59,130,246)" width="3"/>
|
||||
</line>
|
||||
|
||||
<!-- 卡片 1 -->
|
||||
<!-- Card 1 -->
|
||||
<shape type="rect" topLeftX="60" topLeftY="130" width="270" height="360">
|
||||
<fill><fillColor color="rgb(255,255,255)"/></fill>
|
||||
<border color="rgba(0,0,0,0.08)" width="1"/>
|
||||
</shape>
|
||||
<!-- 图框 240×180 = 4:3;原图建议 4:3 -->
|
||||
<!-- Picture frame 240×180 = 4:3; original picture recommended 4:3 -->
|
||||
<img src="@./your-image-1.jpg" topLeftX="75" topLeftY="150" width="240" height="180"/>
|
||||
<shape type="text" topLeftX="75" topLeftY="345" width="240" height="30">
|
||||
<content><p><strong><span color="rgb(15,23,42)" fontSize="18">特性一</span></strong></p></content>
|
||||
<content><p><strong><span color="rgb(15,23,42)" fontSize="18">Feature 1</span></strong></p></content>
|
||||
</shape>
|
||||
<shape type="text" topLeftX="75" topLeftY="380" width="240" height="90">
|
||||
<content><p><span color="rgb(71,85,105)" fontSize="14">简短描述文案,控制在两行以内。</span></p></content>
|
||||
<content><p><span color="rgb(71,85,105)" fontSize="14">Short description copy, controlled within two lines. </span></p></content>
|
||||
</shape>
|
||||
|
||||
<!-- 卡片 2:复制卡片 1,shape/img 的 topLeftX 改为 345 / 360 -->
|
||||
<!-- 卡片 3:复制卡片 1,shape/img 的 topLeftX 改为 630 / 645 -->
|
||||
<!-- Card 2: Copy card 1, change topLeftX of shape/img to 345 / 360 -->
|
||||
<!-- Card 3: Copy card 1, change topLeftX of shape/img to 630 / 645 -->
|
||||
</data>
|
||||
</slide>
|
||||
```
|
||||
|
||||
### 左右分栏(图在左,文在右)
|
||||
### Left and right columns (picture on the left, text on the right)
|
||||
|
||||
图框 360×540(**2:3 竖幅**),建议原图:2:3 或 3:4 竖幅(人像照、产品竖拍、海报)
|
||||
Picture frame 360×540 (**2:3 vertical**), it is recommended that the original image: 2:3 or 3:4 vertical (portraits, product vertical shots, posters)
|
||||
|
||||
> 如果你只有横幅图,不要硬塞进这个竖框 —— 改用"顶部横幅图 + 下方文字"的版式(把这里的图框改成 960×240 横条放在顶部)。
|
||||
> If you only have a banner image, don’t shoehorn it into this vertical frame – use a “top banner + text below” layout instead (change the frame here to a 960×240 horizontal bar at the top).
|
||||
|
||||
```xml
|
||||
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
||||
<style><fill><fillColor color="rgb(255,255,255)"/></fill></style>
|
||||
<data>
|
||||
<!-- 图框 360×540 = 2:3;原图建议 2:3 或 3:4 竖幅 -->
|
||||
<!-- Picture frame 360×540 = 2:3; the original picture is recommended to be 2:3 or 3:4 vertical -->
|
||||
<img src="@./your-portrait.jpg" topLeftX="0" topLeftY="0" width="360" height="540"/>
|
||||
|
||||
<shape type="text" topLeftX="410" topLeftY="80" width="490" height="50">
|
||||
<content><p><strong><span color="rgb(15,23,42)" fontSize="30">场景标题</span></strong></p></content>
|
||||
<content><p><strong><span color="rgb(15,23,42)" fontSize="30">Scene title</span></strong></p></content>
|
||||
</shape>
|
||||
<line startX="410" startY="140" endX="490" endY="140">
|
||||
<border color="rgb(59,130,246)" width="3"/>
|
||||
</line>
|
||||
<shape type="text" topLeftX="410" topLeftY="160" width="490" height="50">
|
||||
<content><p><span color="rgb(71,85,105)" fontSize="16">一句话描述这个场景的价值。</span></p></content>
|
||||
<content><p><span color="rgb(71,85,105)" fontSize="16">Describe the value of this scene in one sentence. </span></p></content>
|
||||
</shape>
|
||||
<shape type="text" topLeftX="410" topLeftY="230" width="490" height="250">
|
||||
<content textType="body" lineSpacing="multiple:1.8">
|
||||
<ul>
|
||||
<li><p><span color="rgb(51,65,85)" fontSize="15">要点一</span></p></li>
|
||||
<li><p><span color="rgb(51,65,85)" fontSize="15">要点二</span></p></li>
|
||||
<li><p><span color="rgb(51,65,85)" fontSize="15">要点三</span></p></li>
|
||||
<li><p><span color="rgb(51,65,85)" fontSize="15">Point 1</span></p></li>
|
||||
<li><p><span color="rgb(51,65,85)" fontSize="15">Point 2</span></p></li>
|
||||
<li><p><span color="rgb(51,65,85)" fontSize="15">Point 3</span></p></li>
|
||||
</ul>
|
||||
</content>
|
||||
</shape>
|
||||
@@ -181,20 +181,20 @@ lark-cli slides xml_presentation.slide create --as user \
|
||||
</slide>
|
||||
```
|
||||
|
||||
## 深色结尾页
|
||||
## Dark end page
|
||||
|
||||
```xml
|
||||
<slide xmlns="http://www.larkoffice.com/sml/2.0">
|
||||
<style><fill><fillColor color="linear-gradient(135deg,rgba(15,23,42,1) 0%,rgba(56,97,140,1) 100%)"/></fill></style>
|
||||
<data>
|
||||
<shape type="text" topLeftX="80" topLeftY="190" width="800" height="55">
|
||||
<content><p textAlign="center"><strong><span color="rgb(255,255,255)" fontSize="36">感谢语或行动号召</span></strong></p></content>
|
||||
<content><p textAlign="center"><strong><span color="rgb(255,255,255)" fontSize="36">Thank you or call to action</span></strong></p></content>
|
||||
</shape>
|
||||
<line startX="410" startY="260" endX="550" endY="260">
|
||||
<border color="rgb(59,130,246)" width="2"/>
|
||||
</line>
|
||||
<shape type="text" topLeftX="80" topLeftY="280" width="800" height="30">
|
||||
<content><p textAlign="center"><span color="rgb(148,163,184)" fontSize="16">补充说明</span></p></content>
|
||||
<content><p textAlign="center"><span color="rgb(148,163,184)" fontSize="16">Supplementary instructions</span></p></content>
|
||||
</shape>
|
||||
</data>
|
||||
</slide>
|
||||
|
||||
@@ -1,45 +1,45 @@
|
||||
# Troubleshooting
|
||||
|
||||
本文件覆盖 lark-slides 的 XML 排障和常见失败处理。
|
||||
This file covers XML troubleshooting and common failure handling for lark-slides.
|
||||
|
||||
## Failure Order
|
||||
|
||||
遇到 `invalid param`、某一页创建失败、页面空白或布局错乱时,按顺序处理:
|
||||
When you hit `invalid param`, a page fails to create, a page is blank, or the layout is broken, handle it in order:
|
||||
|
||||
1. 先判断是否已有可用的 `xml_presentation_id`:从成功 stdout、错误 hint、用户给定链接或已保存上下文中获取;没有 ID 时不要回读,直接按当前错误处理。
|
||||
2. 如果有 `xml_presentation_id`,再用 `slides +xml-get` 尝试回读,确认是否存在演示文稿、是否已有部分页面写入、或是否只是空 presentation。
|
||||
3. 检查失败页是否含未转义字符:`Q&A -> Q&A`,文本 `<` / `>` 写成 `<` / `>`,属性 URL `a=1&b=2 -> a=1&b=2`。
|
||||
4. 检查标签闭合、属性引号、`<content>` 结构,以及 `<slide>` 直接子元素。
|
||||
5. 如果使用 `--slides '[...]'`,怀疑 shell 截断时直接切到两步创建:先 `slides +create`,再用 `xml_presentation.slide create` 逐页添加。
|
||||
1. First determine whether a usable `xml_presentation_id` already exists: get it from a successful stdout, an error hint, a user-provided link, or saved context; without an ID, do not read back — handle the current error directly.
|
||||
2. If you have an `xml_presentation_id`, try reading back with `slides +xml-get` to confirm whether the presentation exists, whether some pages were partially written, or whether it is just an empty presentation.
|
||||
3. Check whether the failing page contains unescaped characters: `Q&A -> Q&A`, textual `<` / `>` written as `<` / `>`, attribute URLs `a=1&b=2 -> a=1&b=2`.
|
||||
4. Check tag closure, attribute quoting, `<content>` structure, and the direct children of `<slide>`.
|
||||
5. If using `--slides '[...]'` and you suspect shell truncation, switch directly to two-step creation: `slides +create` first, then add pages one by one with `xml_presentation.slide create`.
|
||||
|
||||
## Symptom Fixes
|
||||
|
||||
| 看到的问题 | 处理方式 |
|
||||
| Observed problem | Fix |
|
||||
|-----------|----------|
|
||||
| 文字被截断 / 看不全 | 增大 shape 的 `width` 或 `height`,或减少文本量 |
|
||||
| 元素重叠 | 调整 `topLeftX` / `topLeftY`,拉开间距 |
|
||||
| 页面大面积空白 | 回读确认内容是否写入;若内容存在,再缩小间距或增加主体元素 |
|
||||
| 文字和背景色太接近 | 深色背景用浅色文字,浅色背景用深色文字 |
|
||||
| 表格列宽不合理 | 调整 `colgroup` 中 `col` 的 `width` 值 |
|
||||
| 图表没有显示 | 检查 `chartPlotArea` 和 `chartData` 是否都包含,`dim1` / `dim2` 数据数量是否匹配 |
|
||||
| 图片被裁掉一部分 | `<img>` 的 `width` / `height` 是裁剪后尺寸;要整图显示就让 `width:height` 对齐原图比例 |
|
||||
| 图片不显示 / `<img src>` 仍是 `@path` | `@` 占位符只在 `+create --slides` 中替换;直接调 `xml_presentation.slide create` 必须先用 `+media-upload` 拿 `file_token` |
|
||||
| 新插入的 `<img>` 挡住原有元素 | `slide.get` 读原页,对照已有块坐标挑空白位置;空间不够就在同一批 `--parts` 里先移动/缩小现有块再插图 |
|
||||
| 渐变背景变成白色 | 渐变必须用 `rgba()` 格式 + 百分比停靠点,如 `linear-gradient(135deg,rgba(30,60,114,1) 0%,rgba(59,130,246,1) 100%)` |
|
||||
| Text truncated / not fully visible | Increase the shape's `width` or `height`, or reduce the amount of text |
|
||||
| Elements overlap | Adjust `topLeftX` / `topLeftY` to open up spacing |
|
||||
| Large blank areas on the page | Read back to confirm content was written; if content exists, tighten spacing or add primary elements |
|
||||
| Text color too close to background | Use light text on dark backgrounds, dark text on light backgrounds |
|
||||
| Unreasonable table column widths | Adjust the `width` values of `col` in `colgroup` |
|
||||
| Chart not displayed | Check that both `chartPlotArea` and `chartData` are present, and that `dim1` / `dim2` data counts match |
|
||||
| Image partially cropped | The `<img>` `width` / `height` are post-crop dimensions; to show the full image, match `width:height` to the original aspect ratio |
|
||||
| Image not displayed / `<img src>` is still `@path` | The `@` placeholder is only substituted in `+create --slides`; direct `xml_presentation.slide create` calls must first obtain a `file_token` via `+media-upload` |
|
||||
| Newly inserted `<img>` covers existing elements | Read the original page with `slide.get`, pick an empty spot against existing block coordinates; if space is tight, move/shrink existing blocks in the same `--parts` batch before inserting the image |
|
||||
| Gradient background turns white | Gradients must use the `rgba()` format + percentage stops, e.g. `linear-gradient(135deg,rgba(30,60,114,1) 0%,rgba(59,130,246,1) 100%)` |
|
||||
|
||||
## Common Errors
|
||||
|
||||
| 错误码 / 信号 | 含义 | 解决方案 |
|
||||
| Error code / signal | Meaning | Solution |
|
||||
|--------------|------|----------|
|
||||
| 400 XML 格式错误 | XML 语法错误 | 检查标签闭合、属性引号、特殊字符转义 |
|
||||
| 400 请求包装错误 | `--data` 未按 schema 包装 | 检查是否传入 `xml_presentation.content` 或 `slide.content` |
|
||||
| 创建成功但页面空白 / 内容缺失 / 布局错乱 | 常见于 `--slides '[...]'` 的 shell 转义或长参数传递问题 | 改用两步创建,并在创建后立即读取 XML 验证 |
|
||||
| 403 权限不足 | 身份或 scope 不匹配 | 先检查是否误用了 bot 身份,再确认 scope 和文档权限;无权限时根据错误响应引导用户解决 |
|
||||
| 404 演示文稿不存在 | `xml_presentation_id` 不正确或无权限 | 检查 token;wiki URL 需先解析真实 `obj_token` |
|
||||
| 404 幻灯片不存在 | `slide_id` 不正确 | 重新读取 presentation 或 slide,确认最新 ID |
|
||||
| 400 无法删除唯一幻灯片 | 演示文稿至少保留一页 | 先创建新页,再删除旧页 |
|
||||
| 1061002 媒体上传 params error | slides 媒体上传参数不符合约定 | 用 `slides +media-upload`,不要手拼原生 `medias/upload_all`;slides 唯一可用 `parent_type` 是 `slide_file` |
|
||||
| 1061004 forbidden | 当前身份对演示文稿无编辑权限 | 确认 user/bot 对目标 PPT 有编辑权限;bot 常见于 PPT 非该 bot 创建 |
|
||||
| 3350001 | XML 非 well-formed、XML 结构不符合服务端要求,或 replace 片段问题 | 优先检查未转义字符;replace 场景再看 `block_id` 和 `<content/>` |
|
||||
| 3350002 | `revision_id` 大于当前版本 | 用 `-1` 取当前版本,或重新用 `slides +xml-get` 取最新 `revision_id` |
|
||||
| validation: unsafe file path | `--file` 给了绝对路径或上层路径 | `--file` 必须是 CWD 内相对路径;先 `cd` 到素材目录再执行 |
|
||||
| 400 XML format error | XML syntax error | Check tag closure, attribute quoting, special-character escaping |
|
||||
| 400 request wrapping error | `--data` not wrapped per schema | Check whether `xml_presentation.content` or `slide.content` was passed |
|
||||
| Creation succeeded but pages blank / content missing / layout broken | Typically shell escaping or long-argument issues with `--slides '[...]'` | Switch to two-step creation, and read the XML immediately after creation to verify |
|
||||
| 403 insufficient permission | Identity or scope mismatch | First check whether the bot identity was used by mistake, then confirm scopes and document permissions; when unauthorized, guide the user per the error response |
|
||||
| 404 presentation not found | `xml_presentation_id` incorrect or no permission | Check the token; wiki URLs must first be resolved to the real `obj_token` |
|
||||
| 404 slide not found | `slide_id` incorrect | Re-read the presentation or slide to confirm the latest ID |
|
||||
| 400 cannot delete the only slide | The presentation must keep at least one page | Create the new page first, then delete the old one |
|
||||
| 1061002 media upload params error | Slides media upload parameters do not meet the contract | Use `slides +media-upload`; do not hand-build the native `medias/upload_all`; the only valid `parent_type` for slides is `slide_file` |
|
||||
| 1061004 forbidden | The current identity has no edit permission on the presentation | Confirm the user/bot has edit permission on the target PPT; for bots this commonly means the PPT was not created by that bot |
|
||||
| 3350001 | XML not well-formed, XML structure not accepted by the server, or a bad replace fragment | Check unescaped characters first; in replace scenarios also check `block_id` and `<content/>` |
|
||||
| 3350002 | `revision_id` greater than the current version | Use `-1` for the current version, or fetch the latest `revision_id` again with `slides +xml-get` |
|
||||
| validation: unsafe file path | `--file` was given an absolute or parent path | `--file` must be a relative path inside the CWD; `cd` into the asset directory first, then run the command |
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
# Validation Checklist
|
||||
|
||||
创建或大幅改写演示文稿后,必须做一次显式验证。目标是发现空白页、XML 损坏、内容截断、明显溢出、弱视觉层级和未验证输出。
|
||||
After creating or substantially rewriting a presentation, you must perform one explicit validation. The goal is to catch blank pages, broken XML, truncated content, obvious overflow, weak visual hierarchy, and unverified output.
|
||||
|
||||
小型已有页编辑也要做对应范围的验证:至少读取被改页面或全文 XML,确认目标元素已更新且未破坏周边结构。
|
||||
Small edits to existing pages also require scope-appropriate validation: at minimum, read the modified page or the full XML and confirm the target element was updated without breaking the surrounding structure.
|
||||
|
||||
## Required Flow
|
||||
|
||||
1. 记录创建或编辑返回的 `xml_presentation_id`,以及已知的 `slide_id` / `revision_id`。
|
||||
2. 用 `slides +xml-get` 回读全文 XML 到本地文件。
|
||||
3. 检查实际页数是否符合计划或用户要求。
|
||||
4. 检查每页 `<data>` 内是否有预期主要元素。
|
||||
5. 检查没有明显空白页、破损页、缺失标题或缺失主视觉。
|
||||
6. 检查页面不是全部退化为标题加 bullet list。
|
||||
7. 检查视觉层级:标题、主视觉、支撑信息三者可区分。
|
||||
8. 检查明显溢出和布局风险:重叠、越界、底部拥挤、长文本框。
|
||||
9. 在最终回复中给出简短验证记录。
|
||||
1. Record the `xml_presentation_id` returned by the create or edit call, plus any known `slide_id` / `revision_id`.
|
||||
2. Read back the full XML to a local file with `slides +xml-get`.
|
||||
3. Check that the actual page count matches the plan or the user's request.
|
||||
4. Check that each page's `<data>` contains the expected primary elements.
|
||||
5. Check that there are no obvious blank pages, broken pages, missing titles, or missing primary visuals.
|
||||
6. Check that pages have not all degenerated into title + bullet list.
|
||||
7. Check visual hierarchy: title, primary visual, and supporting information are distinguishable.
|
||||
8. Check obvious overflow and layout risks: overlap, out-of-bounds, bottom crowding, long text boxes.
|
||||
9. Include a short validation record in the final reply.
|
||||
|
||||
回读命令:
|
||||
Read-back command:
|
||||
|
||||
```bash
|
||||
lark-cli slides +xml-get --as user \
|
||||
@@ -27,93 +27,93 @@ lark-cli slides +xml-get --as user \
|
||||
|
||||
## Automated XML Text Overlap Lint
|
||||
|
||||
提交前本地 XML 必须运行 XML 语法和文本重叠静态检查:
|
||||
Before submission, local XML must go through the XML-syntax and text-overlap static check:
|
||||
|
||||
```bash
|
||||
python3 skills/lark-slides/scripts/xml_text_overlap_lint.py --input <presentation-or-slide.xml>
|
||||
```
|
||||
|
||||
通过标准:
|
||||
Pass criteria:
|
||||
|
||||
- `summary.error_count == 0`。任何 error 都必须先修复再提交接口。
|
||||
- 当前工具检查 XML well-formed、SXSD tag/attr 支持情况、IconPark icon 类型和 icon 填充可见性、文本元素之间的明显重叠,以及 whiteboard 容器与外部 sibling 元素的可疑边界重叠;它不检查越界、文本高度不足、图文压盖、表格/图表压盖或底部拥挤。
|
||||
- 该工具不能替代页数核对、关键内容核对或真实视觉验收。
|
||||
- `summary.error_count == 0`. Any error must be fixed before calling the API.
|
||||
- The current tool checks XML well-formedness, SXSD tag/attr support, IconPark icon types and icon fill visibility, obvious overlap between text elements, and suspicious boundary overlap between whiteboard containers and external sibling elements; it does not check out-of-bounds, insufficient text height, text-over-image coverage, table/chart coverage, or bottom crowding.
|
||||
- The tool does not replace page-count checks, key-content checks, or real visual acceptance.
|
||||
|
||||
常见 code 的处理方向:
|
||||
Handling directions for common codes:
|
||||
|
||||
| code | 含义 | 处理方式 |
|
||||
| code | Meaning | Fix |
|
||||
|------|------|----------|
|
||||
| `xml_not_well_formed` | XML 语法错误或文本未转义 | 修复标签闭合、属性引号、`&` / `<` / `>` 转义 |
|
||||
| `sml_prefixed_tag` | SML 元素使用了命名空间前缀,如 `<ns0:slide>` 或 `<sml:shape>` | 使用 `<slide xmlns="http://www.larkoffice.com/sml/2.0">` 的默认命名空间,或使用无前缀标签 |
|
||||
| `sxsd_unsupported_tag` | 使用了 SXSD 不支持的标签 | 按 lint `hint` 替换为受支持标签;常见如 `textbox -> <shape type="text">`、`image -> <img>` |
|
||||
| `sxsd_unsupported_attr` | 支持的标签上使用了不支持的属性 | 按 lint `hint` 改为支持的属性;常见如 `x -> topLeftX`、`fontColor -> color` |
|
||||
| `iconpark_unsupported_icon_type` | `<icon>` 使用了 `iconpark-index.json` 中不存在的 `iconType` | 按 lint `hint` 改为名单内的 `iconType`,或先用 `scripts/iconpark_tool.py` 搜索 |
|
||||
| `icon_missing_fill_color` | 视觉规范要求 `<icon>` 设置 `<fill><fillColor color="..."/></fill>`,避免图标不可见 | 给 `<icon>` 添加显式非透明填充色,例如 `rgba(37, 99, 235, 1)` |
|
||||
| `icon_transparent_fill_color` | `<icon>` 的 `fillColor` 是透明色,不满足视觉可见性要求 | 改成与背景有足够对比的非透明颜色 |
|
||||
| `bbox_overlap` | 文本元素的估算绘制区域明显重叠 | 拉开文本坐标、缩小文本框/字号,或改成明确的分栏/分组结构 |
|
||||
| `whiteboard_external_overlap` | whiteboard 容器 bbox 与外部 sibling 元素跨边界重叠 | 按 lint `hint` 缩小或移动 whiteboard / 外部元素;若接受该风险,最终必须以截图 QA 或等价渲染视觉检查为准 |
|
||||
| `xml_not_well_formed` | XML syntax error or unescaped text | Fix tag closure, attribute quoting, `&` / `<` / `>` escaping |
|
||||
| `sml_prefixed_tag` | An SML element uses a namespace prefix, e.g. `<ns0:slide>` or `<sml:shape>` | Use the default namespace of `<slide xmlns="http://www.larkoffice.com/sml/2.0">`, or unprefixed tags |
|
||||
| `sxsd_unsupported_tag` | A tag not supported by SXSD was used | Replace with a supported tag per the lint `hint`; common cases: `textbox -> <shape type="text">`, `image -> <img>` |
|
||||
| `sxsd_unsupported_attr` | An unsupported attribute was used on a supported tag | Change to a supported attribute per the lint `hint`; common cases: `x -> topLeftX`, `fontColor -> color` |
|
||||
| `iconpark_unsupported_icon_type` | `<icon>` uses an `iconType` that does not exist in `iconpark-index.json` | Change to an allowlisted `iconType` per the lint `hint`, or search first with `scripts/iconpark_tool.py` |
|
||||
| `icon_missing_fill_color` | The visual spec requires `<icon>` to set `<fill><fillColor color="..."/></fill>` to keep the icon visible | Add an explicit non-transparent fill color to `<icon>`, e.g. `rgba(37, 99, 235, 1)` |
|
||||
| `icon_transparent_fill_color` | The `<icon>` `fillColor` is transparent and fails the visual visibility requirement | Change to a non-transparent color with sufficient contrast against the background |
|
||||
| `bbox_overlap` | The estimated draw areas of text elements clearly overlap | Spread out text coordinates, shrink text boxes/font sizes, or switch to explicit column/group structures |
|
||||
| `whiteboard_external_overlap` | The whiteboard container bbox crosses boundaries with an external sibling element | Shrink or move the whiteboard / external element per the lint `hint`; if you accept the risk, final acceptance must rely on screenshot QA or equivalent rendered visual inspection |
|
||||
|
||||
## Page Count And Structure
|
||||
|
||||
- 实际页数必须等于用户要求或 `slide_plan.json` 的页数。
|
||||
- 如果创建过程部分失败,先记录已创建的 `xml_presentation_id`,再回读确认哪些页已写入。
|
||||
- 每页都应包含 `<data>`,且 `<data>` 内至少有一个非背景主体元素。
|
||||
- 封面、章节页、总结页可以文字较少,但不能只有空背景。
|
||||
- 技术解释页、对比页、流程页、架构页必须有匹配的结构元素,例如分组框、连线、时间轴、表格或图形化区域。
|
||||
- The actual page count must equal the user's request or the count in `slide_plan.json`.
|
||||
- If the creation process partially failed, record the created `xml_presentation_id` first, then read back to confirm which pages were written.
|
||||
- Every page should contain `<data>`, and `<data>` must have at least one non-background primary element.
|
||||
- Cover, section, and summary pages may carry little text, but must not be an empty background only.
|
||||
- Technical explanation, comparison, flow, and architecture pages must have matching structural elements, e.g. grouped boxes, connectors, timelines, tables, or graphical areas.
|
||||
|
||||
## Expected Elements
|
||||
|
||||
按 `slide_plan.json` 和用户要求逐页核对:
|
||||
Verify page by page against `slide_plan.json` and the user's requirements:
|
||||
|
||||
- 标题或主结论存在,并能对应 `key_message`。
|
||||
- `layout_type` 对应的主要结构已生成。
|
||||
- `visual_focus` 是页面中最醒目或最大的信息区域之一。
|
||||
- `text_density` 影响了文本量,没有用长 bullet 框替代规划。
|
||||
- `asset_need` 有真实素材时已放入正确区域;没有真实素材时,`fallback_if_missing` 已用 XML 形状、线条、标签、表格或图表兜底。
|
||||
- The title or main conclusion exists and corresponds to `key_message`.
|
||||
- The primary structure implied by `layout_type` was generated.
|
||||
- `visual_focus` is one of the most prominent or largest information areas on the page.
|
||||
- `text_density` actually influenced the amount of text; a long bullet box did not replace the plan.
|
||||
- When `asset_need` has a real asset, it is placed in the correct area; without a real asset, `fallback_if_missing` provided an XML fallback of shapes, lines, labels, tables, or charts.
|
||||
|
||||
如果用户指定了关键页,例如“架构解释”“Self-Attention 机制解释”“对比或演进视角”“总结页”,最终验证记录必须逐项说明这些页已存在。
|
||||
If the user specified key pages, e.g. "architecture explanation", "Self-Attention mechanism explanation", "comparison or evolution perspective", "summary page", the final validation record must state item by item that those pages exist.
|
||||
|
||||
## Blank Or Broken Page Signals
|
||||
|
||||
把下面情况视为需要修复后再交付:
|
||||
Treat the following as must-fix before delivery:
|
||||
|
||||
- `<data/>` 为空,或只有背景、装饰线、空 `<content/>`。
|
||||
- 关键文本没有出现在回读 XML 中。
|
||||
- 图片仍是 `@./path`,或 `<img src>` 是 http(s) 外链。
|
||||
- 页面依赖的图片区域为空,且没有 fallback visual。
|
||||
- 返回 XML 缺页、页序明显错误,或某页内容被 shell 截断。
|
||||
- 大量形状坐标完全相同,导致主体内容重叠。
|
||||
- 渐变背景回退成空白或白底,导致文字不可读。
|
||||
- `<data/>` is empty, or contains only background, decorative lines, or empty `<content/>`.
|
||||
- Key text does not appear in the read-back XML.
|
||||
- Images are still `@./path`, or `<img src>` is an http(s) external link.
|
||||
- An image area the page depends on is empty with no fallback visual.
|
||||
- The returned XML is missing pages, the page order is clearly wrong, or a page's content was truncated by the shell.
|
||||
- Many shapes share identical coordinates, causing the primary content to overlap.
|
||||
- A gradient background fell back to blank or white, making text unreadable.
|
||||
|
||||
## Whiteboard Elements
|
||||
|
||||
`slide.get` 回读 XML 时,`<whiteboard>` 块只返回位置属性(`topLeftX`、`topLeftY`、`width`、`height`),SVG / Mermaid 内容**不随 XML 返回**。
|
||||
When reading back XML with `slide.get`, `<whiteboard>` blocks return only position attributes (`topLeftX`, `topLeftY`, `width`, `height`); SVG / Mermaid content is **not returned with the XML**.
|
||||
|
||||
- whiteboard 验证可以核对坐标是否越界:`topLeftX + width ≤ 960`,`topLeftY + height ≤ 540`;lint 还会报告 whiteboard 容器与外部 sibling 元素的可疑边界重叠。
|
||||
- SVG 和 Mermaid 内容的正确性无法通过回读 XML 验证,需要人工视觉验收。
|
||||
- 不要在验证记录中声称 whiteboard 内容已验证,除非用户确认了视觉效果。
|
||||
- Whiteboard validation can verify coordinates stay in bounds: `topLeftX + width ≤ 960`, `topLeftY + height ≤ 540`; the lint also reports suspicious boundary overlap between whiteboard containers and external sibling elements.
|
||||
- The correctness of SVG and Mermaid content cannot be verified via XML read-back; it requires human visual acceptance.
|
||||
- Do not claim in the validation record that whiteboard content was verified unless the user confirmed the visual result.
|
||||
|
||||
## Layout And Overflow Risk
|
||||
|
||||
优先修复这些明显风险:
|
||||
Prioritize fixing these obvious risks:
|
||||
|
||||
- 正文或标签框高度不足,文本很可能被截断。
|
||||
- 多个主体元素在同一区域重叠,而不是有意叠加背景。
|
||||
- 重要内容越过画布边界,或贴近底部超过 `y=500`。
|
||||
- 高密度页使用单个长 bullet list,没有分栏、表格或分组。
|
||||
- 标题、主视觉、正文的字号和颜色差异太弱,视觉层级不清。
|
||||
- 所有内容页都是同一套标题加 bullets 坐标。
|
||||
- Body or label boxes too short, so text is likely truncated.
|
||||
- Multiple primary elements overlapping in the same area, rather than intentional background layering.
|
||||
- Important content crossing the canvas boundary, or hugging the bottom beyond `y=500`.
|
||||
- A high-density page using one long bullet list without columns, tables, or grouping.
|
||||
- Font size and color differences between title, primary visual, and body too weak, making hierarchy unclear.
|
||||
- Every content page using the same title + bullets coordinates.
|
||||
|
||||
## Verification Record
|
||||
|
||||
最终回复必须包含简短验证记录,建议格式:
|
||||
The final reply must include a short validation record; suggested format:
|
||||
|
||||
```text
|
||||
验证记录:
|
||||
- 回读:已执行 slides +xml-get,实际页数 N / 预期 N。
|
||||
- 关键页:架构解释 / Self-Attention / 对比或演进 / 总结页均存在。
|
||||
- 结构:检查了主要 shape/img/table/chart 元素,无明显空白页或破损页。
|
||||
- 布局:检查了标题层级、主视觉、重叠/越界/文本溢出风险。
|
||||
Validation record:
|
||||
- Read-back: ran slides +xml-get, actual pages N / expected N.
|
||||
- Key pages: architecture explanation / Self-Attention / comparison or evolution / summary page all present.
|
||||
- Structure: checked primary shape/img/table/chart elements; no obvious blank or broken pages.
|
||||
- Layout: checked title hierarchy, primary visual, overlap/out-of-bounds/text-overflow risks.
|
||||
```
|
||||
|
||||
不要声称完成了人工视觉验收,除非确实打开或获取了可视化结果。仅从 XML 静态检查得出的结论,应表述为“静态检查未发现明显问题”。
|
||||
Do not claim human visual acceptance was completed unless you actually opened or obtained a rendered result. Conclusions drawn only from XML static checks should be phrased as "static checks found no obvious issues".
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Visual Planning
|
||||
|
||||
新建演示文稿或大幅改写页面时,在 `slide_plan.json` 完成后、生成 XML 前读取本文件。目标是让 `layout_type`、`visual_focus`、`text_density` 变成实际页面几何,而不是只写在 plan 里。
|
||||
When creating a new presentation or substantially rewriting pages, read this file after `slide_plan.json` is complete and before generating XML. The goal is to turn `layout_type`, `visual_focus`, and `text_density` into actual page geometry, not just labels in the plan.
|
||||
|
||||
默认画布按 `960 x 540` 规划。模板 XML 可以覆盖具体坐标,但不能覆盖这些原则:页面要有主视觉区域、文本要受密度约束、不同 `layout_type` 必须产生明显不同的坐标结构。
|
||||
Plan against a default canvas of `960 x 540`. Template XML may override specific coordinates, but it cannot override these principles: every page needs a primary visual region, text must respect density constraints, and different `layout_type` values must produce visibly different coordinate structures.
|
||||
|
||||
## Core Rules
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
# XML 格式指南
|
||||
# XML Format Guide
|
||||
|
||||
本文档基于 [slides_xml_schema_definition.xml](slides_xml_schema_definition.xml) 整理,说明飞书 Slides XML Schema(SML 2.0)的核心结构和常用写法。
|
||||
This document is organized based on [slides_xml_schema_definition.xml](slides_xml_schema_definition.xml) and explains the core structure and common writing methods of Feishu Slides XML Schema (SML 2.0).
|
||||
|
||||
## 基本结构
|
||||
## Basic structure
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<presentation xmlns="http://www.larkoffice.com/sml/2.0" width="960" height="540">
|
||||
<title>演示文稿标题</title>
|
||||
<title>Presentation title</title>
|
||||
<slide>
|
||||
<style>
|
||||
<fill>
|
||||
@@ -17,51 +17,51 @@
|
||||
<data>
|
||||
<shape type="text" topLeftX="80" topLeftY="80" width="800" height="120">
|
||||
<content textType="title">
|
||||
<p>主标题</p>
|
||||
<p>Main title</p>
|
||||
</content>
|
||||
</shape>
|
||||
</data>
|
||||
<note>
|
||||
<content textType="body">
|
||||
<p>这是演讲者备注。</p>
|
||||
<p>These are speaker notes. </p>
|
||||
</content>
|
||||
</note>
|
||||
</slide>
|
||||
</presentation>
|
||||
```
|
||||
|
||||
## 根元素
|
||||
## Root element
|
||||
|
||||
### `<presentation>`
|
||||
|
||||
协议标准写法应带命名空间 `http://www.larkoffice.com/sml/2.0`;当前服务端实现可能兼容不带 `xmlns` 的输入,但不作为协议保证。
|
||||
The protocol standard should be written with the namespace `http://www.larkoffice.com/sml/2.0`; the current server implementation may be compatible with input without `xmlns`, but this is not a protocol guarantee.
|
||||
|
||||
**属性:**
|
||||
**property:**
|
||||
|
||||
| 属性 | 类型 | 必需 | 说明 |
|
||||
| Properties | Type | Required | Description |
|
||||
|------|------|------|------|
|
||||
| `width` | positiveInteger | 是 | 演示文稿宽度,如 `960` |
|
||||
| `height` | positiveInteger | 是 | 演示文稿高度,如 `540` |
|
||||
| `id` | string | 否 | 演示文稿标识 |
|
||||
| `width` | positiveInteger | Yes | Presentation width, such as `960` |
|
||||
| `height` | positiveInteger | Yes | Presentation height, such as `540` |
|
||||
| `id` | string | no | presentation ID |
|
||||
|
||||
**子元素:**
|
||||
**Child element:**
|
||||
|
||||
| 元素 | 必需 | 说明 |
|
||||
| Element | Required | Description |
|
||||
|------|------|------|
|
||||
| `<title>` | 否 | 演示文稿标题 |
|
||||
| `<theme>` | 否 | 全局主题 |
|
||||
| `<slide>` | 是 | 幻灯片页面,至少 1 页,最多 100 页 |
|
||||
| `<title>` | No | Presentation title |
|
||||
| `<theme>` | No | Global theme |
|
||||
| `<slide>` | Yes | Slide pages, minimum 1 page, maximum 100 pages |
|
||||
|
||||
## 主题
|
||||
## theme
|
||||
|
||||
### `<theme>`
|
||||
|
||||
`<theme>` 当前包含两部分:
|
||||
`<theme>` currently contains two parts:
|
||||
|
||||
- `<background>`:演示文稿级背景填充
|
||||
- `<textStyles>`:主题文本样式集合
|
||||
- `<background>`: presentation-level background fill
|
||||
- `<textStyles>`: theme text style collection
|
||||
|
||||
`<textStyles>` 下可选子元素:
|
||||
Optional sub-elements under `<textStyles>`:
|
||||
|
||||
- `<title>`
|
||||
- `<headline>`
|
||||
@@ -69,61 +69,61 @@
|
||||
- `<body>`
|
||||
- `<caption>`
|
||||
|
||||
这些元素定义的是主题默认样式,不是页面结构。常用属性:
|
||||
These elements define the theme's default style, not the page structure. Common properties:
|
||||
|
||||
| 属性 | 说明 |
|
||||
| Properties | Description |
|
||||
|------|------|
|
||||
| `fontFamily` | 字体 |
|
||||
| `fontSize` | 字号 |
|
||||
| `fontColor` | 字体颜色 |
|
||||
| `fontFamily` | Font |
|
||||
| `fontSize` | Font size |
|
||||
| `fontColor` | Font color |
|
||||
|
||||
## 幻灯片元素
|
||||
## Slide elements
|
||||
|
||||
### `<slide>`
|
||||
|
||||
单张幻灯片的结构比较严格。
|
||||
The structure of a single slide is relatively strict.
|
||||
|
||||
**属性:**
|
||||
**property:**
|
||||
|
||||
| 属性 | 类型 | 必需 | 说明 |
|
||||
| Properties | Type | Required | Description |
|
||||
|------|------|------|------|
|
||||
| `id` | string | 否 | 幻灯片标识 |
|
||||
| `id` | string | no | slide ID |
|
||||
|
||||
**直接子元素只有:**
|
||||
**Direct child elements are only:**
|
||||
|
||||
| 元素 | 必需 | 说明 |
|
||||
| Element | Required | Description |
|
||||
|------|------|------|
|
||||
| `<style>` | 否 | 页面样式 |
|
||||
| `<data>` | 否 | 页面元素容器 |
|
||||
| `<note>` | 否 | 演讲者备注 |
|
||||
| `<style>` | No | Page style |
|
||||
| `<data>` | No | Page element container |
|
||||
| `<note>` | No | Speaker Notes |
|
||||
|
||||
这意味着 `<title>`、`<headline>`、`<body>`、`<caption>` 不能直接放在 `<slide>` 下。
|
||||
This means that `<title>`, `<headline>`, `<body>`, `<caption>` cannot be placed directly under `<slide>`.
|
||||
|
||||
## 文本内容模型
|
||||
## Text content model
|
||||
|
||||
### `<content>`
|
||||
|
||||
实际页面文本通常通过 `<content>` 表达,常见位置有:
|
||||
The actual page text is usually expressed through `<content>`, common locations are:
|
||||
|
||||
- `shape` 内部
|
||||
- `table/td` 内部
|
||||
- `note` 内部
|
||||
- `shape` internal
|
||||
- `table/td` internal
|
||||
- `note` internal
|
||||
|
||||
**常用属性:**
|
||||
**Commonly used properties:**
|
||||
|
||||
| 属性 | 说明 |
|
||||
| Properties | Description |
|
||||
|------|------|
|
||||
| `textType` | `title` / `headline` / `sub-headline` / `body` / `caption` |
|
||||
| `verticalAlign` | 垂直对齐 |
|
||||
| `textAlign` | 水平对齐 |
|
||||
| `lineSpacing` | 行间距 |
|
||||
| `fontSize` | 字号 |
|
||||
| `fontFamily` | 字体 |
|
||||
| `color` | 字体颜色 |
|
||||
| `bold` / `italic` / `underline` / `strikethrough` | 内容级样式 |
|
||||
| `wrap` | 是否自动换行 |
|
||||
| `verticalAlign` | Vertical alignment |
|
||||
| `textAlign` | Horizontal alignment |
|
||||
| `lineSpacing` | Line spacing |
|
||||
| `fontSize` | Font size |
|
||||
| `fontFamily` | Font |
|
||||
| `color` | Font color |
|
||||
| `bold` / `italic` / `underline` / `strikethrough` | Content-level styles |
|
||||
| `wrap` | Whether to wrap lines automatically |
|
||||
|
||||
**可包含的子元素:**
|
||||
**Sub-elements that can be included:**
|
||||
|
||||
- `<p>`
|
||||
- `<ul>`
|
||||
@@ -131,7 +131,7 @@
|
||||
|
||||
### `<p>`
|
||||
|
||||
`<p>` 是段落元素,可混排纯文本和内联标签:
|
||||
`<p>` is a paragraph element that can mix plain text and inline tags:
|
||||
|
||||
- `<br/>`
|
||||
- `<strong>`
|
||||
@@ -143,30 +143,30 @@
|
||||
- `<shadow>`
|
||||
- `<outline>`
|
||||
|
||||
示例:
|
||||
Example:
|
||||
|
||||
```xml
|
||||
<content textType="body" textAlign="left">
|
||||
<p>普通文本 <strong>加粗</strong> <em>斜体</em> <a href="https://example.com">链接</a></p>
|
||||
<p>Normal text <strong>Bold</strong> <em>Italic</em> <a href="https://example.com">Links</a></p>
|
||||
<ul>
|
||||
<li><p>列表项 1</p></li>
|
||||
<li><p>列表项 2</p></li>
|
||||
<li><p>List item 1</p></li>
|
||||
<li><p>List item 2</p></li>
|
||||
</ul>
|
||||
</content>
|
||||
```
|
||||
|
||||
## 常用页面元素
|
||||
## Common page elements
|
||||
|
||||
所有页面元素都放在 `<data>` 中。
|
||||
All page elements are placed in `<data>`.
|
||||
|
||||
### `<shape>`
|
||||
|
||||
`shape` 可表示普通形状,也可表示文本框。文本框推荐使用 `type="text"`。
|
||||
`shape` can represent a normal shape or a text box. It is recommended to use `type="text"` for text boxes.
|
||||
|
||||
```xml
|
||||
<shape type="text" topLeftX="80" topLeftY="80" width="800" height="120">
|
||||
<content textType="title">
|
||||
<p>主标题</p>
|
||||
<p>Main title</p>
|
||||
</content>
|
||||
</shape>
|
||||
```
|
||||
@@ -180,20 +180,20 @@
|
||||
</shape>
|
||||
```
|
||||
|
||||
**属性:**
|
||||
**property:**
|
||||
|
||||
| 属性 | 必需 | 说明 |
|
||||
| Properties | Required | Description |
|
||||
|------|------|------|
|
||||
| `type` | 是 | 形状类型,`text` 表示文本框 |
|
||||
| `topLeftX` | 是 | 左上角 X 坐标 |
|
||||
| `topLeftY` | 是 | 左上角 Y 坐标 |
|
||||
| `width` | 是 | 宽度 |
|
||||
| `height` | 是 | 高度 |
|
||||
| `rotation` | 否 | 旋转角度 |
|
||||
| `flipX` / `flipY` | 否 | 翻转 |
|
||||
| `alpha` | 否 | 透明度 |
|
||||
| `type` | Yes | Shape type, `text` represents text box |
|
||||
| `topLeftX` | Yes | X coordinate of the upper left corner |
|
||||
| `topLeftY` | Yes | Y coordinate of the upper left corner |
|
||||
| `width` | Yes | Width |
|
||||
| `height` | Yes | Height |
|
||||
| `rotation` | No | Rotation angle |
|
||||
| `flipX` / `flipY` | No | Flip |
|
||||
| `alpha` | no | transparency |
|
||||
|
||||
**可选子元素:**
|
||||
**Optional sub-elements:**
|
||||
|
||||
- `<fill>`
|
||||
- `<border>`
|
||||
@@ -209,7 +209,7 @@
|
||||
</line>
|
||||
```
|
||||
|
||||
`line` 使用的是 `startX` / `startY` / `endX` / `endY`,不是 `x1` / `y1` / `x2` / `y2`。
|
||||
`line` uses `startX` / `startY` / `endX` / `endY`, not `x1` / `y1` / `x2` / `y2`.
|
||||
|
||||
### `<img>`
|
||||
|
||||
@@ -217,21 +217,21 @@
|
||||
<img src="file_token_or_url" topLeftX="100" topLeftY="220" width="320" height="180"/>
|
||||
```
|
||||
|
||||
`img` 使用 `topLeftX` / `topLeftY`,不是 `x` / `y`。
|
||||
`img` uses `topLeftX` / `topLeftY`, not `x` / `y`.
|
||||
|
||||
`src` 只接受两种值:
|
||||
`src` only accepts two values:
|
||||
|
||||
| `src` 形式 | 说明 |
|
||||
| `src` form | Description |
|
||||
|---|---|
|
||||
| `file_token`(如 `boxcnXXXXXXXXXXXXXXXXXXXXXX`) | 通过 `slides +media-upload` 上传后返回的 token |
|
||||
| `@<本地路径>`(如 `@./assets/chart.png`) | **仅在 `slides +create --slides` 中可用**:CLI 会自动上传该文件并替换为 file_token |
|
||||
| `file_token` (such as `boxcnXXXXXXXXXXXXXXXXXXXXXX`) | The token returned after uploading through `slides +media-upload` |
|
||||
| `@<local path>` (e.g. `@./assets/chart.png`) | **Only available with `slides +create --slides`**: The CLI will automatically upload the file and replace it with file_token |
|
||||
|
||||
> **禁止使用 http(s) 外链 URL**:飞书 slides 渲染端不会代理外链图片,`src="https://..."` 在 PPT 里通常显示破图。要用网图必须先 `curl`/下载到 CWD 内,再走上传流程拿 `file_token`。
|
||||
> **The use of http(s) external link URLs is prohibited**: Feishu slides rendering end will not proxy external link images, `src="https://..."` usually displays broken images in PPT. To use the network image, you must first `curl`/download it into CWD, and then go through the upload process to get `file_token`.
|
||||
|
||||
本地图片的两种姿势:
|
||||
Two poses for local pictures:
|
||||
|
||||
- **新建带图 PPT**:`+create --slides` 里直接写 `src="@./pic.png"`,CLI 在创空白 PPT 后、加 slides 前自动上传并替换 token
|
||||
- **给已有 PPT 加带图新页**:先 `slides +media-upload --file ./pic.png --presentation $PID` 拿 token,再用 token 写进 `xml_presentation.slide create` 的 XML
|
||||
- **Create a new PPT with pictures**: Write `src="@./pic.png"` directly in `+create --slides`, and the CLI will automatically upload and replace the token after creating a blank PPT and before adding slides.
|
||||
- **Add a new page with pictures to an existing PPT**: First use `slides +media-upload --file ./pic.png --presentation $PID` to get the token, and then use the token to write into the XML of `xml_presentation.slide create`
|
||||
|
||||
### `<icon>`
|
||||
|
||||
@@ -241,21 +241,21 @@
|
||||
|
||||
### `<table>`
|
||||
|
||||
表格结构为:
|
||||
The table structure is:
|
||||
|
||||
- `<table>`
|
||||
- `<colgroup>` / `<tr>`
|
||||
- `<tr>` 内为 `<td>`
|
||||
- `<td>` 内可放 `<content>`
|
||||
- `<tr>` contains `<td>`
|
||||
- `<td>` can contain `<content>`
|
||||
|
||||
### `<chart>`
|
||||
|
||||
图表元素必须至少包含:
|
||||
Chart elements must contain at least:
|
||||
|
||||
- `<chartPlotArea>`
|
||||
- `<chartData>`
|
||||
|
||||
同时还可以包含:
|
||||
It can also include:
|
||||
|
||||
- `<chartTitle>`
|
||||
- `<chartSubTitle>`
|
||||
@@ -263,9 +263,9 @@
|
||||
- `<chartLegend>`
|
||||
- `<chartTooltip>`
|
||||
|
||||
完整图表类型覆盖示例见 [slides_chart_demo.xml](slides_chart_demo.xml),其中包含柱状、条形、折线、面积、饼 / 环、雷达等原生 `<chart>` 示例,以及散点、气泡、漏斗、帕累托、瀑布等 `<whiteboard>` SVG 图表示例。
|
||||
For complete chart type coverage examples, see [slides_chart_demo.xml](slides_chart_demo.xml), which includes native `<chart>` examples such as column, bar, line, area, pie/ring, radar, etc., as well as `<whiteboard>` SVG chart examples such as scatter, bubble, funnel, Pareto, waterfall, etc.
|
||||
|
||||
组合图示例(来自 [slides_chart_demo.xml](slides_chart_demo.xml)):
|
||||
Combination chart example (from [slides_chart_demo.xml](slides_chart_demo.xml)):
|
||||
|
||||
```xml
|
||||
<chart width="556" height="350" topLeftX="42" topLeftY="132">
|
||||
@@ -295,14 +295,14 @@
|
||||
<chartLegend position="bottom" fontSize="11"/>
|
||||
<chartData>
|
||||
<dim1>
|
||||
<chartField name="季度">24Q1,24Q2,24Q3,24Q4,25Q1,25Q2,25Q3,25Q4</chartField>
|
||||
<chartField name="Quarter">24Q1,24Q2,24Q3,24Q4,25Q1,25Q2,25Q3,25Q4</chartField>
|
||||
</dim1>
|
||||
<dim2>
|
||||
<chartField name="营收">180,195,210,245,220,238,258,296</chartField>
|
||||
<chartField name="增速">0.08,0.12,0.15,0.18,0.22,0.22,0.23,0.21</chartField>
|
||||
<chartField name="Revenue">180,195,210,245,220,238,258,296</chartField>
|
||||
<chartField name="Growth">0.08,0.12,0.15,0.18,0.22,0.22,0.23,0.21</chartField>
|
||||
</dim2>
|
||||
</chartData>
|
||||
<chartTitle fontSize="12" color="rgba(15, 30, 58, 1)" bold="true">营收(亿美元, 左轴) · 同比增速(%, 右轴)</chartTitle>
|
||||
<chartTitle fontSize="12" color="rgba(15, 30, 58, 1)" bold="true">Revenue (USD 100M, left axis) · Year-over-year growth rate (%, right axis)</chartTitle>
|
||||
<chartStyle>
|
||||
<chartBackground color="rgba(0, 0, 0, 0)"/>
|
||||
<chartBorder color="rgb(222, 224, 227)" width="0"/>
|
||||
@@ -314,7 +314,7 @@
|
||||
</chart>
|
||||
```
|
||||
|
||||
## 样式元素
|
||||
## Style elements
|
||||
|
||||
### `<fill>`
|
||||
|
||||
@@ -330,7 +330,7 @@
|
||||
<border color="rgb(0, 0, 0)" width="2" dashArray="solid"/>
|
||||
```
|
||||
|
||||
### 颜色格式
|
||||
### Color format
|
||||
|
||||
```xml
|
||||
<fillColor color="rgb(255, 0, 0)"/>
|
||||
@@ -339,28 +339,28 @@
|
||||
<fillColor color="radial-gradient(circle at 50% 50%, rgb(255,0,0) 0%, rgb(0,0,255) 100%)"/>
|
||||
```
|
||||
|
||||
## 演讲者备注
|
||||
## Speaker Notes
|
||||
|
||||
### `<note>`
|
||||
|
||||
```xml
|
||||
<note>
|
||||
<content textType="body">
|
||||
<p>这是演讲者备注内容。</p>
|
||||
<p>These are speaker notes. </p>
|
||||
</content>
|
||||
</note>
|
||||
```
|
||||
|
||||
## 完整示例
|
||||
## Complete example
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<presentation xmlns="http://www.larkoffice.com/sml/2.0" width="960" height="540">
|
||||
<title>季度报告</title>
|
||||
<title>Quarterly Report</title>
|
||||
<theme>
|
||||
<textStyles>
|
||||
<title fontFamily="思源黑体" fontSize="54" fontColor="rgba(0, 0, 0, 1)"/>
|
||||
<body fontFamily="思源黑体" fontSize="18" fontColor="rgba(43, 47, 54, 1)"/>
|
||||
<title fontFamily="Siyuan Heidi" fontSize="54" fontColor="rgba(0, 0, 0, 1)"/>
|
||||
<body fontFamily="Siyuan Heidi" fontSize="18" fontColor="rgba(43, 47, 54, 1)"/>
|
||||
</textStyles>
|
||||
</theme>
|
||||
<slide>
|
||||
@@ -372,16 +372,16 @@
|
||||
<data>
|
||||
<shape type="text" topLeftX="80" topLeftY="72" width="760" height="100">
|
||||
<content textType="title">
|
||||
<p>2024 年第一季度报告</p>
|
||||
<p>2024 First Quarter Report</p>
|
||||
</content>
|
||||
</shape>
|
||||
<shape type="text" topLeftX="80" topLeftY="200" width="520" height="180">
|
||||
<content textType="body">
|
||||
<p>核心指标</p>
|
||||
<p>Core indicators</p>
|
||||
<ul>
|
||||
<li><p>用户增长:+25%</p></li>
|
||||
<li><p>收入增长:+30%</p></li>
|
||||
<li><p>市场份额:15%</p></li>
|
||||
<li><p>User growth: +25%</p></li>
|
||||
<li><p>Revenue growth: +30%</p></li>
|
||||
<li><p>Market share: 15%</p></li>
|
||||
</ul>
|
||||
</content>
|
||||
</shape>
|
||||
@@ -394,23 +394,23 @@
|
||||
</data>
|
||||
<note>
|
||||
<content textType="body">
|
||||
<p>讲到增长率时补充样本范围。</p>
|
||||
<p>Supplement the sample range when talking about growth rate. </p>
|
||||
</content>
|
||||
</note>
|
||||
</slide>
|
||||
</presentation>
|
||||
```
|
||||
|
||||
## 最佳实践
|
||||
## Best Practices
|
||||
|
||||
1. 始终带上命名空间 `xmlns="http://www.larkoffice.com/sml/2.0"`
|
||||
2. 用 `shape type="text"` + `content` 表达页面文本
|
||||
3. 用 `topLeftX` / `topLeftY`、`startX` / `startY` 等 schema 中定义的属性名
|
||||
4. 优先使用 `rgb` / `rgba` 颜色格式
|
||||
5. 特殊字符按 XML 规则转义
|
||||
6. 标准 16:9 页面建议使用 `width="960"` 和 `height="540"`
|
||||
1. Always bring the namespace `xmlns="http://www.larkoffice.com/sml/2.0"`
|
||||
2. Use `shape type="text"` + `content` to express page text
|
||||
3. Use attribute names defined in schema such as `topLeftX` / `topLeftY`, `startX` / `startY` etc.
|
||||
4. Prefer to use `rgb` / `rgba` color format
|
||||
5. Special characters are escaped according to XML rules
|
||||
6. It is recommended to use `width="960"` and `height="540"` for standard 16:9 pages
|
||||
|
||||
## 参考文档
|
||||
## Reference documentation
|
||||
|
||||
- [xml-schema-quick-ref.md](xml-schema-quick-ref.md)
|
||||
- [slides_xml_schema_definition.xml](slides_xml_schema_definition.xml)
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
# XML Schema 快速参考
|
||||
# XML Schema Quick Reference
|
||||
|
||||
本文档是 [slides_xml_schema_definition.xml](slides_xml_schema_definition.xml) 的精简版摘要;如果两者不一致,以 XSD 原文为准。
|
||||
This document is a condensed summary of [slides_xml_schema_definition.xml](slides_xml_schema_definition.xml); if the two disagree, the XSD source is authoritative.
|
||||
|
||||
## 最重要的规则
|
||||
## Most Important Rules
|
||||
|
||||
1. 协议标准写法应使用 `<presentation xmlns="http://www.larkoffice.com/sml/2.0">`;当前服务端实现可能兼容不带 `xmlns` 的输入,但不作为协议保证
|
||||
2. `<presentation>` 直接子元素只有 `<title>`、`<theme>`、`<slide>`
|
||||
3. `<slide>` 直接子元素只有 `<style>`、`<data>`、`<note>`
|
||||
4. 页面中的文本通常通过 `<content>` 表达,而不是把 `<title>`、`<body>` 直接挂在 `<slide>` 下
|
||||
1. The standard protocol form is `<presentation xmlns="http://www.larkoffice.com/sml/2.0">`; the current server implementation may tolerate input without `xmlns`, but this is not a protocol guarantee
|
||||
2. The only direct children of `<presentation>` are `<title>`, `<theme>`, `<slide>`
|
||||
3. The only direct children of `<slide>` are `<style>`, `<data>`, `<note>`
|
||||
4. Text on a page is usually expressed through `<content>`, rather than hanging `<title>` or `<body>` directly under `<slide>`
|
||||
|
||||
## 最小可用示例
|
||||
## Minimal Working Example
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
@@ -18,7 +18,7 @@
|
||||
<data>
|
||||
<shape type="text" topLeftX="80" topLeftY="80" width="800" height="120">
|
||||
<content textType="title">
|
||||
<p>标题</p>
|
||||
<p>Title</p>
|
||||
</content>
|
||||
</shape>
|
||||
</data>
|
||||
@@ -26,37 +26,37 @@
|
||||
</presentation>
|
||||
```
|
||||
|
||||
## presentation 根元素
|
||||
## presentation Root Element
|
||||
|
||||
| 属性 | 必需 | 说明 |
|
||||
| Attribute | Required | Description |
|
||||
|------|------|------|
|
||||
| `width` | 是 | 演示文稿宽度,正整数 |
|
||||
| `height` | 是 | 演示文稿高度,正整数 |
|
||||
| `id` | 否 | 演示文稿标识 |
|
||||
| `width` | Yes | Presentation width, positive integer |
|
||||
| `height` | Yes | Presentation height, positive integer |
|
||||
| `id` | No | Presentation identifier |
|
||||
|
||||
**子元素:** `<title>?`, `<theme>?`, `<slide>+`
|
||||
**Child elements:** `<title>?`, `<theme>?`, `<slide>+`
|
||||
|
||||
## slide 元素
|
||||
## slide Element
|
||||
|
||||
| 属性 | 必需 | 说明 |
|
||||
| Attribute | Required | Description |
|
||||
|------|------|------|
|
||||
| `id` | 否 | 幻灯片标识 |
|
||||
| `id` | No | Slide identifier |
|
||||
|
||||
**子元素:**
|
||||
- `<style>?` - 页面样式,目前可放 `<fill>`
|
||||
- `<data>?` - 页面元素容器,可放 `shape`、`line`、`polyline`、`img`、`table`、`icon`、`chart`、`whiteboard`、`undefined`
|
||||
- `<note>?` - 演讲者备注,内部可放 `<content>`
|
||||
**Child elements:**
|
||||
- `<style>?` - Page style; currently can contain `<fill>`
|
||||
- `<data>?` - Page element container; can contain `shape`, `line`, `polyline`, `img`, `table`, `icon`, `chart`, `whiteboard`, `undefined`
|
||||
- `<note>?` - Speaker notes; can contain `<content>` inside
|
||||
|
||||
## theme 与文本类型
|
||||
## theme and Text Types
|
||||
|
||||
XSD 中的 `title`、`headline`、`sub-headline`、`body`、`caption` 主要出现在:
|
||||
The `title`, `headline`, `sub-headline`, `body`, `caption` types in the XSD mainly appear in:
|
||||
|
||||
- `<theme><textStyles>...</textStyles></theme>` 中,作为主题文本样式
|
||||
- `<content textType="...">` 中,作为内容的文本类型
|
||||
- `<theme><textStyles>...</textStyles></theme>`, as theme text styles
|
||||
- `<content textType="...">`, as the content's text type
|
||||
|
||||
`textStyles` 的 schema 默认值如下:
|
||||
The schema defaults for `textStyles` are:
|
||||
|
||||
| textType | 默认字号 |
|
||||
| textType | Default font size |
|
||||
|----------|----------|
|
||||
| `title` | 54 |
|
||||
| `headline` | 38 |
|
||||
@@ -64,39 +64,39 @@ XSD 中的 `title`、`headline`、`sub-headline`、`body`、`caption` 主要出
|
||||
| `body` | 16 |
|
||||
| `caption` | 12 |
|
||||
|
||||
## content 内容模型
|
||||
## content Content Model
|
||||
|
||||
`<content>` 可出现在 `shape`、`table/td`、`note` 中,常用属性包括:
|
||||
`<content>` can appear inside `shape`, `table/td`, and `note`. Common attributes include:
|
||||
|
||||
| 属性 | 说明 |
|
||||
| Attribute | Description |
|
||||
|------|------|
|
||||
| `textType` | `title` / `headline` / `sub-headline` / `body` / `caption` |
|
||||
| `textAlign` | 文本对齐方式 |
|
||||
| `lineSpacing` | 行间距,schema 默认 `multiple:1.5` |
|
||||
| `fontSize` | 字号 |
|
||||
| `fontFamily` | 字体 |
|
||||
| `color` | 字体颜色 |
|
||||
| `bold` / `italic` / `underline` / `strikethrough` | 文本样式 |
|
||||
| `textAlign` | Text alignment |
|
||||
| `lineSpacing` | Line spacing, schema default `multiple:1.5` |
|
||||
| `fontSize` | Font size |
|
||||
| `fontFamily` | Font family |
|
||||
| `color` | Font color |
|
||||
| `bold` / `italic` / `underline` / `strikethrough` | Text styles |
|
||||
|
||||
`<content>` 的子元素只能是:
|
||||
The only allowed children of `<content>` are:
|
||||
|
||||
- `<p>`
|
||||
- `<ul>`
|
||||
- `<ol>`
|
||||
|
||||
### content 示例
|
||||
### content Example
|
||||
|
||||
```xml
|
||||
<content textType="body" textAlign="left">
|
||||
<p>正文内容 <strong>加粗</strong> <em>斜体</em> <a href="https://example.com">链接</a></p>
|
||||
<p>Body text <strong>bold</strong> <em>italic</em> <a href="https://example.com">link</a></p>
|
||||
<ul>
|
||||
<li><p>列表项 1</p></li>
|
||||
<li><p>列表项 2</p></li>
|
||||
<li><p>List item 1</p></li>
|
||||
<li><p>List item 2</p></li>
|
||||
</ul>
|
||||
</content>
|
||||
```
|
||||
|
||||
## data 常用元素
|
||||
## Common data Elements
|
||||
|
||||
### shape
|
||||
|
||||
@@ -109,14 +109,14 @@ XSD 中的 `title`、`headline`、`sub-headline`、`body`、`caption` 主要出
|
||||
</shape>
|
||||
```
|
||||
|
||||
| 属性 | 必需 | 说明 |
|
||||
| Attribute | Required | Description |
|
||||
|------|------|------|
|
||||
| `type` | 是 | 形状类型,`text` 表示文本框 |
|
||||
| `topLeftX` | 是 | 左上角 X 坐标 |
|
||||
| `topLeftY` | 是 | 左上角 Y 坐标 |
|
||||
| `width` | 是 | 宽度 |
|
||||
| `height` | 是 | 高度 |
|
||||
| `rotation` | 否 | 旋转角度 |
|
||||
| `type` | Yes | Shape type; `text` means a text box |
|
||||
| `topLeftX` | Yes | Top-left X coordinate |
|
||||
| `topLeftY` | Yes | Top-left Y coordinate |
|
||||
| `width` | Yes | Width |
|
||||
| `height` | Yes | Height |
|
||||
| `rotation` | No | Rotation angle |
|
||||
|
||||
### line
|
||||
|
||||
@@ -132,9 +132,9 @@ XSD 中的 `title`、`headline`、`sub-headline`、`body`、`caption` 主要出
|
||||
<img src="file_token_or_url" topLeftX="80" topLeftY="120" width="320" height="180"/>
|
||||
```
|
||||
|
||||
`src` 只支持:`slides +media-upload` 返回的 `file_token`,或 `@<本地路径>` 占位符(仅 `+create --slides` 自动上传并替换)。**禁止使用 http(s) 外链 URL**——飞书 slides 渲染端不会代理外链图,外链 src 在 PPT 里通常不显示。本地图片详见 [lark-slides-create.md](lark-slides-create.md#本地图片path-占位符) / [lark-slides-media-upload.md](lark-slides-media-upload.md)。
|
||||
`src` only supports: a `file_token` returned by `slides +media-upload`, or an `@<local path>` placeholder (auto-uploaded and substituted only by `+create --slides`). **Never use external http(s) URLs** — the Feishu slides renderer does not proxy external images, and an external-link src usually does not display in the deck. For local images see [lark-slides-create.md](lark-slides-create.md#local-images-path-placeholders) / [lark-slides-media-upload.md](lark-slides-media-upload.md).
|
||||
|
||||
> **注意**:`width`/`height` 是**裁剪后**的显示尺寸。比例和原图不一致时会自动裁剪(无法靠属性关闭),想避免裁剪就让 `width:height` 对齐原图比例。
|
||||
> **Note**: `width`/`height` are the **post-crop** display dimensions. If the aspect ratio differs from the original image, it is auto-cropped (cannot be disabled via attributes); to avoid cropping, make `width:height` match the original image's aspect ratio.
|
||||
|
||||
### icon
|
||||
|
||||
@@ -146,12 +146,12 @@ XSD 中的 `title`、`headline`、`sub-headline`、`body`、`caption` 主要出
|
||||
</icon>
|
||||
```
|
||||
|
||||
`iconType` 必须来自已验证的 IconPark 路径;视觉 lint 规范要求 `fillColor` 显式设置为非透明颜色,避免图标不可见。需要语义图标时,先运行 `scripts/iconpark_tool.py search --query "<语义>"`,不要凭记忆拼路径。更多规则见 [iconpark.md](iconpark.md)。
|
||||
`iconType` must come from a verified IconPark path; the visual lint spec requires `fillColor` to be explicitly set to a non-transparent color to avoid invisible icons. When you need a semantic icon, run `scripts/iconpark_tool.py search --query "<semantic>"` first — do not compose paths from memory. See [iconpark.md](iconpark.md) for more rules.
|
||||
|
||||
### whiteboard
|
||||
|
||||
```xml
|
||||
<!-- SVG 模式:<chart> 不支持的图表或自定义视觉、装饰元素 -->
|
||||
<!-- SVG mode: charts not supported by <chart>, custom visuals, decorative elements -->
|
||||
<whiteboard topLeftX="580" topLeftY="120" width="340" height="280">
|
||||
<svg xmlns="http://www.w3.org/2000/svg">
|
||||
<rect x="60" y="80" width="40" height="140" rx="3" fill="rgba(59,130,246,0.85)"/>
|
||||
@@ -159,24 +159,24 @@ XSD 中的 `title`、`headline`、`sub-headline`、`body`、`caption` 主要出
|
||||
</svg>
|
||||
</whiteboard>
|
||||
|
||||
<!-- Mermaid 模式:流程图、时序图等结构化图表 -->
|
||||
<!-- Mermaid mode: flowcharts, sequence diagrams, and other structured diagrams -->
|
||||
<whiteboard topLeftX="72" topLeftY="100" width="816" height="340">
|
||||
<mermaid>
|
||||
<![CDATA[
|
||||
flowchart LR
|
||||
A[开始] --> B{判断}
|
||||
B -- 是 --> C[执行]
|
||||
B -- 否 --> D[结束]
|
||||
A[Start] --> B{Decision}
|
||||
B -- Yes --> C[Execute]
|
||||
B -- No --> D[End]
|
||||
]]>
|
||||
</mermaid>
|
||||
</whiteboard>
|
||||
```
|
||||
|
||||
SVG 模式:`<svg>` 需声明 `xmlns="http://www.w3.org/2000/svg"`,内容大小由子元素包围盒决定;`width`/`height`/`viewBox` 不影响渲染,仅当元素使用百分比属性值时需声明 `viewBox`。\
|
||||
Mermaid 模式:内容用 `<![CDATA[...]]>` 包裹,避免 `[`、`>`、`-->` 等字符破坏 XML 解析。\
|
||||
详细用法见 [lark-slides-whiteboard.md](lark-slides-whiteboard.md)。
|
||||
SVG mode: `<svg>` must declare `xmlns="http://www.w3.org/2000/svg"`; content size is determined by the bounding box of the child elements; `width`/`height`/`viewBox` do not affect rendering — declare `viewBox` only when elements use percentage attribute values.\
|
||||
Mermaid mode: wrap the content in `<![CDATA[...]]>` to prevent characters like `[`, `>`, `-->` from breaking XML parsing.\
|
||||
See [lark-slides-whiteboard.md](lark-slides-whiteboard.md) for detailed usage.
|
||||
|
||||
## 颜色与样式
|
||||
## Colors and Styles
|
||||
|
||||
### fill
|
||||
|
||||
@@ -192,7 +192,7 @@ Mermaid 模式:内容用 `<![CDATA[...]]>` 包裹,避免 `[`、`>`、`-->`
|
||||
<border color="rgb(43, 47, 54)" width="2" dashArray="solid"/>
|
||||
```
|
||||
|
||||
### 颜色格式
|
||||
### Color Formats
|
||||
|
||||
```xml
|
||||
<fillColor color="rgb(255, 0, 0)"/>
|
||||
@@ -201,12 +201,12 @@ Mermaid 模式:内容用 `<![CDATA[...]]>` 包裹,避免 `[`、`>`、`-->`
|
||||
<fillColor color="radial-gradient(circle at 50% 50%, rgb(255,0,0) 0%, rgb(0,0,255) 100%)"/>
|
||||
```
|
||||
|
||||
> **注意**:渐变色必须使用 `rgba()` 格式并带百分比停靠点,例如 `linear-gradient(135deg,rgba(30,60,114,1) 0%,rgba(59,130,246,1) 100%)`。使用 `rgb()` 或省略停靠点会导致服务端将其回退为白色。此规则对页面背景和 shape fill 均适用。
|
||||
> **Note**: Gradient colors must use the `rgba()` format with percentage stops, e.g. `linear-gradient(135deg,rgba(30,60,114,1) 0%,rgba(59,130,246,1) 100%)`. Using `rgb()` or omitting stops causes the server to fall back to white. This rule applies to both page backgrounds and shape fills.
|
||||
|
||||
### 页面背景
|
||||
### Page Background
|
||||
|
||||
```xml
|
||||
<!-- 纯色背景 -->
|
||||
<!-- Solid background -->
|
||||
<slide>
|
||||
<style>
|
||||
<fill>
|
||||
@@ -215,7 +215,7 @@ Mermaid 模式:内容用 `<![CDATA[...]]>` 包裹,避免 `[`、`>`、`-->`
|
||||
</style>
|
||||
</slide>
|
||||
|
||||
<!-- 渐变背景(必须用 rgba + 百分比停靠点) -->
|
||||
<!-- Gradient background (must use rgba + percentage stops) -->
|
||||
<slide>
|
||||
<style>
|
||||
<fill>
|
||||
@@ -225,25 +225,25 @@ Mermaid 模式:内容用 `<![CDATA[...]]>` 包裹,避免 `[`、`>`、`-->`
|
||||
</slide>
|
||||
```
|
||||
|
||||
## 备注示例
|
||||
## Note Example
|
||||
|
||||
```xml
|
||||
<note>
|
||||
<content textType="body">
|
||||
<p>这是演讲者备注。</p>
|
||||
<p>This is a speaker note.</p>
|
||||
</content>
|
||||
</note>
|
||||
```
|
||||
|
||||
## 详细参考
|
||||
## Detailed References
|
||||
|
||||
- [slides_xml_schema_definition.xml](slides_xml_schema_definition.xml)
|
||||
- [xml-format-guide.md](xml-format-guide.md)
|
||||
- [examples.md](examples.md)
|
||||
- [slides_demo.xml](slides_demo.xml)
|
||||
|
||||
## Schema 版本信息
|
||||
## Schema Version Info
|
||||
|
||||
- **版本**: 2.0.0
|
||||
- **命名空间**: http://www.larkoffice.com/sml/2.0
|
||||
- **发布日期**: 2025-11-03
|
||||
- **Version**: 2.0.0
|
||||
- **Namespace**: http://www.larkoffice.com/sml/2.0
|
||||
- **Release date**: 2025-11-03
|
||||
|
||||
Reference in New Issue
Block a user