历史归档
核心目标
让用户离开页面再回来时,所有素材、对话、提示词都能秒级恢复。
三层存储架构
text
┌────────────────────────────────────────────────────┐
│ 浏览器层(前端) │
│ │
│ ┌─────────────────┐ ┌──────────────────┐ │
│ │ localStorage │ │ IndexedDB │ │
│ │ - 元数据索引 │ │ - 图片 Blob │ │
│ │ - SKU 列表 │ │ - 视频 URL │ │
│ │ - 当前会话 ID │ │ - 完整对话 │ │
│ │ - 配置偏好 │ │ - 提示词历史 │ │
│ │ │ │ │ │
│ │ ≤ 5 MB │ │ GB 级容量 │ │
│ └─────────────────┘ └──────────────────┘ │
└────────────────────┬───────────────────────────────┘
│
│ 持久化(异步)
▼
┌────────────────────────────────────────────────────┐
│ 后端层(Go + SQLite) │
│ │
│ - usage_logs:配额扣减审计 │
│ - request_logs:完整请求链路 │
│ - kg_entities + kg_relations:GraphRAG 图谱 │
└────────────────────────────────────────────────────┘存储分级策略
| 数据类型 | 存储位置 | 容量级别 | TTL |
|---|---|---|---|
| 用户会话 token | HttpOnly Cookie | < 1KB | 7 天 |
| 当前页面状态 | localStorage | ≤ 5MB | 永久 |
| SKU 索引 / 元数据 | localStorage | ≤ 5MB | 永久 |
| 图片缩略图 | IndexedDB | 100MB | 永久 |
| 图片原图 Blob | IndexedDB | GB 级 | 永久 |
| 视频文件 | 供应商 CDN URL | URL only | 60 天 |
| 选品对话 | IndexedDB | ≤ 100MB | 永久 |
| 配额日志 | 后端 SQLite | 不限 | 永久 |
为什么不用 localStorage 存图片?
localStorage 限制
- 容量上限 5MB(部分浏览器 10MB)
- 同步 API → 阻塞主线程
- 仅支持字符串 → 大图片 base64 化体积膨胀 33%
IndexedDB 优势
- 容量 GB 级(受磁盘限制)
- 异步 API → 不阻塞 UI
- 原生支持 Blob → 直接存二进制
- 索引查询性能高
IndexedDB Schema 设计
javascript
// 数据库结构
const dbSchema = {
name: 'haiyu_history',
version: 1,
stores: {
// 1. 多对话历史
sessions: {
keyPath: 'id',
indexes: ['type', 'created_at', 'title']
},
// 2. 图片大文件
images: {
keyPath: 'id',
indexes: ['session_id', 'model', 'created_at']
},
// 3. 一键全案记录
all_in_one: {
keyPath: 'id',
indexes: ['product_title', 'created_at']
},
// 4. 选品分析
product_analysis: {
keyPath: 'session_id',
indexes: ['topic', 'created_at']
},
// 5. 提示词模板
prompt_templates: {
keyPath: 'id',
indexes: ['category', 'usage_count']
}
}
}数据示例
javascript
{
id: 'img_2026-05-01_xyz',
session_id: 'session_abc',
blob: <Blob 1024×1024 PNG>,
thumbnail: <Blob 256×256 JPG>,
prompt: 'Stainless steel kitchen rack ...',
negative_prompt: '',
model: 'NanoBananaPro',
ratio: '1:1',
resolution: '1K',
created_at: '2026-05-01T08:32:11Z',
metadata: {
seed: 12345,
cfg_scale: 7.5,
graphrag_session: 'kg_xxx'
}
}javascript
{
id: 'aio_2026-05-01_001',
product_title: 'Stainless Steel Kitchen Rack',
parameters: { material: '304 SUS', size: '60×30×80cm', ... },
references: ['ref_image_1.jpg', 'ref_image_2.jpg'],
graphrag: {
entities: [...],
relations: [...],
visualization_url: 'idb://...'
},
outputs: {
main_image: 'idb://img_xxx',
bullets: ['...', '...', '...', '...', '...'],
aplus: ['idb://...', 'idb://...', ...],
grid_4: 'idb://...',
video_url: 'https://cdn.veo.../xxx.mp4'
},
created_at: '2026-05-01T08:30:00Z',
duration_ms: 38420
}javascript
{
session_id: 'pa_2026-05-01_001',
topic: '美国站厨房收纳类目分析',
category: 'Kitchen Storage',
rounds: [
{
user: '我想做美国站厨房收纳...',
ai: '该类目(B0085QQTUC 父节点)当前格局...',
timestamp: '2026-05-01T09:00:00Z',
tokens: { prompt: 234, completion: 1023 }
}
],
extracted_entities: {
categories: ['Kitchen Storage'],
asins: ['B0085QQTUC'],
keywords: ['small apartment', 'foldable']
},
total_tokens: 4567
}多对话切换
历史归档支持多对话标签页式切换:
text
左侧侧栏:
┌──────────────────────────┐
│ + 新对话 │
├──────────────────────────┤
│ 📌 当前会话 │
│ 🍴 厨房收纳全案 │
│ 🏕️ 户外帐篷主图 │
│ 💧 智能水杯 A+ 图 │
│ 📊 美国厨房选品分析 │
│ ... │
│ │
│ [按时间] [按 SKU] │
└──────────────────────────┘切换会话时,主区自动恢复:
- 所有图片画廊
- 文案历史
- GraphRAG 图谱节点
- 输入框最后状态
跨设备同步(路线图)
未来规划
当前版本数据仅保存在浏览器 IndexedDB。下个版本计划:
- 用户主动「云同步」 → 上传到后端 SQLite
- 接入对象存储(OSS / S3) → 替代 IndexedDB
- 多设备登录自动拉取
性能数据
| 操作 | 耗时 | 说明 |
|---|---|---|
| 写入 1MB 图片 Blob | ≈ 50ms | IndexedDB 异步写入 |
| 读取 1000 张缩略图列表 | < 500ms | 索引查询 + 批量读 |
| 搜索 SKU 历史 | < 100ms | localStorage 元数据索引 |
| 切换会话 + 恢复 | < 800ms | 含图片懒加载 |
| 千张图历史回滚 | < 1s | 视口可见时再加载 |
清理策略
javascript
// 用户在「设置」页可清理
- 单条会话删除
- 按时间范围批量删除(如 30 天前)
- 全部清空javascript
// 用户开启后自动清理
- 超过 90 天的会话自动归档
- 单会话超过 100 张图自动压缩
- 视频 URL 60 天后自动失效(CDN 限制)容灾与备份
数据持久性提醒
- IndexedDB 数据仅在当前浏览器,清浏览器缓存会清空
- 重要素材请及时下载到本地
- 后端 SQLite 仅保存配额、日志、知识图谱,不存图片原文件