Skip to content

Ddper/OfficePilot

Repository files navigation

OfficePilot

OfficePilot 是一个 Office Add-in,作为 taskpane 嵌入 Word,通过 Claude API 驱动的对话界面和内联自动补全帮助用户撰写文档。

本地开发和部署

环境要求

  • Node.js 18+ 或 20+
  • Office 365 订阅(Word/Excel/PowerPoint 桌面版或网页版)
  • Anthropic API 密钥

快速开始

  1. 克隆项目

    git clone https://github.com/officepilot/office-pilot.git
    cd office-pilot
  2. 安装依赖

    npm install
  3. 配置环境变量 创建 .env.local 文件:

    ANTHROPIC_API_KEY=your_api_key_here
    # 可选配置
    # ANTHROPIC_BASE_URL=https://api.anthropic.com
    # ANTHROPIC_MODEL=claude-3-haiku-20240307
    # DISABLE_THINKING=true  # 用于 LiteLLM 代理 + Opus 模型时关闭 thinking
  4. 生成 HTTPS 证书 Office Add-in 要求 HTTPS 连接:

    npx office-addin-dev-certs install

    证书将生成在 ~/.office-addin-dev-certs/ 目录。

  5. 启动开发服务器

    npm run dev:https

    服务器将在 https://localhost:3000 启动,同时处理 HTTP 请求和 WebSocket 连接。

开发工作流程

启动开发环境

# 启动自定义 HTTPS 服务器(Next.js + WebSocket 共用 port 3000)
npm run dev:https

# 或使用标准 Next.js 开发服务器(仅 HTTP,不适用于 Office Add-in)
npm run dev

构建和检查

# 构建生产版本
npm run build

# 代码检查
npm run lint

热重载

  • 客户端代码(.ts, .tsx)支持热重载
  • 服务端代码(.mjs)需要手动重启服务器

Office Add-in 注册和安装

1. 配置 manifest.xml

确保 manifest.xml 中的 URL 指向正确的地址:

<SourceLocation DefaultValue="https://localhost:3000/taskpane"/>
<AppDomain>https://localhost:3000</AppDomain>

2. 在 Office 中注册 Add-in

Word 桌面版

  1. 打开 Word
  2. 文件 → 选项 → 信任中心 → 信任中心设置 → 受信任的加载项目录
  3. 添加包含 manifest.xml 的文件夹路径
  4. 插入 → 我的加载项 → 共享文件夹 → 选择 OfficePilot

Word 网页版

  1. 打开 Word Online
  2. 插入 → 加载项 → 上传我的加载项
  3. 选择 manifest.xml 文件

3. 测试 Add-in

  1. 在 Word 中打开文档
  2. 点击 "打开 OfficePilot" 按钮启动任务窗格
  3. 在任务窗格中输入自然语言指令
  4. 在 Word 正文中输入文本测试自动补全功能

项目结构

office-pilot/
├── src/
│   ├── app/                    # Next.js App Router
│   │   └── taskpane/          # 主任务窗格页面
│   ├── lib/                   # 客户端工具库
│   │   ├── office/           # Office.js 相关代码
│   │   │   ├── autocomplete.ts  # 自动补全引擎
│   │   │   └── executor.ts      # Office.js 代码执行器
│   │   ├── use-chat.ts       # 聊天状态管理
│   │   └── use-websocket.ts  # WebSocket 客户端
│   ├── server/               # 服务端代码 (.mjs)
│   │   ├── chat-session.mjs  # Claude API 对话管理
│   │   ├── code-guard.mjs    # 代码安全检查
│   │   ├── prompts/          # 系统提示词
│   │   └── ws-handler.mjs    # WebSocket 消息处理
│   └── types/                # TypeScript 类型定义
├── public/                   # 静态资源
├── manifest.xml             # Office Add-in 配置文件
├── server.mjs              # 自定义 HTTPS 服务器
├── package.json            # 项目依赖和脚本
└── README.md              # 项目文档

部署流程

1. 构建生产版本

npm run build

2. 部署到服务器

  • 将构建后的文件(.next/, public/, package.json 等)上传到服务器
  • 确保服务器支持 HTTPS
  • 配置环境变量

3. 更新 manifest.xml

  • manifest.xml 中的 URL 更新为生产环境地址
  • 更新图标等资源 URL

4. 启动生产服务器

npm start

常见问题

HTTPS 证书问题

症状:浏览器提示 "不安全连接" 或 Office 无法加载 Add-in 解决

  1. 确认已运行 npx office-addin-dev-certs install
  2. 检查证书是否在 ~/.office-addin-dev-certs/
  3. 重启浏览器并清除缓存

Office API 不可用

症状:控制台显示 "Word API not available" 解决

  1. 确认在 Word 中打开了文档
  2. 确认 Add-in 已正确加载
  3. 检查浏览器控制台是否有其他错误

自动补全不触发

症状:输入文本后没有补全建议 解决

  1. 检查 WebSocket 连接是否正常
  2. 确认 ANTHROPIC_API_KEY 已正确配置
  3. 检查控制台日志是否有错误

代码执行失败

症状:Claude 生成的代码无法执行 解决

  1. 检查 executor.ts 中的错误处理
  2. 确认 Office.js API 在当前的 Office 版本中可用
  3. 检查代码是否符合安全限制

贡献指南

  1. 代码风格

    • 使用 TypeScript 和严格模式
    • 遵循现有的代码结构和命名约定
    • 服务端代码使用 .mjs 扩展名
  2. 提交规范

    • 提交信息使用中文
    • 清晰描述修改内容和原因
    • 关联相关 issue 或功能
  3. 测试要求

    • 修改自动补全逻辑后,测试各种交互场景
    • 修改代码执行逻辑后,测试多种 Office.js 代码片段
    • 确保修改不会破坏现有功能
  4. 文档更新

    • 修改功能后更新 README.md 和 CLAUDE.md
    • 添加新配置项时更新环境变量说明
    • 记录已知问题和限制

自动补全

Word 文档中集成 VSCode 风格的幻文本(Ghost Text)自动补全。用户输入时暂停即可触发 LLM 生成的文本建议,逐字符输入可自然消耗或取消建议。

触发机制

  • 用户在 Word 中输入文案,暂停 800ms 后自动触发补全
  • 通过 onParagraphChanged 事件检测文档变化,重置 debounce 计时
  • 请求携带递增的 epoch 计数器,恢复输入后旧 epoch 的响应自动丢弃

建议展示

  • 建议以灰色斜体文本插入光标位置,用 ContentControl(标签 autocomplete-suggestionBoundingBox 外观)包裹
  • 光标置于 ContentControl 之前,用户输入的文字自然落在原文与建议之间

交互逻辑

用户操作 行为
逐字符输入(匹配建议首字符) 建议首字符被"消耗",建议缩短,用户输入保留为正常格式
逐字符输入(不匹配) 建议整体丢弃,用户输入保留
全部字符被消耗 ContentControl 自动删除
方向键 / 鼠标点击 建议保持不变
Enter 键 接受建议:灰色斜体恢复为原文格式,建议内容成为正文

架构

Word 文档 onParagraphChanged
        │
        ▼
 handleParagraphChanged()         ← 800ms debounce,fire-and-forget
        │
        ├─ dismissSuggestionAsync() ← 版本号取消,3 个检查点
        │     ├─ 逐字符匹配消耗
        │     ├─ Enter 接受
        │     └─ 不匹配丢弃
        │
        └─ requestCompletion()     ← 获取段落文本
              │
              ▼
        WebSocket ──► ws-handler.mjs ──► ChatSession.generateCompletion()
                                                │
                                                ▼
                                        Claude API (Haiku)
                                                │
                                                ▼
                              autocomplete_result (epoch 回传)
                                                │
                                                ▼
                              handleAutocompleteResult(text, epoch)

关键文件

文件 职责
src/lib/office/autocomplete.ts 核心补全引擎:状态管理、建议插入/消耗/接受/丢弃、字体恢复
src/app/taskpane/page.tsx 初始化入口,传入 send 回调
src/lib/use-chat.ts 接收 autocomplete_result,调用 handleAutocompleteResult
src/server/chat-session.mjs 调用 Claude API 生成补全文本
src/server/ws-handler.mjs WebSocket 路由,转发 epoch
src/types/ws-messages.ts autocomplete / autocomplete_result 类型定义

技术要点

  • 非阻塞 fire-and-forgetdismissSuggestionAsync 不在 handleParagraphChangedawait,避免阻塞后续事件
  • 版本号取消dismissVersion 计数器 + 3 个检查点,确保过期操作在 context.sync() 后立即中止
  • Epoch 请求取消autocompleteEpoch 随请求递增,服务端原样回传,客户端不匹配则丢弃
  • 逐字符消耗:光标置于 ContentControl 之前,通过比对 textBeforeCC 快照提取用户输入字符,逐字符与建议首字符匹配
  • 字体恢复:插入建议前用临时标记字符捕获原文字体,接受时应用到建议文本
  • 状态清理时序hasPendingSuggestion 在 CC 实际删除(await context.sync())之后才清除,防止 requestCompletion 在 CC 残留时读取段落文本

代码执行与自动补全的隔离

Claude 生成的 Office.js 代码执行时,会修改文档内容并触发 onParagraphChanged 事件。为防止代码执行干扰自动补全,实施四层防护机制

1. 冷却期时间戳(3秒窗口)

  • 代码执行结束时记录时间戳 __lastCodeExecutionEnd
  • 3秒冷却期内,所有文档变化事件被忽略
  • 防止代码执行后立即触发自动补全

2. 全局执行标志

  • 代码执行期间设置 __isExecutingOfficeCode = true
  • 事件处理函数检查此标志并立即返回
  • 确保代码执行期间不处理任何自动补全逻辑

3. 执行计数器

  • 使用 externalCodeExecutionCount 而非布尔值
  • 支持嵌套/并发代码执行场景
  • 计数器归零后才恢复自动补全

4. 文档清理

  • 代码执行前删除所有现有的建议 ContentControl
  • 防止代码与建议内容交互导致文档错乱
  • 确保代码在"干净"的文档环境中执行

防护生效时机

代码执行开始
    ↓
设置全局标志 + 递增计数器
    ↓
删除文档中现有建议
    ↓
执行 Office.js 代码
    ↓
记录结束时间戳(开始3秒冷却期)
    ↓
清除全局标志 + 递减计数器
    ↓
3秒冷却期结束 → 自动补全恢复正常

约束

  • Word API 无键盘事件,所有用户操作通过 onParagraphChanged 间接推断
  • compareLocationWith 在 Office.js 事件回调中不可靠(总是返回 "Before"),不用于位置判断
  • Tab 键在 Word 正文中改变段落缩进(leftIndent)而非插入 \t,不适合用于接受操作

About

Office Pilot

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors