跳到主要内容

Google Slides 集成详解


目录

  1. 功能概述
  2. 设计思路与技术选型
  3. 技术实现方案一:模板替换模式
  4. 技术实现方案二:图片插入模式
  5. 后端与 Apps Script 协同工作原理

功能概述

InsightHub 的核心价值之一是将分析结果快速转化为可交付的专业幻灯片。项目深度集成了 Google Slides,允许用户一键将分析结果导出为 Google Slides 演示文稿,存入自己的 Google Drive。

根据不同功能的业务场景和结果页的复杂度,项目巧妙地采用了两种不同的技术方案来实现导出功能:

  1. 模板替换模式:适用于市场机会分析人群信号分析。这两种功能的结果页结构相对固定,适合使用预设的模板进行内容填充。
  2. 图片插入模式:适用于受众画像幻灯片。该功能的结果包含多个结构复杂的双页幻灯片,采用将前端渲染结果直接“截图”为图片并插入到新幻灯片的方式,能最高保真地还原视觉效果。

设计思路与技术选型

在项目初期,我们面临一个关键的技术选型:是直接通过 API 精细地控制 Google Slides 中的每一个文本框、形状和图片的位置,还是采用更灵活、更高效的方式?

直接控制 API 的挑战

  • 高复杂度:通过 Google Slides API 从零开始构建一个样式精美的幻灯片,需要编写大量繁琐的代码来精确计算和设置每一个元素的位置、大小、字体、颜色等,开发和调试成本极高。
  • 灵活性差:一旦模板样式需要微调(例如,移动一个 Logo、改变一个标题的字号),就需要修改大量的后端或前端代码,维护起来非常困难。
  • 无法预览:用户在点击导出前,无法直观地看到最终生成的幻灯片效果。

我们选择的方案:前端渲染 + 后端辅助

考虑到以上挑战,我们决定采用一种更现代、更聪明的“关注点分离”方案:

  1. 前端负责“颜值”:利用 React 组件和 CSS 的强大能力,在浏览器中直接将结果数据渲染成一个与最终幻灯片视觉效果 100% 一致 的 HTML 页面。这使得样式调整变得非常简单(只需修改 CSS),并且用户可以所见即所得
  2. 后端负责“连接”:后端提供一个轻量级的 API 服务,作为前端与 Google Apps Script 之间的“安全桥梁”。所有敏感操作,如调用需要授权的 Apps Script,都通过后端完成,确保了整个流程的安全性和稳定性。
  3. Apps Script 负责“执行”:Google Apps Script 作为与 Google Workspace(Drive, Slides)交互的最终执行者。它被设计为执行一些标准化的、原子性的操作(例如“在指定幻灯片中插入一张图片”),使得逻辑非常清晰。

这种架构设计,充分利用了每项技术的优势,不仅完美实现了功能,还极大地降低了开发和维护的复杂度,是本项目的一大设计亮点。


技术实现方案一:模板替换模式

此方案应用于市场机会分析人群信号分析功能,其核心思想是“填空”。

业务流程

  1. 用户在结果页点击“导出到 Google Slides”按钮。
  2. 系统在用户的 Google Drive 中创建一个以分析任务命名的新文件夹。
  3. 系统将一个预先设计好的 Google Slides 模板文件复制到这个新文件夹中。
  4. 系统将结果页中的图表(如气泡图)“截图”成一张图片,并上传到该文件夹。
  5. 系统通过 API,用分析结果中的文本(如标题、策略建议等)替换掉模板中的文本占位符(例如 {{标题}})。
  6. 系统调用 Apps Script,将上传的图表图片替换掉模板中的图片占位符(例如 {{图片}})。
  7. 完成后,系统会弹出一个成功提示,并提供一个直接跳转到新生成文件的链接。

技术实现细节

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)问题和权限处理。

技术实现方案二:图片插入模式

此方案专为受众画像幻灯片功能设计,其核心思想是“打印成图,再贴上去”。

业务流程

  1. 用户在结果页点击“导出到 Google Slides”按钮。
  2. 系统在用户的 Google Drive 中创建一个新文件夹。
  3. 系统在该文件夹中创建一个全新的、空白的 Google Slides 演示文稿。
  4. 系统删除这个新演示文稿中默认的第一张空白页。
  5. 系统开始遍历前端页面上的每一个用户画像(Persona)结果: a. 将该画像的第一页幻灯片内容“截图”成一张高清图片。 b. 调用 Apps Script,在演示文稿的末尾新建一页,并将这张图片插入为该页的全部内容。 c. 将该画像的第二页幻灯片内容也“截图”成一张高清图片。 d. 再次调用 Apps Script,在末尾再新建一页,并将第二张图片插入。
  6. 遍历完所有用户画像后,系统弹窗提示成功,并提供文件链接。

技术实现细节

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->>GSlides: 4. 删除默认的第一个空白页

loop 遍历每一个用户画像的每一页
FE->>FE: 5. 将 HTML 幻灯片渲染为图片 (Blob)
FE->>BE: 6. 调用后端接口 `/api/slides/insert-image-to-blank-slide` <br> (传递幻灯片ID, 图片数据)
BE->>GScript: 7. 调用 Apps Script Execution API <br> (执行 `insertImageToBlankSlide` 函数)
GScript->>GSlides: 8. 新建空白页并插入图片
GScript-->>BE: 返回执行结果
BE-->>FE: 返回成功/失败
end

FE->>U: 9. 显示成功消息和文件链接
  • 专用 Hook:此流程由 usePersonaSlideGoogleSlidesExport.ts 驱动,逻辑与通用 Hook 完全不同。
  • 高保真还原:此方案的核心优势在于保真度。由于受众画像幻灯片的布局和内容非常复杂,通过 API 逐个元素创建几乎是不可能的。而将前端精心渲染好的、所见即所得的 HTML 页面直接转换为图片,可以 100% 还原所有的视觉细节,包括字体、颜色、布局、以及 AI 生成的图片。
  • 专用的 Apps Script 函数:我们为此方案编写了一个专用的 Apps Script 函数 insertImageToBlankSlide。它接收图片数据后,会自动在演示文稿的末尾(或指定位置)创建一个新的空白幻灯片,然后将图片插入并设置为铺满整个页面,操作高效且精准。

后端与 Apps Script 协同工作原理

无论是哪种方案,后端 (server/index.ts) 和 Apps Script (SlidePictureCode.gs) 的协同都至关重要。

  1. 统一的 API 入口:前端不直接与 Google 或 Apps Script 通信,而是统一调用后端提供的 /api/slides/* 接口。
  2. 安全的身份验证:前端在调用后端接口时,会在请求头中附带上用户登录时获取的 Google OAuth Access Token。
  3. 后端执行调用:后端收到请求后,会使用这个 Token 作为凭证,去调用 Google Apps Script Execution API。这意味着,Apps Script 是以用户的身份在执行操作,因此它只能访问该用户有权限访问的文件和文件夹,确保了数据的安全。
  4. 原子化的脚本函数:Apps Script 中的函数被设计得非常“原子化”,即每个函数只做一件具体的事(例如,“根据文本替换图片”或“在末尾插入图片”)。这使得脚本本身非常简单、稳定且易于维护。

通过这套精心设计的协同机制,我们成功地将复杂的 Google Workspace 操作封装成了简单、安全、高效的 API 调用,为前端提供了极佳的开发体验。