Gemini / ChatGPT 聊天历史导出与分析
适用边界
本 skill 覆盖两个产品:
| 产品 | 路径 | 产物 | 文件格式 |
|---|---|---|---|
| ChatGPT(OpenAI) | Settings → Data controls → Export | ZIP,内含 conversations.json 等 | JSON |
| Gemini(Google) | Google Takeout → Gemini Apps | ZIP,内含 My Activity/Gemini/*.html | HTML(不是 JSON) |
关键差异:ChatGPT 给 JSON,Gemini 给 HTML——本 skill 两套都要处理。
Part A:ChatGPT(OpenAI)导出
A.1 引导文案(可直接复制)
把跟 ChatGPT 的全部对话导出,大概走这几步:
- 打开 https://chatgpt.com(或 chat.openai.com)并登录
- 右上角点你的头像 → Settings
- 左侧菜单选 Data controls
- 找到 Export your data 区域,点 Request export
- 弹窗里勾上"Include chat history"(这是必须项),点 Confirm request
- 等 1~48 小时——OpenAI 会把下载链接发到你注册邮箱
- 邮件点链接下 ZIP,链接 7 天后失效,别拖
- ZIP 里找
conversations.json文件可能 10MB~1GB+,别打开,告诉我解压后的完整路径。
A.2 文件结构(校验用)
# 顶层是 array
jq 'type' /path/to/conversations.json
# → "array"
# 总数
jq 'length' /path/to/conversations.json
# 单条 session 字段(实测是这些,版本可能小变)
jq '.[0] | keys' /path/to/conversations.json
# 预期: ["create_time","default_model_slug","id","mapping","moderation_results","title","update_time","user_id"]
注意 ChatGPT 的结构和 Claude 完全不同:
- ChatGPT 用
mapping(嵌套树)而不是chat_messages(线性数组) - 时间戳是 Unix timestamp(秒),不是 ISO 字符串
- 消息角色在
mapping.[id].message.author.role里,值是"user"/"assistant"/"tool"
A.3 把 mapping 拍平为线性 messages
# 提取所有 user/assistant 消息,按树遍历顺序
jq -r '
.[] as $c
| $c.id as $cid
| $c.title as $title
| $c.create_time as $ct
| [
($c.mapping | to_entries[]
| .value.message
| select(. != null and .author.role != "tool")
| {
sender: (.author.role | if . == "user" then "human" else . end),
text: ([.content.parts[]? | select(type == "string")] | join("\n")),
created_at: (.create_time // null)
})
] as $msgs
| $cid + "|" + ($ct | tostring) + "|" + $title + "|" + ($msgs | length | tostring)
' /path/to/conversations.json
A.4 常见的 4 类问题(参考 Claude skill 里的 A-G 模板)
| 用户问题 | 对应处理 |
|---|---|
| 找关键词对话 | 用 jq 配合 test() 过滤 text 字段 |
| 列总览 | 用上面的"拍平"输出,按 create_time 排序 |
| 找强建议 | 搜 "我建议|建议你|不应该" |
| 找最长对话 | 排序 mapping 节点数 |
完整命令模板参见 claude-chat-export-analyze skill——结构差异处理完,jq 关键词搜索/时间线/主题提炼的逻辑完全通用。
Part B:Gemini(Google)导出
B.1 引导文案(可直接复制)
把跟 Gemini 的全部对话导出,大概走这几步:
- 打开 https://myaccount.google.com 并登录
- 左上角菜单点 数据和隐私
- 向下滚到 数据下载(或"下载你的数据")区域,点进入 Google Takeout
- 取消全选,只勾 "我的活动"(My Activity)
- 点"我的活动"右边的下拉,确认"Gemini Apps"子项已勾选——只勾"Gemini"不一定包含完整对话
- 点 下一步,选 一次性导出、.zip 格式、大小 1~2GB/卷
- 点 创建导出
- 异步处理,可能几小时到几天,完成后 Google 邮箱会收到下载链接
- 下载 ZIP,解压后看
My Activity/Gemini/目录,里面是 HTML 文件(不是 JSON)提示我解压后的目录路径(整目录,不只是单个文件)。
B.2 文件结构(HTML 格式)
Gemini 导出的是 HTML 不是 JSON——这是最大的坑。
# 先看目录里有什么
ls /path/to/My\ Activity/Gemini/
# 典型:My\ Activity.html 是单文件聚合,或者 Gemini\ Apps.html 等分文件
# 文件结构:每个 <div class="outer-cell"> 是一个对话轮次
B.3 HTML → 结构化文本
用 python 快速解析:
from bs4 import BeautifulSoup
from pathlib import Path
import json, re
src = Path("/path/to/My Activity/Gemini")
out = []
for html_file in src.glob("*.html"):
soup = BeautifulSoup(html_file.read_text(encoding="utf-8"), "html.parser")
# 提取每条对话
cells = soup.find_all("div", class_=re.compile(r"outer-cell|content-cell"))
for cell in cells:
text = cell.get_text("\n", strip=True)
out.append({"file": html_file.name, "text": text})
print(json.dumps(out, ensure_ascii=False, indent=2))
或用 html2text:
html2text "/path/to/My Activity/Gemini/My Activity.html" > /tmp/gemini.txt
# 然后用 grep 搜
grep -n "我建议\|离职\|辞职" /tmp/gemini.txt
B.4 Gemini 导出的局限
⚠️ 跟 ChatGPT / Claude 相比,Gemini 导出有几个明显短板:
- HTML 格式,不能直接 jq——必须先解析
- 没有结构化的 role 字段——要靠 DOM 节点区分"用户问题"和"Gemini 回复"
- 时间戳可能不准确——Takeout 导出时区处理有时出问题
- 附件/图片元信息缺失——Google 通常把附件归到独立 Drive 文件,不在 Takeout 里
如果用户要做严肃分析(时间线/语义检索),建议额外说明这些局限,或让用户优先用 ChatGPT/Claude 那边。
Part C:跨平台统一分析(用户同时导出了多个时)
如果用户同时给了 Claude + ChatGPT + Gemini 三份数据,做"跨平台时间线"时:
C.1 把三家产物统一到同一份 JSONL
import json, sys, re
from pathlib import Path
from datetime import datetime, timezone
def normalize(rec):
"""统一字段:sender, text, created_at, source, session_id, session_name"""
return {
"sender": "assistant" if rec["sender"] in ("assistant", "model", "gemini") else "human",
"text": rec["text"],
"created_at": rec["created_at"],
"source": rec["source"], # "claude" / "chatgpt" / "gemini"
"session_id": rec["session_id"],
"session_name": rec["session_name"],
}
# 然后写出 jsonl
with open("/tmp/unified.jsonl", "w", encoding="utf-8") as f:
for rec in records:
f.write(json.dumps(normalize(rec), ensure_ascii=False) + "\n")
C.2 跨平台查询
# 在所有平台上找"离职"相关
grep -E "离职|辞职|跳槽" /tmp/unified.jsonl | head -20
# 按平台分布
jq -r '.source' /tmp/unified.jsonl | sort | uniq -c
# 按月份聚合
jq -r '.created_at[0:7]' /tmp/unified.jsonl | sort | uniq -c
Part D:安全与隐私(必须告知)
- ChatGPT 导出里包含 user.json,里面有用户邮箱、账号信息
- Gemini 导出里可能包含 Google 账户关联的其他活动记录(搜索、YouTube)
- 一律建议用户导出任务完成后移出工作目录
- 输出报告时默认对邮箱/手机/身份证/银行卡打码
Part E:常见坑(踩过标这里)
- ❌ ChatGPT 的 conversations.json 顶层是 array,但 mapping 字段是嵌套 dict——别用
.chat_messages[]这种 Claude 习惯的语法 - ❌ ChatGPT 时间戳是 Unix 秒数,不是 ISO 字符串——
1633072800这种,需要| todate转 - ❌ Gemini 是 HTML,不是 JSON——
jq没法直接处理,先转文本 - ❌ ChatGPT 导出的
message_feedback.json包含用户 thumbs up/down——隐私敏感,不要 echo - ✅ 三家产物的时区都是 UTC——跨平台对照时统一换算到用户本地时区
- ✅ 如果文件 > 500MB,优先按时间窗口分片——不要一次性 cat/jq
- ✅ ChatGPT mapping 可能含 "current_node" 链,要把这条链的节点按顺序拍平,不是 to_entries 的字典序
微信扫一扫