dwarkeshsp/ai_coworker
GitHub: dwarkeshsp/ai_coworker
一款基于 Gemini 的 Google Docs 评论线程 AI 助手,支持在评论中被 @mention 后结合文档上下文与联网搜索自动回复。
Stars: 28 | Forks: 4
# Docs AI 协作者
针对 **Google Docs** 的评论线程助手:如果你在评论中 **@mention** 了这个 bot,它会使用 Gemini 在评论线程中回复你。它可以查看完整的文档以及所有其他已打开的评论线程。它还可以搜索网络。它不会自行编辑文档。
重要提示:无论你当前正在使用哪个文档,你都必须为分配给 bot 的电子邮件地址授予评论或编辑权限(例如,[hello@dwarkeshpatel.com](mailto:hello@dwarkeshpatel.com))
## 要求
- **Python 3.12+**
- **Google Cloud** 项目,需启用 **Drive API** 和 **Docs API**,配置 OAuth 同意屏幕,并拥有一个 **Desktop** OAuth 客户端(client secret JSON)。
- 用于开发环境中 webhook 的 **HTTPS URL**(例如 [ngrok](https://ngrok.com/))。
## 安装
```
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e ".[dev]"
```
将 `.env.example` 复制为 `.env`,并将 `config.example.yaml` 复制为 `config.yaml`。仅 `.example` 文件会被跟踪;`.env` 和 `config.yaml` 会被忽略。
## 首次设置
请**按顺序**执行以下操作(确保在每个终端中使用相同的 venv:`source .venv/bin/activate`)。
1. **Google Cloud** — 创建一个新项目。启用 Drive 和 Docs API。配置 OAuth 同意屏幕。如果应用为 **External** 且处于 **Testing** 状态,请在 **Test users** 下添加 **bot** 账户的电子邮件地址(参见 [OAuth consent](#oauth-consent-and-test-users))。创建一个 **Desktop** OAuth 客户端并下载 client secret JSON。如果你对于应该将哪个账户设置为 bot 有更多疑问,请参阅下方的 Bot 账户部分
2. **Environment** — 在 `.env` 中,设置 `GEMINI_API_KEY` 或 `GOOGLE_API_KEY`,`SERPER_API_KEY` ([serper.dev](https://serper.dev)),并将 `GOOGLE_OAUTH_CLIENT_SECRETS` 设置为 client secret JSON 的路径
3. **Config** — 在 `config.yaml` 中,设置 `llm.`* 和 `webhook.listen_port`(通常为 `8080`;ngrok 必须指向此端口)
4. **Public URL** — 启动 `ngrok http `,将**仅 HTTPS origin** 复制到 `config.yaml` 中的 `webhook.public_base_url`(参见 [ngrok](#ngrok))
5. **Authorize** — 运行 `docs-ai-worker --mode authorize` 并使用你希望 **bot** 用于回复的 Google 个人资料(即你作为测试用户添加到 Google Cloud 项目中的账户)登录
6. **Run workers** — 在两个新终端中(激活 venv),运行以下命令:`docs-ai-worker --mode webhook` 和 `docs-ai-worker --mode changes-worker`
7. **Register push** — 运行 `docs-ai-worker --mode bootstrap-watch`。当公共 base URL 发生变化时(例如新的 ngrok URL),运行 `docs-ai-worker --mode bootstrap-watch --force-watch-renew`。
8. **Drive** — 与 bot 共享文档或文件夹;在评论中 **@mention** 该 bot。
以后,一旦你完成了所有配置,你可以启动 ngrok,然后运行 `./scripts/dev-up.sh` 来同时启动所有这些进程。你可以运行 `./scripts/dev-down.sh` 来关闭所有进程。
## Bot 账户
为助手使用一个**专用**的 Google 账户,以该用户身份进行 OAuth,并与**该**账户共享内容。以你平常的账户身份进行撰写;在评论中 @mention 该 bot。日常使用中同时使用同一个账户会造成混乱——应避免这种情况。
除非你需要覆盖,否则请将 `config.yaml` 中的 `bot_email` 和 `bot_display_name` 留空。完成 OAuth 后,应用会从 `userinfo.email` / `userinfo.profile` 缓存电子邮件 (`.tokens/oauth-user-email.txt`) 和显示名称 (`.tokens/oauth-user-display-name.txt`),用于 mention 检测和避免自我回复。如果 Google 未返回名称,显示名称将默认为 `AI Collaborator`。如果你是从旧版本升级的,请删除 OAuth token 并针对新的 scope 再次授权。
## 配置
| 区域 | 备注 |
| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Gemini** | `.env` 中的 `GEMINI_API_KEY` 或 `GOOGLE_API_KEY`;`llm.model`,`llm.thinking_level`,`llm.max_output_tokens`,`llm.api_base`,可选的 `llm.max_search_queries` / `llm.max_grounding_hits`。 |
| **Serper** | `.env` 中的 `SERPER_API_KEY` — Google Search grounding([Serper API](https://serper.dev));外部链接仅来自于这些搜索结果。 |
| **Google** | OAuth:`GOOGLE_OAUTH_CLIENT_SECRETS`;可选的 `GOOGLE_OAUTH_TOKEN_FILE`。Service account(高级):`GOOGLE_SERVICE_ACCOUNT_FILE` — 与该身份共享文档。 |
| **Discovery** | `discovery.`*(queue,可选的 `monitored_folder_id` / `folder_scope`);`discovery.max_parallel_thread_jobs`,唤醒信号设置。 |
| **Webhook** | `webhook.public_base_url`,`webhook.path`,`webhook.channel_token`(或 `DRIVE_WEBHOOK_CHANNEL_TOKEN`)。Callback URL 为 `{webhook.public_base_url}{webhook.path}`。 |
可选的调试项:`runtime.llm_pipeline_trace` 和 `runtime.llm_pipeline_trace_dir`。
### OAuth consent 和测试用户
[Google Cloud Console → OAuth consent](https://console.cloud.google.com/apis/credentials/consent) 中的规则控制着**谁可以为你的客户端完成 OAuth**,而不是谁可以编辑文档或 @mention 该 bot。
如果同意屏幕为 **External** 且应用仍处于 **Testing** 状态,请在 **Audience → Test users** 下添加所有将运行 OAuth 的账户——包括 **bot** 账户。否则,同意流程将失败并显示类似“app is being tested”的错误。如果队友仅仅是进行评论或共享文档,则他们无需成为测试用户,除非他们使用你的 client ID 运行此应用。已发布或 **Internal** 的应用遵循 Google 针对你发布状态的相关规则。
### ngrok
Google 通过 **HTTPS** 调用 webhook。请与 `config.yaml` 中的 `webhook.listen_port` 匹配,然后执行:
```
ngrok http 8080 # use your listen_port
```
从 ngrok 的 **Forwarding** 行中,仅复制 `https://…` origin(无路径)。设置 `webhook.public_base_url` 或 `DRIVE_WEBHOOK_PUBLIC_BASE_URL`(以 env 为优先)。不要附加 `webhook.path`——应用会在注册时自动将它们组合。在发生**任何** URL 变更后,请运行 `docs-ai-worker --mode bootstrap-watch --force-watch-renew`。在免费的 ngrok tier 上,当 ngrok 重启时 URL 经常会发生变化——请更新配置并续订 watch。保持 `docs-ai-worker --mode webhook` 运行,以便 tunnel 能够访问 `listen_port`。ngrok 的 inspector(通常是 `http://127.0.0.1:4040`)有助于进行调试。
## 运行
入口点:`docs-ai-worker`(来自 `pip install -e .`)。在每个终端中使用相同的 venv。
### 长时间运行的进程
| Mode | Command | Role |
| -------------- | -------------------------------------- | -------------------------------------------------------------------------------------------------------------------------- |
| Webhook | `docs-ai-worker --mode webhook` | 在 `webhook.listen_host` / `listen_port` 上的 HTTP 服务器(默认为 `0.0.0.0:8080`);Drive 将数据发布到此;工作将排入 SQLite 队列中。 |
| Changes worker | `docs-ai-worker --mode changes-worker` | 没有带 `--mode` 的 `docs-ai-worker` 的默认模式。处理队列中的任务(同步 + 回复)。 |
### 一次性命令
| Mode | Command | When |
| --------------- | --------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| Authorize | `docs-ai-worker --mode authorize` | 仅限浏览器 OAuth;保存 token 和 bot 元数据后退出。 |
| Bootstrap watch | `docs-ai-worker --mode bootstrap-watch` | 注册或续订 Drive push channel;当 `webhook.public_base_url` 变更时使用 `--force-watch-renew`。 |
| Status | `docs-ai-worker --mode status` | 队列健康状况的 JSON 快照;仅用于调试。 |
## 辅助脚本
位于 `[scripts/](scripts/)` 中的可选 bash 脚本(如有需要,请运行 `chmod +x scripts/*.sh`)。它们不会启动 ngrok。
| Script | Purpose |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------- |
| `dev-first-run.sh` | 如果需要,创建 `.venv`,执行 `pip install -e ".[dev]"`,`authorize`,检查公共 base URL,运行 `dev-up.sh`。 |
| `dev-up.sh` | 在后台运行 webhook + changes worker(日志位于 `.state/dev-run/logs/` 下),运行 `bootstrap-watch --force-watch-renew`,打印 `status`。 |
| `dev-down.sh` | 停止由 `dev-up.sh` 启动的进程。 |
该应用在设计上使用了**两个进程**:HTTP webhook 和 worker 共享 SQLite;脚本可以管理它们,但如果不修改代码则无法将它们合并。默认情况下,OAuth 和 ngrok 仍需手动操作。
## 行为
- Context 仅使用**未解决**的线程。
- 当 bot 被 @mention 时(执行 `mentionedEmailAddresses` 和电子邮件子字符串检查)触发回复。
- 通过 SQLite 状态减少重复回复(默认为 `.state/worker_state.sqlite3`)。
- 可选的“Thinking…”确认:`runtime.send_ack_reply`;风格指南:`runtime.style_guide_mode`(`disabled` / `voice` / `full`);线程诊断:`runtime.log_thread_diagnostics`。详情请参见 `config.example.yaml`。
## 许可证
MIT — 参见 [LICENSE](LICENSE)。
标签:Gemini, Python, Webhook, 人工智能, 力导向图, 办公自动化, 无后门, 用户模式Hook绕过, 谷歌文档, 逆向工具