Skip to content

About

Scrape kimi chat history via user cookie and store locally. Automaticly label them with LLM and provide statistics.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

Kimi Bucket 🪣

Kimi 对话历史管理器 —— 将你在 Kimi (kimi.moonshot.cn) 上的所有对话归档到本地,使用 LLM 自动分类打标签,配合可视化图表,构建个人知识库。


技术栈

层 技术
后端 Express (TypeScript), better-sqlite3 (SQLite), Playwright (浏览器自动化), OpenAI SDK
前端 React 18 + Vite, Tailwind CSS, Recharts, React Router v6
包管理 npm workspaces (monorepo)

项目结构

kimi-bucket/
├── package.json              # 根 workspaces 配置 (concurrently 并行启动)
├── .env                      # PORT 配置 (默认 3001)
├── .env.example
├── cookies.json              # Kimi 登录 Cookie (由 Playwright 登录后保存)
│
├── server/                   # 后端 (Express + SQLite)
│   ├── package.json
│   ├── tsconfig.json
│   └── src/
│       ├── index.ts              # Express 入口, 路由挂载, 静态文件服务
│       ├── db/
│       │   └── index.ts          # 数据库初始化 (建表) + 配置存取
│       ├── lib/
│       │   └── day-boundary.ts   # 凌晨 4 点日界线工具
│       ├── scraper/
│       │   ├── auth.ts           # Playwright 登录, Cookie 管理, 验证
│       │   └── kimi.ts           # Kimi API v2 客户端 (ListChats, ListMessages)
│       └── routes/
│           ├── conversations.ts  # 对话列表 (分页/搜索/标签日期筛选) + 详情 + 手动打标签
│           ├── tags.ts           # 标签 CRUD + 导出/导入 (.txt)
│           ├── scraper.ts        # 登录状态 / 登录 / 同步 (SSE 流)
│           ├── llm.ts            # Token 估算 / AI 分类分析 (SSE 流)
│           ├── config.ts         # 应用配置读写 (LLM, 预览长度, 截断行数, 日期策略)
│           ├── charts.ts         # 图表数据 (日/周/月聚合)
│           └── migrate.ts        # 历史报告导入 (output/*.md)
│
├── client/                   # 前端 (React + Vite)
│   ├── package.json
│   ├── vite.config.ts            # 开发代理 /api → localhost:3001, build → server/public/
│   ├── tailwind.config.js
│   └── src/
│       ├── App.tsx               # 根组件: 侧边导航 + 路由 (/  /charts  /settings)
│       ├── main.tsx              # React 入口
│       ├── types.ts              # 共享类型定义
│       ├── lib/
│       │   ├── api.ts            # API 客户端 (fetch + EventSource)
│       │   └── utils.ts          # 工具函数 (日期格式化, 颜色亮度, Kimi 链接, SSE 监听)
│       └── pages/
│           ├── Conversations/    # 对话库主页面 (列表/搜索/筛选/同步/分析)
│           ├── Charts/           # 图表页 (堆叠柱状图 + 饼图 + 明细表)
│           └── Settings/         # 设置页 (偏好设置/标签管理/Prompt/登录)
│
├── data/
│   └── kimi-bucket.db            # SQLite 数据库 (gitignore)
└── output/                       # 历史日报导入源 (gitignore)

数据库设计

核心表

-- 对话
conversations (
    id TEXT PRIMARY KEY,          -- 等同于 kimi_id
    kimi_id TEXT UNIQUE NOT NULL,
    title TEXT NOT NULL,
    kimi_created_at TEXT NOT NULL,
    kimi_updated_at TEXT NOT NULL,
    messages TEXT NOT NULL DEFAULT '[]',   -- JSON: [{role, content}]
    preview TEXT,                           -- 首条用户消息截取
    synced_at TEXT NOT NULL                 -- 本地同步时间
);

-- 标签
tags (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT UNIQUE NOT NULL,
    description TEXT,
    color TEXT NOT NULL DEFAULT '#6366f1',
    is_system INTEGER NOT NULL DEFAULT 0,   -- 1=系统内置 (未分类/其他)
    created_at TEXT
);

-- 对话-标签关联
conversation_tags (
    conversation_id TEXT NOT NULL,
    tag_id INTEGER NOT NULL,
    source TEXT NOT NULL DEFAULT 'manual',  -- manual/llm/system
    assigned_at TEXT,
    PRIMARY KEY (conversation_id, tag_id)
);

-- LLM 分析记录
llm_analyses (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    conversation_id TEXT NOT NULL,
    tags_json TEXT NOT NULL DEFAULT '[]',   -- JSON: ["标签1", "标签2"]
    summary TEXT,                            -- LLM 生成的一句话摘要
    model TEXT NOT NULL,
    prompt_used TEXT,                        -- 使用的完整 prompt
    tokens_used INTEGER,
    created_at TEXT
);

-- 历史日报
legacy_reports (report_date, content, imported_at);

-- 应用配置 (键值对)
app_config (key TEXT PRIMARY KEY, value TEXT NOT NULL);

内置系统标签

标签 颜色 说明
未分类 #94a3b8 (slate-400) 新同步的对话自动打上,LLM 分析成功后自动移除
其他 #cbd5e1 (slate-300) LLM 认为不属于任何预定义标签时使用

核心流程

1. Kimi 登录与认证

用户点击「打开浏览器登录」
  → Playwright 启动 Chromium headful
  → 打开 kimi.com, 用户手动登录
  → 终端按 Enter 确认
  → 保存 Cookie 到 server/cookies.json (含 kimi-auth token)
  → 后续请求携带 Cookie + Authorization Bearer header

认证文件: server/src/scraper/auth.ts

  • loginInteractive() — 交互式登录
  • verifyCookies() — 通过实际 API 调用验证是否过期
  • getAuthToken() — 从 Cookie 中提取 kimi-auth token

2. 对话同步

用户选择同步模式并确认
  → POST /api/scraper/sync (SSE 流式响应)
  → Kimi API v2: ListChats (分页获取全部聊天列表)
  → 根据模式筛选:
      - incremental: 只取 updateTime > 本地最新记录的
      - range: 按用户指定日期区间
      - recent: 取最近 N 条
  → 对每个对话: ListMessages 获取完整消息
  → 写入/更新 SQLite:
      - 新对话: INSERT + 自动打「未分类」标签
      - 已有对话: UPDATE (日期策略由配置决定)
  → SSE 推送实时进度到前端

同步模式实现: server/src/scraper/kimi.ts

  • KIMI_API_V2 = https://www.kimi.com/apiv2
  • gRPC-web 端点: kimi.chat.v1.ChatService/ListChats, kimi.gateway.chat.v1.ChatService/ListMessages

日期冲突策略 (sync_date_conflict 配置项):

  • kimi (默认): 使用 Kimi 返回的日期
  • local: 保留本地已有日期
  • newer: 取两者中较新的

3. LLM 分类分析

用户选中对话 → 点击「分析选中」
  → GET /api/llm/estimate?ids=... 估算 token 消耗
  → 弹出确认框 (显示选中数量和预估 tokens)
  → 用户确认 → GET /api/llm/analyze?ids=... (SSE)
  → 对每条对话:
      1. 构建 Prompt (注入 {tags} {title} {messages})
      2. 调用 OpenAI-compatible API
      3. 解析 JSON 响应 → 提取 tags 和 summary
      4. 清理标签名 (去除 ":描述" 后缀, "()" 等)
      5. 匹配数据库中的标签:
          - 匹配成功 → 打上对应标签
          - LLM 返回"未分类" → 保持未分类状态
          - 匹配失败但有标签名 → 归入「其他」
      6. 删除旧的 LLM 标签 + '未分类' 系统标签 (如果匹配成功)
      7. 保存分析记录到 llm_analyses 表

模型管理: server/src/routes/llm.ts

  • extractJson() — 容错 JSON 解析 (支持 json 代码块, 裸 JSON)
  • normalizeTags() — 标准化标签数组
  • cleanName() — 去除 LLM 输出中的「标签:描述」模式和括号后缀
  • estimateTokens() — 中文字符按 1.5 char/token, 英文按 4 char/token 估算

4. 日界线 (凌晨 4 点)

server/src/lib/day-boundary.ts 和 client/src/lib/utils.ts:

  • 凌晨 4 点之前更新的对话,其 naturalDay 算作前一天
  • 例如: 2026-01-15 03:30 → naturalDay = 2026-01-14
  • 前端筛选日期范围时使用 naturalDay 作为查询维度

5. 图表数据

GET /api/charts/data?period=daily|weekly|monthly&from=&to=
  → 查询所有对话 + 关联标签
  → 按日/周/月聚合: 每个时间桶 × 每个标签 = 计数
  → 返回 { data: [{ date, 标签A: N, 标签B: M, ... }], tagNames: [...] }

前端使用 Recharts 渲染:

  • 堆叠柱状图 — 标签分布趋势 (点击柱子可跳转到对应日期+标签筛选)
  • 饼图 — 总体分布 (按数量降序, 点击扇区跳转)
  • 数据明细表

6. 标签导出/导入

  • 导出: GET /api/tags/export → 下载 .txt 文件, 格式 标签名 或 标签名|描述
  • 导入: POST /api/tags/import → 解析每行, INSERT OR IGNORE 保存到数据库

配置项

所有配置存储在 app_config 表中,通过设置页面的「偏好设置」Tab 管理:

Key 默认值 说明
llm_base_url https://api.openai.com/v1 LLM API 地址
llm_api_key (空) API Key
llm_model gpt-4o-mini 模型名称
preview_length 200 对话列表预览文本长度 (50-2000)
message_max_lines 15 展开消息时的截断行数 (5-100)
sync_date_conflict kimi 重复对话时的日期策略 (kimi/local/newer)
classification_prompt (预设模板) LLM 分类 Prompt, 支持 {tags} {title} {messages} 变量

默认分类 Prompt

你是一个对话分类器。请根据以下预定义标签,为给定的对话分配一个或多个标签。

可用标签:
{tags}

请返回 JSON 格式:
{"tags": ["标签名1", "标签名2"], "summary": "一句话概括这个对话的内容"}

如果对话不属于任何标签,返回 {"tags": ["未分类"], "summary": "..."}

对话标题:{title}
对话内容(截取前2000字):
{messages}

开发指南

环境要求

  • Node.js ≥ 18
  • npm ≥ 9

安装

cd kimi-bucket
npm install       # 安装所有 workspace 依赖

配置

cp .env.example .env
# 编辑 .env: PORT=3001

启动开发环境

npm run dev
# server → localhost:3001 (tsx watch)
# client → localhost:5173 (Vite dev server, proxy /api → 3001)

构建生产版本

npm run build
# client 构建到 server/public/
# server 编译到 server/dist/

生产启动

npm start        # → node server/dist/index.js
# 访问 http://localhost:3001

API 接口速览

Conversations

方法 路径 说明
GET /api/conversations 列表 (分页/搜索/标签/日期筛选)
GET /api/conversations/:id 详情 (含完整消息)
POST /api/conversations/:id/tags 手动设置标签

Tags

方法 路径 说明
GET /api/tags 所有标签
POST /api/tags 创建标签
PATCH /api/tags/:id 编辑标签
DELETE /api/tags/:id 删除标签
GET /api/tags/export 导出 (text/plain)
POST /api/tags/import 导入 (text/plain)

Scraper

方法 路径 说明
GET /api/scraper/status 登录状态 + 最后同步时间
POST /api/scraper/login 打开浏览器登录
GET /api/scraper/sync 同步 (SSE), query: mode/dateFrom/dateTo/limit/ids

LLM

方法 路径 说明
GET /api/llm/estimate Token 估算, query: ids
GET /api/llm/analyze 分类分析 (SSE), query: ids

Charts

方法 路径 说明
GET /api/charts/data 图表数据, query: period/from/to

Config

方法 路径 说明
GET /api/config 获取所有配置
PATCH /api/config 更新配置
GET /api/config/preview-update 批量更新预览文本

关键设计决策

  1. Kimi API v2 直调: 使用 kimi.chat.v1.ChatService/ListChats 和 kimi.gateway.chat.v1.ChatService/ListMessages gRPC-web 端点,替代旧的页面爬取方式,兼容 Kimi 2.x 所有版本
  2. 凌晨 4 点日界线: 适配使用习惯,凌晨三四点还在聊天的场景算作前一天
  3. 解耦 LLM 分析: 用户先同步对话,手动勾选需要分析的条目,确认 token 估算后再执行。而非自动全量分析
  4. 标签名清洗: LLM 可能返回 标签名:描述 格式,通过 cleanName() 截取冒号/括号前部分来精确匹配
  5. 「未分类」标签自动管理: 新同步自动添加 → LLM 分析成功自动移除,形成一个状态机
  6. 单文件 SQLite: 便于备份和迁移,无需额外数据库服务

依赖清单

Server

  • express + cors — HTTP 服务
  • better-sqlite3 — SQLite 数据库
  • playwright — 浏览器自动化登录
  • openai — LLM API 调用
  • dayjs — 日期处理
  • dotenv — 环境变量

Client

  • react + react-dom (v18)
  • react-router-dom (v6)
  • recharts — 图表
  • tailwindcss — 样式
  • dayjs — 日期格式化
  • vite — 构建工具

About

Scrape kimi chat history via user cookie and store locally. Automaticly label them with LLM and provide statistics.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages