news 2026/9/10 12:18:40

用 Onyx(danswer)内置 google-drive 技能的 Docs 命令精修 Google 文档

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用 Onyx(danswer)内置 google-drive 技能的 Docs 命令精修 Google 文档

用 Onyx(danswer)内置 google-drive 技能的 Docs 命令精修 Google 文档

【免费下载链接】danswerOpen Source AI Platform - AI Chat with advanced features that works with every LLM项目地址: https://gitcode.com/GitHub_Trending/da/danswer

在 Onyx(danswer)的技能体系中,Google Docs 命令指南 专门讲解如何通过gdrive_api.py脚本,借助 Google Docs API(https://docs.googleapis.com/v1/,注意与 Drive API 是不同的主机)对 Google Doc 进行基于字符索引的精细化编辑:插入/删除文本、重设段落样式、添加项目符号,以及从零创建新文档。读完本文,你将掌握get-docinsert-textappend-textbatch-updatecreate-doc五个子命令的完整用法、其底层请求构造原理,以及如何用仓库中的单元测试验证这些行为。

为什么需要独立的 Docs 命令

Google Drive 的命令(searchlistread等)走的是https://www.googleapis.com/drive/v3/,它们擅长“按文件粒度”操作:查找文件、读取内容、上传下载。但Doc 内部是结构化的——一段文字、一个段落、一个列表项都对应一个可寻址的字符区间。gdrive_api.py read只能把整篇文档“导出成文本”,无法告诉你“第 10 个字符在哪一段、该往哪个索引插内容”。

Docs 命令解决的就是这个缺口:

  • 先通过get-doc拉取文档的结构骨架body.content,每个元素带startIndex/endIndex);
  • 再用这些索引构造insertTextdeleteContentRangeupdateParagraphStyle等请求,通过batchUpdate精确落笔。

在源码中,这一设计直接体现为两个不同的 API 基地址常量,见 gdrive_api.py:

_BASE = "https://www.googleapis.com/drive/v3/" _UPLOAD_BASE = "https://www.googleapis.com/upload/drive/v3/" # The Google Docs API lives on a different host than Drive; surgical edits to an # existing Doc (get structure / batchUpdate) go here, not through the Drive base. _DOCS_BASE = "https://docs.googleapis.com/v1/"

单元测试 test_gdrive_api_helper.py 专门断言了这一点:test_docs_base_targets_docs_host验证 Docs 命令必须命中docs.googleapis.com/v1/documents/D1:batchUpdate而非 Drive 主机。

重要约定:所有 Docs 命令中的<document_id>就是该 Doc 在 Drive 中的文件 ID,不是文档标题。

运行方式与前置知识

脚本的通用调用形式为(所有子命令一致):

python .opencode/skills/google-drive/gdrive_api.py <command> [args]

在会话工作区中按上述路径运行;运行python gdrive_api.py <command> -h可查看具体命令的全部参数。

鉴权与写操作审批

gdrive_api.py本身不处理任何鉴权:连接用户的 bearer token 由沙箱出口代理(sandbox egress proxy)在请求时注入;而写操作(create/upload/edit/delete)可能在代理层暂停等待用户批准,这在脚本的模块 docstring 中有明确说明(见 gdrive_api.py)。因此在使用编辑类命令时,应预期可能出现一次用户确认环节。

文档 ID 参数:裸 ID 与完整 URL 均可

所有document_id类参数都经过_id_arg归一化(gdrive_api.py):接受裸 ID,也接受形如https://docs.google.com/document/d/<id>/edithttps://drive.google.com/drive/folders/<id>?id=<id>分享链接,自动提取其中的 ID 段。这意味着 Agent 可以直接把用户粘贴的链接原样传给命令。参数化测试 test_id_arg_accepts_urls_and_bare_ids 覆盖了 7 种 URL 形态。

输出瘦身

所有命令默认会对返回 JSON 做空字段裁剪_prune,递归丢弃None/""/[]/{},保留布尔值与 0),见 gdrive_api.py;传入--raw可跳过裁剪。

get-doc:先读结构,拿到编辑所需的字符索引

python gdrive_api.py get-doc <document_id> [--fields "documentId,body,title"]

get-doc返回文档body.content结构,每个结构元素都带startIndex/endIndex——这是后续所有精确编辑的“坐标系统”。--fields用于裁剪返回字段,默认返回整篇文档。

多标签页文档(tabs)

Docs 支持多标签页(tab)结构,而body字段只承载第一个 tab 的内容。若需读取每个 tab 的内容,加--tabs参数,所有 tab 的内容会出现在tabs[]下:

python gdrive_api.py get-doc <document_id> --tabs

其底层实现(gdrive_api.py)会:

  1. 设置查询参数includeTabsContent=true(没有它,响应里的body只含第一个 tab);
  2. 若同时指定了--fields而字段掩码中不含tabs,会自动追加tabs,否则字段掩码会把请求到的 tab 内容过滤掉。

这一点由测试 test_get_doc_tabs_flag_requests_tab_content 与 test_get_doc_tabs_extends_a_caller_field_mask 双重验证:前者断言请求参数为{"includeTabsContent": "true"},后者验证字段掩码"documentId,title"会被扩展为"documentId,title,tabs"且不会重复追加。

insert-text:在指定字符索引处插入文本

python gdrive_api.py insert-text <document_id> --index N --text "..."

这是最直接的写操作:向documents/<id>:batchUpdate发送一条insertText请求,把文本插到字符索引N处(Nget-doc获取)。其请求构造见 gdrive_api.py:

requests = [{"insertText": {"location": {"index": a.index}, "text": a.text}}] resp = _batch_update(a.document_id, requests)

注意命令行的--index帮助文本将其描述为“字符索引”(1-based character index),实际语义以get-doc返回的startIndex/endIndex为准。测试 test_insert_text_builds_batch_update_request 验证了insert-text D1 --index 5 --text hello会生成{"requests": [{"insertText": {"location": {"index": 5}, "text": "hello"}}]}并 POST 到documents/D1:batchUpdate

append-text:免手算索引的“追加到末尾”

python gdrive_api.py append-text <document_id> --text "..."

如果不关心具体位置、只想把内容加到正文末尾,append-text会自动完成两件事:先get-doc取结构,计算正文结束索引,再在该处插入——完全不需要手动指定索引。

其实现(gdrive_api.py)有一个值得注意的边界处理:

doc = _get_doc(a.document_id, fields="body(content(endIndex))") end = _doc_end_index(doc) # Insert just before the final newline of the body to stay in range. index = max(1, end - 1)

_doc_end_index(gdrive_api.py)取正文最后一个结构元素的endIndex作为文档末端,然后end - 1处插入:因为 Docs 正文末尾固定存在一个换行符,越过它插入会越界报错,所以落在其紧前位置才是合法的插入点。空文档时索引退化为max(1, 1 - 1) = 1

测试 test_append_text_computes_end_index_from_get_doc 精确验证了这一逻辑:当get-doc返回的最后一个元素endIndex为 42 时,最终在索引 41 插入,并且结果会附带index字段回显计算值;test_doc_end_index_defaults_to_one_for_empty_body 则确认空文档时索引为 1。

batch-update:直接下发原始 Docs 请求(万能逃生通道)

# 内联 JSON 数组 python gdrive_api.py batch-update <document_id> '[<request>, ...]' # 或从文件读取请求数组 python gdrive_api.py batch-update <document_id> --file requests.json

insert-text/append-text不够用时,batch-update让你直接发送任意Docs API 请求对象数组,脚本会原样包装为{"requests": [...]}发到documents/<id>:batchUpdate(gdrive_api.py)。它支持完整的 Docs 请求集合,例如:

  • insertText— 插入文本
  • deleteContentRange— 删除某字符区间
  • updateParagraphStyle— 重设段落样式
  • createParagraphBullets— 添加项目符号
  • updateTextStyle— 修改文字样式

官方示例:加粗一段文字并转成项目符号

python gdrive_api.py batch-update <document_id> '[ {"updateTextStyle": {"range": {"startIndex": 1, "endIndex": 10}, "textStyle": {"bold": true}, "fields": "bold"}}, {"createParagraphBullets": {"range": {"startIndex": 1, "endIndex": 10}, "bulletPreset": "BULLET_DISC_CIRCLE_SQUARE"}} ]'

两条请求作用于同一个字符区间[1, 10):第一条把区间内文字设为粗体(fields指定只更新bold属性),第二条把该区间对应的段落套用BULLET_DISC_CIRCLE_SQUARE预设的项目符号样式。

请求校验与错误返回

batch-update在下发前会做两项防御性校验(gdrive_api.py):请求体缺失时返回{"ok": false, "error": "no_requests"};JSON 解析失败或不是数组时分别返回invalid requests json: ...requests_not_array,且不会触发网络调用。测试 test_batch_update_rejects_non_array 用'{"a": 1}'验证了这一点;test_batch_update_passes_through_requests_array 与 test_batch_update_reads_requests_from_file 则分别覆盖了内联 JSON 与--file两种输入路径。

create-doc:创建空白新文档

python gdrive_api.py create-doc --title "My Doc"

通过 Docs API 的POST documents创建一个空白 Doc 并返回其documentId(实现见 gdrive_api.py,请求体仅含{"title": ...},测试 test_create_doc_posts_title 验证了这一点)。拿到新 ID 后,再组合insert-text/append-text/batch-update填入内容即可完成“从零造文档”的完整流程。

两种建文档方式的取舍

场景推荐方式
已有 Markdown / HTML 内容,想直接得到渲染好的 Docupload --convert-to application/vnd.google-apps.document(Drive 命令,详见 drive.md)
内容需要程序化、按索引精雕细琢地写入create-doc+insert-text/batch-update

upload --convert-to走 Drive 的上传转换路径(_UPLOAD_BASE,multipart/related 上传,见 gdrive_api.py),适合“批量导入既有文档”;而 Docs 命令适合“在会话中逐步构造内容”。注意_CONTENT_TYPES映射(gdrive_api.py)中.md显式映射为text/markdown——因为标准库mimetypes依赖平台且常常漏掉.md,这正是 Drive 把 Markdown 转成 Google Doc 所必需的。

输出格式约定

两类返回结构(详见原文档):

  • get-doc/create-doc返回:{"ok": true, "document": {...}}
  • insert-text/append-text/batch-update返回:{"ok": true, "data": {...}};其中append-text额外回显计算出的插入位置:{"ok": true, "index": N, "data": {...}}

所有输出均以 JSON 打印到 stdout,通过{"ok": ...}表达成败;错误信息打印到 stderr 并以非零码退出(gdrive_api.py)。main中的异常处理对不同失败类型做了区分:

  • HTTP 错误会打印HTTP <code> calling <Google Docs | Google Drive>: <detail>,并按请求目标自动区分 API 归属;
  • 对 Drive 的 404 会附加一条提示:Drive 对“不存在的 ID”和“当前授权不可见的文件”都返回 404,此时该文件可能仍可通过其专属 API(如 Docs 的get-docgsheets_api.pygslides_api.py)访问;
  • 网络错误、非 JSON 响应、文件缺失也各有明确的 stderr 信息与退出码。

在技能体系中的位置

google-drive是 Onyx 的内置外部应用技能ExternalAppBuiltInProvider,见 built_in.py),其SKILL.md.template的快速参考表把任务分派给四个指南文件(SKILL.md.template):

任务指南
查找、读取、上传、整理、删除任意 Drive 文件drive.md —gdrive_api.py
精细化编辑或创建 Google Doc本文(docs.md)—gdrive_api.pyDocs 命令
读写表格单元格、新建 Sheetsheets.md —gsheets_api.py
读取或编辑 Slides 演示文稿slides.md —gslides_api.py

如果只是想快速把某个 Google 原生文件读成文本,gdrive_api.py read <file_id>就够(Docs→Markdown、Sheets→CSV、Slides→纯文本,见 drive.md);只有当需要结构、ID、索引或编辑时才需要打开各专属 API 指南——这正是本文所讲 Docs 命令的用武之地。

小结:一套“先坐标、后落笔”的编辑范式

Docs 命令的核心理念可以概括为三步:get-doc取索引坐标 → 构造 Docs 请求对象 →batch-update批量落笔insert-textappend-text是这条路径的两个便捷封装(前者要你给索引,后者自动算末尾),batch-update则是完整的通用入口,支持样式、列表、删除等全部请求类型;create-doc则为“从空白开始构造”提供了起点。仓库中的单元测试(test_gdrive_api_helper.py)对这些命令的请求路径、请求体、索引计算与参数归一化做了完整覆盖,可作为实现细节的权威参考。

【免费下载链接】danswerOpen Source AI Platform - AI Chat with advanced features that works with every LLM项目地址: https://gitcode.com/GitHub_Trending/da/danswer

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 12:15:55

基于特征值分析的丘脑DBS网络动力学建模与复现

简介&#xff1a;本资源是一套面向神经科学建模与计算神经工程方向的MATLAB实践代码与配套实验数据&#xff0c;聚焦丘脑深部脑刺激&#xff08;DBS&#xff09;对全脑网络动力学的影响机制研究&#xff0c;适用于计算机、电子信息工程、应用数学等专业本科生开展课程设计、期末…

作者头像 李华
网站建设 2026/9/10 12:14:17

PyQt5+PyTorch智能垃圾分类系统毕设全链路实现

简介&#xff1a;本资源是一份面向计算机专业本科生的智能垃圾分类系统毕设与课程作业完整实现方案&#xff0c;聚焦人工智能在环保领域的落地应用&#xff0c;解决传统垃圾分类依赖人工、效率低、准确率不稳定的现实问题。压缩包共20个文件&#xff0c;含7个Python源码&#x…

作者头像 李华
网站建设 2026/9/10 12:11:27

MATLAB数值转字符:核心技巧与工程实践

1. MATLAB数值转字符的核心价值与应用场景在工程计算和科研数据分析中&#xff0c;我们经常需要将数值结果转换为可读性更强的字符形式。MATLAB作为科学计算领域的标准工具&#xff0c;其数值转字符功能远不止简单的类型转换&#xff0c;而是数据呈现、报告生成和可视化标注的基…

作者头像 李华