Google Slides 集成详解
目录
功能概述
InsightHub 的核心价值之一是将分析结果快速转化为可交付的专业幻灯片。项目深度集成了 Google Slides,允许用户一键将分析结果导出为 Google Slides 演示文稿,存入自己的 Google Drive。
根据不同功能的业务场景和结果页的复杂度,项目巧妙地采用了两种不同的技术方案来实现导出功能:
- 模板替换模式:适用于市场机会分析和人群信号分析。这两种功能的结果页结构相对固定,适合使用预设的模板进行内容填充。
- 图片插入模式:适用于受众画像幻灯片。该功能的结果包含多个结构复杂的双页幻灯片,采用将前端渲染结果直接“截图”为图片并插入到新幻灯片的方式,能最高保真地还原视觉效果。
设计思路与技术选型
在项目初期,我们面临一个关键的技术选型:是直接通过 API 精细地控制 Google Slides 中的每一个文本框、形状和图片的位置,还是采用更灵活、更高效的方式?
直接控制 API 的挑战:
- 高复杂度:通过 Google Slides API 从零开始构建一个样式精美的幻灯片,需要编写大量繁琐的代码来精确计算和设置每一个元素的位置、大小、字体、颜色等,开发和调试成本极高。
- 灵活性差:一旦模板样式需要微调(例如,移动一个 Logo、改变一个标题的字号),就需要修改大量的后端或前端代码,维护起来非常困难。
- 无法预览:用户在点击导出前,无法直观地看到最终生成的幻灯片效果。
我们选择的方案:前端渲染 + 后端辅助
考虑到以上挑战,我们决定采用一种更现代、更聪明的“关注点分离”方案:
- 前端负责“颜值”:利用 React 组件和 CSS 的强大能力,在浏览器中直接将结果数据渲染成一个与最终幻灯片视觉效果 100% 一致 的 HTML 页面。这使得样式调整变得非常简单(只需修改 CSS),并且用户可以所见即所得。
- 后端负责“连接”:后端提供一个轻量级的 API 服务,作为前端与 Google Apps Script 之间的“安全桥梁”。所有敏感操作,如调用需要授权的 Apps Script,都通过后端完成,确保了整个流程的安全性和稳定性。
- Apps Script 负责“执行”:Google Apps Script 作为与 Google Workspace(Drive, Slides)交互的最终执行者。它被设计为执行一些标准化的、原子性的操作(例如“在指定幻灯片中插入一张图片”),使得逻辑非常清晰。
这种架构设计,充分利用了每项技术的优势,不仅完美实现了功能,还极大地降低了开发和维护的复杂度,是本项目的一大设计亮点。
技术实现方案一:模板替换模式
此方案应用于市场机会分析和人群信号分析功能,其核心思想是“填空”。
业务流程
- 用户在结果页点击“导出到 Google Slides”按钮。
- 系统在用户的 Google Drive 中创建一个以分析任务命名的新文件夹。
- 系统将一个预先设计好的 Google Slides 模板文件复制到这个新文件夹中。
- 系统将结果页中的图表(如气泡图 )“截图”成一张图片,并上传到该文件夹。
- 系统通过 API,用分析结果中的文本(如标题、策略建议等)替换掉模板中的文本占位符(例如
{{标题}})。 - 系统调用 Apps Script,将上传的图表图片替换掉模板中的图片占位符(例如
{{图片}})。 - 完成后,系统会弹出一个成功提示,并提供一个直接跳转到新生成文件的链接。
技术实现细节
sequenceDiagram
participant U as 用户 (User)
participant FE as 前端 (React Hook)
participant BE as 后端 (Node.js)
participant GDrive as Google Drive API
participant GSlides as Google Slides API
participant GScript as Google Apps Script
U->>FE: 1. 点击“导出到 Google Slides”
FE->>GDrive: 2. 创建 Drive 文件夹
GDrive-->>FE: 返回文件夹 ID
FE->>GDrive: 3. 复制模板文件到新文件夹
GDrive-->>FE: 返回新幻灯片 ID
FE->>FE: 4. 将 HTML 图表渲染为图片 (Blob)
FE->>BE: 5. 调用后端接口 `/api/slides/insert-image` <br> (传递幻灯片ID, 图片数据, 占位符 `{{图片}}`)
BE->>GScript: 6. 调用 Apps Script Execution API <br> (执行 `insertImageByShapeText` 函数)
GScript->>GSlides: 7. 找到占位符形状并替换为图片
GScript-->>BE: 返回执行结果
BE-->>FE: 返回成功/失败
FE->>GSlides: 8. 发起 `batchUpdate` 请求 <br> (替换所有文本占位符,如 `{{标题}}`)
GSlides-->>FE: 返回成功/失败
FE->>U: 9. 显示成功消息和文件链接
- 前端驱动:整个流程由前端的自定义 Hook
useGoogleSlidesExport.ts统一调度。 - 模板 ID 配置:模板文件的 ID 配置在环境变量
VITE_GOOGLE_SLIDES_TEMPLATE_ID中,方便更换模板而无需修改代码。 - 图片插入的巧思:直接通过 Google Slides API 插入图片并精确控制其大小和位置非常繁琐。我们创造性地利用 Apps Script 来实现这一步:在模板中预先放置一个带有特殊文本(如
{{图片}})的形状,Apps Script 函数insertImageByShapeText的作用就是找到这个形状,并用上传的图片等比例替换它。这使得图片的位置和大小控制变得异常简单,只需在模板中拖拽那个占位符形状即可。 - 后端角色:后端在这里扮演了一个“安全代理”的角色。前端将图片数据和指令发送给后端,后端再以用户的身份安全地调用 Apps Script,避免了复杂的浏览器跨域(CORS)问题和权限处理。