存储
AISCouncil 将所有数据本地存储在您的浏览器中。没有任何内容上传到任何服务器。存储系统使用两个层级 —— localStorage 用于启动时需要的小型同步读取,IndexedDB 用于大型异步数据,如机器人配置文件和聊天历史。
两层存储架构
| 层级 | API | 容量 | 用例 |
|---|---|---|---|
| localStorage | 同步 | 约 5-10 MB | 主题、API 密钥、设置 —— 页面加载时即时需要的数据 |
| IndexedDB | 异步 | 约 100 MB - 1 GB+ | 机器人配置文件、聊天历史、插件清单 —— 大数据 |
这种分离存在是因为 localStorage 快速但大小有限,而 IndexedDB 实际上无限制但需要异步访问。关键的启动时值(主题、API 密钥、登录状态)存在于 localStorage 中,以便应用程序可以立即渲染而无需等待异步读取。
localStorage 键
所有 localStorage 键使用 ais- 前缀:
| 键 | 类型 | 描述 |
|---|---|---|
ais-theme | string | 当前主题(light、dark 或 system) |
ais-apikey-anthropic | string | Anthropic API 密钥 |
ais-apikey-openai | string | OpenAI API 密钥 |
ais-apikey-xai | string | xAI API 密钥 |
ais-apikey-gemini | string | Google Gemini API 密钥 |
ais-apikey-openrouter | string | OpenRouter API 密钥 |
ais-apikey-deepseek | string | DeepSeek API 密钥 |
ais-apikey-groq | string | Groq API 密钥 |
ais-apikey-mistral | string | Mistral API 密钥 |
ais-user | JSON | 登录用户信息(姓名、邮箱、头像、提供商) |
ais-idb-migrated | string | 指示 localStorage 到 IndexedDB 迁移完成的标志 |
ais-ollama-endpoint | string | 自定义 Ollama 端点 URL(默认:http://localhost:11434) |
ais-custom-providers | JSON | 用户定义的自定义提供商配置数组 |
aiscouncil-settings | JSON | 全局设置(主题、字体大小、能力等) |
aiscouncil-usage | JSON | 使用跟踪数据(token、每个提供商的成本) |
localStorage 中的 API 密钥可被同一来源上运行的任何 JavaScript 访问。这是浏览器应用的标准,但意味着您不应安装不受信任的浏览器扩展。密钥从不包含在 URL 导出或数据备份中。
IndexedDB 键
IndexedDB 将数据存储在名为 ais-db 的数据库内的键值对象存储中(或登录时的每用户数据库):
| 键模式 | 类型 | 描述 |
|---|---|---|
ais-bots | array | 所有机器人会话元数据(ID、名称、配置、创建日期) |
ais-profiles | array | 所有保存的配置文件(单个和委员会) |
ais-chat-{botId} | array | 特定机器人会话的聊天消息历史 |
ais-addon-manifests | array | 安装的插件/插件清单 |
ais-miniprogram-* | varies | 安装的小程序数据 |
每个机器人会话都有自己的聊天键(ais-chat-abc123),因此聊天历史是隔离的,可以独立加载。
自动迁移
首次启动时,AIS.Storage.init() 检查 localStorage 中是否存在旧版本的数据,并自动将其迁移到 IndexedDB。ais-idb-migrated 标志防止后续加载时重复迁移。
如果 IndexedDB 不可用(某些隐私浏览器会阻止它),存储层会透明地回退到 localStorage。应用程序继续工作,但有约 5-10 MB 的存储限制。
可选 SQLite WASM 层
对于涉及大型二进制数据(图像、附件)的高级用例,存储系统可以加载可选的 SQLite WASM 模块。SQLite 与 IndexedDB 并发运行,并将数据存储在浏览器的源私有文件系统 (OPFS) 中。
SQLite 按需加载 —— 除非明确请求或需要用于 blob 存储,否则永远不会加载。要启用它,请转到设置 > 通用 > 存储后端并选择 SQLite。
| 功能 | IndexedDB | SQLite WASM |
|---|---|---|
| 键值存储 | 是 | 是 |
| 二进制 blob 存储 | 有限 | 优化 |
| SQL 查询 | 否 | 是 |
| 持久性 | 浏览器管理 | OPFS(基于文件) |
| 加载 | 立即 | 延迟(首次使用时) |
AIS.Storage API
AIS.Storage 模块提供统一的 API,无论活动后端如何都能工作:
核心操作
// 初始化存储(启动时调用一次)
await AIS.Storage.init();
// 获取值
const bots = await AIS.Storage.get("ais-bots");
// 设置值
await AIS.Storage.set("ais-bots", updatedBots);
// 删除键
await AIS.Storage.delete("ais-chat-abc123");
// 列出所有键
const allKeys = await AIS.Storage.keys();
// 获取所有键值对
const everything = await AIS.Storage.getAll();
// 清除所有数据
await AIS.Storage.clear();
Blob 存储 (SQLite)
// 存储二进制 blob
await AIS.Storage.putBlob("image-001", arrayBuffer, "image/png");
// 检索 blob
const blob = await AIS.Storage.getBlob("image-001");
// { data: Uint8Array, mime: 'image/png', size: 12345 }
实用函数
// 同步 localStorage 助手(用于启动时读取)
const theme = AIS.Storage.loadJSON("ais-theme");
AIS.Storage.saveJSON("ais-theme", "dark");
// TTL 缓存工厂(用于注册表缓存)
const cache = AIS.Storage.cache("ais-models-cache", "ais-models-ts", 86400000); // 24h TTL
const data = cache.load(); // 读取缓存数据
cache.save(newData); // 更新缓存
const stale = cache.isStale(); // 检查缓存是否过期
状态属性
AIS.Storage.isIDB; // 如果 IndexedDB 处于活动状态则为 true
AIS.Storage.hasSQLite; // 如果 SQLite WASM 已加载则为 true
导出和导入
导出数据
转到设置 > 隐私 > 导出所有数据或使用 API:
const backup = await AIS.Storage.exportData();
// 返回: { bcz_version: "1.0.0", exported: "2026-02-19T...", data: {...} }
导出包括所有机器人配置文件、聊天历史、设置和插件清单。它明确排除:
- API 密钥(从不导出)
- 配置文件中的每成员 API 密钥(剥离到只有提供商/模型)
导出保存为 ais-backup-YYYY-MM-DD.json。
如果您激活了 SQLite blob 存储,导出还会生成一个单独的 ais-blobs-YYYY-MM-DD.db 文件,包含 SQLite 数据库。
导入数据
转到设置 > 隐私 > 导入数据或使用 API:
const count = await AIS.Storage.importData(jsonBackup);
// 返回: 导入的项目数
导入接受:
.json文件(标准备份格式).db文件(SQLite 数据库)
即使文件中存在 API 密钥,也不会导入。
存储配额
浏览器存储配额因平台而异:
| 浏览器 | IndexedDB 配额 | 具有持久存储 |
|---|---|---|
| Chrome/Edge | 磁盘空间的约 60% | 相同,但不会被驱逐 |
| Firefox | 磁盘空间的约 50% | 提示用户授予权限 |
| Safari | 初始约 1 GB,用户可以授予更多 | 相同 |
AISCouncil 在初始化时通过 navigator.storage.persist() 请求持久存储。当被授予时,当存储空间不足时,浏览器不会自动驱逐您的数据。
打开浏览器的开发者工具,转到应用程序 > 存储,查找来源 aiscouncil.net 以查看当前存储使用情况和配额。
隐私
所有数据都保留在您的设备上:
- 无服务器上传 —— 机器人配置、聊天历史和设置永远不会发送到任何服务器
- 无分析 —— 不传输任何使用数据
- 无 cookie —— 应用程序使用
localStorage和 IndexedDB,而不是跟踪 cookie(ais-authcookie 仅用于跨子域身份验证检测) - 无第三方存储 —— 数据仅存储在
aiscouncil.net来源下
清除数据
要清除所有存储的数据:
- 设置 > 隐私 > 清除所有数据 —— 删除所有 IndexedDB 数据、配置文件和聊天历史
- 浏览器开发者工具 > 应用程序 > 清除存储 —— 核选项,删除包括 localStorage 在内的所有内容
- 单独聊天删除 —— 在侧边栏中右键点击机器人并选择删除
清除所有数据是不可逆的。如果您想要备份,请先导出数据。通过浏览器开发者工具清除时,存储在 localStorage 中的 API 密钥也会被删除。
小程序的每机器人存储
每个安装的小程序都有自己的隔离存储命名空间。小程序通过 ais.storage SDK API 访问存储,该 API 映射到 IndexedDB 中每应用前缀的键。一个小程序无法访问另一个的数据。
// 在小程序内部
await ais.storage.set("my-key", "my-value");
const val = await ais.storage.get("my-key");
const keys = await ais.storage.keys();
await ais.storage.remove("my-key");
卸载小程序时会删除小程序的存储。