用localstorage+isdirty标记+结构化存储可实现崩溃后恢复最近有效上下文:消息需含role/content/timestamp字段并校验;isdirty严格绑定状态变更;恢复时优先加载dirty=true且24小时内数据,并叠加时间戳校验与长度截断容错。

直接用 localStorage + isDirty 标记 + 对话历史结构化存储,就能在页面意外崩溃后恢复最近一次有效上下文。关键不是“存得全”,而是“存得准、读得稳、用得上”。
一、对话数据必须结构化存储
不能只存 raw 字符串或未校验的 JSON。每次新增消息(user/assistant)后,立即序列化为标准格式写入 localStorage:
- 每条消息含固定字段:
role("user"/"assistant")、content(字符串)、timestamp(毫秒时间戳) - 整个对话历史存为数组,键名建议带版本前缀,如
llm_chat_v2_history,便于后续升级兼容 - 写入前做基础校验:非空 content、role 合法、数组长度合理(防无限追加)
二、isDirty 标记要与状态变更强绑定
这个标记不是装饰,是恢复逻辑的开关。它必须真实反映“当前内存中历史是否已同步到持久层”:
将小说章节转换为电影分镜剧本。用户上传txt/md/docx文本,AI分析场景、角色、情绪、镜头语言,输出专业分镜脚本。适用于用户提及“分镜”“storyboard”“小说转分镜”“影视改编”“镜头脚本”或需要将小说改编为分镜的场景。
- 初始化时:从 localStorage 读取历史 → 成功则设
isDirty = false;失败或为空则设isDirty = true(表示需新建) - 每次调用
addMessage()后,立即执行isDirty = true - 每次成功写入 localStorage 后,再设
isDirty = false - 不依赖用户点击“保存”按钮——自动保存即触发标记更新
三、崩溃恢复流程要主动、轻量、可降级
页面加载完成时(DOMContentLoaded),立刻执行恢复检查:
- 先读
llm_chat_v2_history,尝试 JSON.parse;失败则清空该 key 并跳过 - 若读取成功且数组长度 > 0,再检查对应
llm_chat_v2_dirty标记是否存在且为"true" - 只有
dirty === "true"才认为该历史是“未确认的最新状态”,应优先加载并置顶显示 - 若 dirty 为 false 或不存在,说明上次已正常落盘,可直接使用;但建议额外加一个时间兜底:只加载
timestamp > Date.now() - 24*60*60*1000的消息,避免加载陈旧草稿
四、补充容错设计提升鲁棒性
仅靠 isDirty 不足以覆盖所有异常路径,需叠加两层保护:
- 设置
llm_chat_v2_last_save_time时间戳,在恢复时比对:若距今超过 5 分钟,即使 dirty=true 也忽略(防止残留脏数据) - 为 history 数组添加长度上限(如最多保留 50 条),每次写入前截断最早的消息,避免 localStorage 溢出或解析卡顿
- 在
beforeunload中强制触发一次 save + isDirty=false,哪怕只是尽力而为,也能提高最后时刻的保存成功率










