diff --git a/chatlab.md b/chatlab.md
new file mode 100644
index 00000000..580aceae
--- /dev/null
+++ b/chatlab.md
@@ -0,0 +1,326 @@
+# ChatLab 标准化格式规范 v0.0.1
+
+ChatLab 定义了一套标准的聊天记录数据交换格式,用于支持多平台数据的统一导入和分析。
+只要你将聊天记录转为该格式,那么就可以被 ChatLab 解析并使用其分析能力。
+
+> **注意**
+> 该格式规范目前仍处于早期制定阶段,部分字段和结构可能会在后续版本中调整。
+
+## 概述
+
+### 支持的文件格式
+
+| 格式 | 扩展名 | 适用场景 |
+| --- | --- | --- |
+| **JSON** | `.json` | 中小型记录(<100 万条),结构清晰,易于阅读 |
+| **JSONL** | `.jsonl` | 超大规模记录(>100 万条),流式处理,内存占用恒定 |
+
+### 格式对比
+
+| 特性 | JSON | JSONL |
+| --- | --- | --- |
+| **内存占用** | 需加载完整结构 | 逐行处理,恒定(~100MB) |
+| **文件大小限制** | ~1GB(取决于内存) | 无实际限制 |
+| **追加写入** | - 需重写整个文件 | ✅ 直接追加行 |
+| **错误恢复** | 单处错误整文件失效 | 可跳过错误行继续 |
+| **可读性** | ⭐⭐⭐ 易于阅读 | ⭐⭐ 每行一条记录 |
+| **推荐场景** | 小中型记录(<100 万条) | 大型记录(>100 万条) |
+
+---
+
+## 快速说明
+
+以下是一个最小化的 ChatLab 格式示例,只包含必要字段:
+
+```json
+{
+ "chatlab": {
+ "version": "0.0.1",
+ "exportedAt": 1703001600
+ },
+ "meta": {
+ "name": "我的群聊",
+ "platform": "qq",
+ "type": "group"
+ },
+ "members": [
+ {
+ "platformId": "123456",
+ "accountName": "张三"
+ }
+ ],
+ "messages": [
+ {
+ "sender": "123456",
+ "accountName": "张三",
+ "timestamp": 1703001600,
+ "type": 0,
+ "content": "大家好!"
+ }
+ ]
+}
+
+```
+
+---
+
+## JSON 格式详细说明
+
+### 文件头 (chatlab)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| `version` | string | ✅ | 格式版本号,当前为 "0.0.1" |
+| `exportedAt` | number | ✅ | 导出时间(秒级 Unix 时间戳) |
+| `generator` | string | - | 生成工具名称 |
+| `description` | string | - | 描述信息 |
+
+### 元信息 (meta)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| `name` | string | ✅ | 群名或对话名 |
+| `platform` | string | ✅ | 平台标识,如 `qq` / `wechat` / `discord` / `whatsapp` 等 |
+| `type` | string | ✅ | 聊天类型:`group`(群聊)/ `private`(私聊) |
+| `groupId` | string | - | 群ID(仅群聊) |
+| `groupAvatar` | string | - | 群头像(Data URL 格式) |
+| `sources` | MergeSource[] | - | 合并来源(合并工具生成,见下方说明) |
+
+#### MergeSource 结构(合并来源)
+
+当使用合并工具合并多个聊天记录文件时,`sources` 字段会记录原始文件的来源信息:
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| `filename` | string | ✅ | 原文件名 |
+| `platform` | string | - | 原平台 |
+| `messageCount` | number | ✅ | 消息数量 |
+
+### 成员 (members)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| `platformId` | string | ✅ | 用户唯一标识 |
+| `accountName` | string | ✅ | 账号名称 |
+| `groupNickname` | string | - | 群昵称(仅群聊) |
+| `aliases` | string[] | - | 用户自定义别名 |
+| `avatar` | string | - | 用户头像(Data URL 格式) |
+
+### 消息 (messages)
+
+| 字段 | 类型 | 必填 | 说明 |
+| --- | --- | --- | --- |
+| `sender` | string | ✅ | 发送者的 `platformId` |
+| `accountName` | string | ✅ | 发送时的账号名称 |
+| `groupNickname` | string | - | 发送时的群昵称 |
+| `timestamp` | number | ✅ | 秒级 Unix 时间戳 |
+| `type` | number | ✅ | 消息类型(见下方对照表) |
+| `content` | string | null | ✅ |
+
+---
+
+## 消息类型对照表
+
+> **提示**
+> 若您的聊天记录中有其他特殊类型需要支持,请提交 issue 说明情况,我们会评估是否加入标准消息类型中。
+
+### 基础消息类型 (0-19)
+
+| 值 | 名称 | 说明 |
+| --- | --- | --- |
+| 0 | TEXT | 文本消息 |
+| 1 | IMAGE | 图片 |
+| 2 | VOICE | 语音 |
+| 3 | VIDEO | 视频 |
+| 4 | FILE | 文件 |
+| 5 | EMOJI | 表情包/贴纸 |
+| 7 | LINK | 链接/卡片 |
+| 8 | LOCATION | 位置 |
+
+### 交互消息类型 (20-39)
+
+| 值 | 名称 | 说明 |
+| --- | --- | --- |
+| 20 | RED_PACKET | 红包 |
+| 21 | TRANSFER | 转账 |
+| 22 | POKE | 拍一拍/戳一戳 |
+| 23 | CALL | 语音/视频通话 |
+| 24 | SHARE | 分享(音乐、小程序等) |
+| 25 | REPLY | 引用回复 |
+| 26 | FORWARD | 转发消息 |
+| 27 | CONTACT | 名片消息 |
+
+### 系统消息类型 (80+)
+
+| 值 | 名称 | 说明 |
+| --- | --- | --- |
+| 80 | SYSTEM | 系统消息(入群/退群/群公告等) |
+| 81 | RECALL | 撤回消息 |
+| 99 | OTHER | 其他/未知 |
+
+---
+
+## 头像格式说明
+
+头像字段 `avatar` 和 `groupAvatar` 使用 **Data URL** 格式:
+`data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD...`
+
+**支持的图片格式:**
+
+* `image/jpeg` - JPEG 格式(**推荐**,体积较小)
+* `image/png` - PNG 格式
+* `image/gif` - GIF 格式
+* `image/webp` - WebP 格式
+
+> **建议**
+> 导出时建议将头像压缩为 100×100 像素以内,以减小文件体积。
+
+---
+
+## 完整示例
+
+### 群聊示例(含可选字段)
+
+```json
+{
+ "chatlab": {
+ "version": "0.0.1",
+ "exportedAt": 1703001600,
+ "generator": "My Converter Tool",
+ "description": "2024年技术交流群聊天记录备份"
+ },
+ "meta": {
+ "name": "技术交流群",
+ "platform": "wechat",
+ "type": "group",
+ "groupId": "38988428513",
+ "groupAvatar": "data:image/jpeg;base64,/9j/4AAQSkZJRg..."
+ },
+ "members": [
+ {
+ "platformId": "abc123",
+ "accountName": "张三",
+ "groupNickname": "群主-张三",
+ "avatar": "data:image/jpeg;base64,/9j/4AAQSkZJRg..."
+ },
+ {
+ "platformId": "def456",
+ "accountName": "李四",
+ "groupNickname": "管理员",
+ "avatar": "data:image/jpeg;base64,/9j/4AAQSkZJRg..."
+ }
+ ],
+ "messages": [
+ {
+ "sender": "abc123",
+ "accountName": "张三",
+ "groupNickname": "群主-张三",
+ "timestamp": 1703001600,
+ "type": 0,
+ "content": "大家好!欢迎加入技术交流群~"
+ },
+ {
+ "sender": "def456",
+ "accountName": "李四",
+ "groupNickname": "管理员",
+ "timestamp": 1703001610,
+ "type": 1,
+ "content": "[图片: screenshot.jpg]"
+ }
+ ]
+}
+
+```
+
+### 私聊示例
+
+```json
+{
+ "chatlab": {
+ "version": "0.0.1",
+ "exportedAt": 1703001600
+ },
+ "meta": {
+ "name": "与小明的对话",
+ "platform": "qq",
+ "type": "private"
+ },
+ "members": [
+ {
+ "platformId": "123456789",
+ "accountName": "我",
+ "avatar": "data:image/jpeg;base64,/9j/4AAQSkZJRg..."
+ },
+ {
+ "platformId": "987654321",
+ "accountName": "小明",
+ "avatar": "data:image/jpeg;base64,/9j/4AAQSkZJRg..."
+ }
+ ],
+ "messages": [
+ {
+ "sender": "123456789",
+ "accountName": "我",
+ "timestamp": 1703001600,
+ "type": 0,
+ "content": "在吗?"
+ }
+ ]
+}
+
+```
+
+---
+
+## JSONL 流式格式
+
+JSONL(JSON Lines)格式适用于超大规模聊天记录(>100 万条),可避免内存溢出问题。
+
+### 格式特点
+
+* 每行一个 JSON 对象
+* 通过 `_type` 字段区分行类型:`header` / `member` / `message`
+* 内存占用恒定(约 100MB),支持 GB 级文件
+* 支持流式写入,可边导出边追加
+
+### 行类型说明
+
+| `_type` | 说明 | 是否必需 |
+| --- | --- | --- |
+| `header` | 文件头,包含 `chatlab` 和 `meta` | ✅ 必须在第一行 |
+| `member` | 成员信息 | - 可选 |
+| `message` | 消息记录 | ✅ 至少一条 |
+
+### 完整示例
+
+```jsonl
+{"_type":"header","chatlab":{"version":"0.0.1","exportedAt":1703001600},"meta":{"name":"技术交流群","platform":"qq","type":"group"}}
+{"_type":"member","platformId":"123456","accountName":"张三","groupNickname":"群主"}
+{"_type":"member","platformId":"789012","accountName":"李四"}
+{"_type":"message","sender":"123456","accountName":"张三","groupNickname":"群主","timestamp":1703001600,"type":0,"content":"大家好!"}
+{"_type":"message","sender":"789012","accountName":"李四","timestamp":1703001610,"type":0,"content":"你好!"}
+{"_type":"message","sender":"123456","accountName":"张三","groupNickname":"群主","timestamp":1703001620,"type":1,"content":"[图片]"}
+
+```
+
+### 解析规则
+
+1. **第一行必须是 header**:包含 `chatlab` 版本和 `meta` 元信息
+2. **成员行在消息之前**:可选,如果省略,成员信息会从消息中自动收集
+3. **消息按时间顺序排列**:建议按 `timestamp` 升序排列
+4. **每行独立完整**:单行解析错误可跳过继续处理
+5. **支持注释行**:以 `#` 开头的行会被跳过(可用于添加备注)
+
+> **注意**
+> * 每行必须是有效的 JSON(不能跨行)
+> * 行之间用换行符 `\n` 分隔
+>
+>
+
+---
+
+## 版本历史
+
+| 版本 | 日期 | 变更 |
+| --- | --- | --- |
+| 0.0.1 | 2025-12 | 初始版本 |
\ No newline at end of file
diff --git a/internal/chatlog/http/route.go b/internal/chatlog/http/route.go
index c8a58dd0..af53aa3f 100644
--- a/internal/chatlog/http/route.go
+++ b/internal/chatlog/http/route.go
@@ -15,6 +15,7 @@ import (
"github.com/xuri/excelize/v2"
"github.com/sjzar/chatlog/internal/errors"
+ "github.com/sjzar/chatlog/internal/model"
"github.com/sjzar/chatlog/pkg/util"
"github.com/sjzar/chatlog/pkg/util/dat2img"
"github.com/sjzar/chatlog/pkg/util/silk"
@@ -131,6 +132,20 @@ func (s *Service) handleChatlog(c *gin.Context) {
}
switch strings.ToLower(q.Format) {
+ case "chatlab":
+ talkerName := q.Talker
+ if len(messages) > 0 {
+ // Try to find a non-empty TalkerName from messages
+ for _, m := range messages {
+ if m.TalkerName != "" {
+ talkerName = m.TalkerName
+ break
+ }
+ }
+ }
+
+ chatLabData := model.ConvertToChatLab(messages, q.Talker, talkerName)
+ c.JSON(http.StatusOK, chatLabData)
case "csv":
c.Writer.Header().Set("Content-Type", "text/csv; charset=utf-8")
c.Writer.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=%s_%s_%s.csv", q.Talker, start.Format("2006-01-02"), end.Format("2006-01-02")))
diff --git a/internal/chatlog/http/static/index.htm b/internal/chatlog/http/static/index.htm
index e1b119f8..85ee05c5 100644
--- a/internal/chatlog/http/static/index.htm
+++ b/internal/chatlog/http/static/index.htm
@@ -447,6 +447,7 @@