Voyager Data Viewer 全解析:在浏览器本地导入与预览文件夹导出数据
Voyager Data Viewer 全解析:在浏览器本地导入与预览文件夹导出数据
本文围绕 Voyager 官方文档中的 Data Viewer 页面 展开,讲解如何把 Voyager 扩展导出的文件夹数据(
gemini-voyager.folders.v1)在浏览器中离线导入并预览,涵盖交互流程、JSON 数据格式、版本兼容规则以及文档站点与扩展端两侧的源码实现。读完本文,你将理解该数据格式的每个字段含义,掌握导入、校验、浏览与清理数据的完整操作,并能在自己的项目中复刻这套"本地数据查看器"方案。
一、Data Viewer 是什么
Data Viewer 是 Voyager 官方文档站内置的一个纯前端数据查看器:导入从 Voyager 扩展导出的文件夹 JSON 文件后,即可在浏览器中直接查看你的文件夹层级结构和对话列表,无需安装任何额外工具。
它的核心特性由文档站首页描述与源码共同确认:
- 导入即预览:支持拖拽 JSON 文件到页面,或点击按钮选择文件,随后自动渲染出文件夹树与对话清单;
- 纯本地处理:文件通过浏览器
FileReader读取,预览数据仅缓存在当前浏览器的localStorage中,不会上传到任何服务器; - 零依赖使用:查看器是一个注册为
<FolderViewer />的 Vue 组件(见 组件注册),直接内嵌在文档页面中渲染。
适用场景非常直接:导出文件夹数据做迁移前核对、备份完整性检查、跨设备预览组织结构,或者把数据交给不安装扩展的人查看。与 Voyager 的导出能力和文件夹功能配合,就形成了一条"组织 → 导出 → 离线审阅"的完整数据链路。
二、快速上手:三步完成导入与预览
1. 从 Voyager 扩展导出文件夹数据
在 Voyager 扩展的文件夹管理界面中导出数据(扩展端导出实现见 FolderImportExportService.ts)。导出的文件默认按如下格式命名(见 generateExportFilename):
gemini-voyager-folders-YYYYMMDD-HHmmss.json
例如 gemini-voyager-folders-20261009-153000.json。文件由扩展端以 application/json;charset=utf-8 类型通过 Blob 下载生成(见 downloadJSON),内容为格式化(2 空格缩进)的 JSON。
2. 在 Data Viewer 页面导入
打开 Data Viewer 页面后,页面会显示一个虚线框的上传区(源码见 FolderViewer.vue):
- 拖拽导入:直接把
.json文件拖入虚线框,松开即触发解析; - 点击选择:点击虚线框或"浏览文件"按钮,从文件选择器中选取文件;
- 格式约束:仅接受
.json后缀文件,其他扩展名会被直接判为格式无效(见 handleFile)。
导入成功后页面自动展开全部文件夹,并在顶部显示统计信息。
3. 解读预览界面
预览界面分为三块(见 FolderViewer.vue):
| 界面区域 | 内容说明 |
|---|---|
| 顶部统计栏 | 文件夹总数、对话总数、导出时间(exportedAt)、数据版本(version) |
| 操作按钮 | 全部展开(+)、全部收起(−)、重新导入、清除数据 |
| 树形列表 | 文件夹行 + 对话行,支持点击文件夹行展开/收起子级 |
对话行展示的要素包括:
- 标题:优先显示
title,为空时回退显示conversationId; - 星标:
starred: true的对话前显示 ★ 标记; - Gem 标记:
isGem: true的对话显示 "Gem" 标签; - 加入时间:按
addedAt本地化格式化显示; - 可点击跳转:整行是链接,点击后以新标签页打开该对话(
target="_blank"+rel="noopener noreferrer",见 对话行模板)。
文件夹行则会显示:展开箭头、文件夹名、对话数量统计,以及两类特殊标签——Pinned(已置顶,pinned: true)和 Project(设置了 instructions 的"文件夹即项目")。
三、数据格式详解:gemini-voyager.folders.v1
Data Viewer 只接受 Voyager 扩展导出的文件夹格式,格式标识符为 gemini-voyager.folders.v1。该格式在扩展端与查看器两端保持一致:类型定义见 sync.ts 与 FolderViewer.vue 的接口声明。
顶层结构
{
"format": "gemini-voyager.folders.v1",
"exportedAt": "2026-10-09T15:30:00.000Z",
"version": "2.4.1",
"platform": "chatgpt",
"data": {
"folders": [],
"folderContents": {}
}
}
| 字段 | 类型 | 说明 |
|---|---|---|
format |
string | 固定为 gemini-voyager.folders.v1,用于识别格式并做兼容性判断 |
exportedAt |
string | ISO 8601 时间戳,导出时间 |
version |
string | 导出时扩展版本号,来自 manifest.json(见 version.ts) |
platform |
string(可选) | 数据来源标记,目前仅 ChatGPT 导出会写入 "chatgpt";Gemini 与 AI Studio 的导出不带此字段(见 exportedPlatform) |
data |
object | 主体数据,含 folders 与 folderContents 两个成员 |
data.folders:文件夹数组
查看器侧接受的文件夹字段(见 Folder 接口):
| 字段 | 类型 | 说明 |
|---|---|---|
id |
string | 文件夹唯一标识(持久化 ID,可能是历史或导入产生的任意字符串) |
name |
string | 文件夹名称 |
parentId |
string | null | 父文件夹 ID;为 null 表示顶级文件夹,据此构建树形层级 |
pinned |
boolean(可选) | 是否置顶 |
color |
string(可选) | 自定义颜色 |
sortIndex |
number(可选) | 同级排序权重,升序排列 |
createdAt / updatedAt |
number | 创建/更新时间戳(毫秒) |
instructions |
string(可选) | 文件夹即项目(Folder as Project)的指令文本 |
扩展端存储的完整 Folder 类型还额外包含 isExpanded 字段,见 folder.ts。
data.folderContents:对话归属映射
{
"folderContents": {
"f_001": [
{
"conversationId": "conv_abc123",
"title": "Agentic workflows 调研",
"url": "https://gemini.google.com/app/conv_abc123",
"addedAt": 1720000000000,
"isGem": true,
"starred": false,
"sortIndex": 0
}
]
}
}
| 字段 | 类型 | 说明 |
|---|---|---|
conversationId |
string | 对话标识 |
title |
string | 对话标题,为空时界面回退显示 conversationId |
url |
string | 对话链接,预览界面点击跳转 |
addedAt |
number | 加入文件夹的时间戳 |
isGem |
boolean(可选) | 是否为 Gem 对话 |
starred |
boolean(可选) | 是否在文件夹内加星 |
sortIndex |
number(可选) | 对话在文件夹内的排序权重 |
完整字段(含 gemId、customTitle、lastOpenedAt、lastTurnAt 等可选元数据)见扩展端类型 folder.ts。未被任何文件夹引用的键所对应的对话,会被查看器集中归入"未归类对话(Unfiled conversations)"分组显示(见 unfiled 处理逻辑)。
四、版本兼容与格式校验
Data Viewer 页面本身只做两层校验(见 loadPayload):
format必须严格等于gemini-voyager.folders.v1;data.folders与data.folderContents必须都存在。
不满足时页面显示"格式无效"提示;JSON.parse 抛异常时显示"解析失败"提示。
而扩展端导入的校验更为严格,位于 validatePayload,还会额外检查:
- 格式是否受支持:
isSupportedFormat判断format是否在注册表中(见 version.ts); - 版本是否兼容:
getCompatibilityInfo解析version并比较。gemini-voyager.folders.v1的最低兼容扩展版本为 0.7.0(FORMAT_VERSIONS常量),低于该版本或版本号非法都会被拒绝; - 必填字段:
data缺失、folders/folderContents结构错误等均会给出明确的错误分类(ValidationErrorType)。
也就是说:Data Viewer 是"宽容"的查看器,扩展端是"严格"的导入器——前者只关心能否渲染,后者还关心能否安全合并回你的文件夹体系。版本比较逻辑(含预发布版本处理)与未来的数据迁移注册表(VERSION_MIGRATIONS)都在 version.ts 中。
五、源码级原理:FolderViewer 组件如何工作
查看器全部逻辑位于 docs/.vitepress/theme/components/FolderViewer.vue,由 index.ts 注册为全局组件 <FolderViewer />。核心机制如下。
1. 树形构建与排序
buildTree(L243-L268)先按 id 建索引,再依据 parentId 把节点挂到父节点下(父节点不存在或 parentId 为 null 则视为根),随后对根节点与每个父节点的子级都按 sortIndex 升序排序;每个文件夹下挂载的对话也按 sortIndex 排序。折叠状态由 expandedIds(Set)维护,flattenTree 递归展开为扁平行供模板渲染,空文件夹展开后显示"空文件夹"占位行。
2. 未归类对话的识别
查看器把 folderContents 中所有键不在 folders 的 id 集合里的对话提取出来,渲染为一个特殊的"未归类对话"分组(UNFILED_ID = '__unfiled__')。这正好对应扩展侧的一种真实数据形态:当文件夹被删除或数据不完整时,对话引用仍可能残留。
3. 本地缓存与隐私边界
导入成功后,原始 JSON 字符串会写入 localStorage(键名为 gv-folder-viewer-data,见 L48);页面加载时会自动恢复上次数据(onMounted)。点击"清除数据"则同时清空页面状态与缓存(clearData)。
这条链路完整印证了文档的隐私承诺:文件读取(FileReader)→ 内存解析 → localStorage 持久化,全程发生在浏览器本地,无任何网络请求。
4. 多语言
界面文案内置 10 种语言(zh-CN、zh-TW、en-US、ja-JP、ko-KR、fr-FR、es-ES、pt-PT、ar-SA、ru-RU),跟随文档站点语言自动切换,未匹配时回退英文(i18n 表)。
六、扩展端如何生成这份 JSON
理解数据格式的源头,有助于你确认导出文件的正确性。扩展端文件夹导入/导出服务(FolderImportExportService.ts)是主要生成方:
- exportToPayload(L42-L52):把
FolderData(含folders与folderContents)包装为gemini-voyager.folders.v1载荷,exportedAt取当前时间,version自动同步自 manifest; - downloadJSON(L486-L503):以
JSON.stringify(payload, null, 2)生成可读文本,通过 Blob + 临时<a>触发下载; - parseJSONText(L508-L535):导入时不仅支持纯 JSON,还能自动剥离
```json ... ```围栏代码块、以及截取首个{到末尾}之间的内容——这正是"AI 自动整理(AI Auto-Organize)"场景中直接粘贴 Gemini 返回的 JSON也能成功导入的原因; - importExportLock:导入过程加锁,避免并发导入互相覆盖(L455-L466),导入前还会在
sessionStorage写入备份,便于失败时回滚。
另外,Google Drive 同步服务在首次上传时也会构造相同格式的载荷(见 GoogleDriveSyncPayloads.ts),说明 gemini-voyager.folders.v1 不仅是手动导出的格式,也是云同步上传云端的同一份数据格式——Data Viewer 因此也天然适用于审阅云同步备份的内容。
七、常见问题排查
| 现象 | 原因与处理 |
|---|---|
| 页面提示"格式无效" | 文件不是 .json,或 format 字段不是 gemini-voyager.folders.v1,或缺少 data.folders / data.folderContents。请确认文件来自 Voyager 扩展导出 |
| 页面提示"解析失败" | JSON 语法不完整或文件被截断。用任意 JSON 校验工具检查后重新导出 |
| 对话显示在"未归类对话"里 | 该对话引用的文件夹 id 在 folders 中不存在(数据不完整或文件夹已删除),属正常容错展示 |
| 想要完全清空 | 点击预览界面的"清除数据"按钮,会同时删除 localStorage 缓存 |
| 想换一份数据 | 点击"重新导入",直接拖入或选择新的 JSON 文件即可覆盖当前数据 |
如果需要在扩展内重新导入这份 JSON(迁移或恢复),在文件夹面板菜单中选择"导入文件夹",可粘贴 JSON 文本或选择文件;扩展会执行更严格的版本兼容与结构校验,并在导入前自动备份当前文件夹数据。
八、相关资源
- 文档正文:docs/en/data-viewer.md
- 查看器组件实现:docs/.vitepress/theme/components/FolderViewer.vue
- 组件注册与文档站主题:docs/.vitepress/theme/index.ts
- 扩展端导入/导出服务:src/features/folder/services/FolderImportExportService.ts
- 数据类型定义:src/core/types/folder.ts、src/core/types/sync.ts
- 版本兼容与迁移:src/core/utils/version.ts
- 云同步载荷构造:src/core/services/GoogleDriveSyncPayloads.ts
- 上游功能指南:文件夹功能、对话导出