---
name: feishu-cli-slides
description: >-
飞书 Slides 演示文稿。slides create 从 XML 模板创建演示文稿(POST /open-apis/slides_ai/v1/xml_presentations);
slides media-upload 上传媒体(drive upload_all + parent_type=slide_file,单文件 ≤20MB 不支持分片)。
当用户请求"创建飞书 ppt"、"上传幻灯片"、"演示文稿"、"slides"时使用。
不适用:复杂 slide 编辑(block insert/replace 复杂语义)暂未实现,走 lark-slides。
argument-hint: create | media-upload
user-invocable: true
allowed-tools: Bash(feishu-cli slides:*), Bash(feishu-cli auth:*), Read
---
# 飞书 Slides 演示文稿技能
通过 `feishu-cli slides` 创建空白演示文稿,并把本地图片以 `slide_file` 媒体形式上传到该演示文稿,
返回的 `file_token` 可直接在 slide XML 中作为 `
` 引用。
> **feishu-cli**:如尚未安装,请前往 [riba2534/feishu-cli](https://github.com/riba2534/feishu-cli) 获取安装方式。
> **范围声明**:本技能只覆盖「创建空白演示文稿」+「上传媒体」两个最小可用动作。如需在已有
> 演示文稿里做复杂 slide 编辑(block insert/replace 等),目前 CLI 未实现,请改走
> 官方 `lark-slides` 客户端或 OpenAPI 直调。
## 核心概念
### 两种产物分别是什么
| 命令 | 调用的 API | 产物 | 用途 |
|------|------------|------|------|
| `slides create` | `POST /open-apis/slides_ai/v1/xml_presentations` | `xml_presentation_id` | 后续所有 slides 操作的 ID(不是普通 docx token) |
| `slides media-upload` | `POST /open-apis/drive/v1/medias/upload_all` (`parent_type=slide_file`) | `file_token` | 可直接放进 slide XML 的 `
` |
**关键约束**:
- `slide_file` 是 slides 后端唯一接受的 `parent_type`(lark-cli 实测:`slide_image` / `slides_image` /
`slides_file` 都会被拒)
- `parent_node` 必须传 `xml_presentation_id`(而不是 docx token 或 file_token)
- 上传走单分片 `upload_all`,**不支持** `upload_prepare` 多分片,所以单文件硬限 20 MB
### XML 模板格式(create 内部)
`slides create` 在 CLI 内部用 `--title/--width/--height` 拼成最小可用 XML 模板再 POST:
```xml
演示文稿标题
```
> 当前版本不暴露 `--xml-file` 参数让你直接传整个 presentation XML——只能通过 `--title/--width/--height`
> 影响这个最小模板。如需复杂初始内容,先 `create` 拿到 `xml_presentation_id`,再走 lark-slides
> 或后续 CLI 扩展。
## 前置条件
- **认证**:默认走 **App Token**(租户身份),通过 `--user-access-token` 或 `FEISHU_USER_ACCESS_TOKEN`
可切换 User Token(推荐用 User Token,以个人身份创建,便于后续直接在飞书里编辑)
- **权限**:
| 命令 | 所需 scope |
|------|-----------|
| `slides create` | `slides:presentation:create` 或 `slides:presentation:write_only` |
| `slides media-upload` | `docs:document.media:upload` |
- **预检**:`feishu-cli auth check --scope "slides:presentation:create docs:document.media:upload"`
## 命令速查
### 1. `slides create` — 创建空白演示文稿
```bash
# 最简用法(默认尺寸 960x540,title="Untitled")
feishu-cli slides create
# 指定标题
feishu-cli slides create --title "Q2 OKR"
# 自定义宽高(像素)
feishu-cli slides create --title "Wide Deck" --width 1920 --height 1080
# JSON 输出(脚本接力时常用,方便 jq 取 xml_presentation_id)
feishu-cli slides create --title "Demo" --output json
# 以用户身份创建(推荐,演示文稿归属个人)
feishu-cli slides create --title "Demo" --user-access-token
```
**关键参数**:
| 参数 | 说明 | 默认值 |
|------|------|--------|
| `--title`, `-t` | 演示文稿标题 | `Untitled` |
| `--width` | 幻灯片宽度(像素) | `960` |
| `--height` | 幻灯片高度(像素) | `540` |
| `--output`, `-o` | 输出格式(留空 = 文本摘要,`json` = JSON) | 文本摘要 |
| `--user-access-token` | 显式传 User Token | 不传走 App Token |
> **两层默认值分工**:`--title` 在 cobra flag 注册时默认为空字符串、`--width/--height` 注册为 `0`
> (见 `cmd/slides_create.go:78-80`);运行时由 client 层(`internal/client/slides.go:49-58`)
> 把空 title 注入为 `Untitled`、把非正数尺寸注入为标准 16:9 的 `960x540`。所以「未传」≠「传 0」≠「报错」,
> 三者最终都会走到同一个默认值。
**返回**:
```
Slides 演示文稿已创建:
xml_presentation_id:
title: Q2 OKR
revision_id: 1
```
`xml_presentation_id` 就是后续 `media-upload --presentation-token` 要传的值。
### 2. `slides media-upload` — 上传媒体到演示文稿
```bash
# 上传封面图
feishu-cli slides media-upload \
--file ./cover.png \
--presentation-token
# JSON 输出,方便 jq 接力拿 file_token
feishu-cli slides media-upload \
--file ./cover.png \
--presentation-token \
--output json
```
**关键参数**:
| 参数 | 说明 | 必填 |
|------|------|------|
| `--file` | 本地图片路径(**≤ 20 MB**) | 是 |
| `--presentation-token` | 目标演示文稿的 `xml_presentation_id` | 是 |
| `--output`, `-o` | 输出格式(留空 = 文本摘要,`json` = JSON) | 否 |
| `--user-access-token` | 显式传 User Token | 否 |
**返回**:
```
图片上传成功:
file_token:
file_name: cover.png
size: 123456 bytes
presentation_id:
提示: 在 slide XML 中可用作
```
## 典型工作流
### 工作流 A:创建 + 上传封面图(端到端)
```bash
# 1. 创建空白演示文稿
PRES_ID=$(feishu-cli slides create --title "Q2 OKR" --output json | jq -r '.xml_presentation_id')
# 2. 上传封面图,拿到 file_token
FILE_TOKEN=$(feishu-cli slides media-upload \
--file ./cover.png \
--presentation-token "$PRES_ID" \
--output json | jq -r '.file_token')
# 3. 现在 $FILE_TOKEN 可以拼到 slide XML 的
里
echo "presentation: $PRES_ID, cover: $FILE_TOKEN"
```
### 工作流 B:批量上传一组图片
```bash
PRES_ID=$(feishu-cli slides create --title "Photo Deck" --output json | jq -r '.xml_presentation_id')
for img in ./assets/*.png; do
feishu-cli slides media-upload \
--file "$img" \
--presentation-token "$PRES_ID" \
--output json | jq -r '"\(.file_name) -> \(.file_token)"'
done
```
## 何时转用其他工具
| 场景 | 改走 |
|------|------|
| 在已有演示文稿里插入/修改/删除 slide 或 block | `lark-slides`(官方 CLI)或 OpenAPI 直调 `slides_ai/v1/...` 编辑接口 |
| 直接传整个 presentation XML 模板 | 暂未暴露 `--xml-file`,等 CLI 扩展或 OpenAPI 直调 |
| 单文件 > 20 MB 的媒体 | 拆分小图,或直接走飞书客户端上传 |
| 把 markdown / docx 转成 slides | 暂不支持,建议先转 docx 再用飞书客户端导出 |
| 普通文档(不是演示文稿)上传媒体 | 走 **feishu-cli-drive** 技能(`drive upload`) |
## 注意事项
- **`parent_type` 不要乱改**:源码里硬编码 `slide_file`,且经 lark-cli 实测唯一可用值。
自己改成 `slide_image` / `slides_image` / `slides_file` 都会被服务端拒绝
- **20 MB 上限不可绕过**:`upload_prepare` 多分片接口**不接受** `parent_type=slide_file`,
CLI 在 client 侧也做了 20 MB 硬检查,超过会在本地直接报错(不会发请求)
- **`xml_presentation_id` ≠ docx token**:这是 slides 模块独立的标识符,不要拿去当
`docx:document_id` 或 `drive:file_token` 用
- **User Token vs App Token**:默认 App Token(Bot 身份),演示文稿归 Bot 所有,普通人在
飞书 UI 里看不到。**推荐传 `--user-access-token`** 让产物归个人,能直接在「我的空间」找到
- **图片格式**:常见 png/jpg/jpeg/gif/webp 等,由 `medias/upload_all` 自动推断 MIME
## 错误排查
| 错误 | 原因 | 解决 |
|------|------|------|
| `--file 不能为空` / `--presentation-token 不能为空` | 必填参数缺失 | 检查命令行参数 |
| `读取文件失败` / `--file 必须是普通文件` | 路径错或不是 regular file | 检查路径、不要传符号链接到目录 |
| `文件 X 大小 Y 字节超过 slides 上传限制(20 MB)` | 文件超过 20 MB | 压缩 / 切分,slides 后端硬限不可绕过 |
| `创建 slides 失败: code=99991663, msg=...` | scope 不够 | `auth check --scope "slides:presentation:create"` 然后重新 `auth login --domain slides --recommend` |
| `创建 slides 失败: HTTP 400, body: ...invalid xml_presentation...` | XML 模板异常(一般 title 含未转义字符触发) | CLI 已做 XML escape,若仍出现请 issue |
| 上传报 `parent_type invalid` 或类似 | 走的不是 `slide_file`(如直接 curl 调 medias/upload_all 时传错) | 用 CLI 而不是手敲 curl,CLI 已锁定 `slide_file` |
## 参考
- API 文档:飞书开放平台「智能演示」/「云文档 - 素材」
- 代码:`cmd/slides_create.go` / `cmd/slides_media_upload.go` / `internal/client/slides.go`
- 上游 PR:[feishu-cli#135](https://github.com/riba2534/feishu-cli/pull/135)