早上决定穿什么,往往只需要几条信息:今天冷不冷,要去哪里,衣橱里哪些衣服能穿。围绕这个具体场景,testPWA 逐渐长成了「树树衣橱」:一个把照片、衣物信息和穿着记录保存在浏览器本机的穿搭工具。
它的主线很短:录入衣物,按天气挑选或自己组合,记录当天穿着,再回看是否合适。实现过程中,比“给出一套搭配”更费功夫的,是让照片不丢、历史不变,以及自动填写不抢走人的决定权。
一件衣物,有不止一种图片
衣橱列表需要快速浏览,编辑需要裁切和旋转,穿着历史则需要保留当时的样子。把同一张大图塞进每个对象,既增加读取成本,也让修改后的图片难以追溯。
当前实现把实体元数据交给 Dexie / IndexedDB,图片优先写入 OPFS;浏览器没有可用的文件写入能力时,回退到 IndexedDB Blob。图片按 SHA-256 内容标识去重,衣物保存源图、展示图和缩略图的引用,列表按需读取缩略图。
展示图最长边为 1600px,缩略图为 320px。源图单独保留,裁切和旋转作为编辑参数记录,因此重新编辑不必从已经压缩过的展示图开始。重新编码的展示图不保留 EXIF,但原始文件可能仍含原元数据;“保存在本机”不能被误写成“所有元数据已经清除”。
图像内容、编辑过程和界面用途有关联,却不应成为一个无法拆开的字段。
本地保存,也需要处理写入冲突
没有账号和云同步,并不意味着没有并发:两个浏览器窗口都可能打开同一个衣橱。旧窗口晚一点保存,就可能覆盖新窗口刚完成的修改。
存储层通过 revision 校验预期版本,先写图像与暂存数据,再在 IndexedDB 事务内检查版本并切换当前数据集:
- 读取当前衣橱及其 revision。
- 写入并校验本次需要的图片,准备新的数据集。
- 在提交事务中再次确认 revision 没有变化。
- 成功后切换 active 指针;发生冲突则提示重新读取。
OPFS 和 IndexedDB 并不是一个跨存储事务,所以图片必须先准备好,最后才发布元数据引用。保存失败时保留原衣橱,过期暂存和无引用资产交给后续清理。这比直接覆盖当前数据多了一步,却给中断和恢复留下了空间。
推荐负责解释条件,历史负责保留事实
“今日”页使用真实天气,结合体感温度、场合、冷热偏好、颜色和近期穿着来筛选最多三套搭配。推荐函数接收明确的天气输入,在本地执行规则排序;它不是生成式虚拟试穿,也没有从衣物照片直接推断整套穿搭。
天气缺失时,应用显示缓存状态或提供重试、换城入口,不用模拟温度补出一套看似可靠的结果。衣橱管理和自定义搭配仍可继续使用。
记录穿着时,只保存衣物 ID 也不够。今天把“白色短袖”改名,或下周删掉一件衣服,都不应该改写上周的记录。因此穿着历史保存当时的衣物名称、属性和图片引用。同一当地日期、时区与相同衣物内容的重复记录会复用已有记录。
当前衣橱描述“现在有什么”,穿着快照描述“那天穿了什么”。这两个问题必须分别回答。
端侧识别先学会尊重手动输入
衣物识别是可选能力。当前使用量化 FashionCLIP 图像编码器,通过 ONNX Runtime Web 在独立 Worker 中以 CPU / WebAssembly 执行;分类与厚度建议复用同一次图像特征,颜色则由本地图像处理提取。照片不发送到云端推理服务。
识别资源与应用壳分别缓存,首次资源体积约 97.4 MiB,不在首次打开应用时自动加载。模型完整缓存后可以离线读取;不支持、失败或关闭时,手工录入继续可用。
更容易被忽略的是表单合并规则。假设识别正在进行,用户已经把名称改成“周五的白衬衫”,迟到的结果不应该覆盖它。实现为名称、分类、颜色、厚度记录 default、user、ai 三种来源:手动修改优先,换图使旧任务失效,撤销仅恢复未被再次手改的自动字段。
厚度只是外观估计。证据不足时保留“不确定”,鞋包配件也不勉强给出衣料厚度。相似度分数不等于准确率,六张示例图的开发验证也不能替代真实衣物照片的评估。
备份的终点,是能够安全恢复
本地优先减少了照片上传的需求,但无法阻止浏览器清理数据、设备损坏或用户换机。可恢复备份因此属于主流程。
当前 ZIP 备份包含个人衣物、套装、偏好、穿着历史及其关联图片,排除示例、草稿、天气缓存和可重建缩略图。恢复先检查格式、字段、引用与图片完整性,写入独立暂存区,展示预览,再经用户确认切换当前衣橱。取消或校验失败都不应先清空原数据。
大文件处理也遵循同样的思路:逐张读取和校验图片,避免先把整个图片库复制为一个巨大的 JavaScript 缓冲区。项目中的约 200 MiB 备份试验验证了结构和文件 I/O 路径,但它不代表所有手机浏览器都具有相同的内存表现。
让界面承接这些边界
树树衣橱采用奶油纸色、酒红强调色、衬线标题和真实衣物平铺,把“今日、衣橱、搭配、我的”组织成四个稳定入口。示例衣橱与个人衣橱分开,第一次体验不需要先准备一整套自己的照片。
这些视觉选择最终要服务于操作:筛选先编辑再应用,关闭编辑时处理草稿,识别可以纠正,恢复必须能预览。界面的温度来自可预期的行为,而不只是纸张颜色。
目前网页版已经实现上述主要流程;自动抠图、账号云同步和虚拟试穿尚未接入。Android / iOS 真机的离线冷启动、大容量恢复、区域天气可达性以及识别准确率仍需要持续验收。项目的下一步,是用更多真实场景检验这些边界。