# 相册「模型 / LoRA 识别」修复 + 全量回填（2026-09-13）

> 站点：http://192.168.31.76:8900 （口令见 `comfyui-gallery/config.json`）
> 代码：`/home/zyw/Downloads/comfyui-gallery/`（备份 `bak/`）
> 触发：用户反馈「相册不能自动识别模型和 LoRA，只能识别 krea2 且标成 krea，其他模型全被当成"其他"」

## 一、修复前实测现状

```
总数 654（只收录 9/9 部署之后的新作品）
家族：Krea 634 | 其他 11 | 未识别 9
LoRA：KNP_000003000 ×609 | krea2_darkbrush ×3 | krea2-masterpieces-v51 ×1 | hanfu-v3.0-song ×1
```

三条独立缺陷：

1. **视频（411 个）全部瞎**。旧 `sync-agent.js` 只解析 PNG 文本块，视频靠 ComfyUI `/history` 按文件名反查；
   而 ComfyUI `/history` 早就清空（`{}`），于是所有视频常年停在「未识别」。
2. **家族规则太粗、判据用错**。规则把「模型 + LoRA + 节点类型」拼成一个字符串去正则匹配，不区分
   UNETLoader 的主模型、VAELoader 的 VAE、CLIPLoader 的文本编码器、UpscaleModelLoader 的放大模型；
   于是 Pony（`realPony_*`）、国风3（`GuoFeng3_Fix`）、纯放大的后处理作品全部落进「其他」。
3. **存量 1070 个文件根本没入库**。`sinceEpoch` 把部署前的 Boogu(564)、AnimateDiff(108)、ComfyUI(34)、
   视频(330) 等全部挡在门外，相册里从来看不到它们，谈不上识别。

## 二、关键发现：视频其实自带完整元数据

ComfyUI 官方 `SaveVideo` / VHS 会把**整个 prompt 图与 workflow 写进视频容器 tag**：

| 容器 | tag 键名 | 实测覆盖 |
|---|---|---|
| mp4 | `prompt` / `workflow`（小写） | 363 个 |
| webm | `PROMPT` / `WORKFLOW`（大写） | 48 个 |

`ffprobe -v quiet -print_format json -show_format <file>` 即可读出 → **411/411 视频都能还原主模型、LoRA、提示词、参数**，
完全不需要 `/history`。这是本次最大的识别率提升点。

另外两个坑：
- ComfyUI 前端序列化的 prompt 里会出现 JS 字面量 `NaN`（旧代码 `JSON.parse` 直接失败 → 整条记录变「未识别」），
  已加容错解析 `parseGraphLoose()`（清洗 `NaN`/`Infinity`/尾逗号后重试）。
- 视频若确无 tag，用同目录同名 PNG 的 prompt 兜底（`video+png`）。

## 三、改动清单

### 1. `meta-lib.js`（重写识别核心）

- 新增 `parseContainerTags()` / `readEmbeddedMeta()`：PNG 文本块 + 视频容器 tag 统一入口。
- 新增 `parseGraphLoose()`：容错 JSON 解析。
- `extractFromGraph()` 增加**角色识别** `roleOf(cls,key)`：`lora / vae / clip / controlnet / upscale / base / other`，
  并额外产出 `baseModels`（真正的主模型）；旧字段 `models/modelPaths/loras/loraPaths` 保持兼容（服务端 UI 不用改）。
- `classifyFamily()` 判据按优先级重排：
  **主模型 → LoRA → 来源继承 → 输出文件名 → 节点类型 → 辅助模型**，最后才是「其他 / 未识别」。
  （文件名放后面是为了避免 `AnimateDiff_00001.png` 其实是 H3 视频帧这类误判。）
- 家族规则扩充并细分：`Boogu / Krea 2 / Krea / MiniMax H3 / LTX / Wan / Hunyuan / FLUX / Pony/SDXL / SDXL /
  SD1.5（含 GuoFeng、国风、chilloutmix、hans 等中文系）/ AnimateDiff`。
- 新增 `upstreamImages()`：取 workflow 里 `LoadImage` 指向的原图，用于后处理作品继承家族。

### 2. `backfill.js`（新增，一次性全量回填）

1. 先 rsync 拉一次 GPU 机 output（`--no-pull` 可跳过）；
2. 遍历 `media/` **全部**文件（不受 sinceEpoch 限制）重新解析；
3. 家族重算 + 后处理作品按 `LoadImage` 原图**继承家族**（最多 4 层，防环）；
4. 写回 `data/meta/<sha1(rel)[:24]>.json`，**保留已有 `addedAt` 与人工 NSFW 标记**。

用法：
```bash
node backfill.js              # 拉取 + 全量回填
node backfill.js --no-pull    # 只重建元数据
node backfill.js --dry-run    # 只统计不写盘
```
日志：`~/Downloads/gallery-backfill.log`

### 3. `sync-agent.js`（增量同步对齐）

- 改用共享解析：**新生成的视频也会解析容器 tag**，不再依赖 `/history`。
- 后处理作品继承原图家族（`familyOfRel()`，本次运行内缓存）。
- 支持 `config.json` 新增开关 `indexAll: true`：收录 output 下全部作品（回填后语义统一），
  置回 `false` 则恢复「只收录部署之后新生成」。

### 4. `config.json`

新增 `"indexAll": true`。

### 5. UI / 服务端

**未改动**（按用户要求只修家族分类；具体模型文件名、LoRA 权重展示留待后续需要时再做）。
`server.js` 的家族筛选、LoRA 筛选、搜索都是读 meta 现算，元数据一变界面即变。

## 四、修复后实测

```
总数 1725（新增 1070 条存量，更新 655 条旧记录；相册持续收录新作品，复核时已 1726）
家族：Krea 2 672 | Boogu 598 | MiniMax H3 444 | LTX 8 | SDXL 2 | Pony/SDXL 1 | SD1.5 1
      「其他」0 条、「未识别」0 条
LoRA：9 种，823 条作品带 LoRA
主模型识别成功 1716 条（另 9 条是纯放大后处理，已继承原图家族 Krea 2）
视频：411/411 全部解析出主模型与提示词
```

对照样例：

| 作品 | 修复前 | 修复后 |
|---|---|---|
| `video/Godzilla_gas_tank_disaster_12s_00001_audio.mp4` | 未识别 | MiniMax H3（dasiwa ref2va hybrid + Singularity v1.3） |
| `ltx25_douyin_1080p_00001_.mp4` | 未识别 | LTX（ltx-2.5-22b-distilled） |
| `smoke_pony_00001_.png` | 其他 | Pony/SDXL（realPony_cuteJpFixedNo03） |
| `smoke_gufeng_00001_.png` | 其他 | SD1.5（GuoFeng3_Fix + hanfu-v3.0-song） |
| `tg4_gate_2x_00001_.png` | 其他 | Krea 2（继承原图 `tg4_gate_00001_.png`） |
| `ComfyUI_00001_.png` | 未识别（prompt 含 NaN 解析失败） | Boogu（boogu_image_base_bf16） |
| `ComfyUI_00146_.png` | 其他 | SDXL（sd_xl_base_1.0 + refiner） |

### 增量路径验证

修复后 GPU 机新生成的 `ComfyUI_00147_.png` 由 sync-agent 自动收录，日志：

```
15:44:05 新收录 png | ComfyUI_00147_.png | SDXL | sd_xl_base_1.0.safetensors,sd_xl_refiner_1.0.safetensors
```

说明增量同步已走新解析路径（不再依赖 `/history`），且 `models` 列表已按 **主模型优先** 排序，
详情页第一行就是真正的底模，不再是 `taeh3.safetensors` 之类的辅助权重。

## 五、运维命令

```bash
cd /home/zyw/Downloads/comfyui-gallery
bash galleryctl.sh status|start|stop|restart   # 相册启停（sync-agent + server）
node backfill.js --no-pull                    # 重算全部元数据/家族（约 60s）
tail -f ~/Downloads/gallery-sync.log          # 同步日志
tail -f ~/Downloads/gallery-web.log           # Web/缩略图日志
```
- 保活：cron 每分钟跑 `comfyui-gallery/watchdog.sh`（端口 8900 或 sync-agent 缺失即拉起）。
- 回填后 1070 条缺失缩略图由服务端每 5s 自动预热（3 并发，每次 ffmpeg 超时 30s、失败重试 2 次）。
  本次实跑约 20 分钟补齐 **1725/1726**，无失败记录。

## 六、回滚

```bash
cd /home/zyw/Downloads/comfyui-gallery
cp bak/meta-lib.js bak/sync-agent.js bak/config.json .   # 恢复旧代码
bash galleryctl.sh restart
```
元数据如需回到修复前状态：`bak/` 只备份了代码；旧 meta 未单独备份（如需可删 meta 后重跑旧代码）。
**注意**：`config.json` 的 `indexAll` 若改回 false，已入库的存量记录不会消失，只是不再收录新的旧文件。

## 七、遗留与后续可选

- 同一家族下不同权重（如 Krea 2 的 turbo / fp8 / 未来 base）在界面上仍只显示「Krea 2」，
  未展示具体模型文件名 —— 用户选择只修家族；若以后要，可在 `light()` 里加模型名筛选。
- 48 个无 tag 的 webm 靠同名 PNG 兜底；若两者都缺则仍会「未识别」（当前为 0 条）。
- 相册进程仍是 nohup 启动（靠 cron watchdog 兜底），未纳入 systemd；如需更稳可参照下载服务的
  `dl-server.service` 改造。
