
Onyx 技能开发实战用 gslides_api.py 通过 Google Slides API 读取与编辑演示文稿【免费下载链接】danswerOpen Source AI Platform - AI Chat with advanced features that works with every LLM项目地址: https://gitcode.com/GitHub_Trending/da/danswerGoogle Slides 是 Onyx原 danswer内置 Google Drive 技能中的三大办公文档能力之一。本指南以 slides.md 为核心围绕配套的 gslides_api.py 命令行封装器系统讲解如何读取演示文稿结构、按objectId精确定位页面元素、插入与替换文本、新建演示文稿并通过原始batchUpdate请求实现任意高级编辑。读完本文你将掌握这套面向 LLM/Agent 的 Slides 操作工具的完整命令集、参数语义与输出契约能够在 Onyx Craft 沙箱中直接驱动真实演示文稿的读写。一、定位Slides API 与 Drive 导出的分工在 Onyx 的 Google Drive 技能中drive.md 提供的gdrive_api.py read file_id会把 Google 原生文档自动导出为文本Docs 导出为 Markdown、Sheets 导出为 CSV、Slides 导出为纯文本。这种导出适合快速浏览内容但无法满足编辑需求——纯文本中没有页slide与元素shape、table、image的结构信息。gslides_api.py正是为此而生它直接调用https://slides.googleapis.com/v1/Slides REST API暴露每个 slide 和 page element 的objectId而这些objectId正是后续所有编辑操作插文本、替换文本、batchUpdate的寻址依据。这一点在 slides.md 开头有明确说明也是它与gdrive_api.py read的核心分工只想读内容→gdrive_api.py read导出纯文本简单直接需要结构、objectId 或任何编辑能力→ 本指南的gslides_api.py。配套的另外两个 per-API 指南提供了同类能力Google Docs 的get-doc/insert-text/batch-update见 docs.mdGoogle Sheets 的读写封装见 sheets.md。三者遵循完全一致的调用约定与输出风格掌握其一即可触类旁通。注意presentation_id就是演示文稿在 Drive 中的文件 idDrive file id与 Docs 的document_id、Sheets 的spreadsheet_id语义一致。id 参数同样接受完整的 Drive/URL 链接——封装器会为你自动提取 id参见gdrive_api.py的约定。二、调用约定路径、认证与写操作审批2.1 运行方式按 SKILL.md.template 的路径约定在会话工作区中运行python .opencode/skills/google-drive/gslides_api.py command [args]在仓库中的实际位置为backend/onyx/skills/builtin/google-drive/gslides_api.py开发调试时可直接运行python backend/onyx/skills/builtin/google-drive/gslides_api.py command [args]任意子命令都可用python gslides_api.py command -h查看该命令的具体参数源码中通过argparse的add_subparsers(destcmd, requiredTrue)构建了完整的子命令解析器见 gslides_api.py。2.2 认证与审批机制封装器自身不处理任何认证。脚本头部的模块 docstring 明确写道沙箱 egress proxy 会向请求注入当前已连接用户的 bearer tokenthe sandbox egress proxy injects the connected users bearer token。也就是说所有请求都以当前会话用户的身份发出遵循该用户对目标演示文稿的访问权限。读写权限有明显差异读操作get/text/page自由执行写操作create、add-slide、insert-text、replace-text、batch-update可能在 proxy 处暂停等待用户批准。因此在 Agent 工作流中写操作应视为可能触发人工确认的步骤来设计。2.3 底层请求实现从源码看所有命令最终都收敛到同一个_req_json函数gslides_api.py基础地址固定为_BASE https://slides.googleapis.com/v1/请求超时统一为_HTTP_TIMEOUT_SECONDS 180秒路径段通过_seg做 URL 编码urllib.parse.quote(value, safe)因为演示文稿 id 可能包含特殊字符参数中的None值会被过滤GET 用查询串拼接POST 用 JSON 序列化 body 并附带Content-Type: application/json; charsetutf-8。所有写命令最终都调用_batch_update(presentation_id, requests)即向presentations/{id}:batchUpdate发送{requests: [...]}gslides_api.py。三、读取演示文稿get / text / page读取命令有三个覆盖结构、纯文本、单页详情三种粒度python gslides_api.py get presentation_id [--fields ...] python gslides_api.py text presentation_id python gslides_api.py page presentation_id page_object_id3.1get紧凑结构视图返回演示文稿的紧凑结构视图包含幻灯片列表、每个元素的objectId、形状文本等内容足够支撑后续定位编辑又不会携带庞大的样式/变换transform载荷。默认字段选择器定义在源码的_DEFAULT_GET_FIELDSgslides_api.pypresentationId,title,revisionId, slides(objectId,pageElements(objectId,title, shape(shapeType,placeholder(type,index), text(textElements(textRun(content)))), table(rows,columns),image(contentUrl)))可以看到默认视图刻意精选了顶层presentationId、title、revisionId每页 slide自身的objectId每个 pageElementobjectId、title形状shapeshapeType如RECTANGLE、TEXT_BOX、placeholder的type/index区分标题、正文、页码等占位符、text的文本运行内容表格tablerows/columns图片imagecontentUrl。--fields可覆盖默认值。传入空字符串表示返回整个演示文稿的完整结构不裁剪字段。这种字段选择器语法是 Slides API 的原生能力可以按需扩展到任意结构。3.2text逐页纯文本返回每页的纯文本。实现上使用_TEXT_FIELDS title,slides(objectId,pageElements)拉取完整的pageElements再由_element_text递归提取文本gslides_api.py形状文本shape.text下所有textRun.content拼接表格单元格遍历table.tableRows下每个tableCells的text组合元素递归处理elementGroup.children。之所以这里要拉完整pageElements是因为 Slides 的 fields 语法无法表达任意深度递归的分组元素而较大的载荷在提取文本后被丢弃不会进入 LLM 上下文源码注释Only the extracted text is emitted, so the larger payload never reaches the LLM。3.3page单页全量结构按page_object_id返回某一页的完整结构默认不加字段裁剪--fields可指定。当需要精确定位某页内的元素、查看该页全部样式与变换信息时使用。3.4 输出示例get返回{ok: true, presentation: {...}}page返回{ok: true, page: {...}}text返回{ok: true, title: ..., slides: [{index: 0, objectId: ..., text: ...}]}四、创建与扩展演示文稿create / add-slide写操作从零开始建 deck 或追加新页python gslides_api.py create --title Roadmap python gslides_api.py add-slide presentation_id [--layout TITLE_AND_BODY]4.1create新建演示文稿--title为必填参数。底层调用POST presentationsbody 为{title: a.title}gslides_api.py。返回{ok: true, presentation: {...}}其中包含新演示文稿的presentationId供后续命令引用。4.2add-slide按预设布局追加页面--layout指定 Slides API 的预定义布局predefinedLayout默认值为BLANK。源码 help 中列出的常用取值gslides_api.py布局取值说明BLANK空白页默认TITLE仅标题TITLE_AND_BODY标题 正文SECTION_HEADER章节标题页...其余取值取决于所用模板底层实现构造单个createSlide请求{createSlide: {slideLayoutReference: {predefinedLayout: TITLE_AND_BODY}}}并通过_batch_update发送。返回中会从replies[0].createSlide.objectId提取新页的objectId{ok: true, objectId: ..., data: {...}}拿到新页objectId后即可配合insert-text或batch-update填充该页内容。五、文本编辑insert-text / replace-textpython gslides_api.py insert-text presentation_id shape_object_id --text ... python gslides_api.py replace-text presentation_id --find {{name}} --replace Ada5.1insert-text向指定形状插入文本insert-text需要形状的objectId从get的结果中获取。参数与底层请求位置参数presentation_id、object_id目标形状 objectId--text必填要插入的文本--index可选字符插入位置默认 0即从形状文本开头插入typeint。底层构造的请求为gslides_api.py{insertText: {objectId: shape_object_id, insertionIndex: 0, text: ...}}注意与 Google Docs 的insert-text按文档字符 index 定位不同Slides 的插入是目标形状 objectId 形状内字符索引二维寻址——这正是get先取结构的原因。5.2replace-text全篇替换占位符replace-text是填充占位符文本的可靠方式它使用 Slides API 的replaceAllText一次性替换整个演示文稿中的每一处匹配而不是只改一处。--find/--replace均为必填--match-case可选开关开启后大小写敏感匹配默认大小写不敏感。底层请求为gslides_api.py{replaceAllText: { containsText: {text: {{name}}, matchCase: false}, replaceText: Ada }}典型的模板化场景create建页 →insert-text或add-slide铺好带{{name}}、{{date}}占位符的形状 → 多次replace-text一次性填充全部占位符完成整份演示文稿的批量生成。六、原始 batchUpdate万能逃生舱python gslides_api.py batch-update presentation_id [request, ...] python gslides_api.py batch-update presentation_id --file requests.json6.1 请求载荷规则batch-update接受一个JSON 数组数组中的每个元素是一个 Slides API 请求对象随{requests: [...]}发送到presentations/{id}:batchUpdate端点。载荷可以内联传入也可以放在文件中用--file指定——二者只能二选一同时给出会报错源码_load_json_arg明确校验gslides_api.py若都不是合法 JSON 数组会返回requests must be a JSON array of request objects错误。6.2 支持的请求类型原文档列出的常用请求类型包括slides.md 与源码 help 相互印证createShape—— 新建形状createTable—— 新建表格updateTextStyle—— 修改文本样式字号、加粗、颜色等deleteObject—— 删除页面元素updatePageElementTransform—— 调整元素位置/缩放/旋转此外还有createSlide、insertText同前文、replaceAllText、createSheets新建幻灯片组等完整 Slides 请求集。由于batch-update直接透传原生请求对象凡是 Slides API 支持的操作都可以在此表达因此它是覆盖其余一切的逃生舱escape hatch。6.3 组合示例内联传多个请求例如先建一个文本框再写入文字python gslides_api.py batch-update presentation_id [ {createShape: {objectId: TextBox1, shapeType: TEXT_BOX, elementProperties: {pageObjectId: page_object_id, size: {height: {magnitude: 3000000, unit: EMU}, width: {magnitude: 3000000, unit: EMU}}, transform: {scaleX: 1, scaleY: 1, translateX: 100000, translateY: 100000, unit: EMU}}}}, {insertText: {objectId: TextBox1, insertionIndex: 0, text: Hello from Onyx}} ]更复杂的请求集合建议写入requests.json文件后用--file传入便于复用与版本管理。七、输出契约与错误处理7.1 统一的 JSON 输出所有命令都在 stdout 输出 JSON命令返回结构create{ok: true, presentation: {...}}get{ok: true, presentation: {...}}page{ok: true, page: {...}}text{ok: true, title: ..., slides: [{index, objectId, text}]}add-slide{ok: true, objectId: ..., data: {...}}insert-text/replace-text/batch-update{ok: true, data: {...}}7.2 空字段裁剪与--raw默认情况下输出会经过_prune递归删除None//[]/{}等空值gslides_api.py让 LLM 面对的输出尽量精简——注意布尔值与 0 会被保留源码注释Booleans and 0 are kept — they carry signal。传入--raw可跳过裁剪拿到完整原始响应。7.3 退出码与错误信息错误统一输出到 stderr 并返回非零退出码main函数中的异常处理gslides_api.py退出码2--file指向的文件不存在FileNotFoundError退出码1参数校验错误ValueError、JSON 解析失败、HTTPError打印HTTP code calling Google Slides: detail包含 Google 返回的错误详情、网络错误URLError打印network error calling Google Slides: ...。一次成功的调用返回{ok: true, ...}并退出0。Agent 编排时可根据退出码与 stderr 内容区分参数错误 / 文件缺失 / HTTP 服务端错误 / 网络错误从而决定重试还是向用户求助。7.4 一个常见的 404 陷阱结合 SKILL.md.template 的云部署说明当部署的 Google Drive 授权为每文件粒度drive.file时gdrive_api.py的search/read只能看到 Onyx 自己创建的文件对权限外的文件Drive API 会返回HTTP 404 File not found而非 403。但Docs、Sheets、Slides API 不受 per-file 授权限制——它们可以访问用户能打开的任何同类型文件。因此拿到一个 Slides 链接或 id 时即使gdrive_api.py read报 404也应直接尝试gslides_api.py get/text很可能依然可用而空search结果也不代表文件不存在可能只是超出授权范围。这正是per-API 指南存在的意义。八、端到端实战流程把以上命令串起来一个由 Agent 自动生成演示文稿的典型工作流如下Step 1 —— 新建演示文稿python gslides_api.py create --title Q3 Roadmap记录返回中的presentationId。Step 2 —— 追加标题页与正文页python gslides_api.py add-slide presentation_id --layout TITLE_AND_BODY python gslides_api.py add-slide presentation_id --layout TITLE_AND_BODY记录每次返回的objectId分别为 slide A、slide B 的 id。Step 3 —— 查看结构取得形状 objectIdpython gslides_api.py get presentation_id在返回的slides[].pageElements[].objectId中挑出标题 shape 与正文 shape可通过placeholder.type区分如TITLE/BODY。Step 4 —— 填充占位符文本python gslides_api.py replace-text presentation_id --find {{title}} --replace Q3 产品路线图 python gslides_api.py replace-text presentation_id --find {{milestone}} --replace 发布 2.0Step 5 —— 复杂元素用 batchUpdate 兜底需要插入表格、调整元素位置或删除某个占位元素时构造请求数组交给batch-update。Step 6 —— 校验结果用text快速核验各页文本是否符合预期必要时用get复查结构。九、相关资源技能总览与路径/权限约定SKILL.md.templateSlides 封装器源码gslides_api.py本文档原始版slides.mdDrive 文件读写与纯文本导出gdrive_api.py readdrive.mdGoogle Docs 结构编辑按字符索引操作docs.mdGoogle Sheets 单元格读写sheets.mdgsheets_api.py【免费下载链接】danswerOpen Source AI Platform - AI Chat with advanced features that works with every LLM项目地址: https://gitcode.com/GitHub_Trending/da/danswer创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考